helpers.js 16 KB

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