1 | !function(e){var t={}
|
2 | function n(r){if(t[r])return t[r].exports
|
3 | var o=t[r]={i:r,l:!1,exports:{}}
|
4 | e[r].call(o.exports,o,o.exports,n)
|
5 | o.l=!0
|
6 | return o.exports}n.m=e
|
7 | n.c=t
|
8 | n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})}
|
9 | n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})
|
10 | Object.defineProperty(e,"__esModule",{value:!0})}
|
11 | n.t=function(e,t){1&t&&(e=n(e))
|
12 | if(8&t)return e
|
13 | if(4&t&&"object"==typeof e&&e&&e.__esModule)return e
|
14 | var r=Object.create(null)
|
15 | n.r(r)
|
16 | Object.defineProperty(r,"default",{enumerable:!0,value:e})
|
17 | if(2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o))
|
18 | return r}
|
19 | n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e}
|
20 | n.d(t,"a",t)
|
21 | return t}
|
22 | n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}
|
23 | n.p=""
|
24 | n(n.s=12)}([function(e,t){e.exports=require("fs")},function(e,t){e.exports=require("path")},function(e,t){e.exports=require("util")},function(e,t){e.exports=require("crypto")},function(e,t){e.exports=require("url")},function(e,t){e.exports=require("zlib")},function(e,t){e.exports=require("http")},function(e,t){e.exports=require("https")},function(module,__webpack_exports__,__webpack_require__){__webpack_require__.d(__webpack_exports__,"a",function(){return tryRequire})
|
25 | const tryRequire=(name="")=>{try{return eval("require")(name)}catch(e){}}},function(e){e.exports={a:"imock-snapshot",b:"0.7.0"}},function(e,t){e.exports=require("readline")},function(e,t){e.exports=require("stream")},function(e,t,n){n.r(t)
|
26 | var r=n(1)
|
27 | var o=n(0)
|
28 | var s=n(2)
|
29 | n(10)
|
30 | Object(s.promisify)(o.stat)
|
31 | const a=Object(s.promisify)(o.lstat)
|
32 | Object(s.promisify)(o.rename)
|
33 | Object(s.promisify)(o.unlink)
|
34 | Object(s.promisify)(o.access)
|
35 | const i=Object(s.promisify)(o.mkdir)
|
36 | Object(s.promisify)(o.rmdir)
|
37 | const c=Object(s.promisify)(o.readdir)
|
38 | const u=Object(s.promisify)(o.readFile)
|
39 | const p=Object(s.promisify)(o.writeFile)
|
40 | o.copyFile?Object(s.promisify)(o.copyFile):(()=>{const e=Object(s.promisify)(o.open)
|
41 | const t=Object(s.promisify)(o.fstat)})()
|
42 | r.sep
|
43 | const l=new o.Stats(-1,-1,0,-1,-1,-1,0,0,0,0,0,0,0,0)
|
44 | const d="File",g="Directory",h="SymbolicLink",m="Other",f="Error"
|
45 | const S=e=>l
|
46 | const w=e=>a(e).catch(S)
|
47 | const y=e=>e.isDirectory()?g:e.isFile()?d:e.isSymbolicLink()?h:e!==l?m:f
|
48 | const b=async(e,t)=>{void 0===t&&(t=await w(e))
|
49 | if(t.isDirectory())return
|
50 | if(t!==l)throw new Error("[createDirectory] path already taken by non-directory")
|
51 | const n=Object(r.dirname)(e)
|
52 | const o=await w(n)
|
53 | !o.isDirectory()&&await b(n,o)
|
54 | await i(e)}
|
55 | const v=e=>{console.warn(e)
|
56 | throw e}
|
57 | const k=(e,...t)=>{let n,r
|
58 | try{n=e(...t)}catch(e){r=e}return{result:n,error:r}}
|
59 | const x=async(e,...t)=>{let n,r
|
60 | try{n=await e(...t)}catch(e){r=e}return{result:n,error:r}}
|
61 | const T=({queueLengthThreshold:e,...t})=>(({outputStream:e,queueLengthThreshold:t=1024})=>{const n=[]
|
62 | const r=()=>{n.push("")
|
63 | const e=n.join("\n")
|
64 | n.length=0
|
65 | return e}
|
66 | const o=()=>{0!==n.length&&e.write(r())}
|
67 | return{add:e=>{n.push(e)
|
68 | n.length>t&&o()},save:o,end:()=>{0!==n.length&&e.write(r())
|
69 | e.end()}}})({outputStream:(({pathOutputFile:e,flag:t="w",mode:n=438,onError:r=v})=>{let s=Object(o.openSync)(e,t,n)
|
70 | let a=[]
|
71 | let i=[]
|
72 | const c=e=>e?r(e):a.length=0
|
73 | const u=e=>s&&Object(o.write)(s,e,c)
|
74 | return{write:e=>{if(e){i.push(e)
|
75 | if(0===a.length){[a,i]=[i,[]]
|
76 | process.nextTick(u,a.join(""))}}},end:()=>{const e=[...a,...i]
|
77 | 0!==e.length&&Object(o.writeSync)(s,e.join(""))
|
78 | Object(o.closeSync)(s)
|
79 | s=null
|
80 | i.length=a.length=0}}})(t),queueLengthThreshold:e})
|
81 | const O=[{event:"exit",listener:e=>E({eventType:"exit",code:e})},{event:"uncaughtException",listener:e=>N({eventType:"uncaughtException",error:e})},{event:"unhandledRejection",listener:(e,t)=>N({eventType:"unhandledRejection",error:e,promise:t})},...["SIGINT","SIGHUP","SIGQUIT","SIGTERM"].map(e=>({event:e,listener:()=>N({eventType:"signal",signalEventType:e})}))]
|
82 | const $=new Set
|
83 | const L=new Set
|
84 | const E=e=>{for(const t of Array.from($))k(t,e)}
|
85 | const N=async e=>{R()
|
86 | for(const t of Array.from(L))await x(t,e)
|
87 | E(e)
|
88 | process.exit(e.code||(e.error?-1:0))}
|
89 | let A=!1
|
90 | const P=()=>{A=!0
|
91 | O.forEach(({event:e,listener:t})=>process.on(e,t))}
|
92 | const R=()=>{A=!1
|
93 | O.forEach(({event:e,listener:t})=>process.removeListener(e,t))}
|
94 | const j=(...e)=>{e.forEach(e=>$.add(e))
|
95 | !A&&P()}
|
96 | const C=(...e)=>{e.forEach(e=>L.add(e))
|
97 | !A&&P()}
|
98 | const D=()=>{}
|
99 | const I=async({pathLogDirectory:e,logFilePrefix:t})=>{const n=(({add:e,...t})=>({...t,add:(...t)=>e((new Date).toISOString(),...t)}))(e?await(async({pathLogDirectory:e,prefixLogFile:t="",getLogFileName:n=(()=>`${t}${(new Date).toISOString().replace(/\W/g,"-")}.log`),saveInterval:o=3e4,splitInterval:s=864e5,...a})=>{let i
|
100 | let c
|
101 | let u
|
102 | const p=()=>{g()
|
103 | const t=Object(r.resolve)(e,n())
|
104 | i=T({...a,pathOutputFile:t})
|
105 | c=o&&setInterval(l,o)
|
106 | u=s&&setTimeout(d,s)}
|
107 | const l=()=>{i&&i.save()}
|
108 | const d=()=>{i&&p()}
|
109 | const g=()=>{i&&i.end()
|
110 | c&&clearInterval(c)
|
111 | u&&clearTimeout(u)
|
112 | i=null
|
113 | c=null
|
114 | u=null}
|
115 | await b(e)
|
116 | p()
|
117 | return{add:(...e)=>{i&&i.add(e.join(" "))},save:l,split:d,end:g}})({flags:"a",pathLogDirectory:e,getLogFileName:()=>`${t}${(new Date).toISOString().replace(/\W/g,"-")}.log`}):{add:console.log,save:D,split:D,end:D})
|
118 | C(e=>{n.add(`[EXITING] ${JSON.stringify(e)}`)})
|
119 | j(e=>{n.add(`[EXIT] ${JSON.stringify(e)}`)
|
120 | e.error&&n.add(`[EXIT][ERROR] ${e.error.stack||e.error}`)
|
121 | n.end()})
|
122 | return n}
|
123 | var M=n(3)
|
124 | var F=n(6)
|
125 | var _=n(7)
|
126 | const z=()=>"undefined"!=typeof window?window:"undefined"!=typeof global?global:void 0
|
127 | const U=z()
|
128 | const q=(()=>{try{const{performance:e}=U
|
129 | const t=e.now.bind(e)
|
130 | if(t()<=t())return t}catch(e){}try{const{process:e}=U
|
131 | const t=()=>{const[t,n]=e.hrtime()
|
132 | return 1e3*t+1e-6*n}
|
133 | if(t()<=t())return t}catch(e){}return Date.now})()
|
134 | const J=()=>Math.floor(.001*Date.now())
|
135 | const G=(e=0)=>new Promise(t=>setTimeout(t,e))
|
136 | const[H,B]=U.requestAnimationFrame?[U.requestAnimationFrame,U.cancelAnimationFrame]:[e=>setTimeout(e,1e3/60),clearTimeout]
|
137 | const V=(e,t=null,n=null)=>({value:e,prev:t,next:n})
|
138 | const Q=(e,t,n,r)=>({...V(t),key:e,size:n,expireAt:r})
|
139 | const W=({valueSizeSumMax:e,valueSizeSingleMax:t=Math.max(.05*e,1)})=>{const{clear:n,subscribe:r,unsubscribe:o,send:s}=(()=>{let e=new Set
|
140 | return{clear:()=>e.clear(),subscribe:t=>{e.add(t)},unsubscribe:t=>{e.delete(t)},send:t=>e.forEach(e=>e(t))}})()
|
141 | const a=new Map
|
142 | const i=(()=>{let e,t,n
|
143 | const r=()=>{e=new Set
|
144 | t=V(null)
|
145 | n=V(null)
|
146 | t.next=n
|
147 | n.prev=t}
|
148 | r()
|
149 | const o=(t,n)=>{const{next:r}=n
|
150 | n.next=r.prev=t
|
151 | t.prev=n
|
152 | t.next=r
|
153 | e.add(t)}
|
154 | const s=(t,n)=>{const{prev:r}=n
|
155 | n.prev=r.next=t
|
156 | t.prev=r
|
157 | t.next=n
|
158 | e.add(t)}
|
159 | const a=t=>{const{prev:n,next:r}=t
|
160 | n.next=r
|
161 | r.prev=n
|
162 | t.prev=t.next=null
|
163 | e.delete(t)}
|
164 | return{clear:r,getHead:()=>t,getTail:()=>n,getLength:()=>e.size,insertAfter:o,insertBefore:s,remove:a,removeBetween:(t,n)=>{const{prev:r}=t
|
165 | const{next:o}=n
|
166 | r.next=o
|
167 | o.prev=r
|
168 | t.prev=n.next=null
|
169 | let s=t
|
170 | for(;s;){e.delete(s)
|
171 | s=s.next}},forEach:e=>{let r=t.next
|
172 | let o=0
|
173 | for(;r!==n;){e(r,o)
|
174 | r=r.next
|
175 | o++}},forEachReverse:r=>{let o=n.prev
|
176 | let s=e.size-1
|
177 | for(;o!==t;){r(o,s)
|
178 | o=o.prev
|
179 | s--}},reverse:()=>{let e=t.next
|
180 | for(;e!==n;){const{prev:t,next:n}=e
|
181 | e.prev=n
|
182 | e.next=t
|
183 | e=n}const{next:r}=t
|
184 | const{prev:o}=n
|
185 | t.next=o
|
186 | n.prev=r
|
187 | o.prev=t
|
188 | r.next=n},setFirst:e=>{if(e===t.next)return
|
189 | const{prev:n,next:r}=e
|
190 | n.next=r
|
191 | r.prev=n
|
192 | e.prev=t
|
193 | e.next=t.next
|
194 | t.next=e},setLast:e=>{if(e===n.prev)return
|
195 | const{prev:t,next:r}=e
|
196 | t.next=r
|
197 | r.prev=t
|
198 | e.prev=n.prev
|
199 | e.next=n
|
200 | n.prev=e},push:e=>s(e,n),pop:()=>a(n.prev),unshift:e=>o(e,t),shift:()=>a(t.next)}})()
|
201 | let c=0
|
202 | const u=e=>{a.set(e.key,e)
|
203 | i.unshift(e)
|
204 | c+=e.size
|
205 | s({type:"add",key:e.key,payload:e.value})}
|
206 | const p=e=>{a.delete(e.key)
|
207 | i.remove(e)
|
208 | c-=e.size
|
209 | s({type:"delete",key:e.key,payload:e.value})}
|
210 | return{clearHub:n,subscribe:r,unsubscribe:o,getSize:()=>a.size,clear:()=>a.forEach(p),set:(n,r,o=1,s=Date.now()+6e4)=>{const l=a.get(n)
|
211 | l&&p(l)
|
212 | if(!(o>t)){for(;o+c>e;)p(i.getTail().prev)
|
213 | u(Q(n,r,o,s))}},get:(e,t=Date.now())=>{const n=a.get(e)
|
214 | if(n){if(n.expireAt<=t)return p(n)
|
215 | i.setFirst(n)
|
216 | return n.value}},touch:(e,t=Date.now()+6e4)=>{const n=a.get(e)
|
217 | if(n){n.expireAt=t
|
218 | i.setFirst(n)
|
219 | return n.value}},delete:e=>{const t=a.get(e)
|
220 | t&&p(t)
|
221 | return t&&t.value},packList:()=>{const e=[]
|
222 | i.forEachReverse(({key:t,value:n,size:r,expireAt:o})=>e.push({key:t,value:n,size:r,expireAt:o}))
|
223 | return e},parseList:(e,t=Date.now())=>e.forEach(({key:e,value:n,size:r,expireAt:o})=>{const s=Q(e,n,r,o)
|
224 | s.expireAt<=t?p(s):u(s)})}}
|
225 | const Z=Number.isInteger
|
226 | const K=e=>"object"==typeof e&&null!==e&&!Array.isArray(e)
|
227 | const Y=Array.isArray
|
228 | const X=e=>{const t=typeof e
|
229 | let n
|
230 | if("function"===t)n="()=>{...}"
|
231 | else try{n=JSON.stringify(e)}catch(e){n="{...}"}return`<${t}> ${n}`}
|
232 | const ee=(e,t,n)=>{throw new Error(`[verify|${e}]${t?` ${t};`:""} ${n}`)}
|
233 | const te=(e,t)=>(n,r)=>t(n)||ee(e,r,`get: ${X(n)}`)
|
234 | const ne=te("String",e=>"string"==typeof e)
|
235 | const re=te("Number",e=>"number"==typeof e)
|
236 | const oe=te("Integer",Z)
|
237 | te("BasicObject",K)
|
238 | te("Array",Y)
|
239 | const se=(e,t,n)=>((e,t)=>Y(e)&&e.length===t)(e,t)||ee("ArrayLength",n,`expect length: ${t}, get: ${e.length}`)
|
240 | const ae=te("Function",e=>"function"==typeof e)
|
241 | var ie=n(4)
|
242 | const ce=e=>{if(e.response.finished)return e
|
243 | const{error:t}=e.getState()
|
244 | !e.response.headersSent&&e.response.writeHead(t?500:400)
|
245 | e.response.end()}
|
246 | const ue=({url:e,method:t,headers:{host:n=""},socket:{remoteAddress:r,remotePort:o}})=>`[${t}] ${n}${e} (${r}:${o})`
|
247 | const pe=e=>t=>{const{time:n,error:r}=t.getState()
|
248 | e(ue(t.request),"|",r?"[ERROR]":"[END]",(e=>{const t=.75*Math.abs(e)
|
249 | return t<1e3?`${Math.floor(e)}ms`:t<6e4?`${(e/1e3).toFixed(2)}s`:t<36e5?`${(e/6e4).toFixed(2)}m`:t<864e5?`${(e/36e5).toFixed(2)}h`:`${(e/864e5).toFixed(2)}d`})(q()-n),t.response.statusCode,r?r.stack||r:"")}
|
250 | const le={protocol:"https:",hostname:"localhost",port:443,isSecure:!0,secureOptions:M.constants.SSL_OP_NO_SSLv3|M.constants.SSL_OP_NO_SSLv2}
|
251 | const de={protocol:"http:",hostname:"localhost",port:80,isSecure:!1}
|
252 | const ge=new Set([le.protocol,de.protocol])
|
253 | const he=ce
|
254 | const me=async({protocol:e="http:",hostname:t="localhost",port:n,fileSSLKey:r,fileSSLCert:o,fileSSLChain:s,fileSSLDHParam:a})=>{const i="https:"===e
|
255 | return(({protocol:e,...t})=>{if(!ge.has(e))throw new Error(`[createServer] invalid protocol: ${e}`);(t={..."https:"===e?le:de,...t}).baseUrl=`${e}//${t.hostname}:${t.port}`
|
256 | const n=t.isSecure?Object(_.createServer)(t):Object(F.createServer)()
|
257 | t.isSecure&&(e=>{const t=W({valueSizeSumMax:4096})
|
258 | e.on("newSession",(e,n,r)=>{t.set(e.toString("hex"),n,1,Date.now()+6e5)
|
259 | r()})
|
260 | e.on("resumeSession",(e,n)=>{n(null,t.get(e.toString("hex"))||null)})})(n)
|
261 | return{server:n,option:t,start:()=>{!n.listening&&n.listen(t.port,t.hostname)},stop:()=>{n.listening&&n.close()}}})({protocol:e,hostname:t,port:n,key:i&&r?await u(r):null,cert:i&&o?await u(o):null,ca:i&&s?await u(s):null,dhparam:i&&a?await u(a):null})}
|
262 | var fe=n(5)
|
263 | const Se="application/octet-stream"
|
264 | const we=["application/javascript;js;mjs","application/json","application/pdf","application/xml","audio/midi;mid","audio/mpeg;mp3","audio/ogg","audio/wav","audio/webm;weba","audio/x-flac;flac","font/ttf","font/otf","font/woff","font/woff2","image/bmp","image/gif","image/jpeg;jpg","image/png","image/svg+xml;svg","image/webp","image/x-icon;ico","text/css","text/csv","text/html;htm","text/plain;txt;text;conf;log;ini","text/rtf","text/xml","video/mp4;mp4v;mpg4","video/mpeg;mpg","video/webm","video/x-flv;flv","video/x-ms-wmv;wmv","video/x-msvideo;avi"].reduce((e,t)=>{const[n]=t.split(";")
|
265 | t.split("/")[1].split(";").forEach(t=>e[t]=n)
|
266 | return e},{})
|
267 | const ye=e=>new Promise((t,n)=>{const r=[]
|
268 | e.on("error",n)
|
269 | e.on("data",e=>r.push(e))
|
270 | e.on("end",()=>{e.removeListener("error",n)
|
271 | t(Buffer.concat(r))})})
|
272 | const be=(e,t)=>new Promise((n,r)=>{e.on("error",r)
|
273 | e.write(t,()=>{e.removeListener("error",r)
|
274 | n()})})
|
275 | n(11)
|
276 | const ve=Object(s.promisify)(fe.gzip)
|
277 | const ke=(e,t,n,r)=>{t&&e.response.setHeader("etag",t)
|
278 | const o=!t||!e.request.headers["if-none-match"]||!e.request.headers["if-none-match"].includes(t)
|
279 | o?e.response.writeHead(200,{"content-type":n,"content-length":r}):e.response.writeHead(304,{"content-type":n})
|
280 | return o}
|
281 | const xe=async(e,{buffer:t,bufferGzip:n,entityTag:r,type:o=Se,length:s=t.length})=>{r&&e.response.setHeader("etag",r)
|
282 | const a=!r||!e.request.headers["if-none-match"]||!e.request.headers["if-none-match"].includes(r)
|
283 | const i=a&&s&&e.request.headers["accept-encoding"]&&e.request.headers["accept-encoding"].includes("gzip")
|
284 | const c=i?n||await ve(t):t
|
285 | a?e.response.writeHead(200,i?{"content-type":o,"content-length":c.length,"content-encoding":"gzip"}:{"content-type":o,"content-length":s}):e.response.writeHead(304,{"content-type":o})
|
286 | return a&&s&&be(e.response,c)}
|
287 | const Te=(e,{object:t,entityTag:n})=>xe(e,{buffer:Buffer.from(JSON.stringify(t)),type:we.json,entityTag:n})
|
288 | const Oe=(e,t)=>({type:t,buffer:e,bufferGzip:Object(fe.gzipSync)(e),entityTag:(e=>`"${e.length.toString(16)}-${Object(M.createHash)("sha1").update(e).digest("base64")}"`)(e),length:e.length})
|
289 | const $e=(e,t,n)=>K(t)&&e.unshift(...Object.entries(t).map(([e,t],r)=>[e,t,r,n]))
|
290 | const Le=(e,t)=>void 0===e[t]?e[t]={}:e[t]
|
291 | const Ee=(e,t)=>{const n=[]
|
292 | return{routeNode:e=t.split("/").reduce((e,r)=>{if("*"===r){n.push("/*")
|
293 | return Le(e,"/*")}if(":"===r[0]){const o=r.slice(1)
|
294 | if(!o||n.includes(o))throw new Error(`[parseRouteToMap] invalid frag [${r}] for route: ${t}`)
|
295 | n.push(o)
|
296 | return Le(e,"/:PARAM")}return Le(e,r)},e),paramNameList:n}}
|
297 | const Ne=(e,t)=>{const n=[]
|
298 | const r=t.split("/")
|
299 | for(let o=0,s=r.length;o<s;o++){const s=r[o]
|
300 | if(e[s])e=e[s]
|
301 | else{if(!e["/:PARAM"]){if(e["/*"]){n.push(r.slice(o).join("/"))
|
302 | e=e["/*"]
|
303 | break}throw new Error(`[findRouteFromMap] stuck at [${s}] for route: ${t}`)}n.push(s)
|
304 | e=e["/:PARAM"]}}return{routeNode:e,paramValueList:n}}
|
305 | const Ae=(e=[],t=[])=>["<!DOCTYPE html>","<html>","<head>",'<meta charset="utf-8">','<meta name="viewport" content="minimum-scale=1, width=device-width">',...e,"</head>","<body>",...t,"</body>","</html>"].join("\n")
|
306 | const Pe=(e,t)=>{const n=document.querySelector(e)
|
307 | n&&"string"==typeof t&&(n.innerHTML=t)
|
308 | return n}
|
309 | const Re=e=>[...document.querySelectorAll(e)]
|
310 | const je=(e,t={},n=[])=>{const r=Object.assign(document.createElement(e),t)
|
311 | n.forEach(e=>e&&r.appendChild(e))
|
312 | return r}
|
313 | const Ce=(e,t=[])=>t.forEach(t=>t&&e.appendChild(t))
|
314 | const De=(e,t,...n)=>e.classList[t?"add":"remove"](...n)
|
315 | const Ie=(e,t,n,r="")=>e[t?"setAttribute":"removeAttribute"](n,r)
|
316 | const Me=()=>"complete"===document.readyState
|
317 | const Fe=e=>{if(window.iDR())return e()
|
318 | const t=()=>{if(window.iDR()){document.removeEventListener("readystatechange",t)
|
319 | e()}}
|
320 | document.addEventListener("readystatechange",t)}
|
321 | const _e={GET:"/GET",POST:"/POST",PUT:"/PUT",PATCH:"/PATCH",DELETE:"/DELETE",HEAD:"/HEAD",OPTIONS:"/OPTIONS",CONNECT:"/CONNECT",TRACE:"/TRACE"}
|
322 | const ze=(e,t="/",n="GET",r)=>{if(Array.isArray(t))return t.reduce((t,o)=>ze(e,o,n,r),e)
|
323 | if(Array.isArray(n))return n.reduce((n,o)=>ze(e,t,o,r),e)
|
324 | const{routeNode:o,paramNameList:s}=Ee(e,t)
|
325 | if(!_e[n])throw new Error(`[appendRouteMap] invalid method [${n}] for route: ${t}`)
|
326 | if(o[_e[n]])throw new Error(`[appendRouteMap] duplicate method [${n}] for route: ${t}`)
|
327 | if("function"!=typeof r)throw new Error(`[appendRouteMap] invalid routeResponder for route: ${t}`)
|
328 | o[_e[n]]={route:t,paramNameList:s,routeResponder:r}
|
329 | return e}
|
330 | const Ue=(e,t)=>(({paramMap:e},t)=>e[t])(e.getState(),t)
|
331 | const qe=e=>{const t=[]
|
332 | const n=new Set(Object.values(_e));((e,t)=>{const n=[]
|
333 | $e(n,e,0)
|
334 | for(;n.length;){const[e,r,o,s]=n.shift()
|
335 | if(t(r,e,o,s))return{value:r,key:e,index:o,level:s}
|
336 | $e(n,r,s+1)}})(e,(e,r)=>{n.has(r)&&t.push({method:r,route:e.route})})
|
337 | return t}
|
338 | const Je=(e,t=[])=>Ae(["<style>\n*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; outline-color: #f00; }\n::-webkit-scrollbar-thumb { background: #0004; }\n::-webkit-scrollbar-thumb:hover { background: #0006; }\nbody { overflow: hidden; display: flex; flex-flow: column; width: 100vw; height: 100vh; font-family: monospace; font-size: 16px; }\nbutton, .button { text-decoration: none; cursor: pointer; margin: 4px; padding: 4px; min-width: 32px; border: 0; border-radius: 4px; background: hsla(0, 0%, 70%, 0.4); box-shadow: inset 0 0 0 1px #888; }\nbutton:hover, .button:hover { background: hsla(0, 0%, 80%, 0.4); box-shadow: inset 0 0 0 1px #aaa; }\nbutton.select, button:hover.select, .button.select, .button:hover.select { color: #e00; box-shadow: inset 0 0 0 1px #e00; }\nbutton:disabled, button:disabled:hover, .button:disabled, .button:disabled:hover { cursor: default; background: hsla(0, 0%, 100%, 0.4); box-shadow: unset; }\n@media (pointer: fine) {\n ::-webkit-scrollbar { width: 14px; height: 14px; }\n button, .button, .auto-height { min-height: 20px; font-size: 14px; } \n}\n@media (pointer: coarse) {\n ::-webkit-scrollbar { width: 6px; height: 6px; }\n button, .button, .auto-height { min-height: 32px; font-size: 18px; } \n}\n</style>","<style>body { overflow: auto; align-items: start; }</style>"],["<h2>Route List</h2>","<table>",...qe(e).map(({method:e,route:t})=>`<tr><td><b>${e}</b></td><td>${"/GET"===e?`<a href="${t}">${t}</a>`:t}</td></tr>`),"</table>",...t])
|
339 | const Ge=(e,t)=>{const n=[]
|
340 | for(let r=0;r<t;r++)n.push(e(r))
|
341 | return n}
|
342 | const He=(e=0,t=!0)=>({A:()=>e,B:()=>++e,C:()=>--e,D:()=>t,E:()=>t=!1})
|
343 | const Be=(e=(e=>{}))=>{let t=He()
|
344 | let n=Promise.resolve("QUEUE_HEAD")
|
345 | return{reset:()=>{t.E()
|
346 | t=He()
|
347 | n=Promise.resolve("QUEUE_HEAD")},getLength:()=>t.A(),pushTask:r=>{const{promise:o,resolve:s}=(()=>{let e,t
|
348 | return{promise:new Promise((n,r)=>{e=n
|
349 | t=r}),resolve:n=>{const r=e
|
350 | e=t=void 0
|
351 | r&&r(n)},reject:n=>{const r=t
|
352 | e=t=void 0
|
353 | r&&r(n)}}})()
|
354 | const a=n.then(r)
|
355 | a.catch(e).then(()=>{t.C()
|
356 | t.D()&&s()})
|
357 | t.B()
|
358 | n=o
|
359 | return a}}}
|
360 | const Ve=({clearRunner:e=(()=>{}),resetRunner:t=((e,t)=>{}),getTaskId:n,getTaskInitialState:r=(e=>e),runTask:o})=>{const{reset:s,getLength:a,pushTask:i}=Be()
|
361 | const c=new Map
|
362 | const u=e=>c.get(e)
|
363 | const p=(e,t)=>{const n=u(e)
|
364 | n&&c.set(e,{...n,...t})}
|
365 | const l=e=>c.delete(e)
|
366 | return{clear:()=>{s()
|
367 | c.clear()
|
368 | return e()},getStatus:e=>({taskQueue:a(),taskStateMap:c.size,taskStateList:e?Array.from(c.entries()):void 0}),getQueueLength:a,getTaskState:u,startTask:e=>{const s=n(e)
|
369 | return c.get(s)||((e,n)=>{const s=i(()=>o(e,{getTaskState:u,updateTaskState:p})).then(t=>p(e,{result:t,promise:null,endAt:J()})).catch(n=>{p(e,{error:n,promise:null,endAt:J()})
|
370 | return t(n,e)})
|
371 | const a=r({id:e,option:n,promise:s,error:null,result:null,startAt:J(),endAt:null})
|
372 | c.set(e,a)
|
373 | return a})(s,e)},endTask:l,autoEndTask:e=>{const t=J()-Math.abs(e)
|
374 | c.forEach((e,n)=>{e.endAt&&e.endAt<=t&&l(n)})}}}
|
375 | const Qe=({runnerList:e=[],getRunnerByTaskId:t,selectRunner:n=We})=>({clear:()=>e.map(e=>e.clear()),getStatus:t=>e.map(e=>e.getStatus(t)),getQueueLength:()=>e.map(e=>e.getQueueLength()),getTaskState:n=>{const r=t(e,n)
|
376 | return r&&r.getTaskState(n)},startTask:t=>n(e,t).startTask(t),endTask:n=>{const r=t(e,n)
|
377 | return r&&r.endTask(n)},autoEndTask:t=>e.forEach(e=>e.autoEndTask(t))})
|
378 | const We=e=>e.reduce((e,t)=>e.getQueueLength()>t.getQueueLength()?t:e,e[0])
|
379 | const Ze=({protocol:e,hostname:t,hash:n,search:r,pathname:o,href:s,port:a,username:i,password:c})=>{const u={protocol:e,hostname:t,hash:n,search:r,pathname:o,href:s,path:`${o}${r}`}
|
380 | ""!==a&&(u.port=Number(a));(i||c)&&(u.auth=`${i}:${c}`)
|
381 | return u}
|
382 | const Ke=(e,t=null)=>new Promise((n,r)=>{const o=("https:"===e.protocol?_.request:F.request)(e,n)
|
383 | const s=t=>{o.destroy()
|
384 | t.option=e
|
385 | r(t)}
|
386 | o.on("timeout",()=>s(new Error("NETWORK_TIMEOUT")))
|
387 | o.on("error",s)
|
388 | o.end(t)})
|
389 | const Ye=async({url:e,body:t,wait:n=5e3,maxRetry:r=0,...o})=>{o={...o,...Ze(new ie.URL(e)),timeout:n}
|
390 | await(async(e,t=1/0,n=0)=>{let r=0
|
391 | for(;;){const o=q()
|
392 | try{return await e(r,t)}catch(e){if(t<++r)throw e
|
393 | const s=n-(q()-o)
|
394 | s>0&&await G(s)}}})(async()=>{(await Ke(o,t)).destroy()},r,n)}
|
395 | const Xe=async(e,{method:t="GET",headers:n,body:r,timeout:o=1e4}={})=>{const s={...Ze(new ie.URL(e)),method:t,headers:{"accept-encoding":"gzip",...n},timeout:o}
|
396 | const a=await Ke(s,r)
|
397 | const i=a.headers
|
398 | const c=a.statusCode
|
399 | const u=c>=200&&c<300
|
400 | let p=!1
|
401 | let l
|
402 | process.nextTick(()=>{if(!l){a.destroy()
|
403 | p=!0}})
|
404 | const d=async()=>{if(void 0===l){if(p)throw new Error("PAYLOAD_ALREADY_DROPPED")
|
405 | let e=!1
|
406 | let t=!1
|
407 | o&&setTimeout(()=>{if(!t){a.destroy()
|
408 | e=!0}},o)
|
409 | l=ye("gzip"===a.headers["content-encoding"]?a.pipe(Object(fe.createGunzip)()):a).then(n=>{if(e)throw new Error("PAYLOAD_TIMEOUT")
|
410 | t=!0
|
411 | return n})}return l}
|
412 | const g=()=>d().then(e=>e.toString())
|
413 | return{headers:i,status:c,ok:u,buffer:d,text:g,json:()=>g().then(e=>JSON.parse(e))}}
|
414 | var et=n(8)
|
415 | const tt=Object.entries({addSnapShotTask:"({ projectCid, canvasZoom, canvasClip, taskList }) => {\n window.SNAPSHOT_CONTROL.addSnapShotTask({ projectCid, canvasZoom, canvasClip, taskList })\n}",checkReady:"() => {\n const { isReady } = window.SNAPSHOT_CONTROL.getState()\n return isReady\n}",checkWait:"() => {\n const { isReady, isWait } = window.SNAPSHOT_CONTROL.getState()\n return isReady && isWait\n}",getTaskResult:"() => {\n const { state } = window.SNAPSHOT_CONTROL.getState()\n return state\n}",sendResume:"() => {\n window.SNAPSHOT_CONTROL.resume()\n}",sendReset:"() => {\n window.SNAPSHOT_CONTROL.resetTaskQueue()\n window.SNAPSHOT_CONTROL.resume()\n}"}).reduce((e,[t,n])=>{e[t]=Object.assign(()=>{},{toString:()=>n})
|
416 | return e},{})
|
417 | const nt={timeout:1e4}
|
418 | const rt=()=>{process.exit(-1)}
|
419 | const ot={timeout:1e4}
|
420 | const st=e=>Object(M.createHash)("sha1").update(JSON.stringify(e),"utf8").digest("base64").replace(/\W/g,"")
|
421 | const at=async({clusterSize:e,logger:t,urlSnapshotApp:n,urlServerPingTest:o})=>{const s=await(async({logger:e})=>{e.add("[Puppeteer|Browser] init")
|
422 | const t=Object(et.a)("puppeteer")
|
423 | if(!t){const t=new Error("[Puppeteer] failed to load package puppeteer, check peerDependency")
|
424 | e.add(t)
|
425 | throw t}const n=await t.launch({args:["--no-sandbox"],headless:!0,handleSIGHUP:!1,handleSIGINT:!1,handleSIGTERM:!1})
|
426 | n.addListener("disconnected",rt)
|
427 | e.add("[Puppeteer|Browser] init complete")
|
428 | return n})({logger:t})
|
429 | C(async()=>s&&(({puppeteerBrowser:e})=>{e.removeListener("disconnected",rt)
|
430 | return e.close().catch(e=>{})})({puppeteerBrowser:s}))
|
431 | const a=Ge(e=>{let a=null
|
432 | const i=(e,n)=>{e&&t.add(`[Puppeteer|${n}] error: ${e.stack||e.toString()}`)
|
433 | return a&&(({puppeteerPage:e})=>e.close().catch(e=>{}))({puppeteerPage:a}).then(()=>{a=null})}
|
434 | return Ve({clearRunner:i,resetRunner:i,getTaskInitialState:e=>({...e,progress:0}),runTask:async(e,{getTaskState:i,updateTaskState:c})=>{a||(a=await(async({puppeteerBrowser:e,logger:t})=>{t.add("[Puppeteer|Page] init start")
|
435 | const n=await e.newPage()
|
436 | n.on("error",e=>t.add("[Puppeteer|Page] error:",e))
|
437 | n.on("pageerror",e=>t.add("[Puppeteer|Page] pageerror:",e))
|
438 | n.on("requestfailed",e=>t.add("[Puppeteer|Page] requestfailed:",{url:e.url(),method:e.method()}))
|
439 | n.on("console",e=>t.add("[Puppeteer|Page] console:",e.type(),e.text()))
|
440 | t.add("[Puppeteer|Page] init complete")
|
441 | return n})({puppeteerBrowser:s,logger:t}))
|
442 | t.add(`[Puppeteer|${e}] start`)
|
443 | await Ye({url:o,wait:2e3,maxRetry:4})
|
444 | a.url().includes(n)||await(async({urlSnapshotApp:e,puppeteerPage:t,logger:n})=>{n.add("[Puppeteer|Page] setup start")
|
445 | await t.goto(e,{waitUntil:"networkidle2",...nt})
|
446 | await t.setUserAgent("Phantom WebKit")
|
447 | await t.setViewport({width:0,height:0})
|
448 | await t.waitForFunction(tt.checkReady,nt)
|
449 | n.add("[Puppeteer|Page] setup ready")})({urlSnapshotApp:n,puppeteerPage:a,logger:t})
|
450 | const{option:u}=i(e)
|
451 | const p=await(async({option:e,puppeteerPage:t,stepCallback:n,logger:o})=>{const{projectCid:s,canvasZoom:a,canvasClip:i,taskList:c,pathOutput:u}=e
|
452 | c.forEach(e=>e.screenStateCid=e.screenStateCid||"default")
|
453 | await t.waitForFunction(tt.checkReady,ot)
|
454 | await t.evaluate(tt.addSnapShotTask,{projectCid:s,canvasZoom:a,canvasClip:i,taskList:c})
|
455 | const p=[]
|
456 | const l=c.length
|
457 | for(let e=0;e<l;e++){const s=async()=>{o.add(`[snapshot|${e+1}/${l}] wait for puppeteerPage render`)
|
458 | await t.waitForFunction(tt.checkWait,ot)
|
459 | const{canvasData:s,error:d}=await t.evaluate(tt.getTaskResult)
|
460 | if(d||!s){o.add(`[snapshot|${e+1}/${l}] error: ${d}, canvasData: ${JSON.stringify(s)}`)
|
461 | await t.evaluate(tt.sendReset)
|
462 | throw d}const{screenCid:g,screenStateCid:h,canvasWidth:m,canvasHeight:f}=s
|
463 | const S=c.find(e=>e.screenCid===g&&e.screenStateCid===h)
|
464 | if(!S)throw new Error(`[snapshot] error getting task: ${JSON.stringify({taskList:c,canvasData:s})}`)
|
465 | const{fileName:w}=S
|
466 | const y={x:0,y:0,width:m,height:f,...i}
|
467 | const b=Object(r.join)(u,w||`${g}-${h}_${a}_${y.width}_${y.height}.png`)
|
468 | await t.screenshot({path:b,clip:y,omitBackground:!0,type:"png"})
|
469 | await t.evaluate(tt.sendResume)
|
470 | p.push({screenCid:g,screenStateCid:h,canvasZoom:a,canvasClip:i,fileName:w,filePath:b})
|
471 | n({progress:Math.round(100*(e+1)/l)})
|
472 | o.add(`[snapshot|${e+1}/${l}] file ready: ${b}`)}
|
473 | await Promise.race([s(),new Promise((e,t)=>setTimeout(()=>t(new Error("[TIMEOUT] snapshot task timeout after 20000")),2e4))])}return p})({option:u,puppeteerPage:a,stepCallback:({progress:t})=>c(e,{progress:t}),logger:{...t,add:(e=>{let t=Date.now()
|
474 | return(...n)=>{const r=Date.now()
|
475 | e(`[+${r-t}ms]`,...n)
|
476 | t=r}})(t.add)}})
|
477 | t.add(`[Puppeteer|${e}] complete`)
|
478 | return p},getTaskId:t=>`TSS-${e.toString(36)}-${st(t)}`})},e)
|
479 | return Qe({runnerList:a,getRunnerByTaskId:(e,t)=>{const n=t&&/^TSS-(\d+)-/.exec(t)
|
480 | return n&&e[parseInt(n[1],36)]}})}
|
481 | const it=(e,t)=>Math.floor(Math.random()*(t-e+1)+e);(()=>{try{const{crypto:e}=global
|
482 | const t=t=>{const n=new ArrayBuffer(t)
|
483 | for(let r=0;r<t;r+=65536)e.getRandomValues(new Uint8Array(n,r,Math.min(65536,t-r)))
|
484 | return n}
|
485 | if(32===t(32).byteLength)return t}catch(e){}try{const{randomFillSync:e}=Object(et.a)("crypto")
|
486 | const t=t=>{const n=new DataView(new ArrayBuffer(t))
|
487 | e(n)
|
488 | return n.buffer}
|
489 | if(32===t(32).byteLength)return t}catch(e){}})()
|
490 | const ct=({clusterSize:e,logger:t})=>{const n=(e,n)=>e&&t.add(`[DebugTaskRunner|${n}] error: ${e.stack||e.toString()}`)
|
491 | const r=async(e,{getTaskState:n,updateTaskState:r})=>{t.add(`[DebugTaskRunner|${e}] start`,JSON.stringify(n(e).option))
|
492 | for(let n=0,o=((e,t=0)=>it(Math.min(e,t),Math.max(e,t)))(5,10);n<o;n++){await G(500)
|
493 | t.add(`[DebugTaskRunner|${e}] step [${n}/${o}]`)
|
494 | if(8===o&&4===n)throw new Error("[DebugError] predefined error at 4 of 8")
|
495 | r(e,{progress:Math.round(100*(n+1)/o)})}t.add(`[DebugTaskRunner|${e}] complete`)
|
496 | return{output:"DebugTaskRunner"}}
|
497 | const o=Ge(e=>Ve({resetRunner:n,runTask:r,getTaskId:t=>`TASK-DEBUG-${e.toString(36)}-${st(t)}`}),e)
|
498 | return Qe({runnerList:o,getRunnerByTaskId:(e,t)=>{const n=t&&/^TASK-DEBUG-(\d+)-/.exec(t)
|
499 | return n&&e[parseInt(n[1],36)]}})}
|
500 | const ut=async(e,t)=>{void 0===t&&(t=await w(e))
|
501 | if(!t.isDirectory())throw new Error(`[getDirectorySubInfoList] error pathType: ${y(t)} for ${e}`)
|
502 | const n=[]
|
503 | for(const t of await c(e)){const o=Object(r.join)(e,t)
|
504 | const s=await w(o)
|
505 | const a=y(s)
|
506 | n.push({path:o,name:t,stat:s,type:a})}return n}
|
507 | const pt=Object(s.promisify)(o.utimes)
|
508 | const lt=Object(s.promisify)(o.unlink)
|
509 | const dt=["thumbnail","zoom-0.50","zoom-1.00","zoom-2.00"]
|
510 | const gt=async(e,t)=>{for(const{path:n,name:r}of await ut(e))r.startsWith(t)&&await lt(n)}
|
511 | const ht=async(e,t,n,o)=>(async({option:e,taskRunnerCluster:t,logger:n})=>{const{taskList:[{fileName:o,fileNamePrefix:s}],pathOutput:a,routeOutput:i}=e
|
512 | const c=await w(a)
|
513 | const u=Object(r.join)(a,o)
|
514 | if(c.isDirectory()&&(await w(u)).isFile()){n.add(`[Task|sync] exist: ${o}`)
|
515 | const e=J()
|
516 | await pt(u,e,e)}else{c.isDirectory()?await gt(a,s).catch(e=>n.add(`[ERROR|Task|sync] delete expired file error: ${e.stack}`)):await b(a,c)
|
517 | n.add(`[Task|sync] start: ${JSON.stringify(e)}`)
|
518 | const{id:r,promise:o}=t.startTask(e)
|
519 | o&&await o
|
520 | const{error:i}=t.getTaskState(r)
|
521 | if(i)throw i}n.add(`[Task|sync] end: ${o}`)
|
522 | return{pathFile:u,routeFile:Object(r.join)("/",i,o)}})({option:await(async(e,t,n)=>{const r=e.get("mode")||"thumbnail"
|
523 | if(!dt.includes(r))throw new Error(`[fetchSyncTaskConfig] invalid mode: ${r}`)
|
524 | const o=`${n}?${new ie.URLSearchParams({mode:r,access_token:e.get("access-token"),screen_cid:e.get("screen-cid"),screenstate_cid:e.get("screenstate-cid")||"default"})}`
|
525 | const s=await Xe(o,{method:"GET",headers:{cookie:t.cookie||""}})
|
526 | if(!s.ok)throw new Error(`[fetchSyncTaskConfig] fetch failed, url: ${o}, status: ${s.status}`)
|
527 | const a=await s.json()
|
528 | if(a.taskList&&1!==a.taskList.length)throw new Error("expect to get single task taskList")
|
529 | return a})(e.getState().url.searchParams,e.request.headers,t),taskRunnerCluster:n,logger:o})
|
530 | const mt=({logger:e,urlSnapshotTask:t,taskRunnerCluster:n})=>{return{responderStartTask:(t,r)=>{const o=n.startTask(r)
|
531 | e.add(`[Task|start] ${o.id}`)
|
532 | return Te(t,{object:{taskId:o.id}})},responderDeleteTask:(t,r)=>{n.endTask(r)
|
533 | e.add(`[Task|delete] ${r}`)
|
534 | return ce(t)},responderGetTaskStatus:(t,r)=>{const o=n.getTaskState(r)
|
535 | if(!o)return Te(t,{object:{}})
|
536 | const{error:s,progress:a=1}=o
|
537 | const i={taskId:r,error:s&&s.toString(),progress:a}
|
538 | e.add(`[Task|status] ${JSON.stringify(i)}`)
|
539 | return Te(t,{object:i})},responderSyncSnapshotTaskNginx:async r=>{const{routeFile:o}=await ht(r,t,n,e)
|
540 | return((e,{statusCode:t=500,headerMap:n})=>{if(e.response.finished)return e
|
541 | !e.response.headersSent&&e.response.writeHead(t,n)
|
542 | e.response.end()})(r,{statusCode:200,headerMap:{"x-accel-redirect":encodeURI(o)}})},responderSyncSnapshotTaskServe:async r=>{const{pathFile:o}=await ht(r,t,n,e)
|
543 | r.response.setHeader("access-control-allow-origin","*")
|
544 | return((e,{buffer:t,entityTag:n,type:r=Se,length:o=t.length})=>ke(e,n,r,o)&&o&&be(e.response,t))(r,{buffer:await u(o),type:we.png})}}}
|
545 | const ft=()=>{const e=Oe(Buffer.from(Ae(["<style>\n*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; outline-color: #f00; }\n::-webkit-scrollbar-thumb { background: #0004; }\n::-webkit-scrollbar-thumb:hover { background: #0006; }\nbody { overflow: hidden; display: flex; flex-flow: column; width: 100vw; height: 100vh; font-family: monospace; font-size: 16px; }\nbutton, .button { text-decoration: none; cursor: pointer; margin: 4px; padding: 4px; min-width: 32px; border: 0; border-radius: 4px; background: hsla(0, 0%, 70%, 0.4); box-shadow: inset 0 0 0 1px #888; }\nbutton:hover, .button:hover { background: hsla(0, 0%, 80%, 0.4); box-shadow: inset 0 0 0 1px #aaa; }\nbutton.select, button:hover.select, .button.select, .button:hover.select { color: #e00; box-shadow: inset 0 0 0 1px #e00; }\nbutton:disabled, button:disabled:hover, .button:disabled, .button:disabled:hover { cursor: default; background: hsla(0, 0%, 100%, 0.4); box-shadow: unset; }\n@media (pointer: fine) {\n ::-webkit-scrollbar { width: 14px; height: 14px; }\n button, .button, .auto-height { min-height: 20px; font-size: 14px; } \n}\n@media (pointer: coarse) {\n ::-webkit-scrollbar { width: 6px; height: 6px; }\n button, .button, .auto-height { min-height: 32px; font-size: 18px; } \n}\n</style>",(e=>{const t={}
|
546 | const n=[]
|
547 | Object.entries({qS:Pe,qSA:Re,cE:je,aCL:Ce,mECN:De,mEA:Ie,iDR:Me,tDR:Fe,...e}).forEach(([e,r])=>{"function"==typeof r?n.push(`<script>window[${JSON.stringify(e)}] = ${r.toString()}<\/script>`):t[e]=r})
|
548 | return[`<script>Object.assign(window, ${JSON.stringify(t)})<\/script>`,...n].join("\n")})({onload:wt})],[St])),we.html)
|
549 | return t=>xe(t,e)}
|
550 | const St='\n<div style="flex-flow: row;">\n <button onclick="getStatus()">getStatus</button>\n <button onclick="getStatusDetail()">getStatusDetail</button>\n <button onclick="startDebugTask()">startDebugTask</button>\n <button onclick="startDebugTask10()">startDebugTask10</button>\n <button onclick="startDebugSyncTask()">startDebugSyncTask</button>\n <button onclick="resetLog()">resetLog</button>\n</div>\n<pre style="display: flex; flex-flow: row; font-size: 12px;">\n <div id="status" style="overflow: auto; border-right: 2px solid #eee; font-size: 8px;">STATUS</div>\n <div id="log" style="overflow: auto;">LOG</div>\n</pre>\n'
|
551 | const wt=()=>{const{fetch:e,performance:t,qS:n}=window
|
552 | const r=e=>{console.log("[STATUS]",e)
|
553 | n("#status",JSON.stringify(e,null," "))}
|
554 | const o=e=>{console.log("[LOG]",e)
|
555 | n("#log").innerHTML+=`\n${e}`}
|
556 | const s=async()=>{const n=await(await e("/task",{method:"POST",body:JSON.stringify(t.now().toString(36))})).text()
|
557 | o(` - [Task] ${n}`)}
|
558 | Object.assign(window,{resetLog:()=>{n("#log","LOG")},getStatus:async()=>{r(await(await e("/status",{method:"GET"})).json())},getStatusDetail:async()=>{r(await(await e("/status?verbose",{method:"GET"})).json())},startDebugTask:s,startDebugTask10:()=>{for(let e=0;e<10;e++)s().catch(console.warn)},startDebugSyncTask:async()=>{const n=`[SYNC]${t.now().toString(36)}`
|
559 | o(`[SyncTask|${n}] start`)
|
560 | const r=await(await e("/debug-sync-task",{method:"POST",body:JSON.stringify(n)})).text()
|
561 | o(`[SyncTask|${n}] end: ${r}`)}})}
|
562 | const yt=async({option:e,logger:t,routePrefix:n="",clusterSize:r,urlSnapshotApp:o,urlServerPingTest:s,urlSnapshotTask:a,isTaskRunnerDebugOnly:i})=>{const c=`${n}/task`
|
563 | const u=`${n}/nginx-sync-snapshot`
|
564 | const p=`${n}/debug-sync-snapshot`
|
565 | const l=await(i?ct:at)({clusterSize:r,logger:t,urlSnapshotApp:o,urlServerPingTest:s})
|
566 | const d=setInterval(()=>l.autoEndTask(30),3e4)
|
567 | j(()=>clearInterval(d))
|
568 | C(async()=>Promise.all([].concat(l.clear())))
|
569 | const{responderStartTask:g,responderDeleteTask:h,responderGetTaskStatus:m,responderSyncSnapshotTaskNginx:f,responderSyncSnapshotTaskServe:S}=mt({logger:t,urlSnapshotTask:a,taskRunnerCluster:l})
|
570 | const w=[[c,"POST",async e=>g(e,JSON.parse(await ye(e.request)))],[`${c}/:task-id`,"GET",e=>m(e,Ue(e,"task-id"))],[`${c}/:task-id`,"DELETE",e=>h(e,Ue(e,"task-id"))],[[u,`${u}.png`],"GET",f],[[p,`${p}.png`],"GET",S]]
|
571 | if(i){const e=`${n}/debug`
|
572 | const r=`${n}/debug-sync-task`
|
573 | const o=((e,t)=>async(n,r)=>{t.add(`[Task|sync] start: ${JSON.stringify(r)}`)
|
574 | const{id:o,promise:s}=e.startTask(r)
|
575 | s&&await s
|
576 | const{error:a,progress:i=1}=e.getTaskState(o)
|
577 | const c={taskId:o,error:a&&a.toString(),progress:i}
|
578 | t.add(`[Task|sync] end: ${JSON.stringify(c)}`)
|
579 | return Te(n,{object:c})})(l,t)
|
580 | w.push([e,"GET",ft()],[r,"POST",async e=>o(e,JSON.parse(await ye(e.request)))])}return{URL_TASK:c,URL_SYNC_SNAPSHOT_NGINX:u,URL_SYNC_SNAPSHOT_SERVE:p,routeList:w,taskRunnerCluster:l,getTaskRunnerClusterStatus:({isVerbose:e,isRaw:t})=>{const n=l.getStatus(e)
|
581 | return t?n:e?n.map(({taskQueue:e,taskStateMap:t,taskStateList:n})=>({taskQueue:e,taskStateMap:t,taskStateList:n.map(([e,t])=>`[${t.error||`${t.progress||0}%`}] ${e}`)})):n.map(({taskQueue:e,taskStateMap:t})=>`${e}|${t}`)}}}
|
582 | const bt=async({urlServerPingTest:e,urlSnapshotApp:t,urlSnapshotTask:n,taskRunnerCount:r,isTaskRunnerDebugOnly:o},{server:s,option:a,logger:i})=>{const{routeList:c,getTaskRunnerClusterStatus:u}=await yt({option:a,logger:i,routePrefix:"",clusterSize:r,urlSnapshotApp:t,urlServerPingTest:e,urlSnapshotTask:n,isTaskRunnerDebugOnly:o})
|
583 | const p=pe(i.add)
|
584 | const l=e=>{const{url:{searchParams:t}}=e.getState()
|
585 | const n=t.has("verbose")
|
586 | const r=t.has("raw")
|
587 | i.add(`[Status] isVerbose: ${n}, isRaw: ${r}`)
|
588 | return Te(e,{object:{taskRunnerCluster:u({isVerbose:n,isRaw:r})}})}
|
589 | const d=(e=>e.reduce((e,[t,n,r])=>ze(e,t,n,r),{}))([...c,["/status","GET",l],["/","GET",o?((e,t)=>{let n
|
590 | return async r=>{void 0===n&&(n=await Oe(Buffer.from(Je(e(),t)),we.html))
|
591 | return xe(r,n)}})(()=>d):l],[["/favicon","/favicon.ico"],"GET",(()=>{const e=Oe(Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNMXvf/PwAGnQMR4CJUOAAAAABJRU5ErkJggg==","base64"),we.png)
|
592 | return t=>xe(t,e)})()]])
|
593 | s.on("request",(({responderList:e=[],responderEnd:t=he,responderError:n=((e,t)=>e.setState({error:t}))})=>async(r,o)=>{const s=(e=>({getState:()=>e,setState:t=>e={...e,...t}}))({time:q(),error:null})
|
594 | s.request=r
|
595 | s.response=o
|
596 | try{for(const t of e)await t(s)}catch(e){await n(s,e)}await t(s)})({responderList:[(e=>t=>{e(ue(t.request),"|",t.request.headers["user-agent"]||"no-user-agent")})(i.add),(({baseUrl:e="",baseUrlObject:t=new ie.URL(e)})=>e=>{const{url:n,method:r}=e.request
|
597 | e.setState({url:new ie.URL(n,t),method:r})})(a),(e=>t=>{const{url:n,method:r}=t.getState()
|
598 | if(!n||!r)throw new Error(`[responderRouter] missing state: ${JSON.stringify({url:n,method:r})}`)
|
599 | if(!_e[r])throw new Error(`[responderRouter] invalid method [${r}] from route: ${n.pathname}`)
|
600 | const{routeNode:o,paramValueList:s}=Ne(e,n.pathname)
|
601 | if(!o[_e[r]])throw new Error(`[responderRouter] invalid method [${r}] for route: ${n.pathname}`)
|
602 | const{route:a,paramNameList:i,routeResponder:c}=o[_e[r]]
|
603 | const u=i.reduce((e,t,n)=>{e[t]=s[n]
|
604 | return e},{})
|
605 | return c(t,t.setState({route:a,paramMap:u}))})(d)],responderEnd:e=>{ce(e)
|
606 | p(e)}}))}
|
607 | const vt={name:"",nameENV:"",nameJSON:"",shortName:"",aliasNameList:[],optional:!1,argumentCount:"0",argumentLengthMin:0,argumentLengthMax:0,argumentListNormalize:e=>e,argumentListVerify:e=>{},description:"",extendFormatList:[]}
|
608 | const kt=/^(\d+)(-)?(\d+)?$/
|
609 | const xt=(e,t)=>{"function"!=typeof e&&(e=!!e&&Tt)
|
610 | return t?(n,r,o)=>e&&e(n,r,o)||!r.has(t):e}
|
611 | const Tt=()=>!0
|
612 | const Ot=(e,t,n)=>{e={...vt,...e}
|
613 | !$t.test(e.name)&&Et(`name '${e.name}'`,e,t,n)
|
614 | e.shortName&&!Lt.test(e.shortName)&&Et(`shortName '${e.shortName}'`,e,t,n)
|
615 | {const r=e.aliasNameList.findIndex(e=>!$t.test(e));-1!==r&&Et(`aliasNameList #${r} '${e.aliasNameList[r]}'`,e,t,n)}{!kt.test(e.argumentCount)&&Et(`argumentCount '${e.argumentCount}'`,e,t,n)
|
616 | const[,r,,o]=kt.exec(e.argumentCount)
|
617 | o&&parseInt(o)<parseInt(r)&&Et(`argumentCount '${e.argumentCount}'`,e,t,n)}e.extendFormatList.length&&(e.extendFormatList=e.extendFormatList.map((t,n)=>Ot(t,n,e)))
|
618 | return e}
|
619 | const $t=/^[A-Za-z][A-Za-z0-9-]*$/
|
620 | const Lt=/^[A-Za-z]$/
|
621 | const Et=(e,t,n,r)=>{throw new Error(`[Format] ${Ft(t)} #${n}${r?` of ${Ft(r)}`:""} | ${e}`)}
|
622 | const Nt=(e,t)=>n=>{const r=[]
|
623 | const o=()=>r[r.length-1].argumentList
|
624 | for(let s=0,a=n.length;s<a;s++){const a=n[s]
|
625 | if(At.test(a)){const[,t,,n]=At.exec(a)
|
626 | const s=e.get(t)
|
627 | !s&&Rt(t)
|
628 | r.push({format:s,argumentList:[]})
|
629 | n&&o().push(n)}else if(Pt.test(a)){const[,e,,n]=Pt.exec(a)
|
630 | e.split("").forEach(n=>{const o=t.get(n)
|
631 | !o&&Rt(n,`from '${e}'`)
|
632 | r.push({format:o,argumentList:[]})})
|
633 | n&&o().push(n)}else{!r.length&&Rt(a,"no leading option found")
|
634 | "--"===a?o().push(...n.slice(s)):o().push(a)}}return r}
|
635 | const At=/^--([A-Za-z][A-Za-z0-9-]*)(=(.*))?$/
|
636 | const Pt=/^-([A-Za-z]+)(=(.*))?$/
|
637 | const Rt=(e,t="invalid option")=>{throw new Error(`[ParseArgv] unexpected '${e}', ${t}`)}
|
638 | const jt=e=>(t,n={})=>e(t).reduce((e,{format:t,argumentList:n})=>{e[t.name]?e[t.name].argumentList.push(...n):e[t.name]={format:t,argumentList:n,source:"CLI"}
|
639 | return e},n)
|
640 | const Ct=e=>(t,n={})=>{e.forEach((e,r)=>{let o=t[r]
|
641 | if(o){try{o=JSON.parse(o)}catch(e){}n[e.name]={format:e,argumentList:Array.isArray(o)?o:[o],source:"ENV"}}})
|
642 | return n}
|
643 | const Dt=e=>(t,n={})=>{e.forEach((e,r)=>{const o=t[r]
|
644 | o&&(n[e.name]={format:e,argumentList:Array.isArray(o)?o:[o],source:"JSON"})})
|
645 | return n}
|
646 | const It=(e,t)=>(n,r)=>{const o=new Set
|
647 | Object.entries(n).forEach(([e,t])=>{const{format:n,argumentList:s}=t
|
648 | n.argumentLengthMin>s.length&&Mt(`expected ${n.argumentLengthMin-s.length} more argument`,n)
|
649 | n.argumentLengthMax<s.length&&Mt(`expected ${s.length-n.argumentLengthMax} less argument`,n)
|
650 | t.argumentList=n.argumentListNormalize(s,r)
|
651 | n.argumentListVerify(t.argumentList,r)
|
652 | o.add(n)})
|
653 | e.forEach(e=>!o.has(e)&&Mt("non-optional option",e))
|
654 | t.forEach(({format:e,checkOptional:t})=>!t(n,o,e)&&!o.has(e)&&Mt("non-optional option",e))
|
655 | return n}
|
656 | const Mt=(e,t)=>{throw new Error(`[Process] ${Ft(t)} | ${e}`)}
|
657 | const Ft=({name:e,shortName:t,aliasNameList:n})=>`${e}${n.length?`|${n.join("|")}`:""}${t?` [-${t}]`:""}`
|
658 | const _t=e=>Qt(e,zt)
|
659 | const zt=e=>Wt(Ht(e,`--${e.name}${e.aliasNameList.length?` --${e.aliasNameList.join(" --")}`:""}`,e.shortName&&`-${e.shortName}`),e.description&&Zt(e.description,4),Bt(e.extendFormatList,zt,2))
|
660 | const Ut=e=>Wt('"',Zt(`#!/usr/bin/env bash\n${Qt(e,qt)}`),'"')
|
661 | const qt=e=>Wt(`export ${e.nameENV}="${Ht(e)}"`,Bt(e.extendFormatList,qt,0))
|
662 | const Jt=e=>Wt("{",Zt(Qt(e,Gt)),"}")
|
663 | const Gt=e=>Wt(`"${e.nameJSON}": [ "${Ht(e)}" ],`,Bt(e.extendFormatList,Gt,0))
|
664 | const Ht=({optional:e,argumentLengthMin:t,argumentLengthMax:n},...r)=>[...r,e&&(e===Tt?"[OPTIONAL]":"[OPTIONAL-CHECK]"),(t||n)&&`[ARGUMENT=${Vt(t,n)}]`].filter(Boolean).join(" ")
|
665 | const Bt=(e,t,n)=>e.length&&Zt(Qt(e,t),n)
|
666 | const Vt=(e,t)=>`${e}${t===1/0?"+":t>e?`-${t}`:""}`
|
667 | const Qt=(e,t)=>Wt(...e.map(t))
|
668 | const Wt=(...e)=>e.filter(Boolean).join("\n")
|
669 | const Zt=(e,t=2)=>t?((e,t=" ")=>`${t}${e.replace(/\n/g,`\n${t}`)}`)(e," ".repeat(t)):e
|
670 | const Kt=e=>se(e,1,"single argument expected")
|
671 | const Yt=(e,t)=>n=>{Kt(n)
|
672 | e(n[0],`single ${t} argument expected`)}
|
673 | const Xt=(e,t)=>n=>{n.forEach((n,r)=>e(n,`${t} expected at #${r}`))}
|
674 | const en=Xt(ne,"String")
|
675 | const tn=Xt(re,"Number")
|
676 | const nn=Xt(oe,"Integer")
|
677 | const rn=Xt(ae,"Function")
|
678 | const on=e=>e.map(String)
|
679 | const sn=e=>e.map(Number)
|
680 | const an=e=>e.map(parseInt)
|
681 | const cn=(e,t=(()=>{}),n=(e=>e),r="",o=!1)=>({argumentCount:e,argumentListNormalize:n,argumentListVerify:t,description:r,optional:o})
|
682 | const un=(e,t)=>n=>{e(n)
|
683 | return cn(1,(e=>t=>{Kt(t);((e,t,n)=>((e,t)=>t.includes(e))(e,t)||ee("OneOf",n,`expect one of: [${t}], get: ${X(e)}`))(t[0],e)})(n),t,`one of:\n ${((e,t)=>{const n=[]
|
684 | for(let r=0,o=e.length;r<o;r+=t)n.push(e.slice(r,r+t))
|
685 | return n})(n,4).map(e=>e.join(" ")).join("\n ")}`)}
|
686 | const pn={SingleString:cn(1,Yt(ne,"String"),on),SingleNumber:cn(1,Yt(re,"Number"),sn),SingleInteger:cn(1,Yt(oe,"Integer"),an),SingleFunction:cn(1,Yt(ae,"Function"),void 0),AllString:cn("1-",en,on),AllNumber:cn("1-",tn,sn),AllInteger:cn("1-",nn,an),AllFunction:cn("1-",rn,void 0),OneOfString:un(on,en),OneOfNumber:un(sn,tn),OneOfInteger:un(an,nn),BooleanFlag:cn("0-",void 0,()=>[!0],"set to enable",!0),Any:cn("0-",void 0,void 0,"optional",!0)}
|
687 | const ln={...pn,SinglePath:{...pn.SingleString,isPath:!0},AllPath:{...pn.AllString,isPath:!0},Config:{...pn.SingleString,description:"# from JSON: set to 'path/to/config.json'\n# from ENV: set to 'env'",optional:!0,name:"config",shortName:"c"}}
|
688 | const dn=(e,t)=>{Object.values(e).forEach(({format:{isPath:e},argumentList:n})=>e&&n.forEach((e,o)=>n[o]=Object(r.resolve)(t,e)))
|
689 | return e}
|
690 | const{SingleString:gn,SingleInteger:hn,SinglePath:mn,BooleanFlag:fn}=ln
|
691 | const{SingleString:Sn,SingleInteger:wn,BooleanFlag:yn,Config:bn}=ln
|
692 | const vn={prefixENV:"imock-snapshot",formatList:[bn,{...yn,name:"help",shortName:"h"},{...yn,name:"version",shortName:"v"},((e=[])=>({...gn,optional:!0,name:"hostname",shortName:"H",extendFormatList:[{...hn,name:"port",shortName:"P"},{...fn,name:"https",shortName:"S",extendFormatList:[{...mn,name:"file-SSL-key"},{...mn,name:"file-SSL-cert"},{...mn,name:"file-SSL-chain"},{...mn,name:"file-SSL-dhparam"}]},{...mn,optional:!0,name:"log-path",extendFormatList:[{...gn,optional:!0,name:"log-file-prefix"}]},{...mn,optional:!0,name:"pid-file",extendFormatList:[{...fn,name:"pid-ignore-exist"}]},...e]}))([{...Sn,name:"url-server-ping-test"},{...Sn,name:"url-snapshot-app"},{...Sn,name:"url-snapshot-task"},{...wn,name:"task-runner-count"},{...yn,name:"task-runner-debug-only",shortName:"D"}])]}
|
693 | const{parseOption:kn,formatUsage:xn}=(e=>{const{parseCLI:t,parseENV:n,parseJSON:o,processOptionMap:s,formatUsage:a}=(({formatList:e,prefixENV:t="",prefixJSON:n=""})=>{const r=new Map
|
694 | const o=new Map
|
695 | const s=new Map
|
696 | const a=new Map
|
697 | const i=new Set
|
698 | const c=new Set
|
699 | const u=(e,p,l)=>{const{name:d,shortName:g,aliasNameList:h,argumentCount:m}=e
|
700 | const[,f,S,w]=kt.exec(m.toString())
|
701 | e.nameENV=(t?`${t}-${d}`:d).split("-").join("_").toUpperCase()
|
702 | e.nameJSON=((e,t=1)=>e.reduce((e,n,r)=>r>=t?e+n[0].toUpperCase()+n.slice(1):e+n,""))((n?`${n}-${d}`:d).split("-"))
|
703 | e.optional=xt(e.optional,l)
|
704 | e.argumentLengthMin=parseInt(f)
|
705 | e.argumentLengthMax=S?w?parseInt(w):1/0:e.argumentLengthMin
|
706 | r.has(d)&&Et(`duplicate name '${d}'`,e,p,l)
|
707 | r.set(d,e)
|
708 | g&&o.has(g)&&Et(`duplicate shortName '${g}'`,e,p,l)
|
709 | g&&o.set(g,e)
|
710 | {const t=h.find(e=>r.has(e))
|
711 | t&&Et(`duplicate aliasName '${t}'`,e,p,l)
|
712 | h.forEach(t=>r.set(t,e))}s.set(e.nameENV,e)
|
713 | a.set(e.nameJSON,e)
|
714 | e.optional?e.optional!==Tt&&c.add({format:e,checkOptional:e.optional}):i.add(e)
|
715 | e.extendFormatList.forEach((t,n)=>u(t,n,e))};(e=e.map((e,t)=>Ot(e,t,null))).forEach((e,t)=>u(e,t,null))
|
716 | return{parseCLI:jt(Nt(r,o)),parseENV:Ct(s),parseJSON:Dt(a),processOptionMap:It(i,c),formatUsage:(t,n=!1)=>Wt(t&&`Message:\n${Zt(t.toString())}`,`CLI Usage:\n${Zt(_t(e))}`,!n&&`ENV Usage:\n${Zt(Ut(e))}`,!n&&`JSON Usage:\n${Zt(Jt(e))}`)}})(e)
|
717 | return{parseOption:async()=>(e=>{const t=t=>e[t]?e[t].argumentList:void 0
|
718 | const n=(e,n)=>{const r=t(e)
|
719 | if(!r)throw new Error(`[getOption] expecting option ${e}`)
|
720 | if(void 0!==n&&r.length!==n)throw new Error(`[getOption] expecting option ${e} has ${n} value instead of ${r.length}`)
|
721 | return r}
|
722 | return{optionMap:e,getOptionOptional:t,getOption:n,getSingleOptionOptional:t=>e[t]?e[t].argumentList[0]:void 0,getSingleOption:e=>n(e,1)[0]}})(await(async({parseCLI:e,parseENV:t,parseJSON:n,processOptionMap:o})=>{const s=dn(e(process.argv.slice(2)),process.cwd())
|
723 | const a=s.config&&s.config.argumentList.length&&s.config.argumentList[0]
|
724 | return o({...a?"env"===a?dn(t(process.env),process.cwd()):dn(n(JSON.parse(await u(a,"utf8"))),Object(r.dirname)(a)):null,...s})})({parseCLI:t,parseENV:n,parseJSON:o,processOptionMap:s})),formatUsage:a}})(vn)
|
725 | var Tn=n(9)
|
726 | const On=async(e,{getOptionOptional:t,getSingleOption:n,getSingleOptionOptional:s})=>{await(async({filePid:e,shouldIgnoreExistPid:t=!1})=>{if(e){!t&&k(()=>{const t=Object(o.readFileSync)(e,{encoding:"utf8"})
|
727 | if(t){console.warn(`[FilePid] get existing pid: ${t}, exit process...`)
|
728 | return process.exit(-1)}})
|
729 | await b(Object(r.dirname)(e))
|
730 | await p(e,`${process.pid}`)
|
731 | j(t=>{k(o.unlinkSync,e)})}})({filePid:s("pid-file"),shouldIgnoreExistPid:s("pid-ignore-exist")})
|
732 | const{server:a,start:i,option:c}=await me({protocol:t("https")?"https:":"http:",hostname:n("hostname"),port:n("port"),fileSSLKey:s("file-SSL-key"),fileSSLCert:s("file-SSL-cert"),fileSSLChain:s("file-SSL-chain"),fileSSLDHParam:s("file-SSL-dhparam")})
|
733 | const u=await I({pathLogDirectory:s("log-path"),logFilePrefix:s("log-file-prefix")})
|
734 | await bt({urlServerPingTest:n("url-server-ping-test"),urlSnapshotApp:n("url-snapshot-app"),urlSnapshotTask:n("url-snapshot-task"),taskRunnerCount:n("task-runner-count"),isTaskRunnerDebugOnly:Boolean(t("task-runner-debug-only"))},{server:a,option:c,logger:u})
|
735 | i()
|
736 | u.add(`[SERVER UP] version: ${Tn.b}, pid: ${process.pid}, at: ${c.baseUrl}`)};(async()=>{const e=await kn()
|
737 | const t=e.getSingleOptionOptional("hostname")
|
738 | if(!t)return e.getOptionOptional("version")?console.log(JSON.stringify({packageName:Tn.a,packageVersion:Tn.b},null," ")):console.log(xn(null,e.getOptionOptional("help")?null:"simple"))
|
739 | await On(0,e).catch(e=>{console.warn("[Error] server:",e.stack||e)
|
740 | process.exit(2)})})().catch(e=>{console.warn(xn(e.stack||e,"simple"))
|
741 | process.exit(1)})}])
|