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

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

@zhengweikeng

Description

@zhengweikeng

我在authRemote这样写

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

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

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

Activity

fantasyni

fantasyni commented on Jan 20, 2017

@fantasyni
Member

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

39Er

39Er commented on Jul 26, 2017

@39Er

遇到同样的问题,求解

seancheung

seancheung commented on Jul 30, 2017

@seancheung

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

redelva commented on Aug 9, 2017

@redelva
seancheung

seancheung commented on Aug 9, 2017

@seancheung

@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 join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @fantasyni@seancheung@redelva@zhengweikeng@39Er

        Issue actions

          remote的写法支持es6的class么 · Issue #869 · NetEase/pomelo