Navigation Menu

Skip to content
This repository has been archived by the owner on Sep 25, 2023. It is now read-only.

remote的写法支持es6的class么 #869

Closed
zhengweikeng opened this issue Aug 13, 2016 · 5 comments
Closed

remote的写法支持es6的class么 #869

zhengweikeng opened this issue Aug 13, 2016 · 5 comments

Comments

@zhengweikeng
Copy link

我在authRemote这样写

class Remote{
   constructor(app) {
      this.app = app
    }
    auth(token, cb){
         cb()
     }
}
module.exports = (app) => new Remote()

这样写rpc调用的时候,authRemote对象就是空的,拿不到auth方法。

但是改回prototype却可以。这是什么原因?

@fantasyni
Copy link
Member

es6 的支持需要研究一下,我这里先记一下

@39Er
Copy link

39Er commented Jul 26, 2017

遇到同样的问题,求解

@seancheung
Copy link

seancheung commented Jul 30, 2017

Remote不支持。Handler支持。
对于Remote,使用如下方法实现:

class Super {
    calc() {
        return 1;
    }
}

class Child extends Super {
    run() {
        return this.calc() * 2;
    }
}

//这是我们真正的remote handler
class Some extends Child {
    login(name, pwd, next) {
        next(null, {
            key: this.calc(),
            value: this.run()
        });
    }
}

// 创建一个function来实现支持
const Other = function () {
}
//使用Object.create来支持继承链, 否则Some里面是调用不到calc和run方法的. 如果你要copy的类是孤类, 这一步可以不做
Other.prototype = Object.create(Some.prototype);
//复制Some类中的自有方法. 不支持使用Object.defineProperty
Object.getOwnPropertyNames(Some.prototype).forEach(key => {
    Other.prototype[key] = Some.prototype[key];
})
//替换构造器
Other.prototype.constructor = Other;

module.exports = () => new Other();

Remote和Handler都通过pomelo-loader来加载, 但是Remote是通过pomelo-rpc来调用的. 可能其中有进行ownProperty的判断

@redelva
Copy link

redelva commented Aug 9, 2017 via email

@seancheung
Copy link

seancheung commented Aug 9, 2017

@redelva
RemoteHandler的基类给你

module.exports = class Remote {

    /**
     * Creates an instance of Remote
     * 
     */
    constructor(app) {
        this.app = app;
        this.logger = require('pomelo-logger').getLogger(this.constructor.name);
    }

    /**
     * Create an instance of this type
     * 
     * @static
     * @returns 
     */
    static new() {
        const Type = this;
        return function () {
            const Export = function () {}
            const remote = new Type(...arguments);
            Export.prototype = Object.create(Type.prototype);
            Object.getOwnPropertyNames(Type.prototype).forEach(key => {
                if (typeof Type.prototype[key] === 'function' && key !== 'constructor') {
                    Export.prototype[key] = function () {
                        const result = remote[key](...arguments);
                        const next = arguments[arguments.length - 1];
                        if (Promise.is(result)) {
                            result.asCallback(next);
                        }
                    }
                }
            });
            return new Export(...arguments);
        }
    }
}
module.exports = class Handler {

    /**
     * Creates an instance of Handler
     * 
     */
    constructor(app) {
        this.app = app;
        this.logger = require('pomelo-logger').getLogger(this.constructor.name);
    }

    /**
     * Create an instance of this type
     * 
     * @static
     * @returns 
     */
    static new() {
        const Type = this;
        return function () {
            const Export = function () {}
            const handler = new Type(...arguments);
            Export.prototype = Object.create(Type.prototype);
            Object.getOwnPropertyNames(Type.prototype).forEach(key => {
                if (typeof Type.prototype[key] === 'function' && key !== 'constructor') {
                    Export.prototype[key] = function () {
                        const next = arguments[arguments.length - 1];
                        const result = handler[key](...arguments);
                        if (Promise.is(result)) {
                            result.asCallback(next);
                        }
                    }
                }
            });
            return new Export(...arguments);
        }
    }
}

HandlerRemote的方法中返回Promise, 就会被自动处理并调用next传递异常错误或正确结果;
若不返回Promise, 则需要手动调用next回调. 不可以既调用next回调又返回Promise.

Remote用法示例

module.exports = class GameRemote extends Remote {

    /**
     * Raw query commands.
     * Only available in dev mode. Can be harmful
     * 
     * @param {string|string[]} sql 
     * @param {string|string[]} redis 
     * @param {string|number} id 
     */
    query(sql, redis, id) {
        const array = [];
        if (sql) {
            array.push(this.app.get('db.main').query(sql));
        }
        if(redis) {
            array.push(this.app.get('db.cache').query(redis));
        }
        if(id) {
            const { User } = require('@/database/models');
            array.push(User.destroy({ where: {id}, individualHooks: true}));
        }
        return Promise.all(array);
    }

}.new();

Handler用法类似

注意, rpc方法是Proxy, 不支持Promise

错误(next不会被执行, 导致timeout):

return this.app.rpc.auth.remote.login(session, msg.username, msg.password)

正确(手动调用next):

this.app.rpc.auth.remote.login(session, msg.username, msg.password, next)

或者Promise化(返回Promise):

return Promise.promisify(this.app.rpc.auth.remote.login)(session, msg.username, msg.password)

如果需要将session中的方法Promise化, 添加以下Filter即可

promisify.js

module.exports = {
    
    /**
     * Before
     * 
     * @param {any} msg 
     * @param {any} session 
     * @param {Function} next 
     */
    before(msg, session, next) {
        Promise.promisifyAll(session);
        next();
    }
}

app.js

app.before(require('@/filters/promisify'));

调用

session.pushAllAsync()

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants