forked from dreamgineer/Bunginx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbunginx
executable file
·3 lines (3 loc) · 3.85 KB
/
bunginx
1
2
3
#!/usr/bin/env -S bun
// @bun
import J from"fs";import{availableParallelism as A} from"os";import{join as K} from"path";import{parseArgs as V} from"util";import{Worker as W,workerData as T} from"worker_threads";var __filename="/home/superdinmc/Scripts/Bunginx/index.ts";if(Bun.isMainThread){const G=V({args:Bun.argv.slice(2),options:{port:{type:"string",default:process.env.PORT||"8000",short:"p"},cluster:{type:"string",default:A().toString(),short:"c"},help:{type:"boolean",short:"h"},debug:{type:"boolean",short:"d"}},allowPositionals:!0}),H=parseInt(`${G?.values?.cluster}`),I=parseInt(`${G?.values?.port}`);if(!H||Number.isNaN(H))console.error("Cluster thread count must be number [--cluster | -c]"),process.exit(1);if(!I||Number.isNaN(I))console.error("Port must be number [--port | -p]"),process.exit(1);if(G.values.help)console.log("Bunginx: Fast, lightweight, simple HTTP file server\n","bunginx [-pdhc] [--port <port>] [--cluster <count>] [--debug] [cwd]\n","--port <port: number> Set the port for Bunginx [-p]\n"," - defaults to $PORT or 8000.\n","--cluster <count: number> Set the threads that Bunginx will spawn [-c]\n"," - defaults to the CPU core count.\n","--debug Display debug messages during run [-d]\n","--help Display this message [-h]\n","[cwd: string] Directory that Bunginx will run on,\n"," - defaults to current directory."),process.exit();const M=G?.positionals.join(" "),X=!!G?.values.debug;console.log("Bunginx vB8C6EE\n");for(let Q=0;Q<H;Q++){const B=new W(process.argv[1]||__filename,{workerData:{port:I,id:Q,cwd:M||process.cwd(),debug:X}})}console.log("Serving"+(M?" "+M:""),"with",H,"threads at port",I)}else{let Q=function(B,z){const R=Math.max(...B.map((E)=>E.name.length))+5,Z=B.sort((E,U)=>U.priority-E.priority||E.name.localeCompare(U.name)).map((E)=>`<a id="a" href="${K(z,E.name)}">${E.name.padEnd(R," ")} | ${E.type}</a><br>`);return`${z==="/"?"":`<a href="${K(z,"..")}"><=</a>`} <a id="header">${z}:</a><br>${Z.join("")}${X}`};const G=T?.cwd,H=T?.debug;if(Y="Unknown Origin",Bun.serve({async fetch(B){const z=new URL(B.url);Y=z?.pathname;const R=await M(decodeURIComponent(z.pathname));if(H)console.debug(`[w${T.id}|${R.status}] ${z?.pathname}`);return R},error(B){return new Response(`${Y}: ${B}`,{status:500})},reusePort:!0,port:T?.port}),H)console.log(`[w${T.id}] Online.`);const I=Bun.file(G+"404.html");async function M(B){let z=K(G,B);if(!z.startsWith(G)||z.includes(".."))return new Response(B+": 404 Not Found",{status:404});if(!J.existsSync(z)){if(await I.exists())return new Response(I,{status:404,headers:new Headers({"Content-Type":"text/html"})});return new Response(B+": 404 Not Found",{status:404})}if(await Bun.file(K(z,"index.html")).exists()){if(!B.endsWith("/"))return new Response("",{status:307,headers:new Headers({Location:K(B,"/")})});return await M(K(B,"index.html"))}if(await Bun.file(z+".html").exists())z=z+".html";const E=J.lstatSync(z);if(E.isDirectory()){const U=J.readdirSync(z,{withFileTypes:!0}).map((N)=>{let O="Unknown",S=0;if(N.isDirectory()){if(O="Directory",S=3,J.existsSync(K(N.name,"index.html")))O="Website",S=4}if(N.isFile()){const $=N.name.split(".").slice(1);if(!$.length)O="File";else O=$.join(".").toUpperCase()+" file";S=2}if(N.isSymbolicLink())O="Symlink",S=1;return{name:N.name,type:O,priority:S}});return new Response(Q(U,B),{status:200,headers:new Headers({"Content-Type":"text/html"})})}else{if(E.mode&(J.constants.S_IRUSR|J.constants.S_IRGRP|J.constants.S_IROTH))return new Response(Bun.file(z));return new Response(B+": 403 Forbidden",{status:403})}}const X='<hr><a id="footer">Bunginx | Fast, lightweight, simple HTTP file server<br>Dreamnity inc. 2024</a><style>#footer{font-size:smaller;}#header{font-weight:bold;}#a{white-space:break-spaces;font-family:monospace}*{text-decoration:none}</style>'}var Y;