文章目录

WebSocketClient类就是负责程序与远程音乐资料库的连接。它定义于src/musikcore/net/WebSocketClient.h,继承自类IMessageTarget,接收程序的请求并与远程音乐资料库交互。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
class WebSocketClient: public musik::core::runtime::IMessageTarget {
public:
using ClientPtr = std::unique_ptr<RawWebSocketClient>;
/* typedef lib::shared_ptr< message > ptr,WebSocket消息类型 */
using ClientMessage = websocketpp::config::asio_client::message_type::ptr;
/* 唯一标识连接的句柄 */
using Connection = websocketpp::connection_hdl;
using Query = std::shared_ptr<musik::core::db::ISerializableQuery>;
/* 连接状态 */
enum class State: int {
Disconnected = 0,
Connecting = 1,
Authenticating = 2,
Connected = 3,
Disconnecting = 4,
};
/* 查询错误值 */
enum class QueryError: int {
QueryFailed = 1,
Disconnected = 2,
AuthFailed = 3,
QueryNotFound = 4,
ParseFailed = 5,
};
/* 连接错误值 */
enum class ConnectionError : int {
None = 0,
InvalidPassword = 1,
IncompatibleVersion = 2,
ConnectionFailed = 3,
ClosedByServer = 4,
};
/* 专门用于处理各种异常情况,RemoteLibrary类将其继承 */
class Listener {
public:
using Client = WebSocketClient;
using State = Client::State;
using QueryError = Client::QueryError;
/* 密码错误 */
virtual void OnClientInvalidPassword(Client* client) = 0;
/* 更新连接状态 */
virtual void OnClientStateChanged(Client* client, State newState, State oldState) = 0;
/* 查询成功 */
virtual void OnClientQuerySucceeded(Client* client, const std::string& messageId, Query query) = 0;
/* 查询失败 */
virtual void OnClientQueryFailed(Client* client, const std::string& messageId, Query query, QueryError result) = 0;
};
/* 构造函数(设置messageQueue、rawClient(mode、open_handler、fail_handler、message_handler与close_handler)、listener) */
WebSocketClient(
musik::core::runtime::IMessageQueue* messageQueue,
Listener* listener);

WebSocketClient(const WebSocketClient&) = delete;
/* 析构函数(关闭网络连接、重置rawClient、this从messageQueue中注销) */
virtual ~WebSocketClient();
/* 判断传入的host、port、password、useTls是否与该类设置的完全一致;若不完全一致,则将该类的设置为传入的参数;然后根据设置的参数重新连接 */
void Connect(
const std::string& host,
unsigned short port,
const std::string& password,
bool useTls);
/* 对mutex加锁,断开连接,重置io,从setting.json中读取timeout配置项,设置状态为State::Connecting,开辟一个线程处理新连接;线程断开连接后状态设置为State::Disconnected */
void Reconnect();
/* io_service停止,thread右值传递给oldThread,oldThread调用join函数等待被销毁 */
void Disconnect();
/* 返回连接状态 */
State ConnectionState() const;
/* 返回上次连接的connectionError */
ConnectionError LastConnectionError() const;
/* 返回上次连接的serverVersion */
std::string LastServerVersion() const;
/* 返回uri */
std::string Uri() const;
/* 加锁,若状态不是State::Connected且禁止离线队列,则插入失败;若query为空,则返回空字符串;生成此query唯一的messageId,并在messageIdToQuery中建立映射关系,若处于连接状态,则发送此请求;返回messageId */
std::string EnqueueQuery(Query query);
/* 设置消息队列,若传入的参数messageQueue与messageQueue成员相同,直接退出,否则,若messageQueue成员非空,则注销this;messageQueue成员设置为传入的参数messageQueue,并注册this;并向this投递一个ping请求 */
void SetMessageQueue(musik::core::runtime::IMessageQueue* messageQueue);

/* IMessageTarget */
/* 处理消息队列中的消息,仅支持kPingMessage类型的消息;发送ping请求之后再投递一个ping请求 */
void ProcessMessage(musik::core::runtime::IMessage& message) override;

private:
/* 设置状态,若state为State::Disconnected,则重置连接并调用InvalidatePendingQueries;若state为State::connected,则connectionError设置为ConnectionError::None,将messageIdToQuery中的所有query发送;再设置state成员为state参数,listener成员也要切换状态 */
void SetState(State state);
/* 取消所有的query,清空messageIdToQuery */
void InvalidatePendingQueries();
/* 将messageIdToQuery中的所有query发送 */
void SendPendingQueries();
/* 将connectionError设置为errorCode,再调用SetState将状态切换为State::Disconnected */
void SetDisconnected(ConnectionError errorCode);
/* HTTP协议与HTTPS协议的客户端对象 */
ClientPtr rawClient;
/* 唯一标识连接的句柄 */
Connection connection;
/* io_service对象 */
boost::asio::io_service io;
/* 线程对象 */
std::unique_ptr<std::thread> thread;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
         /* 互斥锁 */
mutable std::recursive_mutex mutex;
/* 是否使用TLS协议 */
bool useTls{ false };
/* 密码 */
std::string uri, password;
/* messageId到Query的映射 */
std::unordered_map<std::string, Query> messageIdToQuery;
/* 是否退出 */
std::atomic<bool> quit{ false };
ConnectionError connectionError{ ConnectionError::None };
/* 服务端版本 */
std::string serverVersion;
/* 连接状态 */
State state{ State::Disconnected };
Listener* listener{ nullptr };
/* 消息队列 */
musik::core::runtime::IMessageQueue* messageQueue;
};

WebSocketClient类用到了类RawWebSocketClient,它是对websocketpp::client<websocketpp::config::asio_client>websocketpp::client<websocketpp::config::asio_tls_client>的封装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class RawWebSocketClient {
public:
/* HTTP协议 */
using PlainTextClient = websocketpp::client<websocketpp::config::asio_client>;
using PlainTextClientPtr = std::unique_ptr<PlainTextClient>;
/* HTTPS协议 */
using TlsClient = websocketpp::client<websocketpp::config::asio_tls_client>;
using TlsClientPtr = std::unique_ptr<TlsClient>;
/* SSL协议内容 */
using SslContext = std::shared_ptr<boost::asio::ssl::context>;
/* typedef lib::shared_ptr< message > ptr,WebSocket消息类型 */
using Message = websocketpp::config::asio_client::message_type::ptr;
/* 唯一标识连接的句柄 */
using Connection = websocketpp::connection_hdl;

using OpenHandler = std::function<void(Connection)>;
using FailHandler = std::function<void(Connection)>;
using MessageHandler = std::function<void(Connection, Message)>;
using CloseHandler = std::function<void(Connection)>;
using SendMessageErrorHandler = std::function<void(std::error_code)>;
/* 模式:明文传输与TLS加密传输 */
enum class Mode: int {
PlainText = 0,
TLS = 1
};
/* 构造函数(构造plainTextClient与tlsClient对象并对其初始化)*/
RawWebSocketClient(boost::asio::io_service& io);
RawWebSocketClient(const RawWebSocketClient&) = delete;
/* 析构函数*/
~RawWebSocketClient();
/* 设置协议类型 */
void SetMode(Mode mode);
/* 设置HTTP协议客户端的XX与HTTP协议客户端的XX */
void SetOpenHandler(OpenHandler openHandler);
void SetFailHandler(FailHandler failHandler);
void SetMessageHandler(MessageHandler messageHandler);
void SetCloseHandler(CloseHandler closeHandler);
void SetSendMessageErrorHandler(SendMessageErrorHandler errorHandler);
/* 根据设置的mode调用plainTextClient->send或tlsClient->send,若出错则调用sendMessageErrorHandler处理错误 */
void Send(Connection connection, const std::string& message);
/* 设置等待ping操作回复的时间,若超时未收到回复则认为连接已断开,用于这可以用作keepalive或检测断开的连接 */
void SetPongTimeout(long timeoutMs);
/* 连接操作 */
void Connect(const std::string& uri);
/* 根据设置的mode调用plainTextClient->run或tlsClient->run */
void Run();

private:
/* 协议类型(HTTP还是HTTPS) */
Mode mode;
/* HTTP协议的客户端 */
TlsClientPtr tlsClient;
/* HTTPS协议的客户端 */
PlainTextClientPtr plainTextClient;
/* 处理发送消息错误的句柄 */
SendMessageErrorHandler sendMessageErrorHandler;
};

WebSocketClient类用到了几个静态函数create*Request生成各种请求。