fixes for scanning generator

This commit is contained in:
2024-12-25 19:01:32 +01:00
parent 1bbb182df3
commit 41f0c13da6
39 changed files with 238 additions and 160 deletions

View File

View File

View File

View File

@@ -1,58 +0,0 @@
module redisclient
// original code see https://github.com/patrickpissurno/vredis/blob/master/vredis_test.v
// credits see there as well (-:
import net
// import sync
// import strconv
__global (
redis_connections []Redis
)
const default_read_timeout = net.infinite_timeout
@[heap]
pub struct Redis {
pub:
addr string
mut:
socket net.TcpConn
}
// https://redis.io/topics/protocol
// examples:
// localhost:6379
// /tmp/redis-default.sock
pub fn new(addr string) !Redis {
// lock redis_connections {
for mut conn in redis_connections {
if conn.addr == addr {
return conn
}
}
// means there is no connection yet
mut r := Redis{
addr: addr
}
r.socket_connect()!
redis_connections << r
return r
//}
// panic("bug")
}
pub fn reset() ! {
// lock redis_connections {
for mut conn in redis_connections {
conn.disconnect()
}
redis_connections = []Redis{}
//}
}
pub fn checkempty() {
// lock redis_connections {
assert redis_connections.len == 0
//}
}

View File

@@ -1,19 +0,0 @@
# Redisclient
## basic example to connect to local redis on 127.0.0.1:6379
```v
import freeflowuniverse.herolib.clients.redisclient
mut redis := redisclient.core_get()!
redis.set('test', 'some data') or { panic('set' + err.str() + '\n' + c.str()) }
r := redis.get('test')?
if r != 'some data' {
panic('get error different result.' + '\n' + c.str())
}
```
> redis commands can be found on https://redis.io/commands/

View File

@@ -1,57 +0,0 @@
module redisclient
import freeflowuniverse.herolib.ui.console
pub struct RedisCache {
mut:
redis &Redis @[str: skip]
namespace string
enabled bool = true
}
// return a cache object starting from a redis connection
pub fn (mut r Redis) cache(namespace string) RedisCache {
return RedisCache{
redis: &r
namespace: namespace
}
}
pub fn (mut h RedisCache) get(key string) ?string {
if !h.enabled {
return none
}
key2 := h.namespace + ':' + key
hit := h.redis.get('cache:${key2}') or {
console.print_debug('[-] cache: cache miss, ${key2}')
return none
}
console.print_debug('[+] cache: cache hit: ${key2}')
return hit
}
pub fn (mut h RedisCache) set(key string, val string, expire int) ! {
if !h.enabled {
return
}
key2 := h.namespace + ':' + key
h.redis.set_ex('cache:${key2}', val, expire.str())!
}
pub fn (mut h RedisCache) exists(key string) bool {
h.get(key) or { return false }
return true
}
pub fn (mut h RedisCache) reset() ! {
key_check := 'cache:' + h.namespace
// console.print_debug(key_check)
keys := h.redis.keys(key_check)!
// console.print_debug(keys)
for key in keys {
// console.print_debug(key)
h.redis.del(key)!
}
}

View File

@@ -1,305 +0,0 @@
module redisclient
import freeflowuniverse.herolib.data.resp
import time
pub fn (mut r Redis) ping() !string {
return r.send_expect_strnil(['PING'])
}
pub fn (mut r Redis) set(key string, value string) ! {
return r.send_expect_ok(['SET', key, value])
}
pub fn (mut r Redis) set_ex(key string, value string, ex string) ! {
return r.send_expect_ok(['SET', key, value, 'EX', ex])
}
pub fn (mut r Redis) set_opts(key string, value string, opts SetOpts) !bool {
ex := if opts.ex == -4 && opts.px == -4 {
''
} else if opts.ex != -4 {
' EX ${opts.ex}'
} else {
' PX ${opts.px}'
}
nx := if opts.nx == false && opts.xx == false {
''
} else if opts.nx == true {
' NX'
} else {
' XX'
}
keep_ttl := if opts.keep_ttl == false { '' } else { ' KEEPTTL' }
message := 'SET "${key}" "${value}"${ex}${nx}${keep_ttl}\r\n'
r.write(message.bytes()) or { return false }
time.sleep(1 * time.millisecond)
res := r.read_line()!
match res {
'+OK\r\n' {
return true
}
else {
return false
}
}
}
pub fn (mut r Redis) get(key string) !string {
// mut key2 := key.trim("\"'")
return r.send_expect_strnil(['GET', key])
}
pub fn (mut r Redis) exists(key string) !bool {
r2 := r.send_expect_int(['EXISTS', key])!
return r2 == 1
}
pub fn (mut r Redis) del(key string) !int {
return r.send_expect_int(['DEL', key])
}
pub fn (mut r Redis) hset(key string, skey string, value string) ! {
r.send_expect_int(['HSET', key, skey, value])!
}
pub fn (mut r Redis) hget(key string, skey string) !string {
// mut key2 := key.trim("\"'")
return r.send_expect_strnil(['HGET', key, skey])
}
pub fn (mut r Redis) hgetall(key string) !map[string]string {
// mut key2 := key.trim("\"'")
res := r.send_expect_list_str(['HGETALL', key])!
mut mapped := map[string]string{}
mut i := 0
for i < res.len && i + 1 < res.len {
mapped[res[i]] = res[i + 1]
i += 2
}
return mapped
}
pub fn (mut r Redis) hexists(key string, skey string) !bool {
return r.send_expect_bool(['HEXISTS', key, skey])
}
pub fn (mut r Redis) hdel(key string, skey string) !int {
return r.send_expect_int(['HDEL', key, skey])
}
pub fn (mut r Redis) incrby(key string, increment int) !int {
return r.send_expect_int(['INCRBY', key, increment.str()])
}
pub fn (mut r Redis) incr(key string) !int {
return r.incrby(key, 1)
}
pub fn (mut r Redis) decr(key string) !int {
return r.incrby(key, -1)
}
pub fn (mut r Redis) decrby(key string, decrement int) !int {
return r.incrby(key, -decrement)
}
pub fn (mut r Redis) incrbyfloat(key string, increment f64) !f64 {
res := r.send_expect_str(['INCRBYFLOAT', key, increment.str()])!
count := res.f64()
return count
}
pub fn (mut r Redis) append(key string, value string) !int {
return r.send_expect_int(['APPEND', key, value])
}
pub fn (mut r Redis) setrange(key string, offset int, value string) !int {
return r.send_expect_int(['SETRANGE', key, offset.str(), value.str()])
}
pub fn (mut r Redis) lpush(key string, element string) !int {
return r.send_expect_int(['LPUSH', key, element])
}
pub fn (mut r Redis) rpush(key string, element string) !int {
return r.send_expect_int(['RPUSH', key, element])
}
pub fn (mut r Redis) lrange(key string, start int, end int) ![]resp.RValue {
return r.send_expect_list(['LRANGE', key, start.str(), end.str()])
}
pub fn (mut r Redis) expire(key string, seconds int) !int {
return r.send_expect_int(['EXPIRE', key, seconds.str()])
}
pub fn (mut r Redis) pexpire(key string, millis int) !int {
return r.send_expect_int(['PEXPIRE', key, millis.str()])
}
pub fn (mut r Redis) expireat(key string, timestamp int) !int {
return r.send_expect_int(['EXPIREAT', key, timestamp.str()])
}
pub fn (mut r Redis) pexpireat(key string, millistimestamp i64) !int {
return r.send_expect_int(['PEXPIREAT', key, millistimestamp.str()])
}
pub fn (mut r Redis) persist(key string) !int {
return r.send_expect_int(['PERSIST', key])
}
pub fn (mut r Redis) getset(key string, value string) !string {
return r.send_expect_strnil(['GETSET', key, value])
}
pub fn (mut r Redis) getrange(key string, start int, end int) !string {
return r.send_expect_str(['GETRANGE', key, start.str(), end.str()])
}
pub fn (mut r Redis) keys(pattern string) ![]string {
response := r.send_expect_list(['KEYS', pattern])!
mut result := []string{}
for item in response {
result << resp.get_redis_value(item)
}
return result
}
pub fn (mut r Redis) hkeys(key string) ![]string {
response := r.send_expect_list(['HKEYS', key])!
mut result := []string{}
for item in response {
result << resp.get_redis_value(item)
}
return result
}
pub fn (mut r Redis) randomkey() !string {
return r.send_expect_strnil(['RANDOMKEY'])
}
pub fn (mut r Redis) strlen(key string) !int {
return r.send_expect_int(['STRLEN', key])
}
pub fn (mut r Redis) lpop(key string) !string {
return r.send_expect_strnil(['LPOP', key])
}
pub fn (mut r Redis) blpop(keys []string, timeout f64) ![]string {
mut request := ['BLPOP']
request << keys
request << '${timeout}'
res := r.send_expect_list_str(request)!
if res.len != 2 || res[1] == '' {
return error('timeout on blpop')
}
return res
}
pub fn (mut r Redis) brpop(keys []string, timeout f64) ![]string {
mut request := ['BRPOP']
request << keys
request << '${timeout}'
res := r.send_expect_list_str(request)!
if res.len != 2 {
return error('timeout on brpop')
}
return res
}
pub fn (mut r Redis) rpop(key string) !string {
return r.send_expect_strnil(['RPOP', key])
}
pub fn (mut r Redis) llen(key string) !int {
return r.send_expect_int(['LLEN', key])
}
pub fn (mut r Redis) ttl(key string) !int {
return r.send_expect_int(['TTL', key])
}
pub fn (mut r Redis) pttl(key string) !int {
return r.send_expect_int(['PTTL', key])
}
pub fn (mut r Redis) rename(key string, newkey string) ! {
return r.send_expect_ok(['RENAME', key, newkey])
}
pub fn (mut r Redis) renamenx(key string, newkey string) !int {
return r.send_expect_int(['RENAMENX', key, newkey])
}
pub fn (mut r Redis) setex(key string, second i64, value string) ! {
return r.send_expect_ok(['SETEX', key, second.str(), value])
}
pub fn (mut r Redis) psetex(key string, millisecond i64, value string) ! {
return r.send_expect_ok(['PSETEX', key, millisecond.str(), value])
}
pub fn (mut r Redis) setnx(key string, value string) !int {
return r.send_expect_int(['SETNX', key, value])
}
pub fn (mut r Redis) type_of(key string) !string {
return r.send_expect_strnil(['TYPE', key])
}
pub fn (mut r Redis) flushall() ! {
return r.send_expect_ok(['FLUSHALL'])
}
pub fn (mut r Redis) flushdb() ! {
return r.send_expect_ok(['FLUSHDB'])
}
// select is reserved
pub fn (mut r Redis) selectdb(database int) ! {
return r.send_expect_ok(['SELECT', database.str()])
}
pub fn (mut r Redis) scan(cursor int) !(string, []string) {
res := r.send_expect_list(['SCAN', cursor.str()])!
if res[0] !is resp.RBString {
return error('Redis SCAN wrong response type (cursor)')
}
if res[1] !is resp.RArray {
return error('Redis SCAN wrong response type (list content)')
}
mut values := []string{}
for i in 0 .. resp.get_redis_array_len(res[1]) {
values << resp.get_redis_value_by_index(res[1], i)
}
return resp.get_redis_value(res[0]), values
}
// Add the specified members to the set stored at key. Specified members that are already a member
// of this set are ignored. If key does not exist, a new set is created before adding the specified members.
// An error is returned when the value stored at key is not a set.
pub fn (mut r Redis) sadd(key string, members []string) !int {
mut tosend := ['SADD', key]
for k in members {
tosend << k
}
return r.send_expect_int(tosend)
}
// Returns if member is a member of the set stored at key.
pub fn (mut r Redis) smismember(key string, members []string) ![]int {
// mut key2 := key.trim("\"'")
mut tosend := ['SMISMEMBER', key]
for k in members {
tosend << k
}
res := r.send_expect_list_int(tosend)!
return res
}

View File

@@ -1,24 +0,0 @@
module redisclient
@[params]
pub struct RedisURL {
address string = '127.0.0.1'
port int = 6379
// db int
}
pub fn get_redis_url(url string) !RedisURL {
if !url.contains(':') {
return error('url doesnt contain port')
} else {
return RedisURL{
address: url.all_before_last(':')
port: url.all_after_last(':').u16()
}
}
}
pub fn core_get(url RedisURL) !Redis {
mut r := new('${url.address}:${url.port}')!
return r
}

View File

@@ -1,173 +0,0 @@
module redisclient
import freeflowuniverse.herolib.data.resp
pub fn (mut r Redis) get_response() !resp.RValue {
line := r.read_line()!
if line.starts_with('-') {
return resp.RError{
value: line[1..]
}
}
if line.starts_with(':') {
return resp.RInt{
value: line[1..].int()
}
}
if line.starts_with('+') {
return resp.RString{
value: line[1..]
}
}
if line.starts_with('$') {
mut bulkstring_size := line[1..].int()
if bulkstring_size == -1 {
return resp.RNil{}
}
if bulkstring_size == 0 {
// extract final \r\n and not reading
// any payload
r.read_line()!
return resp.RString{
value: ''
}
}
// read payload
buffer := r.read(bulkstring_size) or { panic(err) }
// extract final \r\n
r.read_line()!
// console.print_debug("readline result:'$buffer.bytestr()'")
return resp.RBString{
value: buffer
} // TODO: won't support binary (afaik), need to fix? WHY not (despiegk)?
}
if line.starts_with('*') {
mut arr := resp.RArray{
values: []resp.RValue{}
}
items := line[1..].int()
// proceed each entries, they can be of any types
for _ in 0 .. items {
value := r.get_response()!
arr.values << value
}
return arr
}
return error('unsupported response type')
}
// TODO: needs to use the resp library
pub fn (mut r Redis) get_int() !int {
line := r.read_line()!
if line.starts_with(':') {
return line[1..].int()
} else {
return error("Did not find int, did find:'${line}'")
}
}
pub fn (mut r Redis) get_list_int() ![]int {
line := r.read_line()!
mut res := []int{}
if line.starts_with('*') {
items := line[1..].int()
// proceed each entries, they can be of any types
for _ in 0 .. items {
value := r.get_int()!
res << value
}
return res
} else {
return error("Did not find int, did find:'${line}'")
}
}
pub fn (mut r Redis) get_list_str() ![]string {
line := r.read_line()!
mut res := []string{}
if line.starts_with('*') {
items := line[1..].int()
// proceed each entries, they can be of any types
for _ in 0 .. items {
value := r.get_string()!
res << value
}
return res
} else {
return error("Did not find int, did find:'${line}'")
}
}
pub fn (mut r Redis) get_string() !string {
line := r.read_line()!
if line.starts_with('+') {
// console.print_debug("getstring:'${line[1..]}'")
return line[1..]
}
if line.starts_with('$') {
r2 := r.get_bytes_from_line(line)!
return r2.bytestr()
} else {
return error("Did not find string, did find:'${line}'")
}
}
pub fn (mut r Redis) get_string_nil() !string {
r2 := r.get_bytes_nil()!
return r2.bytestr()
}
pub fn (mut r Redis) get_bytes_nil() ![]u8 {
line := r.read_line()!
if line.starts_with('+') {
return line[1..].bytes()
}
if line.starts_with('$-1') {
return []u8{}
}
if line.starts_with('$') {
return r.get_bytes_from_line(line)
} else {
return error("Did not find string or nil, did find:'${line}'")
}
}
pub fn (mut r Redis) get_bool() !bool {
i := r.get_int()!
return i == 1
}
pub fn (mut r Redis) get_bytes() ![]u8 {
line := r.read_line()!
if line.starts_with('$') {
return r.get_bytes_from_line(line)
} else {
return error("Did not find bulkstring, did find:'${line}'")
}
}
fn (mut r Redis) get_bytes_from_line(line string) ![]u8 {
mut bulkstring_size := line[1..].int()
if bulkstring_size == -1 {
// return none
return error('bulkstring_size is -1')
}
if bulkstring_size == 0 {
// extract final \r\n, there is no payload
r.read_line()!
return []
}
// read payload
buffer := r.read(bulkstring_size) or { panic('Could not read payload: ${err}') }
// extract final \r\n
r.read_line()!
return buffer
}

View File

@@ -1,121 +0,0 @@
module redisclient
import os
import net
import freeflowuniverse.herolib.data.resp
import time
import net.unix
pub struct SetOpts {
ex int = -4
px int = -4
nx bool
xx bool
keep_ttl bool
}
pub enum KeyType {
t_none
t_string
t_list
t_set
t_zset
t_hash
t_stream
t_unknown
}
fn (mut r Redis) socket_connect() ! {
// print_backtrace()
addr := os.expand_tilde_to_home(r.addr)
// console.print_debug(' - REDIS CONNECT: ${addr}')
if !addr.contains(':') {
unix_socket := unix.connect_stream(addr)!
tcp_socket := net.tcp_socket_from_handle_raw(unix_socket.sock.Socket.handle)
tcp_conn := net.TcpConn{
sock: tcp_socket
handle: unix_socket.sock.Socket.handle
}
r.socket = tcp_conn
} else {
r.socket = net.dial_tcp(addr)!
}
r.socket.set_blocking(true)!
r.socket.set_read_timeout(1 * time.second)
// console.print_debug("---OK")
}
fn (mut r Redis) socket_check() ! {
r.socket.peer_addr() or {
// console.print_debug(' - re-connect socket for redis')
r.socket_connect()!
}
}
pub fn (mut r Redis) read_line() !string {
return r.socket.read_line().trim_right('\r\n')
}
// write *all the data* into the socket
// This function loops, till *everything is written*
// (some of the socket write ops could be partial)
fn (mut r Redis) write(data []u8) ! {
r.socket_check()!
mut remaining := data.len
for remaining > 0 {
// zdbdata[data.len - remaining..].bytestr())
written_bytes := r.socket.write(data[data.len - remaining..])!
remaining -= written_bytes
}
}
fn (mut r Redis) read(size int) ![]u8 {
r.socket_check() or {}
mut buf := []u8{len: size}
mut remaining := size
for remaining > 0 {
read_bytes := r.socket.read(mut buf[buf.len - remaining..])!
remaining -= read_bytes
}
return buf
}
pub fn (mut r Redis) disconnect() {
r.socket.close() or {}
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// TODO: need to implement a way how to use multiple connections at once
const cr_lf_bytes = [u8(`\r`), `\n`]
fn (mut r Redis) write_line(data []u8) ! {
r.write(data)!
r.write(cr_lf_bytes)!
}
// write resp value to the redis channel
pub fn (mut r Redis) write_rval(val resp.RValue) ! {
r.write(val.encode())!
}
// write list of strings to redis challen
fn (mut r Redis) write_cmd(item string) ! {
a := resp.r_bytestring(item.bytes())
r.write_rval(a)!
}
// write list of strings to redis challen
fn (mut r Redis) write_cmds(items []string) ! {
// if items.len==1{
// a := resp.r_bytestring(items[0].bytes())
// r.write_rval(a)!
// }{
a := resp.r_list_bstring(items)
r.write_rval(a)!
// }
}

View File

@@ -1,41 +0,0 @@
module redisclient
import time
pub struct RedisQueue {
pub mut:
key string
redis &Redis
}
pub fn (mut r Redis) queue_get(key string) RedisQueue {
return RedisQueue{
key: key
redis: r
}
}
pub fn (mut q RedisQueue) add(val string) ! {
q.redis.lpush(q.key, val)!
}
// timeout in msec
pub fn (mut q RedisQueue) get(timeout u64) !string {
start := u64(time.now().unix_milli())
for {
r := q.redis.rpop(q.key) or { '' }
if r != '' {
return r
}
if u64(time.now().unix_milli()) > (start + timeout) {
break
}
time.sleep(time.microsecond)
}
return error('timeout on ${q.key}')
}
// get without timeout, returns none if nil
pub fn (mut q RedisQueue) pop() !string {
return q.redis.rpop(q.key)!
}

View File

@@ -1,136 +0,0 @@
module redisclient
import rand
import time
import json
pub struct RedisRpc {
pub mut:
key string // queue name as used by this rpc
redis &Redis
}
// return a rpc mechanism
pub fn (mut r Redis) rpc_get(key string) RedisRpc {
return RedisRpc{
key: key
redis: r
}
}
pub struct RPCArgs {
pub:
cmd string @[required]
data string @[required]
timeout u64 = 60000 // 60 sec
wait bool = true
}
pub struct Message {
pub:
ret_queue string
now i64
cmd string
data string
}
pub struct Response {
pub:
result string
error string
}
// send data to a queue and wait till return comes back
// timeout in milliseconds
// params
// cmd string @[required]
// data string @[required]
// timeout u64=60000 //60 sec
// wait bool=true
pub fn (mut q RedisRpc) call(args RPCArgs) !string {
retqueue := rand.uuid_v4()
now := time.now().unix()
message := Message{
ret_queue: retqueue
now: now
cmd: args.cmd
data: args.data
}
encoded := json.encode(message)
q.redis.lpush(q.key, encoded)!
if args.wait {
return q.result(args.timeout, retqueue)!
}
return ''
}
// get return once result processed
pub fn (mut q RedisRpc) result(timeout u64, retqueue string) !string {
start := u64(time.now().unix_milli())
for {
r := q.redis.rpop(retqueue) or { '' }
if r != '' {
res := json.decode(Response, r)!
if res.error != '' {
return res.error
}
return res.result
}
if u64(time.now().unix_milli()) > (start + timeout) {
break
}
time.sleep(time.millisecond)
}
return error('timeout on returnqueue: ${retqueue}')
}
@[params]
pub struct ProcessParams {
pub:
timeout u64
}
// to be used by processor, to get request and execute, this is the server side of a RPC mechanism
// 2nd argument is a function which needs to execute the job: fn (string,string) !string
pub fn (mut q RedisRpc) process(op fn (string, string) !string, params ProcessParams) !string {
start := u64(time.now().unix_milli())
for {
r := q.redis.rpop(q.key) or { '' }
if r != '' {
msg := json.decode(Message, r)!
returnqueue := msg.ret_queue
// epochtime:=parts[1].u64() //we don't do anything with it now
cmd := msg.cmd
data := msg.data
// if true{panic("sd")}
datareturn := op(cmd, data) or {
response := Response{
result: ''
error: err.str()
}
encoded := json.encode(response)
q.redis.lpush(returnqueue, encoded)!
return ''
}
response := Response{
result: datareturn
error: ''
}
encoded := json.encode(response)
q.redis.lpush(returnqueue, encoded)!
return returnqueue
}
if params.timeout != 0 && u64(time.now().unix_milli()) > (start + params.timeout) {
break
}
time.sleep(time.millisecond)
}
return error('timeout for waiting for cmd on ${q.key}')
}
// get without timeout, returns none if nil
pub fn (mut q RedisRpc) delete() ! {
q.redis.del(q.key)!
}

View File

@@ -1,25 +0,0 @@
import freeflowuniverse.herolib.clients.redisclient
fn setup() !&redisclient.Redis {
mut redis := redisclient.core_get()!
redis.selectdb(10) or { panic(err) }
return &redis
}
fn cleanup(mut redis redisclient.Redis) ! {
redis.flushall()!
// redis.disconnect()
}
fn test_sadd() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.sadd('mysadd', ['a', 'b', 'c']) or { panic(err) }
r := redis.smismember('mysadd', ['a', 'b', 'c']) or { panic(err) }
assert r == [1, 1, 1]
r2 := redis.smismember('mysadd', ['a', 'd', 'c']) or { panic(err) }
assert r2 == [1, 0, 1]
}

View File

@@ -1,6 +0,0 @@
module redisclient
// load a script and return the hash
pub fn (mut r Redis) script_load(script string) !string {
return r.send_expect_str(['SCRIPT LOAD', script])!
}

View File

@@ -1,55 +0,0 @@
module redisclient
import freeflowuniverse.herolib.data.resp
import freeflowuniverse.herolib.ui.console
// send list of strings, expect OK back
pub fn (mut r Redis) send_expect_ok(items []string) ! {
r.write_cmds(items)!
res := r.get_string()!
if res != 'OK' {
console.print_debug("'${res}'")
return error('did not get ok back')
}
}
// send list of strings, expect int back
pub fn (mut r Redis) send_expect_int(items []string) !int {
r.write_cmds(items)!
return r.get_int()
}
pub fn (mut r Redis) send_expect_bool(items []string) !bool {
r.write_cmds(items)!
return r.get_bool()
}
// send list of strings, expect string back
pub fn (mut r Redis) send_expect_str(items []string) !string {
r.write_cmds(items)!
return r.get_string()
}
// send list of strings, expect string or nil back
pub fn (mut r Redis) send_expect_strnil(items []string) !string {
r.write_cmds(items)!
d := r.get_string_nil()!
return d
}
// send list of strings, expect list of strings back
pub fn (mut r Redis) send_expect_list_str(items []string) ![]string {
r.write_cmds(items)!
return r.get_list_str()
}
pub fn (mut r Redis) send_expect_list_int(items []string) ![]int {
r.write_cmds(items)!
return r.get_list_int()
}
pub fn (mut r Redis) send_expect_list(items []string) ![]resp.RValue {
r.write_cmds(items)!
res := r.get_response()!
return resp.get_redis_array(res)
}

View File

@@ -1,864 +0,0 @@
import freeflowuniverse.herolib.clients.redisclient
import time
import freeflowuniverse.herolib.ui.console
// original code see https://github.com/patrickpissurno/vredis/blob/master/vredis_test.v
// credits see there as well (-:
fn setup() !&redisclient.Redis {
mut redis := redisclient.core_get()!
// Select db 10 to be away from default one '0'
redis.selectdb(10) or { panic(err) }
return &redis
}
fn cleanup(mut redis redisclient.Redis) ! {
redis.flushall()!
// redis.disconnect()
}
fn test_set() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
// console.print_debug('start')
// for _ in 0 .. 10000 {
// redis.set('test0', '123')!
// }
console.print_debug('stop')
redis.set('test0', '456')!
res := redis.get('test0')!
assert res == '456'
redis.hset('x', 'a', '222')!
redis.hset('x', 'b', '333')!
mut res3 := redis.hget('x', 'b')!
assert res3 == '333'
redis.hdel('x', 'b')!
res3 = redis.hget('x', 'b')!
assert res3 == ''
e := redis.hexists('x', 'a')!
assert e
}
fn test_large_value() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
rr := 'SSS' + 'a'.repeat(40000) + 'EEE'
mut rr2 := ''
for i in 0 .. 50 {
redis.set('test_large_value0', rr)!
rr2 = redis.get('test_large_value0')!
assert rr.len == rr2.len
assert rr == rr2
}
for i3 in 0 .. 100 {
redis.set('test_large_value${i3}', rr)!
}
for i4 in 0 .. 100 {
rr4 := redis.get('test_large_value${i4}')!
assert rr.len == rr4.len
redis.del('test_large_value${i4}')!
}
}
fn test_queue() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
mut q := redis.queue_get('kds:q')
q.add('test1')!
q.add('test2')!
mut res := q.get(1)!
assert res == 'test1'
res = q.get(1)!
assert res == 'test2'
console.print_debug('start')
res = q.get(100) or { '' }
console.print_debug('stop')
assert res == ''
console.print_debug(res)
}
fn test_scan() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
console.print_debug('stop')
redis.set('test3', '12')!
redis.set('test4', '34')!
redis.set('test5', '56')!
redis.set('test6', '78')!
redis.set('test7', '9')!
cursor, data := redis.scan(0)!
console.print_debug(data)
assert cursor == '0'
}
// fn test_set_opts() {
// mut redis := setup()!
// defer {
// cleanup(mut redis) or { panic(err) }
// }
// assert redis.set_opts('test8', '123', redisclient.SetOpts{
// ex: 2
// }) or {false}== true
// assert redis.set_opts('test8', '456', redisclient.SetOpts{
// px: 2000
// xx: true
// }) or {false} == true
// assert redis.set_opts('test8', '789', redisclient.SetOpts{
// px: 1000
// nx: true
// }) or {false}== false
// // Works with redis version > 6
// assert redis.set_opts('test8', '012', redisclient.SetOpts{ keep_ttl: true }) or {false}== true
// }
fn test_setex() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.setex('test9', 2, '123')!
mut r := redis.get('test9')!
assert r == '123'
time.sleep(2100 * time.millisecond)
r = redis.get('test9')!
assert r == ''
}
fn test_psetex() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.psetex('test10', 200, '123')!
mut r := redis.get('test10') or {
assert false
return
}
assert r == '123'
time.sleep(220 * time.millisecond)
r = redis.get('test10')!
assert r == ''
}
fn test_setnx() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
mut r1 := redis.setnx('test11', '123')!
assert r1 == 1
r1 = redis.setnx('test11', '456')!
assert r1 == 0
val := redis.get('test11') or {
assert false
return
}
assert val == '123'
}
fn test_incrby() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test12', '100')!
r1 := redis.incrby('test12', 4) or {
assert false
return
}
assert r1 == 104
r2 := redis.incrby('test13', 2) or {
assert false
return
}
assert r2 == 2
redis.set('test14', 'nan')!
redis.incrby('test14', 1) or {
assert true
return
}
assert false
}
fn test_incr() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test15', '100')!
r1 := redis.incr('test15') or {
assert false
return
}
assert r1 == 101
r2 := redis.incr('test16') or {
assert false
return
}
assert r2 == 1
redis.set('test17', 'nan')!
redis.incr('test17') or {
assert true
return
}
assert false
}
fn test_decr() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test18', '100')!
r1 := redis.decr('test18') or {
assert false
return
}
assert r1 == 99
r2 := redis.decr('test19') or {
assert false
return
}
assert r2 == -1
redis.set('test20', 'nan')!
redis.decr('test20') or {
assert true
return
}
assert false
}
fn test_decrby() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test21', '100')!
r1 := redis.decrby('test21', 4) or {
assert false
return
}
assert r1 == 96
r2 := redis.decrby('test22', 2) or {
assert false
return
}
assert r2 == -2
redis.set('test23', 'nan')!
redis.decrby('test23', 1) or {
assert true
return
}
assert false
}
fn test_incrbyfloat() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test24', '3.1415')!
r1 := redis.incrbyfloat('test24', 3.1415) or {
assert false
return
}
assert r1 == 6.283
r2 := redis.incrbyfloat('test25', 3.14) or {
assert false
return
}
assert r2 == 3.14
r3 := redis.incrbyfloat('test25', -3.14) or {
assert false
return
}
assert r3 == 0
redis.set('test26', 'nan')!
redis.incrbyfloat('test26', 1.5) or {
assert true
return
}
assert false
}
fn test_append() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test27', 'bac')!
r1 := redis.append('test27', 'on') or {
assert false
return
}
assert r1 == 5
r2 := redis.get('test27') or {
assert false
return
}
assert r2 == 'bacon'
}
fn test_lpush() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r := redis.lpush('test28', 'item 1') or {
assert false
return
}
assert r == 1
}
fn test_rpush() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r := redis.rpush('test29', 'item 1') or {
assert false
return
}
assert r == 1
}
fn test_setrange() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r1 := redis.setrange('test30', 0, 'bac') or {
assert false
return
}
assert r1 == 3
r2 := redis.setrange('test30', 3, 'on') or {
assert false
return
}
assert r2 == 5
}
fn test_expire() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r1 := redis.expire('test31', 2) or {
assert false
return
}
assert r1 == 0
redis.set('test31', '123')!
r2 := redis.expire('test31', 2) or {
assert false
return
}
assert r2 == 1
}
fn test_pexpire() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r1 := redis.pexpire('test32', 200) or {
assert false
return
}
assert r1 == 0
redis.set('test32', '123')!
r2 := redis.pexpire('test32', 200) or {
assert false
return
}
assert r2 == 1
}
fn test_expireat() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r1 := redis.expireat('test33', 1293840000) or {
assert false
return
}
assert r1 == 0
redis.set('test33', '123')!
r2 := redis.expireat('test33', 1293840000) or {
assert false
return
}
assert r2 == 1
}
fn test_pexpireat() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r1 := redis.pexpireat('test34', 1555555555005) or {
assert false
return
}
assert r1 == 0
redis.set('test34', '123')!
r2 := redis.pexpireat('test34', 1555555555005) or {
assert false
return
}
assert r2 == 1
}
fn test_persist() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r1 := redis.persist('test35') or {
assert false
return
}
assert r1 == 0
redis.setex('test35', 2, '123')!
r2 := redis.persist('test35') or {
assert false
return
}
assert r2 == 1
}
fn test_get() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test36', '123')!
mut r := redis.get('test36')!
assert r == '123'
assert helper_get_key_not_found(mut redis, 'test37') == true
}
fn test_getset() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
mut r1 := redis.getset('test38', '10') or { '' }
assert r1 == ''
r2 := redis.getset('test38', '15') or {
assert false
return
}
assert r2 == '10'
r3 := redis.get('test38') or {
assert false
return
}
assert r3 == '15'
}
fn test_getrange() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test39', 'community')!
r1 := redis.getrange('test39', 4, -1) or {
assert false
return
}
assert r1 == 'unity'
r2 := redis.getrange('test40', 0, -1) or {
assert false
return
}
assert r2 == ''
}
fn test_randomkey() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
assert helper_randomkey_database_empty(mut redis) == true
redis.set('test41', '123')!
r2 := redis.randomkey() or {
assert false
return
}
assert r2 == 'test41'
assert helper_get_key_not_found(mut redis, 'test42') == true
}
fn test_strlen() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test43', 'bacon')!
r1 := redis.strlen('test43') or {
assert false
return
}
assert r1 == 5
r2 := redis.strlen('test44') or {
assert false
return
}
assert r2 == 0
}
fn test_lpop() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.lpush('test45', '123') or {
assert false
return
}
r1 := redis.lpop('test45') or {
assert false
return
}
assert r1 == '123'
assert helper_lpop_key_not_found(mut redis, 'test46') == true
}
fn test_rpop() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.lpush('test47', '123') or {
assert false
return
}
r1 := redis.rpop('test47') or {
assert false
return
}
assert r1 == '123'
assert helper_rpop_key_not_found(mut redis, 'test48') == true
}
fn test_brpop() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.lpush('test47', '123')!
redis.lpush('test48', 'balbal')!
r1 := redis.brpop(['test47', 'test48'], 1)!
assert r1[0] == 'test47'
assert r1[1] == '123'
r2 := redis.brpop(['test47', 'test48'], 1)!
assert r2[0] == 'test48'
assert r2[1] == 'balbal'
r3 := redis.brpop(['test47'], 1) or { return }
assert false, 'brpop should timeout'
}
fn test_lrpop() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.lpush('test47', '123')!
redis.lpush('test48', 'balbal')!
r1 := redis.blpop(['test47', 'test48'], 1)!
assert r1[0] == 'test47'
assert r1[1] == '123'
r2 := redis.blpop(['test47', 'test48'], 1)!
assert r2[0] == 'test48'
assert r2[1] == 'balbal'
r3 := redis.blpop(['test47'], 1) or { return }
assert false, 'blpop should timeout'
}
fn test_llen() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r1 := redis.lpush('test49', '123') or {
assert false
return
}
r2 := redis.llen('test49') or {
assert false
return
}
assert r2 == r1
r3 := redis.llen('test50') or {
assert false
return
}
assert r3 == 0
redis.set('test51', 'not a list')!
redis.llen('test51') or {
assert true
return
}
assert false
}
fn test_ttl() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.setex('test52', 15, '123')!
r1 := redis.ttl('test52') or {
assert false
return
}
assert r1 == 15
redis.set('test53', '123')!
r2 := redis.ttl('test53') or {
assert false
return
}
assert r2 == -1
r3 := redis.ttl('test54') or {
assert false
return
}
assert r3 == -2
}
fn test_pttl() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.psetex('test55', 1500, '123')!
r1 := redis.pttl('test55') or {
assert false
return
}
assert r1 >= 1490 && r1 <= 1500
redis.set('test56', '123')!
r2 := redis.pttl('test56') or {
assert false
return
}
assert r2 == -1
r3 := redis.pttl('test57') or {
assert false
return
}
assert r3 == -2
}
fn test_exists() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
r1 := redis.exists('test58') or {
assert false
return
}
assert r1 == false
redis.set('test59', '123')!
r2 := redis.exists('test59') or {
assert false
return
}
assert r2 == true
}
fn test_type_of() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
_ := redis.type_of('test60') or {
assert true
return
}
redis.set('test61', '123')!
mut r := redis.type_of('test61') or {
assert false
return
}
assert r == 'string'
_ := redis.lpush('test62', '123')!
r = redis.type_of('test62') or {
assert false
return
}
assert r == 'list'
}
fn test_del() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test63', '123')!
c := redis.del('test63') or {
assert false
return
}
assert c == 1
assert helper_get_key_not_found(mut redis, 'test63') == true
}
fn test_rename() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.rename('test64', 'test65') or { console.print_debug('key not found') }
redis.set('test64', 'will be 65')!
redis.rename('test64', 'test65')!
r := redis.get('test65') or {
assert false
return
}
assert r == 'will be 65'
}
fn test_renamenx() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
assert helper_renamenx_err_helper(mut redis, 'test66', 'test67') == 'no such key'
redis.set('test68', '123')!
redis.set('test66', 'will be 67')!
r1 := redis.renamenx('test66', 'test67') or {
assert false
return
}
assert r1 == 1
r2 := redis.get('test67') or {
assert false
return
}
assert r2 == 'will be 67'
r3 := redis.renamenx('test67', 'test68') or {
assert false
return
}
assert r3 == 0
}
fn test_flushall() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test69', '123')!
redis.flushall()!
assert helper_get_key_not_found(mut redis, 'test69') == true
}
fn test_keys() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
redis.set('test70:1', '1')!
redis.set('test70:2', '2')!
r1 := redis.keys('test70:*') or {
assert false
return
}
assert r1.len == 2
}
fn helper_get_key_not_found(mut redis redisclient.Redis, key string) bool {
return redis.get(key) or {
if err.msg() == 'key not found' || err.msg() == '' {
return true
} else {
return false
}
} == ''
}
fn helper_randomkey_database_empty(mut redis redisclient.Redis) bool {
return redis.randomkey() or {
if err.msg() == 'database is empty' || err.msg() == '' {
return true
} else {
return false
}
} == ''
}
fn helper_renamenx_err_helper(mut redis redisclient.Redis, key string, newkey string) string {
redis.renamenx(key, newkey) or { return 'no such key' }
return ''
}
fn helper_lpop_key_not_found(mut redis redisclient.Redis, key string) bool {
return redis.lpop(key) or {
if err.msg() == 'key not found' || err.msg() == '' {
return true
} else {
return false
}
} == ''
}
fn helper_rpop_key_not_found(mut redis redisclient.Redis, key string) bool {
return redis.rpop(key) or {
if err.msg() == 'key not found' || err.msg() == '' {
return true
} else {
return false
}
} == ''
}

View File

@@ -1,33 +0,0 @@
import freeflowuniverse.herolib.clients.redisclient
import freeflowuniverse.herolib.ui.console
fn setup() !&redisclient.Redis {
mut redis := redisclient.core_get()!
// Select db 10 to be away from default one '0'
redis.selectdb(10) or { panic(err) }
return &redis
}
fn cleanup(mut redis redisclient.Redis) ! {
redis.flushall()!
// redis.disconnect()
}
fn process_test(cmd string, data string) !string {
return '${cmd}+++++${data}\n\n\n\n'
}
fn test_rpc() {
mut redis := setup()!
defer {
cleanup(mut redis) or { panic(err) }
}
mut r := redis.rpc_get('testrpc')
r.call(cmd: 'test.cmd', data: 'this is my data, normally json', wait: false)!
returnqueue := r.process(10000, process_test)!
mut res := r.result(10000, returnqueue)!
console.print_debug(res)
assert res.str().trim_space() == 'test.cmd+++++this is my data, normally json'
}

View File

View File