UNPKG

@minima-global/mds

Version:

Official MDS Typescript Library for Minima. Used for creating minidapps that interact with the Minima Blockchain.

590 lines 20.6 kB
/** * The MDS TS Library for building MiniDapps * by Minima Global */ import { createCommandFunction } from './helpers.js'; var MDS_MAIN_CALLBACK; var API_CALLS = []; export const MDS = { filehost: '', mainhost: '', minidappuid: '', testhost: '', TEST_MODE: false, logging: false, DEBUG_HOST: null, DEBUG_PORT: 0, DEBUG_MINIDAPPID: '', init: (callback) => { MDS.log('MDS Inited'); if (isTestEnvironment()) { MDS.TEST_MODE = true; MDS.minidappuid = MDS.DEBUG_MINIDAPPID || '0x00'; MDS.filehost = `https://${MDS.DEBUG_HOST}:${MDS.DEBUG_PORT}/`; MDS.mainhost = `http://${MDS.DEBUG_HOST}:${MDS.DEBUG_PORT}/`; MDS.testhost = `http://${MDS.DEBUG_HOST}:${MDS.DEBUG_PORT}/`; MDS_MAIN_CALLBACK = callback; if (callback) { callback({ event: 'inited', data: null }); } return; } if (MDS.form.getParams('MDS_LOGGING') != null) { MDS.logging = true; } var host = window.location.hostname; var port = Number(window.location.port); MDS.minidappuid = MDS.form.getParams('uid'); if (MDS.DEBUG_HOST != null) { MDS.log('DEBUG Settings Found..'); host = MDS.DEBUG_HOST; port = MDS.DEBUG_PORT; } if (MDS.minidappuid == null) { MDS.minidappuid = MDS.DEBUG_MINIDAPPID; } if (MDS.minidappuid == '0x00') { MDS.log('No MiniDAPP UID specified.. using test value'); } MDS.filehost = 'https://' + host + ':' + port + '/'; MDS.mainhost = 'https://' + host + ':' + port + '/mdscommand_/'; MDS.testhost = 'https://' + host + ':' + port + '/'; MDS.log('MDS HOST : ' + MDS.filehost); MDS_MAIN_CALLBACK = callback; PollListener(); //And Post a message MDSPostMessage({ event: 'inited' }); }, log: (data) => { console.log('Minima @ ' + new Date().toLocaleString() + ' : ' + data); }, notify: (output) => { httpPostAsync(MDS.mainhost + 'notify?' + 'uid=' + MDS.minidappuid, output); }, notifycancel: () => { httpPostAsync('notifycancel', '*'); }, cmd: new Proxy({}, { get: (target, prop) => { // If the command is already defined, return it if (prop in target) { return target[prop]; } // Otherwise create a new command function const commandFunction = createCommandFunction(prop); // Add the command function to the target object target[prop] = commandFunction; // Return the command function return commandFunction; }, }), sql: (command, callback) => { return new Promise((resolve) => { httpPostAsync('sql', command, (data) => { resolve(data); if (callback) { callback(data); } }); }); }, dapplink: (dappname, callback) => { return new Promise((resolve) => { httpPostAsync('dapplink', dappname, (result) => { resolve(result); if (callback) { callback(result); } }); }); }, api: { call: (dappname, data, callback) => { var rand = '' + Math.random() * 1000000000; //Construct a callback list object var callitem = {}; callitem.id = rand; callitem.callback = callback; //Add to the api calls.. API_CALLS.push(callitem); //Create the single line var commsline = dappname + '&request&' + rand + '&' + data; //Send via POST httpPostAsync('api', commsline); }, reply: (dappname, id, data, callback) => { var commsline = dappname + '&response&' + id + '&' + data; httpPostAsync('api', commsline, callback); }, }, net: { GET: (url, callback) => { httpPostAsync('net', url, callback); }, POST: (url, data, callback) => { var postline = url + '&' + data; httpPostAsync('netpost', postline, callback); }, }, keypair: { get: (key, callback) => { return new Promise((resolve) => { var commsline = 'get&' + key; httpPostAsync('keypair', commsline, (data) => { resolve(data); if (callback) { callback(data); } }); }); }, set: (key, value, callback) => { return new Promise((resolve) => { var commsline = 'set&' + key + '&' + value; httpPostAsync('keypair', commsline, (data) => { resolve(data); if (callback) { callback(data); } }); }); }, }, comms: { broadcast: (message, callback) => { var commsline = 'public&' + message; httpPostAsync('comms', commsline, callback); }, solo: (message, callback) => { var commsline = 'private&' + message; httpPostAsync('comms', commsline, callback); }, }, file: { list: (folder, _, callback) => { var commsline = 'list&' + folder; httpPostAsync('file', commsline, callback); }, save: (filename, text, callback) => { var commsline = 'save&' + filename + '&' + text; httpPostAsync('file', commsline, callback); }, savebinary: function (filename, hexdata, callback) { var commsline = 'savebinary&' + filename + '&' + hexdata; //Send via POST httpPostAsync('file', commsline, callback); }, load: (filename, _, callback) => { var commsline = 'load&' + filename; //Send via POST httpPostAsync('file', commsline, callback); }, loadbinary(filename, _, callback) { var commsline = 'loadbinary&' + filename; //Send via POST httpPostAsync('file', commsline, callback); }, delete: (filename, _, callback) => { var commsline = 'delete&' + filename; httpPostAsync('file', commsline, callback); }, getpath: (filename, _, callback) => { var commsline = 'getpath&' + filename; //Send via POST httpPostAsync('file', commsline, callback); }, makedir: (filename, _, callback) => { var commsline = 'makedir&' + filename; //Send via POST httpPostAsync('file', commsline, callback); }, copy: (filename, newfilename, callback) => { var commsline = 'copy&' + filename + '&' + newfilename; //Send via POST httpPostAsync('file', commsline, callback); }, move: (filename, newfilename, callback) => { var commsline = 'move&' + filename + '&' + newfilename; //Send via POST httpPostAsync('file', commsline, callback); }, download: (url, _, callback) => { var commsline = 'download&' + url; //Send via POST httpPostAsync('file', commsline, callback); }, upload: (file, _, callback) => { _recurseUploadMDS(file, 0, callback); }, listweb: (folder, _, callback) => { var commsline = 'listweb&' + folder; //Send via POST httpPostAsync('file', commsline, callback); }, copytoweb: (file, webfile, callback) => { var commsline = 'copytoweb&' + file + '&' + webfile; //Send via POST httpPostAsync('file', commsline, callback); }, deletefromweb: (file, _, callback) => { var commsline = 'deletefromweb&' + file; //Send via POST httpPostAsync('file', commsline, callback); }, }, executeRaw: (command, callback) => { return new Promise((resolve) => { httpPostAsync('cmd', command, (data) => { resolve(data); if (callback) { callback(data); } }); }); }, form: { getParams: (parameterName) => { if (isTestEnvironment()) { return null; } var result = null; var tmp = []; var items = window.location.search.substr(1).split('&'); for (var index = 0; index < items.length; index++) { tmp = items[index]?.split('=') ?? []; if (tmp[0] === parameterName) { result = decodeURIComponent(tmp[1] ?? ''); } } return result; }, }, util: { hexToBase64: (hexstring) => { var thex = hexstring; if (hexstring.startsWith('0x')) { thex = hexstring.substring(2); } return btoa((thex.match(/\w{2}/g) || []) .map(function (a) { return String.fromCharCode(parseInt(a, 16)); }) .join('')); }, base64ToHex: (base64) => { const raw = atob(base64); let result = ''; for (let i = 0; i < raw.length; i++) { const hex = raw.charCodeAt(i).toString(16); result += hex.length === 2 ? hex : '0' + hex; } return result.toUpperCase(); }, base64ToArrayBuffer: (base64) => { const binary_string = window.atob(base64); const len = binary_string.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binary_string.charCodeAt(i); } return bytes.buffer; }, getStateVariable: (coin, port) => { //Get the state vars var statvars = coin.state; if (Array.isArray(statvars)) { var len = statvars.length; for (var i = 0; i < len; i++) { var state = statvars[i]; if (state?.port == port) { return state.data; } } } return undefined; }, }, }; function MDSPostMessage(json) { if (MDS_MAIN_CALLBACK) { //Is this an API response call.. if (json.event == 'MDSAPI') { //Check if it is a response.. if (!json.data.request) { //Find the API CALL Object var found = ''; var len = API_CALLS.length; for (var i = 0; i < len; i++) { if (API_CALLS[i].id == json.data.id) { //found it..! found = json.data.id; //Construct a reply.. var reply = {}; reply.status = json.data.status; reply.data = json.data.message; API_CALLS[i].callback(reply); } } //Remove it.. if (found != '') { API_CALLS = API_CALLS.filter(function (apic) { return apic.id != found; }); } else { //MDS.log("API CALL NOT FOUND!"+JSON.stringify(json)); } //Response messages not forwarded - only via API call return; } } //Call the main function MDS_MAIN_CALLBACK(json); } } var PollCounter = 0; var PollSeries = 0; function PollListener() { //The POLL host var pollhost = MDS.mainhost + 'poll?' + 'uid=' + MDS.minidappuid; var polldata = 'series=' + PollSeries + '&counter=' + PollCounter; httpPostAsyncPoll(pollhost, polldata, function (msg) { //Are we on the right Series.. if (PollSeries != msg.series) { //Reset to the right series.. PollSeries = msg.series; PollCounter = msg.counter; } else { //Is there a message ? if (msg.status == true) { //Get the current counter.. PollCounter = msg.response.counter + 1; //And Post the message.. MDSPostMessage(msg.response.message); } } //And around we go again.. PollListener(); }); } function postMDSFail(command, params, status) { //Some error.. if (MDS.logging) { MDS.log('** An error occurred during an MDS command!'); } //Create the message var errormsg = { event: 'MDSFAIL', data: { command: command, params: params, status: status, }, }; //Post it to the stack MDSPostMessage(errormsg); } export function httpPostAsync(theUrl, params, callback) { //Add the MiniDAPP UID.. var finalurl = MDS.TEST_MODE ? MDS.testhost : MDS.mainhost; finalurl += theUrl + '?uid=' + MDS.minidappuid; var testUrl = 'http://' + MDS.DEBUG_HOST + ':' + MDS.DEBUG_PORT + '/' + params; //Do we log it.. if (MDS.logging) { MDS.log('POST_RPC:' + finalurl + ' PARAMS:' + params); } // Use fetch in test mode if (MDS.TEST_MODE) { fetch(testUrl) .then((response) => response.json()) .then((data) => { if (MDS.logging) { MDS.log('RESPONSE:' + JSON.stringify(data)); } if (callback) { callback(data); } }) .catch((error) => { postMDSFail(finalurl, params, error); }); return; } // Original XMLHttpRequest code for non-test mode var xmlHttp = new XMLHttpRequest(); xmlHttp.onreadystatechange = function () { var status = xmlHttp.status; if (xmlHttp.readyState == XMLHttpRequest.DONE) { if (status === 0 || (status >= 200 && status < 400)) { //Do we log it.. if (MDS.logging) { MDS.log('RESPONSE:' + xmlHttp.responseText); } //Send it to the callback function.. if (callback) { try { const responseJson = JSON.parse(xmlHttp.responseText); callback(responseJson); } catch (error) { console.error('Failed to parse response as JSON', error); } } } else { //Some error.. postMDSFail(finalurl, params, xmlHttp.status); } } }; xmlHttp.open('POST', finalurl, true); // true for asynchronous if (xmlHttp.overrideMimeType) { xmlHttp.overrideMimeType('text/plain; charset=UTF-8'); } xmlHttp.send(encodeURIComponent(params)); //xmlHttp.onerror = function () { // console.log("** An error occurred during the transaction"); //}; } function httpPostAsyncPoll(theUrl, params, callback) { //Do we log it.. if (MDS.logging) { MDS.log('POST_POLL_RPC:' + theUrl + ' PARAMS:' + params); } // Use fetch in test mode if (MDS.TEST_MODE) { fetch(theUrl) .then((response) => response.json()) .then((data) => { if (MDS.logging) { MDS.log('RESPONSE:' + JSON.stringify(data)); } if (callback) { callback(data); } }) .catch((error) => { setTimeout(() => { PollListener(); }, 10000); }); return; } // Original XMLHttpRequest code for non-test mode var xmlHttp = new XMLHttpRequest(); xmlHttp.onreadystatechange = function () { var status = xmlHttp.status; if (xmlHttp.readyState == XMLHttpRequest.DONE) { if (status === 0 || (status >= 200 && status < 400)) { //Do we log it.. if (MDS.logging) { MDS.log('RESPONSE:' + xmlHttp.responseText); } //Send it to the callback function.. if (callback) { try { const responseJson = JSON.parse(xmlHttp.responseText); callback(responseJson); } catch (error) { console.error('Failed to parse response as JSON', error); } } } else { //Some error.. postMDSFail(theUrl, params, xmlHttp.status); } } }; xmlHttp.addEventListener('error', function () { MDS.log('Error Polling - reconnect in 10s'); setTimeout(function () { PollListener(); }, 10000); }); xmlHttp.open('POST', theUrl, true); // true for asynchronous if (xmlHttp.overrideMimeType) { xmlHttp.overrideMimeType('text/plain; charset=UTF-8'); } xmlHttp.send(encodeURIComponent(params)); } function _recurseUploadMDS(thefullfile, chunk, callback) { //Get some details var filename = thefullfile.name; var filesize = thefullfile.size; //1MB MAX Chunk size.. var chunk_size = 1024 * 1024; var allchunks = Math.ceil(filesize / chunk_size); //Have we finished.. if (chunk > allchunks - 1) { return; } var startbyte = chunk_size * chunk; var endbyte = startbyte + chunk_size; if (endbyte > filesize) { endbyte = filesize; } //Get a piece of the file var filepiece = thefullfile.slice(startbyte, endbyte); //Create a form.. var formdata = new FormData(); formdata.append('uid', MDS.minidappuid); //Filedata handled a little differently formdata.append('filename', filename); formdata.append('filesize', filesize); formdata.append('allchunks', allchunks); formdata.append('chunknum', chunk); formdata.append('fileupload', filepiece); var request = new XMLHttpRequest(); request.open('POST', '/fileuploadchunk.html'); request.onreadystatechange = function () { var status = request.status; if (request.readyState == XMLHttpRequest.DONE) { if (status === 0 || (status >= 200 && status < 400)) { //Send it to the callback function.. if (callback) { var resp = {}; resp.status = true; resp.filename = filename; resp.size = filesize; resp.allchunks = allchunks; resp.chunk = chunk + 1; resp.start = startbyte; resp.end = endbyte; callback(resp); } //And now continue uploading.. if (callback) { _recurseUploadMDS(thefullfile, chunk + 1, callback); } else { _recurseUploadMDS(thefullfile, chunk + 1); } } else { if (callback) { var resp = {}; resp.status = false; resp.error = request.responseText; resp.filename = filename; resp.size = filesize; resp.allchunks = allchunks; resp.chunk = chunk; resp.start = startbyte; resp.end = endbyte; callback(resp); } //Some error.. MDS.log('MDS FILEUPLOAD CHUNK ERROR: ' + request.responseText); } } }; //And finally send the POST request request.send(formdata); } function isTestEnvironment() { return typeof window === 'undefined' || MDS.TEST_MODE; } //# sourceMappingURL=mds.js.map