├── README.md
├── app.js
├── cari.js
├── cari.png
├── custom.css
├── go-drive-logo.png
├── ss.jpg
└── worker.js
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ## Source
4 | Origin https://github.com/donwa/goindex
5 | Dark Theme & Search https://github.com/ParveenBhadooOfficial/go-drive
6 |
7 |
8 | ## Quick Deployment
9 | 1. Open https://installen.gd.workers.dev
10 | 2. Auth and get the refresh_token and paste on line 8 or just copy the full code and paste in Cloudflare workers.
11 | 3. Deploy the code to [Cloudflare Workers](https://www.cloudflare.com/workers)
12 |
13 | 
14 |
15 | ## Use your own credentials and data
16 | * Open https://console.developers.google.com/apis/credentials
17 | * After creating project or if you already have one.
18 | * Click create credentials.
19 | * Select OAuth client ID.
20 | * Select Web application.
21 | * Give it a name. (anything for your own reference)
22 | * In Authorized JavaScript origins add https://developers.google.com
23 | * In Authorized redirect URIs add https://developers.google.com/oauthplayground
24 | * Save and note down your Client ID and Secret
25 | * Open https://developers.google.com/oauthplayground
26 | * On Right Top Side click on Setting Icon 
27 | * Click on Use your own OAuth credentials.
28 | * Enter OAuth Client ID: and OAuth Client secret:
29 | * Now back to same page https://developers.google.com/oauthplayground left side Step 1 i.e. Select & authorize APIs
30 | * Find Drive API v3
31 | * Select First Option i.e. https://www.googleapis.com/auth/drive
32 | * Click on Authorize API. and give permissions using your google account.
33 | * It will turn to Step 2 Exchange authorization code for tokens at the end of authentication.
34 | * Click on Exchange authorization code for tokens, if it goes to step 3, click on Step 2 yourself.
35 | * Select the option Auto-refresh the token before it expires.
36 | * Copy the refresh token and paste in Line 8 of https://github.com/kulokenci/goindex-drive/blob/master/worker.js along with your own Client ID and Secret at Line 6 and Line 7.
37 | * Copy the Code and paste it into https://workers.cloudflare.com Site.
38 |
39 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | // Edited by Kulo Kenci
2 | // Head
3 | document.write(' ');
4 | document.write(' ');
5 | // Markdown
6 | document.write('');
7 | document.write('');
8 | // Initialization page,And load the necessary resources
9 | function init() {
10 | document.siteName = $('title').html();
11 | $('body').addClass("mdui-theme-primary-blue-grey mdui-theme-accent-blue");
12 | var html = `
13 |
14 |
18 |
19 |
20 | `;
21 | $('body').html(html);
22 | }
23 |
24 | function render(path) {
25 | if (path.indexOf("?") > 0) {
26 | path = path.substr(0, path.indexOf("?"));
27 | }
28 | title(path);
29 | nav(path);
30 | if (path.substr(-1) == '/') {
31 | list(path);
32 | } else {
33 | file(path);
34 | }
35 | }
36 | // Rendering title
37 | function title(path) {
38 | path = decodeURI(path);
39 | $('title').html(document.siteName + ' - ' + path);
40 | }
41 | // Render navigation bar
42 | function nav(path) {
43 | var html = "";
44 | html += `${document.siteName} `;
45 | var arr = path.trim('/').split('/');
46 | var p = '/';
47 | if (arr.length > 0) {
48 | for (i in arr) {
49 | var n = arr[i];
50 | n = decodeURI(n);
51 | p += n + '/';
52 | if (n == '') {
53 | break;
54 | }
55 | html += `chevron_right ${n} `;
56 | }
57 | }
58 | html += `
59 |
60 |
61 |
67 |
68 | `;
69 | $('#nav').html(html);
70 | }
71 | // Render file list
72 | function list(path) {
73 | var content = `
74 |
75 |
76 |
91 |
95 |
96 | `;
97 | $('#content').html(content);
98 | var password = localStorage.getItem('password' + path);
99 | $('#list').html(``);
100 | $('#readme_md').hide().html('');
101 | $('#head_md').hide().html('');
102 | $.post(path, '{"password":"' + password + '"}', function (data, status) {
103 | var obj = jQuery.parseJSON(data);
104 | if (typeof obj != 'null' && obj.hasOwnProperty('error') && obj.error.code == '401') {
105 | var pass = prompt("Folder terenkripsi,Tolong masukan password", "");
106 | localStorage.setItem('password' + path, pass);
107 | if (pass != null && pass != "") {
108 | list(path);
109 | } else {
110 | history.go(-1);
111 | }
112 | } else if (typeof obj != 'null') {
113 | list_files(path, obj.files);
114 | }
115 | });
116 | }
117 |
118 | function list_files(path, files) {
119 | html = "";
120 | for (i in files) {
121 | var item = files[i];
122 | var p = path + item.name + '/';
123 | if (item['size'] == undefined) {
124 | item['size'] = "";
125 | }
126 | item['modifiedTime'] = utc2beijing(item['modifiedTime']);
127 | item['size'] = formatFileSize(item['size']);
128 | if (item['mimeType'] == 'application/vnd.google-apps.folder') {
129 | html += `
130 |
131 | folder_open
132 | ${item.name}
133 |
134 | ${item['modifiedTime']}
135 | ${item['size']}
136 |
137 | `;
138 | } else {
139 | var p = path + item.name;
140 | var c = "file";
141 | if (item.name == "README.md") {
142 | get_file(p, item, function (data) {
143 | markdown("#readme_md", data);
144 | });
145 | }
146 | if (item.name == "HEAD.md") {
147 | get_file(p, item, function (data) {
148 | markdown("#head_md", data);
149 | });
150 | }
151 | var ext = p.split('.').pop();
152 | if ("|html|php|css|go|java|js|json|txt|sh|md|mp4|bmp|jpg|jpeg|png|gif|".indexOf(`|${ext}|`) >= 0) {
153 | p += "?a=view";
154 | c += " view";
155 | }
156 | html += `
157 |
158 | insert_drive_file
159 | ${item.name}
160 |
161 | ${item['modifiedTime']}
162 | ${item['size']}
163 |
164 | `;
165 | }
166 | }
167 | $('#list').html(html);
168 | }
169 |
170 | function get_file(path, file, callback) {
171 | var key = "file_path_" + path + file['modifiedTime'];
172 | var data = localStorage.getItem(key);
173 | if (data != undefined) {
174 | return callback(data);
175 | } else {
176 | $.get(path, function (d) {
177 | localStorage.setItem(key, d);
178 | callback(d);
179 | });
180 | }
181 | }
182 | // Document display ?a=view
183 | function file(path) {
184 | var name = path.split('/').pop();
185 | var ext = name.split('.').pop().toLowerCase().replace(`?a=view`, "");
186 | if ("|html|php|css|go|java|js|json|txt|sh|md|".indexOf(`|${ext}|`) >= 0) {
187 | return file_code(path);
188 | }
189 | if ("|mp4|".indexOf(`|${ext}|`) >= 0) {
190 | return file_video(path);
191 | }
192 | if ("|bmp|jpg|jpeg|png|gif|".indexOf(`|${ext}|`) >= 0) {
193 | return file_image(path);
194 | }
195 | }
196 | // Document display |html|php|css|go|java|js|json|txt|sh|md|
197 | function file_code(path) {
198 | var type = {
199 | "html": "html",
200 | "php": "php",
201 | "css": "css",
202 | "go": "golang",
203 | "java": "java",
204 | "js": "javascript",
205 | "json": "json",
206 | "txt": "Text",
207 | "sh": "sh",
208 | "md": "Markdown",
209 | };
210 | var name = path.split('/').pop();
211 | var ext = name.split('.').pop();
212 | var href = window.location.origin + path;
213 | var content = `
214 |
217 |
218 | Download Link
219 |
220 |
221 | file_download
222 |
223 |
224 |
225 | `;
226 | $('#content').html(content);
227 | $.get(path, function (data) {
228 | $('#editor').html($('
').text(data).html());
229 | var code_type = "Text";
230 | if (type[ext] != undefined) {
231 | code_type = type[ext];
232 | }
233 | var editor = ace.edit("editor");
234 | editor.setTheme("ace/theme/ambiance");
235 | editor.setFontSize(18);
236 | editor.session.setMode("ace/mode/" + code_type);
237 | //Autocompletion
238 | editor.setOptions({
239 | enableBasicAutocompletion: true,
240 | enableSnippets: true,
241 | enableLiveAutocompletion: true,
242 | maxLines: Infinity
243 | });
244 | });
245 | }
246 | // Document display mp4
247 | function file_video(path) {
248 | var url = window.location.origin + path;
249 | var content = `
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 | Download Link
259 |
260 |
261 |
262 | Reference address
263 |
264 |
265 |
266 | file_download
267 | `;
268 | $('#content').html(content);
269 | }
270 | //
271 | function file_image(path) {
272 | var url = window.location.origin + path;
273 | var content = `
274 |
275 |
276 |
277 |
278 |
279 | Download Link
280 |
281 |
282 |
283 | HTML Reference address
284 |
285 |
286 |
287 | Markdown Reference address
288 |
289 |
290 |
291 |
292 | file_download
293 | `;
294 | $('#content').html(content);
295 | }
296 | //Time conversion
297 | function utc2beijing(utc_datetime) {
298 | // 转为正常的时间格式 年-月-日 时:分:秒
299 | var T_pos = utc_datetime.indexOf('T');
300 | var Z_pos = utc_datetime.indexOf('Z');
301 | var year_month_day = utc_datetime.substr(0, T_pos);
302 | var hour_minute_second = utc_datetime.substr(T_pos + 1, Z_pos - T_pos - 1);
303 | var new_datetime = year_month_day + " " + hour_minute_second; // 2017-03-31 08:02:06
304 | // Processing becomes a timestamp
305 | timestamp = new Date(Date.parse(new_datetime));
306 | timestamp = timestamp.getTime();
307 | timestamp = timestamp / 1000;
308 | // Increase 8 hours,Beijing time has eight time zones than utc time
309 | var unixtimestamp = timestamp + 5.5 * 60 * 60;
310 | // Timestamp is converted to time
311 | var unixtimestamp = new Date(unixtimestamp * 1000);
312 | var year = 1900 + unixtimestamp.getYear();
313 | var month = "0" + (unixtimestamp.getMonth() + 1);
314 | var date = "0" + unixtimestamp.getDate();
315 | var hour = "0" + unixtimestamp.getHours();
316 | var minute = "0" + unixtimestamp.getMinutes();
317 | var second = "0" + unixtimestamp.getSeconds();
318 | return year + "-" + month.substring(month.length - 2, month.length) + "-" + date.substring(date.length - 2, date.length) + " " + hour.substring(hour.length - 2, hour.length) + ":" + minute.substring(minute.length - 2, minute.length) + ":" + second.substring(second.length - 2, second.length);
319 | }
320 | // Bytes adaptive conversion to KB,MB,GB
321 | function formatFileSize(bytes) {
322 | if (bytes >= 1000000000) {
323 | bytes = (bytes / 1000000000).toFixed(2) + ' GB';
324 | } else if (bytes >= 1000000) {
325 | bytes = (bytes / 1000000).toFixed(2) + ' MB';
326 | } else if (bytes >= 1000) {
327 | bytes = (bytes / 1000).toFixed(2) + ' KB';
328 | } else if (bytes > 1) {
329 | bytes = bytes + ' bytes';
330 | } else if (bytes == 1) {
331 | bytes = bytes + ' byte';
332 | } else {
333 | bytes = '';
334 | }
335 | return bytes;
336 | }
337 | String.prototype.trim = function (char) {
338 | if (char) {
339 | return this.replace(new RegExp('^\\' + char + '+|\\' + char + '+$', 'g'), '');
340 | }
341 | return this.replace(/^\s+|\s+$/g, '');
342 | };
343 | // README.md HEAD.md stand by
344 | function markdown(el, data) {
345 | if (window.md == undefined) {
346 | //$.getScript('https://cdn.jsdelivr.net/npm/markdown-it@9.1.0/dist/markdown-it.min.js',function(){
347 | window.md = window.markdownit();
348 | markdown(el, data);
349 | //});
350 | } else {
351 | var html = md.render(data);
352 | $(el).show().html(html);
353 | }
354 | }
355 | document.write('');
356 | // Listening back event
357 | window.onpopstate = function () {
358 | var path = window.location.pathname;
359 | render(path);
360 | }
361 | $(function () {
362 | init();
363 | var path = window.location.pathname;
364 | $("body").on("click", '.folder', function () {
365 | var url = $(this).attr('href');
366 | history.pushState(null, null, url);
367 | render(url);
368 | return false;
369 | });
370 | $("body").on("click", '.view', function () {
371 | var url = $(this).attr('href');
372 | history.pushState(null, null, url);
373 | render(url);
374 | return false;
375 | });
376 | render(path);
377 | });
378 | //# sourceMappingURL=/sm/7de5ebd04c9d149c688ff531decdeb96216884e2f3038bf5009b329a0c6f8140.map
379 |
--------------------------------------------------------------------------------
/cari.js:
--------------------------------------------------------------------------------
1 | function myFunction() {
2 | var e, t, n, l;
3 | for (e = document.getElementById("myInput").value.toUpperCase(), t = document.getElementById("list").getElementsByTagName("li"), l = 0; l < t.length; l++)((n = t[l].getElementsByTagName("a")[0]).textContent || n.innerText).toUpperCase().indexOf(e) > -1 ? t[l].style.display = "" : t[l].style.display = "none"
4 | }
5 |
--------------------------------------------------------------------------------
/cari.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lsmother/goindex-drive/39421f996f49c7eaaba4088687a867fb1f715627/cari.png
--------------------------------------------------------------------------------
/custom.css:
--------------------------------------------------------------------------------
1 | .mdui-theme-primary-blue-grey .mdui-color-theme {
2 | background-color: #232427!important
3 | }
4 | body {
5 | color: rgba(255, 255, 255, .87);
6 | background-color: #333232
7 | }
8 | * {
9 | box-sizing: border-box
10 | }
11 | #myInput {
12 | background-image: url(https://cdn.jsdelivr.net/gh/kulokenci/goindex-drive@2.0/cari.png);
13 | background-position: 10px 12px;
14 | background-repeat: no-repeat;
15 | width: 100%;
16 | font-size: 16px;
17 | padding: 12px 20px 12px 40px;
18 | border: 1px solid #ddd;
19 | margin-bottom: 12px
20 | }
21 | #myUL {
22 | list-style-type: none;
23 | padding: 0;
24 | margin: 0
25 | }
26 | #myUL li a {
27 | border: 1px solid #ddd;
28 | margin-top: -1px;
29 | background-color: #f6f6f6;
30 | padding: 12px;
31 | text-decoration: none;
32 | font-size: 18px;
33 | color: #000;
34 | display: block
35 | }
36 | #myUL li a:hover:not(.header) {
37 | background-color: #eee
38 | }
39 |
--------------------------------------------------------------------------------
/go-drive-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lsmother/goindex-drive/39421f996f49c7eaaba4088687a867fb1f715627/go-drive-logo.png
--------------------------------------------------------------------------------
/ss.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lsmother/goindex-drive/39421f996f49c7eaaba4088687a867fb1f715627/ss.jpg
--------------------------------------------------------------------------------
/worker.js:
--------------------------------------------------------------------------------
1 | var authConfig = {
2 | "siteName": "Google Drive", // Site Name
3 | "root_pass": "", // Root Password
4 | "version": "2.0", // Site Version
5 | "theme": "material", // material classic
6 | "client_id": "202264815644.apps.googleusercontent.com", // Google Client ID
7 | "client_secret": "X4Z3ca8xfWDb1Voo-F9a7ZxJ", // Google Client Secret
8 | "refresh_token": "", // Refresh token "root": "root" // Root directory
9 | "root": "root" // Root directory
10 | };
11 |
12 | var gd;
13 |
14 | var html = `
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ${authConfig.siteName}
23 |
24 |
25 |
26 |
27 |
28 |
29 | `;
30 |
31 | addEventListener('fetch', event => {
32 | event.respondWith(handleRequest(event.request));
33 | });
34 |
35 | /**
36 | * Fetch and log a request
37 | * @param {Request} request
38 | */
39 | async function handleRequest(request) {
40 | if(gd == undefined){
41 | gd = new googleDrive(authConfig);
42 | }
43 |
44 | if(request.method == 'POST'){
45 | return apiRequest(request);
46 | }
47 |
48 | let url = new URL(request.url);
49 | let path = url.pathname;
50 | let action = url.searchParams.get('a');
51 |
52 | if(path.substr(-1) == '/' || action != null){
53 | return new Response(html,{status:200,headers:{'Content-Type':'text/html; charset=utf-8'}});
54 | }else{
55 | if(path.split('/').pop().toLowerCase() == ".password"){
56 | return new Response("",{status:404});
57 | }
58 | let file = await gd.file(path);
59 | let range = request.headers.get('Range');
60 | return gd.down(file.id, range);
61 | }
62 | }
63 |
64 |
65 | async function apiRequest(request) {
66 | let url = new URL(request.url);
67 | let path = url.pathname;
68 |
69 | let option = {status:200,headers:{'Access-Control-Allow-Origin':'*'}}
70 |
71 | if(path.substr(-1) == '/'){
72 | // check password
73 | let password = await gd.password(path);
74 | console.log("dir password", password);
75 | if(password != undefined && password != null && password != ""){
76 | try{
77 | var obj = await request.json();
78 | }catch(e){
79 | var obj = {};
80 | }
81 | console.log(password,obj);
82 | if(password != obj.password){
83 | let html = `{"error": {"code": 401,"message": "password error."}}`;
84 | return new Response(html,option);
85 | }
86 | }
87 | let list = await gd.list(path);
88 | return new Response(JSON.stringify(list),option);
89 | }else{
90 | let file = await gd.file(path);
91 | let range = request.headers.get('Range');
92 | return new Response(JSON.stringify(file));
93 | }
94 | }
95 |
96 | class googleDrive {
97 | constructor(authConfig) {
98 | this.authConfig = authConfig;
99 | this.paths = [];
100 | this.files = [];
101 | this.passwords = [];
102 | this.paths["/"] = authConfig.root;
103 | if(authConfig.root_pass != ""){
104 | this.passwords["/"] = authConfig.root_pass;
105 | }
106 | this.accessToken();
107 | }
108 |
109 | async down(id, range=''){
110 | let url = `https://www.googleapis.com/drive/v3/files/${id}?alt=media`;
111 | let requestOption = await this.requestOption();
112 | requestOption.headers['Range'] = range;
113 | return await fetch(url, requestOption);
114 | }
115 |
116 | async file(path){
117 | if(typeof this.files[path] == 'undefined'){
118 | this.files[path] = await this._file(path);
119 | }
120 | return this.files[path] ;
121 | }
122 |
123 | async _file(path){
124 | let arr = path.split('/');
125 | let name = arr.pop();
126 | name = decodeURIComponent(name).replace(/\'/g, "\\'");
127 | let dir = arr.join('/')+'/';
128 | console.log(name, dir);
129 | let parent = await this.findPathId(dir);
130 | console.log(parent);
131 | let url = 'https://www.googleapis.com/drive/v3/files';
132 | let params = {'includeItemsFromAllDrives':true,'supportsAllDrives':true};
133 | params.q = `'${parent}' in parents and name = '${name}' andtrashed = false`;
134 | params.fields = "files(id, name, mimeType, size ,createdTime, modifiedTime, iconLink, thumbnailLink)";
135 | url += '?'+this.enQuery(params);
136 | let requestOption = await this.requestOption();
137 | let response = await fetch(url, requestOption);
138 | let obj = await response.json();
139 | console.log(obj);
140 | return obj.files[0];
141 | }
142 |
143 | // reqeust cache
144 | async list(path){
145 | let id = await this.findPathId(path);
146 | return this._ls(id);
147 | }
148 |
149 | async password(path){
150 | if(this.passwords[path] !== undefined){
151 | return this.passwords[path];
152 | }
153 |
154 | console.log("load",path,".password",this.passwords[path]);
155 |
156 | let file = await gd.file(path+'.password');
157 | if(file == undefined){
158 | this.passwords[path] = null;
159 | }else{
160 | let url = `https://www.googleapis.com/drive/v3/files/${file.id}?alt=media`;
161 | let requestOption = await this.requestOption();
162 | let response = await this.fetch200(url, requestOption);
163 | this.passwords[path] = await response.text();
164 | }
165 |
166 | return this.passwords[path];
167 | }
168 |
169 | async _ls(parent){
170 | console.log("_ls",parent);
171 |
172 | if(parent==undefined){
173 | return null;
174 | }
175 | let url = 'https://www.googleapis.com/drive/v3/files';
176 | let params = {'includeItemsFromAllDrives':true,'supportsAllDrives':true};
177 | params.q = `'${parent}' in parents and trashed = false AND name !='.password'`;
178 | params.orderBy= 'folder,name,modifiedTime desc';
179 | params.fields = "nextPageToken, files(id, name, mimeType, size , modifiedTime)";
180 | params.pageSize = 1000;
181 | url += '?'+this.enQuery(params);
182 | let requestOption = await this.requestOption();
183 | let response = await fetch(url, requestOption);
184 | let obj = await response.json();
185 | return obj;
186 | }
187 |
188 | async findPathId(path){
189 | let c_path = '/';
190 | let c_id = this.paths[c_path];
191 |
192 | let arr = path.trim('/').split('/');
193 | for(let name of arr){
194 | c_path += name+'/';
195 |
196 | if(typeof this.paths[c_path] == 'undefined'){
197 | let id = await this._findDirId(c_id, name);
198 | this.paths[c_path] = id;
199 | }
200 |
201 | c_id = this.paths[c_path];
202 | if(c_id == undefined || c_id == null){
203 | break;
204 | }
205 | }
206 | console.log(this.paths);
207 | return this.paths[path];
208 | }
209 |
210 | async _findDirId(parent, name){
211 | name = decodeURIComponent(name).replace(/\'/g, "\\'");
212 |
213 | console.log("_findDirId",parent,name);
214 |
215 | if(parent==undefined){
216 | return null;
217 | }
218 |
219 | let url = 'https://www.googleapis.com/drive/v3/files';
220 | let params = {'includeItemsFromAllDrives':true,'supportsAllDrives':true};
221 | params.q = `'${parent}' in parents and mimeType = 'application/vnd.google-apps.folder' and name = '${name}' and trashed = false`;
222 | params.fields = "nextPageToken, files(id, name, mimeType)";
223 | url += '?'+this.enQuery(params);
224 | let requestOption = await this.requestOption();
225 | let response = await fetch(url, requestOption);
226 | let obj = await response.json();
227 | if(obj.files[0] == undefined){
228 | return null;
229 | }
230 | return obj.files[0].id;
231 | }
232 |
233 | async accessToken(){
234 | console.log("accessToken");
235 | if(this.authConfig.expires == undefined ||this.authConfig.expires< Date.now()){
236 | const obj = await this.fetchAccessToken();
237 | if(obj.access_token != undefined){
238 | this.authConfig.accessToken = obj.access_token;
239 | this.authConfig.expires = Date.now()+3500*1000;
240 | }
241 | }
242 | return this.authConfig.accessToken;
243 | }
244 |
245 | async fetchAccessToken() {
246 | console.log("fetchAccessToken");
247 | const url = "https://www.googleapis.com/oauth2/v4/token";
248 | const headers = {
249 | 'Content-Type': 'application/x-www-form-urlencoded'
250 | };
251 | const post_data = {
252 | 'client_id': this.authConfig.client_id,
253 | 'client_secret': this.authConfig.client_secret,
254 | 'refresh_token': this.authConfig.refresh_token,
255 | 'grant_type': 'refresh_token'
256 | }
257 |
258 | let requestOption = {
259 | 'method': 'POST',
260 | 'headers': headers,
261 | 'body': this.enQuery(post_data)
262 | };
263 |
264 | const response = await fetch(url, requestOption);
265 | return await response.json();
266 | }
267 |
268 | async fetch200(url, requestOption) {
269 | let response;
270 | for (let i = 0; i < 3; i++) {
271 | response = await fetch(url, requestOption);
272 | console.log(response.status);
273 | if (response.status != 403) {
274 | break;
275 | }
276 | await this.sleep(800 * (i + 1));
277 | }
278 | return response;
279 | }
280 |
281 | async requestOption(headers={},method='GET'){
282 | const accessToken = await this.accessToken();
283 | headers['authorization'] = 'Bearer '+ accessToken;
284 | return {'method': method, 'headers':headers};
285 | }
286 |
287 | enQuery(data) {
288 | const ret = [];
289 | for (let d in data) {
290 | ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
291 | }
292 | return ret.join('&');
293 | }
294 |
295 | sleep(ms) {
296 | return new Promise(function (resolve, reject) {
297 | let i = 0;
298 | setTimeout(function () {
299 | console.log('sleep' + ms);
300 | i++;
301 | if (i >= 2) reject(new Error('i>=2'));
302 | else resolve(i);
303 | }, ms);
304 | })
305 | }
306 | }
307 |
308 | String.prototype.trim = function (char) {
309 | if (char) {
310 | return this.replace(new RegExp('^\\'+char+'+|\\'+char+'+$', 'g'), '');
311 | }
312 | return this.replace(/^\s+|\s+$/g, '');
313 | };
314 |
--------------------------------------------------------------------------------