@betaflight/api-server
Version:
A GraphQL server to retreive data from betaflight flight controllers
132 lines • 5.88 kB
JavaScript
;
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