import * as plugins from './typedserver.plugins.js'; import * as paths from './typedserver.paths.js'; import * as interfaces from './interfaces/index.js'; export interface IEasyServerConstructorOptions { serveDir: string; injectReload: boolean; port?: number; watch?: boolean; } export class TypedServer { // static // nothing here yet // instance public options: IEasyServerConstructorOptions; public smartexpressInstance: plugins.smartexpress.Server; public smartchokInstance: plugins.smartchok.Smartchok; public serveDirHashSubject = new plugins.smartrx.rxjs.ReplaySubject(1); public serveHash: string = '000000'; public typedsocket: plugins.typedsocket.TypedSocket; public typedrouter = new plugins.typedrequest.TypedRouter(); public lastReload: number = Date.now(); public ended = false; constructor(optionsArg: IEasyServerConstructorOptions) { const standardOptions: IEasyServerConstructorOptions = { injectReload: true, port: 3000, serveDir: process.cwd(), watch: true, }; this.options = { ...standardOptions, ...optionsArg, }; } /** * inits and starts the server */ public async start() { // set the smartexpress instance this.smartexpressInstance = new plugins.smartexpress.Server({ port: this.options.port, forceSsl: false, cors: true, }); // add routes to the smartexpress instance this.smartexpressInstance.addRoute( '/typedserver/:request', new plugins.smartexpress.Handler('ALL', async (req, res) => { switch (req.params.request) { case 'devtools': res.setHeader('Content-Type', 'text/javascript'); res.status(200); res.write(plugins.smartfile.fs.toStringSync(paths.bundlePath)); res.end(); break; case 'reloadcheck': console.log('got request for reloadcheck'); res.setHeader('Content-Type', 'text/plain'); res.status(200); if (this.ended) { res.write('end'); res.end(); return; } res.write(this.lastReload.toString()); res.end(); } }) ); this.smartexpressInstance.addRoute( '/*', new plugins.smartexpress.HandlerStatic(this.options.serveDir, { responseModifier: async (responseArg) => { let fileString = responseArg.responseContent; if (plugins.path.parse(responseArg.path).ext === '.html') { const fileStringArray = fileString.split(''); if (this.options.injectReload && fileStringArray.length === 2) { fileStringArray[0] = `${fileStringArray[0]} `; fileString = fileStringArray.join(''); console.log('injected typedserver script.'); } else if (this.options.injectReload) { console.log('Could not insert typedserver script'); } } const headers = responseArg.headers; headers.appHash = this.serveHash; headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'; headers['Pragma'] = 'no-cache'; headers['Expires'] = '0'; return { headers, path: responseArg.path, responseContent: fileString, }; }, serveIndexHtmlDefault: true, }) ); this.smartchokInstance = new plugins.smartchok.Smartchok([this.options.serveDir], {}); if (this.options.watch) { await this.smartchokInstance.start(); (await this.smartchokInstance.getObservableFor('change')).subscribe(async () => { await this.createServeDirHash(); this.reload(); }); } await this.createServeDirHash(); // lets start the server await this.smartexpressInstance.start(); console.log('open url in browser'); this.typedsocket = await plugins.typedsocket.TypedSocket.createServer( this.typedrouter, this.smartexpressInstance ); // await plugins.smartopen.openUrl(`http://testing.git.zone:${this.options.port}`); } /** * reloads the page */ public async reload() { this.lastReload = Date.now(); for (const connectionArg of await this.typedsocket.findAllTargetConnections(async () => true)) { const pushTime = this.typedsocket.createTypedRequest( 'pushLatestServerChangeTime', connectionArg ); pushTime.fire({ time: this.lastReload, }); } } public async stop() { this.ended = true; await this.smartexpressInstance.stop(); await this.typedsocket.stop(); await this.smartchokInstance.stop(); } public async createServeDirHash() { const serveDirHash = await plugins.smartfile.fs.fileTreeToHash(this.options.serveDir, '**/*'); this.serveHash = serveDirHash; console.log('Current ServeDir hash: ' + serveDirHash); this.serveDirHashSubject.next(serveDirHash); } }