QuickSDK 的Think.JS的服务端实现

本文介绍了如何通过Node.js实现接口验证token,查询商品,创建订单以及处理通知。重点展示了`verify_token`、`submit_orderAction`和`notifyAction`方法的工作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不多说,上代码:

const Base = require('./base.js');
const crypto = require('crypto');
const urllib = require('urllib');
const xml2js = require('xml2js');
const { ctx } = require('./base.js');
const ThinkSessionFile = require('think-session-file');
const { Console } = require('console');
const { request } = require('http');


module.exports = class extends Base {



    async verify_token(channel, user_id, token) {

        let url = 
            think.config('quick').check_user        + "?product_code=" +  
            think.config('quick').product_code      + "&channel_code=" +  
            channel + "&uid=" + user_id + "&token=" + token;

        let request_data = {
            method: "GET",
        }
    
        const quest_func = async () => 
        {
            return new Promise((resolve, reject) => {
                try {
                    urllib.request( url, request_data,
                    (err, data, response) => {
                        if( err == null )
                            return resolve(data.toString());
                        else
                            return resolve('0');
                    } )
                } catch (e) {
                    return resolve('0');
                }
            });
        };

        let query_result = await quest_func();
        return query_result;
    }

    decode(str, key) {

        if( str.length <= 0 ) {
            return '';
        }
    
        let list = new Array();
        let result_match = str.match( /\d+/g );
        for( let i = 0; i < result_match.length; i ++ ) {
            list.push( result_match[i] );
        }
    
        if( list.length <= 0 ) {
            return '';
        }
        
        let keys_byte = this.string_to_bytes( key );
        let data_byte = new Array();
        for( let i = 0 ; i < list.length ; i++ ) {
            data_byte[i] = parseInt( list[i]) - ( 0xff & parseInt( keys_byte[i % keys_byte.length] ) );
        }
    
        if( data_byte.length <= 0 ) {
            return '';
        }
    
        let result = this.bytes_to_string( data_byte );
        return result;
    }
    
    
    
    string_to_bytes(str) {

        let ch, st, re = [];
        for( let i = 0; i < str.length; i ++ )
        {
            ch = str.charCodeAt( i );
            st = [];
            do {
                st.push( ch & 0xFF );
                ch = ch >> 8;
            } while( ch );
            re = re.concat( st.reverse() );
        }
        return re;
    } 
    
    
    bytes_to_string(array) {

      return String.fromCharCode.apply( String, array );
    }


    convert_xml(xml) {

        let parser = new xml2js.Parser( {
            explicitArray   : false, 
            ignoreAttrs     : true
        } );

        let result = '';
        parser.parseString( xml, function(err, retval) 
        {
            if( think.isEmpty(retval) == false ) {
                result = retval;
            } else {
                console.log( err );
            }
        } );

        return result;
    }
    
    

    async verifyAction() {

        let channel = this.get('cid');
        let user_id = this.get('uid');
        let token   = this.get('token');
        if( think.isEmpty(channel) ||
            think.isEmpty(user_id) ||
            think.isEmpty(token) )
        {
            return this.fail( 6000, 'invalid arguments' );
        }

        let query_result = await this.verify_token( channel, user_id, token );
        if( query_result != '1' )
        {
            return this.fail( 6007, 'verify token failed: ' + query_result );
        }

        return this.success();
    }
    

    
    async submit_orderAction() {

        let account         = this.get('account');      
        let item_name       = this.get('item_name');    // goods id
        let count           = this.get('count');
        let comment         = this.get('comment');

        if( think.isEmpty(account)   ||
            think.isEmpty(item_name) || 
            think.isEmpty(count)     )
        {
            return this.fail( 6000, "invalid argument" );
        }

        if( think.isEmpty(comment) ) {
            comment = '';
        }

        // 查询得到商品的数据=
        let item = await this.model('commodity', 'mysql_nova').find_item( item_name );

        if( think.isEmpty(item) ) {
            return this.fail( 6001, "invalid item" );
        }        

        // 填充商品数据
        let detail          = item.name + " * " + count;        // 比如xxx * 3
        let sale_off        = item.sale_off;
        let original_price  = item.price * count;
        let actual_price    = original_price * sale_off;

        // 创建订单并插入到数据库中
        let order_id = await this.model('order', 'mysql_nova').save(
            account, item_name, detail, count, original_price, actual_price, sale_off, comment );

        if( think.isEmpty(order_id) ) {
            return this.fail( 6002, "create order failed" );
        }

        return this.success( {
            order_id        : order_id,
            sale_off        : sale_off,
            original_price  : original_price,
            actual_price    : actual_price,
            detail          : detail,
        } );
    }



    async notifyAction() {

        let nt_data    = this.post('nt_data');
        let sign       = this.post('sign');
        let md5Sign    = this.post('md5Sign');

        if( think.isEmpty(nt_data)   ||
            think.isEmpty(sign)      || 
            think.isEmpty(md5Sign)   )
        {
            return this.json( 'FAILED, Invalid arguments' );
        }

        // 校验
        let md5key = think.config('quick').md5_key;
        let verify = crypto.createHash('md5').update(nt_data + sign + md5key).digest("hex");

        if( verify != md5Sign )
        {
            return this.json( 'FAILED, MD5 checksum failed' );
        }

        // 解码xml
        let xml = this.decode( nt_data, think.config('quick').callback_key );
        if( think.isEmpty(xml) )
        {
            return this.json( 'FAILED, decrypto failed' );
        }

        // 分析xml,获取json
        let data = this.convert_xml( xml );
        if( think.isEmpty(data) )
        {
            return this.json( 'FAILED, XML Parser report error');
        }

        // 获取订单信息
        let is_test    = data.quicksdk_message.message.is_test;
        let state      = data.quicksdk_message.message.status;
        let order_id   = data.quicksdk_message.message.game_order;
        let payment_sn = data.quicksdk_message.message.order_no;
        let pay_amount = data.quicksdk_message.message.amount * 100; // convert to cent

        // 如果状态失败,返回failed
        if( state == '1' ) 
        {
            return this.json( 'FAILED, status = 1' );
        }

        // 如果是测试,返回failed
        if( is_test == '1' ) 
        {
            return this.json( 'FAILED, is_test = 1' );
        }

        // 更新订单(仅更新一个标志,反复读写不会有任何障碍)
        let retval = await this.model('order', 'mysql_nova').
            update_payment(order_id, payment_sn, parseInt(pay_amount) );
        console.log( retval );

        if( retval == 1 ) {
            return this.json( 'SUCCESS' );
        }
        
        return this.json( 'FAILED, Invalid order id or pay amount' );
    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值