futoin-xferengine
Version:
Neutral clustered multi-currency transaction engine with limits
194 lines (164 loc) • 5.16 kB
JavaScript
;
/**
* @file
*
* Copyright 2017 FutoIn Project (https://futoin.org)
* Copyright 2017 Andrey Galkin <andrey@futoin.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const XferTools = require( './XferTools' );
const UUIDTool = require( './UUIDTool' );
const SpecTools = require( 'futoin-invoker/SpecTools' );
const {
DB_MESSAGE_TABLE,
EVTGEN_ALIAS,
historyTimeBarrier,
} = require( './main' );
const g_msgtools_types = {
iface : 'messagetools.types',
version : '1.0',
};
const TypeSpec = Object.assign( {
ftn3rev: '1.9',
types: {
HolderID: "string",
MessageInfo : {
type: 'map',
fields: {
sender: 'HolderID',
recipient: {
type: 'HolderID',
optional: true,
},
ext_id : 'string',
orig_ts: 'string',
data: 'map',
rel_id : {
type: 'string',
optional: true,
},
},
},
},
}, g_msgtools_types );
/**
* XferTools with focus on Message processing
*/
class MessageTools extends XferTools {
constructor( ccm ) {
super( ccm, 'Payments' );
this._msg_types = null;
}
_checkExistingMessage( as, msg ) {
//---
const barrier = historyTimeBarrier();
if ( barrier.isAfter( msg.orig_ts ) ) {
as.error( 'OriginalTooOld' );
}
//---
this.db.select( DB_MESSAGE_TABLE )
.where( 'ext_id', msg.ext_id )
.executeAssoc( as );
as.add( ( as, rows ) => {
if ( !rows.length ) {
return;
}
const r = rows[0];
msg.id = r.uuidb64;
//---
if ( ( msg.sender !== r.sender ) ||
( msg.recipient !== r.recipient ) ||
( JSON.stringify( msg.data ) !== r.data ) ||
( msg.rel_id !== r.rel_uuidb64 )
) {
as.error( 'OriginalMismatch' );
}
} );
}
_checkRelId( as, msg ) {
if ( !msg.rel_id ) {
return;
}
const q = this.db.select( DB_MESSAGE_TABLE )
.get( 'uuidb64' )
.where( 'uuidb64', msg.rel_id );
// user message
if ( msg.recipient === null ) {
q.where( [
'OR',
{ sender: msg.sender },
{ recipient: msg.sender },
] );
}
q.execute( as );
as.add( ( as, { rows } ) => {
if ( !rows.length ) {
as.error( 'UnknownRelID' );
}
} );
}
_recordMessage( as, msg ) {
if ( msg.id ) {
return;
}
const dbxfer = this.db.newXfer();
//---
msg.id = UUIDTool.genXfer( dbxfer );
//---
dbxfer.insert( DB_MESSAGE_TABLE )
.set( {
uuidb64: msg.id,
ext_id: msg.ext_id,
sender: msg.sender,
recipient: msg.recipient,
data: JSON.stringify( msg.data ),
rel_uuidb64: msg.rel_id,
created: dbxfer.helpers().now(),
} );
//---
this._ccm.iface( EVTGEN_ALIAS )
.addXferEvent( dbxfer, 'MSG', msg );
//---
this._processLimits(
as, dbxfer,
( msg.recipient === null ) ? 'Misc' : 'Personnel',
msg.sender, null, {
message_daily_cnt: 1,
message_weekly_cnt: 1,
message_monthly_cnt: 1,
}
);
as.add( ( as ) => dbxfer.execute( as ) );
}
processMessage( as, msg ) {
this._load_local_face( as, g_msgtools_types, TypeSpec );
as.add( ( as ) => {
// check data for consistency
// TODO; disable for production
if ( !SpecTools.checkCompiledType( as, g_msgtools_types, 'MessageInfo', msg ) ) {
as.error( 'XferError', 'Invalid message data' );
}
} );
as.add(
( as ) => {
as.add( ( as ) => this._checkExistingMessage( as, msg ) );
as.add( ( as ) => this._checkRelId( as, msg ) );
as.add( ( as ) => this._recordMessage( as, msg ) );
as.add( ( as ) => as.success( msg.id ) );
},
( as, err ) => this._handleError( as, err, 'MSG_ERR', msg, msg.sender )
);
}
}
module.exports = MessageTools;