forked from cerc-io/laconic-console
fix: Add running bots tab. (#56)
* fix: Add bots resolver. * minot fix. * test commit. * add bot kill * Integration. * add refetch. * Lint. * Formatting fix. * Better error handling.
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
"react-dom": "^16.13.1",
|
||||
"source-map-support": "^0.5.12",
|
||||
"systeminformation": "^4.26.5",
|
||||
"tree-kill": "^1.2.2",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -21,8 +21,14 @@ type Query {
|
||||
signal_status: JSONResult!
|
||||
system_status: JSONResult!
|
||||
wns_status: JSONResult!
|
||||
bot_list: JSONResult!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
bot_kill(botId: String!): JSONResult!
|
||||
}
|
||||
|
||||
schema {
|
||||
query: Query
|
||||
mutation: Mutation
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// Copyright 2020 DXOS.org
|
||||
//
|
||||
|
||||
import { spawn } from 'child_process';
|
||||
import debug from 'debug';
|
||||
import fs from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import kill from 'tree-kill';
|
||||
|
||||
const DEFAULT_BOT_FACTORY_CWD = '.wire/bots';
|
||||
const SERVICE_CONFIG_FILENAME = 'service.yml';
|
||||
|
||||
const log = debug('dxos:console:server:resolvers');
|
||||
|
||||
const getBotFactoryTopic = (botFactoryCwd) => {
|
||||
// TODO(egorgripasov): Get topic from config or registry.
|
||||
const serviceFilePath = path.join(os.homedir(), botFactoryCwd || DEFAULT_BOT_FACTORY_CWD, SERVICE_CONFIG_FILENAME);
|
||||
if (fs.existsSync(serviceFilePath)) {
|
||||
const { topic } = yaml.safeLoad(fs.readFileSync(serviceFilePath));
|
||||
return topic;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const topic = getBotFactoryTopic();
|
||||
|
||||
const executeCommand = async (command, args, timeout = 10000) => {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn(command, args, { encoding: 'utf8' });
|
||||
|
||||
const stdout = [];
|
||||
const stderr = [];
|
||||
const timer = setTimeout(() => {
|
||||
try {
|
||||
kill(child.pid, 'SIGKILL');
|
||||
} catch (err) {
|
||||
log(`Can not kill ${command} process: ${err}`);
|
||||
}
|
||||
stderr.push('Timeout.');
|
||||
}, timeout);
|
||||
|
||||
child.stdout.on('data', (data) => stdout.push(data));
|
||||
|
||||
child.stderr.on('data', (data) => stderr.push(data));
|
||||
|
||||
child.on('exit', (code) => {
|
||||
clearTimeout(timer);
|
||||
resolve({
|
||||
code: code === null ? 1 : code,
|
||||
stdout: stdout.join('').trim(),
|
||||
stderr: stderr.join('').trim()
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getRunningBots = async () => {
|
||||
const command = 'wire';
|
||||
const args = ['bot', 'factory', 'status', '--topic', topic];
|
||||
|
||||
const { code, stdout, stderr } = await executeCommand(command, args);
|
||||
return {
|
||||
success: !code,
|
||||
bots: code ? [] : JSON.parse(stdout).bots || [],
|
||||
error: (stderr || code) ? stderr || stdout : undefined
|
||||
};
|
||||
};
|
||||
|
||||
const sendBotCommand = async (botId, botCommand) => {
|
||||
const command = 'wire';
|
||||
const args = ['bot', botCommand, '--topic', topic, '--bot-id', botId];
|
||||
|
||||
const { code, stdout, stderr } = await executeCommand(command, args);
|
||||
|
||||
return {
|
||||
success: !code,
|
||||
botId: code ? undefined : botId,
|
||||
error: (stderr || code) ? stderr || stdout : undefined
|
||||
};
|
||||
};
|
||||
|
||||
export const botsResolvers = {
|
||||
Query: {
|
||||
bot_list: async () => {
|
||||
const result = await getRunningBots();
|
||||
return {
|
||||
timestamp: new Date().toUTCString(),
|
||||
json: JSON.stringify(result)
|
||||
};
|
||||
}
|
||||
},
|
||||
Mutation: {
|
||||
bot_kill: async (_, { botId }) => {
|
||||
const result = await sendBotCommand(botId, 'kill');
|
||||
return {
|
||||
timestamp: new Date().toUTCString(),
|
||||
json: JSON.stringify(result)
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -8,6 +8,7 @@ import defaultsDeep from 'lodash.defaultsdeep';
|
||||
import { ipfsResolvers } from './ipfs';
|
||||
import { systemResolvers } from './system';
|
||||
import { logResolvers } from './log';
|
||||
import { botsResolvers } from './bots';
|
||||
|
||||
// eslint-disable-next-line
|
||||
const log = debug('dxos:console:server:resolvers');
|
||||
@@ -21,4 +22,4 @@ export const resolvers = defaultsDeep({
|
||||
// TODO(burdon): Auth.
|
||||
// https://www.apollographql.com/docs/apollo-server/data/errors/#codes
|
||||
|
||||
}, ipfsResolvers, systemResolvers, logResolvers);
|
||||
}, ipfsResolvers, systemResolvers, logResolvers, botsResolvers);
|
||||
|
||||
Reference in New Issue
Block a user