rtjscomp 0.9.12 → 0.9.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/rtjscomp.js +26 -25
package/package.json
CHANGED
package/rtjscomp.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
(async()=>{const I=require("fs"),G=require("fs/promises"),Ca=require("http"),Za=require("url"),O=require("zlib"),Da=["","gzip","brotli","zstd"],ka={level:9},Ea=O.createBrotliCompress!=null,Fa=O.createZstdCompress!=null,la=/,\s*/,ma=/\bimport\(/g,$a=/^(127\.|10\.|192\.168\.|::1|fc00:|fe80:)/,Ga=typeof Bun!=="undefined",ab=/:([0-9]+)[\):]/,bb=/\+/g,Ha={paths:[require("path").resolve()]},cb=/\bservice_require\(([^)]*)\)/g,na={persistent:!0,interval:1E3},Ia={params:{[100]:3}},Ja=process.argv.includes("-v");
|
|
6
6
|
let v=Ja,P=0,Q=0,Ka=0,aa=!0,R=!1;const ba=new Map([["","index.html"]]),S=new Map([["index.html","/"]]),T=new Map,oa=new Set,pa=new Set,qa=new Set,ra=new Set(["events","html","json","txt"]),sa=new Map([["apk","application/zip"],["bpg","image/bpg"],["css","text/css; charset=utf-8"],["events","text/event-stream"],["flac","audio/flac"],["gz","application/gzip"],["hta","application/hta"],["html","text/html; charset=utf-8"],["ico","image/x-icon"],["jpg","image/jpeg"],["js","text/javascript; charset=utf-8"],
|
|
7
|
-
["json","application/json; charset=utf-8"],["mid","audio/midi"],["mp3","audio/mpeg3"],["pdf","application/pdf"],["png","image/png"],["rss","application/rss+xml; charset=utf-8"],["txt","text/plain; charset=utf-8"],["xml","application/xml; charset=utf-8"],["xz","application/x-xz"],["zip","application/zip"]]),ca=new Set("apk bpg flac gz jpg mp3 pdf png xz zip".split(" ")),da=new Map,q={},F=global.rtjscomp={actions:q,version:"0.9.
|
|
7
|
+
["json","application/json; charset=utf-8"],["mid","audio/midi"],["mp3","audio/mpeg3"],["pdf","application/pdf"],["png","image/png"],["rss","application/rss+xml; charset=utf-8"],["txt","text/plain; charset=utf-8"],["xml","application/xml; charset=utf-8"],["xz","application/x-xz"],["zip","application/zip"]]),ca=new Set("apk bpg flac gz jpg mp3 pdf png xz zip".split(" ")),da=new Map,q={},F=global.rtjscomp={actions:q,version:"0.9.14"};Object.fromEntries||(Object.fromEntries=a=>{const b={};for(const c of a)b[c[0]]=
|
|
8
8
|
c[1];return b});let U=I.watch;if(Ga){const a=U,b=new Map;U=(c,f,g)=>{b.has(c)||a(c,f,()=>{const k=b.get(c);k&&k()});b.set(c,g);return{close:()=>b.set(c,null)}}}global.globals=F;global.actions=F.actions;global.data_load=a=>{e("[deprecated] synchronous load file: data/"+a);try{return I.readFileSync("data/"+a,"utf8")}catch(b){return null}};global.data_save=(a,b)=>(e("[deprecated] synchronous save file: data/"+a),I.writeFileSync("data/"+a,b,"utf8"));global.number_check_int=a=>Math.floor(a)===a;global.number_check_uint=
|
|
9
9
|
a=>a>=0&&number_check_int(a);F.data_load=async a=>{v&&e("load file: data/"+a);const b=await G.readFile("data/"+a,"utf8").catch(()=>null);return a.endsWith(".json")?JSON.parse(b||null):b};F.data_load_watch=(a,b)=>ta("data/"+a,c=>b(a.endsWith(".json")?JSON.parse(c||null):c));F.data_save=(a,b)=>(v&&e("save file: data/"+a),G.writeFile("data/"+a,a.endsWith(".json")?JSON.stringify(b):b,"utf8"));const La=a=>{try{return`:${a.stack.split("\n",2)[1].split(",").pop().match(ab)[1]-2}`}catch(b){return""}},Ma=
|
|
10
10
|
new Set,ua=new Map,va=new Map,wa=a=>{var b=ua.get(a);if(b!=null)return b;v&&e("require module: "+a);b=require.resolve(a,Ha);Ma.add(b);ua.set(a,b=require(b));return b},xa=async a=>{let b=va.get(a);if(b!=null)return b;v&&e("import module: "+a);va.set(a,b=await import("file://"+require.resolve(a,Ha)));return b};q.module_cache_clear=()=>{for(const a of Ma)delete require.cache[a];ua.clear();va.clear()};const ya=xa.constructor,J=new Map;let V=null,za=null;const db=async a=>{await Promise.all([...J.values()].filter(c=>
|
|
@@ -19,28 +19,29 @@ Sa=(a,b,c)=>{if(a===null||!(b in a))return c;c=a[b];if(typeof c!=="boolean")thro
|
|
|
19
19
|
let c=a[b];if(typeof c!=="object"||!c||(c=Object.entries(c)).some(([,f])=>typeof f!=="string"))throw b+" must be object of strings";delete a[b];return c},X=a=>a.split("\n").filter(b=>b.length>0&&b.charCodeAt(0)!==35),Ua=a=>Object.fromEntries(a.split("\n").filter(b=>b.length>0&&b.charCodeAt(0)!==35).map(b=>b.split(":",2))),N=(a,b=!1)=>{if(!b&&!a)throw"path is empty";if(a.charCodeAt(0)===47)throw"path must not start with /";if(a.charCodeAt(a.length-1)===47)throw"path must not end with /";if(a.includes(".."))throw"path must not contain ..";
|
|
20
20
|
if(a.includes("~"))throw"path must not contain ~";if(a.includes("//"))throw"path must not contain //";};let Va=F.log_history=[];q.log_clear=()=>{Va=F.log_history=[]};const e=F.log=a=>(console.log(a),Va.push(a),Y?fa("log",[a]):void 0),Y=I.existsSync("spam.csv");F.spam_history="";q.spam_save=async(a=!1)=>{if(Y)try{const b=F.spam_history;F.spam_history="";await G.appendFile("spam.csv",b,"utf8");v&&!a&&e("spam.csv saved")}catch(b){e("[error] cannot save spam.csv: "+b.message)}};const fa=(a,b)=>{F.spam_history+=
|
|
21
21
|
Date.now()+","+a+","+JSON.stringify(b)+"\n";F.spam_history.length>=1E5&&q.spam_save()},gb=(a,b,c)=>{b=Buffer.from(b);b[0]===34&&(b=b.subarray(1,-1));const f=b.length,g=f+4,k=a.length-g;var l=0;let p=0;for(;(p=a.indexOf(45,p))>=0&&p<=k;)if(a[p+1]!==45||p>0&&a[p-2]!==13||p>0&&a[p-1]!==10||a.compare(b,0,f,p+2,p+2+f)!==0)++p;else{if(l>0){if(p-l<20)throw"part too short";for(var m=l;(m=a.indexOf(13,m))>=0&&a[m+1]!==10||a[m+2]!==13||a[m+3]!==10;)++m;if(m<0)throw"part header end not found";let w="",t="";
|
|
22
|
-
for(const
|
|
22
|
+
for(const C of a.toString("utf8",l,m).split("\r\n",2)){if(!C.startsWith("Content-"))throw"illegal part header";const [z,x]=C.slice(8).split(": ",2);if(z==="Disposition"){if(!x.startsWith("form-data; "))throw"illegal disposition part header";w=x.slice(11)}else if(z==="Type")t=x;else throw"illegal part header";}if(!w)throw"part disposition header missing";let y=l="";for(const C of w.split("; ")){let [z,x]=C.split("=",2);x.charCodeAt(0)===34&&(x=x.slice(1,-1));if(z==="name")l=x;else if(z==="filename")y=
|
|
23
23
|
x;else throw"illegal disposition part header";}if(!l)throw"part name header missing";m=t?{filename:y,data:a.subarray(m+4,p-2),type:t}:a.toString("utf8",m+4,p-2);if(l.endsWith("[]"))if(l=l.slice(0,-2),l in c){if(!(c[l]instanceof Array))throw"duplicate part name";c[l].push(m)}else c[l]=[m];else{if(l in c)throw"duplicate part name";c[l]=m}}l=p+g;p=l+1}},Aa=(a,b)=>{for(const c of a.split("&")){let [f,g]=c.split("=",2);(a=f.endsWith("[]"))&&(f=f.slice(0,-2));if(!f)throw"key is empty";g=g!=null?decodeURIComponent(g.replace(bb,
|
|
24
|
-
" ")):"1";if(f in b){if(b[f]instanceof Array!==a)throw"type mismatch";a?b[f].push(g):b[f]=g}else b[f]=a?[g]:g}},Wa=async(a,b,c)=>{const f=a.method,g=a.headers;var k;const l=((k=g["x-forwarded-for"])==null?void 0:k.split(la).findLast(
|
|
25
|
-
h.includes("//"))throw 404;if(h.length>1&&h.endsWith("/")&&(h=h.slice(0,-1),h.lastIndexOf("/")<h.lastIndexOf(".")))throw b.setHeader("Location",h),301;h=h.slice(1);if(!(h.includes("php")||h.includes("sql")||h.includes(".git/")||oa.has(h))){b.setHeader("Access-Control-Allow-Origin","*");var p=null,m=null;if(S.has(h))throw b.setHeader("Location",S.get(h)),301;if(ba.has(h))h=ba.get(h);else{var w=h.split("/"),t=T.get(w.shift());if(t!=null)a:for(var y of t){var
|
|
26
|
-
for(let d=0;d<z;++d)if(
|
|
27
|
-
a.on("end",
|
|
28
|
-
d.includes("globals.")&&e(`[deprecated] ${h}: uses globals object`);const u=d.length;let
|
|
29
|
-
"output","request","response","require","custom_import","service_require","service_require_try",
|
|
30
|
-
r)}catch(d){throw e(`[error] ${h} request x-input: ${d}`),400;}if(
|
|
31
|
-
d}`),400;}r.https=c;r.ip=l;r.method=k?"get":f.toLowerCase();r.path=
|
|
32
|
-
[h,Object.fromEntries(Object.entries(r).filter(d=>d[0]!=="body").map(d=>d[0]==="password"?[d[0],"***"]:d).map(d=>d[0]==="file"?[d[0],"..."]:d).map(d=>typeof d[1]!=="object"||d[1]===null||d[1].length?d:[d[0],Object.keys(d[1]).slice(0,20)]).map(d=>d[0]!=="user_agent"&&typeof d[1]==="string"&&d[1].length>20?[d[0],d[1].slice(0,20)+"..."]:d))]);k&&(A.write=A.end=()=>{throw null;});await V;try{var
|
|
33
|
-
503:500):typeof d==="number"?(e(`[deprecated] ${h}: status code thrown, use return instead`),
|
|
34
|
-
500;throw
|
|
35
|
-
A[1],
|
|
36
|
-
K?{start:
|
|
37
|
-
q.halt=async()=>{R=!0;v&&e("stop all");await Promise.all([q.http_stop&&q.http_stop(),q.https_stop&&q.https_stop(),eb()]);await q.spam_save();e("stopped all")};q.exit=async a=>{R||(typeof a!=="number"&&(a=0),await q.halt(),v&&e("exit"),process.exit(a))};process.on("uncaughtException",a=>{typeof a==="symbol"&&(a=a.toString());e("[error] uncaughtException: "+
|
|
38
|
-
a));console.error(a);R&&process.exit(1);q.exit(1)});process.on("exit",q.exit);process.on("SIGINT",q.exit);process.on("SIGUSR2",q.exit);process.on("SIGTERM",q.exit);e(`rtjscomp v${"0.9.
|
|
39
|
-
const [hb,ib,...Xa]=await Promise.all([G.stat("data/").catch(a=>null),G.stat("public/").catch(a=>null),..."file_blocks file_privates file_raws file_type_dyns file_type_mimes file_type_nocompress path_aliases port_http port_https services".split(" ").map(a=>G.readFile("config/"+a+".txt","utf8").catch(b=>null))]);hb||I.mkdirSync("data/");ib||I.cpSync(__dirname+"/public/",
|
|
40
|
-
[b,c,f,g,k,l,p,m,w,t]=Xa;b&&(a.path_ghosts=X(b));c&&(a.path_hiddens=X(c));f&&(a.path_statics=X(f));g&&(a.type_dynamics=X(g));k&&(a.type_mimes=Ua(k));l&&(a.type_raws=X(l));p&&(a.path_aliases=Ua(p));if(m){const y=Number(m);isNaN(y)||(a.port_http=y)}if(w){const y=Number(w);isNaN(y)||(a.port_https=y)}t&&(a.services=t.split("\n").filter(y=>y.length>0));await G.writeFile("rtjscomp.json",
|
|
41
|
-
0,ha=!1,Z=null;const ia=new Map,ja=Ca.createServer((a,b)=>Wa(a,b,!1));ja.on("error",a=>{e("[error] http: "+a.message);Z&&Z()});ja.on("connection",a=>{const b=++Ya;ia.set(b,a);a.on("close",()=>{ia.delete(b)})});q.http_start=async()=>{await q.http_stop();P&&(ha=!0,e("start http: http://localhost:"+P),await new Promise(a=>ja.listen(P,Z=a)),Z?Z=null:v&&e("started http"))};
|
|
42
|
-
v&&e("stopped http")}};q.http_kill=async()=>{ha||(e("kill http"),await Promise.all([...ia.values()].map(a=>a.destroy())),v&&e("killed http"),ia.clear())};try{const a=I.readFileSync("config/ssl/domain.key"),b=I.readFileSync("config/ssl/chained.pem");let c=!1,f=null;const g=new Map,k=require("https").createServer({key:a,cert:b},(l,p)=>Wa(l,p,!0));k.on("error",l=>{e("[error] https: "+
|
|
43
|
-
{await q.https_stop();Q&&(c=!0,e("start https: https://localhost:"+Q),await new Promise(l=>k.listen(Q,f=l)),f?f=null:v&&e("started https"))};q.https_stop=async()=>{if(c){c=!1;e("stop https");var l=setTimeout(q.https_kill,5E3);await new Promise(p=>k.close(p));clearTimeout(l);v&&e("stopped https")}};q.https_kill=async()=>{c||(e("kill https"),await Promise.all([...g.values()].map(l=>
|
|
44
|
-
a=>{try{a=JSON.parse(a);if(typeof a!=="object")throw"must contain {}";const b=Sa(a,"compress",!0),c=W(a,"gzip_level",3),f=Sa(a,"log_verbose",Ja),g=Ta(a,"path_aliases"),k=M(a,"path_ghosts"),l=M(a,"path_hiddens"),p=M(a,"path_statics"),m=W(a,"port_http",8080),w=W(a,"port_https",0),t=M(a,"services")||[],y=M(a,"type_dynamics"),
|
|
45
|
-
if(m>65535||w>65535)throw"port > 65535";if(H>19)throw"zstd_level > 19";aa=b;ka.level=aa?c:0;Ia.params[100]=H;v=f;Ka=x*1024*1024;if(k){oa.clear();for(const n of k)N(n),oa.add(n)}if(l){pa.clear();for(const n of l)N(n),pa.add(n)}if(p){qa.clear();for(const n of p)N(n),qa.add(n)}if(g){ba.clear();S.clear();T.clear();for(const [n,r]of g)if(N(n,!0),N(r),n.includes("*")){const A=
|
|
46
|
-
null||A.length-1>r.length)&&S.set(r,"/"+n)}}if(y){ra.clear();for(const n of y)ra.add(n)}if(
|
|
24
|
+
" ")):"1";if(f in b){if(b[f]instanceof Array!==a)throw"type mismatch";a?b[f].push(g):b[f]=g}else b[f]=a?[g]:g}},Wa=async(a,b,c)=>{const f=a.method,g=a.headers;var k;const l=((k=g["x-forwarded-for"])==null?void 0:k.split(la).findLast(E=>!$a.test(E)))||a.socket.remoteAddress;k=f==="HEAD";"x-forwarded-proto"in g&&(c=g["x-forwarded-proto"]==="https");Y&&fa("request",[c,a.url,l]);try{b.setHeader("Server","l3p3 rtjscomp v0.9.14");const E=Za.parse(a.url,!1);let h=E.pathname||"/";if(h.charCodeAt(0)!==47||
|
|
25
|
+
h.includes("//"))throw 404;if(h.length>1&&h.endsWith("/")&&(h=h.slice(0,-1),h.lastIndexOf("/")<h.lastIndexOf(".")))throw b.setHeader("Location",h),301;h=h.slice(1);if(!(h.includes("php")||h.includes("sql")||h.includes(".git/")||oa.has(h))){b.setHeader("Access-Control-Allow-Origin","*");var p=null,m=null;if(S.has(h))throw b.setHeader("Location",S.get(h)),301;if(ba.has(h))h=ba.get(h);else{var w=h.split("/"),t=T.get(w.shift());if(t!=null)a:for(var y of t){var C=y.x3,z=C.length;if(z===w.length){t={};
|
|
26
|
+
for(let d=0;d<z;++d)if(C[d].charCodeAt(0)===42)C[d].length>1&&(t[C[d].slice(1)]=w[d]);else if(C[d]!==w[d])continue a;h=y.value;p=t;break}}}var x=h.lastIndexOf(".");if(h.includes("..")||h.includes("~")||x<=h.lastIndexOf("/"))throw 404;var H=h.slice(x+1).toLowerCase();x=0;var L=ra.has(H)&&!qa.has(h);if(!k&&f!=="GET"){if(!L)throw 405;if("content-length"in g){var n=Number(g["content-length"]);if(isNaN(n)||n<0||n%1>0)throw 400;if(n>Ka)throw 413;m=new Promise(d=>{const u=[];a.on("data",D=>{u.push(D)});
|
|
27
|
+
a.on("end",D=>{D&&u.push(D);d(Buffer.concat(u))})})}}n=w=null;y="public/"+h;if(L&&da.has(h))w=da.get(h);else{v&&e(`load ${L?"dynam":"stat"}ic file: ${h}`);if(pa.has(h)||h.endsWith(".service.js")||(n=await G.stat(y).catch(()=>{throw 404;})).isDirectory())throw 403;if(L){const d=await G.readFile(y,"utf8").catch(()=>{throw 404;});try{if(d.includes("\r"))throw"illegal line break, must be unix";if(d.includes("response.write(")||d.includes("response.end("))throw"response.write() not allowed, use output.write()";
|
|
28
|
+
d.includes("globals.")&&e(`[deprecated] ${h}: uses globals object`);const u=d.length;let D=`const log=a=>rtjscomp.log(${JSON.stringify(h+": ")}+a);`;C=!1;for(t=z=0;t<u;)if(C){if((t=d.indexOf("?>",z=t+2))<0)throw'"?>" missing';C=!1;z<t&&(D=d.charCodeAt(z)!==61?D+(d.slice(z,t).replace(ma,"custom_import(")+";"):D+`output.write(''+(${d.slice(++z,t).replace(ma,"custom_import(")}));`);t+=2}else(t=d.indexOf("<?",z=t))>-1?C=!0:t=u,z<t&&(D+=`output.write(${JSON.stringify(d.slice(z,t))});`);try{w=new ya("input",
|
|
29
|
+
"output","request","response","require","custom_import","service_require","service_require_try",D)}catch(Ba){throw Ba.message;}}catch(u){throw e(`[error] ${h} compile: ${u}`),500;}da.set(h,w);fb(y,()=>da.delete(h))}}b.statusCode=200;b.setHeader("Content-Type",sa.get(H)||sa.get("txt"));if(L){var r=p||{};if(g.cookie)for(let d of g.cookie.split(";")){d=d.trim();const u=d.indexOf("=");u>0?r[d.slice(0,u).trimRight()]=decodeURI(d.slice(u+1).trimLeft()):u<0&&(r[d]=void 0)}if(g["x-input"])try{Aa(g["x-input"],
|
|
30
|
+
r)}catch(d){throw e(`[error] ${h} request x-input: ${d}`),400;}if(E.query)try{Aa(E.query,r)}catch(d){throw e(`[error] ${h} request query: ${d}`),400;}if(m)try{const d=a.headers["content-type"]||"",u=r.body=await m;switch(d.split(";",1)[0]){case "application/json":Object.assign(r,JSON.parse(u.toString()));break;case "application/x-www-form-urlencoded":Aa(u.toString(),r);break;case "multipart/form-data":gb(u,d.split("boundary=",2)[1].split(";",1)[0],r)}}catch(d){throw e(`[error] ${h} request body: ${d.message||
|
|
31
|
+
d}`),400;}r.https=c;r.ip=l;r.method=k?"get":f.toLowerCase();r.path=E.pathname;r.user_agent=g["user-agent"];var A=b;b.setHeader("Cache-Control","no-cache, no-store");if(aa&&"accept-encoding"in g&&!ca.has(H)){var K=g["accept-encoding"].split(la);Fa&&K.includes("zstd")?(x=3,k||(A=O.createZstdCompress(Ia)).pipe(b)):Ea&&K.includes("br")?(x=2,k||(A=O.createBrotliCompress()).pipe(b)):ka.level>0&&K.includes("gzip")&&(x=1,k||(A=O.createGzip(ka)).pipe(b));x>0&&b.setHeader("Content-Encoding",Da[x])}Y&&fa("execute",
|
|
32
|
+
[h,Object.fromEntries(Object.entries(r).filter(d=>d[0]!=="body").map(d=>d[0]==="password"?[d[0],"***"]:d).map(d=>d[0]==="file"?[d[0],"..."]:d).map(d=>typeof d[1]!=="object"||d[1]===null||d[1].length?d:[d[0],Object.keys(d[1]).slice(0,20)]).map(d=>d[0]!=="user_agent"&&typeof d[1]==="string"&&d[1].length>20?[d[0],d[1].slice(0,20)+"..."]:d))]);k&&(A.write=A.end=()=>{throw null;});await V;try{var B=await w(r,A,a,b,wa,xa,Pa,Qa)}catch(d){d instanceof Error?(e(`[error] ${h}: ${d.message}`),B=d.message.startsWith("service required: ")?
|
|
33
|
+
503:500):typeof d==="number"?(e(`[deprecated] ${h}: status code thrown, use return instead`),B=d):d!==null&&(e(`[error] ${h}: invalid throw type: ${typeof d}`),B=500)}k&&(delete A.write,delete A.end);if(B!=null){b.headersSent?(b.writableEnded!=null?b.writableEnded:b.finished)||A.end(`${H==="html"?"<hr>":"\n\n---\n"}ERROR!`):x>0&&b.removeHeader("Content-Encoding");if(typeof B!=="number"||B<100||B>599||B%1>0)throw e(`[error] ${h}: invalid status code: ${B}`),500;if(b.headersSent&&B<500)throw e(`[error] ${h}: status code after content`),
|
|
34
|
+
500;throw B;}A.end()}else{const d=aa&&!ca.has(H);H=y;if(d&&"accept-encoding"in g){const u=g["accept-encoding"].split(la);u.includes("zstd")&&I.existsSync(y+".zst")?(x=3,H+=".zst"):u.includes("br")&&I.existsSync(y+".br")?(x=2,H+=".br"):u.includes("gzip")&&I.existsSync(y+".gz")&&(x=1,H+=".gz")}Y&&fa("static_send",[h,x]);d&&b.setHeader("Vary","Accept-Encoding");b.setHeader("Cache-Control","public, max-age=31536000");b.setHeader("Last-Modified",(new Date(n.mtimeMs)).toUTCString());if("if-modified-since"in
|
|
35
|
+
g&&n.mtimeMs<=new Date(g["if-modified-since"]))b.statusCode=304,b.end();else{B=0;r=n.size-1;K=!1;if(x===0&&(b.setHeader("Accept-Ranges","bytes"),!k&&"range"in g&&(A=g.range.match(/^bytes=(\d*)-(\d*)$/)))){const u=A[1],D=A[2];if(u||D){K=!0;if(u&&D)B=parseInt(u),r=parseInt(D);else{if(u)B=parseInt(u);else{const Ba=parseInt(D);B=Math.max(0,n.size-Ba)}r=n.size-1}if(B>r||r>=n.size)throw b.setHeader("Content-Range",`bytes */${n.size}`),416;b.statusCode=206;b.setHeader("Content-Length",r-B+1);b.setHeader("Content-Range",
|
|
36
|
+
`bytes ${B}-${r}/${n.size}`)}}K||(x===0?b.setHeader("Content-Length",n.size):b.setHeader("Content-Encoding",Da[x]));if(k)b.end();else{const u=I.createReadStream(H,K?{start:B,end:r}:{});u.on("error",D=>{e(`[error] ${h} stream: ${D.message}`);if(!b.headersSent)throw 500;});u.pipe(b)}}}}}catch(E){typeof E!=="number"&&(console.error("[internal error]",E),E=500),(E>=500||v&&E>=400)&&e(`[error] request failed: ${E}; ${l}; ${a.url}`),b.headersSent||(b.writeHead(E,{"Content-Type":"text/html","Cache-Control":"no-cache, no-store"}),
|
|
37
|
+
b.end(`<!DOCTYPE html><html><body><h1>HTTP ${E}: ${Ca.STATUS_CODES[E]||"Error"}</h1></body></html>`)),"content-length"in g&&a.socket.destroy()}};q.halt=async()=>{R=!0;v&&e("stop all");await Promise.all([q.http_stop&&q.http_stop(),q.https_stop&&q.https_stop(),eb()]);await q.spam_save();e("stopped all")};q.exit=async a=>{R||(typeof a!=="number"&&(a=0),await q.halt(),v&&e("exit"),process.exit(a))};process.on("uncaughtException",a=>{typeof a==="symbol"&&(a=a.toString());e("[error] uncaughtException: "+
|
|
38
|
+
(a.message||a));console.error(a);R&&process.exit(1);q.exit(1)});process.on("unhandledRejection",a=>{e("[error] unhandledRejection: "+(a.message||a));console.error(a);R&&process.exit(1);q.exit(1)});process.on("exit",q.exit);process.on("SIGINT",q.exit);process.on("SIGUSR2",q.exit);process.on("SIGTERM",q.exit);e(`rtjscomp v${"0.9.14"} in ${Ga?"bun":"node"} on ${process.platform.replace("win32","windows")}`);v&&!Ea&&e("[hint] brotli not available");v&&!Fa&&e("[hint] zstd not available");await ta("config/init.js",
|
|
39
|
+
async a=>{if(a){e("[deprecated] run global init script");try{await (new ya("require",a))(wa)}catch(b){e("[error] init.js: "+b.message)}}});const [hb,ib,...Xa]=await Promise.all([G.stat("data/").catch(a=>null),G.stat("public/").catch(a=>null),..."file_blocks file_privates file_raws file_type_dyns file_type_mimes file_type_nocompress path_aliases port_http port_https services".split(" ").map(a=>G.readFile("config/"+a+".txt","utf8").catch(b=>null))]);hb||I.mkdirSync("data/");ib||I.cpSync(__dirname+"/public/",
|
|
40
|
+
"public/",{recursive:!0});if(Xa.some(a=>a!==null)){const a=JSON.parse(await G.readFile("rtjscomp.json","utf8").catch(y=>null))||{},[b,c,f,g,k,l,p,m,w,t]=Xa;b&&(a.path_ghosts=X(b));c&&(a.path_hiddens=X(c));f&&(a.path_statics=X(f));g&&(a.type_dynamics=X(g));k&&(a.type_mimes=Ua(k));l&&(a.type_raws=X(l));p&&(a.path_aliases=Ua(p));if(m){const y=Number(m);isNaN(y)||(a.port_http=y)}if(w){const y=Number(w);isNaN(y)||(a.port_https=y)}t&&(a.services=t.split("\n").filter(y=>y.length>0));await G.writeFile("rtjscomp.json",
|
|
41
|
+
JSON.stringify(a,null,"\t")+"\n","utf8");e("[deprecated] config files found, rtjscomp.json written, please delete config files")}let Ya=0,ha=!1,Z=null;const ia=new Map,ja=Ca.createServer((a,b)=>Wa(a,b,!1));ja.on("error",a=>{e("[error] http: "+a.message);Z&&Z()});ja.on("connection",a=>{const b=++Ya;ia.set(b,a);a.on("close",()=>{ia.delete(b)})});q.http_start=async()=>{await q.http_stop();P&&(ha=!0,e("start http: http://localhost:"+P),await new Promise(a=>ja.listen(P,Z=a)),Z?Z=null:v&&e("started http"))};
|
|
42
|
+
q.http_stop=async()=>{if(ha){ha=!1;e("stop http");var a=setTimeout(q.http_kill,5E3);await new Promise(b=>ja.close(b));clearTimeout(a);v&&e("stopped http")}};q.http_kill=async()=>{ha||(e("kill http"),await Promise.all([...ia.values()].map(a=>a.destroy())),v&&e("killed http"),ia.clear())};try{const a=I.readFileSync("config/ssl/domain.key"),b=I.readFileSync("config/ssl/chained.pem");let c=!1,f=null;const g=new Map,k=require("https").createServer({key:a,cert:b},(l,p)=>Wa(l,p,!0));k.on("error",l=>{e("[error] https: "+
|
|
43
|
+
l.message);f&&f()});k.on("connection",l=>{const p=++Ya;g.set(p,l);l.on("close",()=>{g.delete(p)})});q.https_start=async()=>{await q.https_stop();Q&&(c=!0,e("start https: https://localhost:"+Q),await new Promise(l=>k.listen(Q,f=l)),f?f=null:v&&e("started https"))};q.https_stop=async()=>{if(c){c=!1;e("stop https");var l=setTimeout(q.https_kill,5E3);await new Promise(p=>k.close(p));clearTimeout(l);v&&e("stopped https")}};q.https_kill=async()=>{c||(e("kill https"),await Promise.all([...g.values()].map(l=>
|
|
44
|
+
l.destroy())),v&&e("killed https"),g.clear())}}catch(a){v&&e("[hint] https: no cert, disabled")}await ta("rtjscomp.json",a=>{try{a=JSON.parse(a);if(typeof a!=="object")throw"must contain {}";const b=Sa(a,"compress",!0),c=W(a,"gzip_level",3),f=Sa(a,"log_verbose",Ja),g=Ta(a,"path_aliases"),k=M(a,"path_ghosts"),l=M(a,"path_hiddens"),p=M(a,"path_statics"),m=W(a,"port_http",8080),w=W(a,"port_https",0),t=M(a,"services")||[],y=M(a,"type_dynamics"),C=Ta(a,"type_mimes"),z=M(a,"type_raws"),x=W(a,"upload_limit",
|
|
45
|
+
10),H=W(a,"zstd_level",3);if(a){const n=Object.keys(a);if(n.length>0)throw"unknown: "+n.join(", ");}if(c>9)throw"gzip_level > 9";if(m>65535||w>65535)throw"port > 65535";if(H>19)throw"zstd_level > 19";aa=b;ka.level=aa?c:0;Ia.params[100]=H;v=f;Ka=x*1024*1024;if(k){oa.clear();for(const n of k)N(n),oa.add(n)}if(l){pa.clear();for(const n of l)N(n),pa.add(n)}if(p){qa.clear();for(const n of p)N(n),qa.add(n)}if(g){ba.clear();S.clear();T.clear();for(const [n,r]of g)if(N(n,!0),N(r),n.includes("*")){const A=
|
|
46
|
+
n.split("/"),K=A.shift();T.has(K)?T.get(K).push({x3:A,value:r}):T.set(K,[{x3:A,value:r}])}else{ba.set(n,r);const A=S.get(r);(A==null||A.length-1>r.length)&&S.set(r,"/"+n)}}if(y){ra.clear();for(const n of y)ra.add(n)}if(C)for(const [n,r]of C)sa.set(n,r);if(z){ca.clear();for(const n of z)ca.add(n)}for(const n of t)N(n);const L=[db(t.filter(n=>n.charCodeAt(0)!==35))];m!==P&&(P=m,L.push(m>0?q.http_start():q.http_stop()));q.https_stop!=null&&w!==Q&&(Q=w,L.push(w>0?q.https_start():q.https_stop()));return Promise.all(L)}catch(b){e("[error] rtjscomp.json: "+
|
|
47
|
+
(b.message||b))}});v&&e("started all")})();
|