fix(mothership): cleanup reconnection events

This commit is contained in:
Alexis Tyler
2020-08-05 09:54:34 +09:30
parent e4955119cf
commit 90209a4816
6 changed files with 85 additions and 54 deletions
+7
View File
@@ -60,5 +60,12 @@ You should get something like this back.
Click the "Schema" and "Docs" button on the right side of the playground to learn more.
For exploring the schema visually I'd suggest using [Voyager](https://apis.guru/graphql-voyager/).
# Development
## Running this locally
```bash
NCHAN=disable DEBUG=true LOG_LEVEL=info PATHS_STATES=$(pwd)/dev/states PATHS_DYNAMIX_CONFIG=$(pwd)/dev/dynamix.cfg PORT=5000 node index.js
```
## License
Copyright 2019 Lime Technology Inc. All rights reserved.
+16 -11
View File
@@ -40,6 +40,7 @@ const baseTypes = [gql`
type Query {
# This should always be available even for guest users
welcome: Welcome! @func(module: "getWelcome")
online: Boolean!
info: Info!
pluginModule(plugin: String!, module: String!, params: JSON, result: String): JSON @func(result: "json")
}
@@ -279,19 +280,23 @@ const schema = makeExecutableSchema({
});
const ensureApiKey = (apiKeyToCheck: string) => {
// Check there is atleast one valid key
if (core.apiManager.getValidKeys().length !== 0) {
if (!apiKeyToCheck) {
throw new AppError('Missing API key.');
}
try {
// Check there is atleast one valid key
if (core.apiManager.getValidKeys().length !== 0) {
if (!apiKeyToCheck) {
throw new AppError('Missing API key.');
}
if (!apiManager.isValid(apiKeyToCheck)) {
throw new AppError('Invalid API key.');
}
} else {
if (process.env.NODE_ENV !== 'development') {
throw new AppError('No valid API keys active.');
if (!apiManager.isValid(apiKeyToCheck)) {
throw new AppError('Invalid API key.');
}
} else {
if (process.env.NODE_ENV !== 'development') {
throw new AppError('No valid API keys active.');
}
}
} catch {
throw new AppError('Invalid Api key.');
}
};
+10 -2
View File
@@ -3,7 +3,7 @@
* Written by: Alexis Tyler
*/
import { pluginManager, pubsub, utils, bus, errors, states, modules, apiManager } from '@unraid/core';
import { pluginManager, pubsub, utils, bus, errors, states, modules, apiManager, log } from '@unraid/core';
import dee from '@gridplus/docker-events';
import { setIntervalAsync } from 'set-interval-async/dynamic';
import GraphQLJSON from 'graphql-type-json';
@@ -105,6 +105,7 @@ const getServers = (): Server[] => {
// Fall back to locally generated data
if (servers.length === 0) {
log.debug('Falling back to local state for /servers endpoint');
const guid = varState?.data?.regGuid;
// For now use the my_servers key
// Later we should return the correct one for the current user with the correct scope, etc.
@@ -116,7 +117,11 @@ const getServers = (): Server[] => {
const remoteurl = null;
return [{
owner: null,
owner: {
username: 'root',
url: '',
avatar: ''
},
guid,
apikey,
name,
@@ -128,12 +133,15 @@ const getServers = (): Server[] => {
}];
}
log.debug('Using upstream for /servers endpoint');
// Return servers from upstream cache
return servers;
};
export const resolvers = {
Query: {
online: () => true,
info: () => ({}),
vms: () => ({}),
server(_: unknown, { name }, context: Context) {
+7 -4
View File
@@ -1,7 +1,7 @@
import fs from 'fs';
import request from 'request';
import WebSocket from 'ws';
import { log, utils, paths, states } from '@unraid/core';
import { log, utils, paths, states, config } from '@unraid/core';
import { DynamixConfig } from '@unraid/core/dist/lib/types';
import { userCache, CachedServer } from './cache';
@@ -88,7 +88,10 @@ const isServersPayload = (payload: any): payload is Servers => payload.topic ===
const forwardMessageToLocalSocket = (message: Message, apiKey: string) => {
log.debug(`Got a "${message.type}" request from mothership, forwarding to socket.`);
request.post('http://unix:/var/run/graphql-api.sock:/graphql', {
const port = config.get('graphql-api-port');
const localEndpoint = (!isNaN(port as number)) ? `localhost:${port}` : `unix:${port}:`;
const url = `http://${localEndpoint}/graphql`;
request.post(url, {
body: JSON.stringify({
operationName: null,
variables: {},
@@ -170,7 +173,7 @@ export const connectToMothership = async (wsServer, currentRetryAttempt: number
}
// Clear all listeners before running this again
mothership.removeAllListeners();
mothership?.removeAllListeners();
// Reconnect
setTimeout(async () => {
@@ -224,7 +227,7 @@ export const connectToMothership = async (wsServer, currentRetryAttempt: number
* Disconnect from mothership.
*/
export const disconnectFromMothership = async () => {
if (mothership) {
if (mothership && mothership.readyState !== 0) {
log.debug('Disconnecting from the proxy server.');
try {
mothership.close();
+19 -12
View File
@@ -150,19 +150,26 @@ export const server = {
const key = dotProp.get(loadState(filePath), 'remote.apikey');
return (key === undefined || String(key).trim() === '') ? undefined : key;
};
const startWatcher = () => {
watcher.on('raw', async () => {
const key = getApiKey();
const reconnect = async () => {
const key = getApiKey();
// Try and stop the last connection if it's still open
await disconnectFromMothership();
log.debug('my_servers API key was updated, restarting proxy connection.');
process.nextTick(() => {
if (key !== undefined) {
connectToMothership(wsServer);
}
});
// Try and stop the last connection if it's still open
await disconnectFromMothership();
log.debug('my_servers API key was updated, restarting proxy connection.');
process.nextTick(() => {
if (key !== undefined) {
connectToMothership(wsServer);
}
});
};
let timeout: NodeJS.Timeout;
// If we detect an event wait 0.5s before doing anything
const startWatcher = () => {
watcher.on('all', () => {
clearTimeout(timeout);
timeout = setTimeout(reconnect, 500);
});
};
+26 -25
View File
@@ -1184,7 +1184,7 @@
}
},
"@unraid/core": {
"version": "github:unraid/core#b0d36f199b88e6eed1150985cf4b620394febf49",
"version": "github:unraid/core#ef6dcac418b6313ac10cd1c042e82a541f88bace",
"from": "github:unraid/core",
"requires": {
"accesscontrol": "^2.2.1",
@@ -3825,6 +3825,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
@@ -3836,6 +3837,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -6321,9 +6323,9 @@
}
},
"docker-modem": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-2.1.3.tgz",
"integrity": "sha512-cwaRptBmYZwu/FyhGcqBm2MzXA77W2/E6eVkpOZVDk6PkI9Bjj84xPrXiHMA+OWjzNy+DFjgKh8Q+1hMR7/OHg==",
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-2.1.4.tgz",
"integrity": "sha512-vDTzZjjO1sXMY7m0xKjGdFMMZL7vIUerkC3G4l6rnrpOET2M6AOufM8ajmQoOB+6RfSn6I/dlikCUq/Y91Q1sQ==",
"requires": {
"debug": "^4.1.1",
"readable-stream": "^3.5.0",
@@ -6352,11 +6354,10 @@
}
},
"dockerode": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.2.0.tgz",
"integrity": "sha512-C+y/W4Kks7YLBsfUOTMkk1IVilb4cdj+rE+UZ5hnE+rpcn2frSs7kX+6H8GteTqHcv8sln+GyxuP1qdno3IzIw==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.2.1.tgz",
"integrity": "sha512-XsSVB5Wu5HWMg1aelV5hFSqFJaKS5x1aiV/+sT7YOzOq1IRl49I/UwV8Pe4x6t0iF9kiGkWu5jwfvbkcFVupBw==",
"requires": {
"concat-stream": "~2.0.0",
"docker-modem": "^2.1.0",
"tar-fs": "~2.0.1"
},
@@ -8869,9 +8870,9 @@
},
"dependencies": {
"@types/node": {
"version": "9.6.56",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.56.tgz",
"integrity": "sha512-Cq4pUCsBL6H7X0HFAOap75lmQqcnSmUDSP0R03lz9UsxRvBu5QsnKLLgIoitlFBX+j6LmciWYQAbOSmGMi7vwA=="
"version": "9.6.57",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.57.tgz",
"integrity": "sha512-588MBlPWKeJFshLmnYbqMEaM3NaJFCVZFgpQ5rQxKCVXMNw2Gs7sTORvCDlaPBP6AabiIvmd22eT9fcIvTeZUw=="
}
}
},
@@ -9449,11 +9450,11 @@
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"har-validator": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"requires": {
"ajv": "^6.5.5",
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
}
},
@@ -10385,9 +10386,9 @@
}
},
"is-observable": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.0.0.tgz",
"integrity": "sha512-fhBZv3eFKUbyHXZ1oHujdo2tZ+CNbdpdzzlENgCGZUC8keoGxUew2jYFLYcUB4qo7LDD03o4KK11m/QYD7kEjg=="
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz",
"integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw=="
},
"is-path-cwd": {
"version": "2.2.0",
@@ -14667,7 +14668,7 @@
}
},
"redact-secrets": {
"version": "github:OmgImAlexis/redact-secrets#793a0bc696e1be69af6d65e6884177db9659976f",
"version": "github:OmgImAlexis/redact-secrets#126cb8140fffe9b82e8864d191e24eedd0364a00",
"from": "github:OmgImAlexis/redact-secrets",
"requires": {
"is-secret": "^1.0.0",
@@ -15735,9 +15736,9 @@
},
"dependencies": {
"@types/node": {
"version": "9.6.56",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.56.tgz",
"integrity": "sha512-Cq4pUCsBL6H7X0HFAOap75lmQqcnSmUDSP0R03lz9UsxRvBu5QsnKLLgIoitlFBX+j6LmciWYQAbOSmGMi7vwA=="
"version": "9.6.57",
"resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.57.tgz",
"integrity": "sha512-588MBlPWKeJFshLmnYbqMEaM3NaJFCVZFgpQ5rQxKCVXMNw2Gs7sTORvCDlaPBP6AabiIvmd22eT9fcIvTeZUw=="
}
}
},
@@ -16578,9 +16579,9 @@
}
},
"tracer": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/tracer/-/tracer-1.1.2.tgz",
"integrity": "sha512-SlXPQJEozEvtPLwOX+viPh36WL9SaH3a2q459aRH41nqqR2QGgPZ9em/ZaCeKLeEQMxzYUsAmATmFID/INIL3g==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/tracer/-/tracer-1.1.3.tgz",
"integrity": "sha512-/h/dbzKRLtaAx07wwEGLg7dPzDKWQX6wcHnQEqlBTO7e/fLHhRcwxEcJd0+VITmn6pCK4CjDjXahCu0+TkKaDA==",
"requires": {
"colors": "1.4.0",
"dateformat": "3.0.3",