【问题标题】:Unable to read data from Redis using NodeJS TypeScript code无法使用 NodeJS TypeScript 代码从 Redis 读取数据
【发布时间】:2020-10-01 02:23:41
【问题描述】:

我正在调用 loadFilteredPolicy() 方法,方法是从客户端传递作为我的 hashkey 的过滤器对象,但它的方法 get() 或 hgetall() 永远不会被执行,并且控制在没有从中获取数据的情况下退出Redis 服务器没有抛出任何错误。让我确认一下,我可以调试并且可以确保 this.redisInstance 上有一个 redis 对象,但不确定为什么 then 方法不执行。我可以通过命令 hgetall 直接使用 redis-cli 获取相同的数据。

我想告诉你的另一件事是,当我取消注释上面的 Promise 行(等待 this.redisInstance.hgetall)并再次调试时,this.redisInstance 返回未定义。我不确定发生了什么。我以前使用过 JS,但没有太多 TypeScript,我从早上开始就陷入了这个错误,现在是晚上了。

这是我的 TypeScript 代码 (adapter.ts),它被编译为 JS 文件:-

import { Helper, Model, FilteredAdapter } from 'casbin';
import * as redis from 'redis';

interface IConnectionOptions {
    host: string;
    port: number;
}
class Line {
    ptype: string;
    v0: string;
    v1: string;
    v2: string;
    v3: string;
    v4: string;
    v5: string;
}
export class RedisAdapter implements FilteredAdapter {

    private redisInstance = null;
    private policies = null;
    private filtered = false;

    public isFiltered(): boolean {
        return this.filtered;
    }

    private deliveredOptions = {
        retry_strategy(options) {
            if (options.error && options.error.code === 'ECONNREFUSED') {
                return new Error('The server refused the connection');
            }
            if (options.total_retry_time > 1000 * 60 * 60) {
                return new Error('Retry time exhausted');
            }
            if (options.attempt > 10) {
                return undefined;
            }
            // reconnect after
            return Math.min(options.attempt * 100, 300);
        },
    };

    /**
     * Helper Methods
     */

    savePolicyLine(ptype, rule) {
        const line = new Line();
        line.ptype = ptype;
        if (rule.length > 0) {
            line.v0 = rule[0];
        }

        if (rule.length > 1) {
            line.v1 = rule[1];
        }

        if (rule.length > 2) {
            line.v2 = rule[2];
        }

        if (rule.length > 3) {
            line.v3 = rule[3];
        }

        if (rule.length > 4) {
            line.v4 = rule[4];
        }

        if (rule.length > 5) {
            line.v5 = rule[5];
        }
        return line;
    }
    loadPolicyLine(line, model) {
        console.log("load Policies line called");
        let lineText = line.ptype;
        if (line.v0) {
            lineText += ", " + line.v0;
        }
        if (line.v1) {
            lineText += ", " + line.v1;
        }
        if (line.v2) {
            lineText += ", " + line.v2;
        }
        if (line.v3) {
            lineText += ", " + line.v3;
        }
        if (line.v4) {
            lineText += ", " + line.v4;
        }
        if (line.v5) {
            lineText += ", " + line.v5;
        }
        Helper.loadPolicyLine(lineText, model);
    }

    storePolicies(policies) {
        return new Promise((resolve, reject) => {
            console.log({ r: this.redisInstance });
            this.redisInstance.del('policies');
            this.redisInstance.set('policies', JSON.stringify(policies), (err, reply) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(reply);
                }
            });
        });
    }

    reducePolicies(policies, ptype, rule) {
        let i = rule.length;
        let policyIndex = policies.fieldIndex((policy) => {
            let flag = false;
            flag = policy.ptype === ptype ? true : false;
            flag = i > 5 && policy.v5 === rule[5] ? true : false;
            flag = i > 4 && policy.v4 === rule[4] ? true : false;
            flag = i > 3 && policy.v3 === rule[3] ? true : false;
            flag = i > 2 && policy.v2 === rule[2] ? true : false;
            flag = i > 1 && policy.v0 === rule[1] ? true : false;
            return flag;
        });
        if (policyIndex !== -1) {
            return policies.splice(policyIndex, 1);
        }
        return [];
    }

    constructor(options: IConnectionOptions) {
        this.redisInstance = redis.createClient(
            {
                ...options,
                ...this.deliveredOptions,
            },
        );
    }

    static async newAdapter(options: IConnectionOptions) {
        const adapter = new RedisAdapter(options);
        await new Promise(resolve => adapter.redisInstance.on('connect', resolve));
        return adapter;
    }

    /**
     * Adapter Methods
     */
    public async loadPolicy(model) {
        this.redisInstance.get("policies", (err, policies) => {
            var AdapterRef = this;
            console.log("Loading Policies...\n", policies);
            if (!err) {
                policies = JSON.parse(policies);
                this.policies = policies;//For add and remove policies methods
                console.log(policies);
                policies.forEach(function (policy, index) {
                    AdapterRef.loadPolicyLine(policy, model);
                });
                console.log("Policies are loaded");
            } else {
                return err;
            }
        });
    }

    public async loadFilteredPolicy(model: Model, filter: object): Promise<void> {
        let key = filter['hashKey'];
        //return await new Promise(function (resolve, reject) {
            this.redisInstance.hgetall(key, (err, policies) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(err);
                    var AdapterRef = this;
                    console.log("Loading filtered Policies...\n", policies);
                    policies = JSON.parse(policies);
                    this.policies = policies;//For add and remove policies methods
                    console.log(policies);
                    policies.forEach(function (policy, index) {
                        AdapterRef.loadPolicyLine(policy, model);
                    });
                    console.log("Filtered Policies are loaded...");
                    this.filtered = true;
                }
            });
        //})
    }

    public async savePolicy(model: Model): Promise<boolean> {
        const policyRuleAST = model.model.get("p");
        const groupingPolicyAST = model.model.get("g");
        let policies = [];

        //var rows2 = <Array<any>>policyRuleAST;
        //var rows2 = <Array<any>>groupingPolicyAST;

        for (const [ptype, ast] of Object.entries(policyRuleAST)) {
            for (const rule of ast.policy) {
                const line = this.savePolicyLine(ptype, rule);
                policies.push(line);
            }
        }

        for (const [ptype, ast] of Object.entries(groupingPolicyAST)) {
            for (const rule of ast.policy) {
                const line = this.savePolicyLine(ptype, rule);
                policies.push(line);
            }
        }
        //this.storePolicies(policies);

        return new Promise((resolve, reject) => {
            console.log({ r: this.redisInstance });
            this.redisInstance.del('policies');
            this.redisInstance.set('policies', JSON.stringify(policies), (err, reply) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(true);
                }
            });
        });
    }

    async addPolicy(sec, ptype, rule) {
        const line = this.savePolicyLine(ptype, rule);
        this.policies.push(line);
        this.storePolicies(this.policies);
        //reSave the policies
    }

    async removePolicy(sec, ptype, rule) {
        let result = this.reducePolicies(this.policies, ptype, rule);
        //the modified policies
        if (result.length) { //if length>0
            this.policies = result;
            //Store in Redis
            this.storePolicies(this.policies);
        } else {
            // console.IN("No Policy found");
            throw new Error("No Policy Found");
        }
    }

    public async removeFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string[]) {
        throw new Error("Method not implemented");
    }
}

对应的adapter.js:-

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RedisAdapter = void 0;
const casbin_1 = require("casbin");
const redis = require("redis");
class Line {
}
class RedisAdapter {
    constructor(options) {
        this.redisInstance = null;
        this.policies = null;
        this.filtered = false;
        this.deliveredOptions = {
            retry_strategy(options) {
                if (options.error && options.error.code === 'ECONNREFUSED') {
                    return new Error('The server refused the connection');
                }
                if (options.total_retry_time > 1000 * 60 * 60) {
                    return new Error('Retry time exhausted');
                }
                if (options.attempt > 10) {
                    return undefined;
                }
                return Math.min(options.attempt * 100, 300);
            },
        };
        this.redisInstance = redis.createClient(Object.assign(Object.assign({}, options), this.deliveredOptions));
    }
    isFiltered() {
        return this.filtered;
    }
    savePolicyLine(ptype, rule) {
        const line = new Line();
        line.ptype = ptype;
        if (rule.length > 0) {
            line.v0 = rule[0];
        }
        if (rule.length > 1) {
            line.v1 = rule[1];
        }
        if (rule.length > 2) {
            line.v2 = rule[2];
        }
        if (rule.length > 3) {
            line.v3 = rule[3];
        }
        if (rule.length > 4) {
            line.v4 = rule[4];
        }
        if (rule.length > 5) {
            line.v5 = rule[5];
        }
        return line;
    }
    loadPolicyLine(line, model) {
        console.log("load Policies line called");
        let lineText = line.ptype;
        if (line.v0) {
            lineText += ", " + line.v0;
        }
        if (line.v1) {
            lineText += ", " + line.v1;
        }
        if (line.v2) {
            lineText += ", " + line.v2;
        }
        if (line.v3) {
            lineText += ", " + line.v3;
        }
        if (line.v4) {
            lineText += ", " + line.v4;
        }
        if (line.v5) {
            lineText += ", " + line.v5;
        }
        casbin_1.Helper.loadPolicyLine(lineText, model);
    }
    storePolicies(policies) {
        return new Promise((resolve, reject) => {
            console.log({ r: this.redisInstance });
            this.redisInstance.del('policies');
            this.redisInstance.set('policies', JSON.stringify(policies), (err, reply) => {
                if (err) {
                    reject(err);
                }
                else {
                    resolve(reply);
                }
            });
        });
    }
    reducePolicies(policies, ptype, rule) {
        let i = rule.length;
        let policyIndex = policies.fieldIndex((policy) => {
            let flag = false;
            flag = policy.ptype === ptype ? true : false;
            flag = i > 5 && policy.v5 === rule[5] ? true : false;
            flag = i > 4 && policy.v4 === rule[4] ? true : false;
            flag = i > 3 && policy.v3 === rule[3] ? true : false;
            flag = i > 2 && policy.v2 === rule[2] ? true : false;
            flag = i > 1 && policy.v0 === rule[1] ? true : false;
            return flag;
        });
        if (policyIndex !== -1) {
            return policies.splice(policyIndex, 1);
        }
        return [];
    }
    static async newAdapter(options) {
        const adapter = new RedisAdapter(options);
        await new Promise(resolve => adapter.redisInstance.on('connect', resolve));
        return adapter;
    }
    async loadPolicy(model) {
        this.redisInstance.get("policies", (err, policies) => {
            var AdapterRef = this;
            console.log("Loading Policies...\n", policies);
            if (!err) {
                policies = JSON.parse(policies);
                this.policies = policies;
                console.log(policies);
                policies.forEach(function (policy, index) {
                    AdapterRef.loadPolicyLine(policy, model);
                });
                console.log("Policies are loaded");
            }
            else {
                return err;
            }
        });
    }
    async loadFilteredPolicy(model, filter) {
        let key = filter['hashKey'];
        //await new Promise(function (resolve, reject) {

            await this.redisInstance.hgetall(key, (err, policies) => {
                if (err) {
                    return err;
                }
                else {
                    var AdapterRef = this;
                    console.log("Loading filtered Policies...\n", policies);
                    policies = JSON.parse(policies);
                    this.policies = policies;
                    console.log(policies);
                    policies.forEach(function (policy, index) {
                        AdapterRef.loadPolicyLine(policy, model);
                    });
                    console.log("Filtered Policies are loaded...");
                    this.filtered = true;
                }
            });
       // });
    }
    async savePolicy(model) {
        const policyRuleAST = model.model.get("p");
        const groupingPolicyAST = model.model.get("g");
        let policies = [];
        for (const [ptype, ast] of Object.entries(policyRuleAST)) {
            for (const rule of ast.policy) {
                const line = this.savePolicyLine(ptype, rule);
                policies.push(line);
            }
        }
        for (const [ptype, ast] of Object.entries(groupingPolicyAST)) {
            for (const rule of ast.policy) {
                const line = this.savePolicyLine(ptype, rule);
                policies.push(line);
            }
        }
        return new Promise((resolve, reject) => {
            console.log({ r: this.redisInstance });
            this.redisInstance.del('policies');
            this.redisInstance.set('policies', JSON.stringify(policies), (err, reply) => {
                if (err) {
                    reject(err);
                }
                else {
                    resolve(true);
                }
            });
        });
    }
    async addPolicy(sec, ptype, rule) {
        const line = this.savePolicyLine(ptype, rule);
        this.policies.push(line);
        this.storePolicies(this.policies);
    }
    async removePolicy(sec, ptype, rule) {
        let result = this.reducePolicies(this.policies, ptype, rule);
        if (result.length) {
            this.policies = result;
            this.storePolicies(this.policies);
        }
        else {
            throw new Error("No Policy Found");
        }
    }
    async removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues) {
        throw new Error("Method not implemented");
    }
}
exports.RedisAdapter = RedisAdapter;

如果您能建议我使此代码正常工作,我将不胜感激。此适配器源代码的我的 GitHub 链接可在此处获得 https://github.com/vinod827/node-casbin-redis-adapter.git

谢谢,

[已更新代码,仍无法正常工作]

async loadFilteredPolicy(model, filter) {
    let key = filter['hashKey'];
    let filteredPolicies = await this.getFilteredPolicies(key).then(data => { return data });
    console.log(filteredPolicies);
}
getFilteredPolicies = async (hashKey) => {
    return await new Promise(function (resolve, reject) {
        this.redisInstance.hgetall((hashKey), function (err, data) {
            if (err) {
                reject(err);
            } else {
                resolve(data);
            }
        })
    })
};

【问题讨论】:

    标签: javascript node.js typescript ecmascript-6 casbin


    【解决方案1】:

    我觉得你需要重新学习Promise的使用,至少你需要知道什么时候使用resolve()

    见:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

    顺便说一句,不要以typescript为借口,这里只有javascript

    我在这里为您提供一个可行的最小实现:

    import * as redis from "redis";
    
    const client = redis.createClient(6379, "127.0.0.1");
    
    function func() {
      return new Promise((resolve, reject) => {
        client.hgetall("myhash", (err, data) => {
          if (err) {
            reject(err);
          }
          resolve(data);
        });
      });
    }
    
    async function main() {
      const data = await func();
      console.log(data);
    }
    
    main();
    

    【讨论】:

    • 感谢您对此进行调查。我已经写了承诺,但仍然没有工作。将 Promise 用于 redis 实例对象时获取未定义。如果您能帮助我,我将不胜感激。
    【解决方案2】:

    您可以在https://github.com/vinod827/node-casbin-redis-adapter/blob/master/src/adapter.ts#L150 上尝试以下代码吗? ?

    public async loadPolicy(model) {
        return new Promise((resolve, reason)=> {
            this.redisInstance.get("policies", (err, policies) => {
                console.log("Loading Policies...\n", policies);
                if (!err) {
                    policies = JSON.parse(policies);
                    console.log(policies);
                    policies.forEach((policy, index)=> {
                        this.loadPolicyLine(policy, model);
                    });
                    console.log("Policies are loaded");
                    resolve()
                } else {
                    reason(err)
                }
            });
        })
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-31
      • 2017-05-06
      • 2019-03-07
      • 1970-01-01
      相关资源
      最近更新 更多