Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1334)

Unified Diff: native_client_sdk/src/examples/demo/drive/drive.cc

Issue 14500010: [NaCl SDK] Google Drive example (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: native_client_sdk/src/examples/demo/drive/drive.cc
diff --git a/native_client_sdk/src/examples/demo/drive/drive.cc b/native_client_sdk/src/examples/demo/drive/drive.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6b1d44ad08c98a1fec2ebadddb4f92b993dd2489
--- /dev/null
+++ b/native_client_sdk/src/examples/demo/drive/drive.cc
@@ -0,0 +1,634 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/url_loader.h"
+#include "ppapi/cpp/url_request_info.h"
+#include "ppapi/cpp/url_response_info.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi/utility/completion_callback_factory.h"
+
+#include "json/reader.h"
+#include "json/writer.h"
+
+static const char kTokenMessage[] = "token:";
+static const char kGetFileMessage[] = "getFile";
+static const char kBoundary[] = "NACL_BOUNDARY_600673";
+
+
+static std::string EncodeUriComponent(const std::string& s) {
+ char hex[] = "0123456789ABCDEF";
+ std::string result;
+ for (size_t i = 0; i < s.length(); ++i) {
+ char c = s[i];
+ if (isalpha(c) || isdigit(c) || strchr("-_.!~*'()", c)) {
+ result += c;
+ } else {
+ result += '%';
+ result += hex[(c >> 4) & 0xf];
+ result += hex[c & 0xf];
+ }
+ }
+ return result;
+}
+
+static std::string IntToString(int x) {
+ char buffer[32];
+ snprintf(&buffer[0], 32, "%d", x);
+ return &buffer[0];
+}
+
+static void AddQueryParameter(std::string* s,
+ const std::string& key,
+ const std::string& value,
+ bool first) {
+ *s += first ? '?' : '&';
+ *s += EncodeUriComponent(key);
+ *s += '=';
+ *s += EncodeUriComponent(value);
+}
+
+static void AddQueryParameter(std::string* s,
+ const std::string& key,
+ int value,
+ bool first) {
+ AddQueryParameter(s, key, IntToString(value), first);
+}
+
+static void AddAuthTokenHeader(std::string* s, const std::string& auth_token) {
+ *s += "Authorization: Bearer ";
+ *s += auth_token;
+ *s += "\n";
+}
+
+static void AddHeader(std::string* s,
+ const char* key,
+ const std::string& value) {
+ *s += key;
+ *s += ": ";
+ *s += value;
+ *s += "\n";
+}
+
+//
+// UrlReader
+//
+struct UrlReaderParams {
+ std::string url;
+ std::string method;
+ std::string request_headers;
+ std::string request_body;
+};
+
+class UrlReaderDelegate {
+ public:
+ virtual void OnReadSucceeded(const std::string& output) = 0;
+ virtual void OnReadFailed(int32_t result) = 0;
+};
+
+class UrlReader {
+ public:
+ static UrlReader* Create(pp::Instance* instance,
+ const UrlReaderParams& params,
+ UrlReaderDelegate* delegate);
+ ~UrlReader();
+
+ void Run();
+
+ private:
+ UrlReader(pp::Instance* instance,
+ const UrlReaderParams& params,
+ UrlReaderDelegate* delegate);
+
+ static const int32_t kReadBufferSize = 16 * 1024;
+
+ void InitRequestInfo();
+ void OnOpen(int32_t result);
+ void ReadBody();
+ void OnRead(int32_t result);
+ void AppendDataBytes(int32_t num_bytes);
+
+ void Success();
+ void Failure(int32_t result);
+
+ pp::Instance* instance_; // Weak pointer.
+ pp::URLRequestInfo url_request_;
+ pp::URLLoader url_loader_;
+ pp::CompletionCallbackFactory<UrlReader> cc_factory_;
+ UrlReaderParams params_;
+ UrlReaderDelegate* delegate_; // Weak pointer.
+
+ uint8_t* buffer_;
+ std::string response_body_;
+};
+
+// static
+UrlReader* UrlReader::Create(pp::Instance* instance,
+ const UrlReaderParams& params,
+ UrlReaderDelegate* delegate) {
+ return new UrlReader(instance, params, delegate);
+}
+
+UrlReader::UrlReader(pp::Instance* instance,
+ const UrlReaderParams& params,
+ UrlReaderDelegate* delegate)
+ : instance_(instance),
+ url_request_(instance),
+ url_loader_(instance),
+ cc_factory_(this),
+ params_(params),
+ delegate_(delegate),
+ buffer_(new uint8_t[kReadBufferSize]) {}
+
+UrlReader::~UrlReader() { delete[] buffer_; }
+
+void UrlReader::Run() {
+ InitRequestInfo();
+ pp::CompletionCallback cc = cc_factory_.NewCallback(&UrlReader::OnOpen);
+ url_loader_.Open(url_request_, cc);
+}
+
+void UrlReader::InitRequestInfo() {
+ url_request_.SetURL(params_.url);
+ url_request_.SetMethod(params_.method);
+ url_request_.SetHeaders(params_.request_headers);
+ url_request_.SetRecordDownloadProgress(true);
+ if (params_.request_body.size()) {
+ url_request_.AppendDataToBody(params_.request_body.data(),
+ params_.request_body.size());
+ }
+}
+
+void UrlReader::OnOpen(int32_t result) {
+ if (result != PP_OK)
+ return Failure(result);
+
+ pp::URLResponseInfo url_response = url_loader_.GetResponseInfo();
+ if (url_response.GetStatusCode() != 200)
+ return Failure(PP_ERROR_FAILED);
+
+ int64_t bytes_received = 0;
+ int64_t total_bytes_to_be_received = 0;
+ if (url_loader_.GetDownloadProgress(&bytes_received,
+ &total_bytes_to_be_received)) {
+ if (total_bytes_to_be_received > 0) {
+ response_body_.reserve(total_bytes_to_be_received);
+ }
+ }
+
+ url_request_.SetRecordDownloadProgress(false);
+ ReadBody();
+}
+
+void UrlReader::ReadBody() {
+ pp::CompletionCallback cc =
+ cc_factory_.NewOptionalCallback(&UrlReader::OnRead);
+ int32_t result = PP_OK;
+ do {
+ result = url_loader_.ReadResponseBody(buffer_, kReadBufferSize, cc);
+ if (result > 0) {
+ AppendDataBytes(result);
+ }
+ } while (result > 0);
+
+ if (result != PP_OK_COMPLETIONPENDING) {
+ cc.Run(result);
+ }
+}
+
+void UrlReader::OnRead(int32_t result) {
+ if (result < 0)
+ return Failure(result);
+
+ if (result == 0) {
+ Success();
+ } else if (result > 0) {
+ AppendDataBytes(result);
+ ReadBody();
+ }
+}
+
+void UrlReader::AppendDataBytes(int32_t num_bytes) {
+ num_bytes = num_bytes > kReadBufferSize ? kReadBufferSize : num_bytes;
+ response_body_.insert(response_body_.end(), buffer_, buffer_ + num_bytes);
+}
+
+void UrlReader::Success() {
+ delegate_->OnReadSucceeded(response_body_);
+ delete this;
+}
+
+void UrlReader::Failure(int32_t result) {
+ delegate_->OnReadFailed(result);
+ delete this;
+}
+
+//
+// FilesList
+//
+struct FilesListParams {
+ int max_results;
+ std::string page_token;
+ std::string q;
+};
+
+class FilesListDelegate {
+ public:
+ virtual void OnFilesListSucceeded(const Json::Value& url) = 0;
+ virtual void OnFilesListFailed(int32_t result) = 0;
+};
+
+class FilesList : public UrlReaderDelegate {
+ public:
+ static FilesList* Create(pp::Instance* instance,
+ const std::string& auth_token,
+ const FilesListParams& params,
+ FilesListDelegate* delegate);
+ ~FilesList();
+
+ void Run();
+ virtual void OnReadSucceeded(const std::string& output);
+ virtual void OnReadFailed(int32_t result);
+
+ private:
+ FilesList(pp::Instance* instance,
+ const std::string& auth_token,
+ const FilesListParams& params,
+ FilesListDelegate* delegate);
+
+ pp::Instance* instance_; // Weak pointer.
+ std::string auth_token_;
+ FilesListParams params_;
+ FilesListDelegate* delegate_; // Weak pointer.
+};
+
+// static
+FilesList* FilesList::Create(pp::Instance* instance,
+ const std::string& auth_token,
+ const FilesListParams& params,
+ FilesListDelegate* delegate) {
+ return new FilesList(instance, auth_token, params, delegate);
+}
+
+FilesList::FilesList(pp::Instance* instance,
+ const std::string& auth_token,
+ const FilesListParams& params,
+ FilesListDelegate* delegate)
+ : instance_(instance),
+ auth_token_(auth_token),
+ params_(params),
+ delegate_(delegate) {}
+
+FilesList::~FilesList() {}
+
+void FilesList::Run() {
+ static const char base_url[] = "https://www.googleapis.com/drive/v2/files";
+
+ UrlReaderParams p;
+ p.method = "GET";
+ p.url = base_url;
+ AddQueryParameter(&p.url, "maxResults", params_.max_results, true);
+ if (params_.page_token.length())
+ AddQueryParameter(&p.url, "pageToken", params_.page_token, false);
+ AddQueryParameter(&p.url, "q", params_.q, false);
+ AddAuthTokenHeader(&p.request_headers, auth_token_);
+ UrlReader* url_reader = UrlReader::Create(instance_, p, this);
+ url_reader->Run();
+}
+
+void FilesList::OnReadSucceeded(const std::string& output) {
+ Json::Reader reader(Json::Features::strictMode());
+ Json::Value value;
+ if (!reader.parse(output, value, false)) {
+ printf("Couldn't parse JSON!\n");
+ delegate_->OnFilesListFailed(PP_ERROR_FAILED);
+ delete this;
+ }
+
+ delegate_->OnFilesListSucceeded(value);
+ delete this;
+}
+
+void FilesList::OnReadFailed(int32_t result) {
+ delegate_->OnFilesListFailed(result);
+ delete this;
+}
+
+//
+// FilesInsert
+//
+struct FilesInsertParams {
+ std::string file_id;
+ std::string content;
+ std::string description;
+ std::string mime_type;
+ std::string title;
+};
+
+class FilesInsertDelegate {
+ public:
+ virtual void OnFilesInsertSucceeded(const Json::Value& url) = 0;
+ virtual void OnFilesInsertFailed(int32_t result) = 0;
+};
+
+class FilesInsert : public UrlReaderDelegate {
+ public:
+ static FilesInsert* Create(pp::Instance* instance,
+ const std::string& auth_token,
+ const FilesInsertParams& params,
+ FilesInsertDelegate* delegate);
+ ~FilesInsert();
+
+ void Run();
+ virtual void OnReadSucceeded(const std::string& output);
+ virtual void OnReadFailed(int32_t result);
+
+ private:
+ FilesInsert(pp::Instance* instance,
+ const std::string& auth_token,
+ const FilesInsertParams& params,
+ FilesInsertDelegate* delegate);
+
+ std::string BuildRequestBody();
+
+ pp::Instance* instance_; // Weak pointer.
+ std::string auth_token_;
+ FilesInsertParams params_;
+ FilesInsertDelegate* delegate_; // Weak pointer.
+};
+
+// static
+FilesInsert* FilesInsert::Create(pp::Instance* instance,
+ const std::string& auth_token,
+ const FilesInsertParams& params,
+ FilesInsertDelegate* delegate) {
+ return new FilesInsert(instance, auth_token, params, delegate);
+}
+
+FilesInsert::FilesInsert(pp::Instance* instance,
+ const std::string& auth_token,
+ const FilesInsertParams& params,
+ FilesInsertDelegate* delegate)
+ : instance_(instance),
+ auth_token_(auth_token),
+ params_(params),
+ delegate_(delegate) {}
+
+FilesInsert::~FilesInsert() {}
+
+void FilesInsert::Run() {
+ static const char base_url[] =
+ "https://www.googleapis.com/upload/drive/v2/files";
+ const char* method = "POST";
+
+ UrlReaderParams p;
+ p.url = base_url;
+
+ // If file_id is defined, we are actually updating an existing file.
+ if (!params_.file_id.empty()) {
+ p.url += "/";
+ p.url += params_.file_id;
+ p.method = "PUT";
+ } else {
+ p.method = "POST";
+ }
+
+ AddQueryParameter(&p.url, "uploadType", "multipart", true);
+ AddAuthTokenHeader(&p.request_headers, auth_token_);
+ AddHeader(&p.request_headers,
+ "Content-Type",
+ std::string("multipart/related; boundary=") + kBoundary + "\n");
+ p.request_body = BuildRequestBody();
+ UrlReader* url_reader = UrlReader::Create(instance_, p, this);
+ url_reader->Run();
+}
+
+void FilesInsert::OnReadSucceeded(const std::string& output) {
+ Json::Reader reader(Json::Features::strictMode());
+ Json::Value value;
+ if (!reader.parse(output, value, false)) {
+ printf("Couldn't parse JSON!\n");
+ delegate_->OnFilesInsertFailed(PP_ERROR_FAILED);
+ delete this;
+ }
+
+ delegate_->OnFilesInsertSucceeded(value);
+ delete this;
+}
+
+void FilesInsert::OnReadFailed(int32_t result) {
+ delegate_->OnFilesInsertFailed(result);
+ delete this;
+}
+
+std::string FilesInsert::BuildRequestBody() {
+ std::string result;
+ result += "--";
+ result += kBoundary;
+ result += "\nContent-Type: application/json; charset=UTF-8\n\n";
+
+ Json::Value value(Json::objectValue);
+ value["description"] = Json::Value(params_.description);
+ value["mimeType"] = Json::Value(params_.mime_type);
+ value["title"] = Json::Value(params_.title);
+ Json::FastWriter writer;
+ std::string metadata = writer.write(value);
+
+ result += metadata;
+ result += "--";
+ result += kBoundary;
+ result += "\nContent-Type: ";
+ result += params_.mime_type;
+ result += "\n\n";
+ result += params_.content;
+ result += "\n--";
+ result += kBoundary;
+ result += "--";
+ return result;
+}
+
+//
+// Instance
+//
+class Instance : public pp::Instance,
+ public UrlReaderDelegate,
+ public FilesListDelegate,
+ public FilesInsertDelegate {
+ public:
+ explicit Instance(PP_Instance instance);
+ virtual ~Instance();
+ virtual void HandleMessage(const pp::Var& var_message);
+
+ virtual void OnFilesListSucceeded(const Json::Value& root);
+ virtual void OnFilesListFailed(int32_t result);
+
+ virtual void OnReadSucceeded(const std::string& output);
+ virtual void OnReadFailed(int32_t result);
+
+ virtual void OnFilesInsertSucceeded(const Json::Value& root);
+ virtual void OnFilesInsertFailed(int32_t result);
+
+ private:
+ bool GetFirstItemStringValue(const Json::Value& root,
+ const char* key,
+ std::string* out);
+ void GetFileMetadata(const char* title);
+ void DownloadFile(const std::string& download_url);
+ void InsertFile(const char* title,
+ const char* description,
+ const char* content);
+
+ std::string auth_token_;
+};
+
+Instance::Instance(PP_Instance instance) : pp::Instance(instance) {}
+
+Instance::~Instance() {}
+
+void Instance::HandleMessage(const pp::Var& var_message) {
+ if (!var_message.is_string()) {
+ return;
+ }
+
+ std::string message = var_message.AsString();
+ if (!strncmp(message.c_str(), kTokenMessage, strlen(kTokenMessage))) {
+ // Auth token
+ auth_token_ = message.c_str() + strlen(kTokenMessage);
+ printf("Auth token: %s\n", auth_token_.c_str());
+ } else if (!strncmp(
+ message.c_str(), kGetFileMessage, strlen(kGetFileMessage))) {
+ // getFile
+ printf("Getting file...\n");
+ GetFileMetadata("hello nacl.txt");
+ }
+}
+
+void Instance::OnFilesListSucceeded(const Json::Value& root) {
+ // Extract the download URL...
+ std::string download_url;
+ if (GetFirstItemStringValue(root, "downloadUrl", &download_url)) {
+ // Read the file...
+ printf("got a download url: %s\n", download_url.c_str());
+ DownloadFile(download_url);
+ } else {
+ // Insert a new file instead!
+ InsertFile(
+ "hello nacl.txt", "A file generated by NaCl!", "Hello, Google Drive!");
+ }
+}
+
+void Instance::OnFilesListFailed(int32_t result) {
+ printf("drive.files.list failed with result %d\n", result);
+}
+
+void Instance::OnReadSucceeded(const std::string& output) {
+ PostMessage(output);
+}
+
+void Instance::OnReadFailed(int32_t result) {
+ printf("Reading download URL failed with result %d\n", result);
+}
+
+void Instance::OnFilesInsertSucceeded(const Json::Value& root) {
+ // Extract the download URL...
+ std::string download_url;
+ if (GetFirstItemStringValue(root, "downloadUrl", &download_url)) {
+ // Read the file...
+ printf("got a download url: %s\n", download_url.c_str());
+ DownloadFile(download_url);
+ } else {
+ printf("Inserted a file, but it doesn't have a downloadUrl?\n");
+ }
+}
+
+void Instance::OnFilesInsertFailed(int32_t result) {
+ printf("Inserting file failed with result %d\n", result);
+}
+
+bool Instance::GetFirstItemStringValue(const Json::Value& root,
+ const char* key,
+ std::string* out) {
+ if (!root.isMember("items")) {
+ printf("No items...\n");
+ return false;
+ }
+
+ Json::Value items = root["items"];
+ if (!items.isValidIndex(0)) {
+ printf("Expected items[0] to be valid.\n");
+ return false;
+ }
+
+ Json::Value first_item = items[0U];
+ if (!first_item.isMember(key)) {
+ printf("Expected items[0].%s to be valid.\n", key);
+ return false;
+ }
+
+ Json::Value value = first_item[key];
+ if (!value.isString()) {
+ printf("Expected items[0].%s to be a string.\n", key);
+ return false;
+ }
+
+ *out = value.asString();
+ return true;
+}
+
+void Instance::GetFileMetadata(const char* filename) {
+ FilesListParams p;
+ p.max_results = 1;
+ p.q = "title = \'";
+ p.q += filename;
+ p.q += "\'";
+ FilesList* func = FilesList::Create(this, auth_token_, p, this);
+ func->Run();
+}
+
+void Instance::InsertFile(const char* title,
+ const char* description,
+ const char* content) {
+ FilesInsertParams p;
+ p.content = content;
+ p.description = description;
+ p.mime_type = "text/plain";
+ p.title = title;
+ FilesInsert* func = FilesInsert::Create(this, auth_token_, p, this);
+ func->Run();
+}
+
+void Instance::DownloadFile(const std::string& download_url) {
+ UrlReaderParams p;
+ p.method = "GET";
+ p.url = download_url;
+ AddAuthTokenHeader(&p.request_headers, auth_token_);
+ UrlReader* url_reader = UrlReader::Create(this, p, this);
+ url_reader->Run();
+}
+
+class Module : public pp::Module {
+ public:
+ Module() : pp::Module() {}
+ virtual ~Module() {}
+
+ virtual pp::Instance* CreateInstance(PP_Instance instance) {
+ return new Instance(instance);
+ }
+};
+
+namespace pp {
+
+Module* CreateModule() { return new ::Module(); }
+
+} // namespace pp

Powered by Google App Engine
This is Rietveld 408576698