/// <summary> /// Validate the token and get informations. /// </summary> /// <param name="accessToken">Access token.</param> /// <returns>TokenInfoResponse or Exception for error</returns> static IEnumerator ValidateToken(string accessToken) { var request = new UnityWebRequest( "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + accessToken); var response = request.GetResponse(); while (!response.isDone) yield return null; if (response.error != null) { yield return response.error; yield break; } JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) { yield return new Exception(-1, "TokenInfo response parsing failed."); yield break; } yield return new TokenInfoResponse(json); }
/// <summary> /// Revoke a access token. /// </summary> /// <param name="token">Access token.</param> /// <returns>RevokeResponse or Exception for error.</returns> static IEnumerator RevokeToken(string token) { var request = new UnityWebRequest( "https://accounts.google.com/o/oauth2/revoke?token=" + token); var response = request.GetResponse(); while (!response.isDone) yield return null; if (response.error != null) { yield return response.error; yield break; } JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) // no response is success. yield return new RevokeResponse(); // error is null. else yield return new RevokeResponse(json); }
public UnityWebResponse(UnityWebRequest request) { ThreadPool.QueueUserWorkItem((arg) => { try { int redirection = 0; TcpClient client = new TcpClient(); Uri uri = request.uri; client.Connect(uri.Host, uri.Port); bool newConnection = true; Stream stream = null; do { #region Get stream if (newConnection) { client.SendTimeout = TIMEOUT; client.ReceiveTimeout = TIMEOUT; stream = client.GetStream(); if (uri.Scheme == "https") { stream = new SslStream(stream, false, new RemoteCertificateValidationCallback((sender, cert, chain, error) => true)); (stream as SslStream).AuthenticateAsClient(uri.Host); } } #endregion #region Request { BinaryWriter writer = new BinaryWriter(stream); writer.Write(Encoding.UTF8.GetBytes(request.method + " " + uri.PathAndQuery + " " + request.protocol + "\r\n")); request.headers["Host"] = uri.Host; foreach (DictionaryEntry kv in request.headers) { if (kv.Key is string && kv.Value is string) { writer.Write(Encoding.UTF8.GetBytes(kv.Key + ": " + kv.Value + "\r\n")); } else if (kv.Key is string && kv.Value is string[]) { for (int i = 0; i < (kv.Value as string[]).Length; i++) { writer.Write(Encoding.UTF8.GetBytes(kv.Key + ": " + (kv.Value as string[])[i] + "\r\n")); } } } if (request.body != null) { writer.Write(Encoding.UTF8.GetBytes("Content-Length:" + request.body.Length + "\r\n\r\n")); writer.Write(request.body); } else { writer.Write(Encoding.UTF8.GetBytes("\r\n")); } } #endregion #region Response { BufferedStream bufferedStream = new BufferedStream(stream); #region Read headers { List<string> lines = new List<string>(); do { string line = ReadLine(bufferedStream); if (line.Length == 0) break; lines.Add(line); } while (true); string[] statusLine = lines[0].Split(' '); this.httpVersion = statusLine[0]; this.statusCode = int.Parse(statusLine[1]); this.reasonPhrase = string.Join(" ", statusLine, 2, statusLine.Length - 2); this.headers = new Hashtable(); for (int i = 1; i < lines.Count; i++) { string k = lines[i].Substring(0, lines[i].IndexOf(':')).Trim(); string v = lines[i].Substring(lines[i].IndexOf(':') + 1).Trim(); if (!this.headers.ContainsKey(k)) { this.headers.Add(k, v); } else { if (this.headers[k] is string) { string a = this.headers[k] as string; string[] b = { a, v }; this.headers[k] = b; } else if (this.headers[k] is string[]) { string[] a = this.headers[k] as string[]; string[] b = new string[a.Length + 1]; a.CopyTo(b, 0); b[a.Length - 1] = v; this.headers[k] = b; } } } } #endregion //UnityEngine.Debug.Log(DumpHeaders() + // "\r\n" + // "----"); #region Read body { int contentLength = -1; if (this.headers.ContainsKey("Content-Length")) contentLength = int.Parse(this.headers["Content-Length"] as string); string transferEncoding = null; if (this.headers.ContainsKey("Transfer-Encoding")) transferEncoding = (this.headers["Transfer-Encoding"] as string).ToLower(); if (contentLength >= 0) { this.bytes = new byte[contentLength]; int bytesReceived = 0; while (bytesReceived < contentLength) { bytesReceived += bufferedStream.Read(this.bytes, bytesReceived, this.bytes.Length - bytesReceived); } } else if (transferEncoding == "chunked") { MemoryStream ms = new MemoryStream(4096); byte[] buffer = new byte[4096]; do { string chunkSizeString = ReadLine(bufferedStream); if (chunkSizeString.Length == 0) break; int chunkSize = Convert.ToInt32(chunkSizeString, 16); if (chunkSize == 0) break; int bytesReceived = 0; while (bytesReceived < chunkSize) { int read = bufferedStream.Read(buffer, 0, chunkSize - bytesReceived < buffer.Length ? chunkSize - bytesReceived : buffer.Length); ms.Write(buffer, 0, read); bytesReceived += read; } bufferedStream.ReadByte(); // \r bufferedStream.ReadByte(); // \n } while (true); this.bytes = ms.ToArray(); ms.Dispose(); } else { MemoryStream ms = new MemoryStream(4096); byte[] buffer = new byte[4096]; int read = 0; do { read = bufferedStream.Read(buffer, 0, buffer.Length); ms.Write(buffer, 0, read); } while (read > 0); this.bytes = ms.ToArray(); ms.Dispose(); } cachedText = null; } #endregion #region Redirection if ((this.statusCode == 301 || this.statusCode == 302 || this.statusCode == 303 || this.statusCode == 307) && this.headers.ContainsKey("Location") && redirection < MAX_REDIRECTION) { string oldHost = uri.Host; string location = this.headers["Location"] as string; uri = new Uri(uri, location); if (oldHost != uri.Host) { stream.Close(); client.Close(); client = new TcpClient(); client.Connect(uri.Host, uri.Port); newConnection = true; } else newConnection = false; redirection++; continue; } #endregion #region Decoding if (this.headers.ContainsKey("Content-Encoding")) { bytes = Decompress((this.headers["Content-Encoding"] as string).ToLower(), bytes); } #endregion #if UNITY_EDITOR // test--- UnityEngine.Debug.LogWarning(request.DumpHeaders() + (request.body == null ? "" : "Content-Length: " + request.body.Length + "\r\n") + "\r\n" + (request.body == null ? "" : Encoding.UTF8.GetString(request.body))); UnityEngine.Debug.LogWarning(DumpHeaders() + "\r\n" + this.text); #endif } #endregion stream.Close(); client.Close(); break; } while (redirection < MAX_REDIRECTION); } catch (Exception e) { error = e; } finally { isDone = true; } }); }
/// <summary> /// Upload a file. /// </summary> /// <param name="file">File metadata.</param> /// <param name="data">Data.</param> /// <returns>AsyncSuccess with File or Exception for error.</returns> /// <example> /// Upload a file to the root folder. /// <code> /// var bytes = Encoding.UTF8.GetBytes("world!"); /// /// var file = new GoogleDrive.File(new Dictionary<string, object> /// { /// { "title", "hello.txt" }, /// { "mimeType", "text/plain" }, /// }); /// /// StartCoroutine(drive.UploadFile(file, bytes)); /// </code> /// Update the file content. /// <code> /// var listFiles = drive.ListFilesByQueary("title = 'a.txt'"); /// yield return StartCoroutine(listFiles); /// /// var files = GoogleDrive.GetResult<List<GoogleDrive.File>>(listFiles); /// if (files != null && files.Count > 0) /// { /// var bytes = Encoding.UTF8.GetBytes("new content."); /// StartCoroutine(drive.UploadFile(files[0], bytes)); /// } /// </code> /// </example> public IEnumerator UploadFile(File file, byte[] data) { #region Check the access token is expired var check = CheckExpiration(); while (check.MoveNext()) yield return null; if (check.Current is Exception) { yield return check.Current; yield break; } #endregion string uploadUrl = null; // Start a resumable session. if (file.ID == null || file.ID == string.Empty) { var request = new UnityWebRequest( "https://www.googleapis.com/upload/drive/v2/files?uploadType=resumable"); request.method = "POST"; request.headers["Authorization"] = "Bearer " + AccessToken; request.headers["Content-Type"] = "application/json"; request.headers["X-Upload-Content-Type"] = file.MimeType; request.headers["X-Upload-Content-Length"] = data.Length; string metadata = JsonWriter.Serialize(file.ToJSON()); request.body = Encoding.UTF8.GetBytes(metadata); var response = new UnityWebResponse(request); while (!response.isDone) yield return null; if (response.statusCode != 200) { JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) { yield return new Exception(-1, "UploadFile response parsing failed."); yield break; } else if (json.ContainsKey("error")) { yield return GetError(json); yield break; } } // Save the resumable session URI. uploadUrl = response.headers["Location"] as string; } else { uploadUrl = "https://www.googleapis.com/upload/drive/v2/files/" + file.ID; } // Upload the file. { var request = new UnityWebRequest(uploadUrl); request.method = "PUT"; request.headers["Authorization"] = "Bearer " + AccessToken; request.headers["Content-Type"] = "application/octet-stream"; // file.MimeType; request.body = data; var response = new UnityWebResponse(request); while (!response.isDone) yield return null; JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) { yield return new Exception(-1, "UploadFile response parsing failed."); yield break; } else if (json.ContainsKey("error")) { yield return GetError(json); yield break; } yield return new AsyncSuccess(new File(json)); } }
/// <summary> /// Download a file content. /// </summary> /// <param name="file">Download URL.</param> /// <returns>AsyncSuccess with byte[] or Exception for error.</returns> /// <example> /// Download the thumbnail image. /// <code> /// if (file.ThumbnailLink != null) /// { /// var download = drive.DownloadFile(file.ThumbnailLink); /// yield return StartCoroutine(drive); /// /// var data = GoogleDrive.GetResult<byte[]>(download); /// if (data != null) /// someTexture.LoadImage(data); /// } /// </code> /// </example> public IEnumerator DownloadFile(string url) { #region Check the access token is expired var check = CheckExpiration(); while (check.MoveNext()) yield return null; if (check.Current is Exception) { yield return check.Current; yield break; } #endregion var request = new UnityWebRequest(url); request.headers["Authorization"] = "Bearer " + AccessToken; var response = new UnityWebResponse(request); while (!response.isDone) yield return null; yield return new AsyncSuccess(response.bytes); }
/// <summary> /// Duplicate a file. /// </summary> /// <param name="file">File to duplicate.</param> /// <param name="newFile">New file data.</param> /// <returns>AsyncSuccess with File or Exception for error.</returns> /// <example> /// Copy 'someFile' to 'newFile'. /// <code> /// var newFile = new GoogleDrive.File(new Dictionary<string, object> /// { /// { "title", someFile.Title + "(2)" }, /// { "mimeType", someFile.MimeType }, /// }); /// newFile.Parents = new List<string> { newParentFolder.ID }; /// /// StartCoroutine(drive.DuplicateFile(someFile, newFile)); /// </code> /// </example> IEnumerator DuplicateFile(File file, File newFile) { #region Check the access token is expired var check = CheckExpiration(); while (check.MoveNext()) yield return null; if (check.Current is Exception) { yield return check.Current; yield break; } #endregion var request = new UnityWebRequest("https://www.googleapis.com/drive/v2/files/" + file.ID + "/copy"); request.method = "POST"; request.headers["Authorization"] = "Bearer " + AccessToken; request.headers["Content-Type"] = "application/json"; string metadata = JsonWriter.Serialize(newFile.ToJSON()); request.body = Encoding.UTF8.GetBytes(metadata); var response = new UnityWebResponse(request); while (!response.isDone) yield return null; JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) { yield return new Exception(-1, "DuplicateFile response parsing failed."); yield break; } else if (json.ContainsKey("error")) { yield return GetError(json); yield break; } yield return new AsyncSuccess(new File(json)); }
/// <summary> /// Touch a file(or folder). /// </summary> /// <param name="file">File to touch.</param> /// <returns>AsyncSuccess with File or Exception for error.</returns> /// <example> /// <code> /// StartCoroutine(drive.TouchFile(someFile)); /// </code> /// </example> public IEnumerator TouchFile(File file) { #region Check the access token is expired var check = CheckExpiration(); while (check.MoveNext()) yield return null; if (check.Current is Exception) { yield return check.Current; yield break; } #endregion var request = new UnityWebRequest("https://www.googleapis.com/drive/v2/files/" + file.ID + "/touch"); request.method = "POST"; request.headers["Authorization"] = "Bearer " + AccessToken; request.body = new byte[0]; // with no data var response = new UnityWebResponse(request); while (!response.isDone) yield return null; JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) { yield return new Exception(-1, "TouchFile response parsing failed."); yield break; } else if (json.ContainsKey("error")) { yield return GetError(json); yield break; } yield return new AsyncSuccess(new File(json)); }
/// <summary> /// Delete a file(or folder). /// </summary> /// <param name="file">File.</param> /// <returns>AsyncSuccess or Exception for error.</returns> /// <example> /// Delete all files. /// <code> /// var listFiles = drive.ListAllFiles(); /// yield return StartCoroutine(listFiles); /// var files = GoogleDrive.GetResult<List<GoogleDrive.File>>(listFiles); /// /// if (files != null) /// { /// for (int i = 0; i < files.Count; i++) /// yield return StartCoroutine(drive.DeleteFile(files[i])); /// } /// </code> /// </example> public IEnumerator DeleteFile(File file) { #region Check the access token is expired var check = CheckExpiration(); while (check.MoveNext()) yield return null; if (check.Current is Exception) { yield return check.Current; yield break; } #endregion var request = new UnityWebRequest("https://www.googleapis.com/drive/v2/files/" + file.ID); request.method = "DELETE"; request.headers["Authorization"] = "Bearer " + AccessToken; var response = new UnityWebResponse(request); while (!response.isDone) yield return null; // If successful, empty response. JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json != null && json.ContainsKey("error")) { yield return GetError(json); yield break; } yield return new AsyncSuccess(); }
public IEnumerator ListFilesByQueary(string query) { #region Check the access token is expired var check = CheckExpiration(); while (check.MoveNext()) yield return null; if (check.Current is Exception) { yield return check.Current; yield break; } #endregion var request = new UnityWebRequest( new Uri("https://www.googleapis.com/drive/v2/files?q=" + query)); request.headers["Authorization"] = "Bearer " + AccessToken; var response = new UnityWebResponse(request); while (!response.isDone) yield return null; JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) { yield return new Exception(-1, "ListFiles response parsing failed."); yield break; } else if (json.ContainsKey("error")) { yield return GetError(json); yield break; } // parsing var results = new List<File>(); if (json.ContainsKey("items") && json["items"] is Dictionary<string, object>[]) { var items = json["items"] as Dictionary<string, object>[]; foreach (var item in items) { results.Add(new File(item)); } } yield return new AsyncSuccess(results); }
/// <summary> /// Get the access code by the refresh token. /// </summary> /// <param name="refreshToken">Refresh token.</param> /// <returns>TokenResponse or Exception for error.</returns> IEnumerator GetAccessTokenByRefreshToken(string refreshToken) { var request = new UnityWebRequest("https://accounts.google.com/o/oauth2/token"); request.method = "POST"; request.headers["Content-Type"] = "application/x-www-form-urlencoded"; request.body = Encoding.UTF8.GetBytes(string.Format( "client_id={0}&" + "client_secret={1}&" + "refresh_token={2}&" + "grant_type=refresh_token", ClientID, ClientSecret, refreshToken)); var response = request.GetResponse(); while (!response.isDone) yield return null; if (response.error != null) { yield return response.error; yield break; } JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) { yield return new Exception(-1, "RefreshToken response parsing failed."); yield break; } yield return new TokenResponse(json); }
/// <summary> /// Insert a folder to otehr folder. /// </summary> /// <param name="parentFolder">Parent folder.</param> /// <returns>AsyncSuccess with File or Exception for error.</returns> /// <example> /// <code> /// var insert = drive.InsertFolder("new_folder_in_appdata", drive.AppData); /// yield return StartCoroutine(insert); /// </code> /// </example> public IEnumerator InsertFolder(string title, File parentFolder) { #region Check the access token is expired var check = CheckExpiration(); while (check.MoveNext()) yield return null; if (check.Current is Exception) { yield return check.Current; yield break; } #endregion var request = new UnityWebRequest("https://www.googleapis.com/drive/v2/files"); request.method = "POST"; request.headers["Authorization"] = "Bearer " + AccessToken; request.headers["Content-Type"] = "application/json"; Dictionary<string, object> data = new Dictionary<string, object>(); data["title"] = title; data["mimeType"] = "application/vnd.google-apps.folder"; if (parentFolder != null) { data["parents"] = new List<Dictionary<string, string>> { new Dictionary<string, string> { { "id", parentFolder.ID } }, }; } request.body = Encoding.UTF8.GetBytes(JsonWriter.Serialize(data)); var response = new UnityWebResponse(request); while (!response.isDone) yield return null; JsonReader reader = new JsonReader(response.text); var json = reader.Deserialize<Dictionary<string, object>>(); if (json == null) { yield return new Exception(-1, "InsertFolder response parsing failed."); yield break; } else if (json.ContainsKey("error")) { yield return GetError(json); yield break; } yield return new AsyncSuccess(new File(json)); }