文章目录

该类管理远程的音乐资料库并提供编辑远程音乐资料库的接口,定义于src/musikcore/library/RemoteLibrary.h,继承了ILibrary、IMessageTarget、Listener、IResourceLocator类,并通过继承模板类std::enable_shared_from_this使得this指针成为shared_ptr指针。

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
class RemoteLibrary :
public ILibrary,
public mymusic::core::runtime::IMessageTarget,
public std::enable_shared_from_this<RemoteLibrary>,
public mymusic::core::net::WebSocketClient::Listener,
public ILibrary::IResourceLocator
{
public:
using Client = mymusic::core::net::WebSocketClient;
using Query = std::shared_ptr<mymusic::core::db::ISerializableQuery>;
using MessageQueue = mymusic::core::runtime::IMessageQueue;
/* 生成一个LocalLibrary对象,返回其智能指针 */
static ILibraryPtr Create(std::string name, int id, MessageQueue* messageQueue);
/* RemoteLibrary类构造函数:传递messageQueue与this指针构造WebSocketClient对象—成员wsc;identifier设置为id的字符串形式;创建thread成员,运行的函数为ThreadProc;调用ReloadConnectionFromPreferences函数根据配置文件重新加载数据库连接;若messageQueue成员非空,在messageQueue上注册它本身 */
RemoteLibrary(std::string name, int id, MessageQueue* messageQueue);
RemoteLibrary(const RemoteLibrary&) = delete;
/* RemoteLibrary类析构函数:关闭该类(释放indexer成员,thread成员置空,清空queryQueue,exit置为true,通知所有等待在queueCondition上的线程,等待线程thread的结束,并回收它的资源);若messageQueue成员非空,将this从其中注销 */
virtual ~RemoteLibrary();

/* ILibrary */
/* 判断是否为完全本地的查询,若为,则调用LocalLibrary单例的EnqueueAndWait函数;否则,将查询对象序列化;对互斥量queueMutex加锁,创建QueryContext对象并将其智能指针加入queryQueue,然后通知其他线程;直到query处理完(包括出错)然后退出! */
int Enqueue(QueryPtr query, Callback = Callback()) override;
/* 判断是否为完全本地的查询,若为,则调用LocalLibrary单例的EnqueueAndWait函数;将查询对象序列化;对互斥量queueMutex加锁,创建QueryContext对象并将其智能指针加入queryQueue,然后通知其他线程;若timeoutMs=0,返回query的ID即可;若timeoutMs=-1,直到query处理完(包括出错)然后退出!若timeoutMs>0且不等于-1,则要么等待 timeoutMs退出,要么query提前被处理完(包括出错)然后退出 */
int EnqueueAndWait(QueryPtr query, size_t timeoutMs = kWaitIndefinite, Callback = Callback()) override;
/* 返回NullIndexer对象kNullIndexer */
mymusic::core::IIndexer *Indexer() override;
/* 返回id成员的值 */
int Id() override;
/* 返回name成员的值 */
const std::string& Name() override;
/* 设置消息队列messageQueue成员 */
void SetMessageQueue(mymusic::core::runtime::IMessageQueue& queue) override;
/* 返回messageQueue成员 */
mymusic::core::runtime::IMessageQueue& GetMessageQueue() noexcept override { return *messageQueue; }
ILibrary::IResourceLocator& GetResourceLocator() noexcept override { return *this; }
/* 配置文件中RemoteLibraryViewed的属性值 */
bool IsConfigured() override;
/* 获取连接状态connectionState */
ConnectionState GetConnectionState() const override { return this->connectionState; }
/* 类型:远程 */
Type GetType() const noexcept override { return Type::Remote; }
/* 关闭该类(关闭socket连接,清空queryQueue,exit置为true,thread成员置空) */
void Close() override;

/* IMessageTarget */
/* 处理消息(对于MESSAGE_QUERY_COMPLETED类型的message,向连接到QueryCompleted上的接收者通知context对应的查询完成的消息,再执行回调函数;对于MESSAGE_RECONNECT_SOCKET类型的message,若wsc的状态为Disconnected,则根据配置文件重新加载数据库连接;对于MESSAGE_UPDATE_CONNECTION_STATE类型的message,将状态更新为message所设置的状态) */
void ProcessMessage(mymusic::core::runtime::IMessage &message) override;

/* WebSocketClient::Listener */
/* 将验证失败的消息加入消息队列,以通知this */
void OnClientInvalidPassword(Client* client) override;
/* 若messageQueue非空,根据上一次连接出错的原因与newState判断是否重新连接,若重新连接则先将消息队列中所有目标为this、类型为MESSAGE_RECONNECT_SOCKET的消息删除、然后将目标为this、类型为MESSAGE_RECONNECT_SOCKET的消息加入消息队列延迟2500ms投递;再向消息队列中加入MESSAGE_UPDATE_CONNECTION_STATE类型的消息(data为newState)给this */
void OnClientStateChanged(Client* client, State newState, State oldState) override;
/* 调用OnQueryCompleted(messageId, query) */
void OnClientQuerySucceeded(Client* client, const std::string& messageId, Query query) override;
/* 调用OnQueryCompleted(messageId, query) */
void OnClientQueryFailed(Client* client, const std::string& messageId, Query query, Client::QueryError reason) override;

/* IResourceLocator */
/* 返回值格式:musikcore://remote-track/<{{ "uri", scheme + host + ":" + std::to_string(port) + "/audio/id/" + std::to_string(track->GetId())},
{ "originalUri", std::string(track->Uri()) },
{ "type", type },
{ "password", password }
}.dump()> */
std::string GetTrackUri(mymusic::core::sdk::ITrack* track, const std::string& defaultUri) override;

/* RemoteLibrary */
/* 根据配置文件重新加载数据库连接 */
void ReloadConnectionFromPreferences();
/* 返回wsc对象 */
const mymusic::core::net::WebSocketClient& WebSocketClient() const;

private:
/* 专门用来表示QueryCompleted的消息 */
class QueryCompletedMessage;

struct QueryContext {
std::shared_ptr<mymusic::core::db::ISerializableQuery> query;
Callback callback;
};

using QueryContextPtr = std::shared_ptr<QueryContext>;
using QueryList = std::list<QueryContextPtr>;
/* 处理查询消息(对queueMutex加锁,再调用RunQueryOnWebSocketClient) */
void RunQuery(QueryContextPtr context);
void RunQueryOnLoopback(QueryContextPtr context);
/* 在WebSocketClient上运行查询(将query插入wsc的队列,若插入成功,会返回对应的messageId,否则,调用OnQueryCompleted函数发送此查询完成的消息,然后通知所有等待在syncQueryCondition上的线程) */
void RunQueryOnWebSocketClient(QueryContextPtr context);
/* 根据messageId得到对应的context=queriesInFlight[messageId],再将这对映射关系从queriesInFlight中删除;再调用OnQueryCompleted(context),然后通知所有等待在syncQueryCondition上的线程 */
void OnQueryCompleted(const std::string& messageId, Query query);
/* 若messageQueue非空,则将要投递给this的MESSAGE_QUERY_COMPLETED类型的消息加入消息队列,否则,向连接到QueryCompleted上的接收者通知context对应的查询完成的消息,再执行回调函数 */
void OnQueryCompleted(QueryContextPtr context);
/* 向连接到QueryCompleted上的接收者通知context对应的查询完成的消息,再执行context中的回调函数 */
void NotifyQueryCompleted(QueryContextPtr context);
/* 判断是否在queryQueue或queriesInFlight中 */
bool IsQueryInFlight(Query query);
/* thread线程要运行的函数 */
void ThreadProc();
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
        /* 获取queryQueue中的第一个QueryContextPtr */
QueryContextPtr GetNextQuery();
/* 要查询的QueryContext先放到queryQueue,等wsc将QueryContext加入到待发送队列后,QueryContext移入queriesInFlight */
QueryList queryQueue;
/* 消息队列 */
mymusic::core::runtime::IMessageQueue* messageQueue;
/* WebSocketClient对象,作为客户端 */
mymusic::core::net::WebSocketClient wsc;
/* 标识符 */
std::string identifier;
int id;
/* 音乐资料库名 */
std::string name;
/* 那些加入到wsc待发送消息的队列中的QueryContextPtr,和与之对应的messageId */
std::unordered_map<std::string, QueryContextPtr> queriesInFlight;
/* 开辟的专门用来处理查询消息的线程 */
std::unique_ptr<std::thread> thread;
std::condition_variable_any queueCondition, syncQueryCondition;
/* 互斥量,保证任一时刻最多只有一个线程处理queryQueue+queriesInFlight */
std::recursive_mutex queueMutex;
/* 连接状态 */
std::atomic<ConnectionState> connectionState{ ConnectionState::Disconnected };
/* 是否退出 */
std::atomic<bool> exit;
};