UNPKG

@betaflight/api-server

Version:

A GraphQL server to retreive data from betaflight flight controllers

132 lines 5.88 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createServer = void 0; /* eslint-disable react-hooks/rules-of-hooks */ const apollo_server_express_1 = require("apollo-server-express"); const debug_1 = __importDefault(require("debug")); const express_1 = __importDefault(require("express")); const http_1 = __importDefault(require("http")); const ws_1 = __importDefault(require("ws")); const ws_2 = require("graphql-ws/lib/use/ws"); const graphql_1 = require("graphql"); const get_port_1 = __importDefault(require("get-port")); const subscriptions_transport_ws_1 = require("subscriptions-transport-ws"); const graphql_ws_1 = require("graphql-ws"); const api_graph_1 = require("@betaflight/api-graph"); const log = (0, debug_1.default)("api-graph:errors"); // eslint-disable-next-line import/prefer-default-export const createServer = ({ mocked, persistedQueries, artifactsDirectory = `${__dirname}/artifacts/`, } = {}) => { const persistedQueriesStore = persistedQueries ? Object.fromEntries(Object.entries(persistedQueries).map(([id, query]) => [ id, (0, graphql_1.parse)(query), ])) : undefined; const app = (0, express_1.default)(); const server = http_1.default.createServer(app); app.use("/job-artifacts", express_1.default.static(artifactsDirectory)); const contextGenerator = mocked ? (0, api_graph_1.mockedDeviceContext)({ artifactsDir: artifactsDirectory }) : (0, api_graph_1.context)({ artifactsDir: artifactsDirectory }); // Create a graphql server which will work with // graphql-ws const graphqlWsServer = new ws_1.default.Server({ noServer: true, }); (0, ws_2.useServer)({ context: contextGenerator, onSubscribe: persistedQueriesStore ? (_ctx, msg) => { const document = persistedQueriesStore[msg.payload.query]; if (!document) { // for extra security you only allow the queries from the store throw new apollo_server_express_1.ApolloError("404: Query Not Found"); } return { document, schema: api_graph_1.schema, variableValues: msg.payload.variables, }; } : undefined, schema: api_graph_1.schema, execute: async (args) => { var _a; const result = await (0, graphql_1.execute)(args); (_a = result.errors) === null || _a === void 0 ? void 0 : _a.filter((e) => !e.message.includes("not open") && !e.message.includes("is not active")).forEach((error) => log(error)); return result; }, subscribe: graphql_1.subscribe, }, graphqlWsServer); // And one which works with legacy protocol (subscriptions-transport-ws) const subscriptionTransportWsServer = new ws_1.default.Server({ noServer: true, }); subscriptions_transport_ws_1.SubscriptionServer.create({ schema: api_graph_1.schema, execute: graphql_1.execute, subscribe: graphql_1.subscribe, onConnect: () => contextGenerator(), }, subscriptionTransportWsServer); // And create an apollo http server which // will handle HTTP traffic const apolloServer = new apollo_server_express_1.ApolloServer({ schema: api_graph_1.schema, context: contextGenerator, formatError: (error) => { log(error); return error; }, }); // route to the correct graphql server // based on the received protocol server.on("upgrade", (req, socket, head) => { // extract websocket subprotocol from header const protocol = req.headers["sec-websocket-protocol"]; const protocols = Array.isArray(protocol) ? protocol : protocol === null || protocol === void 0 ? void 0 : protocol.split(",").map((p) => p.trim()); // decide which websocket server to use const wss = (protocols === null || protocols === void 0 ? void 0 : protocols.includes(subscriptions_transport_ws_1.GRAPHQL_WS)) && // subscriptions-transport-ws subprotocol !protocols.includes(graphql_ws_1.GRAPHQL_TRANSPORT_WS_PROTOCOL) // graphql-ws subprotocol ? subscriptionTransportWsServer : // graphql-ws will welcome its own subprotocol and // gracefully reject invalid ones. if the client supports // both transports, graphql-ws will prevail graphqlWsServer; wss.handleUpgrade(req, socket, head, (s) => { wss.emit("connection", s, req); }); }); return { schema: api_graph_1.schema, context: contextGenerator, startMockTicks: api_graph_1.startMockDevice, apolloServer, rest: app, listen: async ({ port, hostname }) => { const listeningPort = port !== null && port !== void 0 ? port : (await (0, get_port_1.default)({ port: 9000, host: hostname })); await apolloServer.start(); apolloServer.applyMiddleware({ app }); return new Promise((resolve, reject) => { try { server.listen(listeningPort, hostname, () => { if (mocked) { (0, api_graph_1.startMockDevice)(); } resolve(listeningPort); }); } catch (e) { reject(e); } }); }, }; }; exports.createServer = createServer; //# sourceMappingURL=index.js.map