summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraunsane <aunsane@gmail.com>2017-04-23 13:50:22 +0300
committeraunsane <aunsane@gmail.com>2017-04-23 13:50:22 +0300
commit3aac528057ce49c8497211a4348df5363af17e1e (patch)
tree2a4c1b8cad10d59bd5fd1682a1d62a6925001abf
parent5048672e81f3ee9aa864ef9d736a3d74da051754 (diff)
CloudFile: implement GDrive upload
-rw-r--r--include/m_http.h2
-rw-r--r--plugins/CloudFile/src/Services/google_api.h44
-rw-r--r--plugins/CloudFile/src/Services/google_service.cpp93
-rw-r--r--plugins/CloudFile/src/Services/google_service.h6
-rw-r--r--plugins/CloudFile/src/cloud_service.cpp2
-rw-r--r--plugins/CloudFile/src/file_transfer.h4
6 files changed, 100 insertions, 51 deletions
diff --git a/include/m_http.h b/include/m_http.h
index 85feebdbb3..297f4e4466 100644
--- a/include/m_http.h
+++ b/include/m_http.h
@@ -42,6 +42,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define HTTP_CODE_PARTIAL_CONTENT 206
#define HTTP_CODE_MULTI_STATUS 207
+#define HTTP_CODE_SUCCESS(code) ((code) <= (HTTP_CODE_MULTI_STATUS) && (code) >= (HTTP_CODE_OK))
+
// 3xx Redirection
#define HTTP_CODE_MULTIPLE_CHOICES 300
#define HTTP_CODE_MOVED_PERMANENTLY 301
diff --git a/plugins/CloudFile/src/Services/google_api.h b/plugins/CloudFile/src/Services/google_api.h
index 7df5446065..a48e9e878b 100644
--- a/plugins/CloudFile/src/Services/google_api.h
+++ b/plugins/CloudFile/src/Services/google_api.h
@@ -4,9 +4,11 @@
namespace GDriveAPI
{
#define GOOGLE_OAUTH "https://accounts.google.com/o/oauth2/v2"
-#define GDRIVE_API "https://www.googleapis.com/drive/v2/files"
+#define GDRIVE_API "https://www.googleapis.com/drive/v3/files"
+#define GDRIVE_UPLOAD "https://www.googleapis.com/upload/drive/v3/files"
+#define GDRIVE_SHARE "https://drive.google.com/open?id=%s"
-#define GOOGLE_APP_ID "271668553802-3sd3tubkf165ibgrqnrhe3id8mcgnaf7.apps.googleusercontent.com"
+#define GOOGLE_APP_ID "528761318515-9hp30q3pcsk7c3qhbajs5ntvi7aiqp0b.apps.googleusercontent.com"
#include "../../../miranda-private-keys/Google/client_secret.h"
class GetAccessTokenRequest : public HttpRequest
@@ -37,25 +39,34 @@ namespace GDriveAPI
class StartUploadFileRequest : public HttpRequest
{
public:
- StartUploadFileRequest(const char *token) :
- HttpRequest(REQUEST_POST, GDRIVE_API)
+ StartUploadFileRequest(const char *token, const char *name) :
+ HttpRequest(REQUEST_POST, GDRIVE_UPLOAD)
{
- AddBearerAuthHeader(token);
- AddHeader("Content-Type", "application/json");
+ AddUrlParameter("access_token=%s", token);
AddUrlParameter("uploadType=resumable");
+
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode params(JSON_NODE);
+ params << JSONNode("name", name);
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
}
};
class UploadFileRequest : public HttpRequest
{
public:
- UploadFileRequest(const char *token, const char *data, size_t size) :
- HttpRequest(REQUEST_POST, GDRIVE_API)
+ UploadFileRequest(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize) :
+ HttpRequest(REQUEST_PUT, uploadUri)
{
- AddBearerAuthHeader(token);
- AddUrlParameter("uploadType=resumable");
+ uint64_t rangeMin = offset;
+ uint64_t rangeMax = offset + chunkSize - 1;
+ CMStringA range(CMStringDataFormat::FORMAT, "bytes %I64u-%I64u/%I64u", rangeMin, rangeMax, fileSize);
+ AddHeader("Content-Range", range);
- SetData(data, size);
+ SetData(chunk, chunkSize);
}
};
@@ -65,7 +76,7 @@ namespace GDriveAPI
CreateFolderRequest(const char *token, const char *path) :
HttpRequest(REQUEST_PUT, GDRIVE_API)
{
- AddBearerAuthHeader(token);
+ AddUrlParameter("access_token=%s", token);
AddHeader("Content-Type", "application/json");
JSONNode params(JSON_NODE);
@@ -78,13 +89,14 @@ namespace GDriveAPI
}
};
- class ShareRequest : public HttpRequest
+ class GrantPermissionsRequest : public HttpRequest
{
public:
- ShareRequest(const char *token, const char *fileId) :
- HttpRequest(REQUEST_PUT, FORMAT, GDRIVE_API "/%s/permissions", fileId)
+ GrantPermissionsRequest(const char *token, const char *fileId) :
+ HttpRequest(REQUEST_POST, FORMAT, GDRIVE_API "/%s/permissions", fileId)
{
- AddBearerAuthHeader(token);
+ AddUrlParameter("access_token=%s", token);
+
AddHeader("Content-Type", "application/json");
JSONNode params(JSON_NODE);
diff --git a/plugins/CloudFile/src/Services/google_service.cpp b/plugins/CloudFile/src/Services/google_service.cpp
index f0185bfbb8..03b4880bd0 100644
--- a/plugins/CloudFile/src/Services/google_service.cpp
+++ b/plugins/CloudFile/src/Services/google_service.cpp
@@ -107,26 +107,46 @@ void CGDriveService::HandleJsonError(JSONNode &node)
}
}
-void CGDriveService::StartUploadFile()
+void CGDriveService::StartUploadFile(char *uploadUri, const char *name)
{
ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
- GDriveAPI::StartUploadFileRequest request(token);
- NLHR_PTR response(request.Send(hConnection));
+ GDriveAPI::StartUploadFileRequest request(token, name);
+ NETLIBHTTPREQUEST* response = request.Send(hConnection);
- GetJsonResponse(response);
+ if (response == NULL)
+ throw Exception(HttpStatusToError());
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ for (int i = 0; i < response->headersCount; i++)
+ {
+ if (mir_strcmpi(response->headers[i].szName, "Location"))
+ continue;
+
+ mir_strcpy(uploadUri, response->headers[i].szValue);
+ return;
+ }
+ }
+
+ if (response->dataLength)
+ throw Exception(response->pData);
+ throw Exception(HttpStatusToError(response->resultCode));
}
-void CGDriveService::UploadFile(const char *url, const char *data, size_t size)
+void CGDriveService::UploadFile(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId)
{
- ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
- GDriveAPI::UploadFileRequest request(token, data, size);
+ GDriveAPI::UploadFileRequest request(uploadUri, chunk, chunkSize, offset, fileSize);
NLHR_PTR response(request.Send(hConnection));
if (response == NULL)
throw Exception(HttpStatusToError());
- if (response->resultCode >= HTTP_CODE_OK &&
- response->resultCode <= HTTP_CODE_MULTIPLE_CHOICES) {
+ if (response->resultCode == HTTP_CODE_PERMANENT_REDIRECT)
+ return;
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ JSONNode root = GetJsonResponse(response);
+ JSONNode id = root.at("id");
+ mir_strcpy(fileId, id.as_string().c_str());
return;
}
@@ -144,15 +164,24 @@ void CGDriveService::CreateFolder(const char *path)
GetJsonResponse(response);
}
-void CGDriveService::CreateSharedLink(const char *path, char *url)
+void CGDriveService::CreateSharedLink(const char *fileId, char *url)
{
ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
- GDriveAPI::ShareRequest request(token, path);
+ GDriveAPI::GrantPermissionsRequest request(token, fileId);
NLHR_PTR response(request.Send(hConnection));
- JSONNode root = GetJsonResponse(response);
- JSONNode link = root.at("href");
- mir_strcpy(url, link.as_string().c_str());
+ if (response == NULL)
+ throw Exception(HttpStatusToError());
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ CMStringA sharedUrl(CMStringDataFormat::FORMAT, GDRIVE_SHARE, fileId);
+ mir_strcpy(url, sharedUrl);
+ return;
+ }
+
+ if (response->dataLength)
+ throw Exception(response->pData);
+ throw Exception(HttpStatusToError(response->resultCode));
}
UINT CGDriveService::Upload(FileTransferParam *ftp)
@@ -181,26 +210,32 @@ UINT CGDriveService::Upload(FileTransferParam *ftp)
const wchar_t *fileName = ftp->GetCurrentRelativeFilePath();
uint64_t fileSize = ftp->GetCurrentFileSize();
- char path[MAX_PATH];
- const wchar_t *serverFolder = ftp->GetServerFolder();
- if (serverFolder) {
- wchar_t serverPath[MAX_PATH] = { 0 };
- mir_snwprintf(serverPath, L"%s\\%s", serverFolder, fileName);
- PreparePath(serverPath, path);
- }
- else
- PreparePath(fileName, path);
- StartUploadFile();
+ uint64_t offset = 0;
+ char fileId[32];
+ char uploadUri[1024];
+ StartUploadFile(uploadUri, T2Utf(fileName));
+
+ size_t chunkSize = ftp->GetCurrentFileChunkSize();
+ mir_ptr<char>chunk((char*)mir_calloc(chunkSize));
- mir_ptr<char>data((char*)mir_calloc(fileSize));
- size_t size = ftp->ReadCurrentFile(data, fileSize);
- UploadFile("", data, size);
+ size_t size = 0;
+ for (size_t i = 0; i < (fileSize / chunkSize); i++)
+ {
+ ftp->CheckCurrentFile();
- ftp->Progress(size);
+ size = ftp->ReadCurrentFile(chunk, chunkSize);
+ if (size == 0)
+ break;
+
+ UploadFile(uploadUri, chunk, size, offset, fileSize, fileId);
+
+ offset += size;
+ ftp->Progress(size);
+ }
if (!wcschr(fileName, L'\\')) {
char url[MAX_PATH];
- CreateSharedLink(path, url);
+ CreateSharedLink(fileId, url);
ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(url)));
}
} while (ftp->NextFile());
diff --git a/plugins/CloudFile/src/Services/google_service.h b/plugins/CloudFile/src/Services/google_service.h
index db72ef9dee..d9c99009c6 100644
--- a/plugins/CloudFile/src/Services/google_service.h
+++ b/plugins/CloudFile/src/Services/google_service.h
@@ -9,10 +9,10 @@ private:
void HandleJsonError(JSONNode &node);
- void StartUploadFile();
- void UploadFile(const char *url, const char *data, size_t size);
+ void StartUploadFile(char *uploadUri, const char *name);
+ void UploadFile(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId);
void CreateFolder(const char *path);
- void CreateSharedLink(const char *path, char *url);
+ void CreateSharedLink(const char *fileId, char *url);
public:
CGDriveService(HNETLIBUSER hConnection);
diff --git a/plugins/CloudFile/src/cloud_service.cpp b/plugins/CloudFile/src/cloud_service.cpp
index 9e57dc14aa..a14af9b821 100644
--- a/plugins/CloudFile/src/cloud_service.cpp
+++ b/plugins/CloudFile/src/cloud_service.cpp
@@ -10,7 +10,7 @@ LIST<CCloudService> Services(10, CompareServices);
void InitServices()
{
Services.insert(new CDropboxService(hNetlibConnection));
- //Services.insert(new CGDriveService(hNetlibConnection));
+ Services.insert(new CGDriveService(hNetlibConnection));
Services.insert(new CYandexService(hNetlibConnection));
PROTOCOLDESCRIPTOR pd = { sizeof(pd) };
diff --git a/plugins/CloudFile/src/file_transfer.h b/plugins/CloudFile/src/file_transfer.h
index 16f515f856..700988eaf4 100644
--- a/plugins/CloudFile/src/file_transfer.h
+++ b/plugins/CloudFile/src/file_transfer.h
@@ -189,9 +189,9 @@ public:
return pfts.currentFileSize;
}
- const uint64_t GetCurrentFileChunkSize() const
+ const size_t GetCurrentFileChunkSize() const
{
- int chunkSize = 1024 * 1024;
+ size_t chunkSize = 1024 * 1024;
if (pfts.currentFileSize < chunkSize)
chunkSize = min(pfts.currentFileSize, chunkSize / 4);
else if (pfts.currentFileSize > 20 * chunkSize)