typedserver/ts/typedserver.classes.typedserver.ts
2023-03-29 14:54:07 +02:00

171 lines
5.4 KiB
TypeScript

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<string>(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('<head>');
if (this.options.injectReload && fileStringArray.length === 2) {
fileStringArray[0] = `${fileStringArray[0]}<head>
<!-- injected by @apiglobal/typedserver start -->
<script async defer type="module" src="/typedserver/devtools"></script>
<script>
globalThis.typedserver = {
lastReload: '${this.lastReload}',
versionInfo: ${JSON.stringify({}, null, 2)},
}
</script>
<!-- injected by @apiglobal/typedserver stop -->
`;
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<interfaces.IReq_PushLatestServerChangeTime>(
'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);
}
}