mirror of
https://github.com/unraid/api.git
synced 2026-04-29 03:29:34 -05:00
fix: servers endpoint not updating when mothership updates
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { pluginManager, pubsub, utils, bus, errors, states, modules, apiManager, log } from '@unraid/core';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import dee from '@gridplus/docker-events';
|
||||
import { setIntervalAsync } from 'set-interval-async/dynamic';
|
||||
import GraphQLJSON from 'graphql-type-json';
|
||||
@@ -101,7 +102,7 @@ const getServers = async (): Promise<Server[]> => {
|
||||
|
||||
// For now use the my_servers key
|
||||
// Later we should return the correct one for the current user with the correct scope, etc.
|
||||
const apikey = apiManager.getValidKeys().find(key => key.name === 'my_servers')?.key.toString();
|
||||
const apiKey = apiManager.getValidKeys().find(key => key.name === 'my_servers')?.key.toString();
|
||||
|
||||
// No cached servers found
|
||||
if (!cachedServers) {
|
||||
@@ -113,19 +114,23 @@ const getServers = async (): Promise<Server[]> => {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: 'query($apikey: String!) { servers @auth(apiKey: $apikey) { owner { username url avatar } guid apikey name status wanip lanip localurl remoteurl } }',
|
||||
query: 'query($apiKey: String!) { servers @auth(apiKey: $apiKey) { owner { username url avatar } guid apikey name status wanip lanip localurl remoteurl } }',
|
||||
variables: {
|
||||
apikey
|
||||
apiKey
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(({ data }) => data.servers as Promise<CachedServer[]>);
|
||||
.then(({ data }) => data.servers as Promise<CachedServer[]>)
|
||||
.catch(error => {
|
||||
Sentry.captureException(error);
|
||||
return [];
|
||||
});
|
||||
|
||||
log.debug('Using upstream for /servers endpoint');
|
||||
|
||||
// No servers found
|
||||
if (servers.length === 0) {
|
||||
if (!servers || servers.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -153,7 +158,7 @@ const getServers = async (): Promise<Server[]> => {
|
||||
avatar: ''
|
||||
},
|
||||
guid,
|
||||
apikey,
|
||||
apikey: apiKey,
|
||||
name,
|
||||
status: 'online',
|
||||
wanip,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import fs from 'fs';
|
||||
import WebSocket from 'ws';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { utils, paths, states, log } from '@unraid/core';
|
||||
import { MOTHERSHIP_RELAY_WS_LINK, INTERNAL_WS_LINK, ONE_MINUTE } from './consts';
|
||||
import { DynamixConfig } from '@unraid/core/dist/lib/types';
|
||||
import { MOTHERSHIP_RELAY_WS_LINK, INTERNAL_WS_LINK, ONE_MINUTE } from '../consts';
|
||||
import { subscribeToServersEndpoint } from './subscribe-to-servers-endpoint';
|
||||
|
||||
const { loadState } = utils;
|
||||
const { varState } = states;
|
||||
@@ -79,6 +81,7 @@ export const connectToMothership = async (wsServer: WebSocket.Server, currentRet
|
||||
const lanIp = states.networkState.data.find(network => network.ipaddr[0]).ipaddr[0] || '';
|
||||
const machineId = `${await utils.getMachineId()}`;
|
||||
let localGraphqlApi: WebSocket;
|
||||
let mothershipServersEndpoint;
|
||||
|
||||
// Connect to mothership's relay endpoint
|
||||
// Keep reference outside this scope so we can disconnect later
|
||||
@@ -109,6 +112,7 @@ export const connectToMothership = async (wsServer: WebSocket.Server, currentRet
|
||||
|
||||
// Errors
|
||||
localGraphqlApi.on('error', error => {
|
||||
Sentry.captureException(error);
|
||||
log.error('ws:local-relay', 'error', error);
|
||||
});
|
||||
|
||||
@@ -127,7 +131,7 @@ export const connectToMothership = async (wsServer: WebSocket.Server, currentRet
|
||||
payload: {
|
||||
'x-api-key': apiKey
|
||||
}
|
||||
}));
|
||||
}));
|
||||
});
|
||||
|
||||
// Relay message back to mothership
|
||||
@@ -141,6 +145,9 @@ export const connectToMothership = async (wsServer: WebSocket.Server, currentRet
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Connect to mothership's "servers" endpoint
|
||||
|
||||
});
|
||||
|
||||
// Relay is closed
|
||||
@@ -158,6 +165,9 @@ export const connectToMothership = async (wsServer: WebSocket.Server, currentRet
|
||||
// Clear all listeners before running this again
|
||||
relay?.removeAllListeners();
|
||||
|
||||
// Stop subscriptions with mothership
|
||||
mothershipServersEndpoint.unsubscribe();
|
||||
|
||||
// We likely closed this
|
||||
// This is usually because the API key is updated
|
||||
if (code === 4200) {
|
||||
@@ -171,7 +181,7 @@ export const connectToMothership = async (wsServer: WebSocket.Server, currentRet
|
||||
log.debug('Invalid API key, waiting for new key...');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reconnect
|
||||
setTimeout(async () => {
|
||||
@@ -0,0 +1,46 @@
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { pubsub } from '@unraid/core';
|
||||
import { SubscriptionClient } from 'graphql-subscriptions-client';
|
||||
import { MOTHERSHIP_GRAPHQL_LINK } from '../consts';
|
||||
import { userCache, CachedServers } from '../cache';
|
||||
|
||||
const client = new SubscriptionClient(MOTHERSHIP_GRAPHQL_LINK, {
|
||||
reconnect: true,
|
||||
lazy: true, // only connect when there is a query
|
||||
connectionCallback: (error) => {
|
||||
if (error) {
|
||||
Sentry.captureException(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const subscribeToServersEndpoint = (apiKey: string) => {
|
||||
return client.request({
|
||||
query: `subscription servers ($apiKey: String!) {
|
||||
servers @auth(apiKey: $apiKey)
|
||||
}`,
|
||||
variables: {
|
||||
apiKey
|
||||
}
|
||||
})
|
||||
.subscribe({
|
||||
next({ data, errors }) {
|
||||
if (errors) {
|
||||
// Send all errors to Sentry
|
||||
errors.forEach((error: Error) => {
|
||||
Sentry.captureException(error);
|
||||
});
|
||||
}
|
||||
if (data) {
|
||||
const obj = {
|
||||
servers: data.servers
|
||||
};
|
||||
|
||||
// Update internal cache
|
||||
userCache.set<CachedServers>('mine', obj);
|
||||
// Update subscribers
|
||||
pubsub.publish('servers', obj);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
+7
-4
@@ -1,14 +1,16 @@
|
||||
/* eslint-disable camelcase */
|
||||
const path = require('path');
|
||||
|
||||
const SENTRY_DSN = 'https://335a7a44d1a048648a585fc4fa053d65@o427961.ingest.sentry.io/5439629';
|
||||
|
||||
const staging = {
|
||||
MOTHERSHIP_RELAY_WS_LINK: 'wss://staging.mothership.unraid.net/relay',
|
||||
SENTRY_DSN: 'https://335a7a44d1a048648a585fc4fa053d65@o427961.ingest.sentry.io/5439629'
|
||||
SENTRY_DSN
|
||||
};
|
||||
const production = {
|
||||
NODE_ENV: 'production',
|
||||
PORT: '/var/run/graphql-api.sock'
|
||||
}
|
||||
};
|
||||
|
||||
const envs = {
|
||||
env_development: {
|
||||
@@ -18,7 +20,8 @@ const envs = {
|
||||
PATHS_STATES: path.resolve(__dirname, './dev/states'),
|
||||
PATHS_DYNAMIX_DATA: '/tmp/dynamix/',
|
||||
PATHS_DYNAMIX_CONFIG: path.resolve(__dirname, './dev/dynamix.cfg'),
|
||||
DEBUG: true
|
||||
DEBUG: true,
|
||||
SENTRY_DSN
|
||||
},
|
||||
'env_safe-mode': {
|
||||
NODE_ENV: 'safe-mode'
|
||||
@@ -43,7 +46,7 @@ module.exports = {
|
||||
wait_ready: true,
|
||||
listen_timeout: 3000,
|
||||
exp_backoff_restart_delay: 100,
|
||||
max_memory_restart: '200M',
|
||||
max_memory_restart: '150M',
|
||||
env: {
|
||||
PROCESS_TITLE: 'graphql-api'
|
||||
},
|
||||
|
||||
Generated
+17
@@ -9741,6 +9741,23 @@
|
||||
"iterall": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"graphql-subscriptions-client": {
|
||||
"version": "github:OmgImAlexis/graphql-subscriptions-client#b5c6ad721da1c903612a0f942681803644b712fa",
|
||||
"from": "github:OmgImAlexis/graphql-subscriptions-client",
|
||||
"requires": {
|
||||
"backo2": "^1.0.2",
|
||||
"eventemitter3": "^3.1.2",
|
||||
"symbol-observable": "^1.2.0",
|
||||
"ws": "^7.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
|
||||
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"graphql-tag": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.11.0.tgz",
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"express": "^4.17.1",
|
||||
"graphql": "^15.3.0",
|
||||
"graphql-directive": "^0.2.1",
|
||||
"graphql-subscriptions-client": "github:OmgImAlexis/graphql-subscriptions-client",
|
||||
"graphql-tag": "^2.11.0",
|
||||
"graphql-type-json": "^0.3.2",
|
||||
"graphql-type-long": "^0.1.1",
|
||||
|
||||
Reference in New Issue
Block a user