tools-mock
Version:
A node.js mock tool to quickly start the server via http
2 lines (1 loc) • 7.15 kB
JavaScript
;var t=require("os"),e=require("node:process"),r=require("http"),s=require("cors"),i=require("path"),n=require("fs"),o=require("url"),c=require("ws");function a(t){var e=Object.create(null);return t&&Object.keys(t).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,s.get?s:{enumerable:!0,get:function(){return t[r]}})}})),e.default=t,Object.freeze(e)}var l=a(t),p=a(r),h=a(i),f=a(n),u=a(o),g=a(c);class d{static async getLocalIPv4(){const t=l.networkInterfaces();for(let e in t){let r=t[e];for(let t=0;t<r.length;t++){let e=r[t];if("IPv4"===e.family&&"127.0.0.1"!==e.address&&!e.internal)return e.address}}}static exceptionFun=(t,e)=>{console.log(t,e)};static exceptionRun=!1;static exception(t){this.exceptionRun||(this.exceptionRun=!0,e.on("uncaughtException",t??this.exceptionFun))}}class m{staticDir="";port=3900;config={staticFileContentType:t=>({".html":"text/html",".js":"text/javascript",".css":"text/css",".json":"application/json",".png":"image/png",".jpg":"image/jpg",".gif":"image/gif",".svg":"image/svg+xml",".zip":"application/zip"}[t]||"application/octet-stream")};wsconfig={open:!1}}class y{CMockConfig;constructor(t){this.CMockConfig=t}controller=async(t,e,r)=>{const s=t.method;"GET"===s&&(r=(t=>{const e=/[?&]([^=#]+)=([^&#]*)/g;if(t.match){const r=t.match(e);if(r)return r.reduce(((t,e)=>{const[r,s]=e.substring(1).split("=");return t[r]=decodeURIComponent(s),t}),{})}return{}})(t.url));let i=t.url+"";-1!==i.indexOf("?")&&(i=i.split("?")[0]);const n=this.CMockConfig.config.data[i];if(n){let o=t.headers["Content-Type"];if(o||(o="application/json"),n.method.toLocaleUpperCase()!=s)return e.writeHead(405,{"Content-Type":`${o}; charset=utf-8`}),void e.end();(async()=>{try{r=JSON.parse(r)}catch(t){}try{r=JSON.stringify(r)}catch(t){}let s=await n.fun(r,t,e),c={"Content-Type":`${o}; charset=utf-8`,"Access-Control-Allow-Origin":"*","Access-Control-Allow-Credentials":"true"};const a=this.CMockConfig.config.resAfter;if(a){const t={url:i,data:s,headers:c};a(t),s=t.data,c=t.headers}o.indexOf("event-stream")<0&&(e.writeHead(200,c),e.write(s||""),e.end())})()}else{const t=this.CMockConfig.config.staticFileUrl;i=decodeURIComponent(i),t&&(i=t(i));let r=h.join(this.CMockConfig.staticDir,i);const s=String(h.extname(i)).toLowerCase(),n=this.CMockConfig.config.staticFileContentType,o=n?n(s):"application/octet-stream";e.writeHead(200,{"Content-Type":o});const c=f.createReadStream(r);c.pipe(e),c.on("error",(t=>{"ENOENT"===t.code?e.end("404 Not Found"):e.end(`Server Error: ${t.code}`)}))}}}function C(t){const e=Array.from(t.matchAll(/\/#{([^\/}]+)}/g));if(0===e.length)return{params:[]};return{params:e.map((t=>t[1]))}}class v{CMockConfig;pathMap=null;constructor(t){this.CMockConfig=t}setPath=()=>{this.pathMap={};const t=this.CMockConfig.wsconfig.data,e=Object.keys(t);for(let r=0;r<e.length;r++){const s=e[r],i=t[s],n=s.indexOf("/#"),o=-1!==n?s.substring(0,n):s;let c=[];-1!==n&&(c=C(s.substring(n)).params),this.pathMap[o]||(this.pathMap[o]={}),this.pathMap[o][c.length]={params:c,connection:i.connection,message:i.message}}};getUrl=t=>{const e=u.parse(t.url,!0),r=e.pathname.split("/").filter(Boolean);let s=null,i="",n={};for(let t=0;t<r.length;t++){i=i+"/"+r[t];const e=this.pathMap[i];if(e){const i=JSON.parse(JSON.stringify(r)),o=i.splice(t+1,i.length-1),c=e[o.length];c&&(o.forEach(((t,e)=>{n[c.params[e]]=o[e]})),s=c)}else if(s)break}if(s){return{item:s,param:Object.assign({...e.query},n)}}return null}}class w{server=null;wsserver=null;CMockConfig;CMockRouter;CMockWSRouter;constructor(t){this.CMockConfig=t,this.CMockRouter=new y(t),this.CMockWSRouter=new v(t)}run=()=>{let t=this.CMockConfig.port;const e=this.CMockConfig.staticDir;return new Promise((async r=>{try{if(this.CMockConfig.staticDir=h.resolve(e),null!==this.server)return void r(!1);if(t=parseInt(t+""),t+""=="NaN")return void r(!1);this.server=p.createServer(((t,e)=>{s()(t,e,(()=>{const r=this.CMockConfig.config.reqBefore;if(r&&!1===r(t,e))return;const s=t.headers["content-type"];if(s&&-1!==s.indexOf("multipart/form-data"))return void this.CMockRouter.controller(t,e,{});let i="";t.on("data",(t=>{i+=t})),t.on("end",(()=>{t.headers?this.CMockRouter.controller(t,e,i):(e.writeHead(404,{"Content-Type":"text/plain"}),e.end())}))}))})),this.CMockConfig.wsconfig.open&&(this.CMockWSRouter.setPath(),this.wsserver=new g.Server({noServer:!0}),this.wsserver.on("connection",((t,e)=>{const r=this.CMockWSRouter.getUrl(e);r?(r.item.connection({req:e,ws:t,param:r.param}),t.on("message",(s=>{r.item.message({req:e,ws:t,param:r.param,message:s})}))):t.close(4e3,"Invalid path format")})),this.server.on("upgrade",((t,e,r)=>{this.wsserver.handleUpgrade(t,e,r,(e=>{this.wsserver.emit("connection",e,t)}))}))),this.server.listen(t,(async()=>{const t=await d.getLocalIPv4();r([t])}))}catch(t){r(!1)}}))};stop=()=>{this.server&&(this.server.removeAllListeners(),this.server.closeAllConnections(),this.server.close(),this.server=null)}}class k{static copyFile(t,e){return new Promise(((r,s)=>{const i=f.createReadStream(t);i.on("error",(t=>{s(t)}));const n=f.createWriteStream(e);n.on("error",(t=>{s(t)})),n.on("close",(()=>{r()})),i.pipe(n)}))}static async copyFolder(t,e){return new Promise(((r,s)=>{f.mkdir(e,{recursive:!0},(async i=>{if(i)s(i);else try{const s=await f.promises.readdir(t,{withFileTypes:!0});for(const r of s){const s=h.join(t,r.name),i=h.join(e,r.name);r.isDirectory()?await this.copyFolder(s,i):await this.copyFile(s,i)}r()}catch(i){s(i)}}))}))}static deleteFileOrDirectory=t=>{try{if(f.existsSync(t))if(f.lstatSync(t).isDirectory()){const e=f.readdirSync(t);for(let r=0;r<e.length;r++){const s=h.join(t,e[r]);k.deleteFileOrDirectory(s)}f.rmdirSync(t)}else f.unlinkSync(t)}catch(e){console.error(`删除错误 ${t}: ${e}`)}};static readFile(t,e="utf8"){return new Promise(((r,s)=>{f.readFile(t,e,((t,e)=>{r(t?void 0:e)}))}))}static async readDirectory(t,e){try{const r=(await f.promises.readdir(t)).map((async r=>{const s=h.join(t,r);(await f.promises.stat(s)).isDirectory()?await k.readDirectory(s,e):e&&await e(s)}));await Promise.all(r)}catch(t){throw t}}static async writeFile(t,e,r="utf8"){const s=h.dirname(t);try{f.mkdirSync(s,{recursive:!0}),"string"!=typeof e&&(e=Buffer.from(e)),f.writeFileSync(t,e,r)}catch{console.log("保存错误",t)}}static async exists(t,e=!0){const r=f.existsSync(t);return r||(e&&f.mkdirSync(t,{recursive:!0}),r)}static getSuffix(t){const e=t.split(".");return 1===e.length||""===e[0]&&2===e.length?null:e.pop()?.split("?")[0]||null}}exports.CMock=class{server=null;config=null;constructor(){this.config=new m}setStaticDir=t=>{this.config.staticDir=t};setConfig=t=>{this.config.config=Object.assign(this.config.config,t)};setData=t=>{this.config.config.data=Object.assign(this.config.config.data||{},t)};setWSData=t=>{this.config.wsconfig.open=!0,this.config.wsconfig.data=t};run=async t=>{d.exception(),this.server&&(this.server.stop(),this.server=null),this.config.port=t,this.server=new w(this.config);const e=await this.server.run();return console.log("success => ","http://"+e[0]+":"+t),e}},exports.FileUtil=k,exports.SystemUtil=d;