|
| 1 | +/** |
| 2 | + * Author: Zeta Ret |
| 3 | + * Date: 2019 - Today |
| 4 | + * Subserver of extended Server loaded as module. |
| 5 | + **/ |
| 6 | +declare module "zetaret.node.modules::Subserver"; |
| 7 | +declare module "protoss-nodejs-basic/dist/modules/Subserver.js"; |
| 8 | + |
| 9 | +export { } |
| 10 | + |
| 11 | +var XProtoSSChe: zetaret.node.modules.XProtoSSCheCTOR, |
| 12 | + xpros: zetaret.node.modules.XProtoSSCheModule = require((global as zetaret.node.BasicServerGlobal).SubserverRequireModule || "./XProtoSSChe"), |
| 13 | + events = require("events"); |
| 14 | + |
| 15 | +const EVENTS = { |
| 16 | + VOID: "", |
| 17 | +}; |
| 18 | +const ROUTER_SWITCH = { |
| 19 | + AddPathListener: "addPathListener", |
| 20 | + AddMethodPathListener: "addMethodPathListener", |
| 21 | + AddParamsPathListener: "addParamsPathListener", |
| 22 | +}; |
| 23 | +const SERVERID = "zetaret.node.modules::Subserver"; |
| 24 | + |
| 25 | +function getExtendedServerProtoSS(ProtoSSChe: zetaret.node.ProtoSSCheCTOR): zetaret.node.modules.SubserverCTOR { |
| 26 | + if (!XProtoSSChe) XProtoSSChe = xpros.getExtendedServerProtoSS(ProtoSSChe); |
| 27 | + return class Subserver extends XProtoSSChe implements zetaret.node.modules.Subserver { |
| 28 | + routeMap: object; |
| 29 | + codeMap: object | any; |
| 30 | + noRouteCode: number; |
| 31 | + noRouteEvent: string; |
| 32 | + debugRoute: boolean; |
| 33 | + debugRouteList: string[]; |
| 34 | + listener: zetaret.node.Emitter; |
| 35 | + pathEmitter: zetaret.node.Emitter; |
| 36 | + routeRegMap: object; |
| 37 | + routeRegExp: RegExp; |
| 38 | + routeRegGet: Function; |
| 39 | + useProxy: boolean; |
| 40 | + proxyPaths: string; |
| 41 | + proxyMask: object | any; |
| 42 | + noProxyCode: number; |
| 43 | + noProxyEvent: string; |
| 44 | + emitExacts: boolean; |
| 45 | + |
| 46 | + constructor() { |
| 47 | + super(null, null, {}); |
| 48 | + var o = this; |
| 49 | + o.routeMap = {}; |
| 50 | + o.codeMap = {}; |
| 51 | + o.noRouteCode = 404; |
| 52 | + o.noRouteEvent = "error404"; |
| 53 | + o.debugRoute = true; |
| 54 | + o.debugRouteList = []; |
| 55 | + o.listener = new events.EventEmitter(); |
| 56 | + o.pathEmitter = new events.EventEmitter(); |
| 57 | + o.routeRegMap = {}; |
| 58 | + o.routeRegExp = new RegExp("^[\\w|\\-]+$"); |
| 59 | + o.routeRegGet = null; |
| 60 | + o.useProxy = true; |
| 61 | + o.proxyPaths = "__proxypaths"; |
| 62 | + o.proxyMask = {}; |
| 63 | + o.noProxyCode = 400; |
| 64 | + o.noProxyEvent = "proxyNoRoute"; |
| 65 | + o.emitExacts = false; |
| 66 | + o.initRouteListener(); |
| 67 | + } |
| 68 | + |
| 69 | + addPathListener(path: string, callback?: Function): Function { |
| 70 | + var o = this; |
| 71 | + if (o.debugRouteList) o.debugRouteList.push(path); |
| 72 | + if (!callback) callback = (o as any).pathListenerX || o.pathListener.bind(o); |
| 73 | + o.pathEmitter.on(path, callback as any); |
| 74 | + return callback; |
| 75 | + } |
| 76 | + |
| 77 | + removePathListener(path: string, callback: Function): zetaret.node.modules.Subserver { |
| 78 | + var o = this; |
| 79 | + (o.pathEmitter as any).remove(path, callback); |
| 80 | + let starpath = path |
| 81 | + .split("/") |
| 82 | + .map(() => "*") |
| 83 | + .join("/"); |
| 84 | + (o.pathEmitter as any).remove(starpath, callback); |
| 85 | + return o; |
| 86 | + } |
| 87 | + |
| 88 | + pathListener(server: zetaret.node.modules.Subserver, robj: object, routeData: object, request: zetaret.node.Input, response: zetaret.node.Output): void { |
| 89 | + var o = this; |
| 90 | + if (o.debugRoute) console.log(robj, (request as Http2Request).url, request.method); |
| 91 | + } |
| 92 | + |
| 93 | + addMethodPathListener(method: string, path: string, callback: Function): Function { |
| 94 | + var o = this; |
| 95 | + const methodup = method.toUpperCase(); |
| 96 | + return o.addPathListener(path, function (server: zetaret.node.modules.Subserver, |
| 97 | + robj: object, routeData: object, request: zetaret.node.Input, response: zetaret.node.Output): void { |
| 98 | + if (request.method.toUpperCase() === methodup) { |
| 99 | + callback(server, robj, routeData, request, response); |
| 100 | + } |
| 101 | + }); |
| 102 | + } |
| 103 | + |
| 104 | + addParamsPathListener(path: string, callback: Function | Function[], method?: string, autoRoute?: boolean): Function { |
| 105 | + var o = this; |
| 106 | + if (o.debugRouteList) o.debugRouteList.push(path); |
| 107 | + const methodup = method ? method.toUpperCase() : null; |
| 108 | + var paramPath: string[] = []; |
| 109 | + var r: any = o.routeMap; |
| 110 | + var listenPath = path |
| 111 | + .split("/") |
| 112 | + .map((e: any) => { |
| 113 | + var param = e; |
| 114 | + if (param.charAt(0) === "{" && param.charAt(param.length - 1) === "}") { |
| 115 | + param = new RegExp(param.substring(1, param.length - 1)); |
| 116 | + if (autoRoute) { |
| 117 | + if (!r["*"]) r["*"] = {}; |
| 118 | + r = r["*"]; |
| 119 | + } |
| 120 | + } else if (param.charAt(0) === ":") { |
| 121 | + if (autoRoute) { |
| 122 | + if (!r["*"]) r["*"] = {}; |
| 123 | + r = r["*"]; |
| 124 | + } |
| 125 | + } else { |
| 126 | + if (autoRoute) { |
| 127 | + if (!r[param]) r[param] = {}; |
| 128 | + r = r[param]; |
| 129 | + } |
| 130 | + } |
| 131 | + paramPath.push(param); |
| 132 | + return "*"; |
| 133 | + }) |
| 134 | + .join("/"); |
| 135 | + |
| 136 | + return o.addPathListener(listenPath, function (server: zetaret.node.modules.Subserver, |
| 137 | + robj: object | any, routeData: object, request: zetaret.node.Input, response: zetaret.node.Output): void { |
| 138 | + if (!methodup || request.method.toUpperCase() === methodup) { |
| 139 | + var pcsplit = robj.pageCurrent.split("/"); |
| 140 | + var i, |
| 141 | + param, |
| 142 | + paramc, |
| 143 | + vars: any = {}; |
| 144 | + |
| 145 | + if (paramPath.length <= pcsplit.length) { |
| 146 | + for (i = 0; i < paramPath.length; i++) { |
| 147 | + param = paramPath[i]; |
| 148 | + paramc = param.constructor; |
| 149 | + if (paramc === RegExp && !pcsplit[i].match(param)) break; |
| 150 | + else if (paramc === String && param.charAt(0) === ":") vars[param.substring(1)] = pcsplit[i]; |
| 151 | + else if (paramc === String && param !== pcsplit[i]) break; |
| 152 | + } |
| 153 | + if (i === paramPath.length) { |
| 154 | + var newrobj = { ...robj }; |
| 155 | + newrobj.vars = { ...robj.vars, ...vars }; |
| 156 | + newrobj.paramsPathData = { |
| 157 | + path: path, |
| 158 | + listenPath: listenPath, |
| 159 | + paramPath: paramPath, |
| 160 | + params: vars, |
| 161 | + }; |
| 162 | + if (callback.constructor === Array) { |
| 163 | + for (let ci = 0; ci < callback.length; ci++) { |
| 164 | + callback[ci](server, newrobj, routeData, request, response); |
| 165 | + if ((response as zetaret.node.RoutedResponse).__breakRoute) break; |
| 166 | + } |
| 167 | + } else (callback as Function)(server, newrobj, routeData, request, response); |
| 168 | + } |
| 169 | + } |
| 170 | + } |
| 171 | + }); |
| 172 | + } |
| 173 | + |
| 174 | + addRegPathListener(path: string, callback: Function): Function { |
| 175 | + var o = this; |
| 176 | + if (o.debugRouteList) o.debugRouteList.push(path); |
| 177 | + var regexp = o.setRouteRegExp(path); |
| 178 | + var listenPath = path |
| 179 | + .split("/") |
| 180 | + .map(() => "*") |
| 181 | + .join("/"); |
| 182 | + return o.addPathListener(listenPath, (server: zetaret.node.modules.Subserver, |
| 183 | + robj: object | any, routeData: object, request: zetaret.node.Input, response: zetaret.node.Output): void => { |
| 184 | + if (robj.pageCurrent.match(regexp)) callback(server, robj, routeData, request, response); |
| 185 | + else { |
| 186 | + (response as zetaret.node.RoutedResponse).__rcode = server.noProxyCode; |
| 187 | + if (server.noProxyEvent) |
| 188 | + server.listener.emit(server.noProxyEvent, server, robj, routeData, request, response); |
| 189 | + } |
| 190 | + }); |
| 191 | + } |
| 192 | + |
| 193 | + setRouteRegExp(path: string): RegExp { |
| 194 | + var o = this; |
| 195 | + var r: any = o.routeMap, |
| 196 | + regmap = (o.routeRegMap as any)[path]; |
| 197 | + path.split("/").forEach((e: any, i: number, a: any) => { |
| 198 | + if (regmap) { |
| 199 | + if (!regmap[i]) e = "*"; |
| 200 | + } else if (o.routeRegExp) { |
| 201 | + if (!e.match(o.routeRegExp)) e = "*"; |
| 202 | + } else if (o.routeRegGet) { |
| 203 | + if (!o.routeRegGet(e, i, a)) e = "*"; |
| 204 | + } |
| 205 | + if (!r[e]) r[e] = {}; |
| 206 | + r = r[e]; |
| 207 | + }); |
| 208 | + if (!r[o.proxyPaths]) r[o.proxyPaths] = {}; |
| 209 | + r[o.proxyPaths][path] = {}; |
| 210 | + return new RegExp(path); |
| 211 | + } |
| 212 | + |
| 213 | + routeCallback(routeData: object, body: string, request: zetaret.node.Input, response: zetaret.node.Output): void { |
| 214 | + var o = this; |
| 215 | + var cp, |
| 216 | + pp, |
| 217 | + p, |
| 218 | + i, |
| 219 | + r: any = o.routeMap, |
| 220 | + robj = (response as zetaret.node.RoutedResponse).__splitUrl, |
| 221 | + l = robj.pages.length, |
| 222 | + rawpath = robj.pages.join("/"), |
| 223 | + stars = ""; |
| 224 | + robj.rawpath = rawpath; |
| 225 | + if (l > 0) { |
| 226 | + for (i = 0; i < l; i++) { |
| 227 | + p = robj.pages[i]; |
| 228 | + if (p === "*") p = ""; |
| 229 | + cp = cp ? cp + "/" + p : p; |
| 230 | + stars = stars ? stars + "/*" : "*"; |
| 231 | + robj.pageIndex = i; |
| 232 | + robj.pageCurrent = cp; |
| 233 | + robj.pageProxy = null; |
| 234 | + if (o.useProxy && (p === o.proxyPaths || o.proxyMask[cp] || o.proxyMask[p])) r = null; |
| 235 | + else r = r[p] || r["*"]; |
| 236 | + |
| 237 | + if (!r) { |
| 238 | + (response as zetaret.node.RoutedResponse).__rcode = o.noRouteCode; |
| 239 | + if (o.noRouteEvent) o.listener.emit(o.noRouteEvent, o, robj, routeData, request, response); |
| 240 | + break; |
| 241 | + } else { |
| 242 | + robj.exact = cp === robj.rawpath; |
| 243 | + o.pathEmitter.emit(stars, o, robj, routeData, request, response); |
| 244 | + if (!o.emitExacts || robj.exact) o.pathEmitter.emit(cp, o, robj, routeData, request, response); |
| 245 | + if (o.useProxy && r[o.proxyPaths]) { |
| 246 | + for (pp in r[o.proxyPaths]) { |
| 247 | + robj.pageProxy = pp; |
| 248 | + o.pathEmitter.emit(pp, o, robj, routeData, request, response); |
| 249 | + } |
| 250 | + } |
| 251 | + if ((response as zetaret.node.RoutedResponse).__breakRoute) break; |
| 252 | + } |
| 253 | + } |
| 254 | + } else { |
| 255 | + robj.exact = true; |
| 256 | + o.pathEmitter.emit(EVENTS.VOID, o, robj, routeData, request, response); |
| 257 | + } |
| 258 | + if (o.codeMap[rawpath]) (response as zetaret.node.RoutedResponse).__rcode = o.codeMap[rawpath]; |
| 259 | + } |
| 260 | + |
| 261 | + initRoute(): void { |
| 262 | + var o = this; |
| 263 | + o.routeScope = o; |
| 264 | + } |
| 265 | + |
| 266 | + initRouteListener(): zetaret.node.modules.Subserver { |
| 267 | + var o = this; |
| 268 | + (o as any).pathListenerX = o.pathListener.bind(o); |
| 269 | + Object.defineProperty(o, "pathListenerX", { |
| 270 | + enumerable: false, |
| 271 | + }); |
| 272 | + o.addPathListener(o.noRouteEvent); |
| 273 | + o.listener.on(o.noRouteEvent, (o as any).pathListenerX); |
| 274 | + return o; |
| 275 | + } |
| 276 | + |
| 277 | + addRouter(router: zetaret.node.api.Router): void { |
| 278 | + var o = this; |
| 279 | + var prefix = router.prefix; |
| 280 | + router.adds.forEach((routerAdd) => { |
| 281 | + var c, |
| 282 | + m = routerAdd.method, |
| 283 | + a = routerAdd.arguments; |
| 284 | + |
| 285 | + switch (m) { |
| 286 | + case ROUTER_SWITCH.AddPathListener: |
| 287 | + c = o.addPathListener(prefix + a[0], a[1]); |
| 288 | + break; |
| 289 | + case ROUTER_SWITCH.AddMethodPathListener: |
| 290 | + c = o.addMethodPathListener(a[0], prefix + a[1], a[2]); |
| 291 | + break; |
| 292 | + case ROUTER_SWITCH.AddParamsPathListener: |
| 293 | + c = o.addParamsPathListener(prefix + a[0], a[1], a[2], a[3]); |
| 294 | + break; |
| 295 | + } |
| 296 | + |
| 297 | + router.returns.push({ add: routerAdd, server: o, callback: c }); |
| 298 | + }); |
| 299 | + } |
| 300 | + |
| 301 | + pushProtoSSResponse(request: zetaret.node.Input, response: zetaret.node.Output): Subserver { |
| 302 | + var o = this; |
| 303 | + if (!(response as zetaret.node.RoutedResponse).__headers) (response as zetaret.node.RoutedResponse).__headers = {}; |
| 304 | + return o; |
| 305 | + } |
| 306 | + |
| 307 | + addHeaders(request: zetaret.node.Input, response: zetaret.node.Output): object { |
| 308 | + var headers = (response as zetaret.node.RoutedResponse).__headers || {}; |
| 309 | + return headers; |
| 310 | + } |
| 311 | + }; |
| 312 | +} |
| 313 | + |
| 314 | +module.exports.xpros = xpros; |
| 315 | +module.exports.EVENTS = EVENTS; |
| 316 | +module.exports.SERVERID = SERVERID; |
| 317 | +module.exports.resetExtends = (): void => (XProtoSSChe = null); |
| 318 | +module.exports.getExtends = (): zetaret.node.ProtoSSCheCTOR => XProtoSSChe; |
| 319 | +module.exports.getExtendedServerProtoSS = getExtendedServerProtoSS; |
0 commit comments