xref: /expo/apps/bare-expo/relapse/server.js (revision 4db0ee32)
1import WebSocket from 'ws';
2
3import RelapseError from './RelapseError';
4import { RelapseCode } from './protocol';
5
6const defaultOptions = {
7  port: 8085,
8};
9
10let state;
11
12export async function startAsync(startOptions = {}) {
13  if (state) {
14    throw new RelapseError(`server`, 'Server is already started');
15  }
16  const options = { ...defaultOptions, ...startOptions };
17
18  const wss = new WebSocket.Server({ port: options.port });
19
20  state = {
21    ws: null,
22    server: wss,
23  };
24
25  wss.on('connection', ws => {
26    ws.on('message', message => {
27      const body = JSON.parse(message);
28      if (body.code === RelapseCode.SerializationError) {
29        console.error(`Client failed to serialize the arguments for a call to ${body.call}`);
30      } else if (body.code === RelapseCode.ProxyCall) {
31        if (!Array.isArray(body.arguments)) {
32          console.error(
33            `Proxied invocation of ${body.call} from the client did not send an array of arguments:`,
34            body.arguments
35          );
36        } else {
37          options.onEvent && options.onEvent(body.call, body.arguments);
38        }
39      }
40    });
41    state.ws = ws;
42    startOptions.onConnect && startOptions.onConnect(ws);
43  });
44
45  return async () => {
46    if (state.ws) state.ws.close();
47    return new Promise((resolve, reject) =>
48      wss.close(error => {
49        if (error) reject(error);
50        else resolve();
51      })
52    );
53  };
54}
55
56export function send(message) {
57  if (!state || !state.ws) {
58    throw new RelapseError(`server`, 'Server cannot send data');
59  }
60  state.ws.send(JSON.stringify(message));
61}
62