diff options
author | George Hazan <george.hazan@gmail.com> | 2013-10-06 13:17:00 +0000 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2013-10-06 13:17:00 +0000 |
commit | 74bbe14fb8a018a65f89d28386eb3e88edfd0516 (patch) | |
tree | 8309b29c8d288e472955aa07defab7e5e3f1726b /protocols/VKontakte | |
parent | 91003eb7373b4cb9e340be5ecdbbb7884a5e973f (diff) |
VK: async http requests
git-svn-id: http://svn.miranda-ng.org/main/trunk@6373 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/VKontakte')
-rw-r--r-- | protocols/VKontakte/src/misc.cpp | 11 | ||||
-rw-r--r-- | protocols/VKontakte/src/stdafx.h | 2 | ||||
-rw-r--r-- | protocols/VKontakte/src/vk.h | 5 | ||||
-rw-r--r-- | protocols/VKontakte/src/vk_proto.cpp | 32 | ||||
-rw-r--r-- | protocols/VKontakte/src/vk_proto.h | 47 | ||||
-rw-r--r-- | protocols/VKontakte/src/vk_queue.cpp | 137 | ||||
-rw-r--r-- | protocols/VKontakte/src/vk_thread.cpp | 16 | ||||
-rw-r--r-- | protocols/VKontakte/vk_10.vcxproj | 1 | ||||
-rw-r--r-- | protocols/VKontakte/vk_10.vcxproj.filters | 3 | ||||
-rw-r--r-- | protocols/VKontakte/vk_11.vcxproj | 1 | ||||
-rw-r--r-- | protocols/VKontakte/vk_11.vcxproj.filters | 3 |
11 files changed, 243 insertions, 15 deletions
diff --git a/protocols/VKontakte/src/misc.cpp b/protocols/VKontakte/src/misc.cpp index 0802d73405..b45ce5da7f 100644 --- a/protocols/VKontakte/src/misc.cpp +++ b/protocols/VKontakte/src/misc.cpp @@ -27,6 +27,17 @@ TCHAR* CVkProto::GetUserStoredPassword() return NULL;
}
+void CVkProto::SetAllContactStatuses(int iStatus)
+{
+ for (HANDLE hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ if (isChatRoom(hContact))
+ continue;
+
+ if (getWord(hContact, "Status", 0) != iStatus)
+ setWord(hContact, "Status", iStatus);
+ }
+}
+
int CVkProto::SetServerStatus(int iStatus)
{
return 0;
diff --git a/protocols/VKontakte/src/stdafx.h b/protocols/VKontakte/src/stdafx.h index e3137a17a5..adf0de846a 100644 --- a/protocols/VKontakte/src/stdafx.h +++ b/protocols/VKontakte/src/stdafx.h @@ -56,6 +56,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <m_userinfo.h>
#include <m_utils.h>
+#include <m_folders.h>
+
#include "win2k.h"
#include "resource.h"
diff --git a/protocols/VKontakte/src/vk.h b/protocols/VKontakte/src/vk.h index 23d92fa906..51723a527d 100644 --- a/protocols/VKontakte/src/vk.h +++ b/protocols/VKontakte/src/vk.h @@ -15,4 +15,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define VK_APP_ID 3917910
+
+#define VK_API_URL "api.vk.com"
+#define VK_REDIRECT_URL "http://" VK_API_URL "/blank.html"
+
extern HINSTANCE hInst;
\ No newline at end of file diff --git a/protocols/VKontakte/src/vk_proto.cpp b/protocols/VKontakte/src/vk_proto.cpp index fe308aff71..d2e213e998 100644 --- a/protocols/VKontakte/src/vk_proto.cpp +++ b/protocols/VKontakte/src/vk_proto.cpp @@ -18,13 +18,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h"
CVkProto::CVkProto(const char *szModuleName, const TCHAR *ptszUserName) :
- PROTO<CVkProto>(szModuleName, ptszUserName)
+ PROTO<CVkProto>(szModuleName, ptszUserName),
+ m_arRequestsQueue(10)
{
+ InitQueue();
+
CreateProtoService(PS_CREATEACCMGRUI, &CVkProto::SvcCreateAccMgrUI);
+
+ TCHAR descr[512];
+ mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), m_tszUserName);
+
+ NETLIBUSER nlu = {sizeof(nlu)};
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR;
+ nlu.szSettingsModule = m_szModuleName;
+ nlu.szSettingsModule = m_szModuleName;
+ nlu.ptszDescriptiveName = descr;
+ m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
+
+ mir_sntprintf(descr, SIZEOF(descr), _T("%%miranda_avatarcache%%\\%s"), m_tszUserName);
+ hAvatarFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), m_szModuleName, descr, m_tszUserName);
+
+ // Set all contacts offline -- in case we crashed
+ SetAllContactStatuses(ID_STATUS_OFFLINE);
}
CVkProto::~CVkProto()
{
+ UninitQueue();
}
int CVkProto::OnModulesLoaded(WPARAM wParam, LPARAM lParam)
@@ -34,6 +54,8 @@ int CVkProto::OnModulesLoaded(WPARAM wParam, LPARAM lParam) int CVkProto::OnPreShutdown(WPARAM wParam, LPARAM lParam)
{
+ m_bTerminated = true;
+ SetEvent(m_evRequestsQueue);
return 0;
}
@@ -77,17 +99,19 @@ int CVkProto::SetStatus(int iNewStatus) return 0;
int oldStatus = m_iStatus;
- if (iNewStatus == ID_STATUS_OFFLINE) {
+ m_iDesiredStatus = iNewStatus;
+
+ if (iNewStatus == ID_STATUS_OFFLINE) {
if ( IsOnline())
ShutdownSession();
m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
}
- else if (!m_hWorkerThread && !(m_iStatus >= ID_STATUS_CONNECTING && m_iStatus < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES)) {
+ else if ( !(m_iStatus >= ID_STATUS_CONNECTING && m_iStatus < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES)) {
m_iStatus = ID_STATUS_CONNECTING;
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
- ForkThread(&CVkProto::WorkerThread, 0);
+ m_hWorkerThread = ForkThreadEx(&CVkProto::WorkerThread, 0, NULL);
}
else if ( IsOnline())
SetServerStatus(iNewStatus);
diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index cc1d82884c..2965ab8e74 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -15,6 +15,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+struct CVkProto;
+typedef void (CVkProto::*VK_REQUEST_HANDLER)(NETLIBHTTPREQUEST*);
+
struct CVkProto : public PROTO<CVkProto>
{
CVkProto(const char*, const TCHAR*);
@@ -75,6 +78,8 @@ struct CVkProto : public PROTO<CVkProto> int __cdecl OnOptionsInit(WPARAM, LPARAM);
int __cdecl OnPreShutdown(WPARAM, LPARAM);
+ void OnOAuthAuthorize(NETLIBHTTPREQUEST*);
+
//==== Services ======================================================================
INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM);
@@ -85,13 +90,41 @@ struct CVkProto : public PROTO<CVkProto> __forceinline bool IsOnline() const { return m_bOnline; }
- void ShutdownSession();
- void OnLoggedOut();
- void __cdecl WorkerThread(void*);
+ void RequestMyInfo();
private:
- int SetServerStatus(int);
-
- bool m_bOnline;
- UINT m_hWorkerThread;
+ struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject
+ {
+ ~AsyncHttpRequest()
+ {
+ mir_free(szUrl);
+ }
+
+ VK_REQUEST_HANDLER m_pFunc;
+ time_t m_expireTime;
+ };
+ LIST<AsyncHttpRequest> m_arRequestsQueue;
+ CRITICAL_SECTION m_csRequestsQueue;
+ HANDLE m_evRequestsQueue;
+ HANDLE m_hWorkerThread;
+ bool m_bTerminated;
+
+ void InitQueue();
+ void UninitQueue();
+ void ExecuteRequest(AsyncHttpRequest*);
+ bool PushAsyncHttpRequest(int iRequestType, LPCSTR szUrl, bool bSecure, VK_REQUEST_HANDLER pFunc, int iTimeout = 10000);
+ int SetupConnection(void);
+ void __cdecl WorkerThread(void*);
+
+ void OnLoggedOut();
+ void ShutdownSession();
+
+ void SetAllContactStatuses(int status);
+ int SetServerStatus(int);
+
+ bool m_bOnline;
+
+ HANDLE m_hNetlibUser, m_hNetlibConn;
+ HANDLE hAvatarFolder;
+ ptrA m_szAccessToken;
};
diff --git a/protocols/VKontakte/src/vk_queue.cpp b/protocols/VKontakte/src/vk_queue.cpp new file mode 100644 index 0000000000..9dd6b8b382 --- /dev/null +++ b/protocols/VKontakte/src/vk_queue.cpp @@ -0,0 +1,137 @@ +/*
+Copyright (C) 2013 Miranda NG Project (http://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h"
+
+void CVkProto::InitQueue()
+{
+ ::InitializeCriticalSection(&m_csRequestsQueue);
+ m_evRequestsQueue = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+void CVkProto::UninitQueue()
+{
+ m_arRequestsQueue.destroy();
+ CloseHandle(m_evRequestsQueue);
+ ::DeleteCriticalSection(&m_csRequestsQueue);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CVkProto::SetupConnection()
+{
+ if (m_hNetlibConn != NULL)
+ return TRUE;
+
+ NETLIBOPENCONNECTION nloc = { sizeof(nloc) };
+ nloc.flags = NLOCF_SSL | NLOCF_HTTP | NLOCF_V2;
+ nloc.szHost = VK_API_URL;
+ nloc.wPort = 443;
+ nloc.timeout = 5000;
+ m_hNetlibConn = (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)m_hNetlibUser, (LPARAM)&nloc);
+ return m_hNetlibConn != NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CVkProto::ExecuteRequest(AsyncHttpRequest *pReq)
+{
+ int bytesSent = CallService(MS_NETLIB_SENDHTTPREQUEST, (WPARAM)m_hNetlibConn, (LPARAM)pReq);
+ if (bytesSent > 0) {
+ NETLIBHTTPREQUEST *reply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_RECVHTTPHEADERS, (WPARAM)m_hNetlibConn, 0);
+ if (reply != NULL) {
+ (this->*(pReq->m_pFunc))(reply);
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)reply);
+ }
+ }
+ delete pReq;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static NETLIBHTTPHEADER hdrs[3] =
+{
+ { "Connection", "keep-alive" },
+ { "User-Agent", "Mozilla/4.0 (compatible; MSIE 5.5)" },
+ { "Host", VK_API_URL }
+};
+
+bool CVkProto::PushAsyncHttpRequest(int iRequestType, LPCSTR szUrl, bool bSecure, VK_REQUEST_HANDLER pFunc, int iTimeout)
+{
+ if ( !SetupConnection())
+ return false;
+
+ AsyncHttpRequest *pReq = new AsyncHttpRequest();
+ pReq->cbSize = sizeof(NETLIBHTTPREQUEST);
+ pReq->requestType = iRequestType;
+ pReq->headers = hdrs;
+ pReq->headersCount = SIZEOF(hdrs);
+ pReq->szUrl = mir_strdup(szUrl);
+ pReq->nlc = m_hNetlibConn;
+ pReq->flags = NLHRF_PERSISTENT | NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_NODUMP;
+ if (bSecure)
+ pReq->flags |= NLHRF_SSL;
+ pReq->m_expireTime = time(0) + iTimeout;
+ pReq->m_pFunc = pFunc;
+ {
+ mir_cslock lck(m_csRequestsQueue);
+ m_arRequestsQueue.insert(pReq);
+ }
+ SetEvent(m_evRequestsQueue);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CVkProto::WorkerThread(void*)
+{
+ m_szAccessToken = getStringA("AccessToken");
+ if (m_szAccessToken != NULL)
+ RequestMyInfo();
+ else { // Initialize new OAuth session
+ CMStringA szUrl;
+ szUrl.Format("/oauth/authorize?client_id=%d&scope=%s&redirect_uri=%s&display=wap&response_type=token",
+ VK_APP_ID, "friends,photos,audio,video,wall,messages,offline", VK_REDIRECT_URL);
+ PushAsyncHttpRequest(REQUEST_GET, szUrl, false, &CVkProto::OnOAuthAuthorize);
+ }
+
+ while(true) {
+ DWORD dwRet = WaitForSingleObject(m_evRequestsQueue, 1000);
+ if (dwRet == WAIT_TIMEOUT) {
+ // check expiration;
+ continue;
+ }
+
+ if (dwRet != WAIT_OBJECT_0)
+ continue;
+
+ if (m_bTerminated)
+ break;
+
+ AsyncHttpRequest *pReq;
+ { mir_cslock lck(m_csRequestsQueue);
+ if (m_arRequestsQueue.getCount() == 0)
+ continue;
+
+ pReq = m_arRequestsQueue[0];
+ m_arRequestsQueue.remove(0);
+ }
+ ExecuteRequest(pReq);
+ }
+
+ OnLoggedOut();
+}
diff --git a/protocols/VKontakte/src/vk_thread.cpp b/protocols/VKontakte/src/vk_thread.cpp index dea822ec83..71ee02c2a3 100644 --- a/protocols/VKontakte/src/vk_thread.cpp +++ b/protocols/VKontakte/src/vk_thread.cpp @@ -19,19 +19,27 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. void CVkProto::ShutdownSession()
{
+ if (m_hWorkerThread) {
+ m_bTerminated = true;
+ SetEvent(m_evRequestsQueue);
+ }
+
OnLoggedOut();
}
void CVkProto::OnLoggedOut()
{
+ m_hWorkerThread = 0;
+
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE);
m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
}
-void CVkProto::WorkerThread(void*)
+void CVkProto::OnOAuthAuthorize(NETLIBHTTPREQUEST *reply)
{
- m_hWorkerThread = GetCurrentThreadId();
+}
- OnLoggedOut();
- m_hWorkerThread = 0;
+void CVkProto::RequestMyInfo()
+{
}
+
diff --git a/protocols/VKontakte/vk_10.vcxproj b/protocols/VKontakte/vk_10.vcxproj index 721069ae12..2897473b2e 100644 --- a/protocols/VKontakte/vk_10.vcxproj +++ b/protocols/VKontakte/vk_10.vcxproj @@ -176,6 +176,7 @@ </ClCompile>
<ClCompile Include="src\vk_options.cpp" />
<ClCompile Include="src\vk_proto.cpp" />
+ <ClCompile Include="src\vk_queue.cpp" />
<ClCompile Include="src\vk_thread.cpp" />
</ItemGroup>
<ItemGroup>
diff --git a/protocols/VKontakte/vk_10.vcxproj.filters b/protocols/VKontakte/vk_10.vcxproj.filters index eaf30d69b3..60d0e438ca 100644 --- a/protocols/VKontakte/vk_10.vcxproj.filters +++ b/protocols/VKontakte/vk_10.vcxproj.filters @@ -33,6 +33,9 @@ <ClCompile Include="src\vk_thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\vk_queue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\resource.h">
diff --git a/protocols/VKontakte/vk_11.vcxproj b/protocols/VKontakte/vk_11.vcxproj index b4ec687c4c..afb873f2ed 100644 --- a/protocols/VKontakte/vk_11.vcxproj +++ b/protocols/VKontakte/vk_11.vcxproj @@ -179,6 +179,7 @@ </ClCompile>
<ClCompile Include="src\vk_options.cpp" />
<ClCompile Include="src\vk_proto.cpp" />
+ <ClCompile Include="src\vk_queue.cpp" />
<ClCompile Include="src\vk_thread.cpp" />
</ItemGroup>
<ItemGroup>
diff --git a/protocols/VKontakte/vk_11.vcxproj.filters b/protocols/VKontakte/vk_11.vcxproj.filters index de21e62729..408fc79322 100644 --- a/protocols/VKontakte/vk_11.vcxproj.filters +++ b/protocols/VKontakte/vk_11.vcxproj.filters @@ -33,6 +33,9 @@ <ClCompile Include="src\vk_thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\vk_queue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\version.h">
|