mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
a91d493ffc
Summary: - Substantial refactoring of the logic when the server fails to send some messages to a client. - Add seqId numbers to server messages to ensure reliable order. - Add a needReload flag in clientConnect for a clear indication whent the browser client needs to reload the app. - Reproduce some potential failure scenarios in a test case (some of which previously could have led to incorrectly ordered messages). - Convert other Comm tests to typescript. - Tweak logging of Comm and Client to be slightly more concise (in particular, avoid logging sessionId) Note that despite the big refactoring, this only addresses a fairly rare situation, with websocket failures while server is trying to send to the client. It includes no improvements for failures while the client is sending to the server. (I looked for an existing library that would take care of these issues. A relevant article I found is https://docs.microsoft.com/en-us/azure/azure-web-pubsub/howto-develop-reliable-clients, but it doesn't include a library for both ends, and is still in review. Other libraries with similar purposes did not inspire enough confidence.) Test Plan: New test cases, which reproduce some previously problematic scenarios. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D3470
67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
import {getAppRoot} from 'app/server/lib/places';
|
|
import {fromCallback} from 'app/server/lib/serverUtils';
|
|
import * as express from 'express';
|
|
import * as http from 'http';
|
|
import {AddressInfo, Socket} from 'net';
|
|
import * as path from 'path';
|
|
import {fixturesRoot} from 'test/server/testUtils';
|
|
|
|
export interface Serving {
|
|
url: string;
|
|
shutdown: () => Promise<void>;
|
|
}
|
|
|
|
|
|
// Adds static files from a directory.
|
|
// By default exposes /fixture/sites
|
|
export function addStatic(app: express.Express, rootDir?: string) {
|
|
// mix in a copy of the plugin api
|
|
app.use(/^\/(grist-plugin-api.js)$/, (req, res) =>
|
|
res.sendFile(req.params[0], {root:
|
|
path.resolve(getAppRoot(), "static")}));
|
|
app.use(express.static(rootDir || path.resolve(fixturesRoot, "sites"), {
|
|
setHeaders: (res) => {
|
|
res.set("Access-Control-Allow-Origin", "*");
|
|
}
|
|
}));
|
|
}
|
|
|
|
// Serve from a directory.
|
|
export async function serveStatic(rootDir: string): Promise<Serving> {
|
|
return serveSomething(app => addStatic(app, rootDir));
|
|
}
|
|
|
|
// Serve a string of html.
|
|
export async function serveSinglePage(html: string): Promise<Serving> {
|
|
return serveSomething(app => {
|
|
app.get('', (req, res) => res.send(html));
|
|
});
|
|
}
|
|
|
|
export function serveCustomViews(): Promise<Serving> {
|
|
return serveStatic(path.resolve(fixturesRoot, "sites"));
|
|
}
|
|
|
|
export async function serveSomething(setup: (app: express.Express) => void, port= 0): Promise<Serving> {
|
|
const app = express();
|
|
const server = http.createServer(app);
|
|
await fromCallback(cb => server.listen(port, cb));
|
|
|
|
const connections = new Set<Socket>();
|
|
server.on('connection', (conn) => {
|
|
connections.add(conn);
|
|
conn.on('close', () => connections.delete(conn));
|
|
});
|
|
|
|
async function shutdown() {
|
|
await fromCallback(cb => server.close(cb));
|
|
for (const conn of connections) { conn.destroy(); }
|
|
}
|
|
|
|
port = (server.address() as AddressInfo).port;
|
|
app.set('port', port);
|
|
setup(app);
|
|
const url = `http://localhost:${port}`;
|
|
return {url, shutdown};
|
|
}
|