Skip to content

Commit

Permalink
Auto-spawn a genie-client on startup
Browse files Browse the repository at this point in the history
  • Loading branch information
gcampax committed Nov 18, 2021
1 parent 4812e91 commit 44a450d
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 4 deletions.
39 changes: 36 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@js-temporal/polyfill": "^0.2.0",
"body-parser": "^1.17.2",
"color-scheme": "^1.0.0",
"configparser": "^0.3.9",
"connect-flash": "^0.1.1",
"cookie-parser": "^1.4.6",
"csurf": "^1.9.0",
Expand All @@ -35,6 +36,7 @@
"serve-favicon": "^2.4.3",
"thingpedia": "^2.10.0-alpha.5",
"uuid": "^8.3.1",
"which": "^2.0.2",
"ws": "^7.5.5"
},
"devDependencies": {
Expand All @@ -56,6 +58,7 @@
"@types/passport-strategy": "^0.2.35",
"@types/q": "^1.5.5",
"@types/serve-static": "^1.13.10",
"@types/which": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"coveralls": "^3.1.1",
Expand Down
30 changes: 29 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@
process.on('unhandledRejection', (up) => { throw up; });

import * as Genie from 'genie-toolkit';
import which from 'which';
import * as fs from 'fs';

import WebFrontend from './frontend';
import type { ServerPlatform } from './service/platform';
import platform from './service/platform';
import ClientManager from './service/client-manager';

import * as Config from './config';

let _stopped = false;
let _running = false;
let _engine : Genie.AssistantEngine, _frontend : WebFrontend;
let _engine : Genie.AssistantEngine,
_frontend : WebFrontend,
_clientManager : ClientManager;

function handleStop() {
if (_running)
Expand Down Expand Up @@ -61,6 +66,26 @@ async function init(platform : ServerPlatform) {
await conversation.start();
}

function spawnClient() {
if (!process.env.PULSE_SERVER && !fs.existsSync(process.env.XDG_RUNTIME_DIR + '/pulse/native')) {
console.log('Skipping audio because PulseAudio is not available');
return;
}

which('genie-client', (err, resolved) => {
if (err) {
console.log(`Skipping audio because genie-client-cpp is not found: ${err}`);
return;
}

// great, we found it!
_clientManager = new ClientManager(Number(process.env.PORT || 3000));
_clientManager.start().catch((e) => {
console.error(`Failed to spawn genie-client-cpp: ${e}`);
});
});
}

async function main() {
process.on('SIGINT', handleStop);
process.on('SIGTERM', handleStop);
Expand Down Expand Up @@ -89,9 +114,12 @@ async function main() {
console.log('Ready');
if (!_stopped) {
_running = true;
spawnClient();
await _engine.run();
}
} finally {
if (_clientManager)
_clientManager.stop();
try {
await _engine.close();
} catch(error) {
Expand Down
86 changes: 86 additions & 0 deletions src/service/client-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*-
//
// This file is part of Almond
//
// Copyright 2021 The Board of Trustees of the Leland Stanford Junior University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Giovanni Campagna <gcampagn@cs.stanford.edu>

import * as crypto from 'crypto';
import * as path from 'path';
import * as child_process from 'child_process';
import ConfigParser from 'configparser';

import platform from './platform';

import * as Config from '../config';

/**
* Manage a genie client running in the same container/machine as almond-server
*/
export default class ClientManager {
private _child : child_process.ChildProcess|null;
private _port : number;

constructor(port : number) {
this._child = null;
this._port = port;
}

async start() {
const config = new ConfigParser();
const configfilepath = path.resolve(platform.getWritableDir(), 'config.ini');

try {
await config.readAsync(configfilepath);
} catch(e) {
if (e.code !== 'ENOENT')
throw e;
}

if (!config.hasSection('general'))
config.addSection('general');
config.set('general', 'url', `ws://127.0.0.1:${this._port}/api/conversation`);
config.set('general', 'conversationId', 'main');

if (Config.HOST_BASED_AUTHENTICATION === 'disabled') {
config.set('general', 'auth_mode', 'bearer');

const prefs = platform.getSharedPreferences();
let accessToken = prefs.get('access-token') as string|undefined;
if (accessToken === undefined) {
accessToken = crypto.randomBytes(32).toString('hex');
prefs.set('access-token', accessToken);
}

config.set('general', 'accessToken', accessToken);
} else {
config.set('general', 'auth_mode', 'none');
}

await config.writeAsync(configfilepath);

this._child = child_process.spawn('genie-client', {
stdio: 'inherit',
cwd: platform.getWritableDir(),
detached: false
});
}

async stop() {
if (this._child)
this._child.kill('SIGTERM');
}
}

0 comments on commit 44a450d

Please sign in to comment.