mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 14:13:47 +02:00
resolve conflicts on merge with birarda/console
This commit is contained in:
commit
7632a8af42
8 changed files with 236 additions and 39 deletions
|
@ -22,6 +22,8 @@
|
|||
#include "AssignmentClient.h"
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "AssignmentClientApp.h"
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QStandardPaths>
|
||||
|
||||
|
||||
AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||
|
@ -92,6 +94,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
const QCommandLineOption monitorPortOption(ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION, "assignment-client monitor port", "port");
|
||||
parser.addOption(monitorPortOption);
|
||||
|
||||
const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory");
|
||||
parser.addOption(logDirectoryOption);
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qCritical() << parser.errorText() << endl;
|
||||
parser.showHelp();
|
||||
|
@ -130,6 +135,13 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
numForks = minForks;
|
||||
}
|
||||
|
||||
QDir logDirectory { "." };
|
||||
if (parser.isSet(logDirectoryOption)) {
|
||||
logDirectory = parser.value(logDirectoryOption);
|
||||
} else {
|
||||
logDirectory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||
}
|
||||
|
||||
Assignment::Type requestAssignmentType = Assignment::AllTypes;
|
||||
if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) {
|
||||
requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt();
|
||||
|
@ -200,7 +212,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,
|
||||
requestAssignmentType, assignmentPool,
|
||||
listenPort, walletUUID, assignmentServerHostname,
|
||||
assignmentServerPort);
|
||||
assignmentServerPort, logDirectory);
|
||||
monitor->setParent(this);
|
||||
connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit);
|
||||
} else {
|
||||
|
|
|
@ -25,6 +25,7 @@ const QString ASSIGNMENT_NUM_FORKS_OPTION = "n";
|
|||
const QString ASSIGNMENT_MIN_FORKS_OPTION = "min";
|
||||
const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
|
||||
const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port";
|
||||
const QString ASSIGNMENT_LOG_DIRECTORY = "log-directory";
|
||||
|
||||
class AssignmentClientApp : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include <memory>
|
||||
#include <signal.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <AddressManager.h>
|
||||
#include <LogHandler.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
@ -29,7 +32,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
const unsigned int maxAssignmentClientForks,
|
||||
Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||
quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname,
|
||||
quint16 assignmentServerPort) :
|
||||
quint16 assignmentServerPort, QDir logDirectory) :
|
||||
_numAssignmentClientForks(numAssignmentClientForks),
|
||||
_minAssignmentClientForks(minAssignmentClientForks),
|
||||
_maxAssignmentClientForks(maxAssignmentClientForks),
|
||||
|
@ -37,7 +40,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
_assignmentPool(assignmentPool),
|
||||
_walletUUID(walletUUID),
|
||||
_assignmentServerHostname(assignmentServerHostname),
|
||||
_assignmentServerPort(assignmentServerPort)
|
||||
_assignmentServerPort(assignmentServerPort),
|
||||
_logDirectory(logDirectory)
|
||||
{
|
||||
qDebug() << "_requestAssignmentType =" << _requestAssignmentType;
|
||||
|
||||
|
@ -155,11 +159,50 @@ void AssignmentClientMonitor::spawnChildClient() {
|
|||
_childArguments.append("--" + ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION);
|
||||
_childArguments.append(QString::number(DependencyManager::get<NodeList>()->getLocalSockAddr().getPort()));
|
||||
|
||||
// Setup log files
|
||||
const QString DATETIME_FORMAT = "yyyyMMdd.hh.mm.ss.zzz";
|
||||
|
||||
if (!_logDirectory.exists()) {
|
||||
qDebug() << "Log directory (" << _logDirectory.absolutePath() << ") does not exist, creating.";
|
||||
_logDirectory.mkpath(_logDirectory.absolutePath());
|
||||
}
|
||||
|
||||
auto nowString = QDateTime::currentDateTime().toString(DATETIME_FORMAT);
|
||||
auto stdoutFilenameTemp = QString("ac_stdout_%1.txt").arg(nowString);
|
||||
auto stderrFilenameTemp = QString("ac_stderr_%1.txt").arg(nowString);
|
||||
QString stdoutPathTemp = _logDirectory.absoluteFilePath(stdoutFilenameTemp);
|
||||
QString stderrPathTemp = _logDirectory.absoluteFilePath(stderrFilenameTemp);
|
||||
|
||||
// reset our output and error files
|
||||
assignmentClient->setStandardOutputFile(stdoutPathTemp);
|
||||
assignmentClient->setStandardErrorFile(stderrPathTemp);
|
||||
|
||||
// make sure that the output from the child process appears in our output
|
||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments);
|
||||
|
||||
// Update log path to use PID in filename
|
||||
auto stdoutFilename = QString("ac_stdout_%1_%2.txt").arg(nowString).arg(assignmentClient->processId());
|
||||
auto stderrFilename = QString("ac_stderr_%1_%2.txt").arg(nowString).arg(assignmentClient->processId());
|
||||
QString stdoutPath = _logDirectory.absoluteFilePath(stdoutFilename);
|
||||
QString stderrPath = _logDirectory.absoluteFilePath(stderrFilename);
|
||||
|
||||
qDebug() << "Renaming " << stdoutPathTemp << " to " << stdoutPath;
|
||||
if (!_logDirectory.rename(stdoutFilenameTemp, stdoutFilename)) {
|
||||
qDebug() << "Failed to rename " << stdoutFilenameTemp;
|
||||
stdoutFilename = stdoutFilenameTemp;
|
||||
}
|
||||
|
||||
qDebug() << "Renaming " << stderrPathTemp << " to " << stderrPath;
|
||||
if (!QFile::rename(stderrPathTemp, stderrPath)) {
|
||||
qDebug() << "Failed to rename " << stderrFilenameTemp;
|
||||
stderrFilename = stderrFilenameTemp;
|
||||
}
|
||||
|
||||
qDebug() << "Child stdout being written to: " << stdoutPathTemp;
|
||||
qDebug() << "Child stderr being written to: " << stderrPathTemp;
|
||||
|
||||
if (assignmentClient->processId() > 0) {
|
||||
// make sure we hear that this process has finished when it does
|
||||
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(childProcessFinished()));
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QDir>
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
|
@ -29,7 +30,7 @@ public:
|
|||
AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks,
|
||||
const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType,
|
||||
QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname,
|
||||
quint16 assignmentServerPort);
|
||||
quint16 assignmentServerPort, QDir logDirectory);
|
||||
~AssignmentClientMonitor();
|
||||
|
||||
void stopChildProcesses();
|
||||
|
@ -47,6 +48,8 @@ private:
|
|||
|
||||
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||
|
||||
QDir _logDirectory;
|
||||
|
||||
const unsigned int _numAssignmentClientForks;
|
||||
const unsigned int _minAssignmentClientForks;
|
||||
const unsigned int _maxAssignmentClientForks;
|
||||
|
|
|
@ -80,11 +80,13 @@
|
|||
<div id="manage-separator">
|
||||
<img src="images/manage-button-sep.svg"/>
|
||||
</div>
|
||||
<a id="settings" href="#" class="manage-button">
|
||||
|
||||
<!-- TODO: handle the case where the DS HTTP port is non-standard -->
|
||||
<a id="settings" href="http://localhost:40100/settings" target="_blank" class="manage-button">
|
||||
<img src="images/settings.svg" />
|
||||
<p>Settings</p>
|
||||
</a>
|
||||
<a id="logs" href="#" class="manage-button">
|
||||
<a id="open-logs" href="#" class="manage-button">
|
||||
<img src="images/logs.svg" />
|
||||
<p>Logs</p>
|
||||
</a>
|
||||
|
|
|
@ -4,18 +4,17 @@ $(function() {
|
|||
function onProcessUpdate(event, arg) {
|
||||
console.log("update", event, arg);
|
||||
|
||||
// Update interface
|
||||
// var interfaceState = arg.interface.state;
|
||||
// $('#process-interface .status').text(interfaceState);
|
||||
// var interfaceOn = interfaceState != 'stopped';
|
||||
// $('#process-interface .power-on').prop('disabled', interfaceOn);
|
||||
// $('#process-interface .power-off').prop('disabled', !interfaceOn);
|
||||
|
||||
// var state = arg.interface.state;
|
||||
// $('#process-interface .status').text(state);
|
||||
// var on = state != 'stopped';
|
||||
// if (on) {
|
||||
// $('#process-interface .power-on').hide();
|
||||
// $('#process-interface .power-off').show();
|
||||
// } else {
|
||||
// $('#process-interface .power-on').show();
|
||||
// $('#process-interface .power-off').hide();
|
||||
// }
|
||||
var serverState = arg.home.state;
|
||||
$('#server .status').text(serverState);
|
||||
var serverOn = serverState != 'stopped';
|
||||
$('#server .power-on').prop('disabled', serverOn);
|
||||
$('#server .power-off').prop('disabled', !serverOn);
|
||||
}
|
||||
|
||||
$('#process-interface .power-on').click(function() {
|
||||
|
@ -24,6 +23,15 @@ $(function() {
|
|||
$('#process-interface .power-off').click(function() {
|
||||
ipcRenderer.send('stop-process', { name: 'interface' });
|
||||
});
|
||||
$('#server .power-on').click(function() {
|
||||
ipcRenderer.send('start-server', { name: 'home' });
|
||||
});
|
||||
$('#server .power-off').click(function() {
|
||||
ipcRenderer.send('stop-server', { name: 'home' });
|
||||
});
|
||||
$('#open-logs').click(function() {
|
||||
ipcRenderer.send('open-logs');
|
||||
});
|
||||
|
||||
ipcRenderer.on('process-update', onProcessUpdate);
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@ var app = electron.app; // Module to control application life.
|
|||
var BrowserWindow = require('browser-window'); // Module to create native browser window.
|
||||
var Menu = require('menu');
|
||||
var Tray = require('tray');
|
||||
var shell = require('shell');
|
||||
var os = require('os');
|
||||
var childProcess = require('child_process');
|
||||
var path = require('path');
|
||||
|
||||
var hfprocess = require('./modules/hf-process.js');
|
||||
var Process = hfprocess.Process;
|
||||
|
@ -12,9 +16,6 @@ var ProcessGroup = hfprocess.ProcessGroup;
|
|||
|
||||
const ipcMain = electron.ipcMain;
|
||||
|
||||
// Report crashes to our server.
|
||||
require('crash-reporter').start();
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
var mainWindow = null;
|
||||
|
@ -47,6 +48,18 @@ if (argv.localDebugBuilds || argv.localReleaseBuilds) {
|
|||
acPath = pathFinder.discoveredPath("assignment-client", argv.localReleaseBuilds);
|
||||
}
|
||||
|
||||
function openFileBrowser(path) {
|
||||
var type = os.type();
|
||||
console.log(type);
|
||||
if (type == "Windows_NT") {
|
||||
childProcess.exec('start ' + path);
|
||||
} else if (type == "Darwin") {
|
||||
childProcess.exec('open ' + path);
|
||||
} else if (type == "Linux") {
|
||||
childProcess.exec('xdg-open ' + path);
|
||||
}
|
||||
}
|
||||
|
||||
// if at this point any of the paths are null, we're missing something we wanted to find
|
||||
// TODO: show an error for the binaries that couldn't be found
|
||||
|
||||
|
@ -89,16 +102,20 @@ app.on('ready', function() {
|
|||
mainWindow = null;
|
||||
});
|
||||
|
||||
// When a link is clicked that has `_target="_blank"`, open it in the user's native browser
|
||||
mainWindow.webContents.on('new-window', function(e, url) {
|
||||
e.preventDefault();
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
var logPath = path.join(app.getAppPath(), 'logs');
|
||||
|
||||
if (interfacePath && dsPath && acPath) {
|
||||
var pInterface = new Process('interface', interfacePath);
|
||||
|
||||
var homeServer = new ProcessGroup('home', [
|
||||
new Process('Domain Server', dsPath),
|
||||
new Process('AC - Audio', acPath, ['-t0']),
|
||||
new Process('AC - Avatar', acPath, ['-t1']),
|
||||
new Process('AC - Asset', acPath, ['-t3']),
|
||||
new Process('AC - Messages', acPath, ['-t4']),
|
||||
new Process('AC - Entity', acPath, ['-t6'])
|
||||
new Process('domain_server', dsPath),
|
||||
new Process('ac_monitor', acPath, ['-n6', '--log-directory', logPath])
|
||||
]);
|
||||
homeServer.start();
|
||||
|
||||
|
@ -106,7 +123,7 @@ app.on('ready', function() {
|
|||
app.on('quit', function(){
|
||||
pInterface.stop();
|
||||
homeServer.stop();
|
||||
})
|
||||
});
|
||||
|
||||
var processes = {
|
||||
interface: pInterface,
|
||||
|
@ -119,6 +136,7 @@ app.on('ready', function() {
|
|||
};
|
||||
|
||||
pInterface.on('state-update', sendProcessUpdate);
|
||||
homeServer.on('state-update', sendProcessUpdate);
|
||||
|
||||
ipcMain.on('start-process', function(event, arg) {
|
||||
pInterface.start();
|
||||
|
@ -128,9 +146,18 @@ app.on('ready', function() {
|
|||
pInterface.stop();
|
||||
sendProcessUpdate();
|
||||
});
|
||||
ipcMain.on('update', function(event, arg) {
|
||||
ipcMain.on('start-server', function(event, arg) {
|
||||
homeServer.start();
|
||||
sendProcessUpdate();
|
||||
});
|
||||
ipcMain.on('stop-server', function(event, arg) {
|
||||
homeServer.stop();
|
||||
sendProcessUpdate();
|
||||
});
|
||||
ipcMain.on('open-logs', function(event, arg) {
|
||||
openFileBrowser(logPath);
|
||||
});
|
||||
ipcMain.on('update', sendProcessUpdate);
|
||||
|
||||
sendProcessUpdate();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,13 @@ var extend = require('extend');
|
|||
var util = require('util');
|
||||
var events = require('events');
|
||||
var childProcess = require('child_process');
|
||||
var fs = require('fs');
|
||||
|
||||
const ProcessGroupStates = {
|
||||
STOPPED: 'stopped',
|
||||
STARTED: 'started',
|
||||
STOPPING: 'stopping'
|
||||
};
|
||||
|
||||
const ProcessStates = {
|
||||
STOPPED: 'stopped',
|
||||
|
@ -12,35 +19,72 @@ const ProcessStates = {
|
|||
};
|
||||
|
||||
function ProcessGroup(name, processes) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
this.name = name;
|
||||
this.processes = processes;
|
||||
this.state = ProcessGroupStates.STOPPED;
|
||||
this.processes = [];
|
||||
|
||||
for (let process of processes) {
|
||||
this.addProcess(process);
|
||||
}
|
||||
};
|
||||
util.inherits(ProcessGroup, events.EventEmitter);
|
||||
ProcessGroup.prototype = extend(ProcessGroup.prototype, {
|
||||
addProcess: function(process) {
|
||||
this.processes.push(process);
|
||||
process.on('state-update', this.onProcessStateUpdate.bind(this));
|
||||
},
|
||||
start: function() {
|
||||
if (this.state != ProcessGroupStates.STOPPED) {
|
||||
console.warn("Can't start process group that is not stopped.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (let process of this.processes) {
|
||||
process.start();
|
||||
}
|
||||
|
||||
this.state = ProcessGroupStates.STARTED;
|
||||
},
|
||||
stop: function() {
|
||||
if (this.state != ProcessGroupStates.STARTED) {
|
||||
console.warn("Can't stop process group that is not started.");
|
||||
return;
|
||||
}
|
||||
for (let process of this.processes) {
|
||||
process.stop();
|
||||
}
|
||||
this.state = ProcessGroupStates.STOPPING;
|
||||
},
|
||||
|
||||
// Event handlers
|
||||
onProcessStateUpdate: function(process) {
|
||||
var processesStillRunning = false;
|
||||
for (let process of this.processes) {
|
||||
if (process.state != ProcessStates.STOPPED) {
|
||||
processesStillRunning = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!processesStillRunning) {
|
||||
this.state = ProcessGroupStates.STOPPED;
|
||||
}
|
||||
this.emit('state-update', this, process);
|
||||
}
|
||||
});
|
||||
|
||||
var ID = 0;
|
||||
function Process(name, command, commandArgs) {
|
||||
function Process(name, command, commandArgs, logDirectory) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
this.blah = 'adsf';
|
||||
this.id = ++ID;
|
||||
this.name = name;
|
||||
this.command = command;
|
||||
this.commandArgs = commandArgs ? commandArgs : [];
|
||||
this.child = null;
|
||||
this.logDirectory = logDirectory;
|
||||
|
||||
this.state = ProcessStates.STOPPED;
|
||||
};
|
||||
|
@ -52,23 +96,80 @@ Process.prototype = extend(Process.prototype, {
|
|||
return;
|
||||
}
|
||||
console.log("Starting " + this.command);
|
||||
|
||||
var logStdout = 'ignore',
|
||||
logStderr = 'ignore';
|
||||
|
||||
if (this.logDirectory) {
|
||||
var logDirectoryCreated = false;
|
||||
|
||||
try {
|
||||
fs.mkdirSync('logs');
|
||||
logDirectoryCreated = true;
|
||||
} catch (e) {
|
||||
if (e.code == 'EEXIST') {
|
||||
logDirectoryCreated = true;
|
||||
} else {
|
||||
console.error("Error creating log directory");
|
||||
}
|
||||
}
|
||||
|
||||
if (logDirectoryCreated) {
|
||||
// Create a temporary file with the current time
|
||||
var time = (new Date).getTime();
|
||||
var tmpLogStdout = this.logDirectory + '/' + this.name + '-' + time + '-stdout.txt';
|
||||
var tmpLogStderr = this.logDirectory + '/' + this.name + '-' + time + '-stderr.txt';
|
||||
|
||||
try {
|
||||
logStdout = fs.openSync(tmpLogStdout, 'ax');
|
||||
} catch(e) {
|
||||
console.log("Error creating stdout log file", e);
|
||||
logStdout = 'ignore';
|
||||
}
|
||||
try {
|
||||
logStderr = fs.openSync(tmpLogStderr, 'ax');
|
||||
} catch(e) {
|
||||
console.log("Error creating stderr log file", e);
|
||||
logStderr = 'ignore';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.child = childProcess.spawn(this.command, this.commandArgs, {
|
||||
detached: false,
|
||||
stdio: 'ignore'
|
||||
stdio: ['ignore', logStdout, logStderr]
|
||||
});
|
||||
//console.log("started ", this.child);
|
||||
this.child.on('error', this.onChildStartError.bind(this));
|
||||
this.child.on('close', this.onChildClose.bind(this));
|
||||
this.state = ProcessStates.STARTED;
|
||||
console.log("Child process started");
|
||||
} catch (e) {
|
||||
console.log("Got error starting child process for " + this.name, e);
|
||||
this.child = null;
|
||||
this.state = ProcessStates.STOPPED;
|
||||
}
|
||||
|
||||
this.emit('state-update');
|
||||
if (logStdout != 'ignore') {
|
||||
var pidLogStdout = './logs/' + this.name + "-" + this.child.pid + "-" + time + "-stdout.txt";
|
||||
fs.rename(tmpLogStdout, pidLogStdout, function(e) {
|
||||
if (e !== null) {
|
||||
console.log("Error renaming log file from " + tmpLogStdout + " to " + pidLogStdout, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (logStderr != 'ignore') {
|
||||
var pidLogStderr = './logs/' + this.name + "-" + this.child.pid + "-" + time + "-stderr.txt";
|
||||
fs.rename(tmpLogStderr, pidLogStderr, function(e) {
|
||||
if (e !== null) {
|
||||
console.log("Error renaming log file from " + tmpLogStdout + " to " + pidLogStdout, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.child.on('error', this.onChildStartError.bind(this));
|
||||
this.child.on('close', this.onChildClose.bind(this));
|
||||
this.state = ProcessStates.STARTED;
|
||||
console.log("Child process started");
|
||||
|
||||
this.emit('state-update', this);
|
||||
},
|
||||
stop: function() {
|
||||
if (this.state != ProcessStates.STARTED) {
|
||||
|
@ -83,12 +184,12 @@ Process.prototype = extend(Process.prototype, {
|
|||
onChildStartError: function(error) {
|
||||
console.log("Child process error ", error);
|
||||
this.state = ProcessStates.STOPPED;
|
||||
this.emit('state-update');
|
||||
this.emit('state-update', this);
|
||||
},
|
||||
onChildClose: function(code) {
|
||||
console.log("Child process closed with code ", code);
|
||||
this.state = ProcessStates.STOPPED;
|
||||
this.emit('state-update');
|
||||
this.emit('state-update', this);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue