Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local socket = require'socket'
- local concat = table.concat
- local floor = math.floor
- -- // Core
- local connection = {}
- connection.__index = connection
- connection.default = {
- timeout = 5,
- ip = '127.0.0.1',
- port = 6379
- }
- function connection:getIPSockType(ip)
- if type(ip) ~= "string" then return false, 'ip is not string' end
- local ip, err = socket.dns.toip(ip)
- if not ip then return ip, err end
- -- check for format X.XX.XXX.XXX for ipv4
- if ip:match'^%d+%.%d+%.%d+%.%d+$' then
- return (socket.tcp4 or socket.tcp)()
- end
- if not socket.tcp4 then return false, 'ipv6 not alowed, update luasocket library up to v3.x' end
- return socket.tcp()
- end
- function connection:new(ip, port, pass, timeout)
- self = setmetatable({}, self)
- self.ip = ip or self.default.ip
- self.port = port or self.default.port
- self.timeout = timeout or self.default.timeout
- self.pass = pass
- return self
- end
- -- settimeout(0) --> settimeout() = set to zero and restore back
- function connection:settimeout(t)
- if not self.tcp then return end
- if not t then self.tcp:settimeout(self.timeout) end
- if t ~= 0 then
- self.timeout = t
- end
- self.tcp:settimeout(t)
- end
- setmetatable(connection, {__call = connection.new})
- -- connect and auth (if needed)
- function connection:connect(ip, port, pass)
- if self.tcp then return true end
- self.ip = ip or self.ip
- self.port = port or self.port
- self.pass = pass or self.pass
- local sock, err = self:getIPSockType(self.ip)
- if not sock then return false, err end
- self.tcp = sock
- self.tcp:connect(self.ip, self.port)
- self.tcp:settimeout(self.timeout)
- if self.pass then
- if self:auth(self.pass) then return true end
- else
- if self:ping() then return true end
- end
- self:close()
- return false, 'redis not responded'
- end
- -- destroy connection
- function connection:close()
- if not self.tcp then return end
- self.tcp:close()
- self.tcp = nil
- end
- -- set of functions for receiving any data
- local receiver = {}
- connection.receiver = receiver
- -- simple strings
- receiver['+'] = function(self, data) return data end
- -- errors
- receiver['-'] = function(self, data) return false, data end
- -- bulk strings
- receiver['$'] = function(self, data)
- local bytes = tonumber(data)
- if not bytes or bytes < 1 then return bytes end
- local res, err = self.tcp:receive(bytes + 2) -- data + '\r\n'
- return err and false or res:sub(1, -3), err -- cut '\r\n'
- end
- -- integers
- receiver[':'] = function(self, data)
- return tonumber(data)
- end
- -- arrays
- receiver['*'] = function(self, data)
- local count = tonumber(data)
- if not count then return false, 'unknown redis response' end
- local list = {}
- for i = 1, count do
- list[i] = self:receive()
- end
- return list
- end
- -- recursive auto-reconnect receiver
- function connection:receive(async)
- local res, err = self.tcp:receive'*l'
- if not res then
- if async then return end
- return self:close(), err
- end
- local head, tail = res:sub(1, 1), res:sub(2)
- if not self.receiver[head] then
- return false, 'unknown type: ['..head..']', res
- end
- return self.receiver[head](self, tail)
- end
- -- base string request
- function connection:request(command, close)
- if not self:connect() then return end
- self.tcp:send(command..'\r\n')
- return self:receive()
- end
- -- base table request
- function connection:trequest(request_table)
- if not self:connect() then return end
- self.tcp:send(concat(request_table, ' ')..'\r\n')
- return self:receive()
- end
- -- // Utility
- -- Utily
- function connection:concat(...)
- return concat({...}, ' ')
- end
- -- Get string-serialized object and object
- function connection:inspect(key, fmt)
- fmt = fmt or 0
- local template = '%'..fmt..'s (%s)'
- if not key then
- local res = {}
- local keys = self:keys('*')
- for i, key in ipairs(keys) do
- res[#res + 1] = template:format(key, self:type(key))
- end
- return table.concat(res, '\r\n')
- end
- local type = self:type(key)
- local text = "%s (%s): "
- text = text:format(type, key)
- if type == 'string' then
- return text:format(key, t, self:get(key))
- end
- if self[type] then
- local obj = self[type](self, key)
- return obj and obj:Inspect() or 'No object ['..tostring(key)..']', obj
- end
- return 'nil'
- end
- function connection:format(v)
- local type = type(v)
- if type == 'number' then
- return v
- elseif type == 'string' then
- return ('"%s"'):format(v:gsub('"', '\\"'))
- elseif type == 'table' then
- for i = 1, #v do
- v[i] = ('"%s"'):format(tostring(v[i]):gsub('"', '\\"'))
- end
- return concat(v, ' ')
- end
- end
- -- Delete a keys by mask
- function connection:pdel(mask)
- assert(mask, 'Name or delete mask required')
- local keys = self:request('keys '..mask)
- if #keys == 0 then return true end
- return self:trequest{'DEL ', unpack(keys)}
- end
- -- // Set of classic command-methods
- -- APPEND key value
- -- Append a value to a key
- function connection:append(key, value)
- return self:trequest{'APPEND', key, self:format(value)}
- end
- -- AUTH password
- -- Authenticate to the server
- function connection:auth(password)
- self.pass = assert(password or self.pass, 'Password required')
- return self:request('AUTH '..self.pass)
- end
- -- BGREWRITEAOF
- -- Asynchronously rewrite the append-only file
- function connection:bgrewriteaof()
- return self:request('BGREWRITEAOF')
- end
- -- BGSAVE
- -- Asynchronously save the dataset to disk
- function connection:bgsave()
- return self:request('BGSAVE')
- end
- -- BITCOUNT key [start end]
- -- Count set bits in a string
- function connection:bitcount(key, s, e)
- return self:trequest{'BITCOUNT', key, s, e}
- end
- -- BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
- -- Perform arbitrary bitfield integer operations on strings
- function connection:bitfield(key, ...)
- return self:trequest{'BITFIELD', key, ...}
- end
- -- BITOP operation destkey key [key ...]
- -- Perform bitwise operations between strings
- function connection:bitop(key, destkey, key, ...)
- return self:trequest{'BITOP', destkey, key, ...}
- end
- -- BITPOS key bit [start] [end]
- -- Find first bit set or clear in a string
- function connection:bitpos(key, bit, s, e)
- return self:trequest{'BITPOS', bit, s, e}
- end
- -- BLPOP key [key ...] timeout
- -- Remove and get the first element in a list, or block until one is available
- function connection:blpop(key, ...)
- return self:trequest{'BLPOP', key, ...}
- end
- -- BRPOP key [key ...] timeout
- -- Remove and get the last element in a list, or block until one is available
- function connection:brpop(key, ...)
- return self:trequest{'BRPOP', key, ...}
- end
- -- BRPOPLPUSH source destination timeout
- -- Pop a value from a list, push it to another list and return it; or block until one is available
- function connection:brpoplpush(source, destination, timeout)
- return self:trequest{'BRPOPLPUSH', source, destination, timeout}
- end
- -- CLIENT KILL [ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [ADDR ip:port] [SKIPME yes/no]
- -- Kill the connection of a client
- function connection:clientKill(...)
- return self:trequest{'CLIENT KILL', ...}
- end
- -- CLIENT LIST
- -- Get the list of client connections
- function connection:clientList()
- return self:request('CLIENT LIST')
- end
- -- CLIENT GETNAME
- -- Get the current connection name
- function connection:clientGetName()
- return self:request('CLIENT GETNAME')
- end
- -- CLIENT PAUSE timeout
- -- Stop processing commands from clients for some time
- function connection:clientPause(timeout)
- return self:request('CLIENT PAUSE '..(timeout or 0))
- end
- -- CLIENT REPLY ON|OFF|SKIP
- -- Instruct the server whether to reply to commands
- function connection:clientReply(mode)
- return self:request('CLIENT REPLY '..(mode or 'ON'))
- end
- -- CLIENT SETNAME connection-name
- -- Set the current connection name
- function connection:clientSetName(name)
- return self:request('CLIENT SETNAME '..name)
- end
- -- CLUSTER ADDSLOTS slot [slot ...]
- -- Assign new hash slots to receiving node
- function connection:clusterAddSlots(slot, ...)
- return self:trequest{'CLUSTER ADDSLOTS', slot, ...}
- end
- -- CLUSTER COUNT-FAILURE-REPORTS node-id
- -- Return the number of failure reports active for a given node
- function connection:clusterCountFailureReports(node)
- return self:request('CLUSTER COUNT-FAILURE-REPORTS '..node)
- end
- -- CLUSTER COUNTKEYSINSLOT slot
- -- Return the number of local keys in the specified hash slot
- function connection:clusterCountKeysInSlot(slot)
- return self:request('CLUSTER COUNTKEYSINSLOT '..slot)
- end
- -- CLUSTER DELSLOTS slot [slot ...]
- -- Set hash slots as unbound in receiving node
- function connection:clusterDelSlots(slot, ...)
- return self:trequest{'CLUSTER DELSLOTS', slot, ...}
- end
- -- CLUSTER FAILOVER [FORCE|TAKEOVER]
- -- Forces a slave to perform a manual failover of its master.
- function connection:clusterFailover(mode)
- return self:request('CLUSTER FAILOVER '..(mode or 'FORCE'))
- end
- -- CLUSTER FORGET node-id
- -- Remove a node from the nodes table
- function connection:clusterForget(node)
- return self:request('CLUSTER FORGET '..node)
- end
- -- CLUSTER GETKEYSINSLOT slot count
- -- Return local key names in the specified hash slot
- function connection:clusterGetKeysInSlot(slot, count)
- return self:trequest{'CLUSTER GETKEYSINSLOT', slot, count}
- end
- -- CLUSTER INFO
- -- Provides info about Redis Cluster node state
- function connection:clusterInfo()
- return self:request('CLUSTER INFO')
- end
- -- CLUSTER KEYSLOT key
- -- Returns the hash slot of the specified key
- function connection:clusterKeyslot(key)
- return self:request('CLUSTER KEYSLOT '..key)
- end
- -- CLUSTER MEET ip port
- -- Force a node cluster to handshake with another node
- function connection:clusterMeet(ip, port)
- return self:trequest{'CLUSTER MEET', ip, port}
- end
- -- CLUSTER NODES
- -- Get Cluster config for the node
- function connection:clusterNodes()
- return self:request('CLUSTER NODES')
- end
- -- CLUSTER REPLICATE node-id
- -- Reconfigure a node as a slave of the specified master node
- function connection:clusterReplicate(node)
- return self:request('CLUSTER REPLICATE '..node)
- end
- -- CLUSTER RESET [HARD|SOFT]
- -- Reset a Redis Cluster node
- function connection:clusterReset(mode)
- return self:request('CLUSTER RESET '..(mode or 'HARD'))
- end
- -- CLUSTER SAVECONFIG
- -- Forces the node to save cluster state on disk
- function connection:clusterSaveConfig()
- return self:request('CLUSTER SAVECONFIG')
- end
- -- CLUSTER SET-CONFIG-EPOCH config-epoch
- -- Set the configuration epoch in a new node
- function connection:clusterSetConfigEpoch(config_epoch)
- return self:request('CLUSTER SET-CONFIG-EPOCH '..config_epoch)
- end
- -- CLUSTER SETSLOT slot IMPORTING|MIGRATING|STABLE|NODE [node-id]
- -- Bind a hash slot to a specific node
- function connection:clusterSetSlot(slot, mode, node)
- return self:trequest{'CLUSTER SETSLOT', slot, mode, node}
- end
- -- CLUSTER SLAVES node-id
- -- List slave nodes of the specified master node
- function connection:clusterSlaves(node)
- return self:request('CLUSTER SLAVES '..node)
- end
- -- CLUSTER SLOTS
- -- Get array of Cluster slot to node mappings
- function connection:clusterSlots()
- return self:request('CLUSTER SLOTS')
- end
- -- COMMAND
- -- Get array of Redis command details
- function connection:command()
- return self:request('COMMAND')
- end
- -- COMMAND COUNT
- -- Get total number of Redis commands
- function connection:commandCount()
- return self:request('COMMAND COUNT')
- end
- -- COMMAND GETKEYS
- -- Extract keys given a full Redis command
- function connection:commandGetKeys()
- return self:request('COMMAND GETKEYS')
- end
- -- COMMAND INFO command-name [command-name ...]
- -- Get array of specific Redis command details
- function connection:commandInfo(command, ...)
- return self:trequest{'COMMAND INFO', command, ...}
- end
- -- CONFIG GET parameter
- -- Get the value of a configuration parameter
- function connection:configGet(param)
- return self:request('CONFIG GET '..param)
- end
- -- CONFIG REWRITE
- -- Rewrite the configuration file with the in memory configuration
- function connection:configRewrite()
- return self:request('CONFIG REWRITE')
- end
- -- CONFIG SET parameter value
- -- Set a configuration parameter to the given value
- function connection:configSet(...)
- return self:trequest{'CONFIG SET ', ...}
- end
- -- CONFIG RESETSTAT
- -- Reset the stats returned by INFO
- function connection:configResetStat()
- return self:request('CONFIG RESETSTAT')
- end
- -- DBSIZE
- -- Return the number of keys in the selected database
- function connection:dbsize()
- return self:request('DBSIZE')
- end
- -- DEBUG OBJECT key
- -- Get debugging information about a key
- function connection:debugObject(key)
- return self:request('DEBUG OBJECT '..key)
- end
- -- DEBUG SEGFAULT
- -- Make the server crash
- function connection:debugSegfault()
- return self:request('DEBUG SEGFAULT')
- end
- -- DECR key
- -- Decrement the integer value of a key by one
- function connection:decr(key)
- return self:request('DECR '..key)
- end
- -- DECRBY key decrement
- -- Decrement the integer value of a key by the given number
- function connection:decrby(key, inc)
- return self:trequest{'DECRBY', key, inc}
- end
- -- DEL key [key ...]
- -- Delete a key
- function connection:del(...)
- self:trequest{'DEL', ...}
- end
- -- DISCARD
- -- Discard all commands issued after MULTI
- function connection:discard()
- return self:request('DISCARD')
- end
- -- DUMP key
- -- Return a serialized version of the value stored at the specified key.
- function connection:dump(key)
- return self:request('DUMP '..key)
- end
- -- ECHO message
- -- Echo the given string
- function connection:echo(msg)
- return self:request('ECHO '..self:format(msg))
- end
- -- EVAL script numkeys key [key ...] arg [arg ...]
- -- Execute a Lua script server side
- function connection:eval(script, nargs, ...)
- local args = self:format{...}
- return self:trequest{'EVAL', self:format(script), nargs or 0, unpack(args)}
- end
- -- EVALSHA sha1 numkeys key [key ...] arg [arg ...]
- -- Execute a Lua script server side
- function connection:evalsha(script, nargs, ...)
- local args = self:format{...}
- return self:trequest{'EVALSHA', script, nargs or 0, unpack(args)}
- end
- -- EXEC
- -- Execute all commands issued after MULTI
- function connection:exec()
- return self:request('EXEC')
- end
- -- EXISTS key [key ...]
- -- Determine if a key exists
- function connection:exists(...)
- return self:trequest{'EXISTS', ...}
- end
- -- EXPIRE key seconds
- -- Set a key's time to live in seconds
- function connection:expire(key, seconds)
- return self:trequest{'EXPIRE', key, seconds}
- end
- -- EXPIREAT key timestamp
- -- Set the expiration for a key as a UNIX timestamp
- function connection:expireAt(key, timestamp)
- return self:trequest{'EXPIREAT', key, timestamp}
- end
- -- FLUSHALL [ASYNC]
- -- Remove all keys from all databases
- function connection:flushAll(async)
- return self:trequest{'FLUSHALL', async and 'ASYNC' or nil}
- end
- -- FLUSHDB [ASYNC]
- -- Remove all keys from the current database
- function connection:flushDB(async)
- return self:trequest{'FLUSHDB', async and 'ASYNC' or nil}
- end
- -- GEOADD key longitude latitude member [longitude latitude member ...]
- -- Add one or more geospatial items in the geospatial index represented using a sorted set
- function connection:geoAdd(key, ...)
- return self:trequest{'GEOADD', key, ...}
- end
- -- GEOHASH key member [member ...]
- -- Returns members of a geospatial index as standard geohash strings
- function connection:geoHash(key, ...)
- return self:trequest{'GEOHASH', key, ...}
- end
- -- GEOPOS key member [member ...]
- -- Returns longitude and latitude of members of a geospatial index
- function connection:geoPos(key, ...)
- return self:trequest{'GEOPOS', key, ...}
- end
- -- GEODIST key member1 member2 [unit]
- -- Returns the distance between two members of a geospatial index
- function connection:geoDist(key, ...)
- return self:trequest{'GEODIST', key, ...}
- end
- -- GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
- -- Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point
- function connection:geoRadius(key, long, lat, rad, ...)
- return self:trequest{'GEORADIUS', key, long, lat, rad, ...}
- end
- -- GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
- -- Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member
- function connection:geoRadiusByMember(key, member, rad, ...)
- return self:trequest{'GEORADIUSBYMEMBER', key, member, rad, ...}
- end
- -- GET key
- -- Get the value of a key
- function connection:get(key)
- return self:request('GET '..key)
- end
- -- GETBIT key offset
- -- Returns the bit value at offset in the string value stored at key
- function connection:getBit(key, offset)
- return self:trequest{'GETBIT', key, offset}
- end
- -- GETRANGE key start end
- -- Get a substring of the string stored at a key
- function connection:getRange(key, s, e)
- return self:trequest{'GETRANGE', s, e}
- end
- -- GETSET key value
- -- Set the string value of a key and return its old value
- function connection:getSet(key, value)
- return self:trequest{'GETSET', key, self:format(value)}
- end
- -- HDEL key field [field ...]
- -- Delete one or more hash fields
- function connection:hdel(key, ...)
- return self:trequest{'HDEL', ...}
- end
- -- HEXISTS key field
- -- Determine if a hash field exists
- function connection:hexists(key, field)
- return self:trequest{'HEXISTS', key, field}
- end
- -- HGET key field
- -- Get the value of a hash field
- function connection:hget(key, field)
- return self:trequest{'HGET', key, field}
- end
- -- HGETALL key
- -- Get all the fields and values in a hash
- function connection:hgetall(key)
- return self:request('HGETALL '..key)
- end
- -- HINCRBY key field increment
- -- Increment the integer value of a hash field by the given number
- function connection:hincrby(key, field, increment)
- return self:trequest{'HINCRBY', key, field, increment}
- end
- -- HINCRBYFLOAT key field increment
- -- Increment the float value of a hash field by the given amount
- function connection:hincrbyfloat(key, field, increment)
- return self:trequest{'HINCRBYFLOAT', key, field, increment}
- end
- -- HKEYS key
- -- Get all the fields in a hash
- function connection:hkeys(key)
- return self:request('HKEYS '..key)
- end
- -- HLEN key
- -- Get the number of fields in a hash
- function connection:hlen(key)
- return self:request('HLEN '..key)
- end
- -- HMGET key field [field ...]
- -- Get the values of all the given hash fields
- function connection:hmget(key, ...)
- return self:trequest{'HMGET', key, ...}
- end
- -- HMSET key field value [field value ...]
- -- Set multiple hash fields to multiple values
- function connection:hmset(key, ...)
- local args = {...}
- for i = 2, #args, 2 do args[i] = self:format(args[i]) end
- return self:trequest{'HMSET', key, unpack(args)}
- end
- -- HSET key field value
- -- Set the string value of a hash field
- function connection:hset(key, field, value)
- return self:trequest{'HSET', key, field, value and self:format(value) or 'nil'}
- end
- -- HSETNX key field value
- -- Set the value of a hash field, only if the field does not exist
- function connection:hsetnx(key, field, value)
- return self:trequest{'HSETNX', key, field, self:format(value)}
- end
- -- HSTRLEN key field
- -- Get the length of the value of a hash field
- function connection:hstrlen(key, field)
- return self:trequest{'HSTRLEN', key, field}
- end
- -- HVALS key
- -- Get all the values in a hash
- function connection:hvals(key)
- return self:request('HVALS '..key)
- end
- -- INCR key
- -- Increment the integer value of a key by one
- function connection:incr(key)
- return self:request('INCR '..key)
- end
- -- INCRBY key increment
- -- Increment the integer value of a key by the given amount
- function connection:incrby(key, increment)
- return self:trequest{'INCRBY', key, increment}
- end
- -- INCRBYFLOAT key increment
- -- Increment the float value of a key by the given amount
- function connection:incrbyfloat(key, increment)
- return self:trequest{'INCRBYFLOAT', key, increment}
- end
- -- INFO [section]
- -- Get information and statistics about the server
- function connection:info(section)
- return self:trequest{'INFO', section}
- end
- -- KEYS pattern
- -- Find all keys matching the given pattern
- function connection:keys(mask)
- return self:request('KEYS '..(mask or '*'))
- end
- -- LASTSAVE
- -- Get the UNIX time stamp of the last successful save to disk
- function connection:lastsave()
- return self:request('LASTSAVE')
- end
- -- LINDEX key index
- -- Get an element from a list by its index
- function connection:lindex(key, index)
- return self:trequest{'LINDEX', key, index}
- end
- -- LINSERT key BEFORE|AFTER pivot value
- -- Insert an element before or after another element in a list
- function connection:linsert(key, pivot, value, shift)
- shift = shift and 'BEFORE' or 'AFTER'
- return self:trequest{'LINSERT', key, shift, self:format(pivot), self:format(value)}
- end
- -- LLEN key
- -- Get the length of a list
- function connection:llen(key)
- return self:request('LLEN '..key)
- end
- -- LPOP key
- -- Remove and get the first element in a list
- function connection:lpop(key)
- return self:request('LPOP '..key)
- end
- -- LPUSH key value [value ...]
- -- Prepend one or multiple values to a list
- function connection:lpush(key, value)
- return self:trequest{'LPUSH', key, self:format(value)}
- end
- -- LPUSHX key value
- -- Prepend a value to a list, only if the list exists
- function connection:lpushx(key, value)
- return self:trequest{'LPUSHX', key, self:format(value)}
- end
- -- LRANGE key start stop
- -- Get a range of elements from a list
- function connection:lrange(key, s, e)
- return self:trequest{'LRANGE', key, s, e}
- end
- -- LREM key count value
- -- Remove elements from a list
- function connection:lrem(key, count, value)
- return self:trequest{'LREM', key, count, self:format(value)}
- end
- -- LSET key index value
- -- Set the value of an element in a list by its index
- function connection:lset(key, index, value)
- return self:trequest{'LSET', key, index, self:format(value)}
- end
- -- LTRIM key start stop
- -- Trim a list to the specified range
- function connection:ltrim(key, s, e)
- return self:trequest{'LTRIM', key, s, e}
- end
- -- MEMORY DOCTOR
- -- Outputs memory problems report
- function connection:memoryDoctor()
- return self:request('MEMORY DOCTOR')
- end
- -- MEMORY HELP
- -- Show helpful text about the different subcommands
- function connection:memoryHelp()
- return self:request('MEMORY HELP')
- end
- -- MEMORY MALLOC-STATS
- -- Show allocator internal stats
- function connection:memoryMallocStats()
- return self:request('MEMORY MALLOC-STATS')
- end
- -- MEMORY PURGE
- -- Ask the allocator to release memory
- function connection:memoryPurge()
- return self:request('MEMORY PURGE')
- end
- -- MEMORY STATS
- -- Show memory usage details
- function connection:memoryStats()
- return self:request('MEMORY STATS')
- end
- -- MEMORY USAGE key [SAMPLES count]
- -- Estimate the memory usage of a key
- function connection:memoryUsage(key, count)
- return self:trequest{'MEMORY USAGE', key, 'SAMPLES', count or 5}
- end
- -- MGET key [key ...]
- -- Get the values of all the given keys
- function connection:mget(key, ...)
- return self:trequest{'MGET', key, ...}
- end
- -- MIGRATE host port key|"" destination-db timeout [COPY] [REPLACE] [KEYS key [key ...]]
- -- Atomically transfer a key from a Redis instance to another one.
- function connection:migrate(host, port, key, destination, timeout, ...)
- return self:trequest{'MIGRATE', host, port, key, destination, timeout, ...}
- end
- -- MONITOR
- -- Listen for all requests received by the server in real time
- -- Returns monitoring object, string log is path to logging file
- function connection:monitor(log)
- local conn = self
- local self = {}
- self.__file = log and assert(io.open(log, 'wb'), 'Cannot open '..tostring(log)..' path')
- self.__type = 'monitor'
- self.__conn = connection:new(conn.ip, conn.port, conn.pass)
- self.__conn:settimeout(.25)
- self.__conn:connect()
- print('MON', self.__conn:request('MONITOR'))
- function self:receive()
- local data, err = self.__conn:receive(true)
- if self.__file then
- while data do
- self.__file:write(tostring(data)..'\r\n')
- data, err = self.__conn:receive(true)
- end
- else
- return data, err
- end
- end
- function self:close()
- self.receive = function() error('Monitoring disconnected') end
- return self.__conn:close()
- end
- return self
- end
- -- MOVE key db
- -- Move a key to another database
- function connection:move(key, db)
- return self:trequest{'MOVE', key, db}
- end
- -- MSET key value [key value ...]
- -- Set multiple keys to multiple values
- function connection:mset(...)
- local args = {...}
- for i = 2, #args, 2 do args[i] = self:format(args[i]) end
- return self:trequest{'MSET', unpack(args)}
- end
- -- MSETNX key value [key value ...]
- -- Set multiple keys to multiple values, only if none of the keys exist
- function connection:msetnx(...)
- local args = {...}
- for i = 2, #args, 2 do args[i] = self:format(args[i]) end
- return self:trequest{'MSETNX', unpack(args)}
- end
- -- MULTI
- -- Mark the start of a transaction block
- function connection:multi()
- return self:request('MULTI')
- end
- -- OBJECT subcommand [arguments [arguments ...]]
- -- Inspect the internals of Redis objects
- function connection:object(subcommand, ...)
- return self:trequest{'OBJECT', subcommand, ...}
- end
- -- PERSIST key
- -- Remove the expiration from a key
- function connection:persist(key)
- return self:request('PERSIST '..key)
- end
- -- PEXPIRE key milliseconds
- -- Set a key's time to live in milliseconds
- function connection:pexpire(key, milliseconds)
- return self:trequest{'PEXPIRE', key, milliseconds}
- end
- -- PEXPIREAT key milliseconds-timestamp
- -- Set the expiration for a key as a UNIX timestamp specified in milliseconds
- function connection:pexpireat(key, milliseconds_ts)
- return self:trequest{'PEXPIREAT', key, milliseconds_ts}
- end
- -- PFADD key element [element ...]
- -- Adds the specified elements to the specified HyperLogLog.
- function connection:pfadd(key, element, ...)
- return self:trequest{'PFADD', element, ...}
- end
- -- PFCOUNT key [key ...]
- -- Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).
- function connection:pfcount(key, ...)
- return self:trequest{'PFCOUNT', key, ...}
- end
- -- PFMERGE destkey sourcekey [sourcekey ...]
- -- Merge N different HyperLogLogs into a single one.
- function connection:pfmerge(destkey, sourcekey, ...)
- return self:trequest{'PFMERGE', destkey, sourcekey, ...}
- end
- -- PING [message]
- -- Ping the server
- function connection:ping(msg)
- return self:trequest{'PING', msg} and true
- end
- -- PSETEX key milliseconds value
- -- Set the value and expiration in milliseconds of a key
- function connection:psetex(key, ms, value)
- return self:trequest{'PSETEX', ms, self:format(value)}
- end
- -- PUBSUB subcommand [argument [argument ...]]
- -- Inspect the state of the Pub/Sub subsystem
- function connection:pubsub(subcommand, ...)
- return self:trequest{'PUBSUB', subcommand, ...}
- end
- -- PTTL key
- -- Get the time to live for a key in milliseconds
- function connection:pttl(key)
- return self:request('PTTL '..key)
- end
- -- QUIT
- -- Close the connection
- function connection:quit()
- return self:request('QUIT')
- end
- -- RANDOMKEY
- -- Return a random key from the keyspace
- function connection:randomkey()
- return self:request('RANDOMKEY')
- end
- -- READONLY
- -- Enables read queries for a connection to a cluster slave node
- function connection:readonly()
- return self:request('READONLY')
- end
- -- READWRITE
- -- Disables read queries for a connection to a cluster slave node
- function connection:readwrite()
- return self:request('READWRITE')
- end
- -- RENAME key newkey
- -- Rename a key
- function connection:rename(key, newkey)
- return self:trequest{'RENAME', key, newkey}
- end
- -- RENAMENX key newkey
- -- Rename a key, only if the new key does not exist
- function connection:renamenx(key, newkey)
- return self:trequest{'RENAMENX', key, newkey}
- end
- -- RESTORE key ttl serialized-value [REPLACE]
- -- Create a key using the provided serialized value, previously obtained using DUMP.
- function connection:restore(key, ttl, serialized_value, replace)
- return self:trequest{'RENAMENX', key, ttl, serialized_value, replace and 'REPLACE'}
- end
- -- ROLE
- -- Return the role of the instance in the context of replication
- function connection:role()
- return self:request('ROLE')
- end
- -- RPOP key
- -- Remove and get the last element in a list
- function connection:rpop(key)
- return self:request('RPOP '..key)
- end
- -- RPOPLPUSH source destination
- -- Remove the last element in a list, prepend it to another list and return it
- function connection:rpoplpush(source, destination)
- return self:trequest{'RPOPLPUSH', source, destination}
- end
- -- RPUSH key value [value ...]
- -- Append one or multiple values to a list
- function connection:rpush(key, ...)
- return self:trequest{'RPUSH', key, unpack(self:format{...})}
- end
- -- RPUSHX key value
- -- Append a value to a list, only if the list exists
- function connection:rpushx(key, ...)
- return self:trequest{'RPUSHX', key, unpack(self:format{...})}
- end
- -- SADD key member [member ...]
- -- Add one or more members to a set
- function connection:sadd(key, ...)
- return self:trequest{'SADD', key, unpack(self:format{...})}
- end
- -- SAVE
- -- Synchronously save the dataset to disk
- function connection:save()
- return self:request('SAVE')
- end
- -- SCARD key
- -- Get the number of members in a set
- function connection:scard(key)
- return self:request('SCARD '..key)
- end
- -- SCRIPT DEBUG YES|SYNC|NO
- -- Set the debug mode for executed scripts.
- function connection:scriptDebug(mode)
- return self:request('SCRIPT DEBUG '..(mode or 'YES'))
- end
- -- SCRIPT EXISTS sha1 [sha1 ...]
- -- Check existence of scripts in the script cache.
- function connection:scriptExists(...)
- return self:trequest{'SCRIPT EXISTS', ...}
- end
- -- SCRIPT FLUSH
- -- Remove all the scripts from the script cache.
- function connection:scriptFlush()
- return self:request('SCRIPT FLUSH')
- end
- -- SCRIPT KILL
- -- Kill the script currently in execution.
- function connection:scriptKill()
- return self:request('SCRIPT KILL')
- end
- -- SCRIPT LOAD script
- -- Load the specified Lua script into the script cache.
- function connection:scriptLoad(script)
- return self:request('SCRIPT LOAD '..self:format(script:gsub('[\r\n]', [[\r\n]])))
- end
- -- SDIFF key [key ...]
- -- Subtract multiple sets
- function connection:sdiff(key, ...)
- return self:trequest{'SDIFF', key, ...}
- end
- -- SDIFFSTORE destination key [key ...]
- -- Subtract multiple sets and store the resulting set in a key
- function connection:sdiffstore(destination, key, ...)
- return self:trequest{'SDIFFSTORE', destination, key, ...}
- end
- -- SELECT index
- -- Change the selected database for the current connection
- function connection:select(index)
- return self:request('SELECT '..index)
- end
- -- SET key value [EX seconds] [PX milliseconds] [NX|XX]
- -- Set the string value of a key
- function connection:set(key, value, ex, ex_mode)
- local req = {}
- req[1] = 'SET'
- req[2] = tostring(key)
- req[3] = self:format(value)
- if type(ex) == 'number' then
- local sec = floor(ex)
- local msc = floor(ex % 1 * 1000)
- req[#req + 1] = ('EX %d PX %d'):format(sec, msc)
- end
- if type(ex_mode) == 'boolean' then
- req[#req + 1] = ex_mode and 'NX' or 'XX'
- end
- return self:trequest(req)
- end
- -- SETBIT key offset value
- -- Sets or clears the bit at offset in the string value stored at key
- function connection:setbit(key, offset, value)
- return self:trequest{'SETBIT', key, offset, self:format(value)}
- end
- -- SETEX key seconds value
- -- Set the value and expiration of a key
- function connection:setex(key, seconds, value)
- return self:trequest{'SETEX', key, seconds, self:format(value)}
- end
- -- SETNX key value
- -- Set the value of a key, only if the key does not exist
- function connection:setnx(key, value)
- return self:trequest{'SETNX', key, self:format(value)}
- end
- -- SETRANGE key offset value
- -- Overwrite part of a string at key starting at the specified offset
- function connection:setrange(key, offset, value)
- return self:trequest{'SETRANGE', key, offset, self:format(value)}
- end
- -- SHUTDOWN [NOSAVE|SAVE]
- -- Synchronously save the dataset to disk and then shut down the server
- function connection:shutdown(noSave)
- return self:request('SHUTDOWN '..(noSave and 'NOSAVE' or 'SAVE'))
- end
- -- SINTER key [key ...]
- -- Intersect multiple sets
- function connection:sinter(key, ...)
- return self:trequest{'SINTER', key, ...}
- end
- -- SINTERSTORE destination key [key ...]
- -- Intersect multiple sets and store the resulting set in a key
- function connection:sinterstore(destination, key, ...)
- return self:trequest{'SINTERSTORE', destination, key, ...}
- end
- -- SISMEMBER key member
- -- Determine if a given value is a member of a set
- function connection:sismember(key, member)
- return self:trequest{'SISMEMBER', key, self:format(member)}
- end
- -- SLAVEOF host port
- -- Make the server a slave of another instance, or promote it as master
- function connection:slaveof(host, port)
- return self:trequest{'SLAVEOF', host, port}
- end
- -- SLOWLOG subcommand [argument]
- -- Manages the Redis slow queries log
- function connection:slowlog(subcommand, argument)
- return self:trequest{'SLOWLOG', subcommand, argument}
- end
- -- SMEMBERS key
- -- Get all the members in a set
- function connection:smembers(key)
- return self:request('SMEMBERS '..key)
- end
- -- SMOVE source destination member
- -- Move a member from one set to another
- function connection:smove(source, destination, member)
- return self:trequest{'SMOVE', source, destination, self:format(member)}
- end
- -- SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]
- -- Sort the elements in a list, set or sorted set
- function connection:sort(key, ...)
- return self:trequest{'SORT', key, ...}
- end
- -- SPOP key [count]
- -- Remove and return one or multiple random members from a set
- function connection:spop(key, count)
- return self:trequest{'SPOP', key, count}
- end
- -- SRANDMEMBER key [count]
- -- Get one or multiple random members from a set
- function connection:srandmember(key, count)
- return self:trequest{'SRANDMEMBER', key, count}
- end
- -- SREM key member [member ...]
- -- Remove one or more members from a set
- function connection:srem(key, ...)
- return self:trequest{'SREM', key, unpack(self:format{...})}
- end
- -- STRLEN key
- -- Get the length of the value stored in a key
- function connection:strlen(key)
- return self:request('STRLEN '..key)
- end
- -- SUNION key [key ...]
- -- Add multiple sets
- function connection:sunion(key, ...)
- return self:trequest{'SUNION', key, ...}
- end
- -- SUNIONSTORE destination key [key ...]
- -- Add multiple sets and store the resulting set in a key
- function connection:sunionstore(destination, key, ...)
- return self:trequest{'SUNIONSTORE', destination, key, ...}
- end
- -- SWAPDB index index
- -- Swaps two Redis databases
- function connection:swapdb(indexA, indexB)
- return self:trequest{'SWAPDB', indexA, indexB}
- end
- -- SYNC
- -- Internal command used for replication
- function connection:sync()
- return self:request('SYNC')
- end
- -- TIME
- -- Return the current server time
- function connection:time()
- return self:request('TIME')
- end
- -- TOUCH key [key ...]
- -- Alters the last access time of a key(s). Returns the number of existing keys specified.
- function connection:touch(key, ...)
- return self:trequest{'TOUCH', key, ...}
- end
- -- TTL key
- -- Get the time to live for a key
- function connection:ttl(key)
- return self:request('TTL '..key)
- end
- -- TYPE key
- -- Determine the type stored at key
- function connection:type(obj)
- local res = self:request('TYPE '..obj)
- return res
- end
- -- UNLINK key [key ...]
- -- Delete a key asynchronously in another thread. Otherwise it is just as DEL, but non blocking.
- function connection:unlink(key, ...)
- return self:trequest{'UNLINK', key, ...}
- end
- -- UNWATCH
- -- Forget about all watched keys
- function connection:unwatch()
- return self:request('UNWATCH')
- end
- -- WAIT numslaves timeout
- -- Wait for the synchronous replication of all the write commands sent in the context of the current connection
- function connection:wait(numslaves, timeout)
- return self:trequest{'WAIT', numslaves, timeout}
- end
- -- WATCH key [key ...]
- -- Watch the given keys to determine execution of the MULTI/EXEC block
- function connection:watch(key, ...)
- return self:trequest{'WATCH', key, ...}
- end
- -- ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
- -- Add one or more members to a sorted set, or update its score if it already exists
- function connection:zadd(key, ...)
- return self:trequest{'ZADD', key, ...}
- end
- -- ZCARD key
- -- Get the number of members in a sorted set
- function connection:zcard(key)
- return self:request('ZCARD '..key)
- end
- -- ZCOUNT key min max
- -- Count the members in a sorted set with scores within the given values
- function connection:zcount(key, min, max)
- return self:trequest{'ZCOUNT', key, min, max}
- end
- -- ZINCRBY key increment member
- -- Increment the score of a member in a sorted set
- function connection:zincrby(key, increment, member)
- return self:trequest{'ZINCRBY', key, increment, self:format(member)}
- end
- -- ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
- -- Intersect multiple sorted sets and store the resulting sorted set in a new key
- function connection:zinterstore(destination, numkeys, key, ...)
- return self:trequest{'ZINTERSTORE', destination, numkeys, key, ...}
- end
- -- ZLEXCOUNT key min max
- -- Count the number of members in a sorted set between a given lexicographical range
- function connection:zlexcount(key, min, max)
- return self:trequest{'ZLEXCOUNT', key, min, max}
- end
- -- ZRANGE key start stop [WITHSCORES]
- -- Return a range of members in a sorted set, by index
- function connection:zrange(key, start, stop, withscores)
- return self:trequest{'ZRANGE', key, start, stop, (withscores and 'WITHSCORES' or nil)}
- end
- -- ZRANGEBYLEX key min max [LIMIT offset count]
- -- Return a range of members in a sorted set, by lexicographical range
- function connection:zrangebylex(key, min, max, ...)
- return self:trequest{'ZRANGEBYLEX', key, min, max, ...}
- end
- -- ZREVRANGEBYLEX key max min [LIMIT offset count]
- -- Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.
- function connection:zrevrangebylex(key, max, min, ...)
- return self:trequest{'ZREVRANGEBYLEX', key, max, min, ...}
- end
- -- ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
- -- Return a range of members in a sorted set, by score
- function connection:zrangebyscore(key, min, max, withscores, ...)
- return self:trequest{'ZRANGEBYSCORE', key, min, max, (withscores and 'WITHSCORES' or nil), ...}
- end
- -- ZRANK key member
- -- Determine the index of a member in a sorted set
- function connection:zrank(key, member)
- return self:trequest{'ZRANK', key, self:format(member)}
- end
- -- ZREM key member [member ...]
- -- Remove one or more members from a sorted set
- function connection:zrem(key, ...)
- return self:trequest{'ZREM', key, self:format{...}}
- end
- -- ZREMRANGEBYLEX key min max
- -- Remove all members in a sorted set between the given lexicographical range
- function connection:zremrangebylex(key, min, max)
- return self:trequest{'ZREMRANGEBYLEX', key, min, max}
- end
- -- ZREMRANGEBYRANK key start stop
- -- Remove all members in a sorted set within the given indexes
- function connection:zremrangebyrank(key, start, stop)
- return self:trequest{'ZREMRANGEBYRANK', key, start, stop}
- end
- -- ZREMRANGEBYSCORE key min max
- -- Remove all members in a sorted set within the given scores
- function connection:zremrangebyscore(key, min, max)
- return self:trequest{'ZREMRANGEBYSCORE', key, min, max}
- end
- -- ZREVRANGE key start stop [WITHSCORES]
- -- Return a range of members in a sorted set, by index, with scores ordered from high to low
- function connection:zrevrange(key, start, stop, withscores)
- return self:trequest{'ZREVRANGE', key, start, stop, (withscores and 'WITHSCORES' or nil)}
- end
- -- ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
- -- Return a range of members in a sorted set, by score, with scores ordered from high to low
- function connection:zrevrangebyscore(key, max, min, withscores, ...)
- return self:trequest{'ZREVRANGEBYSCORE', key, max, min, (withscores and 'WITHSCORES' or nil), ...}
- end
- -- ZREVRANK key member
- -- Determine the index of a member in a sorted set, with scores ordered from high to low
- function connection:zrevrank(key, member)
- return self:trequest{'ZREVRANK', key, self:format(member)}
- end
- -- ZSCORE key member
- -- Get the score associated with the given member in a sorted set
- function connection:zscore(key, member)
- return self:trequest{'ZSCORE', key, self:format(member)}
- end
- -- ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
- -- Add multiple sorted sets and store the resulting sorted set in a new key
- function connection:zunionstore(destination, numkeys, ...)
- return self:trequest{'ZUNIONSTORE', destination, numkeys, ...}
- end
- -- SCAN cursor [MATCH pattern] [COUNT count]
- -- Incrementally iterate the keys space
- function connection:scan(cursor, ...)
- return self:trequest{'SCAN', cursor, ...}
- end
- -- SSCAN key cursor [MATCH pattern] [COUNT count]
- -- Incrementally iterate Set elements
- function connection:sscan(key, cursor, ...)
- return self:trequest{'SSCAN', key, cursor, ...}
- end
- -- HSCAN key cursor [MATCH pattern] [COUNT count]
- -- Incrementally iterate hash fields and associated values
- function connection:hscan(key, cursor, ...)
- return self:trequest{'HSCAN', key, cursor, ...}
- end
- -- ZSCAN key cursor [MATCH pattern] [COUNT count]
- -- Incrementally iterate sorted sets elements and associated scores
- function connection:zscan(key, cursor, ...)
- return self:trequest{'ZSCAN', key, cursor, ...}
- end
- -- PUBLISH channel message
- -- Post a message to a channel
- function connection:publish(channel, message)
- return self:trequest{'PUBLISH', channel, self:format(message)}
- end
- -- // base structure
- local structure = {}
- structure.__index = structure
- function structure:new(name, connection)
- local o = {}
- o.__name = name
- o.__conn = connection
- return setmetatable(o, self)
- end
- function structure:Inspect()
- return 'Structure ['..self.__name..']'
- end
- -- // structures
- local hash = setmetatable({}, structure)
- hash.__type = 'hash'
- function hash:__index(key)
- key = key and tostring(key) or nil
- if hash[key] then return hash[key] end
- return self:Get(key)
- end
- function hash:__tostring()
- return 'Hash ['..self.__name..']'
- end
- function hash:new(name, connection)
- local o = structure:new(name, connection)
- o.__updated = false
- o.__cache = {}
- return setmetatable(o, self)
- end
- -- HSET key field value
- -- Set the string value of a hash field
- function hash:Set(key, value, mode)
- key = key and tostring(key) or nil
- local req = {}
- req[1] = 'hset'
- req[2] = self.__name
- req[3] = key
- if type(value) == 'nil' then
- req[1] = 'hdel'
- self.__cache[key] = nil
- return self.__conn:trequest(req)
- end
- if mode then
- req[1] = 'hsetnx'
- end
- req[4] = self.__conn:format(value)
- local res = self.__conn:trequest(req)
- if res then self.__cache[key] = value end
- return res
- end
- -- HSETNX key field value
- -- Set the value of a hash field, only if the field does not exist
- function hash:SetNx(key, value)
- return self:Set(key, value, true)
- end
- -- HMSET key field value [field value ...]
- -- Set multiple hash fields to multiple values
- function hash:Mset(tbl)
- local req = {}
- req[1] = 'hmset'
- req[2] = self.__name
- for key, value in pairs(tbl) do
- req[#req + 1] = tostring(key)
- req[#req + 1] = self.__conn:format(value)
- end
- return self.__conn:trequest(req)
- end
- -- HGET key field
- -- Get the value of a hash field
- function hash:Get(key)
- local cache = self.__cache[key]
- if cache then return cache end
- local req = {}
- req[1] = 'HGET'
- req[2] = self.__name
- req[3] = self.__conn:format(key)
- local value = self.__conn:trequest(req)
- -- cache
- if value ~= -1 then
- self.__cache[key] = value
- end
- return self.__cache[key]
- end
- function hash:Mget(...)
- local req = {}
- req[1] = 'HMGET'
- req[2] = self.__name
- req[3] = type(...) == 'tab'
- local t = type(...)
- if t == 'table' then
- req[3] = self.__conn:format(...)
- else
- req[3] = self.__conn:format{...}
- end
- local res = self.__conn:trequest(req)
- local value
- for i, key in ipairs(tbl) do
- value = res[i]
- self.__cache[key] = value ~= -1 and value or nil
- end
- return res
- end
- function hash:Mset(tbl)
- local req = {}
- req[1] = 'HMSET'
- req[2] = self.__name
- for key, value in pairs(tbl) do
- req[#req + 1] = tostring(key)
- req[#req + 1] = self.__conn:format(value)
- self.__cache[key] = value
- end
- return self.__conn:trequest(req)
- end
- hash.__newindex = hash.Set
- function hash:Len()
- return self.__conn:request('HLEN '..self.__name)
- end
- function hash:Del(key)
- return self.__conn:trequest{'HDEL', self.__name, key}
- end
- function hash:StrLen(key)
- return self.__conn:trequest{'HSTRLEN', self.__name, key}
- end
- function hash:IncrBy(key, inc)
- return self.__conn:trequest{'HINCRBY', self.__name, key, inc or 1}
- end
- function hash:IncrByFloat(key, inc)
- return self.__conn:trequest{'HINCRBYFLOAT', self.__name, key, inc or 1}
- end
- function hash:Keys()
- return self.__conn:request('HKEYS '..self.__name)
- end
- function hash:Vals()
- return self.__conn:request('HVALS '..self.__name)
- end
- function hash:Pairs()
- self:GetAll()
- local key, value
- return function()
- key, value = next(self.__cache, key)
- return key, value
- end
- end
- function hash:Inspect(fmt)
- fmt = fmt or 0
- self:GetAll()
- local res = {}
- res[1] = ('%s (%s) {'):format(self.__name, self.__conn:type(self.__name))
- local template = '%'..fmt..'s: [%s]'
- for k, v in pairs(self.__cache) do
- res[#res + 1] = template:format(k, v)
- end
- res[#res + 1] = '}'
- return concat(res, '\n')
- end
- function hash:Scan(key, match, count)
- local req = {}
- req[1] = 'HSCAN'
- req[2] = self.__name
- req[3] = type(key) == 'number' and key or 0
- req[4] = 'MATCH'
- req[5] = match or '*'
- req[6] = 'COUNT'
- req[7] = count or 1000
- local res = self.__conn:trequest(req)
- key = res[1]
- res = res[2]
- local result = {}
- local key, value
- for i = 1, #res, 2 do
- key, value = res[i], res[i + 1]
- result[key] = value
- self.__cache[key] = value
- end
- return result, key
- end
- function hash:Find(match, count)
- return self:Scan(0, match, count)
- end
- function hash:Exists(field)
- return self.__conn:trequest{'HEXISTS', self.__name, field}
- end
- -- HGETALL key
- -- Get all the fields and values in a hash
- function hash:GetAll()
- if self.__updated then return end
- self.__updated = true
- local res = self.__conn:request('hgetall '..self.__name)
- local result = {}
- local key, value
- for i = 1, #res, 2 do
- key, value = res[i], res[i + 1]
- self.__cache[key] = value
- result[key] = value
- end
- return result
- end
- -- DEL
- function hash:Delete()
- return self.__conn:request('DEL '..self.__name)
- end
- local list = setmetatable({}, structure)
- list.__type = 'list'
- function list:new(name, connection)
- local o = structure:new(name, connection)
- o.__updated = false
- o.__cache = {}
- return setmetatable(o, self)
- end
- function list:__index(key)
- if type(key) ~= 'number' then
- return rawget(self, key) or list[key]
- end
- return self:Index(key)
- end
- function list:__newindex(key, value)
- error('List: cannot direct assign values', 2)
- end
- function list:__tostring()
- return 'List ['..self.__name..']'
- end
- function list:Index(key)
- key = key > 0 and key or self:Len() + (key + 1)
- local cache = self.__cache[key]
- if cache then return cache end
- local value = self.__conn:trequest{'LINDEX', self.__name, key}
- -- cache
- if value ~= -1 then
- self.__cache[key] = value
- end
- return self.__cache[key]
- end
- function list:Push(...)
- local req = {}
- req[1] = 'LPUSH'
- req[2] = self.__name
- req[3] = self.__conn:format{...}
- local res = self.__conn:trequest(req)
- if res then
- self.__cache[res] = value
- end
- return res
- end
- function list:Lpush(...)
- local req = {}
- req[1] = 'LPUSH'
- req[2] = self.__name
- req[3] = self.__conn:format{...}
- local res = self.__conn:trequest(req)
- if res then
- self.__cache[res] = value
- end
- return res
- end
- function list:Len()
- return self.__conn:request('LLEN '..self.__name)
- end
- function list:GetAll()
- if self.__updated then return self.__cache end
- self.__updated = true
- return self:Range()
- end
- function list:Inspect(fmt)
- fmt = fmt or 0
- self:GetAll()
- local res = {}
- res[1] = ('%s (%s) {'):format(self.__name, self.__conn:type(self.__name))
- local template = '%'..fmt..'d: [%s]'
- for i, v in ipairs(self.__cache) do
- res[#res + 1] = template:format(i, v)
- end
- res[#res + 1] = '}'
- return concat(res, '\n')
- end
- function list:Range(min, max)
- -- lua key-index normalisation (starts from 1)
- min = min or 1
- max = max or -1
- min = min > 0 and min - 1 or min
- max = max > 0 and max - 1 or max
- local req = {}
- req[1] = 'LRANGE'
- req[2] = self.__name
- req[3] = min
- req[4] = max
- local result = self.__conn:trequest(req)
- for i, v in ipairs(result) do
- i = i + min
- self.__cache[i] = v
- end
- return result
- end
- function list:Ipairs()
- self:GetAll()
- local i = 0
- return function()
- i = i + 1
- if self[i] then
- return i, self[i]
- end
- end
- end
- local set = setmetatable({}, structure)
- set.__type = 'set'
- set.__index = set
- function set:new(name, connection)
- local o = structure:new(name, connection)
- o.__updated = false
- o.__cache = {}
- return setmetatable(o, self)
- end
- function set:__index(key)
- key = key and tostring(key) or nil
- local v = rawget(self, key) or set[key]
- if v then return v end
- if self.__cache[key] then return true end
- return self:IsMember(key)
- end
- function set:__newindex(key, value)
- key = key and tostring(key) or nil
- return value and self:Add(key) or self:Rem(key)
- end
- function set:__tostring()
- return 'Set ['..self.__name..']'
- end
- function set:Add(...)
- if not ... then return end
- local req = {}
- req[1] = 'sadd'
- req[2] = self.__name
- for i, value in ipairs{...} do
- if not self.__cache[value] then
- req[#req + 1] = self.__conn:format(value)
- end
- self.__cache[value] = true
- end
- return self.__conn:trequest(req)
- end
- function set:Rem(...)
- if not ... then return end
- local req = {}
- req[1] = 'SREM'
- req[2] = self.__name
- for i, value in ipairs{...} do
- if self.__cache[value] then
- req[#req + 1] = self.__conn:format(value)
- end
- self.__cache[value] = nil
- end
- return self.__conn:trequest(req)
- end
- function set:Diff(...)
- if not ... then return end
- local req = {}
- req[1] = 'SDIFF'
- req[2] = self.__name
- for i, value in ipairs{...} do
- if type(value) == 'table' then
- value = value.__name
- end
- req[#req + 1] = value
- end
- return self.__conn:trequest(req)
- end
- function set:DiffStore(...)
- if not ... then return end
- local req = {}
- req[1] = 'SDIFFSTORE'
- req[2] = self.__name
- for i, value in ipairs{...} do
- if type(value) == 'table' then
- value = value.__name
- end
- req[#req + 1] = value
- end
- local res = self.__conn:trequest(req)
- self:Members()
- return res
- end
- function set:Inter(...)
- if not ... then return end
- local req = {}
- req[1] = 'SINTER'
- req[2] = self.__name
- for i, value in ipairs{...} do
- if type(value) == 'table' and value.__type == 'list' then
- value = value.__name
- end
- req[#req + 1] = value
- end
- return self.__conn:trequest(req)
- end
- function set:InterStore(...)
- if not ... then return end
- local req = {}
- req[1] = 'SINTERSTORE'
- req[2] = self.__name
- for i, value in ipairs{...} do
- if type(value) == 'table' and value.__type == 'list' then
- value = value.__name
- end
- req[#req + 1] = value
- end
- local res = self.__conn:trequest(req)
- self:Members()
- return res
- end
- function set:Union(...)
- if not ... then return end
- local req = {}
- req[1] = 'SUNIONS'
- req[2] = self.__name
- for i, value in ipairs{...} do
- if type(value) == 'table' then
- value = value.__name
- end
- req[#req + 1] = value
- end
- return self.__conn:trequest(req)
- end
- function set:UnionStore(...)
- if not ... then return end
- local req = {}
- req[1] = 'SUNIONSTORE'
- req[2] = self.__name
- for i, value in ipairs{...} do
- if type(value) == 'table' and value.__type == 'list' then
- value = value.__name
- end
- req[#req + 1] = value
- end
- local res = self.__conn:trequest(req)
- self:Members()
- return res
- end
- function set:IsMember(value)
- if self.__cache[value] then
- return 1
- end
- local res = self.__conn:trequest{'SISMEMBER', self.__name, self:format(value)}
- self.__cache[value] = res == 1 or nil
- return res
- end
- function set:Members()
- local res = self.__conn:trequest{'SMEMBER', self.__name}
- self.__cache = {}
- for i, value in ipairs(res or {}) do
- self.__cache[value] = true
- end
- return res
- end
- function set:Move(destination, value)
- local dstable = type(destination) == 'table'
- if dstable then
- destination = destination.__name
- end
- local res = self.__conn:trequest{'SMOVE', self.__name}
- if res == 1 then
- self.__cache[value] = nil
- if dstable then
- dstable.__cache[value] = true
- end
- end
- return res
- end
- function set:RandMember(count)
- return self.__conn:trequest{'SRANDMEMBER', self.__name, count}
- end
- function set:GetAll()
- if self.__updated then return self.__cache end
- self.__updated = true
- return self:Members()
- end
- function set:Len()
- return self.__conn:trequest{'SCARD', self.__name}
- end
- set.Card = set.Len
- function set:Pop(n)
- local res = self.__conn:trequest{'SPOP', self.__name, n or 1}
- if type(res) == 'string' then
- self.__cache[res] = nil
- return res
- end
- for i, value in ipairs(res) do
- self.__cache[value] = nil
- end
- return res
- end
- function set:Inspect(fmt)
- fmt = fmt or 0
- local res = {}
- res[1] = ('%s (%s) {'):format(self.__name, self.__conn:type(self.__name))
- local template = ' %'..fmt..'s'
- for k, v in pairs(self.__cache) do
- res[#res + 1] = template:format(k)
- end
- res[#res + 1] = '}'
- return concat(res, '\n')
- end
- local subscriber = {}
- subscriber.__type = 'subscriber'
- subscriber.__index = subscriber
- function subscriber:new(connect, ...)
- self = setmetatable({}, self)
- self.__subs = {}
- self.__psubs = {}
- self.__conn = connection:new(connect.ip, connect.port, connection.pass)
- self.__conn:connect()
- if ... then
- self:subscribe(...)
- for i = 1, select('#', ...) - 1 do
- self.__conn:receive(true)
- end
- end
- self.__conn:settimeout(0) -- set to zero
- return self
- end
- local function key_conc(t, sep)
- local res = {}
- for k, v in pairs(t) do res[#res + 1] = tostring(k) end
- return table.concat(res, sep or ' ')
- end
- function subscriber:__tostring()
- return 'Subscriber: subs: {'..key_conc(self.__subs)..'}, psubs: {'..key_conc(self.__psubs)..'}'
- end
- -- user redefined
- function subscriber:onMessage(channel, message)
- -- print('Published message:', channel, message)
- end
- -- receive new messages, call onMessage callback
- function subscriber:update()
- local data = self.__conn:receive(true)
- while data do
- self:onMessage(data[2], data[3])
- data = self.__conn:receive(true)
- end
- end
- -- SUBSCRIBE channel [channel ...]
- -- Listen for messages published to the given channels
- function subscriber:subscribe(...)
- for i, v in ipairs{...} do self.__subs[v] = true end
- return self.__conn:trequest{'SUBSCRIBE', ...}
- end
- -- UNSUBSCRIBE [channel [channel ...]]
- -- Stop listening for messages posted to the given channels
- function subscriber:unsubscribe(...)
- for i, v in ipairs{...} do self.__subs[v] = nil end
- return self.__conn:trequest{'UNSUBSCRIBE', ...}
- end
- -- PSUBSCRIBE pattern [pattern ...]
- -- Listen for messages published to channels matching the given patterns
- function subscriber:psubscribe(...)
- for i, v in ipairs{...} do self.__psubs[v] = true end
- return self.__conn:trequest{'PSUBSCRIBE', ...}
- end
- -- PUNSUBSCRIBE [pattern [pattern ...]]
- -- Stop listening for messages posted to channels matching the given patterns
- function subscriber:punsubscribe(...)
- for i, v in ipairs{...} do self.__psubs[v] = nil end
- return self.__conn:trequest{'PUNSUBSCRIBE', ...}
- end
- -- close connection
- function subscriber:close()
- local subs, psubs = {}, {}
- for sub in pairs(self.__subs) do subs[#subs + 1] = sub end
- for pub in pairs(self.__psubs) do psubs[#psubs + 1] = pub end
- if #subs > 0 then self:unsubscribe(unpack(subs)) end
- if #psubs > 0 then self:punsubscribe(unpack(psubs)) end
- return self.__conn:close()
- end
- -- // structure instancing
- function connection:newHash(name)
- assert(type('name' == 'string'), 'String name of hash expected, got '..type(name))
- return hash:new(name, self)
- end
- function connection:newList(name)
- assert(type('name' == 'string'), 'String name of list expected, got '..type(name))
- return list:new(name, self)
- end
- function connection:newSet(name)
- assert(type('name' == 'string'), 'String name of set expected, got '..type(name))
- local set = set:new(name, self)
- set:GetAll()
- return set
- end
- function connection:newSubscriber(...)
- return subscriber:new(self, ...)
- end
- return connection
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement