2020-06-08 12:17:56 -04:00
|
|
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
|
|
|
|
|
2022-02-10 22:59:29 -05:00
|
|
|
// ensure each app gets a local version-specific copy, not shared
|
2020-05-29 13:16:38 -04:00
|
|
|
function require_fresh(path) {
|
|
|
|
|
const rpa = require.resolve(path);
|
|
|
|
|
delete require.cache[rpa];
|
|
|
|
|
return require(rpa);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const fs = require('fs');
|
2022-01-13 22:48:34 -05:00
|
|
|
const uglify = require('uglify-js');
|
2020-05-29 13:16:38 -04:00
|
|
|
const moment = require('moment');
|
|
|
|
|
const agent = require('express-useragent');
|
2021-12-27 10:14:21 -05:00
|
|
|
const license = require_fresh('./src/moto/license.js');
|
2020-05-30 20:39:56 -04:00
|
|
|
const version = license.VERSION || "rogue";
|
2024-05-17 01:04:13 -04:00
|
|
|
const netdb = require('@gridspace/net-level-client');
|
2024-06-14 17:48:01 -04:00
|
|
|
const PATH = require('path');
|
2020-05-29 13:16:38 -04:00
|
|
|
|
|
|
|
|
const fileCache = {};
|
|
|
|
|
const code_src = {};
|
|
|
|
|
const code = {};
|
|
|
|
|
const mods = {};
|
|
|
|
|
const load = [];
|
2020-06-03 22:39:30 -04:00
|
|
|
const synth = {};
|
2020-06-04 00:15:48 -04:00
|
|
|
const api = {};
|
2024-06-27 21:50:54 -04:00
|
|
|
const wrap = {};
|
2020-05-29 13:16:38 -04:00
|
|
|
|
2024-06-14 17:48:01 -04:00
|
|
|
let forceUseCache = false;
|
2022-09-23 13:24:13 -04:00
|
|
|
let serviceWorker = true;
|
2022-09-23 12:55:14 -04:00
|
|
|
let crossOrigin = false;
|
2020-12-13 09:55:30 -05:00
|
|
|
let setupFn;
|
2020-05-30 18:16:40 -04:00
|
|
|
let cacheDir;
|
2020-05-29 13:16:38 -04:00
|
|
|
let startTime;
|
2021-01-26 09:03:02 -05:00
|
|
|
let oversion;
|
2022-02-04 15:31:45 -05:00
|
|
|
let dversion;
|
2020-05-29 13:16:38 -04:00
|
|
|
let lastmod;
|
|
|
|
|
let logger;
|
|
|
|
|
let debug;
|
2022-09-01 11:12:24 -04:00
|
|
|
let over;
|
2020-05-30 18:16:40 -04:00
|
|
|
let http;
|
2020-05-29 13:16:38 -04:00
|
|
|
let util;
|
|
|
|
|
let dir;
|
2020-05-30 18:16:40 -04:00
|
|
|
let log;
|
2020-05-29 13:16:38 -04:00
|
|
|
|
2022-02-10 22:59:29 -05:00
|
|
|
const EventEmitter = require('events');
|
|
|
|
|
class AppEmitter extends EventEmitter {}
|
|
|
|
|
const events = new AppEmitter();
|
|
|
|
|
|
2024-05-17 01:04:13 -04:00
|
|
|
netdb.create = async function(map = {}) {
|
|
|
|
|
if (util.isfile(map.conf)) {
|
|
|
|
|
Object.assign(map, JSON.parse(fs.readFileSync(map.conf)));
|
|
|
|
|
}
|
|
|
|
|
const client = new netdb();
|
|
|
|
|
if (map.host && map.port) await client.open(map.host, map.port);
|
|
|
|
|
if (map.user && map.pass) await client.auth(map.user, map.pass);
|
|
|
|
|
if (map.base) await client.use(map.base);
|
|
|
|
|
logger.log({ netdb: map.host, user: map.user, base: map.base });
|
|
|
|
|
return client;
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-29 07:14:20 -04:00
|
|
|
// experimental wrapping of esm modules using embedded data urls
|
|
|
|
|
function wrap_module(buf, as) {
|
2024-06-30 15:27:37 -04:00
|
|
|
const base64 = Buffer.from(buf).toString('base64');
|
2024-06-29 07:14:20 -04:00
|
|
|
const path = as.split('.');
|
|
|
|
|
const exp = path.pop();
|
2024-06-27 21:50:54 -04:00
|
|
|
return [
|
2024-06-29 07:14:20 -04:00
|
|
|
`gapp.register("${path.join('.')}", [], (root, exports) => {`,
|
|
|
|
|
`const url = "data:text/javascript;base64,${base64}";`,
|
|
|
|
|
`exports({ ["${exp}"]: import(url) });`,
|
2024-06-27 21:50:54 -04:00
|
|
|
"});"
|
|
|
|
|
].join('\n');
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-22 00:05:29 -05:00
|
|
|
function addonce(array, v) {
|
|
|
|
|
if (array.indexOf(v) < 0) {
|
|
|
|
|
array.push(v);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-29 13:16:38 -04:00
|
|
|
function init(mod) {
|
2024-06-16 21:48:41 -04:00
|
|
|
const ENV = mod.env;
|
|
|
|
|
|
2020-05-29 13:16:38 -04:00
|
|
|
startTime = time();
|
|
|
|
|
lastmod = mod.util.lastmod;
|
|
|
|
|
logger = mod.log;
|
2024-06-16 21:48:41 -04:00
|
|
|
debug = ENV.debug || mod.meta.debug;
|
|
|
|
|
oversion = ENV.over || mod.meta.over;
|
2025-02-10 19:45:04 -05:00
|
|
|
crossOrigin = ENV.xorigin || mod.meta.xorigin || debug;
|
2024-06-16 21:48:41 -04:00
|
|
|
serviceWorker = (ENV.service || mod.meta.service) !== false;
|
2020-05-30 18:16:40 -04:00
|
|
|
http = mod.http;
|
2020-05-29 13:16:38 -04:00
|
|
|
util = mod.util;
|
|
|
|
|
dir = mod.dir;
|
2020-05-30 18:16:40 -04:00
|
|
|
log = mod.log;
|
2020-07-05 20:14:52 -04:00
|
|
|
|
2024-06-16 21:48:41 -04:00
|
|
|
if (ENV.single) console.log({ cwd: process.cwd(), env: ENV });
|
2022-09-01 11:12:24 -04:00
|
|
|
dversion = debug ? `_${version}` : version;
|
2024-06-16 21:48:41 -04:00
|
|
|
cacheDir = ENV.cache || mod.util.datadir("cache");
|
|
|
|
|
if (ENV.single) logger.log({ cacheDir });
|
|
|
|
|
forceUseCache = ENV.cache ? true : false;
|
2020-05-29 13:16:38 -04:00
|
|
|
|
2024-06-14 17:48:01 -04:00
|
|
|
const approot = PATH.join("main","gapp");
|
2022-02-22 00:05:29 -05:00
|
|
|
const refcache = {};
|
|
|
|
|
const callstack = [];
|
|
|
|
|
let xxxx = false;
|
2021-12-29 10:37:17 -05:00
|
|
|
|
2024-06-29 07:14:20 -04:00
|
|
|
function find_refs(cache, path, ismod) {
|
2022-02-22 00:05:29 -05:00
|
|
|
let rec = refcache[path];
|
|
|
|
|
if (rec) {
|
|
|
|
|
let crec = cache[path];
|
|
|
|
|
if (!crec) {
|
|
|
|
|
cache[path] = rec;
|
|
|
|
|
for (let d of rec.deps) find_refs(cache, d);
|
2022-02-22 11:32:35 -05:00
|
|
|
for (let u of rec.uses) find_refs(cache, u);
|
2021-12-30 22:59:46 -05:00
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
return;
|
2021-12-30 22:59:46 -05:00
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
callstack.push(path);
|
|
|
|
|
rec = cache[path] = refcache[path] = {
|
|
|
|
|
uses: [],
|
|
|
|
|
deps: [ approot ]
|
|
|
|
|
};
|
2024-06-14 17:48:01 -04:00
|
|
|
let full = PATH.join(dir,"src",`${path}.js`);
|
2022-02-22 00:05:29 -05:00
|
|
|
try {
|
|
|
|
|
fs.lstatSync(full);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log({missing: full, callstack});
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
2024-06-29 07:14:20 -04:00
|
|
|
// skip interrogating file if it's a module (external compacted)
|
|
|
|
|
if (ismod) {
|
|
|
|
|
wrap[`src/${path}.js`] = path.replaceAll('/','.');
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
let lines = fs.readFileSync(full)
|
2021-12-29 10:37:17 -05:00
|
|
|
.toString()
|
|
|
|
|
.split('\n');
|
|
|
|
|
for (let line of lines) {
|
2022-02-22 00:05:29 -05:00
|
|
|
let arr, pos;
|
2022-02-20 12:56:43 -05:00
|
|
|
let upos = line.indexOf('// use:');
|
|
|
|
|
if (upos >= 0) {
|
2022-02-22 00:05:29 -05:00
|
|
|
arr = rec.uses;
|
|
|
|
|
pos = upos + 7;
|
2022-02-20 12:56:43 -05:00
|
|
|
}
|
2021-12-29 10:37:17 -05:00
|
|
|
let dpos = line.indexOf('// dep:');
|
|
|
|
|
if (dpos >= 0) {
|
2022-02-22 00:05:29 -05:00
|
|
|
arr = rec.deps;
|
|
|
|
|
pos = dpos + 7;
|
|
|
|
|
}
|
2024-06-29 07:14:20 -04:00
|
|
|
let mpos = line.indexOf('// mod:');
|
|
|
|
|
if (mpos >= 0) {
|
|
|
|
|
arr = rec.deps;
|
|
|
|
|
pos = mpos + 7;
|
|
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
if (upos >= 0 && dpos >= 0) {
|
|
|
|
|
console.log(`invalid line: ${line}`);
|
|
|
|
|
process.exit();
|
|
|
|
|
}
|
|
|
|
|
if (arr && pos >= 0) {
|
|
|
|
|
let path = line.substring(pos).trim().replace(/\./g,'/').trim();
|
|
|
|
|
addonce(arr, path);
|
2024-06-29 07:14:20 -04:00
|
|
|
find_refs(cache, path, mpos >= 0);
|
2022-02-22 00:05:29 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if (xxxx) console.log({path, ...rec});
|
2022-02-22 11:32:35 -05:00
|
|
|
if (false) {
|
|
|
|
|
let seek = 'mesh/api';
|
|
|
|
|
if (rec.uses.indexOf(seek) >= 0 || rec.deps.indexOf(seek) >= 0) {
|
|
|
|
|
console.log({PULLS:seek, path});
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
callstack.pop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return record position indicated by path
|
|
|
|
|
function pos(path, list) {
|
|
|
|
|
for (let i=0; i<list.length; i++) {
|
|
|
|
|
if (list[i].path === path) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-29 07:14:20 -04:00
|
|
|
console.trace(`not found: ${path}`);
|
2022-02-22 00:05:29 -05:00
|
|
|
process.exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function order_refs(cache) {
|
|
|
|
|
const recs = Object.entries(cache).map(entry => {
|
|
|
|
|
return { path: entry[0], deps: entry[1].deps }
|
|
|
|
|
}).sort((a,b) => {
|
|
|
|
|
return a.path === b.path ? 0 : a.path < b.path ? -1 : 1;
|
|
|
|
|
});
|
|
|
|
|
if (xxxx) console.log({ordering: recs});
|
|
|
|
|
|
|
|
|
|
// for each rec, ensure that dependencies are inserted before it
|
|
|
|
|
let lrec = recs.slice();
|
|
|
|
|
for (let rec of lrec) {
|
|
|
|
|
let { path, deps } = rec;
|
|
|
|
|
for (let dep of deps) {
|
|
|
|
|
let rpos = pos(path, recs);
|
|
|
|
|
let dpos = pos(dep, recs);
|
|
|
|
|
if (dpos > rpos) {
|
|
|
|
|
let drec = recs[dpos];
|
|
|
|
|
// remove old dep record
|
|
|
|
|
recs.splice(dpos, 1);
|
|
|
|
|
// insert dep before
|
|
|
|
|
recs.splice(rpos, 0, drec);
|
|
|
|
|
let nrpos = pos(path, recs);
|
|
|
|
|
let ndpos = pos(dep, recs);
|
|
|
|
|
let fail = nrpos != ndpos + 1;
|
|
|
|
|
// if (xxxx) { console.log({move: dep, dpos, before: path, rpos}); }
|
|
|
|
|
if (fail) {
|
|
|
|
|
console.log({move: dep, dpos, before: path, rpos, ndpos, nrpos, recs: recs.slice(0,10)});
|
|
|
|
|
process.exit();
|
|
|
|
|
}
|
2021-12-29 10:37:17 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
if (xxxx) console.log({recs});
|
|
|
|
|
return recs.map(rec => rec.path);
|
2021-12-29 10:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
2021-12-29 08:10:51 -05:00
|
|
|
// process script dependencies, expand paths
|
2022-02-22 00:05:29 -05:00
|
|
|
for (let [ key, val ] of Object.entries(script)) {
|
|
|
|
|
if (val.indexOf(approot) < 0) {
|
|
|
|
|
val = [ approot, ...val ];
|
|
|
|
|
}
|
|
|
|
|
const list = val.map(p => p.charAt(0) === '&' ? p.substring(1) : p);
|
|
|
|
|
const cache = {};
|
|
|
|
|
const roots = [];
|
2022-02-22 22:00:50 -05:00
|
|
|
// xxxx = key === "kiri_work";
|
2022-02-22 00:05:29 -05:00
|
|
|
// for each path in the list, find deps and add to list
|
2021-12-29 08:10:51 -05:00
|
|
|
for (let path of val) {
|
2021-12-29 10:37:17 -05:00
|
|
|
let fc = path.charAt(0);
|
|
|
|
|
if (fc === '@') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-06-27 21:50:54 -04:00
|
|
|
if (fc === '#') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-12-29 10:37:17 -05:00
|
|
|
if (fc === '&') {
|
|
|
|
|
path = path.substring(1);
|
2022-02-22 00:05:29 -05:00
|
|
|
addonce(roots, path);
|
2021-12-29 10:37:17 -05:00
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
find_refs(cache, path);
|
|
|
|
|
}
|
2024-06-29 07:14:20 -04:00
|
|
|
if (xxxx) console.log({ processing: key, val });
|
2022-02-22 00:05:29 -05:00
|
|
|
let refs = order_refs(cache).filter(p => roots.indexOf(p) < 0);
|
|
|
|
|
// remove paths that are in refs
|
|
|
|
|
let paths = list.filter(p => {
|
|
|
|
|
if (p.charAt(0) === '&') {
|
|
|
|
|
p = p.substring(1);
|
2021-12-29 08:10:51 -05:00
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
return refs.indexOf(p) < 0 && roots.indexOf(p) < 0;
|
|
|
|
|
});
|
|
|
|
|
// when dependency roots exist, re-write val array
|
|
|
|
|
if (roots.length) {
|
|
|
|
|
val = [...refs, ...paths, ...roots];
|
2021-12-29 08:10:51 -05:00
|
|
|
}
|
2022-02-22 00:05:29 -05:00
|
|
|
// val.splice(1, 0, ...roots);
|
|
|
|
|
if (xxxx) console.log({key, cache, refs, paths, roots, val});
|
2024-06-27 21:50:54 -04:00
|
|
|
script[key] = val.map(p => {
|
|
|
|
|
let fc = p.charAt(0);
|
|
|
|
|
if (fc === '@') return p;
|
|
|
|
|
if (fc === '#') {
|
2024-06-29 07:14:20 -04:00
|
|
|
fc = p.split('#');
|
|
|
|
|
let nupath = `src/${fc[1]}.js`;
|
|
|
|
|
wrap[nupath] = fc[1].replaceAll('/','.');
|
2024-06-27 21:50:54 -04:00
|
|
|
return nupath;
|
|
|
|
|
}
|
|
|
|
|
return `src/${p}.js`;
|
|
|
|
|
});
|
2022-02-23 09:29:33 -05:00
|
|
|
// console.log({script: key, files: script[key]});
|
2021-12-29 08:10:51 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-30 18:16:40 -04:00
|
|
|
mod.on.test((req) => {
|
2020-06-12 11:51:02 -04:00
|
|
|
let cookie = cookieValue(req.headers.cookie, "version") || undefined;
|
2020-11-20 09:46:10 -05:00
|
|
|
let vmatch = mod.meta.version || "*";
|
|
|
|
|
if (!Array.isArray(vmatch)) {
|
|
|
|
|
vmatch = [ vmatch ];
|
|
|
|
|
}
|
|
|
|
|
if (vmatch.indexOf("*") >= 0) {
|
|
|
|
|
return true;
|
2020-05-30 18:16:40 -04:00
|
|
|
}
|
2020-11-20 09:46:10 -05:00
|
|
|
return vmatch.indexOf(cookie) >= 0;
|
2020-05-30 18:16:40 -04:00
|
|
|
});
|
2020-05-29 13:16:38 -04:00
|
|
|
|
2020-12-13 09:55:30 -05:00
|
|
|
mod.add(handleSetup);
|
2020-05-29 13:16:38 -04:00
|
|
|
mod.add(handleOptions);
|
2022-10-22 11:02:02 -04:00
|
|
|
mod.add(handleWasm);
|
2020-05-29 13:16:38 -04:00
|
|
|
mod.add(fullpath({
|
2020-05-30 21:26:01 -04:00
|
|
|
"/kiri" : redir("/kiri/", 301),
|
2021-12-16 19:11:52 -05:00
|
|
|
"/mesh" : redir("/mesh/", 301),
|
2020-05-30 21:26:01 -04:00
|
|
|
"/meta" : redir("/meta/", 301),
|
|
|
|
|
"/kiri/index.html" : redir("/kiri/", 301),
|
2021-12-16 19:11:52 -05:00
|
|
|
"/mesh/index.html" : redir("/mesh/", 301),
|
2020-05-30 21:26:01 -04:00
|
|
|
"/meta/index.html" : redir("/meta/", 301)
|
2020-05-29 13:16:38 -04:00
|
|
|
}));
|
2020-05-30 20:39:56 -04:00
|
|
|
mod.add(handleVersion);
|
2020-05-29 13:16:38 -04:00
|
|
|
mod.add(prepath([
|
|
|
|
|
[ "/code/", handleCode ],
|
2022-10-22 11:02:02 -04:00
|
|
|
// [ "/wasm/", handleWasm ]
|
2020-05-29 13:16:38 -04:00
|
|
|
]));
|
|
|
|
|
mod.add(fixedmap("/api/", api));
|
|
|
|
|
if (debug) {
|
|
|
|
|
mod.static("/mod/", "mod");
|
2025-01-25 18:03:56 -05:00
|
|
|
mod.static("/mods/", "mods");
|
2020-05-30 18:16:40 -04:00
|
|
|
mod.sync("/reload", () => {
|
|
|
|
|
mod.reload();
|
|
|
|
|
return "reload";
|
|
|
|
|
});
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
2020-05-30 21:26:01 -04:00
|
|
|
mod.add(rewriteHtmlVersion);
|
2024-06-27 21:50:54 -04:00
|
|
|
mod.add((req, res, next) => {
|
|
|
|
|
const path = req.gs.path.substring(1);
|
|
|
|
|
if (wrap[path]) {
|
2024-06-29 07:14:20 -04:00
|
|
|
const data = getCachedFile(path, file => {
|
2024-06-30 15:27:37 -04:00
|
|
|
console.log({ hot_wrap: file });
|
2024-06-29 07:14:20 -04:00
|
|
|
return fs.readFileSync(file);
|
2024-06-27 21:50:54 -04:00
|
|
|
});
|
2024-06-29 07:14:20 -04:00
|
|
|
res.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
|
2024-06-27 21:50:54 -04:00
|
|
|
return res.end(data);
|
|
|
|
|
}
|
|
|
|
|
next();
|
|
|
|
|
});
|
2021-09-01 13:50:28 -04:00
|
|
|
mod.static("/src/", "src");
|
2020-05-29 13:16:38 -04:00
|
|
|
mod.static("/obj/", "web/obj");
|
2021-12-16 19:11:52 -05:00
|
|
|
mod.static("/font/", "web/font");
|
2024-07-28 15:02:35 -04:00
|
|
|
mod.static("/fon2/", "web/fon2");
|
2021-12-16 19:11:52 -05:00
|
|
|
mod.static("/mesh/", "web/mesh");
|
2020-05-29 13:16:38 -04:00
|
|
|
mod.static("/moto/", "web/moto");
|
2020-05-30 21:26:01 -04:00
|
|
|
mod.static("/meta/", "web/meta");
|
2020-05-29 13:16:38 -04:00
|
|
|
mod.static("/kiri/", "web/kiri");
|
|
|
|
|
|
2025-01-25 18:03:56 -05:00
|
|
|
function load_modules(root, force) {
|
|
|
|
|
// load modules
|
|
|
|
|
lastmod(`${dir}/${root}`) && fs.readdirSync(`${dir}/${root}`).forEach(mdir => {
|
|
|
|
|
const modpath = `${root}/${mdir}`;
|
2025-02-04 16:59:06 -05:00
|
|
|
if (dir.charAt(0) === '.' && !ENV.single) return;
|
2025-01-25 18:03:56 -05:00
|
|
|
const stats = fs.lstatSync(`${mod.dir}/${modpath}`);
|
|
|
|
|
if (!(stats.isDirectory() || stats.isSymbolicLink())) return;
|
|
|
|
|
if (util.isfile(PATH.join(mod.dir,modpath,".disable"))) return;
|
|
|
|
|
const isDebugMod = util.isfile(PATH.join(mod.dir,modpath,".debug"));
|
|
|
|
|
const isElectronMod = util.isfile(PATH.join(mod.dir,modpath,".electron"));
|
|
|
|
|
if (force || (ENV.electron && !isElectronMod)) return;
|
|
|
|
|
if (force || (!ENV.electron && isElectronMod && !isDebugMod)) return;
|
|
|
|
|
try {
|
|
|
|
|
loadModule(mod, modpath);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.log({ module: mdir, error });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// load development and 3rd party modules
|
|
|
|
|
load_modules('mod');
|
|
|
|
|
|
|
|
|
|
// load optional local modules
|
|
|
|
|
load_modules('mods');
|
2020-05-29 13:16:38 -04:00
|
|
|
|
|
|
|
|
// run loads injected by modules
|
|
|
|
|
while (load.length) {
|
|
|
|
|
try {
|
|
|
|
|
load.shift()();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.log({on_load_fail: e});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// runs after module loads / injects
|
|
|
|
|
prepareScripts();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// either add module assets to path or require(init.js)
|
|
|
|
|
function loadModule(mod, dir) {
|
|
|
|
|
if (dir.indexOf('node_modules') >= 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (lastmod(`${mod.dir}/${dir}/.ignore`)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
lastmod(`${mod.dir}/${dir}/init.js`) ?
|
|
|
|
|
initModule(mod, `./${dir}/init.js`, dir) :
|
|
|
|
|
mod.static("/", `${mod.dir}/${dir}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// load module and call returned function with helper object
|
|
|
|
|
function initModule(mod, file, dir) {
|
|
|
|
|
logger.log({module: file});
|
|
|
|
|
require_fresh(file)({
|
2022-02-10 22:59:29 -05:00
|
|
|
// express functions added here show up at "/api/" url root
|
2020-05-29 13:16:38 -04:00
|
|
|
api: api,
|
|
|
|
|
adm: {
|
2021-01-26 09:03:02 -05:00
|
|
|
reload: prepareScripts,
|
2022-09-23 12:55:14 -04:00
|
|
|
setver: (ver) => { oversion = ver },
|
|
|
|
|
crossOrigin: (bool) => { crossOrigin = bool }
|
2020-05-29 13:16:38 -04:00
|
|
|
},
|
2022-02-10 22:59:29 -05:00
|
|
|
events,
|
2020-05-29 13:16:38 -04:00
|
|
|
const: {
|
|
|
|
|
args: {},
|
2020-06-04 00:31:59 -04:00
|
|
|
meta: mod.meta,
|
2020-05-29 13:16:38 -04:00
|
|
|
debug: debug,
|
|
|
|
|
script: script,
|
|
|
|
|
moddir: dir,
|
|
|
|
|
rootdir: mod.dir,
|
2022-09-01 11:12:24 -04:00
|
|
|
version: oversion || version
|
2020-05-29 13:16:38 -04:00
|
|
|
},
|
2020-07-06 18:36:57 -04:00
|
|
|
env: mod.env,
|
2020-05-29 13:16:38 -04:00
|
|
|
pkg: {
|
|
|
|
|
agent,
|
2024-05-17 01:04:13 -04:00
|
|
|
moment,
|
|
|
|
|
netdb,
|
2020-05-29 13:16:38 -04:00
|
|
|
},
|
|
|
|
|
mod: mods,
|
|
|
|
|
util: {
|
|
|
|
|
log: logger.log,
|
|
|
|
|
time: time,
|
|
|
|
|
guid: guid,
|
2020-05-30 18:16:40 -04:00
|
|
|
mkdirs: util.mkdir,
|
2021-03-08 21:57:28 -05:00
|
|
|
isfile: util.isfile,
|
|
|
|
|
confdir: util.confdir,
|
2020-05-30 18:16:40 -04:00
|
|
|
datadir: util.datadir,
|
2020-05-29 13:16:38 -04:00
|
|
|
lastmod: lastmod,
|
|
|
|
|
obj2string: obj2string,
|
|
|
|
|
string2obj: string2obj,
|
|
|
|
|
getCookieValue: cookieValue,
|
2020-05-30 18:16:40 -04:00
|
|
|
logger: log.new
|
2020-05-29 13:16:38 -04:00
|
|
|
},
|
2022-02-17 15:04:36 -05:00
|
|
|
inject: (code, file, opt = {}) => {
|
|
|
|
|
let codelist = script[code];
|
|
|
|
|
if (!codelist) {
|
2020-05-29 13:16:38 -04:00
|
|
|
return logger.log(`inject missing target "${code}"`);
|
|
|
|
|
}
|
2020-11-17 14:18:09 -05:00
|
|
|
const path = `${dir}/${file}`;
|
2022-02-23 09:29:33 -05:00
|
|
|
codelist.push(path);
|
2020-11-17 15:49:41 -05:00
|
|
|
if (opt.cachever) {
|
|
|
|
|
cachever[path] = opt.cachever;
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
path: {
|
|
|
|
|
any: arg => { mod.add(arg) },
|
|
|
|
|
pre: arg => { mod.add(prepath(arg)) },
|
|
|
|
|
map: arg => { mod.add(fixedmap(arg)) },
|
|
|
|
|
full: arg => { mod.add(fullpath(arg)) },
|
|
|
|
|
static: (root, pre) => {
|
|
|
|
|
mod.static(pre || "/", root);
|
|
|
|
|
},
|
|
|
|
|
code: (endpoint, path) => {
|
2024-06-14 17:48:01 -04:00
|
|
|
let fpath = PATH.join(mod.dir, path);
|
2020-05-29 13:16:38 -04:00
|
|
|
if (debug) {
|
|
|
|
|
code[endpoint] = fs.readFileSync(fpath);
|
|
|
|
|
} else {
|
|
|
|
|
code[endpoint] = minify(fpath);
|
|
|
|
|
}
|
|
|
|
|
code_src[endpoint] = {
|
|
|
|
|
endpoint,
|
|
|
|
|
path: path,
|
|
|
|
|
mod: lastmod(fpath)
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
redir: redir,
|
2020-12-13 09:55:30 -05:00
|
|
|
remap: remap,
|
|
|
|
|
setup: fn => { setupFn = fn }
|
2020-05-29 13:16:38 -04:00
|
|
|
},
|
|
|
|
|
handler: {
|
|
|
|
|
addCORS: addCorsHeaders,
|
2020-05-30 18:16:40 -04:00
|
|
|
redirect: http.redirect,
|
|
|
|
|
reply404: http.reply404,
|
2022-02-24 19:53:22 -05:00
|
|
|
decodePost: http.decodePost,
|
2020-05-29 13:16:38 -04:00
|
|
|
reply: quickReply
|
|
|
|
|
},
|
|
|
|
|
ws: {
|
|
|
|
|
register: mod.wss
|
|
|
|
|
},
|
|
|
|
|
onload: (fn) => {
|
|
|
|
|
load.push(fn);
|
|
|
|
|
},
|
|
|
|
|
onexit: (fn) => {
|
|
|
|
|
mod.on.exit(fn);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const script = {
|
|
|
|
|
kiri : [
|
2020-06-04 21:29:40 -04:00
|
|
|
"@devices",
|
2022-02-22 11:32:35 -05:00
|
|
|
"kiri/ui",
|
2022-02-22 00:05:29 -05:00
|
|
|
"&main/kiri",
|
|
|
|
|
"&kiri/lang-en"
|
2021-12-26 19:43:48 -05:00
|
|
|
],
|
2021-12-28 15:52:28 -05:00
|
|
|
kiri_work : [
|
2022-02-22 11:36:04 -05:00
|
|
|
"kiri-run/worker",
|
2022-02-22 11:32:35 -05:00
|
|
|
"&main/kiri",
|
2021-12-26 19:43:48 -05:00
|
|
|
],
|
2021-12-28 15:52:28 -05:00
|
|
|
kiri_pool : [
|
2022-02-23 09:29:33 -05:00
|
|
|
"&kiri-run/minion",
|
|
|
|
|
"&main/kiri",
|
2021-12-26 19:43:48 -05:00
|
|
|
],
|
2020-12-31 23:22:39 -05:00
|
|
|
engine : [
|
2022-02-23 09:29:33 -05:00
|
|
|
"&kiri-run/engine",
|
|
|
|
|
"&main/kiri",
|
2021-12-26 19:43:48 -05:00
|
|
|
],
|
2021-01-04 20:36:35 -05:00
|
|
|
frame : [
|
2022-02-19 13:13:53 -05:00
|
|
|
"kiri-run/frame"
|
2021-12-26 19:43:48 -05:00
|
|
|
],
|
2020-05-30 21:26:01 -04:00
|
|
|
meta : [
|
2021-12-29 10:37:17 -05:00
|
|
|
"main/meta",
|
2021-12-26 19:43:48 -05:00
|
|
|
],
|
2021-12-16 19:11:52 -05:00
|
|
|
mesh : [
|
2021-12-29 10:37:17 -05:00
|
|
|
"&main/mesh"
|
2021-12-26 19:43:48 -05:00
|
|
|
],
|
|
|
|
|
mesh_work : [
|
2021-12-29 10:37:17 -05:00
|
|
|
"&mesh/work"
|
2021-12-27 18:13:11 -05:00
|
|
|
],
|
|
|
|
|
mesh_pool : [
|
2021-12-29 10:37:17 -05:00
|
|
|
"&mesh/pool"
|
2022-08-31 16:35:25 -04:00
|
|
|
],
|
|
|
|
|
cache : [
|
2022-08-31 21:41:51 -04:00
|
|
|
"moto/license",
|
2022-08-31 16:35:25 -04:00
|
|
|
"main/service",
|
|
|
|
|
],
|
|
|
|
|
service : [
|
2022-08-31 21:41:51 -04:00
|
|
|
"moto/license",
|
2022-08-31 16:35:25 -04:00
|
|
|
"moto/service"
|
2021-12-26 19:43:48 -05:00
|
|
|
]
|
2020-05-29 13:16:38 -04:00
|
|
|
};
|
|
|
|
|
|
2020-11-17 14:18:09 -05:00
|
|
|
// prevent caching of specified modules
|
2020-11-17 15:49:41 -05:00
|
|
|
const cachever = {};
|
2020-11-17 14:18:09 -05:00
|
|
|
|
2020-05-29 13:16:38 -04:00
|
|
|
function promise(resolve, reject) {
|
|
|
|
|
return new Promise(resolve, reject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function rval() {
|
|
|
|
|
return (Math.round(Math.random()*0xffffffff)).toString(36);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function guid() {
|
|
|
|
|
return time().toString(36)+rval()+rval()+rval();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function time() {
|
|
|
|
|
return Date.now();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function obj2string(o) {
|
|
|
|
|
return JSON.stringify(o);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function string2obj(s) {
|
|
|
|
|
return JSON.parse(s);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-13 09:55:30 -05:00
|
|
|
function handleSetup(req, res, next) {
|
2020-12-13 19:31:35 -05:00
|
|
|
if (setupFn) {
|
|
|
|
|
setupFn(req, res, next);
|
|
|
|
|
} else {
|
|
|
|
|
next();
|
|
|
|
|
}
|
2020-12-13 09:55:30 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-30 20:39:56 -04:00
|
|
|
function handleVersion(req, res, next) {
|
2022-02-04 15:31:45 -05:00
|
|
|
let vstr = oversion || dversion || version;
|
2021-12-27 20:39:07 -05:00
|
|
|
if (["/kiri/","/mesh/","/meta/"].indexOf(req.app.path) >= 0 && req.url.indexOf(vstr) < 0) {
|
2020-05-30 20:39:56 -04:00
|
|
|
if (req.url.indexOf("?") > 0) {
|
2021-01-26 09:03:02 -05:00
|
|
|
return http.redirect(res, `${req.url},ver:${vstr}`);
|
2020-05-30 20:39:56 -04:00
|
|
|
} else {
|
2021-01-26 09:03:02 -05:00
|
|
|
return http.redirect(res, `${req.url}?ver:${vstr}`);
|
2020-05-30 20:39:56 -04:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-29 13:16:38 -04:00
|
|
|
function handleOptions(req, res, next) {
|
2020-06-02 20:28:48 -04:00
|
|
|
try {
|
|
|
|
|
req.app.ua = agent.parse(req.headers['user-agent'] || '');
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.log("ua parse error on : "+req.headers['user-agent']);
|
|
|
|
|
}
|
2022-08-31 16:35:25 -04:00
|
|
|
res.setHeader("Service-Worker-Allowed", "/");
|
2020-05-29 13:16:38 -04:00
|
|
|
if (req.method === 'OPTIONS') {
|
|
|
|
|
addCorsHeaders(req, res);
|
|
|
|
|
res.end();
|
|
|
|
|
} else {
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleWasm(req, res, next) {
|
2022-10-22 11:02:02 -04:00
|
|
|
let file = req.app.path.split('/').pop();
|
2020-05-29 13:16:38 -04:00
|
|
|
let ext = (file || '').split('.')[1];
|
2024-06-14 17:48:01 -04:00
|
|
|
let path = PATH.join(dir,"src","wasm",file);
|
2020-05-29 13:16:38 -04:00
|
|
|
let mod = lastmod(path);
|
|
|
|
|
|
2022-10-22 11:02:02 -04:00
|
|
|
if (ext === 'wasm' && mod) {
|
2020-05-29 13:16:38 -04:00
|
|
|
let imd = ifModifiedDate(req);
|
|
|
|
|
if (imd && mod <= imd) {
|
|
|
|
|
res.writeHead(304, "Not Modified");
|
|
|
|
|
return res.end();
|
|
|
|
|
}
|
|
|
|
|
res.writeHead(200, {
|
|
|
|
|
'Content-Type': 'application/wasm',
|
|
|
|
|
'Cache-Control': 'public, max-age=600',
|
|
|
|
|
'Last-Modified': new Date(mod).toGMTString(),
|
|
|
|
|
});
|
|
|
|
|
res.end(fs.readFileSync(path));
|
|
|
|
|
} else {
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleCode(req, res, next) {
|
|
|
|
|
let key = req.app.path.split('/')[2].split('.')[0],
|
|
|
|
|
ck = code_src[key],
|
|
|
|
|
js = code[key];
|
|
|
|
|
|
|
|
|
|
if (!js) {
|
2020-05-30 18:16:40 -04:00
|
|
|
return http.reply404(req, res);
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
|
|
|
|
if (ck) {
|
2020-12-11 15:31:22 -05:00
|
|
|
let mpath = `${dir}/${ck.path}`;
|
|
|
|
|
let mod = lastmod(mpath);
|
2020-05-29 13:16:38 -04:00
|
|
|
if (mod > ck.mod) {
|
|
|
|
|
if (debug) {
|
2020-12-11 15:31:22 -05:00
|
|
|
js = code[ck.endpoint] = fs.readFileSync(mpath);
|
2020-05-29 13:16:38 -04:00
|
|
|
} else {
|
2020-12-11 15:31:22 -05:00
|
|
|
js = code[ck.endpoint] = minify(mpath);
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
|
|
|
|
ck.mod = mod;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addCorsHeaders(req, res);
|
|
|
|
|
serveCode(req, res, {
|
|
|
|
|
code: js,
|
|
|
|
|
mtime: startTime
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function serveCode(req, res, code) {
|
|
|
|
|
if (code.deny) {
|
2020-05-30 18:16:40 -04:00
|
|
|
return http.reply404(req, res);
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let imd = ifModifiedDate(req);
|
|
|
|
|
if (imd && code.mtime <= imd && !code.nocache) {
|
|
|
|
|
res.writeHead(304, "Not Modified");
|
|
|
|
|
res.end();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let cacheControl = code.nocache ?
|
|
|
|
|
'private, max-age=0' :
|
|
|
|
|
'public, max-age=600';
|
|
|
|
|
|
|
|
|
|
res.writeHead(200, {
|
|
|
|
|
'Content-Type': 'application/javascript',
|
|
|
|
|
'Cache-Control': cacheControl,
|
|
|
|
|
'Last-Modified': new Date(code.mtime).toGMTString(),
|
|
|
|
|
});
|
|
|
|
|
res.end(code.code);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-12 10:11:38 -04:00
|
|
|
// pack/concat device script strings to inject into /code/ scripts
|
2020-06-04 21:29:40 -04:00
|
|
|
function generateDevices() {
|
2024-06-14 17:48:01 -04:00
|
|
|
let root = PATH.join(dir,"src","kiri-dev");
|
2020-06-03 22:39:30 -04:00
|
|
|
let devs = {};
|
|
|
|
|
fs.readdirSync(root).forEach(type => {
|
|
|
|
|
let map = devs[type] = devs[type] || {};
|
2024-06-14 17:48:01 -04:00
|
|
|
fs.readdirSync(PATH.join(root,type)).forEach(device => {
|
|
|
|
|
map[device] = JSON.parse(fs.readFileSync(PATH.join(root,type,device)));
|
2020-06-03 22:39:30 -04:00
|
|
|
});
|
|
|
|
|
});
|
2020-06-04 21:29:40 -04:00
|
|
|
synth.devices = `self.devices = ${JSON.stringify(devs)};`;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-12 10:11:38 -04:00
|
|
|
// pack/concat code modules served under "/code/"
|
2020-05-29 13:16:38 -04:00
|
|
|
function prepareScripts() {
|
2020-06-04 21:29:40 -04:00
|
|
|
generateDevices();
|
2021-12-26 19:43:48 -05:00
|
|
|
for (let key of Object.keys(script)) {
|
|
|
|
|
code[key] = concatCode(script[key]);
|
|
|
|
|
}
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function concatCode(array) {
|
|
|
|
|
let code = [];
|
2020-06-03 22:44:05 -04:00
|
|
|
let direct = array.filter(f => f.charAt(0) !== '@');
|
|
|
|
|
let inject = array.filter(f => f.charAt(0) === '@').map(f => f.substring(1));
|
2020-05-29 13:16:38 -04:00
|
|
|
|
2022-02-17 15:04:36 -05:00
|
|
|
synth.inject = "/* injection point */";
|
|
|
|
|
|
2020-05-29 13:16:38 -04:00
|
|
|
// in debug mode, the script should load dependent
|
|
|
|
|
// scripts instead of serving a complete bundle
|
|
|
|
|
if (debug) {
|
2022-02-04 15:46:55 -05:00
|
|
|
const code = [
|
2022-09-23 13:24:13 -04:00
|
|
|
oversion ? `self.debug_version='${oversion}';self.enable_service=${serviceWorker};` : '',
|
2022-02-04 15:46:55 -05:00
|
|
|
'self.debug=true;',
|
|
|
|
|
'(function() { let load = [ '
|
|
|
|
|
];
|
2020-06-03 22:39:30 -04:00
|
|
|
direct.forEach(file => {
|
2022-09-01 11:12:24 -04:00
|
|
|
const vers = cachever[file] || oversion || dversion || version;
|
2020-11-17 14:18:09 -05:00
|
|
|
code.push(`"/${file.replace(/\\/g,'/')}?${vers}",`);
|
2020-05-29 13:16:38 -04:00
|
|
|
});
|
|
|
|
|
code.push([
|
|
|
|
|
']; function load_next() {',
|
|
|
|
|
'let file = load.shift();',
|
|
|
|
|
'if (!file) return;',
|
|
|
|
|
'if (!self.document) { importScripts(file); return load_next() }',
|
|
|
|
|
'let s = document.createElement("script");',
|
|
|
|
|
's.type = "text/javascript";',
|
|
|
|
|
's.src = file;',
|
|
|
|
|
's.onload = load_next;',
|
|
|
|
|
'document.head.appendChild(s);',
|
2022-02-04 15:46:55 -05:00
|
|
|
'} load_next(); })();'
|
2020-05-29 13:16:38 -04:00
|
|
|
].join('\n'));
|
2020-06-03 22:39:30 -04:00
|
|
|
inject.forEach(key => {
|
|
|
|
|
code.push(synth[key]);
|
|
|
|
|
});
|
2020-05-29 13:16:38 -04:00
|
|
|
return code.join('\n');
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-03 22:39:30 -04:00
|
|
|
direct.forEach(file => {
|
2024-06-30 15:27:37 -04:00
|
|
|
let cached = getCachedFile(file, path => {
|
2024-06-14 17:48:01 -04:00
|
|
|
return minify(PATH.join(dir,file));
|
2020-05-29 13:16:38 -04:00
|
|
|
});
|
2022-09-01 11:27:59 -04:00
|
|
|
if (oversion) {
|
2022-09-23 13:24:13 -04:00
|
|
|
cached = `self.debug_version='${oversion}';self.enable_service=${serviceWorker};` + cached;
|
2022-09-01 11:27:59 -04:00
|
|
|
}
|
2020-05-29 13:16:38 -04:00
|
|
|
code.push(cached);
|
|
|
|
|
});
|
|
|
|
|
|
2020-06-03 22:39:30 -04:00
|
|
|
inject.forEach(key => {
|
|
|
|
|
code.push(synth[key]);
|
|
|
|
|
});
|
|
|
|
|
|
2020-05-29 13:16:38 -04:00
|
|
|
return code.join('');
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-30 18:16:40 -04:00
|
|
|
function getCachedFile(file, fn) {
|
2024-06-14 17:48:01 -04:00
|
|
|
let filePath = PATH.join(dir,file);
|
|
|
|
|
let cachePath = cacheDir + PATH.sep + file
|
2020-05-29 13:16:38 -04:00
|
|
|
.replace(/\//g,'_')
|
|
|
|
|
.replace(/\\/g,'_')
|
|
|
|
|
.replace(/:/g,'_'),
|
|
|
|
|
cached = fileCache[filePath],
|
|
|
|
|
now = time();
|
|
|
|
|
|
|
|
|
|
if (cached) {
|
|
|
|
|
if (now - cached.lastcheck > 60000) {
|
|
|
|
|
let smod = lastmod(filePath),
|
|
|
|
|
cmod = cached.mtime;
|
|
|
|
|
|
2021-02-14 16:21:51 -05:00
|
|
|
if (!smod) {
|
|
|
|
|
throw "missing source file";
|
|
|
|
|
}
|
|
|
|
|
if (smod > cmod) {
|
|
|
|
|
cached = null;
|
|
|
|
|
} else {
|
|
|
|
|
cached.lastcheck = now;
|
|
|
|
|
}
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!cached) {
|
|
|
|
|
let smod = lastmod(filePath),
|
|
|
|
|
cmod = lastmod(cachePath),
|
|
|
|
|
cacheData;
|
|
|
|
|
|
2024-06-14 17:48:01 -04:00
|
|
|
if (cmod >= smod || (forceUseCache && cmod)) {
|
2020-05-29 13:16:38 -04:00
|
|
|
cacheData = fs.readFileSync(cachePath);
|
|
|
|
|
} else {
|
|
|
|
|
logger.log({update_cache:filePath});
|
|
|
|
|
cacheData = fn(filePath);
|
2025-02-04 16:59:06 -05:00
|
|
|
// console.log(`NEW_CACHE_FILE: ${cachePath}`);
|
2020-05-29 13:16:38 -04:00
|
|
|
fs.writeFileSync(cachePath, cacheData);
|
|
|
|
|
}
|
2024-06-27 21:50:54 -04:00
|
|
|
|
|
|
|
|
if (wrap[file]) {
|
2024-06-30 15:27:37 -04:00
|
|
|
// console.log('WRAP', filePath, cacheData.length);
|
2024-06-29 07:14:20 -04:00
|
|
|
cacheData = wrap_module(cacheData, wrap[file]);
|
2024-06-27 21:50:54 -04:00
|
|
|
}
|
2020-05-29 13:16:38 -04:00
|
|
|
|
|
|
|
|
cached = {
|
|
|
|
|
data: cacheData,
|
|
|
|
|
mtime: cmod || now,
|
|
|
|
|
lastcheck: now
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fileCache[filePath] = cached;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-30 15:27:37 -04:00
|
|
|
// console.log('[*]', filePath, cached.data.length);
|
2020-05-29 13:16:38 -04:00
|
|
|
return cached.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function minify(path) {
|
|
|
|
|
let code = fs.readFileSync(path);
|
2022-02-22 22:00:50 -05:00
|
|
|
let mini = uglify.minify(code.toString(), {
|
2024-06-08 00:07:42 -07:00
|
|
|
compress: {
|
|
|
|
|
merge_vars: false,
|
|
|
|
|
unused: false
|
|
|
|
|
}
|
2022-02-22 22:00:50 -05:00
|
|
|
});
|
2020-05-29 13:16:38 -04:00
|
|
|
if (mini.error) {
|
|
|
|
|
console.trace(mini.error);
|
|
|
|
|
throw mini.error;
|
|
|
|
|
}
|
|
|
|
|
return mini.code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function quickReply(res, code, msg) {
|
|
|
|
|
res.writeHead(code);
|
|
|
|
|
res.end(msg+"\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ifModifiedDate(req) {
|
|
|
|
|
let ims = req.headers['if-modified-since'];
|
|
|
|
|
if (ims) {
|
|
|
|
|
// because sys time has a higher resolution than
|
|
|
|
|
// seconds converted from IMS header. so give it
|
|
|
|
|
// an extra second
|
|
|
|
|
return new Date(ims).getTime() + 1000;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addCorsHeaders(req, res) {
|
|
|
|
|
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
|
|
|
res.setHeader('Access-Control-Allow-Headers', 'X-Moto-Ajax, Content-Type');
|
2022-05-15 12:02:38 -04:00
|
|
|
res.setHeader('Access-Control-Allow-Origin', req.headers['origin'] || '*');
|
2025-02-10 19:45:04 -05:00
|
|
|
if (req.headers['access-control-request-private-network'] === 'true') {
|
|
|
|
|
res.setHeader('Access-Control-Allow-Private-Network', 'true');
|
|
|
|
|
}
|
2022-09-23 12:55:14 -04:00
|
|
|
if (!crossOrigin) {
|
|
|
|
|
res.setHeader("Cross-Origin-Opener-Policy", 'same-origin');
|
|
|
|
|
res.setHeader("Cross-Origin-Embedder-Policy", 'require-corp');
|
|
|
|
|
}
|
2020-05-29 13:16:38 -04:00
|
|
|
res.setHeader("Allow", "GET,POST,OPTIONS");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dispatch for path prefixs
|
|
|
|
|
function prepath(pre) {
|
|
|
|
|
|
|
|
|
|
function handle(req, res, next) {
|
|
|
|
|
pre.uid = pre.uid || guid();
|
|
|
|
|
req.ppi = req.ppi || {};
|
|
|
|
|
|
|
|
|
|
let path = req.app.path,
|
|
|
|
|
key, fn, i = req.ppi[pre.uid] || 0;
|
|
|
|
|
|
|
|
|
|
while (i < pre.length) {
|
|
|
|
|
key = pre[i][0];
|
|
|
|
|
fn = pre[i++][1];
|
|
|
|
|
if (path.indexOf(key) === 0) {
|
|
|
|
|
return fn(req, res, () => {
|
|
|
|
|
req.ppi[pre.uid] = i;
|
|
|
|
|
handle(req, res, next);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dispatch full fixed paths
|
|
|
|
|
function fullpath(map) {
|
|
|
|
|
return (req, res, next) => {
|
|
|
|
|
let fn = map[req.app.path];
|
|
|
|
|
if (fn) fn(req, res, next);
|
|
|
|
|
else next();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dispatch full paths based on a prefix and a function map
|
|
|
|
|
function fixedmap(prefix, map) {
|
|
|
|
|
return (req, res, next) => {
|
|
|
|
|
let path = req.app.path;
|
|
|
|
|
if (path.indexOf(prefix) != 0) return next();
|
|
|
|
|
let fn = map[path.substring(prefix.length)];
|
|
|
|
|
if (fn) fn(req, res, next);
|
|
|
|
|
else next();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HTTP 307 redirect
|
2020-05-30 20:39:56 -04:00
|
|
|
function redir(path, type) {
|
|
|
|
|
return (req, res, next) => http.redirect(res, path, type);
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// mangle request path
|
|
|
|
|
function remap(path) {
|
|
|
|
|
return (req, res, next) => {
|
|
|
|
|
req.url = req.app.path = path;
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cookieValue(cookie,key) {
|
|
|
|
|
if (!cookie) return null;
|
|
|
|
|
key = (key || "key") + "=";
|
|
|
|
|
let kpos = cookie.lastIndexOf(key);
|
|
|
|
|
if (kpos >= 0) {
|
|
|
|
|
return cookie.substring(kpos+key.length).split(';')[0];
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function rewriteHtmlVersion(req, res, next) {
|
2023-01-15 16:45:22 -05:00
|
|
|
if (["/kiri/","/mesh/","/meta/","/kiri/engine.html","/kiri/frame.html"].indexOf(req.app.path) >= 0) {
|
2022-05-15 12:02:38 -04:00
|
|
|
addCorsHeaders(req, res);
|
2020-05-29 13:16:38 -04:00
|
|
|
let real_write = res.write;
|
|
|
|
|
let real_end = res.end;
|
2021-12-28 17:30:15 -05:00
|
|
|
let mlen = '{{version}}'.length;
|
2022-09-01 11:12:24 -04:00
|
|
|
let vstr = oversion || dversion || version;
|
2021-12-28 17:30:15 -05:00
|
|
|
if (vstr.length < mlen) {
|
|
|
|
|
vstr = vstr.padStart(mlen,0);
|
|
|
|
|
} else if (vstr.length > mlen) {
|
|
|
|
|
vstr = vstr.substring(0,mlen);
|
|
|
|
|
}
|
2020-05-29 13:16:38 -04:00
|
|
|
res.write = function() {
|
2021-12-28 17:30:15 -05:00
|
|
|
arguments[0] = arguments[0].toString().replace(/{{version}}/g,vstr);
|
2020-05-29 13:16:38 -04:00
|
|
|
real_write.apply(res, arguments);
|
|
|
|
|
};
|
|
|
|
|
res.end = function() {
|
|
|
|
|
if (arguments[0]) {
|
2021-12-28 17:30:15 -05:00
|
|
|
arguments[0] = arguments[0].toString().replace(/{{version}}/g,vstr);
|
2020-05-29 13:16:38 -04:00
|
|
|
}
|
|
|
|
|
real_end.apply(res, arguments);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = init;
|