9 var Emitter = require(
"events").EventEmitter;
10 var fs = require(
"fs");
11 var stream = require(
"stream");
12 var child_process = require(
"child_process");
13 var Utils = require(
"./Utils");
14 var Connector = require(
"./DBConnector");
15 var path_module = require(
"path");
16 var db =
new Emitter();
20 var DefaultColumns = [
35 title:
"User Comment",
65 var MakeDbConfig =
function (configFile) {
67 dbprovider:
"filesystem"
68 , configNameFilter:
"*"
69 , baseDir: process.env.ARTDAQ_DATABASE_URI ? process.env[
"ARTDAQ_DATABASE_URI"] :
""
75 , instanceName: configFile.instanceName ? configFile.instanceName :
"test_db"
78 if (defaultConfig.baseDir.indexOf(
"filesystemdb://") === 0) {
79 console.log(
"Parsing filesystemdb URI: " + defaultConfig.baseDir);
80 defaultConfig.baseDir = defaultConfig.baseDir.replace(
"filesystemdb://",
"").replace(/\/$/,
"");
81 var tempArr = defaultConfig.baseDir.split(
'/');
82 defaultConfig.instanceName = tempArr.splice(-1);
83 defaultConfig.baseDir = tempArr.slice(0,-1).join(
'/');
84 }
else if (defaultConfig.baseDir.indexOf(
"mongodb://") === 0) {
85 console.log(
"Parsing mongodb URI: " + defaultConfig.baseDir);
86 var matches = defaultConfig.baseDir.match(/mongodb:\/\/(?:([^@:]*)(?::([^@]*))?@)?([^:]*):([0-9]+)\/([^/]*)\/?/);
87 defaultConfig.baseDir =
"";
88 defaultConfig.dbprovider =
"mongo";
89 console.log(JSON.stringify(matches, null, 4));
90 defaultConfig.mongoConfig.dbUser = matches[1] ? matches[1] :
"";
91 var pass = matches[2];
92 if (pass !== null && pass !== undefined) {
93 fs.writeFileSync(
".dbpasswd", pass);
95 defaultConfig.mongoConfig.dbHost = matches[3];
96 defaultConfig.mongoConfig.dbPort = matches[4];
97 defaultConfig.instanceName = matches[5];
100 if (defaultConfig.baseDir ===
"") {
101 defaultConfig.baseDir = process.env[
"ARTDAQ_DATABASE_DIR"];
104 console.log(
"DBConfig: " + JSON.stringify(defaultConfig, null, 4));
105 return defaultConfig;
108 function GetFileBase(configName, collection, entity) {
109 return path_module.join(configName, collection, entity +
".gui.json");
112 function GetTempFilePath(configName, collection, entity, dirs) {
113 var filebase = GetFileBase(configName, collection, entity);
115 if (!fs.existsSync(path_module.join(dirs.tmp, configName))) fs.mkdirSync(path_module.join(dirs.tmp, configName));
116 if (!fs.existsSync(path_module.join(dirs.tmp, configName, collection))) fs.mkdirSync(path_module.join(dirs.tmp, configName, collection));
117 return path_module.join(dirs.tmp, filebase);
120 function GetFilePath(configName, collection, entity, dirs, dbOnly) {
121 var filebase = GetFileBase(configName, collection, entity);
122 console.log(
"GetFilePath: filebase is " + filebase +
", dirs: " + JSON.stringify(dirs, null, 4));
123 if (!dbOnly && fs.existsSync(path_module.join(dirs.tmp, filebase))) {
124 return path_module.join(dirs.tmp, filebase);
127 if (!fs.existsSync(path_module.join(dirs.db, configName))) fs.mkdirSync(path_module.join(dirs.db, configName));
128 if (!fs.existsSync(path_module.join(dirs.db, configName, collection))) fs.mkdirSync(path_module.join(dirs.db, configName, collection));
129 return path_module.join(dirs.db, filebase);
137 function LoadFile(fileInfo, dirs, dbConfig) {
138 console.log(
"LoadFile: fileInfo: " + JSON.stringify(fileInfo, null, 4) +
", dirs: " + JSON.stringify(dirs, null, 4) +
", dbConfig: " + JSON.stringify(dbConfig, null, 4));
147 output.entity = fileInfo.query.filter[
"entities.name"];
148 output.collection = fileInfo.query.collection;
149 output.configName = fileInfo.query.filter[
"configurations.name"];
151 console.log(
"File info: " + JSON.stringify(fileInfo, null, 4));
152 output.filePath = GetFilePath(output.configName, output.collection, output.entity, dirs,
true);
154 if (!fs.existsSync(output.filePath)) {
155 console.log(
"Loading file from database");
156 output.data = Connector.RunLoadQuery(dbConfig, fileInfo.query);
157 console.log(
"Writing file " + output.filePath);
158 fs.writeFileSync(output.filePath, JSON.stringify(output.data, null, 4));
160 output.data = JSON.parse(
"" + fs.readFileSync(output.filePath));
162 console.log(
"File Data: " + JSON.stringify(output, null, 4));
163 console.log(
"Done Loading file");
178 function FetchFile(fileInfo, dataFormat, dbdirectory, dbConfig) {
179 console.log(
"FetchFile: fileInfo: " + JSON.stringify(fileInfo, null, 4) +
", dataFormat: " + dataFormat +
", dbDirectory: " + dbdirectory);
180 var fileName = path_module.join(fileInfo.collection +
"_" + fileInfo.name +
"_" + fileInfo.version);
181 if (dataFormat ===
"fhicl") {
183 }
else if (dataFormat ===
"gui") {
184 fileName +=
".gui.json";
188 var filePath = path_module.join(dbdirectory, fileName);
191 "entities.name": fileInfo.name,
192 version: fileInfo.version
194 collection: fileInfo.collection,
195 configurable_entity: fileInfo.name,
196 dbprovider: dbConfig.dbprovider,
198 dataformat: dataFormat
200 var fhiclData = Connector.RunLoadQuery(dbConfig, query,
true);
201 fs.writeFileSync(filePath, JSON.stringify(fhiclData, null, 4));
203 var stat = fs.statSync(filePath);
204 return { fileName: fileName, filePath: filePath, size: stat.size }
207 function MakeColumns(rowIn, index, columns, columnGroups, group) {
213 for (var p in rowIn) {
214 if (rowIn.hasOwnProperty(p)) {
215 var value = rowIn[p];
216 if (value !== Object(value) && Utils.ContainsName(columns, p,
"name") < 0) {
217 columns.push({ name: p, type:
"string", editable:
true, display:
true, columnGroup: group });
219 }
else if (value === Object(value)) {
221 if (Utils.ContainsName(columnGroups, p,
"name") < 0) {
222 columnGroups.push({ name:
"" + p, text:
"" + p, parentGroup: group });
224 if (value.constructor === Array) {
225 for (var i in value) {
226 if (value.hasOwnProperty(i)) {
227 res = MakeColumns(value[i], index +
"." + i, columns, columnGroups, p);
228 columns = res.columns;
229 columnGroups = res.columnGroups;
230 res.row.name = rowIn.name +
"/" + p +
"___" + i;
231 res.row.index = index +
"." + i;
232 rowOut.children.push(res.row);
236 res = MakeColumns(value, index, columns, columnGroups, p);
237 columns = res.columns;
238 columnGroups = res.columnGroups;
239 for (var pp in res.row) {
240 if (res.row.hasOwnProperty(pp)) {
241 rowOut[pp] = res.row[pp];
251 if (rowOut.children.length === 0)
delete rowOut.children;
252 else if (Utils.ContainsName(columns,
"children",
"name") < 0) { columns.push({ name:
"children", type:
"array", editable:
false, display:
false }); }
254 return { row: rowOut, columns: columns, columnGroups: columnGroups };
263 function ParseSequence(sequence, name) {
264 console.log(
"ParseSequence: sequence: " + JSON.stringify(sequence, null, 4) +
", name: " + name);
266 var hasTable =
false;
269 var columnGroups = [];
270 columns.push({ name:
"index", type:
"number", editable:
false, display:
true, columnGroup: name });
271 columns.push({ name:
"name", type:
"string", editable:
false, display:
true, columnGroup: name });
273 for (var i = 0; i < sequence.length; ++i) {
274 if (sequence[i] === Object(sequence[i])) {
276 if (sequence[i].constructor === Array) {
278 var arr = ParseSequence(sequence[i], name +
"___" + i);
279 if (arr.children !== undefined && arr.children.length > 0) {
280 children.push({ name: name +
"___" + i, children: arr.children });
281 rows.push({ index: i, name: name +
"___" + i, children: arr.children });
282 if (Utils.ContainsName(columns,
"children",
"name") < 0) {
283 columns.push({ name:
"children", type:
"array", editable:
false, display:
false });
286 if (arr.rows !== undefined && arr.rows.length > 0) {
290 for (var r in arr.rows) {
291 if (arr.rows.hasOwnProperty(r)) {
292 rows.push(arr.rows[r]);
295 for (var c in arr.columns) {
296 if (arr.columns.hasOwnProperty(c) && Utils.ContainsName(columns, arr.columns[c].name,
"name") < 0) {
297 columns.push(arr.columns[c]);
304 console.log(
"Parsing as table: " + JSON.stringify(sequence[i], null, 4));
305 if (!sequence[i].hasOwnProperty(
"name") || sequence[i].name.length === 0) {
306 sequence[i].name = name +
"___" + i;
308 if (Utils.ContainsName(columnGroups, name,
"name") < 0) {
309 columnGroups.push({ name:
"" + name, text:
"" + name });
311 var res = MakeColumns(sequence[i], i, columns, columnGroups, name);
314 columns = res.columns;
315 columnGroups = res.columnGroups;
318 var vname = name +
"___" + i;
319 var value = sequence[i];
320 children.push({ name: vname, value: value });
321 rows.push({ index: i, name: vname, value: value });
322 if (Utils.ContainsName(columns,
"value",
"name") < 0) {
323 columns.push({ name:
"value", type:
"string", editable:
true, display:
true, columnGroup: name });
327 var comment = sequence.comment ? sequence.comment :
" ";
338 , columnGroups: columnGroups
341 console.log(
"\nParseSequence returning table: " + JSON.stringify(table, null, 4));
344 var output = { name: name, comment: comment, children: children };
345 console.log(
"\nParseSequence returning: " + JSON.stringify(output, null, 4));
356 function ParseFhiclTable(table, sub) {
357 console.log(
"ParseFhiclTable: table: " + JSON.stringify(table, null, 4) +
", sub: " + sub);
360 var hasSubtables =
false;
361 var comment = table.comment ? table.comment :
" ";
364 for (var e in table.children) {
365 if (table.children.hasOwnProperty(e)) {
366 var element = table.children[e];
367 if (element.type ===
"table" && element.isSequence) {
368 element.type =
"sequence";
371 switch (element.type) {
375 children.push(ParseFhiclTable(element, 1));
378 children.push(ParseSequence(element.children, element.name));
383 children.push(element);
386 console.log(
"Unknown type " + element.type +
" encountered!");
392 var obj = { name: table.name, hasSubtables: hasSubtables, children: children, subtables: subtables, type:
"table", comment: comment, columns: DefaultColumns };
393 if (sub === 0 || sub === undefined) {
399 function FindConfigs(configNameFilter, dbConfig) {
400 console.log(
"\nFindConfigs: Request for Named Configurations received");
401 var configsOutput = { Success:
false, data: [], configs: {} };
403 var configs = Connector.RunGetConfigsQuery(dbConfig).search;
404 for (var conf in configs) {
405 if (configs.hasOwnProperty(conf)) {
406 var config = configs[conf];
407 if (config.name.search(configNameFilter) >= 0) {
408 configsOutput.data.push(
"<option value=" + JSON.stringify(config.query) +
">" + config.name +
"</option>");
409 configsOutput.configs[config.name] = config.query;
413 if (configsOutput.data.length === 0) {
414 configsOutput.data.push(
"<option value=\"\">No Configurations Found</option>");
415 configsOutput.configs[configNameFilter] = {};
417 configsOutput.Success =
true;
419 console.log(
"Exception caught: " + e.name +
": " + e.message);
421 console.log(
"NamedConfigs complete");
422 return configsOutput;
425 function FindInstances(dbConfig) {
426 console.log(
"FindInstances: Request for Database Instances received");
427 var instancesOutput = { Success:
false, data: [] };
428 instancesOutput.data.push(
"<option value=\"NONE\">Create New Database Instance</option>");
430 var dbs = Connector.RunListDatabasesQuery(dbConfig, {}).search;
431 for (var db in dbs) {
432 if (dbs.hasOwnProperty(db)) {
433 instancesOutput.data.push(
"<option value=" + dbs[db].name +
">" + dbs[db].name +
"</option>");
436 instancesOutput.Success =
true;
438 console.log(
"Exception caught: " + e.name +
": " + e.message);
440 console.log(
"FindInstances complete");
441 return instancesOutput;
451 function LoadConfigFiles(configName, dirs, query, dbConfig) {
452 console.log(
"LoadConfigFiles: configName: " + configName +
", dirs: " + JSON.stringify(dirs, null, 4) +
", query: " + JSON.stringify(query, null, 4));
458 var configFiles = [];
461 configFiles = Connector.RunBuildFilterQuery(dbConfig, configName, query).search;
464 console.log(
"Exception occurred: " + e.name +
": " + e.message);
468 for (var file in configFiles) {
469 if (configFiles.hasOwnProperty(file)) {
470 console.log(
"File info: " + JSON.stringify(configFiles[file], null, 4));
471 var entity = LoadFile(configFiles[file], dirs, dbConfig).entity;
472 var collection = configFiles[file].query.collection;
473 if (!retval.collections.hasOwnProperty(collection)) {
474 retval.collections[collection] = {
479 console.log(
"Adding " + entity +
" to output list");
480 retval.collections[collection].files.push(entity);
483 retval.Success =
true;
485 console.log(
"Exception occurred: " + e.name +
": " + e.message);
491 function SearchFile(fileData, searchKey) {
492 console.log(
"\nSearching for " + searchKey +
" in object " + JSON.stringify(fileData, null, 4));
493 var retval = { name: fileData.name, children: [], columns: fileData.columns };
494 for (var ii in fileData.children) {
495 if (fileData.children.hasOwnProperty(ii)) {
496 var child = fileData.children[ii];
497 console.log(
"Key name: " + child.name);
498 if (child.name.indexOf(searchKey) !== -1) {
499 console.log(
"Adding child to output");
500 retval.children.push(child);
501 }
else if (child.children && child.children.length > 0) {
502 console.log(
"Searching child's children");
503 var table = SearchFile(child, searchKey);
504 if (table.children.length > 0) {
505 retval.children.push(table);
510 console.log(
"\nSearchFile returning " + JSON.stringify(retval, null, 4));
514 function SearchConfigFiles(searchKey, configName, dirs, dbConfig) {
515 console.log(
"\nSearchConfigFiles: keySearch: " + searchKey +
", configName: " + configName +
", dirs: " + JSON.stringify(dirs, null, 4));
519 columns: DefaultColumns,
523 var configFiles = [];
524 var query = FindConfigs(configName, dbConfig).configs[configName];
527 configFiles = Connector.RunBuildFilterQuery(dbConfig, configName, query).search;
530 console.log(
"Exception occurred: " + e.name +
": " + e.message);
534 for (var file in configFiles) {
535 if (configFiles.hasOwnProperty(file)) {
536 console.log(
"File info: " + JSON.stringify(configFiles[file], null, 4));
537 var entity = LoadFile(configFiles[file], dirs, dbConfig).entity;
538 var collection = configFiles[file].query.collection;
539 if (!retval.collectionsTemp.hasOwnProperty(collection)) {
540 retval.collectionsTemp[collection] = {
545 var fileData = GetData(configName, collection, entity, dirs);
546 fileData.name = entity;
547 var fileMatches = SearchFile(fileData, searchKey);
548 if (fileMatches.children.length > 0) {
549 console.log(
"Adding " + entity +
" to output list");
550 retval.collectionsTemp[collection].children.push(fileMatches);
554 retval.Success =
true;
556 console.log(
"Exception occurred: " + e.name +
": " + e.message);
560 for (var ii in retval.collectionsTemp) {
561 if (retval.collectionsTemp.hasOwnProperty(ii)) {
562 retval.collections.push(retval.collectionsTemp[ii]);
565 delete retval.collectionsTemp;
566 console.log(
"\nSearchConfigFiles returning: " + JSON.stringify(retval, null, 4));
582 function GetData(configName, collectionName, entity, dirs) {
583 console.log(
"GetData: configName: " + configName +
", collectionName: " + collectionName +
", entity: " + entity +
", dirs: " + JSON.stringify(dirs, null, 4));
584 var fileName = GetFilePath(configName, collectionName, entity, dirs,
false);
585 if (!fs.existsSync(fileName)) {
throw { name:
"FileNotFoundException", message:
"The requested file was not found" }; }
586 var jsonFile = JSON.parse(
"" + fs.readFileSync(fileName));
587 var jsonBase = ParseFhiclTable({ children: jsonFile.document.converted.guidata, name: entity }, 0);
592 function ReplaceByPath(obj, pathArr, data) {
593 console.log(
"Utils.ReplaceByPath: obj: " + JSON.stringify(obj, null, 4) +
", pathArr: " + JSON.stringify(pathArr, null, 4) +
", data: " + JSON.stringify(data, null, 4));
594 if (pathArr.length === 0 && (!obj.name || obj.name === data.name)) {
595 if (data.column && data.value) {
596 obj[data.column] = data.value;
597 }
else if (data.type) {
598 for (var i in data) {
599 if (data.hasOwnProperty(i)) {
607 var thisName = pathArr.shift();
609 if (obj.type ===
"table") {
610 index = Utils.ContainsName(obj.children, thisName,
"name");
611 }
else if (obj.type ===
"sequence") {
612 index = thisName.slice(thisName.indexOf(
"___") + 3);
615 obj.children[index] = ReplaceByPath(obj.children[index], pathArr, data);
628 function UpdateTable(configName, tablePath, data, dirs) {
629 console.log(
"UpdateTable: tablePath:" + tablePath +
", configName: " + configName +
", data: " + JSON.stringify(data, null, 4) +
", dirs: " + JSON.stringify(dirs, null, 4));
630 var tableArray = tablePath.split(
'/');
631 var collection = tableArray.shift();
632 var entity = tableArray.shift();
633 var fileName = GetFilePath(configName, collection, entity, dirs,
false);
634 if (!fs.existsSync(fileName)) {
throw { name:
"FileNotFoundException", message:
"The requested file: \"" + fileName +
"\" was not found" }; }
635 console.log(
"Reading from file " + fileName);
636 var jsonFile = JSON.parse(
"" + fs.readFileSync(fileName));
637 var oldFile = jsonFile.document.converted.guidata;
639 var curName = tableArray.shift();
640 var dataIdx = Utils.ContainsName(oldFile, curName,
"name");
642 console.log(
"Cannot find data in file!");
645 var oldData = oldFile[dataIdx];
646 console.log(
"oldData: " + JSON.stringify(oldData, null, 4));
647 ReplaceByPath(oldData, tableArray, data);
649 jsonFile.document.converted.guidata[dataIdx] = oldData;
650 console.log(
"After replacement, table data is " + JSON.stringify(oldData, null, 4));
652 var filePath = GetTempFilePath(configName, collection, entity, dirs);
653 console.log(
"Writing to file " + filePath);
654 fs.writeFileSync(filePath, JSON.stringify(jsonFile, null, 4));
664 function DiscardWorkingDir(dirs) {
665 console.log(
"Deleting existing trash dir (if any)");
666 Utils.ExecSync(
"rm -rf " + dirs.trash);
667 console.log(
"DiscardWorkingDir: Moving db temp to TRASH: mv " + dirs.db +
" " + dirs.trash);
668 Utils.ExecSync(
"mv " + dirs.db +
" " + dirs.trash);
669 console.log(
"DiscardWorkingDir: Moving temp files to TRASH: mv " + dirs.tmp +
"/* " + dirs.trash);
670 Utils.ExecSync(
"mv " + dirs.tmp +
"/* " + dirs.trash);
671 console.log(
"DiscardWorkingDir: Deleting temp directory: rmdir " + dirs.tmp);
672 Utils.ExecSync(
"rmdir " + dirs.tmp);
687 function SaveConfigurationChanges(oldConfig, newConfig, files, dirs, dbConfig) {
688 console.log(
"Saving Configuration Changes, oldConfig: " + oldConfig +
", newConfig: " + newConfig +
", files: " + JSON.stringify(files, null, 4) +
", dirs: " + JSON.stringify(dirs, null, 4));
689 var fileInfo = Connector.RunBuildFilterQuery(dbConfig, oldConfig).search;
693 if (files.hasOwnProperty(f)) {
694 console.log(
"Current file information: " + JSON.stringify(files[f], null, 4));
695 var collectionName = files[f].collection;
696 var entities = files[f].entities;
697 var entity = files[f].entity ? files[f].entity :
"notprovided";
698 var version = files[f].version;
699 var thisFileInfo = {};
700 for (var fi in fileInfo) {
701 if (fileInfo.hasOwnProperty(fi)) {
702 if (collectionName === fileInfo[fi].query.collection && Utils.ContainsString(entities, fileInfo[fi].query.filter[
"entities.name"]) != -1) {
703 console.log(
"Matched file information to Document: " + JSON.stringify(fileInfo[fi], null, 4));
704 thisFileInfo = fileInfo[fi];
705 entity = fileInfo[fi].query.filter[
"entities.name"];
706 fileInfo.splice(fi, 1);
711 console.log(
"Getting metadata from original and changed files");
712 var modified = GetFilePath(oldConfig, collectionName, entity, dirs,
false);
713 var newMetadata = ReadFileMetadata(dirs, thisFileInfo, dbConfig);
717 newMetadata.version = version;
718 console.log(
"newMetadata: " + JSON.stringify(newMetadata, null, 4));
720 console.log(
"Checking metadata version strings");
721 while (VersionExists(entity, collectionName, newMetadata.version, dbConfig)) {
722 console.log(
"Inferring new version string...");
723 version = Utils.Uniquify(newMetadata.version);
724 console.log(
"Changing version from " + newMetadata.version +
" to " + version);
725 newMetadata.version = version;
728 console.log(
"Prepending changelog");
729 newMetadata.changelog = files[f].changelog + newMetadata.changelog;
731 console.log(
"Writing new metadata to file");
732 if (WriteFileMetadata(newMetadata, modified)) {
734 console.log(
"Running store query");
735 var data =
"" + fs.readFileSync(modified);
736 console.log(
"Writing " + data +
" to database");
737 Connector.RunStoreQuery(dbConfig, data, collectionName, newMetadata.version, entity,
"gui", newConfig);
739 console.log(
"ERROR: Could not find file " + modified);
740 console.log(
"Please check if it exists.");
745 console.log(
"Running addconfig for unmodified files: " + JSON.stringify(fileInfo, null, 4));
746 for (f in fileInfo) {
747 if (fileInfo.hasOwnProperty(f)) {
748 var unmodifiedVersion = GetVersion(fileInfo[f], dirs, dbConfig);
749 Connector.RunAddConfigQuery(dbConfig, newConfig, unmodifiedVersion, fileInfo[f].query.collection, { name: fileInfo[f].query.filter[
"entities.name"] });
753 DiscardWorkingDir(dirs);
764 function CreateNewConfiguration(configName, configData, dbConfig) {
765 console.log(
"CreateNewConfigration: configName: " + configName +
", configData: " + JSON.stringify(configData, null, 4));
770 for (var d in configData.entities) {
771 if (configData.entities.hasOwnProperty(d)) {
772 var entityData = configData.entities[d];
773 console.log(
"Entity: " + JSON.stringify(entityData, null, 4));
774 query.operations.push({
775 filter: { version: entityData.version,
"entities.name": entityData.name },
776 configuration: configName,
777 collection: entityData.collection,
778 dbprovider: dbConfig.dbprovider,
779 operation:
"addconfig",
785 Connector.RunNewConfigQuery(dbConfig, query);
794 function ReadConfigurationMetadata(configName, dirs, dbConfig) {
795 console.log(
"ReadConfigurationMetadata: configname: " + configName +
", dirs: " + JSON.stringify(dirs, null, 4));
797 var data = Connector.RunBuildFilterQuery(dbConfig, configName ).search;
802 for (var i in data) {
803 if (data.hasOwnProperty(i)) {
804 console.log(
"Loading metadata: File " + i +
" of " + data.length);
805 var version = GetVersion(data[i], dirs, dbConfig);
806 metadata.entities.push({ name: data[i].query.filter[
"entities.name"], file: data[i].name +
"_" + data[i].query.collection, version: version, collection: data[i].query.collection });
810 console.log(
"Returning entity list: " + JSON.stringify(metadata.entities, null, 4));
822 function GetVersion(query, dirs, dbConfig) {
823 console.log(
"\"GetVersion\": {\"query\":" + JSON.stringify(query, null, 4) +
", \"dirs\":" + JSON.stringify(dirs, null, 4) +
"},");
824 var ver = LoadFile(query, dirs, dbConfig).data.version;
825 console.log(
"GetVersion Returning " + ver);
838 function ReadFileMetadata(dirs, query, dbConfig) {
839 console.log(
"ReadFileMetadata: query=" + JSON.stringify(query, null, 4) +
", dirs=" + JSON.stringify(dirs, null, 4) +
", dbConfig: " + JSON.stringify(dbConfig, null, 4));
841 var jsonFile = LoadFile(query, dirs, dbConfig).data;
842 if (jsonFile.changelog === undefined) {
843 jsonFile.changelog =
"";
846 entities: jsonFile.entities,
847 bookkeeping: jsonFile.bookkeeping,
848 aliases: jsonFile.aliases,
849 configurations: jsonFile.configurations,
850 version: jsonFile.version,
851 changelog: jsonFile.changelog,
852 collection: query.query.collection
855 console.log(
"ReadFileMetadata returning: " + JSON.stringify(metadata, null, 4));
865 function WriteFileMetadata(newMetadata, fileName) {
866 console.log(
"WriteFileMetadata: newMetadata=" + JSON.stringify(newMetadata, null, 4) +
", fileName=" + fileName);
868 console.log(
"Reading file: " + fileName);
869 if (!fs.existsSync(fileName))
return false;
870 var jsonFile = JSON.parse(
"" + fs.readFileSync(fileName));
873 console.log(
"Setting fields: " + JSON.stringify(newMetadata, null, 4));
874 jsonFile.configurable_entity = newMetadata.configurable_entity;
875 jsonFile.bookkeeping = newMetadata.bookkeeping;
876 jsonFile.aliases = newMetadata.aliases;
877 jsonFile.configurations = newMetadata.configurations;
878 jsonFile.version = newMetadata.version;
879 jsonFile.document.converted.changelog = newMetadata.changelog;
881 console.log(
"Writing data to file");
883 fs.writeFileSync(fileName, JSON.stringify(jsonFile, null, 4));
893 function GetDirectories(userId, dbConfig) {
894 console.log(
"GetDirectories: userid=" + userId);
895 if (dbConfig.baseDir ===
"" || !dbConfig.baseDir) {
896 dbConfig.baseDir = process.env[
"HOME"] +
"/databases";
897 console.log(
"WARNING: ARTDAQ_DATABASE_DATADIR not set. Using $HOME/databases instead!!!");
900 if (!fs.existsSync(dbConfig.baseDir)) {
901 console.log(
"ERROR: Base Directory " +dbConfig.baseDir +
" doesn't exist!!!");
902 throw { name:
"BaseDirectoryMissingException", message:
"ERROR: Base Directory doesn't exist!!!" };
904 if (!fs.existsSync(path_module.join(dbConfig.baseDir,
"db"))) {
905 fs.mkdirSync(path_module.join(dbConfig.baseDir,
"db"));
907 if (!fs.existsSync(path_module.join(dbConfig.baseDir,
"tmp"))) {
908 fs.mkdirSync(path_module.join(dbConfig.baseDir,
"tmp"));
910 if (!fs.existsSync(path_module.join(dbConfig.baseDir,
"TRASH"))) {
911 fs.mkdirSync(path_module.join(dbConfig.baseDir,
"TRASH"));
915 var db = path_module.join(dbConfig.baseDir,
"db", userId);
916 var tmp = path_module.join(dbConfig.baseDir,
"tmp", userId);
917 var trash = path_module.join(dbConfig.baseDir,
"TRASH", userId);
920 if (!fs.existsSync(db)) {
923 if (!fs.existsSync(tmp)) {
926 if (!fs.existsSync(trash)) {
930 return { db: db, tmp: tmp, trash: trash };
941 function VersionExists(entity, collection, version, dbConfig) {
942 console.log(
"\"VersionExists\": { version:\"" + version +
"\", entity:" + JSON.stringify(entity, null, 4) +
", collection: \"" + collection +
"\"}");
945 "entities.name": entity
947 collection: collection,
948 dbprovider: dbConfig.dbprovider,
949 operation:
"findversions",
952 var vers = Connector.RunGetVersionsQuery(dbConfig, query).search;
953 console.log(
"Search returned: " + JSON.stringify(vers, null, 4));
954 return Utils.ContainsName(vers, version,
"name") >= 0;
963 if (fs.existsSync(
"/tmp/node_db_lockfile")) {
964 if (Date.now() - fs.fstatSync(
"/tmp/node_db_lockfile").ctime.getTime() > 1000) {
965 console.log(
"Stale Lockfile detected, deleting...");
968 console.log(
"Lockfile detected and is not stale, aborting...");
973 fs.writeFileSync(
"/tmp/node_db_lockfile",
"locked");
982 console.log(
"Unlock");
983 fs.unlinkSync(
"/tmp/node_db_lockfile");
988 db.RO_GetData =
function (post, dbConfig) {
989 console.log(
"RO_GetData: " + JSON.stringify(post, null, 4));
990 var ret = { Success:
false, data: {} };
992 ret.data = GetData(post.configName, post.collection, post.entity, GetDirectories(post.user, dbConfig));
995 console.log(
"Exception occurred: " + e.name +
": " + e.message);
998 console.log(
"GetData complete");
1002 db.RW_MakeNewConfig =
function (post, dbConfig) {
1004 console.log(
"RW_MakeNewConfig: Request to make new configuration received: " + JSON.stringify(post, null, 4));
1005 var res = { Success:
false };
1009 var configs = Connector.RunGetConfigsQuery(dbConfig).search;
1010 if (!Utils.ValidatePath(post.name)) {
1011 console.log(
"Invalid name detected!");
1014 while (Utils.ContainsName(configs, post.name,
"name") >= 0) {
1015 console.log(
"Inferring new configuration name");
1016 post.name = Utils.Uniquify(post.name);
1020 console.log(
"Exception occurred: " + e.name +
": " + e.message);
1023 console.log(
"Creating Configuration");
1025 CreateNewConfiguration(post.name, JSON.parse(post.config), dbConfig);
1028 console.log(
"Exception occurred: " + e.name +
": " + e.message);
1032 console.log(
"MakeNewConfig completed");
1038 db.RW_saveConfig =
function (post, dbConfig) {
1040 console.log(
"RW_saveConfig: Request to save configuration recieved. Configuration data: " + JSON.stringify(post, null, 4));
1041 var res = { Success:
false };
1045 console.log(
"Checking for unique Configuration name");
1046 var configs = Connector.RunGetConfigsQuery(dbConfig).search;
1047 if (!Utils.ValidatePath(post.newConfigName) || Utils.ContainsName(configs, post.oldConfigName,
"name") < 0) {
1048 console.log(
"Invalid name detected!");
1051 while (Utils.ContainsName(configs, post.newConfigName,
"name") >= 0) {
1052 console.log(
"Inferring new configuration name");
1053 post.newConfigName = Utils.Uniquify(post.newConfigName);
1057 console.log(
"Exception occurred: " + e.name +
": " + e.message);
1061 console.log(
"Updating Configuration Files");
1062 SaveConfigurationChanges(post.oldConfigName, post.newConfigName, post.files, GetDirectories(post.user, dbConfig), dbConfig);
1065 console.log(
"Exception occurred: " + e.name +
": " + e.message);
1069 console.log(
"SaveConfig completed");
1075 db.RO_LoadNamedConfig =
function (post, dbConfig) {
1076 console.log(
"RO_LoadNamedConfig: Request for configuration with name \"" + post.configName +
"\" and search query \"" + post.query +
"\" received.");
1077 if (post.query.length === 0 || post.configName ===
"No Configurations Found") {
1078 return { collections: [] };
1080 return LoadConfigFiles(post.configName, GetDirectories(post.user, dbConfig), JSON.parse(post.query), dbConfig);
1083 db.RW_discardConfig =
function (post, dbConfig) {
1084 console.log(
"RW_discardConfig: Discarding configuration with parameters: " + JSON.stringify(post, null, 4));
1085 DiscardWorkingDir(GetDirectories(post.user, dbConfig));
1086 return { Success:
true };
1089 db.RO_AddOrUpdate =
function (post, dbConfig) {
1090 console.log(
"RO_AddOrUpdate: Request to update table row recieved: " + JSON.stringify(post, null, 4));
1091 UpdateTable(post.configName, post.table, post.row, GetDirectories(post.user, dbConfig));
1092 return { Success:
true };
1095 db.RO_Update =
function (post, dbConfig) {
1096 console.log(
"RO_Update: Request to update table received: " + JSON.stringify(post, null, 4));
1097 UpdateTable(post.configName, post.table, {
id: post.id, name: post.name, column: post.column, value: post.value }, GetDirectories(post.user, dbConfig));
1098 console.log(
"Update Complete");
1099 return { Success:
true };
1102 db.RO_LoadConfigMetadata =
function (post, dbConfig) {
1103 console.log(
"RO_LoadConfigMetadata: Request to load configuration metadata received: " + JSON.stringify(post, null, 4) +
", dbConfig: " + JSON.stringify(dbConfig, null, 4));
1104 var ret = { Success:
false, data: {} };
1106 ret.data = ReadConfigurationMetadata(post.configName, GetDirectories(post.user, dbConfig), dbConfig);
1109 console.log(
"Exception caught: " + e.name +
": " + e.message);
1111 console.log(
"LoadConfigMetadata complete");
1115 db.RO_LoadFileMetadata =
function (post, dbConfig) {
1116 console.log(
"RO_LoadFileMetadata: Request to load file metadata received: " + JSON.stringify(post, null, 4));
1117 var ret = { Success:
false, data: {} };
1118 var dirs = GetDirectories(post.user, dbConfig);
1123 var search = Connector.RunBuildFilterQuery(dbConfig, post.configName).search;
1124 for (var s in search) {
1125 if (search.hasOwnProperty(s)) {
1126 if (search[s].query.collection === post.collection && search[s].query.filter[
"entities.name"] === post.entity) {
1133 console.log(
"Exception caught: " + e.name +
": " + e.message);
1137 ret.data = ReadFileMetadata(dirs, query, dbConfig);
1140 console.log(
"Exception caught: " + e.name +
": " + e.message);
1143 console.log(
"LoadFileMetadata complete");
1147 db.RW_UploadConfigurationFile =
function (post, dbConfig) {
1149 console.log(
"RW_UploadConfigurationFile: Recieved request to upload file: " + JSON.stringify(post, null, 4));
1152 var ret = { Success:
false };
1154 while (VersionExists(post.entity, post.collection, post.version, dbConfig)) {
1155 console.log(
"Version already exists. Running uniquifier...");
1156 post.version = Utils.Uniquify(post.version);
1160 console.log(
"Exception caught: " + e.name +
": " + e.message);
1164 console.log(
"Running store fhicl query");
1166 Connector.RunStoreQuery(dbConfig, post.file, post.collection, post.version, post.entity, post.type);
1169 console.log(
"Exception caught: " + e.name +
": " + e.message);
1173 console.log(
"UploadConfigurationFile complete");
1179 db.RO_DownloadConfigurationFile =
function (post, dbConfig) {
1180 console.log(
"RO_DownloadConfigurationFile: Request to download file(s) received: " + JSON.stringify(post, null, 4));
1181 var dirs = GetDirectories(post.user, dbConfig);
1182 var configObj = JSON.parse(post.config);
1184 if (configObj.entities.length === 1) {
1185 console.log(
"Single file mode: Fetching file...");
1186 var fileInfo = FetchFile(configObj.entities[0], post.type, dirs.db, dbConfig);
1189 'Content-Type':
'text/plain',
1190 'Content-Length': fileInfo.size,
1191 'Content-Disposition':
'attachment filename=' + fileInfo.fileName
1193 console.log(
"Headers: " + JSON.stringify(fclhdrs, null, 4) +
", fileInfo: " + JSON.stringify(fileInfo, null, 4));
1195 var fclStream = fs.createReadStream(fileInfo.filePath);
1196 db.emit(
"stream", fclStream, fclhdrs, 200);
1197 }
else if (configObj.entities.length > 1) {
1199 for (var e in configObj.entities) {
1200 if (configObj.entities.hasOwnProperty(e)) {
1201 args.push(FetchFile(configObj.entities[e], post.type, dirs.db, dbConfig).fileName);
1204 var fileName = post.tarFileName +
".tar.gz";
1206 'Content-Type':
"application/x-gzip",
1207 'Content-Disposition':
'attachment filename=' + fileName
1210 console.log(
"Spawning: tar " + args.join(
" "));
1211 var tar = child_process.spawn(
"tar", args, { cwd: dirs.db, stdio: [0,
'pipe', 0] });
1212 db.emit(
"stream", tar.stdout, tarhdrs, 200);
1216 console.log(
"Exception caught: " + err.name +
": " + err.message);
1218 var s =
new stream.Readable();
1219 s._read =
function noop() { };
1224 'Content-Type':
'text/plain'
1226 db.emit(
"stream", s, errhdrs, 500);
1231 db.RO_NamedConfigs =
function (post, dbConfig) {
1232 console.log(
"RO_NamedConfigs: Request for Named Configurations received");
1233 var filter =
"" + post.configFilter;
1234 return FindConfigs(filter, dbConfig);
1237 db.RW_updateDbConfig =
function (post, dbConfig) {
1238 console.log(
"RW_updateDbConfig: Request to update module configuration received: " + JSON.stringify(post, null, 4));
1239 var output = { Success:
false };
1240 if (fs.existsSync(post.baseDir) && (post.dbprovider ===
"filesystem" || post.dbprovider ===
"mongo")) {
1241 if (dbConfig.baseDir !== post.baseDir) {
1242 dbConfig.baseDir = post.baseDir;
1243 db.emit(
"message", { name:
"db", target:
"baseDir", data: post.baseDir });
1245 if (dbConfig.dbprovider !== post.dbprovider) {
1246 dbConfig.dbprovider = post.dbprovider;
1247 db.emit(
"message", { name:
"db", target:
"dbprovider", data: post.dbprovider });
1249 if (dbConfig.instanceName !== post.instanceName) {
1250 dbConfig.instanceName = post.instanceName;
1251 db.emit(
"message", { name:
"db", target:
"instanceName", data: post.instanceName });
1253 console.log(
"DB Config is now: " + JSON.stringify(dbConfig, null, 4));
1254 output.Success =
true;
1259 db.RO_SearchLoadedConfig =
function (post, dbConfig) {
1260 console.log(
"RO_SearchLoadedConfig: Searching for keys containing name \"" + post.searchKey +
"\" from configuration name \"" + post.configName +
"\" received.");
1261 if (post.configName ===
"No Configurations Found") {
1262 return { Success:
false, collections: [] };
1264 return SearchConfigFiles(post.searchKey, post.configName, GetDirectories(post.user, dbConfig), dbConfig);
1267 db.RW_makeNewDBInstance =
function (post, dbConfig) {
1268 console.log(
"RW_makeNewDBInstance: Creating new database instance \"" + post.name +
"\".");
1269 dbConfig.instanceName = post.name;
1270 return { Success:
true };
1273 db.RW_AddEntityToFile =
function (post, dbConfig) {
1274 console.log(
"RW_AddEntityToFile: request to add entity name \"" + post.name +
"\" to configuration file " + post.configName +
"/" + post.collection +
"/" + post.entity);
1275 return { Success:
true };
1279 db.GET_EntitiesAndVersions =
function (dbConfig) {
1280 console.log(
"GET_EntitiesAndVersions: Request for current Entities and Versions received");
1286 var entities = Connector.RunGetEntitiesQuery(dbConfig).search;
1287 console.log(
"Returned entities: " + JSON.stringify(entities, null, 4));
1288 for (var ent in entities) {
1289 if (entities.hasOwnProperty(ent)) {
1290 var entity = entities[ent];
1291 var versions = Connector.RunGetVersionsQuery(dbConfig, entity.query);
1292 if (Utils.ContainsName(output.collections, entity.query.collection,
"name") < 0) {
1293 output.collections.push({ name: entity.query.collection, entities: [] });
1296 var index = Utils.ContainsName(output.collections, entity.query.collection,
"name");
1299 collection: entity.query.collection,
1303 output.collections[index].entities.push(entityObj);
1306 output.Success =
true;
1308 console.log(
"Exception caught: " + e.name +
": " + e.message);
1310 console.log(
"EntitiesAndVersions complete");
1314 db.GET_getDbConfig =
function (dbConfig) {
1315 console.log(
"GET_getDbConfig Request for Database Module Configuration received");
1317 var instances = FindInstances(dbConfig);
1320 baseDir: dbConfig.baseDir,
1321 dbprovider: dbConfig.dbprovider,
1322 instanceName: dbConfig.instanceName,
1323 data: instances.data
1329 db.MasterInitFunction =
function (workerData, config) {
1330 var dbConfig = MakeDbConfig(config);
1331 workerData[
"db"] = dbConfig;
1332 GetDirectories(
"", dbConfig);
1335 module.exports =
function (moduleHolder) {
1336 moduleHolder[
"db"] = db;