Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmsgpack global object is missing in lua context #1143

Open
felixmosh opened this issue Jan 31, 2022 · 4 comments
Open

cmsgpack global object is missing in lua context #1143

felixmosh opened this issue Jan 31, 2022 · 4 comments

Comments

@felixmosh
Copy link
Contributor

felixmosh commented Jan 31, 2022

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
Copy link
Owner

stipsan commented Feb 1, 2022

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

@felixmosh
Copy link
Contributor Author

Hi, there is any progress with this?

@umrbrwn
Copy link

umrbrwn commented Feb 20, 2024

@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
Copy link
Contributor Author

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

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

No branches or pull requests

3 participants