277 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*jshint -W054 */
 | |
| (function (exports) {
 | |
|   "use strict";
 | |
| 
 | |
|   function create(Desi) {
 | |
|     // Chrome, Firefox, and even MSIE11+ all support crypto
 | |
|     var crypto = window.crypto || window.msCrypto,
 | |
|       Promise = window.Promise,
 | |
|       algos;
 | |
| 
 | |
|     // convenience mappings for common digest algorithms
 | |
|     algos = {
 | |
|       sha1: "SHA-1",
 | |
|       sha256: "SHA-256",
 | |
|       sha512: "SHA-512",
 | |
|     };
 | |
| 
 | |
|     // The function to generate a sha1sum is the same as generating any digest
 | |
|     // but here's a shortcut function anyway
 | |
|     function sha1sum(str) {
 | |
|       return hashsum("sha1", str);
 | |
|     }
 | |
| 
 | |
|     // a more general convenience function
 | |
|     function hashsum(hash, str) {
 | |
|       // you have to convert from string to array buffer
 | |
|       var ab,
 | |
|         // you have to represent the algorithm as an object
 | |
|         algo = { name: algos[hash] };
 | |
|       if ("string" === typeof str) {
 | |
|         ab = str2ab(str);
 | |
|       } else {
 | |
|         ab = str;
 | |
|       }
 | |
| 
 | |
|       // All crypto digest methods return a promise
 | |
|       return crypto.subtle
 | |
|         .digest(algo, ab)
 | |
|         .then(function (digest) {
 | |
|           // you have to convert the ArrayBuffer to a DataView and then to a hex String
 | |
|           return ab2hex(digest);
 | |
|         })
 | |
|         .catch(function (e) {
 | |
|           // if you specify an unsupported digest algorithm or non-ArrayBuffer, you'll get an error
 | |
|           console.error("sha1sum ERROR");
 | |
|           console.error(e);
 | |
|           throw e;
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     // convert from arraybuffer to hex
 | |
|     function ab2hex(ab) {
 | |
|       var dv = new DataView(ab),
 | |
|         i,
 | |
|         len,
 | |
|         hex = "",
 | |
|         c;
 | |
| 
 | |
|       for (i = 0, len = dv.byteLength; i < len; i += 1) {
 | |
|         c = dv.getUint8(i).toString(16);
 | |
| 
 | |
|         if (c.length < 2) {
 | |
|           c = "0" + c;
 | |
|         }
 | |
| 
 | |
|         hex += c;
 | |
|       }
 | |
| 
 | |
|       return hex;
 | |
|     }
 | |
| 
 | |
|     // convert from string to arraybuffer
 | |
|     function str2ab(stringToEncode, insertBom) {
 | |
|       stringToEncode = stringToEncode.replace(/\r\n/g, "\n");
 | |
| 
 | |
|       var utftext = [],
 | |
|         n,
 | |
|         c;
 | |
| 
 | |
|       if (true === insertBom) {
 | |
|         utftext[0] = 0xef;
 | |
|         utftext[1] = 0xbb;
 | |
|         utftext[2] = 0xbf;
 | |
|       }
 | |
| 
 | |
|       for (n = 0; n < stringToEncode.length; n += 1) {
 | |
|         c = stringToEncode.charCodeAt(n);
 | |
| 
 | |
|         if (c < 128) {
 | |
|           utftext[utftext.length] = c;
 | |
|         } else if (c > 127 && c < 2048) {
 | |
|           utftext[utftext.length] = (c >> 6) | 192;
 | |
|           utftext[utftext.length] = (c & 63) | 128;
 | |
|         } else {
 | |
|           utftext[utftext.length] = (c >> 12) | 224;
 | |
|           utftext[utftext.length] = ((c >> 6) & 63) | 128;
 | |
|           utftext[utftext.length] = (c & 63) | 128;
 | |
|         }
 | |
|       }
 | |
|       return new Uint8Array(utftext).buffer;
 | |
|     }
 | |
| 
 | |
|     exports.hashsum = hashsum;
 | |
|     exports.sha1sum = sha1sum;
 | |
| 
 | |
|     //
 | |
|     // FSAPI
 | |
|     //
 | |
|     var fsapi;
 | |
| 
 | |
|     function request() {}
 | |
|     request.get = function (url /*, query*/) {
 | |
|       // Return a new promise.
 | |
|       return new Promise(function (resolve, reject) {
 | |
|         // Do the usual XHR stuff
 | |
|         var req = new XMLHttpRequest();
 | |
|         req.onload = function () {
 | |
|           // This is called even on 404 etc
 | |
|           // so check the status
 | |
|           if (200 === req.status) {
 | |
|             // Resolve the promise with the response text
 | |
|             resolve(req.response);
 | |
|           } else {
 | |
|             // Otherwise reject with the status text
 | |
|             // which will hopefully be a meaningful error
 | |
|             reject(Error(req.statusText));
 | |
|           }
 | |
|         };
 | |
| 
 | |
|         // Handle network errors
 | |
|         req.onerror = function () {
 | |
|           reject(Error("Network Error"));
 | |
|         };
 | |
| 
 | |
|         // Make the request
 | |
|         req.open("GET", url);
 | |
|         req.send();
 | |
|       });
 | |
|     };
 | |
|     request.post = function (url /*, query*/, body) {
 | |
|       // Return a new promise.
 | |
|       return new Promise(function (resolve, reject) {
 | |
|         // Do the usual XHR stuff
 | |
|         var req = new XMLHttpRequest();
 | |
|         req.onload = function () {
 | |
|           // This is called even on 404 etc
 | |
|           // so check the status
 | |
|           if (200 === req.status) {
 | |
|             // Resolve the promise with the response text
 | |
|             resolve(req.response);
 | |
|           } else {
 | |
|             // Otherwise reject with the status text
 | |
|             // which will hopefully be a meaningful error
 | |
|             reject(Error(req.statusText));
 | |
|           }
 | |
|         };
 | |
| 
 | |
|         // Handle network errors
 | |
|         req.onerror = function () {
 | |
|           reject(Error("Network Error"));
 | |
|         };
 | |
| 
 | |
|         req.open("POST", url);
 | |
|         req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
 | |
|         // Make the request
 | |
|         if ("string" !== typeof body) {
 | |
|           body = JSON.stringify(body);
 | |
|         }
 | |
|         req.send(body);
 | |
|       });
 | |
|     };
 | |
| 
 | |
|     Desi.fsapi = fsapi = Desi.fsapi || {};
 | |
|     fsapi.getMeta = function (collections, opts) {
 | |
|       opts = opts || {};
 | |
| 
 | |
|       var extensions = "",
 | |
|         dotfiles = "",
 | |
|         contents = "",
 | |
|         sha1sum = "";
 | |
|       if (Array.isArray(opts.extensions)) {
 | |
|         extensions = "&extensions=" + opts.extensions.join(","); // md,markdown,jade,htm,html
 | |
|       }
 | |
|       if (opts.dotfiles) {
 | |
|         dotfiles = "&dotfiles=true";
 | |
|       }
 | |
|       if (opts.contents) {
 | |
|         contents = "&contents=true";
 | |
|       }
 | |
|       if (false === opts.sha1sum) {
 | |
|         sha1sum = "&sha1sum=false";
 | |
|       }
 | |
| 
 | |
|       return request
 | |
|         .post(
 | |
|           "/api/fs/walk?_method=GET" +
 | |
|             dotfiles +
 | |
|             extensions +
 | |
|             contents +
 | |
|             sha1sum,
 | |
|           {
 | |
|             dirs: collections,
 | |
|           }
 | |
|         )
 | |
|         .then(function (resp) {
 | |
|           return JSON.parse(resp);
 | |
|         })
 | |
|         .catch(function (e) {
 | |
|           throw e;
 | |
|         });
 | |
|     };
 | |
| 
 | |
|     fsapi.getContents = function (filepaths) {
 | |
|       return request
 | |
|         .post("/api/fs/files?_method=GET", {
 | |
|           paths: filepaths,
 | |
|         })
 | |
|         .then(function (resp) {
 | |
|           return JSON.parse(resp);
 | |
|         });
 | |
|     };
 | |
| 
 | |
|     fsapi.getCache = function () {
 | |
|       return request
 | |
|         .get("/api/fs/static/cache.json")
 | |
|         .then(function (resp) {
 | |
|           return JSON.parse(resp);
 | |
|         })
 | |
|         .catch(function (/*e*/) {
 | |
|           return {};
 | |
|         })
 | |
|         .then(function (obj) {
 | |
|           return obj;
 | |
|         });
 | |
|     };
 | |
| 
 | |
|     fsapi.copy = function (files) {
 | |
|       var body = { files: files };
 | |
|       body = JSON.stringify(body); // this is more or less instant for a few MiB of posts
 | |
|       return request.post("/api/fs/copy", body).then(function (resp) {
 | |
|         var response = JSON.parse(resp);
 | |
|         // not accurate for utf8/unicode, but close enough
 | |
|         response.size = body.length;
 | |
|         return response;
 | |
|       });
 | |
|     };
 | |
| 
 | |
|     fsapi.putFiles = function (files) {
 | |
|       var body = { files: files };
 | |
|       files.forEach(function (file) {
 | |
|         if (!file.contents || "string" === typeof file.contents) {
 | |
|           return;
 | |
|         }
 | |
|         if (/\.json$/i.test(file.path)) {
 | |
|           file.contents = JSON.stringify(file.contents);
 | |
|         } else if (/\.ya?ml$/i.test(file.path)) {
 | |
|           file.contents = exports.jsyaml.dump(file.contents);
 | |
|         }
 | |
|       });
 | |
| 
 | |
|       body = JSON.stringify(body); // this is more or less instant for a few MiB of posts
 | |
|       return request.post("/api/fs/files", body).then(function (resp) {
 | |
|         var response = JSON.parse(resp);
 | |
|         // not accurate for utf8/unicode, but close enough
 | |
|         response.size = body.length;
 | |
|         return response;
 | |
|       });
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   if (exports.Desirae) {
 | |
|     create(exports.Desirae);
 | |
|   } else {
 | |
|     exports.create = create;
 | |
|   }
 | |
| })(("undefined" !== typeof exports && exports) || window);
 |