diff --git a/lib/historyKeeper.js b/lib/historyKeeper.js index aa320f4b6..7e45faf08 100644 --- a/lib/historyKeeper.js +++ b/lib/historyKeeper.js @@ -38,6 +38,7 @@ module.exports.create = function (config, cb) { channel_cache: {}, queueStorage: WriteQueue(), queueDeletes: WriteQueue(), + queueValidation: WriteQueue(), batchIndexReads: BatchRead("HK_GET_INDEX"), batchMetadata: BatchRead('GET_METADATA'), diff --git a/lib/hk-util.js b/lib/hk-util.js index 562114ec7..81984b300 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -859,23 +859,30 @@ HK.onChannelMessage = function (Env, Server, channel, msgStruct) { // trim the checkpoint indicator off the message if it's present let signedMsg = (isCp) ? msgStruct[4].replace(CHECKPOINT_PATTERN, '') : msgStruct[4]; - // convert the message from a base64 string into a Uint8Array - - //const txid = Util.uid(); // Listen for messages - //console.log(+new Date(), "Send verification request"); - Env.validateMessage(signedMsg, metadata.validateKey, w(function (err) { - // no errors means success - if (!err) { return; } - // validation can fail in multiple ways - if (err === 'FAILED') { - // we log this case, but not others for some reason - Log.info("HK_SIGNED_MESSAGE_REJECTED", 'Channel '+channel.id); - } - // always abort if there was an error... - return void w.abort(); - })); + /* queueing this helps avoid race conditions in which workers + validate and write messages in a different order than they were received. + For best effect the validate and store should actually be queued atomically, + but this is a step in the right direction. + */ + var proceed = w(); + Env.queueValidation(channel.id, function (next) { + Env.validateMessage(signedMsg, metadata.validateKey, function (err) { + // always go on to the next item in the queue regardless of the outcome + next(); + + // no errors means success + if (!err) { return proceed(); } + // validation can fail in multiple ways + if (err === 'FAILED') { + // we log this case, but not others for some reason + Log.info("HK_SIGNED_MESSAGE_REJECTED", 'Channel '+channel.id); + } + // always abort if there was an error... + return void w.abort(); + }); + }); }).nThen(function () { // do checkpoint stuff... diff --git a/lib/log.js b/lib/log.js index 386ee6b41..a815500b0 100644 --- a/lib/log.js +++ b/lib/log.js @@ -28,7 +28,7 @@ var handlers = {}; handlers[level] = function (ctx, content) { console.log(content); }; }); ['warn', 'error'].forEach(function (level) { - handlers[level] = function (ctx, content) { console.error(content); } + handlers[level] = function (ctx, content) { console.error(content); }; }); var noop = function () {}; diff --git a/lib/workers/index.js b/lib/workers/index.js index 911b34337..6858dffb5 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -8,7 +8,7 @@ const Workers = module.exports; const PID = process.pid; const DB_PATH = 'lib/workers/db-worker'; -const MAX_JOBS = 16; +const MAX_JOBS = 8; Workers.initialize = function (Env, config, _cb) { var cb = Util.once(Util.mkAsync(_cb)); @@ -97,7 +97,7 @@ Workers.initialize = function (Env, config, _cb) { // track which worker is doing which jobs state.tasks[txid] = msg; - response.expect(txid, cb, 60000); + response.expect(txid, cb, 180000); state.worker.send(msg); }; diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index 84532c6c5..96d89b44b 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -32,9 +32,18 @@ .cp-support-list-message { &:last-child:not(.cp-support-fromadmin) { color: @colortheme_cp-red; - background-color: lighten(@colortheme_cp-red, 25%); + background-color: lighten(@colortheme_form-warning, 25%); .cp-support-showdata { - background-color: lighten(@colortheme_cp-red, 30%); + background-color: lighten(@colortheme_form-warning, 30%); + } + } + + &:last-child { + &.cp-support-frompremium { + background-color: lighten(@colortheme_cp-red, 25%); + .cp-support-showdata { + background-color: lighten(@colortheme_cp-red, 30%); + } } } } diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index fc9c4046c..48f800075 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -23,7 +23,7 @@ define([ init: function () {} }; - var mermaidThemeCSS = ".node rect { fill: #DDD; stroke: #AAA; } " + + var mermaidThemeCSS = //".node rect { fill: #DDD; stroke: #AAA; } " + "rect.task, rect.task0, rect.task2 { stroke-width: 1 !important; rx: 0 !important; } " + "g.grid g.tick line { opacity: 0.25; }" + "g.today line { stroke: red; stroke-width: 1; stroke-dasharray: 3; opacity: 0.5; }"; diff --git a/www/support/ui.js b/www/support/ui.js index 2038d8ddd..ba6ae9967 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -188,6 +188,7 @@ define([ var senderKey = content.sender && content.sender.edPublic; var fromMe = senderKey === privateData.edPublic; var fromAdmin = ctx.adminKeys.indexOf(senderKey) !== -1; + var fromPremium = Boolean(content.sender.plan); var userData = h('div.cp-support-showdata', [ Messages.support_showData, @@ -199,8 +200,10 @@ define([ ev.stopPropagation(); }); + var adminClass = (fromAdmin? '.cp-support-fromadmin': ''); + var premiumClass = (fromPremium && !fromAdmin? '.cp-support-frompremium': ''); var name = Util.fixHTML(content.sender.name) || Messages.anonymous; - return h('div.cp-support-list-message' + (fromAdmin? '.cp-support-fromadmin': ''), { + return h('div.cp-support-list-message' + adminClass + premiumClass, { 'data-hash': hash }, [ h('div.cp-support-message-from' + (fromMe ? '.cp-support-fromme' : ''), [