redis.lua 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. ------------------------------------------------------------------------------
  2. -- Redis client module
  3. --
  4. -- LICENCE: http://opensource.org/licenses/MIT
  5. -- Vladimir Dronnikov <dronnikov@gmail.com>
  6. --
  7. -- Example:
  8. -- local redis = dofile("redis.lua").connect(host, port)
  9. -- redis:publish("chan1", foo")
  10. -- redis:subscribe("chan1", function(channel, msg) print(channel, msg) end)
  11. ------------------------------------------------------------------------------
  12. local M
  13. do
  14. -- const
  15. local REDIS_PORT = 6379
  16. -- cache
  17. local pairs, tonumber = pairs, tonumber
  18. --
  19. local publish = function(self, chn, s)
  20. self._fd:send(("*3\r\n$7\r\npublish\r\n$%d\r\n%s\r\n$%d\r\n%s\r\n"):format(
  21. #chn, chn, #s, s
  22. ))
  23. -- TODO: confirmation? then queue of answers needed
  24. end
  25. local subscribe = function(self, chn, handler)
  26. -- TODO: subscription to all channels, with single handler
  27. self._fd:send(("*2\r\n$9\r\nsubscribe\r\n$%d\r\n%s\r\n"):format(
  28. #chn, chn
  29. ))
  30. self._handlers[chn] = handler
  31. -- TODO: confirmation? then queue of answers needed
  32. end
  33. local unsubscribe = function(self, chn)
  34. self._handlers[chn] = false
  35. end
  36. -- NB: pity we can not just augment what net.createConnection returns
  37. local close = function(self)
  38. self._fd:close()
  39. end
  40. local connect = function(host, port)
  41. local _fd = net.createConnection(net.TCP, 0)
  42. local self = {
  43. _fd = _fd,
  44. _handlers = { },
  45. -- TODO: consider metatables?
  46. close = close,
  47. publish = publish,
  48. subscribe = subscribe,
  49. unsubscribe = unsubscribe,
  50. }
  51. _fd:on("connection", function()
  52. --print("+FD")
  53. end)
  54. _fd:on("disconnection", function()
  55. -- FIXME: this suddenly occurs. timeout?
  56. --print("-FD")
  57. end)
  58. _fd:on("receive", function(fd, s) --luacheck: no unused
  59. --print("IN", s)
  60. -- TODO: subscription to all channels
  61. -- lookup message pattern to determine channel and payload
  62. -- NB: pairs() iteration gives no fixed order!
  63. for chn, handler in pairs(self._handlers) do
  64. local p = ("*3\r\n$7\r\nmessage\r\n$%d\r\n%s\r\n$"):format(#chn, chn)
  65. if s:find(p, 1, true) then
  66. -- extract and check message length
  67. -- NB: only the first TCP packet considered!
  68. local _, start, len = s:find("(%d-)\r\n", #p)
  69. if start and tonumber(len) == #s - start - 2 and handler then
  70. handler(chn, s:sub(start + 1, -2)) -- ends with \r\n
  71. end
  72. end
  73. end
  74. end)
  75. _fd:connect(port or REDIS_PORT, host)
  76. return self
  77. end
  78. -- expose
  79. M = {
  80. connect = connect,
  81. }
  82. end
  83. return M