1 | import debug = require("debug");
|
2 | import express = require("express");
|
3 | import expressSession = require("express-session");
|
4 | import { createServer } from "http";
|
5 | import { RemoteMessageType, REQUIRE_FUNC_NAME } from "neweb-core";
|
6 | import { ModulePacker } from "neweb-pack";
|
7 | import { ServerPageRenderer } from "neweb-react/server";
|
8 | import { Application, SeancesManager, Server } from "neweb-server";
|
9 | import { join, resolve } from "path";
|
10 | import SessionFileStore = require("session-file-store");
|
11 | import SocketIO = require("socket.io");
|
12 | import ExpressHttpHandler from "./ExpressHttpHandler";
|
13 | import ModuleServer from "./ModulesServer";
|
14 | import NewebServerPageRenderer from "./neweb-components/server/PageRenderer";
|
15 | import SessionsManager from "./SessionsManager";
|
16 | import SocketIOClient from "./SocketIOClient";
|
17 | export interface IServerBootstrapConfig {
|
18 | rootPath: string;
|
19 | port: number;
|
20 | env: "production" | "development";
|
21 | expressApp?: express.Express;
|
22 | engine?: "react" | "neweb";
|
23 | }
|
24 | class ServerBootstrap {
|
25 | protected engine: "react" | "neweb" = "neweb";
|
26 | constructor(protected config: IServerBootstrapConfig) {
|
27 | this.engine = this.config.engine || "neweb";
|
28 | }
|
29 | public async start() {
|
30 | const rootPath = this.config.rootPath;
|
31 | const port = this.config.port;
|
32 | const env = this.config.env;
|
33 |
|
34 | const appPath = resolve(join(rootPath, "app"));
|
35 | const modulesPath = join(appPath, "..", "modules");
|
36 | const sessionsPath = join(appPath, "..", "sessions");
|
37 |
|
38 | if (env === "development") {
|
39 | debug.enable("*,-engine:*,-engine,-socket.io-parser,-socket.io:*");
|
40 | }
|
41 | const expressApp = this.config.expressApp ? this.config.expressApp : express();
|
42 |
|
43 | const modulePacker = new ModulePacker({
|
44 | appRoot: appPath,
|
45 | excludedModules: ["react", "react-dom", "neweb", "neweb-components"],
|
46 | modulesPath,
|
47 | REQUIRE_FUNC_NAME,
|
48 | disableCacheForLocalModules: env === "development",
|
49 | webpackConfig: {
|
50 | module: {
|
51 | rules: [{
|
52 | test: /\.html$/,
|
53 | use: [{
|
54 | loader: require.resolve("html-loader"),
|
55 | options: {
|
56 | minimize: true,
|
57 | },
|
58 | }],
|
59 | }],
|
60 | },
|
61 | },
|
62 | });
|
63 |
|
64 | const app = new Application({
|
65 | appDir: appPath,
|
66 | env,
|
67 | modulePacker,
|
68 | });
|
69 | await app.init();
|
70 |
|
71 | const appConfig = await app.getConfig();
|
72 |
|
73 | const sessionsFileStore = SessionFileStore(expressSession);
|
74 | const sessionsStorage = new sessionsFileStore({
|
75 | path: sessionsPath,
|
76 | retries: 1,
|
77 | ttl: appConfig.session.ttl || 86400 * 100000,
|
78 | });
|
79 | const session = expressSession({
|
80 | secret: appConfig.session.secret,
|
81 | saveUninitialized: true,
|
82 | resave: true,
|
83 | store: sessionsStorage,
|
84 | });
|
85 |
|
86 |
|
87 | expressApp.use(express.static(resolve(join(appPath, "public"))));
|
88 | expressApp.get("/bundle." + env + ".js", (_, res) =>
|
89 | res.sendFile(resolve(join(__dirname, "..", "dist", "bundle." + env + "." + this.engine + ".js"))));
|
90 |
|
91 | const sessionsManager = new SessionsManager({
|
92 | sessionsPath,
|
93 | sessionsStorage,
|
94 | });
|
95 | const seancesManager = new SeancesManager({
|
96 | app,
|
97 | sessionsManager,
|
98 | });
|
99 |
|
100 | const pageRenderer = this.engine === "react" ? new ServerPageRenderer({
|
101 | app,
|
102 | }) : new NewebServerPageRenderer({
|
103 | app,
|
104 | });
|
105 | const server = new Server({
|
106 | app,
|
107 | seancesManager,
|
108 | pageRenderer,
|
109 | });
|
110 | const modulesServer = new ModuleServer({
|
111 | modulesPath,
|
112 | });
|
113 | expressApp.get("/modules/:type/:name/:version.js", modulesServer.handle);
|
114 |
|
115 | const expressHandler = new ExpressHttpHandler({
|
116 | app: expressApp,
|
117 | server,
|
118 | });
|
119 | expressApp.use(session, expressHandler.handle);
|
120 |
|
121 | const httpServer = createServer(expressApp);
|
122 |
|
123 | const io = SocketIO();
|
124 | io.use((socket, next) => {
|
125 | session(socket.request, socket.request.res, next);
|
126 | });
|
127 | io.on("connection", (socket) => {
|
128 | socket.on(RemoteMessageType.Initialize, async ({ seanceId }: { seanceId: string }) => {
|
129 | const socketClient = new SocketIOClient({
|
130 | socket,
|
131 | seanceId,
|
132 | });
|
133 | const request = await socketClient.getRequest();
|
134 | server.connectClient({
|
135 | seanceId,
|
136 | client: socketClient,
|
137 | request,
|
138 | });
|
139 | });
|
140 | });
|
141 | io.attach(httpServer);
|
142 |
|
143 | httpServer.listen(port, (err: any) => {
|
144 | if (err) {
|
145 | debug("http")("Error server starting", err);
|
146 | process.exit(1);
|
147 | return;
|
148 | }
|
149 | debug("http")("Http server at port ", port);
|
150 | });
|
151 | }
|
152 | }
|
153 | export default ServerBootstrap;
|