UNPKG

jsharmony-factory

Version:
596 lines (557 loc) 28.5 kB
/* Copyright 2017 apHarmony This file is part of jsHarmony. jsHarmony is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. jsHarmony is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this package. If not, see <http://www.gnu.org/licenses/>. */ var _ = require('lodash'); var fs = require('fs'); var async = require('async'); var Helper = require('jsharmony/Helper'); var HelperFS = require('jsharmony/HelperFS'); var XValidate = require('jsharmony-validate'); var SMS = require('../lib/SMS.js'); function AppSrvJobProc(jshFactory, db) { this.jshFactory = jshFactory; this.jsh = jshFactory.jsh; this.db = db; this.AppSrv = jshFactory.jsh.AppSrv; this.TaskHistory = {}; this.QueueHistory = {}; this.jobTimer = null; this.isRunning = false; this.runNextLoopImmediately = false; } AppSrvJobProc.prototype._transform = function(elem){ return this.jshFactory.transform.mapping[elem]; }; AppSrvJobProc.prototype._map = function(elem){ return this.jshFactory.Config.job_field_mapping[elem]; }; AppSrvJobProc.prototype.transform_db_params = function(params) { var _this = this; if (!params) return params; var rslt = {}; for (var f in params) { if (f in _this.jshFactory.transform.mapping) { rslt[_this.jshFactory.transform.mapping[f]] = params[f]; } else rslt[f] = params[f]; } return rslt; }; AppSrvJobProc.prototype.map_db_rslt = function(row) { var _this = this; if (!row) return row; var rslt = {}; var foundkeys = {}; for(var mapkey in _this.jshFactory.Config.job_field_mapping){ var mapval = _this.jshFactory.Config.job_field_mapping[mapkey]; if(mapval in row) rslt[mapkey] = row[mapval]; foundkeys[mapval] = true; } for (var f in row) { if(!(f in foundkeys)) rslt[f] = row[f]; } return rslt; }; AppSrvJobProc.prototype.Run = function () { var _this = this; if(_this.isRunning){ _this.runNextLoopImmediately = true; return; } _this.isRunning = true; if(_this.jobTimer) clearTimeout(_this.jobTimer); _this.jobTimer = null; function scheduleNextLoop(timeout){ _this.jobTimer = setTimeout(function () { _this.Run(); }, (_this.runNextLoopImmediately ? 1 : timeout)); _this.runNextLoopImmediately = false; _this.isRunning = false; } if (this.jshFactory.Config.debug_params.disable_job_processor){ return scheduleNextLoop(_this.jshFactory.Config.JobSleepDelay); } _this.CheckJobQueue(function (job) { if (job) { _this.ExecJob(job, function () { _this.CheckSubscriberQueue(function () { return scheduleNextLoop(_this.jshFactory.Config.JobSleepDelay); }); }); } else { _this.CheckSubscriberQueue(function () { return scheduleNextLoop(_this.jshFactory.Config.JobCheckDelay); }); } }); }; AppSrvJobProc.prototype.CheckJobQueue = function (onComplete) { var _this = this; if (_this.jshFactory.Config.enable_scheduler && _this.jshFactory.Config.scheduled_tasks) { var curdt = new Date(); for (var t in _this.jshFactory.Config.scheduled_tasks) { var task = _this.jshFactory.Config.scheduled_tasks[t]; if (!(t in this.TaskHistory)) this.TaskHistory[t] = new Date(0); if (task.when(curdt, this.TaskHistory[t])) { if(task.options && task.options.quiet){ /* Do nothing */ } else _this.jsh.Log.info('Running Task ' + t); task.action(this); this.TaskHistory[t] = curdt; } } } this.AppSrv.ExecRow('jobproc', _this._transform('jobproc_jobcheck'), [], {}, function (err, rslt) { if (err != null) { _this.jsh.Log.error(err); return onComplete(null); } if ((rslt != null) && (rslt.length == 1) && (rslt[0] != null)) { var job = _this.map_db_rslt(rslt[0]); return onComplete(job); } else return onComplete(null); }); }; AppSrvJobProc.prototype.ExecJob = function (job, onComplete) { var _this = this; if (_this.jshFactory.Config.debug_params.email_override) { if (job.email_to) job.email_to = _this.jshFactory.Config.debug_params.email_override; if (job.email_cc) job.email_cc = _this.jshFactory.Config.debug_params.email_override; if (job.email_bcc) job.email_bcc = _this.jshFactory.Config.debug_params.email_override; } if (_this.jshFactory.Config.debug_params.sms_override) { if (job.sms_to) job.sms_to = _this.jshFactory.Config.debug_params.sms_override; } _this.jsh.Log.info('Starting Job #' + job.job_id); if (_this.jshFactory.Config.debug_params.job_requests) _this.jsh.Log.info(job); if (job.job_action == 'REPORT') return _this.ExecJob_REPORT(job, onComplete); else if (job.job_action == 'MESSAGE') return _this.ExecJob_MESSAGE(job, onComplete); else if (job.job_action == 'TASK') return _this.ExecJob_TASK(job, onComplete); else return _this.SetJobResult(job, 'ERROR', 'job_action not Supported', onComplete); }; AppSrvJobProc.prototype.ExecJob_MESSAGE = function (job, onComplete) { var _this = this; if (job.job_action != 'MESSAGE') return _this.SetJobResult(job, 'ERROR', 'job_action not MESSAGE', onComplete); var rparams = {}; if (job.job_params){ try{ rparams = JSON.parse(job.job_params); } catch (ex) { return _this.SetJobResult(job, 'ERROR', 'Error parsing JOB MESSAGE - Invalid Parameter JSON: '+ex.toString(), onComplete); } } _this.processJobResult(job, rparams, '', undefined, 0, onComplete); }; AppSrvJobProc.prototype.ExecJob_TASK = function (job, onComplete) { var _this = this; var thisapp = this.AppSrv; if (job.job_action != 'TASK') return _this.SetJobResult(job, 'ERROR', 'job_action not TASK', onComplete); //Process Task ID (make sure it's in the system) var modelid = job.job_action_target; if (!thisapp.jsh.hasTask(undefined, modelid)) return _this.SetJobResult(job, 'ERROR', 'Invalid Task Model ID: ' + modelid, onComplete); var rparams = {}; if (job.job_params){ try{ rparams = JSON.parse(job.job_params); } catch (ex) { return _this.SetJobResult(job, 'ERROR', 'Error parsing JOB Parameters - Invalid Parameter JSON: '+ex.toString(), onComplete); } } thisapp.tasksrv.exec(undefined, undefined, undefined, modelid, rparams, function(err, rslt){ if(err) return _this.SetJobResult(job, 'ERROR', err.toString(), onComplete); _this.processJobResult(job, rparams, '', undefined, 0, onComplete); }); }; AppSrvJobProc.prototype.ExecJob_REPORT = function (job, onComplete) { var _this = this; var thisapp = this.AppSrv; if (job.job_action != 'REPORT') return _this.SetJobResult(job, 'ERROR', 'job_action not REPORT', onComplete); //Process Report ID (make sure it's in the system) var fullmodelid = job.job_action_target; if (!thisapp.jsh.hasModel(undefined, fullmodelid)) return _this.SetJobResult(job, 'ERROR', 'Report not found in collection', onComplete); var model = thisapp.jsh.getModel(undefined, fullmodelid); var reportFormat = model && model.format; var rparams = {}; if (job.job_params){ try{ rparams = JSON.parse(job.job_params); } catch (ex) { return _this.SetJobResult(job, 'ERROR', 'Error parsing JOB Parameters - Invalid Parameter JSON: '+ex.toString(), onComplete); } } thisapp.rptsrv.queueReport(undefined, undefined, fullmodelid, rparams, {}, { db: _this.db, dbcontext: 'jobproc', errorHandler: function(num, txt){ return _this.SetJobResult(job, 'ERROR', txt, onComplete); } }, function (err, tmppath, dispose, dbdata) { if (err) return _this.SetJobResult(job, 'ERROR', err.toString(), onComplete); /* Report Done */ fs.stat(tmppath, function (err, stat) { if (err != null) return _this.SetJobResult(job, 'ERROR', 'Report file not found: '+err.toString(), onComplete); var fsize = stat.size; if (fsize > _this.jsh.Config.max_filesize) return _this.SetJobResult(job, 'ERROR', 'Report file size exceeds system maximum file size', function () { if(onComplete) onComplete(); dispose(); }); //Report is available at tmppath _this.processJobResult(job, dbdata, tmppath, reportFormat, fsize, function () { if(onComplete) onComplete(); dispose(); }); }); }); }; AppSrvJobProc.prototype.processJobResult = function (job, dbdata, tmppath, reportFormat, fsize, onComplete) { var _this = this; var _transform = function(elem){ return _this._transform(elem); }; if (_this.jsh.Config.debug_params.report_debug) _this.jsh.Log.info(dbdata); var thisapp = this.AppSrv; var dbtypes = thisapp.DB.types; var doc_id = null; var queue_id = null; var doc_ext = null; if(reportFormat=='pdf') doc_ext = '.pdf'; else if(reportFormat=='xlsx') doc_ext = '.xlsx'; var saveD = function (callback) { let sqlparams = {}; sqlparams[_transform('doc_scope')] = job.doc_scope; sqlparams[_transform('doc_scope_id')] = job.doc_scope_id; sqlparams[_transform('doc_ctgr')] = job.doc_ctgr; sqlparams[_transform('doc_desc')] = job.doc_desc; sqlparams[_transform('doc_ext')] = doc_ext; sqlparams[_transform('doc_size')] = fsize; _this.db.Scalar('jobproc', _this._transform('jobproc_save_doc'), [dbtypes.VarChar(32), dbtypes.BigInt, dbtypes.VarChar(32), dbtypes.VarChar(255), dbtypes.VarChar(16), dbtypes.BigInt], sqlparams, function (err, rslt) { if ((err == null) && (rslt == null)) { _this.jsh.Log.error(err); err = Helper.NewError('Error inserting document', -99999); } if (err == null) doc_id = rslt; callback(err); }); }; var saveRQ = function (callback) { var queue_message = job.queue_message || '{}'; var queue_message_obj = {}; try { queue_message_obj = JSON.parse(queue_message); } catch (ex) { _this.jsh.Log.error('Error parsing '+_transform('queue_message')+': ' + queue_message_obj); } let sqlparams = {}; sqlparams[_transform('queue_name')] = job.queue_name; _this.db.Scalar('jobproc', _this._transform('jobproc_save_queue'), [dbtypes.VarChar(255)], sqlparams, function (err, rslt) { if ((err == null) && (rslt == null)) { _this.jsh.Log.error(err); err = Helper.NewError('Error inserting remote queue request', -99999); } if (err == null) { queue_id = rslt; queue_message_obj.url = '/_dl/'+_this.jshFactory.namespace+_transform('Queue__model')+'/' + queue_id + '/'+_transform('queue__tbl')+'_file'; queue_message_obj.filetype = reportFormat; let sqlparams = {}; sqlparams[_transform('queue_id')] = queue_id; sqlparams[_transform('queue_message')] = JSON.stringify(queue_message_obj); _this.db.Command('jobproc', _this._transform('jobproc_save_queue_message'), [dbtypes.BigInt, dbtypes.VarChar(dbtypes.MAX)], sqlparams, function (err, rslt) { callback(err); }); } else callback(err); }); }; var saveN = function (callback) { let sqlparams = {}; sqlparams[_transform('note_scope')] = job.note_scope; sqlparams[_transform('note_scope_id')] = job.note_scope_id; sqlparams[_transform('note_type')] = job.note_type; sqlparams[_transform('note_body')] = job.note_body; _this.db.Command('jobproc', _this._transform('jobproc_save_note'), [dbtypes.VarChar(32), dbtypes.BigInt, dbtypes.VarChar(32), dbtypes.VarChar(dbtypes.MAX)], sqlparams, function (err, rslt) { callback(err); }); }; var sendEMAIL = function (callback) { //Add attachment?? if (_this.jshFactory.Config.debug_params.no_job_email) return callback(null); var attachments = []; async.waterfall([ function(cb){ if (job.email_attach && tmppath){ fs.exists(tmppath, function(exists){ if(!exists) return cb(new Error('Report output does not exist')); var filename = _transform('doc__tbl') + (doc_id||'0') + doc_ext; if(job.email_attach.toString().substr(0,9)=='filename:') filename = job.email_attach.substr(9); attachments.push({ filename: filename, content: fs.createReadStream(tmppath) }); return cb(); }); } else return cb(); }, function(cb){ if (job.email_doc_id){ var email_doc_id_path = _this.jsh.Config.datadir + '/'+_transform('doc__tbl')+'/'+_transform('doc__tbl')+'_file_' + job.email_doc_id; fs.exists(email_doc_id_path, function(exists){ if(!exists) return cb(new Error('Email '+_transform('email_doc_id')+' does not exist')); attachments.push({ filename: job.email_doc_filename, content: fs.createReadStream(email_doc_id_path) }); return cb(); }); } else return cb(); }, function(cb){ if (job.email_txt_attrib) thisapp.jsh.SendTXTEmail('jobproc', job.email_txt_attrib, job.email_to, job.email_cc, job.email_bcc, attachments, dbdata, cb); else thisapp.jsh.SendBaseEmail('jobproc', job.email_subject, job.email_text, job.email_html, job.email_to, job.email_cc, job.email_bcc, attachments, dbdata, cb); } ], callback); }; var sendSMS = function (callback) { //Add attachment?? if (_this.jshFactory.Config.debug_params.no_job_sms) return callback(null); if (job.sms_txt_attrib) SMS.SendTXTSMS('jobproc', thisapp.jsh, job.sms_txt_attrib, job.sms_to, dbdata, callback); else SMS.SendBaseSMS('jobproc', thisapp.jsh, job.sms_body, job.sms_to, dbdata, callback); }; var execarr = []; if (job.doc_scope && tmppath) { execarr.push(saveD); execarr.push(function (cb) { HelperFS.copyFile(tmppath, (_this.jsh.Config.datadir +_transform('doc__tbl')+'/'+_transform('doc__tbl')+'_file_' + doc_id), cb); }); } if (job.queue_name && tmppath) { execarr.push(saveRQ); execarr.push(function (cb) { HelperFS.copyFile(tmppath, (_this.jsh.Config.datadir +_transform('queue__tbl')+'/'+_transform('queue__tbl')+'_file_' + queue_id), cb); }); } if (job.note_scope) execarr.push(saveN); if (job.sms_to) execarr.push(sendSMS); if (job.email_to) execarr.push(sendEMAIL); async.waterfall(execarr, function (err, rslt) { if(err && _this.jsh.Config.debug_params.report_debug) _this.jsh.Log.info(err); if (err) return _this.SetJobResult(job, 'ERROR', err.toString(), onComplete); else return _this.SetJobResult(job, 'OK', null, onComplete); }); }; AppSrvJobProc.prototype.SetJobResult = function (job, job_rslt, job_snotes, onComplete) { var _this = this; this.jsh.Log.info('Completed Job #' + job.job_id + ': ' + job_rslt + (job_snotes ? ' - ' + job_snotes : '')); var dbtypes = this.AppSrv.DB.types; let sqlparams = {}; sqlparams[_this._transform('job_rslt')] = job_rslt; sqlparams[_this._transform('job_snotes')] = job_snotes; sqlparams[_this._transform('job_id')] = job.job_id; this.AppSrv.ExecRow('jobproc', _this._transform('jobproc_jobresult'), [dbtypes.VarChar(32), dbtypes.VarChar(dbtypes.MAX), dbtypes.BigInt], sqlparams, function (err, rslt) { onComplete(); }); }; AppSrvJobProc.prototype.AddDBJob = function (req, res, jobtasks, jobtaskid, _jrow, fullmodelid, rparams) { var rslt = false; this.AddDBJobBase(req._DBContext, jobtasks, jobtaskid, _jrow, fullmodelid, rparams, function(err){ if(err){ return Helper.GenError(req, res, -99999, err.message); } rslt = true; }); return rslt; }; AppSrvJobProc.prototype.AddDBJobBase = function (dbcontext, jobtasks, jobtaskid, _jrow, fullmodelid, rparams, callback) { var _this = this; var _transform = function(elem){ return _this._transform(elem); }; var thisapp = this.AppSrv; var dbtypes = thisapp.DB.types; var jobvalidate = new XValidate(); var jrow = _this.map_db_rslt(_jrow); var job_sql = this.AppSrv.getSQL('',_this._transform('jobproc_add_BEGIN')); var job_sql_ptypes = [dbtypes.VarChar(32), dbtypes.VarChar(32), dbtypes.VarChar(50), dbtypes.VarChar(dbtypes.MAX), dbtypes.Int]; var job_sql_params = {}; job_sql_params['job_source'] = jrow.job_source; job_sql_params['job_action'] = 'REPORT'; job_sql_params['job_action_target'] = fullmodelid; job_sql_params['job_params'] = JSON.stringify(rparams); job_sql_params['job_prty'] = jrow.job_prty||0; jobvalidate.AddValidator('_obj.job_source', _transform('job_source'), 'B', [XValidate._v_MaxLength(32), XValidate._v_Required()]); jobvalidate.AddValidator('_obj.job_prty', _transform('job_prty'), 'B', [XValidate._v_IsNumeric(), XValidate._v_Required()]); if ('doc_scope' in jrow) { //Add Document to Job if (!('doc_scope_id' in jrow) || !('doc_ctgr' in jrow) || !('doc_desc' in jrow)) throw new Error('Job with d_scope requires d_scope_id, d_ctgr, and d_desc'); job_sql += this.AppSrv.getSQL('',_this._transform('jobproc_add_doc')); job_sql_ptypes.push(dbtypes.VarChar(32)); job_sql_params['doc_scope'] = jrow.doc_scope; jobvalidate.AddValidator('_obj.doc_scope', _transform('doc_scope'), 'B', [XValidate._v_MaxLength(32), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.BigInt); job_sql_params['doc_scope_id'] = jrow.doc_scope_id; jobvalidate.AddValidator('_obj.doc_scope_id', _transform('doc_scope_id'), 'B', [XValidate._v_IsNumeric(), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.VarChar(32)); job_sql_params['doc_ctgr'] = jrow.doc_ctgr; jobvalidate.AddValidator('_obj.doc_ctgr', _transform('doc_ctgr'), 'B', [XValidate._v_MaxLength(32), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.VarChar(255)); job_sql_params['doc_desc'] = jrow.doc_desc; jobvalidate.AddValidator('_obj.doc_desc', _transform('doc_desc'), 'B', [XValidate._v_MaxLength(255), XValidate._v_Required()]); } if ('queue_name' in jrow) { //Add Queue to Job job_sql += this.AppSrv.getSQL('',_this._transform('jobproc_add_queue')); job_sql_ptypes.push(dbtypes.VarChar(255)); job_sql_params['queue_name'] = jrow.queue_name; jobvalidate.AddValidator('_obj.queue_name', _transform('queue_name'), 'B', [XValidate._v_MaxLength(255), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.VarChar(dbtypes.MAX)); job_sql_params['queue_message'] = jrow.queue_message || ''; jobvalidate.AddValidator('_obj.queue_message', _transform('queue_message'), 'B', [XValidate._v_MaxLength(32)]); } if ('email_to' in jrow) { //Add Email to Job if (!('email_txt_attrib' in jrow) && !('email_subject' in jrow)) throw new Error('Job with email_to requires email_txt_attrib or email_subject'); job_sql += this.AppSrv.getSQL('',_this._transform('jobproc_add_email')); job_sql_ptypes.push(dbtypes.VarChar(32)); job_sql_params['email_txt_attrib'] = jrow.email_txt_attrib; jobvalidate.AddValidator('_obj.email_txt_attrib', _transform('email_txt_attrib'), 'B', [XValidate._v_MaxLength(32)]); job_sql_ptypes.push(dbtypes.VarChar(255)); job_sql_params['email_to'] = jrow.email_to; jobvalidate.AddValidator('_obj.email_to', _transform('email_to'), 'B', [XValidate._v_MaxLength(255), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.VarChar(255)); job_sql_params['email_cc'] = jrow.email_cc || null; jobvalidate.AddValidator('_obj.email_cc', _transform('email_cc'), 'B', [XValidate._v_MaxLength(255)]); job_sql_ptypes.push(dbtypes.VarChar(255)); job_sql_params['email_bcc'] = jrow.email_bcc || null; jobvalidate.AddValidator('_obj.email_bcc', _transform('email_bcc'), 'B', [XValidate._v_MaxLength(255)]); job_sql_ptypes.push(dbtypes.VarChar(dbtypes.MAX)); job_sql_params['email_attach'] = jrow.email_attach || null; job_sql_ptypes.push(dbtypes.VarChar(500)); job_sql_params['email_subject'] = jrow.email_subject || null; jobvalidate.AddValidator('_obj.email_subject', _transform('email_subject'), 'B', [XValidate._v_MaxLength(500)]); job_sql_ptypes.push(dbtypes.VarChar(dbtypes.MAX)); job_sql_params['email_text'] = jrow.email_text || null; job_sql_ptypes.push(dbtypes.VarChar(dbtypes.MAX)); job_sql_params['email_html'] = jrow.email_html || null; job_sql_ptypes.push(dbtypes.BigInt); job_sql_params['email_doc_id'] = jrow.email_doc_id || null; jobvalidate.AddValidator('_obj.email_doc_id', _transform('email_doc_id'), 'B', [XValidate._v_IsNumeric()]); } if ('sms_to' in jrow) { //Add SMS to Job if (!('sms_txt_attrib' in jrow) && !('sms_body' in jrow)) throw new Error('Job with sms_to requires sms_txt_attrib or sms_body'); job_sql += this.AppSrv.getSQL('',_this._transform('jobproc_add_sms')); job_sql_ptypes.push(dbtypes.VarChar(32)); job_sql_params['sms_txt_attrib'] = jrow.sms_txt_attrib; jobvalidate.AddValidator('_obj.sms_txt_attrib', _transform('sms_txt_attrib'), 'B', [XValidate._v_MaxLength(32)]); job_sql_ptypes.push(dbtypes.VarChar(255)); job_sql_params['sms_to'] = jrow.sms_to; jobvalidate.AddValidator('_obj.sms_to', _transform('sms_to'), 'B', [XValidate._v_MaxLength(255), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.VarChar(dbtypes.MAX)); job_sql_params['sms_body'] = jrow.sms_body || null; } if ('note_scope' in jrow) { //Add Note to Job if (!('note_scope_id' in jrow) || !('note_type' in jrow) || !('note_body' in jrow)) throw new Error('Job with n_scope requires n_scope_id, n_type, and n_note'); job_sql += this.AppSrv.getSQL('',_this._transform('jobproc_add_note')); job_sql_ptypes.push(dbtypes.VarChar(32)); job_sql_params['note_scope'] = jrow.note_scope; jobvalidate.AddValidator('_obj.note_scope', _transform('note_scope'), 'B', [XValidate._v_MaxLength(32), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.BigInt); job_sql_params['note_scope_id'] = jrow.note_scope_id; jobvalidate.AddValidator('_obj.note_scope_id', _transform('note_scope_id'), 'B', [XValidate._v_IsNumeric(), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.VarChar(32)); job_sql_params['note_type'] = jrow.note_type; jobvalidate.AddValidator('_obj.note_type', _transform('note_type'), 'B', [XValidate._v_MaxLength(32), XValidate._v_Required()]); job_sql_ptypes.push(dbtypes.VarChar(dbtypes.MAX)); job_sql_params['note_body'] = jrow.note_body; jobvalidate.AddValidator('_obj.note_body', _transform('note_body'), 'B', [XValidate._v_Required()]); } job_sql += this.AppSrv.getSQL('',_this._transform('jobproc_add_END')); var verrors = _.merge(verrors, jobvalidate.Validate('B', job_sql_params)); //Transform job_sql_params job_sql_params = _this.transform_db_params(job_sql_params); if (!_.isEmpty(verrors)) { return callback(new Error('Error during job queue: ' + verrors[''].join('\n') + ' ' + JSON.stringify(job_sql_params))); } //Add SQL to Transaction jobtasks[jobtaskid] = function (dbtrans, callback, transtbl) { _this.db.Scalar(dbcontext, job_sql, job_sql_ptypes, job_sql_params, dbtrans, function (err, rslt) { if (err != null) { err.sql = job_sql; } callback(err, rslt); }); }; return callback(); }; AppSrvJobProc.prototype.SetSubscriberQueueResult = function (queue_id, queue_rslt, queue_snotes, onComplete) { var _this = this; _this.jsh.Log.info('Completed Queue Task #' + queue_id + ': ' + queue_rslt + (queue_snotes ? ' - ' + queue_snotes : '')); var dbtypes = this.AppSrv.DB.types; let sqlparams = {}; sqlparams[_this._transform('queue_rslt')] = queue_rslt; sqlparams[_this._transform('queue_snotes')] = queue_snotes; sqlparams[_this._transform('queue_id')] = queue_id; this.AppSrv.ExecRow('jobproc', _this._transform('jobproc_queueresult'), [dbtypes.VarChar(32), dbtypes.VarChar(dbtypes.MAX), dbtypes.BigInt], sqlparams, function (err, rslt) { if (err) { _this.jsh.Log.error(err); } if (onComplete) onComplete(); }); }; AppSrvJobProc.prototype.SubscribeToQueue = function (req, res, queue_name) { //Check if queue has a message, otherwise, add to subscriptions var _this = this; var dbtypes = this.AppSrv.DB.types; let sqlparams = {}; sqlparams[_this._transform('queue_name')] = queue_name; this.AppSrv.ExecRow('jobproc', _this._transform('jobproc_queuecheck'), [dbtypes.VarChar(255)], sqlparams, function (err, rslt) { if (err != null) { _this.jsh.Log.error(err); return Helper.GenError(req, res, -99999, err); } if ((rslt != null) && (rslt.length == 1) && (rslt[0])) { var queuetask = _this.map_db_rslt(rslt[0]); _this.jsh.Log.info('Notifying subscriber ' + queue_name); var msg = JSON.stringify({ ID: queuetask.queue_id, MESSAGE: queuetask.queue_message }); res.send(msg); } else { _this.AppSrv.QueueSubscriptions.push({ id: queue_name, req: req, res: res }); req.on('close', function(){ for(var i=0;i<_this.AppSrv.QueueSubscriptions.length;i++){ var queue = _this.AppSrv.QueueSubscriptions[i]; if(queue.req === req){ _this.AppSrv.QueueSubscriptions.splice(i, 1); i--; } } }); } }); }; AppSrvJobProc.prototype.CheckSubscriberQueue = function (onComplete) { var _this = this; if(_.isEmpty(_this.AppSrv.jsh.Config.queues)) return onComplete(); for(var queueName in _this.QueueHistory){ if(_this.QueueHistory[queueName]==1) _this.QueueHistory[queueName] = 2; else delete _this.QueueHistory[queueName]; } this.AppSrv.ExecRecordset('jobproc', _this._transform('jobproc_queuesubscribers'), [], {}, function (err, rslt) { if (err != null) { _this.jsh.Log.error(err); return onComplete(null); } //Handle invalid queue //Update results if ((rslt != null) && (rslt.length == 1) && (rslt[0])) { async.each(rslt[0], function (row, queue_cb) { var queuetask = _this.map_db_rslt(row); if (!(queuetask.queue_name in _this.AppSrv.jsh.Config.queues)) { _this.SetSubscriberQueueResult(queuetask.queue_id, 'ERROR', 'Queue not set up in config', queue_cb); } else { if(!_this.QueueHistory[queuetask.queue_name]) _this.jsh.Log.info('Message for queue ' + queuetask.queue_name); _this.QueueHistory[queuetask.queue_name] = 1; var msg = JSON.stringify({ ID: queuetask.queue_id, MESSAGE: queuetask.queue_message }); _this.AppSrv.SendQueue(queuetask.queue_name, msg); queue_cb(null); } }, function (err) { if (err) _this.jsh.Log.error(err); return onComplete(null); }); } }); }; AppSrvJobProc.prototype.PopQueue = function (req, res, queue_name, queueresult, onComplete) { var _this = this; var dbtypes = this.AppSrv.DB.types; let sqlparams = {}; sqlparams[_this._transform('queue_id')] = queueresult.ID; sqlparams[_this._transform('queue_name')] = queue_name; this.AppSrv.ExecScalar('jobproc', _this._transform('jobproc_queuepop'), [dbtypes.BigInt, dbtypes.VarChar(255)], sqlparams, function (err, rslt) { if (err) { return Helper.GenError(req, res, -99999, err); } else if ((rslt == null) || (rslt.length != 1) || (!rslt[0])) { return Helper.GenError(req, res, -99999, 'Queue item ID does not exist or has already been resulted.'); } _this.SetSubscriberQueueResult(queueresult.ID, queueresult.RSLT, queueresult.NOTES, function () { //Delete request file, if applicable if (queueresult.RSLT == 'OK') HelperFS.tryUnlink((_this.jsh.Config.datadir +_this._transform('queue__tbl')+'/'+_this._transform('queue__tbl')+'_file_' + queueresult.ID), onComplete); else if (onComplete) onComplete(); }); }); }; module.exports = AppSrvJobProc;