kopia lustrzana https://github.com/OpenDroneMap/NodeODM
Task start working, console output
rodzic
7a4bee53b9
commit
48e292a6cf
14
index.js
14
index.js
|
@ -39,7 +39,7 @@ let upload = multer({
|
|||
})
|
||||
});
|
||||
|
||||
app.post('/newTask', addRequestId, upload.array('images'), (req, res) => {
|
||||
app.post('/task/new', addRequestId, upload.array('images'), (req, res) => {
|
||||
if (req.files.length === 0) res.json({error: "Need at least 1 file."});
|
||||
else{
|
||||
// Move to data
|
||||
|
@ -81,11 +81,11 @@ let getTaskFromUuid = (req, res, next) => {
|
|||
}else res.json({error: `${req.params.uuid} not found`});
|
||||
}
|
||||
|
||||
app.get('/taskInfo/:uuid', getTaskFromUuid, (req, res) => {
|
||||
app.get('/task/:uuid/info', getTaskFromUuid, (req, res) => {
|
||||
res.json(req.task.getInfo());
|
||||
});
|
||||
app.get('/taskOutput/:uuid', getTaskFromUuid, (req, res) => {
|
||||
res.json(req.task.getOutput());
|
||||
app.get('/task/:uuid/output', getTaskFromUuid, (req, res) => {
|
||||
res.json(req.task.getOutput(req.query.line));
|
||||
});
|
||||
|
||||
let uuidCheck = (req, res, next) => {
|
||||
|
@ -100,15 +100,15 @@ let successHandler = res => {
|
|||
};
|
||||
};
|
||||
|
||||
app.post('/cancelTask', uuidCheck, (req, res) => {
|
||||
app.post('/task/cancel', uuidCheck, (req, res) => {
|
||||
taskManager.cancel(req.body.uuid, successHandler(res));
|
||||
});
|
||||
|
||||
app.post('/removeTask', uuidCheck, (req, res) => {
|
||||
app.post('/task/remove', uuidCheck, (req, res) => {
|
||||
taskManager.remove(req.body.uuid, successHandler(res));
|
||||
});
|
||||
|
||||
app.post('/restartTask', uuidCheck, (req, res) => {
|
||||
app.post('/task/restart', uuidCheck, (req, res) => {
|
||||
taskManager.restart(req.body.uuid, successHandler(res));
|
||||
});
|
||||
|
||||
|
|
15
libs/Task.js
15
libs/Task.js
|
@ -33,7 +33,13 @@ module.exports = class Task{
|
|||
// Get path where images are stored for this task
|
||||
// (relative to nodejs process CWD)
|
||||
getImagesFolderPath(){
|
||||
return `data/${this.uuid}/images`;
|
||||
return `${this.getProjectFolderPath()}/images`;
|
||||
}
|
||||
|
||||
// Get path of project (where all images and assets folder are contained)
|
||||
// (relative to nodejs process CWD)
|
||||
getProjectFolderPath(){
|
||||
return `data/${this.uuid}`;
|
||||
}
|
||||
|
||||
setStatus(code, extra){
|
||||
|
@ -68,7 +74,7 @@ module.exports = class Task{
|
|||
if (this.status.code === statusCodes.QUEUED){
|
||||
this.setStatus(statusCodes.RUNNING);
|
||||
this.runnerProcess = odmRunner.run({
|
||||
projectPath: `${__dirname}/../${this.getImagesFolderPath()}`
|
||||
projectPath: `${__dirname}/../${this.getProjectFolderPath()}`
|
||||
}, (err, code, signal) => {
|
||||
if (err){
|
||||
this.setStatus(statusCodes.FAILED, {errorMessage: `Could not start process (${err.message})`});
|
||||
|
@ -81,6 +87,8 @@ module.exports = class Task{
|
|||
}
|
||||
done();
|
||||
}, output => {
|
||||
// Replace console colors
|
||||
output = output.replace(/\x1b\[[0-9;]*m/g, "");
|
||||
this.output.push(output);
|
||||
});
|
||||
|
||||
|
@ -120,7 +128,6 @@ module.exports = class Task{
|
|||
// Returns the output of the OpenDroneMap process
|
||||
// Optionally starting from a certain line number
|
||||
getOutput(startFromLine = 0){
|
||||
let lineNum = Math.min(this.output.length, startFromLine);
|
||||
return this.output.slice(lineNum, this.output.length);
|
||||
return this.output.slice(startFromLine, this.output.length);
|
||||
}
|
||||
};
|
|
@ -3,7 +3,7 @@ let assert = require('assert');
|
|||
let Task = require('./Task');
|
||||
let statusCodes = require('./statusCodes');
|
||||
|
||||
let PARALLEL_QUEUE_PROCESS_LIMIT = 1;
|
||||
let PARALLEL_QUEUE_PROCESS_LIMIT = 2;
|
||||
|
||||
module.exports = class TaskManager{
|
||||
constructor(){
|
||||
|
@ -50,8 +50,6 @@ module.exports = class TaskManager{
|
|||
this.runningQueue = this.runningQueue.filter(t => {
|
||||
return t !== task;
|
||||
});
|
||||
|
||||
console.log("New queue length: " + this.runningQueue.length);
|
||||
}
|
||||
|
||||
addNew(task){
|
||||
|
@ -90,7 +88,10 @@ module.exports = class TaskManager{
|
|||
restart(uuid, cb){
|
||||
let task;
|
||||
if (task = this.find(uuid, cb)){
|
||||
task.restart(cb);
|
||||
task.restart(err => {
|
||||
this.processNextTask();
|
||||
cb(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,4 +48,11 @@
|
|||
|
||||
.task .actionButtons{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.task .consoleOutput{
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
font-family: monospace;
|
||||
font-size: 90%;
|
||||
}
|
|
@ -64,6 +64,8 @@
|
|||
<div class="taskItem"><strong>Name:</strong> <span data-bind="text: info().name"></span></div>
|
||||
<div class="taskItem"><strong>Images:</strong> <span data-bind="text: info().imagesCount"></span></div>
|
||||
<div class="taskItem"><strong>Status:</strong> <span data-bind="text: statusDescr()"></span></div>
|
||||
<div class="taskItem"><strong>Output:</strong> <a href="javascript:void(0);" data-bind="click: viewOutput, visible: !viewingOutput()">View</a><a href="javascript:void(0);" data-bind="click: hideOutput, visible: viewingOutput()">Hide</a></div>
|
||||
<textarea class="consoleOutput" data-bind="value: output().join(''), visible: viewingOutput(), event: {mouseover: consoleMouseOver, mouseout: consoleMouseOut}, attr: {id: 'console_' + uuid}"></textarea>
|
||||
|
||||
<span data-bind="css: 'statusIcon glyphicon ' + icon()"></span>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ $(function(){
|
|||
return new Task(uuid);
|
||||
}));
|
||||
}
|
||||
TaskList.prototype.addNew = function(task) {
|
||||
TaskList.prototype.add = function(task) {
|
||||
this.tasks.push(task);
|
||||
this.saveTaskListToLocalStorage();
|
||||
};
|
||||
|
@ -30,6 +30,8 @@ $(function(){
|
|||
this.uuid = uuid;
|
||||
this.loading = ko.observable(true);
|
||||
this.info = ko.observable({});
|
||||
this.viewingOutput = ko.observable(false);
|
||||
this.resetOutput();
|
||||
|
||||
var statusCodes = {
|
||||
10: {
|
||||
|
@ -64,7 +66,6 @@ $(function(){
|
|||
this.icon = ko.pureComputed(function(){
|
||||
if (this.info().status && this.info().status.code){
|
||||
if(statusCodes[this.info().status.code]){
|
||||
console.log(statusCodes[this.info().status.code].icon);
|
||||
return statusCodes[this.info().status.code].icon;
|
||||
}else return "glyphicon-question-sign";
|
||||
}else return "";
|
||||
|
@ -73,14 +74,11 @@ $(function(){
|
|||
return this.info().status && this.info().status.code === 50;
|
||||
}, this);
|
||||
|
||||
this.refreshInfo();
|
||||
this.refreshInterval = setInterval(function(){
|
||||
self.refreshInfo();
|
||||
}, 2000);
|
||||
this.startRefreshingInfo();
|
||||
}
|
||||
Task.prototype.refreshInfo = function(){
|
||||
var self = this;
|
||||
var url = "/taskInfo/" + this.uuid;
|
||||
var url = "/task/" + this.uuid + "/info";
|
||||
$.get(url)
|
||||
.done(self.info)
|
||||
.fail(function(){
|
||||
|
@ -88,9 +86,61 @@ $(function(){
|
|||
})
|
||||
.always(function(){ self.loading(false); });
|
||||
};
|
||||
Task.prototype.consoleMouseOver = function(){ this.autoScrollOutput = false; }
|
||||
Task.prototype.consoleMouseOut = function(){ this.autoScrollOutput = true; }
|
||||
Task.prototype.resetOutput = function(){
|
||||
this.viewOutputLine = 0;
|
||||
this.autoScrollOutput = true;
|
||||
this.output = ko.observableArray();
|
||||
};
|
||||
Task.prototype.viewOutput = function(){
|
||||
var self = this;
|
||||
|
||||
function fetchOutput(){
|
||||
var url = "/task/" + self.uuid + "/output";
|
||||
$.get(url, {line: self.viewOutputLine})
|
||||
.done(function(output){
|
||||
for (var i in output){
|
||||
self.output.push(output[i]);
|
||||
}
|
||||
if (output.length){
|
||||
self.viewOutputLine += output.length;
|
||||
if (self.autoScrollOutput){
|
||||
var $console = $("#console_" + self.uuid);
|
||||
$console.scrollTop($console[0].scrollHeight - $console.height())
|
||||
}
|
||||
}
|
||||
})
|
||||
.fail(function(){
|
||||
self.info({error: url + " is unreachable."});
|
||||
});
|
||||
}
|
||||
this.fetchOutputInterval = setInterval(fetchOutput, 2000);
|
||||
fetchOutput();
|
||||
|
||||
this.viewingOutput(true);
|
||||
};
|
||||
Task.prototype.hideOutput = function(){
|
||||
if (this.fetchOutputInterval) clearInterval(this.fetchOutputInterval);
|
||||
this.viewingOutput(false);
|
||||
};
|
||||
Task.prototype.startRefreshingInfo = function() {
|
||||
var self = this;
|
||||
this.stopRefreshingInfo();
|
||||
this.refreshInfo();
|
||||
this.refreshInterval = setInterval(function(){
|
||||
self.refreshInfo();
|
||||
}, 2000);
|
||||
};
|
||||
Task.prototype.stopRefreshingInfo = function() {
|
||||
if (this.refreshInterval){
|
||||
clearInterval(this.refreshInterval);
|
||||
this.refreshInterval = null;
|
||||
}
|
||||
};
|
||||
Task.prototype.remove = function() {
|
||||
var self = this;
|
||||
var url = "/removeTask";
|
||||
var url = "/task/remove";
|
||||
|
||||
$.post(url, {
|
||||
uuid: this.uuid
|
||||
|
@ -102,13 +152,11 @@ $(function(){
|
|||
self.info({error: json.error});
|
||||
}
|
||||
|
||||
if (self.refreshInterval){
|
||||
clearInterval(self.refreshInterval);
|
||||
self.refreshInterval = null;
|
||||
}
|
||||
self.stopRefreshingInfo();
|
||||
})
|
||||
.fail(function(){
|
||||
self.info({error: url + " is unreachable."});
|
||||
self.stopRefreshingInfo();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -116,34 +164,32 @@ $(function(){
|
|||
return function(){
|
||||
var self = this;
|
||||
|
||||
|
||||
// TODO: maybe there's a better way
|
||||
// to handle refreshInfo here...
|
||||
|
||||
$.post(url, {
|
||||
uuid: this.uuid
|
||||
})
|
||||
.done(function(json){
|
||||
if (json.success){
|
||||
self.refreshInfo();
|
||||
self.startRefreshingInfo();
|
||||
}else{
|
||||
self.stopRefreshingInfo();
|
||||
self.info({error: json.error});
|
||||
}
|
||||
})
|
||||
.fail(function(){
|
||||
self.info({error: url + " is unreachable."});
|
||||
self.stopRefreshingInfo();
|
||||
});
|
||||
}
|
||||
};
|
||||
Task.prototype.cancel = genApiCall("/cancelTask");
|
||||
Task.prototype.restart = genApiCall("/restartTask");
|
||||
Task.prototype.cancel = genApiCall("/task/cancel");
|
||||
Task.prototype.restart = genApiCall("/task/restart");
|
||||
|
||||
var taskList = new TaskList();
|
||||
ko.applyBindings(taskList);
|
||||
|
||||
// Handle uploads
|
||||
$("#images").fileinput({
|
||||
uploadUrl: '/newTask',
|
||||
uploadUrl: '/task/new',
|
||||
showPreview: false,
|
||||
allowedFileExtensions: ['jpg', 'jpeg'],
|
||||
elErrorContainer: '#errorBlock',
|
||||
|
@ -170,7 +216,7 @@ $(function(){
|
|||
$("#images").fileinput('reset');
|
||||
|
||||
if (params.response.success && params.response.uuid){
|
||||
taskList.addNew(new Task(params.response.uuid));
|
||||
taskList.add(new Task(params.response.uuid));
|
||||
}
|
||||
})
|
||||
.on('filebatchuploadcomplete', function(){
|
||||
|
|
Ładowanie…
Reference in New Issue