helpers.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. The MIT License (MIT)
  3. Copyright (c) 2014-2018 Nikolai Suslov and the Krestianstvo.org project contributors. (https://github.com/NikolaySuslov/livecodingspace/blob/master/LICENSE.md)
  4. Virtual World Framework Apache 2.0 license (https://github.com/NikolaySuslov/livecodingspace/blob/master/licenses/LICENSE_VWF.md)
  5. */
  6. class Helpers {
  7. constructor() {
  8. console.log("helpers constructor");
  9. // List of valid ID characters for use in an instance.
  10. this.ValidIDChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  11. // List of valid extensions for VWF components.
  12. this.template_extensions = ["", ".yaml", ".json"];
  13. this.applicationRoot = "/"; //app
  14. }
  15. reduceSaveObject(path) {
  16. let obj = Object.assign({}, path);
  17. if (path.saveObject) {
  18. if (path.saveObject["queue"]) {
  19. if (path.saveObject["queue"]["time"]) {
  20. obj.saveObject = {
  21. "init": true,
  22. "queue": {
  23. "time": path.saveObject["queue"]["time"]
  24. }
  25. }
  26. }
  27. }
  28. }
  29. return obj
  30. }
  31. // IsInstanceID tests if the passed in potential Instance ID
  32. // is a valid instance id.
  33. IsInstanceID(potentialInstanceID) {
  34. if (potentialInstanceID.match(/^[0-9A-Za-z]{16}$/)) {
  35. return true;
  36. }
  37. return false;
  38. }
  39. // GenerateInstanceID function creates a randomly generated instance ID.
  40. GenerateInstanceID() {
  41. var text = "";
  42. for (var i = 0; i < 16; i++)
  43. text += this.ValidIDChars.charAt(Math.floor(Math.random() * this.ValidIDChars.length));
  44. return text;
  45. }
  46. // JoinPath
  47. // Takes multiple arguments, joins them together into one path.
  48. JoinPath( /* arguments */) {
  49. var result = "";
  50. if (arguments.length > 0) {
  51. if (arguments[0]) {
  52. result = arguments[0];
  53. }
  54. for (var index = 1; index < arguments.length; index++) {
  55. var newSegment = arguments[index];
  56. if (newSegment == undefined) {
  57. newSegment = "";
  58. }
  59. if ((newSegment[0] == "/") && (result[result.length - 1] == "/")) {
  60. result = result + newSegment.slice(1);
  61. } else if ((newSegment[0] == "/") || (result[result.length - 1] == "/")) {
  62. result = result + newSegment;
  63. } else {
  64. result = result + "/" + newSegment;
  65. }
  66. //result = libpath.join( result, newSegment );
  67. }
  68. }
  69. return result;
  70. }
  71. GetNamespace(processedURL) {
  72. if ((processedURL['instance']) && (processedURL['public_path'])) {
  73. return this.JoinPath(processedURL['public_path'], processedURL['application'], processedURL['instance']);
  74. }
  75. return undefined;
  76. }
  77. // GenerateSegments takes a string, breaks it into
  78. // '/' separated segments, and removes potential
  79. // blank first and last segments.
  80. GenerateSegments(argument) {
  81. var result = argument.split("/");
  82. if (result.length > 0) {
  83. if (result[0] == "") {
  84. result.shift();
  85. }
  86. }
  87. if (result.length > 0) {
  88. if (result[result.length - 1] == "") {
  89. result.pop();
  90. }
  91. }
  92. return result;
  93. }
  94. getInstanceID(obj) {
  95. // "/world/index.vwf/CcI3c1MnTsblg3H7"
  96. return obj.split('/')[3]
  97. }
  98. get appPath() {
  99. return JSON.parse(localStorage.getItem('lcs_app')).path.public_path.slice(1)
  100. }
  101. get worldStateName() {
  102. let appConfig = JSON.parse(localStorage.getItem('lcs_app'));
  103. var saveName = appConfig.path.public_path.slice(1);
  104. let privatePath = appConfig.path.private_path;
  105. if (privatePath) {
  106. if (privatePath.indexOf('load') !== -1) {
  107. saveName = privatePath.split('/')[1];
  108. }
  109. }
  110. return saveName
  111. }
  112. getRoot() {
  113. let data = JSON.parse(localStorage.getItem('lcs_app'));
  114. return {
  115. "root": data.path.public_path.slice(1),
  116. "inst": data.path.instance,
  117. "user": data.user
  118. }
  119. }
  120. get worldUser() {
  121. return this.getRoot(false).root.split('/')[0];
  122. }
  123. randId() {
  124. return '_' + Math.random().toString(36).substr(2, 9);
  125. }
  126. getRandomInt(min, max) {
  127. min = Math.ceil(min);
  128. max = Math.floor(max);
  129. return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
  130. }
  131. GUID() {
  132. var S4 = function () {
  133. return Math.floor(
  134. Math.random() * 0x10000 /* 65536 */
  135. ).toString(16);
  136. };
  137. return (
  138. S4() + S4() + "-" +
  139. S4() + "-" +
  140. S4() + "-" +
  141. S4() + "-" +
  142. S4() + S4() + S4()
  143. );
  144. }
  145. async sha256(message) {
  146. // encode as UTF-8
  147. const msgBuffer = new TextEncoder('utf-8').encode(message);
  148. // hash the message
  149. const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
  150. // convert ArrayBuffer to Array
  151. const hashArray = Array.from(new Uint8Array(hashBuffer));
  152. // convert bytes to hex string
  153. const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
  154. return hashHex;
  155. }
  156. replaceSubStringALL(target, search, replacement) {
  157. return target.split(search).join(replacement);
  158. };
  159. convertFileSource(file, source) {
  160. //var source = (typeof(sourceToEdit) =="object") ? JSON.stringify(sourceToEdit): sourceToEdit;
  161. var convert;
  162. if (file.includes('_json') && (typeof source !== 'object')) {
  163. convert = (typeof JSON.parse(source) == 'object') ? JSON.stringify(JSON.parse(source), null, '\t') : source
  164. //source = source;//JSON.stringify(source, null, '\t');
  165. } else if (typeof source == 'object') {
  166. convert = JSON.stringify(source, null, '\t')
  167. } else if (typeof source == 'string') {
  168. convert = source
  169. }
  170. return convert
  171. }
  172. async getHtmlText(url) {
  173. let file = await fetch(url, { method: 'get' });
  174. let text = await file.text();
  175. return text
  176. }
  177. removeProps(obj) {
  178. let rm = L.lazy(rec =>
  179. L.ifElse(R.is(String),
  180. L.when(x => x == 'id'
  181. || x == 'patches'
  182. || x == 'random'
  183. || x == 'sequence'), [L.keysEverywhere, rec], L.optional)
  184. );
  185. return L.remove(rm, obj)
  186. // Object.keys(obj).forEach(key =>
  187. // (key === 'id' || key === 'patches' || key === 'random' || key === 'sequence') && delete obj[key] ||
  188. // (obj[key] && typeof obj[key] === 'object') && this.removeProps(obj[key])
  189. // );
  190. //return obj;
  191. };
  192. removeGrammarObj(obj) {
  193. let rm = L.lazy(rec =>
  194. L.ifElse(R.is(String),
  195. L.when(x => x == 'grammar'
  196. || x == 'semantics'), [L.keysEverywhere, rec], L.optional)
  197. );
  198. return L.remove(rm, obj)
  199. // Object.keys(obj).forEach(key =>
  200. // (key === 'grammar' || key === 'semantics') && delete obj[key] ||
  201. // (obj[key] && typeof obj[key] === 'object') && this.removeGrammarObj(obj[key])
  202. // );
  203. // return obj;
  204. };
  205. collectMethods(obj) {
  206. let files = {};
  207. Object.keys(obj.children).forEach(childName => {
  208. let child = obj.children[childName];
  209. if (child.scritps && child.methods)
  210. files[childName] = "";
  211. let methods = child.methods;
  212. Object.keys(methods).forEach(el => {
  213. let method = methods[el];
  214. if (method.body) {
  215. let params = method.parameters ? method.parameters.toString() : '';
  216. let funDef = "this." + el + ' = function(' + params + ') { \n' + method.body + '\n' + '}';
  217. files[childName] = files[childName].concat('\n').concat(funDef);
  218. }
  219. })
  220. })
  221. return files
  222. }
  223. getNodeJSProps(nodeID) {
  224. let node = vwf.models.javascript.nodes[nodeID]
  225. return node
  226. }
  227. getWorldProto() {
  228. let worldID = vwf.application();
  229. let nodeDef = this.getNodeDef(worldID);
  230. const rm = L.lazy(rec =>
  231. L.ifElse(R.is(String), L.when(x => x.includes('avatar-') || x.includes('xcontroller-') || x.includes('gearvr-')), [L.keys, rec], L.optional)
  232. )
  233. let fixedDef = L.remove(['children', L.props(rm)], nodeDef)
  234. return fixedDef
  235. }
  236. getNodeDef(nodeID) {
  237. let node = vwf.getNode(nodeID, true);
  238. let nodeDefPure = this.removeProps(node);
  239. let nodeDef = this.removeGrammarObj(nodeDefPure);
  240. let finalDef = this.replaceFloatArraysInNodeDef(nodeDef);
  241. return finalDef
  242. }
  243. replaceFloatArraysInNodeDef(state) {
  244. var objectIsTypedArray = function (candidate) {
  245. var typedArrayTypes = [
  246. Int8Array,
  247. Uint8Array,
  248. // Uint8ClampedArray,
  249. Int16Array,
  250. Uint16Array,
  251. Int32Array,
  252. Uint32Array,
  253. Float32Array,
  254. Float64Array
  255. ];
  256. var isTypedArray = false;
  257. if (typeof candidate == "object" && candidate != null) {
  258. typedArrayTypes.forEach(function (typedArrayType) {
  259. isTypedArray = isTypedArray || candidate instanceof typedArrayType;
  260. });
  261. }
  262. return isTypedArray;
  263. };
  264. var transitTransformation = function (object) {
  265. return objectIsTypedArray(object) ?
  266. Array.prototype.slice.call(object) : object;
  267. };
  268. let value = require("vwf/utility").transform(
  269. state, transitTransformation
  270. );
  271. return value
  272. }
  273. httpGet(url) {
  274. return new Promise(function (resolve, reject) {
  275. // do the usual Http request
  276. let request = new XMLHttpRequest();
  277. request.open('GET', url);
  278. request.onload = function () {
  279. if (request.status == 200) {
  280. resolve(request.response);
  281. } else {
  282. reject(Error(request.statusText));
  283. }
  284. };
  285. request.onerror = function () {
  286. reject(Error('Network Error'));
  287. };
  288. request.send();
  289. });
  290. }
  291. async httpGetJson(url) {
  292. // check if the URL looks like a JSON file and call httpGet.
  293. let regex = /\.(json)$/i;
  294. if (regex.test(url)) {
  295. // call the async function, wait for the result
  296. return await this.httpGet(url);
  297. } else {
  298. throw Error('Bad Url Format');
  299. }
  300. }
  301. authUser(alias, pass) {
  302. let self = this;
  303. _LCSDB.user().auth(alias, pass
  304. , function (ack) {
  305. if (ack.err) {
  306. self.notyErr(ack.err)
  307. }
  308. }
  309. );
  310. }
  311. testJSON(text) {
  312. if (typeof text !== "string") {
  313. return false;
  314. }
  315. try {
  316. JSON.parse(text);
  317. return true;
  318. }
  319. catch (error) {
  320. return false;
  321. }
  322. }
  323. async getUserPub(userName) {
  324. //TODO: Fix for using hashids instead users aliases with pubs sorted by time of registration
  325. let alias = '~@' + userName;
  326. let user = await (new Promise(res => _LCSDB.get(alias).once(res)));
  327. if (user) {
  328. if (Object.keys(user).length > 1) {
  329. let pubs = await Promise.all(Object.keys(user).filter(el => el !== '_').map(el => _LCSDB.user(el.slice(1)).then(res => {
  330. let ts = Gun.state.is(res, 'pub')
  331. return { pub: res.pub, time: ts }
  332. })))
  333. //console.log(pubs);
  334. pubs.sort(function (a, b) {
  335. return new Date(b.time) - new Date(a.time);
  336. });
  337. return pubs[0].pub
  338. } else {
  339. return Object.keys(user)[1].slice(1)
  340. }
  341. }
  342. }
  343. checkUserCollision() {
  344. //TODO: Fix for using hashids instead users aliases with pubs sorted by time of registration
  345. _app.helpers.getUserPub(_LCSDB.user().is.alias).then(res => {
  346. if (_LCSDB.user().is.pub !== res) {
  347. if (window.confirm("ERROR: User name collision. Try to delete user collision?")) {
  348. _LCSDB.user().delete();
  349. window.reload();
  350. }
  351. }
  352. })
  353. }
  354. async getUserAlias(userPub) {
  355. let user = await (new Promise(res => _LCSDB.user(userPub).get('alias').once(res)));
  356. if (user)
  357. return user
  358. }
  359. notyOK(msg) {
  360. let noty = new Noty({
  361. text: msg,
  362. timeout: 2000,
  363. theme: 'mint',
  364. layout: 'bottomRight',
  365. type: 'success'
  366. });
  367. noty.show();
  368. }
  369. notyErr(msg) {
  370. let noty = new Noty({
  371. text: msg,
  372. timeout: 2000,
  373. theme: 'mint',
  374. layout: 'bottomRight',
  375. type: 'error'
  376. });
  377. noty.show();
  378. }
  379. }
  380. export { Helpers }