fix: mothership connection, unneeded logging and servers endpoint

This commit is contained in:
Alexis Tyler
2020-09-19 10:05:57 +09:30
parent 15f2f7c231
commit 62eaf0feee
6 changed files with 108 additions and 104 deletions

35
app/consts.ts Normal file
View File

@@ -0,0 +1,35 @@
import { config } from '@unraid/core';
const internalWsAddress = () => {
const port = config.get('graphql-api-port');
return isNaN(port as any)
// Unix Socket
? `ws+unix:${port}`
// Numbered port
: `ws://localhost:${port}`;
}
/**
* One second in milliseconds.
*/
export const ONE_SECOND = 1000;
/**
* One minute in milliseconds.
*/
export const ONE_MINUTE = 60 * ONE_SECOND;
/**
* Relay ws link.
*/
export const MOTHERSHIP_RELAY_WS_LINK = process.env.RELAY_WS_LINK ? process.env.RELAY_WS_LINK : 'wss://mothership.unraid.net/relay';
/**
* Graphql link.
*/
export const MOTHERSHIP_GRAPHQL_LINK = process.env.RELAY_WS_LINK ? process.env.RELAY_WS_LINK : 'https://mothership.unraid.net/graphql';
/**
* Internal ws link.
*/
export const INTERNAL_WS_LINK = process.env.INTERNAL_WS_LINK ? process.env.INTERNAL_WS_LINK : internalWsAddress();

View File

@@ -9,9 +9,11 @@ import { setIntervalAsync } from 'set-interval-async/dynamic';
import GraphQLJSON from 'graphql-type-json';
import GraphQLLong from 'graphql-type-long';
import GraphQLUUID from 'graphql-type-uuid';
import fetch from 'cross-fetch';
import { run, publish } from '../../run';
import { userCache, CachedServer, CachedServers } from '../../cache';
import { hasSubscribedToChannel, canPublishToChannel } from '../../ws';
import { hasSubscribedToChannel } from '../../ws';
import { MOTHERSHIP_GRAPHQL_LINK } from '../../consts';
const { ensurePermission } = utils;
const { usersState, varState, networkState } = states;
@@ -37,11 +39,6 @@ dee.on('*', async (data: { Type: string }) => {
return;
}
// Don't publish when we have no clients
if (!canPublishToChannel('info')) {
return;
}
const { json } = await modules.getApps();
publish('info', 'UPDATED', json);
});
@@ -50,10 +47,6 @@ dee.listen();
// This needs to be fixed to run from events
setIntervalAsync(async () => {
if (!canPublishToChannel('services')) {
return;
}
// @todo: Create a system user for this
const user = usersState.findOne({ name: 'root' });
@@ -100,43 +93,67 @@ type makeNullUndefinedAndOptional<T> = {
type Server = makeNullUndefinedAndOptional<CachedServer>;
const getServers = (): Server[] => {
const servers = userCache.get<CachedServers>('mine')?.servers ?? [];
const getServers = async (): Promise<Server[]> => {
const cachedServers = userCache.get<CachedServers>('mine')?.servers;
// 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.
const apikey = apiManager.getValidKeys().find(key => key.name === 'my_servers')?.key.toString();
const name = varState?.data?.name;
const wanip = null;
const lanip = networkState.data[0].ipaddr[0];
const localurl = `http://${lanip}:${varState?.data?.port}`;
const remoteurl = null;
return [{
owner: {
username: 'root',
url: '',
avatar: ''
// No cached servers found
if (!cachedServers) {
// Fetch servers from mothership
const servers = await fetch(MOTHERSHIP_GRAPHQL_LINK, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
guid,
apikey,
name,
status: 'online',
wanip,
lanip,
localurl,
remoteurl
}];
body: JSON.stringify({
query: "{ servers { owner { username url avatar } guid apikey name status wanip lanip localurl remoteurl } }"
})
}).then(r => r.json() as Promise<CachedServer[]>);
log.debug('Using upstream for /servers endpoint');
// No servers found
if (servers.length === 0) {
return [];
}
console.log({servers});
// @todo: Cache servers
// userCache.set<CachedServers>('mine', {
// servers
// })
// Return servers from mothership
return servers;
}
log.debug('Using upstream for /servers endpoint');
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.
const apikey = apiManager.getValidKeys().find(key => key.name === 'my_servers')?.key.toString();
const name = varState?.data?.name;
const wanip = null;
const lanip = networkState.data[0].ipaddr[0];
const localurl = `http://${lanip}:${varState?.data?.port}`;
const remoteurl = null;
// Return servers from upstream cache
return servers;
return [{
owner: {
username: 'root',
url: '',
avatar: ''
},
guid,
apikey,
name,
status: 'online',
wanip,
lanip,
localurl,
remoteurl
}];
};
export const resolvers = {
@@ -152,7 +169,7 @@ export const resolvers = {
});
// Single server
return getServers().find(server => server.name === name);
return getServers().then(server => server.find(server => server.name === name));
},
servers(_: unknown, __: unknown, context: Context) {
ensurePermission(context.user, {

View File

@@ -1,6 +1,7 @@
import fs from 'fs';
import WebSocket from 'ws';
import { utils, paths, states, config } from '@unraid/core';
import { utils, paths, states } from '@unraid/core';
import { MOTHERSHIP_RELAY_WS_LINK, INTERNAL_WS_LINK } from './consts';
import { DynamixConfig } from '@unraid/core/dist/lib/types';
const log = console;
@@ -11,34 +12,6 @@ const { varState } = states;
process.on('uncaughtException', log.debug);
process.on('unhandledRejection', log.debug);
const internalWsAddress = () => {
const port = config.get('graphql-api-port');
return isNaN(port as any)
// Unix Socket
? `ws+unix:${port}`
// Numbered port
: `ws://localhost:${port}`;
}
/**
* One second in milliseconds.
*/
const ONE_SECOND = 1000;
/**
* One minute in milliseconds.
*/
const ONE_MINUTE = 60 * ONE_SECOND;
/**
* Relay ws link.
*/
const RELAY_WS_LINK = process.env.RELAY_WS_LINK ? process.env.RELAY_WS_LINK : 'wss://relay.unraid.net';
/**
* Internal ws link.
*/
const INTERNAL_WS_LINK = process.env.INTERNAL_WS_LINK ? process.env.INTERNAL_WS_LINK : internalWsAddress();
/**
* Get a number between the lowest and highest value.
* @param low Lowest value.
@@ -110,7 +83,7 @@ export const connectToMothership = async (wsServer: WebSocket.Server, currentRet
// Connect to mothership's relay endpoint
// Keep reference outside this scope so we can disconnect later
relay = new WebSocket(RELAY_WS_LINK, ['graphql-ws'], {
relay = new WebSocket(MOTHERSHIP_RELAY_WS_LINK, ['graphql-ws'], {
headers: {
'x-api-key': apiKey,
'x-flash-guid': varState.data?.flashGuid ?? '',

View File

@@ -1,6 +1,5 @@
import { CoreResult } from '@unraid/core/dist/lib/types';
import { pubsub, utils, log } from '@unraid/core';
import { canPublishToChannel } from './ws';
const { debugTimer } = utils;
@@ -19,11 +18,6 @@ export const publish = (channel: string, mutation: string, node?: {}) => {
}
};
if (!canPublishToChannel(channel)) {
log.debug(`can't post to ${channel}`);
return;
}
// Update clients
const fieldName = Object.keys(data)[0];
pubsub.publish(channel, {

View File

@@ -1,5 +1,3 @@
import { log } from '@unraid/core';
interface subscription {
total: number
channels: string[]
@@ -70,22 +68,3 @@ export const wsHasDisconnected = (id: string) => {
subscriptions[id].total = 0;
subscriptions[id].channels = [];
};
// Only allows function to publish to pubsub when clients are online and are connected to the specific channel
// the reason we do this is otherwise pubsub will cause a memory leak
export const canPublishToChannel = (channel: string) => {
// No ws connections
if (getWsConectionCount() === 0) {
return false;
}
// No ws connections to this channel
const channelConnectionCount = getWsConectionCountInChannel(channel);
if (channelConnectionCount === 0) {
return false;
}
const plural = channelConnectionCount !== 1;
log.debug(`Allowing publish to "${channel}" as there ${plural ? 'are' : 'is'} ${channelConnectionCount} connection${plural ? 's' : ''} in that channel.`);
return true;
};

14
package-lock.json generated
View File

@@ -1223,7 +1223,7 @@
}
},
"@unraid/core": {
"version": "github:unraid/core#f1569b3a663d73452c0aa9078e971a2788c4a208",
"version": "github:unraid/core#adeb036d27d4c0b00b96012b7e97eac0c783e4f9",
"from": "github:unraid/core",
"requires": {
"accesscontrol": "^2.2.1",
@@ -1273,6 +1273,7 @@
"path-exists": "^4.0.0",
"path-type": "4.0.0",
"pify": "^5.0.0",
"pretty-bytes": "^5.4.1",
"pretty-ms": "^7.0.0",
"redact-secrets": "github:omgimalexis/redact-secrets",
"request": "^2.88.2",
@@ -14349,6 +14350,11 @@
"fast-diff": "^1.1.2"
}
},
"pretty-bytes": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz",
"integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA=="
},
"pretty-ms": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.0.tgz",
@@ -16388,9 +16394,9 @@
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
},
"systeminformation": {
"version": "4.27.4",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.27.4.tgz",
"integrity": "sha512-VlFlxbkvSddq16F/nHC0GRaKBZOKWbAuRbck4G9muHhCUcDKskhNkVbaBBFxxqwcp0IyVozLS96eAVmkRZTG4w=="
"version": "4.27.5",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.27.5.tgz",
"integrity": "sha512-EysogxKqREk54ZYDEFcsCODv8GymKZcyiSfegYit8dKhPjzuQr+KX4GFHjssWjYrWFEIM2bYNsFrZX5eufeAXg=="
},
"table": {
"version": "5.4.6",