From e37072a0e51cbeda17a10d11fa538e1839ac88b2 Mon Sep 17 00:00:00 2001 From: Cheng Chung Yan Date: Thu, 1 Jun 2023 16:28:38 +0800 Subject: [PATCH] patch for upload existing file at GDrv --- resumableuploadUpdate2.js | 245 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 resumableuploadUpdate2.js diff --git a/resumableuploadUpdate2.js b/resumableuploadUpdate2.js new file mode 100644 index 0000000..0f69107 --- /dev/null +++ b/resumableuploadUpdate2.js @@ -0,0 +1,245 @@ +/** + * ResumableUploadToGoogleDrive for Javascript library + * + * GitHub https://github.com/tanaikech/ResumableUploadForGoogleDrive2_js
+ * In this Class ResumableUploadToGoogleDrive2, the selected file is uploaded by splitting data on the disk. By this, the large file can be uploaded.
+ * + * [Offical Doc - Update](https://developers.google.com/drive/api/reference/rest/v3/files/update) + * [uploads Types](https://developers.google.com/drive/api/guides/manage-uploads) + */ + (function (r) { + let ResumableUploadToGoogleDrive2; + ResumableUploadToGoogleDrive2 = (function () { + function ResumableUploadToGoogleDrive2() { + this.obj = {}; + this.chunkSize = 52428800; + this.endpoint = + "https://www.googleapis.com/upload/drive/v3/files"; + } + + /** + * Run resumable upload a file. + * @param {Object} resource the object for resumable uploading a file. + */ + ResumableUploadToGoogleDrive2.prototype.Do = async function ( + resource, + callback + ) { + callback({ status: "initialize" }, null); + try { + this.obj = await init.call(this, resource); + } catch (err) { + callback(null, err); + return; + } + try { + const head = await getLocation.call(this); + this.location = head.get("location"); + callback({ status: "getLocation" }, null); + callback({ status: "start" }, null); + const fileSize = resource.file.size; + const len = Math.ceil(fileSize / this.chunkSize); + for (let i = 0; i < len; i++) { + let start = i * this.chunkSize; + let end = + fileSize < start + this.chunkSize + ? fileSize + : start + this.chunkSize; + let data = resource.file.slice(start, end); + end -= 1; + callback( + { + status: "Uploading", + progressNumber: { current: i, end: len }, + progressByte: { + current: start, + end: end, + total: fileSize, + }, + }, + null + ); + try { + const res = await getFile.call(this, { + fileSize, + len, + start, + end, + data, + i, + }); + if ( + res.status == "Next" || + (res.status == "Done" && i == len - 1) + ) { + callback(res, null); + } else { + callback(null, "Internal error."); + return; + } + } catch (err) { + callback(null, err); + return; + } + } + } catch (err) { + callback(null, err); + return; + } + }; + + const init = function (resource) { + return new Promise((resolve, reject) => { + if (!("accessToken" in resource) || !("file" in resource)) { + reject({ + Error: + "There are no required parameters. accessToken, fileName, fileSize, fileType and fileBuffer are required.", + }); + return; + } + let object = {}; + object.resource = resource; + if ( + "chunkSize" in resource && + resource.chunkSize >= 262144 && + resource.chunkSize % 262144 == 0 + ) { + this.chunkSize = resource.chunkSize; + } + + // file id for content updating + if ("fileId" in resource && resource.fileId != "") { + this.endpoint += "/" + encodeURIComponent(resource.fileId); + } + + // adding resumable type + // must after fileId + this.endpoint += "?uploadType=resumable"; + + // fields + if ("fields" in resource && resource.fields != "") { + this.endpoint += "&fields=" + encodeURIComponent(resource.fields); + } + + if ("convertToGoogleDocs" in resource && resource.convertToGoogleDocs) { + fetch( + "https://www.googleapis.com/drive/v3/about?fields=importFormats", + { + method: "GET", + headers: { Authorization: "Bearer " + resource.accessToken }, + } + ) + .then((res) => { + if (res.status != 200) { + res.json().then((e) => reject(e)); + return; + } + res.json().then((res) => { + if (resource.file.type in res.importFormats) { + object.resource.fileType = + res.importFormats[resource.fileType][0]; + } + resolve(object); + }); + }) + .catch((err) => { + reject(err); + }); + } else { + resolve(object); + } + }); + }; + + const getLocation = function () { + return new Promise((resolve, reject) => { + const resource = this.obj.resource; + const accessToken = resource.accessToken; + let metadata = { + mimeType: resource.file.type, + name: resource.file.name, + }; + if ("folderId" in resource && resource.folderId != "") { + metadata.addParents = [resource.folderId]; + } + console.log("PATCH 1 "); + fetch(this.endpoint, { + method: "PATCH", + body: JSON.stringify(metadata), + headers: { + Authorization: "Bearer " + accessToken, + "Content-Type": "application/json", + }, + }) + .then((res) => { + if (res.status != 200) { + res.json().then((e) => reject(e)); + return; + } + resolve(res.headers); + }) + .catch((err) => { + reject(err); + }); + }); + }; + + const getFile = function ({ fileSize, len, start, end, data, i }) { + const location = this.location; + return new Promise(function (resolve, reject) { + const fr = new FileReader(); + fr.onload = async function () { + const buf = fr.result; + const obj = { + data: new Uint8Array(buf), + length: end - start + 1, + range: "bytes " + start + "-" + end + "/" + fileSize, + startByte: start, + endByte: end, + total: fileSize, + cnt: i, + totalChunkNumber: len, + }; + await doUpload(obj, location) + .then((res) => resolve(res)) + .catch((err) => reject(err)); + }; + fr.readAsArrayBuffer(data); + }); + }; + + const doUpload = function (e, url) { + return new Promise(function (resolve, reject) { + fetch(url, { + method: "PUT", + body: e.data, + headers: { "Content-Range": e.range }, + }) + .then((res) => { + const status = res.status; + if (status == 308) { + resolve({ status: "Next", result: r }); + } else if (status == 200) { + res.json().then((r) => resolve({ status: "Done", result: r })); + } else { + res.json().then((err) => { + err.additionalInformation = + "When the file size is large, there is the case that the file cannot be converted to Google Docs. Please be careful this."; + reject(err); + return; + }); + return; + } + }) + .catch((err) => { + reject(err); + return; + }); + }); + }; + + return ResumableUploadToGoogleDrive2; + })(); + + return (r.ResumableUploadToGoogleDrive2 = ResumableUploadToGoogleDrive2); +})(this);