const util = require('util'); const utils = require('./utils'); const db = require("./db"); const log = require("./log"); const boxrepairer = require('./boxrepairer'); const bc = require('./blockchain'); const C = require('./C'); class BoxOrder { constructor(orderDb, isNewOrder) { this.isNewOrder = isNewOrder; this.orderDb = orderDb; this.repairer = new boxrepairer.BoxRepairer(this); } init () { if (this.isNewOrder) { setTimeout(this.start.bind(this), 1000 * 0.1 + Math.floor(Math.random() * 100)); } else { setTimeout(this.start.bind(this), 1000 * 1 + Math.floor(Math.random() * 1000 * 3)); } } async start() { if (this.isPaid()) { //修复已支付成功订单的t_box表关系 await this.repairer.repairPaidOrder(); return; } if (this.isExpired()) { //修复已过期订单的t_box表关系 await this.repairer.repairExpiredOrder(); return; } if (this.isFail()) { //修复支付失败的订单 await this.repairer.repairFailOrder(); return; } if (!this.isSynced()) { //查询 const found = await this.bcSearch(); if (!found) { //上链 const ok = await this.bcSync(); if (!ok) { utils.emitEvent(C.REMOVE_PENDING_ORDER_EVENT, this.getOrderId()); return; } } } //等待确认支付成功 await this.bcConfirm(); } async bcSearch() { const logClass = 'bcSearch'; const events = await bc.mallInstance.getPastEvents( 'BEBoxPaid', { fromBlock: 0, toBlock: 'latest', filter: { boxId: this.getOrderId() } }); if (events.length > 0) { while (true) { const err = await this.setSynced(logClass); if (!err) { break; } await utils.sleep(1000 * 3); } this.orderDb['bc_synced'] = 1; } return events.length > 0; } async bcSync() { const logClass = 'bcSync'; const doSync = async () => { console.log(this.orderDb); const result = await bc.mallInstance.methods.buyBoxWithSignature( this.orderDb['order_id'], this.orderDb['item_id'], this.orderDb['buyer_address'], this.orderDb['price'], this.orderDb['payment_token_address'], this.orderDb['nonce'], this.orderDb['signature']).send({gas: 1000000}); return result; }; while (true) { try { const result = doSync(); } catch (e) { log.warning(util.format('%s end orderDb:%s err:s', logClass, JSON.stringify(this.orderDb), e ) ); } await utils.sleep(1000 * 3 + Math.random() * 1000); } } async bcConfirm() { const logClass = 'bcConfirm'; while (true) { if (bc.isComfirmed(this.getBlockNumber())) { break; } await utils.sleep(1000 * 3); } while (true) { const err = await this.setPaidState(logClass); if (!err) { break; } await utils.sleep(1000 * 3); } { const {err, boxDb} = await this.getBoxDb(logClass); if (err || !boxDb) { log.warning(util.format('%s box not found orderDb:%s err:%s', logClass, JSON.stringify(this.boxOrder.getOrderDb()), err ) ); return; } while (true) { const err = await this.setBoxPaidState(logClass, boxDb); if (!err) { break; } await utils.sleep(1000 * 3); } } while (true) { const err = await this.setDone(logClass); if (!err) { break; } await utils.sleep(1000 * 3); } utils.emitEvent(C.REMOVE_PENDING_ORDER_EVENT, this.getOrderId()); } async getBoxDb(logClass) { const {err, row} = await db.execOneQuery('SELECT * FROM t_box where order_id=?', [ this.getOrderId() ]); if (!row) { log.warning(util.format('%s box not found orderDb:%s', logClass, JSON.stringify(this.orderDb), ) ); } return { 'err': err, 'boxDb': row }; } async setSynced(logClass) { const err = await db.execScript('UPDATE t_box_order SET bc_synced=1 WHERE order_id=?', [ this.getOrderId() ]); if (err) { log.error(util.format('%s setSynced orderDb:%s err:%s', logClass, JSON.stringify(this.orderDb), err ) ); } else { log.info(util.format('%s setSynced orderDb:%s', logClass, JSON.stringify(this.orderDb) ) ); } return err; } async setDone(logClass) { const err = await db.execScript('UPDATE t_box_order SET done=1 WHERE order_id=?', [ this.getOrderId() ]); if (err) { log.error(util.format('%s setDoneErr orderDb:%s err:%s', logClass, JSON.stringify(this.orderDb), err ) ); } else { log.info(util.format('%s setDoneOk orderDb:%s', logClass, JSON.stringify(this.orderDb) ) ); } return err; } async setPaidState(logClass) { const err = await db.execScript('UPDATE t_box_order SET state=? WHERE order_id=?', [ C.ORDER_STATE_PAID, this.getOrderId() ]); if (err) { log.error(util.format('%s setPaidState orderDb:%s err:%s', logClass, JSON.stringify(this.orderDb), err ) ); } else { log.error(util.format('%s setPaidState orderDb:%s', logClass, JSON.stringify(this.orderDb) ) ); } return err; } async setBoxPaidState(logClass, boxDb) { const err = await db.execScript('UPDATE t_box SET state=? WHERE idx=?', [ C.BOX_STATE_PAID, boxDb['idx'] ]); if (err) { log.error(util.format('%s setBoxPaidState orderDb:%s boxDb:%s err:%s', logClass, JSON.stringify(this.orderDb), JSON.stringify(boxDb), err ) ); } else { log.error(util.format('%s setBoxPaidState orderDb:%s boxDb:%s', logClass, JSON.stringify(this.orderDb), JSON.stringify(boxDb), ) ); } return err; } async setBoxOrderInvalid(logClass, boxDb) { const err = await db.execScript('UPDATE t_box SET order_valid=0 WHERE idx=?', [ boxDb['idx'] ]); if (err) { log.error(util.format('%s setBoxOrderInvalid orderDb:%s boxDb:%s err:%s', logClass, JSON.stringify(this.orderDb), JSON.stringify(boxDb), err ) ); } else { log.error(util.format('%s setBoxOrderInvalid orderDb:%s boxDb:%s', logClass, JSON.stringify(this.orderDb), JSON.stringify(boxDb), ) ); } return err; } getOrderDb() { return this.orderDb; } getOrderId() { return this.orderDb['order_id']; } getBlockNumber() { return this.orderDb['bc_block_number']; } isExpired() { return this.orderDb['expired']; } isPaid() { return this.orderDb['state'] == C.ORDER_STATE_PAID; } isSynced() { return this.orderDb['bc_synced'] != 0; } isFail() { return this.isSynced() && this.orderDb['bc_result'] != C.BC_RESULT_OK; } }; exports.BoxOrder = BoxOrder;