stipsan / ioredis-mock

Emulates ioredis by performing all operations in-memory.
MIT License
339 stars 123 forks source link

`cmsgpack` global object is missing in lua context #1143

Open felixmosh opened 2 years ago

felixmosh commented 2 years ago

cmsgpack is a global lua object which allows to pack & unpack messagepacks. It is a standard object that redis adds, therefore, in my opinion it is better to add it as this mock adds the redis global object.

A possible js implementation of cmsgpack can be msgpackr

This code should work:

local packed = cmsgpack.pack('{"some": "obj"}');
return cmsgpack.unpack(packed);
stipsan commented 2 years ago

I tried to setup an experiment with it but it's painfully obvious that Lua isn't my forte 😭

felixmosh commented 2 years ago

Hi, there is any progress with this?

umrbrwn commented 8 months ago

@stipsan I got this working by adding this gist directly inside ioredis-mock/lib/index.js bundled file.

defineCmsgpackObject = (vm) => {
  // installed 'msgpackr' separately
  defineGlobalFunction(vm.L)(function() {
    const packer = new msgpackr.Packr({
      useRecords: false,
      encodeUndefinedAsNil: true,
    });
    try {
      // extract function arguments, unpack function takes 1 arg, so we're picking first item of args array
      const [args] = extractArgs(vm.L)();
      const result = packer.unpack(args);
      // push the result back to fengari lua stack
      import_fengari_interop2.default.push(vm.L, result)
      // return number of items we have returned and lua will pick this many items from stack as return values
      return 1;
    } catch (error) {
      console.error('FAILED TO UNPACK USING CUSTOM IMPLEMENTATION', error)
    }
    // failed to unpack anything? return 0 argument, this converts to 'nil' in lua or 'null' in js
    return 0;
  }, 'msgpackr_unpack');
  vm.luaExecString(`
    local cmsgpack = {}
    cmsgpack.unpack = function(data)
      return msgpackr_unpack(data)
    end
    return cmsgpack
  `), lua2.lua_setglobal(vm.L, toLuaString2("cmsgpack"));
}

and then called defineCmsgpackObject inside the customCommand function.

var customCommand = (numberOfKeys, luaCode) => function(...luaScriptArgs) {
  let vm = init();
  defineRedisObject(vm)(callToRedisCommand(vm).bind(this)), defineKeys.bind(this)(vm, numberOfKeys, luaScriptArgs), defineArgv.bind(this)(vm, numberOfKeys, luaScriptArgs);

  defineCmsgpackObject(vm);

  let topBeforeExecute = lua2.lua_gettop(vm.L);
  vm.luaExecString(luaCode);
  let retVal = vm.popReturnValue(topBeforeExecute);
  return dispose(vm), retVal;
};

It's a prototype, same logic can be applied in the source code to support cmsgpack.

felixmosh commented 8 months ago

What is needed for it to be production ready? ;]

vlad-sweetcode commented 5 days ago

Update this version with fix please

felixmosh commented 5 days ago

What version?

vlad-sweetcode commented 5 days ago

Latest version when try to use with bullmq