diff options
author | George Hazan <ghazan@miranda.im> | 2017-01-03 19:10:33 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2017-01-03 19:10:33 +0300 |
commit | 1b5e5bbb9f7abc2d56cf0ef0ffe7cd281854c874 (patch) | |
tree | 45c59c30b55c117807a964b120ef6df253fa1296 | |
parent | e8ccd6330c478c4196dd1cedeeddf14add597784 (diff) |
server history syncing support
-rw-r--r-- | protocols/Discord/proto_discord/res/Invisible.ico | bin | 4150 -> 5430 bytes | |||
-rw-r--r-- | protocols/Discord/src/proto.cpp | 18 | ||||
-rw-r--r-- | protocols/Discord/src/proto.h | 11 | ||||
-rw-r--r-- | protocols/Discord/src/server.cpp | 72 | ||||
-rw-r--r-- | protocols/Discord/src/stdafx.h | 2 | ||||
-rw-r--r-- | protocols/Discord/src/utils.cpp | 18 |
6 files changed, 120 insertions, 1 deletions
diff --git a/protocols/Discord/proto_discord/res/Invisible.ico b/protocols/Discord/proto_discord/res/Invisible.ico Binary files differindex c2830ed132..3c27bb3f03 100644 --- a/protocols/Discord/proto_discord/res/Invisible.ico +++ b/protocols/Discord/proto_discord/res/Invisible.ico diff --git a/protocols/Discord/src/proto.cpp b/protocols/Discord/src/proto.cpp index 358f4e7bf6..41179a5a2d 100644 --- a/protocols/Discord/src/proto.cpp +++ b/protocols/Discord/src/proto.cpp @@ -40,6 +40,7 @@ CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) : // Events HookProtoEvent(ME_OPT_INITIALISE, &CDiscordProto::OnOptionsInit); + HookProtoEvent(ME_MSG_WINDOWEVENT, &CDiscordProto::OnSrmmEvent); // Clist Clist_GroupCreate(NULL, m_wszDefaultGroup); @@ -267,6 +268,23 @@ int CDiscordProto::OnPreShutdown(WPARAM, LPARAM) ///////////////////////////////////////////////////////////////////////////////////////// +int CDiscordProto::OnSrmmEvent(WPARAM, LPARAM lParam) +{ + MessageWindowEventData *MWeventdata = (MessageWindowEventData*)lParam; + + if (MWeventdata->uType == MSG_WINDOW_EVT_OPENING && MWeventdata->hContact) { + SnowFlake oldid = getId(MWeventdata->hContact, DB_KEY_LASTMSGID); + if (oldid > 0) + RetrieveHistory(MWeventdata->hContact, MSG_AFTER, oldid, 99); + else + RetrieveHistory(MWeventdata->hContact, MSG_NOFILTER, 0, 99); + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + int CDiscordProto::OnEvent(PROTOEVENTTYPE event, WPARAM wParam, LPARAM lParam) { switch (event) { diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h index ee9569781c..8d0e6c24fb 100644 --- a/protocols/Discord/src/proto.h +++ b/protocols/Discord/src/proto.h @@ -59,6 +59,11 @@ JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM ¶m); ///////////////////////////////////////////////////////////////////////////////////////// +enum CDiscordHitoryOp +{ + MSG_NOFILTER, MSG_AFTER, MSG_BEFORE +}; + struct CDiscordUser : public MZeroedObject { CDiscordUser(SnowFlake _id) : @@ -161,18 +166,22 @@ public: int __cdecl OnModulesLoaded(WPARAM, LPARAM); int __cdecl OnPreShutdown(WPARAM, LPARAM); int __cdecl OnOptionsInit(WPARAM, LPARAM); + int __cdecl OnSrmmEvent(WPARAM, LPARAM); void OnLoggedIn(); void OnLoggedOut(); void OnReceiveAuth(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnReceiveToken(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnReceiveUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnReceiveGuilds(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnReceiveChannels(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnReceiveFriends(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void RetrieveUserInfo(MCONTACT hContact); + void OnReceiveUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + + void RetrieveHistory(MCONTACT hContact, CDiscordHitoryOp iOp = MSG_NOFILTER, SnowFlake msgid = 0, int iLimit = 50); + void OnReceiveHistory(NETLIBHTTPREQUEST*, AsyncHttpRequest*); // Misc void SetServerStatus(int iStatus); diff --git a/protocols/Discord/src/server.cpp b/protocols/Discord/src/server.cpp index b8af77f8cb..a5ac8e215a 100644 --- a/protocols/Discord/src/server.cpp +++ b/protocols/Discord/src/server.cpp @@ -17,6 +17,76 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h" +///////////////////////////////////////////////////////////////////////////////////////// +// retrieves server history + +void CDiscordProto::RetrieveHistory(MCONTACT hContact, CDiscordHitoryOp iOp, SnowFlake msgid, int iLimit) +{ + CDiscordUser *pUser = FindUser(getId(hContact, DB_KEY_ID)); + if (pUser == NULL) + return; + + CMStringA szUrl(FORMAT, "/channels/%lld/messages", pUser->channelId); + AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveHistory); + pReq << INT_PARAM("limit", iLimit); + switch (iOp) { + case MSG_AFTER: + pReq << CHAR_PARAM("after", CMStringA(FORMAT, "%lld", msgid)); break; + case MSG_BEFORE: + pReq << CHAR_PARAM("before", CMStringA(FORMAT, "%lld", msgid)); break; + } + pReq->pUserInfo = pUser; + Push(pReq); +} + +void CDiscordProto::OnReceiveHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) +{ + CDiscordUser *pUser = (CDiscordUser*)pReq->pUserInfo; + + if (pReply->resultCode != 200) + return; + + JSONNode root = JSONNode::parse(pReply->pData); + if (!root) + return; + + DBEVENTINFO dbei = {}; + dbei.cbSize = sizeof(dbei); + dbei.szModule = m_szModuleName; + dbei.flags = DBEF_READ | DBEF_UTF; + dbei.eventType = EVENTTYPE_MESSAGE; + + SnowFlake lastId = getId(pUser->hContact, DB_KEY_LASTMSGID); // as stored in a database + + for (auto it = root.begin(); it != root.end(); ++it) { + JSONNode &p = *it; + + SnowFlake authorid = _wtoi64(p["author"]["id"].as_mstring()); + if (authorid == m_ownId) + dbei.flags |= DBEF_SENT; + else + dbei.flags &= ~DBEF_SENT; + + SnowFlake msgid = _wtoi64(p["id"].as_mstring()); + + CMStringA szBody(ptrA(mir_utf8encodeW(p["content"].as_mstring()))); + szBody.AppendFormat("%c%lld", 0, msgid); + + dbei.timestamp = StringToDate(p["timestamp"].as_mstring()); + dbei.pBlob = (PBYTE)szBody.GetBuffer(); + dbei.cbBlob = szBody.GetLength(); + db_event_add(pUser->hContact, &dbei); + + if (lastId < msgid) + lastId = msgid; + } + + setId(pUser->hContact, DB_KEY_LASTMSGID, lastId); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// retrieves user info + void CDiscordProto::RetrieveUserInfo(MCONTACT hContact) { AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "/users/@me", &CDiscordProto::OnReceiveUserInfo); @@ -96,6 +166,8 @@ void CDiscordProto::OnReceiveChannels(NETLIBHTTPREQUEST *pReply, AsyncHttpReques pUser->lastMessageId = _wtoi64(p["last_message_id"].as_mstring()); pUser->channelId = _wtoi64(p["id"].as_mstring()); pUser->bIsPrivate = p["is_private"].as_bool(); + + setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId); } } diff --git a/protocols/Discord/src/stdafx.h b/protocols/Discord/src/stdafx.h index e0177716ab..43d0077d7c 100644 --- a/protocols/Discord/src/stdafx.h +++ b/protocols/Discord/src/stdafx.h @@ -56,3 +56,5 @@ extern HINSTANCE g_hInstance; #define DB_KEY_GROUP "GroupName" #define DB_KEYVAL_GROUP L"Discord" + +time_t StringToDate(const CMStringW &str); diff --git a/protocols/Discord/src/utils.cpp b/protocols/Discord/src/utils.cpp index 5913f6ef33..0513e49aac 100644 --- a/protocols/Discord/src/utils.cpp +++ b/protocols/Discord/src/utils.cpp @@ -46,6 +46,24 @@ JSONNode& operator<<(JSONNode &json, const WCHAR_PARAM ¶m) ///////////////////////////////////////////////////////////////////////////////////////// +time_t StringToDate(const CMStringW &str) +{ + struct tm T = { 0 }; + int boo; + if (swscanf(str, L"%04d-%02d-%02dT%02d:%02d:%02d.%d", &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec, &boo) != 7) + return 0; + + T.tm_year -= 1900; + T.tm_mon--; + time_t t = mktime(&T); + + _tzset(); + t -= _timezone; + return (t >= 0) ? t : 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + SnowFlake CDiscordProto::getId(const char *szSetting) { DBVARIANT dbv; |