import http from 'http'; import url from 'url'; import path from 'path'; import fs from 'fs'; //import pg from 'pg'; import React from 'react'; import TestRenderer from 'react-test-renderer'; import ReactDOMServer from 'react-dom/server'; import { App } from './App.js'; import { StateTree } from './StateTree.js'; function promisify(f) { return new Promise((resolve, reject) => f((error, result) => error ? reject(error) : resolve(result))); } export class SSRServer { static defaultConfig = { host: '127.0.0.1', port: 9223, }; start(cfg) { this.cfg = cfg; for (let k in this.constructor.defaultConfig) { this.cfg[k] = this.cfg[k] || this.constructor.defaultConfig[k]; } this.server = http.Server((req, resp) => this.handleRequest(req, resp)); this.server.listen(this.cfg.port, this.cfg.host); if (this.cfg.db) { this.connectPg(); } this.dir = __dirname; } async connectPg() { this.db = new pg.Client(this.cfg.db); this.db.on('error', () => setTimeout(() => this.connectPg(), 30000)); this.db.on('notification', (msg) => this.onNotification(msg)); await this.db.connect(); } onNotification({ name, length, processId, channel, payload }) { } async handleRequest(req, resp) { const u = url.parse(req.url, true); const path = u.pathname.replace(/^\/+|\/+$/g, ''); if (!path) { resp.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', }); let pending = 0; let st, testr; let finish = () => { st.update(); const data = st.export(); testr.unmount(); testr = null; st = new StateTree({ doQuery: () => {} }); st.import(data); const html = ''+ ''+ '
'+ ReactDOMServer.renderToString()+ '
'+ ''; resp.write(html); resp.end(); }; st = new StateTree({ doQuery: (cb) => { pending++; this.handle('data', (r) => { cb(r); pending--; if (!pending) { testr.update(); finish(); } }); } }); testr = TestRenderer.create(); if (testr && !pending) { finish(); } } else if (path == 'main.c.js') { const data = await promisify(h => fs.readFile(this.dir + '/main.c.js', h)); resp.writeHead(200, { 'Content-Type': 'application/javascript', }); resp.write(data); resp.end(); } else { this.handle(path, (r) => { resp.writeHead(200, { 'Content-Type': 'application/json', }); resp.write(JSON.stringify(r)); resp.end(); }); } } handle(path, cb) { let r; if (path == 'data') { // Data r = { text: 'Hello world!' }; } else r = { error: 'Unknown action' }; setTimeout(() => { cb(r); }, 100); } }