kopia lustrzana https://github.com/OpenDroneMap/NodeODM
GPC files support, cleanups, options support, testing
rodzic
f22e572a91
commit
61269d37c1
27
index.js
27
index.js
|
@ -21,6 +21,7 @@ let config = require('./config.js');
|
|||
|
||||
let logger = require('./libs/logger');
|
||||
let fs = require('fs');
|
||||
let path = require('path');
|
||||
let async = require('async');
|
||||
|
||||
let express = require('express');
|
||||
|
@ -68,6 +69,11 @@ let upload = multer({
|
|||
app.post('/task/new', addRequestId, upload.array('images'), (req, res) => {
|
||||
if (req.files.length === 0) res.json({error: "Need at least 1 file."});
|
||||
else{
|
||||
let srcPath = `tmp/${req.id}`;
|
||||
let destPath = `data/${req.id}`;
|
||||
let destImagesPath = `${destPath}/images`;
|
||||
let destGpcPath = `${destPath}/gpc`;
|
||||
|
||||
async.series([
|
||||
cb => {
|
||||
odmOptions.filterOptions(req.body.options, (err, options) => {
|
||||
|
@ -79,18 +85,27 @@ app.post('/task/new', addRequestId, upload.array('images'), (req, res) => {
|
|||
});
|
||||
},
|
||||
|
||||
// Move uploads to data dir
|
||||
// Move all uploads to data/<uuid>/images dir
|
||||
cb => {
|
||||
fs.stat(`data/${req.id}`, (err, stat) => {
|
||||
fs.stat(destPath, (err, stat) => {
|
||||
if (err && err.code === 'ENOENT') cb();
|
||||
else cb(new Error(`Directory exists (should not have happened: ${err.code})`));
|
||||
});
|
||||
},
|
||||
cb => { fs.mkdir(`data/${req.id}`, undefined, cb); },
|
||||
cb => fs.mkdir(destPath, undefined, cb),
|
||||
cb => fs.mkdir(destGpcPath, undefined, cb),
|
||||
cb => fs.rename(srcPath, destImagesPath, cb),
|
||||
cb => {
|
||||
fs.rename(`tmp/${req.id}`, `data/${req.id}/images`, err => {
|
||||
if (!err) cb();
|
||||
else cb(new Error("Could not move images folder."))
|
||||
// Find any *.txt (GPC) file and move it to the data/<uuid>/gpc directory
|
||||
fs.readdir(destImagesPath, (err, entries) => {
|
||||
if (err) cb(err);
|
||||
else{
|
||||
async.eachSeries(entries, (entry, cb) => {
|
||||
if (/\.txt$/gi.test(entry)){
|
||||
fs.rename(path.join(destImagesPath, entry), path.join(destGpcPath, entry), cb);
|
||||
}else cb();
|
||||
}, cb);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
53
libs/Task.js
53
libs/Task.js
|
@ -16,8 +16,12 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
let async = require('async');
|
||||
let assert = require('assert');
|
||||
let logger = require('./logger');
|
||||
let fs = require('fs');
|
||||
let path = require('path');
|
||||
let rmdir = require('rimraf');
|
||||
let odmRunner = require('./odmRunner');
|
||||
let archiver = require('archiver');
|
||||
|
@ -36,16 +40,40 @@ module.exports = class Task{
|
|||
this.processingTime = -1;
|
||||
this.setStatus(statusCodes.QUEUED);
|
||||
this.options = options;
|
||||
this.gpcFiles = [];
|
||||
this.output = [];
|
||||
this.runnerProcess = null;
|
||||
|
||||
// Read images info
|
||||
fs.readdir(this.getImagesFolderPath(), (err, files) => {
|
||||
if (err) done(err);
|
||||
else{
|
||||
this.images = files;
|
||||
done(null, this);
|
||||
async.series([
|
||||
// Read images info
|
||||
cb => {
|
||||
fs.readdir(this.getImagesFolderPath(), (err, files) => {
|
||||
if (err) cb(err);
|
||||
else{
|
||||
this.images = files;
|
||||
logger.debug(`Found ${this.images.length} images for ${this.uuid}`)
|
||||
cb(null);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Find GCP (if any)
|
||||
cb => {
|
||||
fs.readdir(this.getGpcFolderPath(), (err, files) => {
|
||||
if (err) cb(err);
|
||||
else{
|
||||
files.forEach(file => {
|
||||
if (/\.txt$/gi.test(file)){
|
||||
this.gpcFiles.push(file);
|
||||
}
|
||||
});
|
||||
logger.debug(`Found ${this.gpcFiles.length} GPC files (${this.gpcFiles.join(" ")}) for ${this.uuid}`);
|
||||
cb(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
], err => {
|
||||
done(err, this);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -74,6 +102,12 @@ module.exports = class Task{
|
|||
return `${this.getProjectFolderPath()}/images`;
|
||||
}
|
||||
|
||||
// Get path where GPC file(s) are stored
|
||||
// (relative to nodejs process CWD)
|
||||
getGpcFolderPath(){
|
||||
return `${this.getProjectFolderPath()}/gpc`;
|
||||
}
|
||||
|
||||
// Get path of project (where all images and assets folder are contained)
|
||||
// (relative to nodejs process CWD)
|
||||
getProjectFolderPath(){
|
||||
|
@ -194,9 +228,14 @@ module.exports = class Task{
|
|||
return result;
|
||||
}, {});
|
||||
|
||||
runnerOptions["project-path"] = `${__dirname}/../${this.getProjectFolderPath()}`;
|
||||
runnerOptions["project-path"] = fs.realpathSync(this.getProjectFolderPath());
|
||||
runnerOptions["pmvs-num-cores"] = os.cpus().length;
|
||||
|
||||
if (this.gpcFiles.length > 0){
|
||||
runnerOptions["odm_georeferencing-useGcp"] = true;
|
||||
runnerOptions["odm_georeferencing-gcpFile"] = fs.realpathSync(path.join(this.getGpcFolderPath(), this.gpcFiles[0]));
|
||||
}
|
||||
|
||||
this.runnerProcess = odmRunner.run(runnerOptions, (err, code, signal) => {
|
||||
if (err){
|
||||
this.setStatus(statusCodes.FAILED, {errorMessage: `Could not start process (${err.message})`});
|
||||
|
|
|
@ -91,7 +91,7 @@ module.exports = class TaskManager{
|
|||
async.eachSeries(entries, (entry, cb) => {
|
||||
let dirPath = path.join(DATA_DIR, entry);
|
||||
if (fs.statSync(dirPath).isDirectory() &&
|
||||
entry.match(/[\w\d]+\-[\w\d]+\-[\w\d]+\-[\w\d]+\-[\w\d]+/) &&
|
||||
entry.match(/^[\w\d]+\-[\w\d]+\-[\w\d]+\-[\w\d]+\-[\w\d]+$/) &&
|
||||
!this.tasks[entry]){
|
||||
logger.info(`Found orphaned directory: ${entry}, removing...`);
|
||||
rmdir(dirPath, cb);
|
||||
|
@ -101,7 +101,6 @@ module.exports = class TaskManager{
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
// Load tasks that already exists (if any)
|
||||
restoreTaskListFromDump(done){
|
||||
fs.readFile(TASKS_DUMP_FILE, (err, data) => {
|
||||
|
@ -238,7 +237,7 @@ module.exports = class TaskManager{
|
|||
|
||||
fs.writeFile(TASKS_DUMP_FILE, JSON.stringify(output), err => {
|
||||
if (err) logger.error(`Could not dump tasks: ${err.message}`);
|
||||
else logger.debug("Dumped tasks list.");
|
||||
else logger.info("Dumped tasks list.");
|
||||
if (done !== undefined) done();
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
"use strict";
|
||||
let spawn = require('child_process').spawn;
|
||||
let config = require('../config.js');
|
||||
let logger = require('./logger');
|
||||
|
||||
module.exports = {
|
||||
run: function(options = {
|
||||
|
@ -38,7 +39,9 @@ module.exports = {
|
|||
command.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logger.info(`About to run: python ${command.join(" ")}`);
|
||||
|
||||
// Launch
|
||||
let childProcess = spawn("python", command, {cwd: config.odm_path});
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<label for="taskName">Project Name:</lable> <input type="text" class="form-control" value="" id="taskName" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="images">Aerial Imageries:</label> <input id="images" name="images" multiple type="file">
|
||||
<label for="images">Aerial Imageries and GCP List (optional):</label> <input id="images" name="images" multiple type="file">
|
||||
<div id="errorBlock" class="help-block"></div>
|
||||
</div>
|
||||
<div class="text-right"><input type="submit" class="btn btn-success" value="Start Task" id="btnUpload" /></div>
|
||||
|
|
|
@ -3205,8 +3205,8 @@
|
|||
$.fn.fileinputLocales.en = {
|
||||
fileSingle: 'file',
|
||||
filePlural: 'files',
|
||||
browseLabel: 'Browse …',
|
||||
removeLabel: 'Remove',
|
||||
browseLabel: 'Add …',
|
||||
removeLabel: 'Clear All',
|
||||
removeTitle: 'Clear selected files',
|
||||
cancelLabel: 'Cancel',
|
||||
cancelTitle: 'Abort ongoing upload',
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
$.fn.fileinputLocales['_LANG_'] = {
|
||||
fileSingle: 'file',
|
||||
filePlural: 'files',
|
||||
browseLabel: 'Browse …',
|
||||
removeLabel: 'Remove',
|
||||
browseLabel: 'Add …',
|
||||
removeLabel: 'Clear All',
|
||||
removeTitle: 'Clear selected files',
|
||||
cancelLabel: 'Cancel',
|
||||
cancelTitle: 'Abort ongoing upload',
|
||||
|
|
|
@ -59,6 +59,14 @@ $(function(){
|
|||
this.saveTaskListToLocalStorage();
|
||||
};
|
||||
|
||||
var codes = {
|
||||
QUEUED: 10,
|
||||
RUNNING: 20,
|
||||
FAILED: 30,
|
||||
COMPLETED: 40,
|
||||
CANCELED: 50
|
||||
};
|
||||
|
||||
function Task(uuid){
|
||||
var self = this;
|
||||
|
||||
|
@ -70,13 +78,6 @@ $(function(){
|
|||
this.resetOutput();
|
||||
this.timeElapsed = ko.observable("00:00:00");
|
||||
|
||||
var codes = {
|
||||
QUEUED: 10,
|
||||
RUNNING: 20,
|
||||
FAILED: 30,
|
||||
COMPLETED: 40,
|
||||
CANCELED: 50
|
||||
};
|
||||
var statusCodes = {
|
||||
10: {
|
||||
descr: "Queued",
|
||||
|
@ -205,22 +206,30 @@ $(function(){
|
|||
var self = this;
|
||||
var url = "/task/remove";
|
||||
|
||||
$.post(url, {
|
||||
uuid: this.uuid
|
||||
})
|
||||
.done(function(json){
|
||||
if (json.success || self.info().error){
|
||||
taskList.remove(self);
|
||||
}else{
|
||||
self.info({error: json.error});
|
||||
}
|
||||
function doRemove(){
|
||||
$.post(url, {
|
||||
uuid: self.uuid
|
||||
})
|
||||
.done(function(json){
|
||||
if (json.success || self.info().error){
|
||||
taskList.remove(self);
|
||||
}else{
|
||||
self.info({error: json.error});
|
||||
}
|
||||
|
||||
self.stopRefreshingInfo();
|
||||
})
|
||||
.fail(function(){
|
||||
self.info({error: url + " is unreachable."});
|
||||
self.stopRefreshingInfo();
|
||||
});
|
||||
self.stopRefreshingInfo();
|
||||
})
|
||||
.fail(function(){
|
||||
self.info({error: url + " is unreachable."});
|
||||
self.stopRefreshingInfo();
|
||||
});
|
||||
}
|
||||
|
||||
if (this.info().status && this.info().status.code === codes.COMPLETED){
|
||||
if (confirm("Are you sure?")) doRemove();
|
||||
}else{
|
||||
doRemove();
|
||||
}
|
||||
};
|
||||
|
||||
function genApiCall(url, onSuccess){
|
||||
|
@ -260,7 +269,7 @@ $(function(){
|
|||
$("#images").fileinput({
|
||||
uploadUrl: '/task/new',
|
||||
showPreview: false,
|
||||
allowedFileExtensions: ['jpg', 'jpeg'],
|
||||
allowedFileExtensions: ['jpg', 'jpeg', 'txt'],
|
||||
elErrorContainer: '#errorBlock',
|
||||
showUpload: false,
|
||||
uploadAsync: false,
|
||||
|
|
Plik binarny nie jest wyświetlany.
Przed Szerokość: | Wysokość: | Rozmiar: 72 KiB Po Szerokość: | Wysokość: | Rozmiar: 100 KiB |
Ładowanie…
Reference in New Issue