Skip to content

Commit

Permalink
feat: support custom server
Browse files Browse the repository at this point in the history
  • Loading branch information
mildronize committed Feb 6, 2024
1 parent 95a325e commit 882ae92
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 77 deletions.
23 changes: 23 additions & 0 deletions examples/custom-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import express from 'express';
import { DataViewer } from 'src/main';

const getUsers = async () => (await fetch('https://jsonplaceholder.typicode.com/users')).json();
const getPosts = async () => (await fetch('https://jsonplaceholder.typicode.com/posts')).json();

async function main() {

const dataViewer = new DataViewer({
path: '/viewer',
});

dataViewer.addHeader('User Table');
dataViewer.addTable((await getUsers()));
dataViewer.addHeader('Post Table');
dataViewer.addTable(await getPosts());

const app = express();
dataViewer.registerMiddleware(app);
app.listen(3000, async () => console.log(`Already servered on http://localhost:3000/viewer`));
}

main();
92 changes: 92 additions & 0 deletions src/view-server/data-viewer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type { Logger } from 'pino';
import type express from 'express';

import type { AllTableData, HeaderComponent, ServerOptions, TableComponent } from './types';

import { format } from './utils';
import { getLogger } from '../logger';
import { startViewServer } from './server';

export class DataViewer {
private dataView: AllTableData[] = [];
private logger: Logger;

constructor(protected option: ServerOptions = {}) {
this.logger = this.setupLogger(option);
}

public setupLogger(option: ServerOptions) {
return getLogger(
option.logger ?? {
level: 'info',
...(option.logger ?? {}),
}
);
}

public getOption() {
return this.option;
}

public setOption(option: ServerOptions) {
this.option = option;
this.logger = this.setupLogger(option);
return this;
}

public addData(data: AllTableData) {
this.dataView.push(data);
return this;
}

public addTable(data: TableComponent['data']) {
this.dataView.push({ type: 'table', data });
return this;
}

public addHeader(data: HeaderComponent['data']) {
this.dataView.push({ type: 'header', data });
return this;
}

public clear() {
this.dataView = [];
return this;
}

public start() {
startViewServer(this, this.logger);
}

public registerMiddleware(app: express.Express) {
const viewPath = this.option.path ?? '/';
const viewDirectory = this.option.viewDirectory ?? __dirname + '/views';
console.debug(`Config viewDirectory: ${viewDirectory}`);
let cellFormatter = this.option.cellFormatter ?? format;
if (typeof this.option.cellFormatter === 'function') {
console.debug(`Config cellFormatter: Using custom cell formatter`);
} else if (this.option.cellFormatter !== undefined) {
console.warn(`Config cellFormatter: Invalid cell formatter, using default cell formatter`);
cellFormatter = format;
}

// Set the custom path for EJS views
app.set('views', viewDirectory);

// Set the view engine to EJS
app.set('view engine', 'ejs');

// Middleware to add the formatDate function to locals
app.use((req, res, next) => {
res.locals.format = cellFormatter;
next();
});

// Define a route to render the HTML page
app.get(viewPath, (req, res) => {
res.render('index', { dataView: this.dataView });
});
}
}

export const dataViewer = new DataViewer();
1 change: 1 addition & 0 deletions src/view-server/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './server';
export * from './types';
export * from './utils';
export * from './data-viewer';
106 changes: 29 additions & 77 deletions src/view-server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,78 +4,30 @@ import express from 'express';
import { Server } from 'socket.io';
import { createServer } from 'node:http';

import type { AllTableData, HeaderComponent, ServerOptions, TableComponent } from './types';
import type { DataViewer } from './data-viewer';

import { getLogger } from '../logger';
import { delay, format } from './utils';
import { delay } from './utils';

export class DataViewer {
private dataView: AllTableData[] = [];
private logger: Logger;

constructor(protected option: ServerOptions = {}) {
this.logger = this.setupLogger(option);
}

public setupLogger(option: ServerOptions) {
return getLogger(
option.logger ?? {
level: 'info',
...(option.logger ?? {}),
}
);
}

public setOption(option: ServerOptions) {
this.option = option;
this.logger = this.setupLogger(option);
return this;
}

public addData(data: AllTableData) {
this.dataView.push(data);
return this;
}

public addTable(data: TableComponent['data']) {
this.dataView.push({ type: 'table', data });
return this;
}

public addHeader(data: HeaderComponent['data']) {
this.dataView.push({ type: 'header', data });
return this;
}

public clear() {
this.dataView = [];
return this;
}

public start() {
startViewServer(this.dataView, this.option, this.logger);
}
}

export async function startViewServer(dataView: AllTableData[], option: ServerOptions = {}, logger: Logger) {
export async function startViewServer(dataViewer: DataViewer, logger: Logger) {
const viewerOption = dataViewer.getOption();
logger.debug('Starting view server');
const app = express();
logger.debug('Express app created');
const server = createServer(app);
logger.debug('HTTP server created');
const io = new Server(server);
logger.debug('Socket.IO server created');
const port = option.port ?? 3030;
const port = viewerOption.port ?? 3030;
logger.debug(`Config port: ${port}`);
const viewDirectory = option.viewDirectory ?? __dirname + '/views';
logger.debug(`Config viewDirectory: ${viewDirectory}`);
let cellFormatter = option.cellFormatter ?? format;
if (typeof option.cellFormatter === 'function') {
logger.debug(`Config cellFormatter: Using custom cell formatter`);
} else if (option.cellFormatter !== undefined) {
logger.warn(`Config cellFormatter: Invalid cell formatter, using default cell formatter`);
cellFormatter = format;
}
// const viewDirectory = viewerOption.viewDirectory ?? __dirname + '/views';
// logger.debug(`Config viewDirectory: ${viewDirectory}`);
// let cellFormatter = option.cellFormatter ?? format;
// if (typeof option.cellFormatter === 'function') {
// logger.debug(`Config cellFormatter: Using custom cell formatter`);
// } else if (option.cellFormatter !== undefined) {
// logger.warn(`Config cellFormatter: Invalid cell formatter, using default cell formatter`);
// cellFormatter = format;
// }

let isClientConnected = false;

Expand Down Expand Up @@ -108,22 +60,24 @@ export async function startViewServer(dataView: AllTableData[], option: ServerOp
});
});

// Set the custom path for EJS views
app.set('views', viewDirectory);
dataViewer.registerMiddleware(app);

// Set the view engine to EJS
app.set('view engine', 'ejs');
// // Set the custom path for EJS views
// app.set('views', viewDirectory);

// Middleware to add the formatDate function to locals
app.use((req, res, next) => {
res.locals.format = cellFormatter;
next();
});
// // Set the view engine to EJS
// app.set('view engine', 'ejs');

// Define a route to render the HTML page
app.get('/', (req, res) => {
res.render('index', { dataView });
});
// // Middleware to add the formatDate function to locals
// app.use((req, res, next) => {
// res.locals.format = cellFormatter;
// next();
// });

// // Define a route to render the HTML page
// app.get('/', (req, res) => {
// res.render('index', { dataView });
// });

server.listen(port, async () => {
logger.info(`Server is running at http://localhost:${port}`);
Expand All @@ -134,5 +88,3 @@ export async function startViewServer(dataView: AllTableData[], option: ServerOp
logger.debug('Start reload');
});
}

export const dataViewer = new DataViewer();
5 changes: 5 additions & 0 deletions src/view-server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export interface HeaderComponent {
export type AllTableData = TableComponent | HeaderComponent;

export interface ServerOptions {
/**
* The path to serve the view
* @default '/'
*/
path?: string;
port?: number;
viewDirectory?: string;
/**
Expand Down

0 comments on commit 882ae92

Please sign in to comment.