adilbaig / tiny-redis Goto Github PK
View Code? Open in Web Editor NEWRedis driver for D
Home Page: http://adilbaig.github.io/Tiny-Redis/
License: ISC License
Redis driver for D
Home Page: http://adilbaig.github.io/Tiny-Redis/
License: ISC License
Is tiny-redis available as a dub package?
Hi,
The BLPOP command has an optional timeout parameter. When the command times out, Redis will respond with a null array ("*-1\r\n").
This causes the receiveResponses method in the RedisConnection class to get stuck in an infinite loop. For one or some reason after parsing the count is set to 4294967295 on my system. Not 0 or -1.
I provisionally patched the response parser to look for this particular "*-1" pattern but I am not a Redis protocol specialist and cannot oversee the consequence yet.
Best regards,
Jeroen
PS Awesome library! I use it quite a lot because it is simple and very fast!
14:10 $ dub test --compiler=gdc
Generating test runner configuration '__test__default__' for 'default' (library).
Building tinyredis 2.1.0 configuration "__test__default__", build type unittest.
Running gdc...
source/tinyredis/collections/set.d:100: error: module primitives is in file 'std/range/primitives.d' which cannot be read
import path[0] = /mnt/lotsostuff/dev/tools/x86_64-gdcproject-linux-gnu/include/d/4.9.0/x86_64-unknown-linux-gnu
import path[1] = /mnt/lotsostuff/dev/tools/x86_64-gdcproject-linux-gnu/include/d/4.9.0
import path[2] = /mnt/lotsostuff/dev/repos/Tiny-Redis.git/source
FAIL .dub/build/__test__default__-unittest-linux.posix-x86_64-gdc_2065-C3639316B5C48C03D979CFC6A9132E22/ __test__default__ executable
Error executing command test: gdc failed with exit code 1.
It appears we don't have std.range.primitives in that earlier version, though it's hard to tell from the Dlang docs when std.range.primitives was introduced. Because TinyRedis core doesn't rely on std.range.primitives, it would make sense to refactor the one test case using this, line 100-101 of set.d.
Sometimes Redis returns the reponses from a pipeline of commands in more than one response. It appears that receiveReponses in connection.d assumes that they are all recieved in one go. I am running Ubuntu 12.10, dmd 2.061. Below is part of your example.d (which failed for me by the way) called short_ex.d. At the bottom of the file are commented sample sessions. The first run is ok. The second run, shows the results of a pipelined command being split. The tail of the response is treated as the response to a subsequent pipelined transaction. The same scenarios are also shown with -debug.
import tinyredis.redis,
std.stdio
;
/**
Make sure the redis server is running
*/
void main()
{
auto redis = new Redis();
scope( exit ) {
destroy(redis);
}
/*
Here's how you can add multiple items to a Redis Set
*/
redis.send("SADD", "myset", "adil");
redis.send("SADD", "myset", 350001939);
redis.send("SADD", "myset", 1.2);
redis.send("SADD", "myset", true);
Response response = redis.send("SMEMBERS myset");
writeln(response);
/*
Or you can pipeline the queries
*/
Response[] buddies =
redis.pipeline(["SADD buddies Batman", "SADD buddies Spiderman",
"SADD buddies Hulk", "SMEMBERS buddies"]);
writeln(buddies);
/*
Redis Transactions .. are pipelined!
*/
Response[] responses =
redis.transaction(["DEL ctr", "SET ctr 0", "INCR ctr", "INCR ctr"], true);
writeln(responses);
}
/*
redis$> dmd src/short_ex.d tinyredis/*
// THIS IS OK
redis$> ./short_ex
[1.2, 1, true, adil, 350001939, $4]
[0, 0, 0, [Batman, Spiderman, Hulk]]
[OK, QUEUED, QUEUED, QUEUED, QUEUED, [1, OK, 1, 2]]
// THIS IS BAD
redis$> ./short_ex
[1.2, 1, true, adil, 350001939, $4]
[0, 0, 0]
[[Batman, Spiderman, Hulk]]
*/
/* debug
redis$> ./short_ex
Request : '_3\r\n$4\r\nSADD\r\n$5\r\nmyset\r\n$4\r\nadil\r\n'
Response : ':0\r\n' Length : 4
Request : '_3\r\n$4\r\nSADD\r\n$5\r\nmyset\r\n$9\r\n350001939\r\n'
Response : ':0\r\n' Length : 4
Request : '_3\r\n$4\r\nSADD\r\n$5\r\nmyset\r\n$3\r\n1.2\r\n'
Response : ':0\r\n' Length : 4
Request : '_3\r\n$4\r\nSADD\r\n$5\r\nmyset\r\n$4\r\ntrue\r\n'
Response : ':0\r\n' Length : 4
Request : '_2\r\n$8\r\nSMEMBERS\r\n$5\r\nmyset\r\n'
Response : '_6\r\n$3\r\n1.2\r\n$1\r\n1\r\n$4\r\ntrue\r\n$4\r\nadil\r\n$9\r\n350001939\r\n$2\r\n$4\r\n' Length : 63
[1.2, 1, true, adil, 350001939, $4]
// Request : '_3\r\n$4\r\nSADD\r\n$7\r\nbuddies\r\n$6\r\nBatman\r\n_3\r\n$4\r\nSADD\r\n$7\r\nbuddies\r\n$9\r\nSpiderman\r\n_3\r\n$4\r\nSADD\r\n$7\r\nbuddies\r\n$4\r\nHulk\r\n_2\r\n$8\r\nSMEMBERS\r\n$7\r\nbuddies\r\n'
// Response : ':0\r\n:0\r\n:0\r\n*3\r\n$6\r\nBatman\r\n$9\r\nSpiderman\r\n$4\r\nHulk\r\n' Length : 53
// [0, 0, 0, [Batman, Spiderman, Hulk]]
Request : '_1\r\n$5\r\nMULTI\r\n_2\r\n$3\r\nDEL\r\n$3\r\nctr\r\n_3\r\n$3\r\nSET\r\n$3\r\nctr\r\n$1\r\n0\r\n_2\r\n$4\r\nINCR\r\n$3\r\nctr\r\n_2\r\n$4\r\nINCR\r\n$3\r\nctr\r\n_1\r\n$4\r\nEXEC\r\n'
Response : '+OK\r\n+QUEUED\r\n+QUEUED\r\n+QUEUED\r\n+QUEUED\r\n*4\r\n:1\r\n+OK\r\n:1\r\n:2\r\n' Length : 62
[OK, QUEUED, QUEUED, QUEUED, QUEUED, [1, OK, 1, 2]]
r
redis$> ./short_ex
Request : '_3\r\n$4\r\nSADD\r\n$5\r\nmyset\r\n$4\r\nadil\r\n'
Response : ':0\r\n' Length : 4
Request : '_3\r\n$4\r\nSADD\r\n$5\r\nmyset\r\n$9\r\n350001939\r\n'
Response : ':0\r\n' Length : 4
Request : '_3\r\n$4\r\nSADD\r\n$5\r\nmyset\r\n$3\r\n1.2\r\n'
Response : ':0\r\n' Length : 4
Request : '_3\r\n$4\r\nSADD\r\n$5\r\nmyset\r\n$4\r\ntrue\r\n'
Response : ':0\r\n' Length : 4
Request : '_2\r\n$8\r\nSMEMBERS\r\n$5\r\nmyset\r\n'
Response : '_6\r\n$3\r\n1.2\r\n$1\r\n1\r\n$4\r\ntrue\r\n$4\r\nadil\r\n$9\r\n350001939\r\n$2\r\n$4\r\n' Length : 63
[1.2, 1, true, adil, 350001939, $4]
// Request : '_3\r\n$4\r\nSADD\r\n$7\r\nbuddies\r\n$6\r\nBatman\r\n_3\r\n$4\r\nSADD\r\n$7\r\nbuddies\r\n$9\r\nSpiderman\r\n_3\r\n$4\r\nSADD\r\n$7\r\nbuddies\r\n$4\r\nHulk\r\n_2\r\n$8\r\nSMEMBERS\r\n$7\r\nbuddies\r\n'
// Response : ':0\r\n:0\r\n:0\r\n' Length : 12
// [0, 0, 0]
Request : '_1\r\n$5\r\nMULTI\r\n_2\r\n$3\r\nDEL\r\n$3\r\nctr\r\n_3\r\n$3\r\nSET\r\n$3\r\nctr\r\n$1\r\n0\r\n_2\r\n$4\r\nINCR\r\n$3\r\nctr\r\n_2\r\n$4\r\nINCR\r\n$3\r\nctr\r\n_1\r\n$4\r\nEXEC\r\n'
// Response : '*3\r\n$6\r\nBatman\r\n$9\r\nSpiderman\r\n$4\r\nHulk\r\n' Length : 41
// [[Batman, Spiderman, Hulk]]
*/
Hi.
One of the nice things about redis is that strings can be binary. This facilitates use with binary object serialisation using msgpack, for example.
I think you do not implement opCast for ubyte[], which is what would be needed for this purpose.
Am I missing something, or is it worth considering this enhancement?
Laeeth.
After a dmd update:
$ dub build
/usr/include/dlang/dmd/std/format.d(6304,26): Error: type char is not an expression
source/tinyredis/encoder.d(169,15): Error: template instance `tinyredis.encoder.toBulk!char` error instantiating
source/tinyredis/encoder.d(51,31): instantiated from here: accumulator!(char, string)
source/tinyredis/redis.d(64,31): instantiated from here: toMultiBulk!(char, string)
source/tinyredis/collections/set.d(30,22): instantiated from here: send!(Response, string)
source/tinyredis/collections/set.d(35,31): Error: template instance `tinyredis.redis.Redis.send!(int, string)` error instantiating
source/tinyredis/encoder.d(51,31): Error: template instance `tinyredis.encoder.accumulator!(char, string, const(char)[])` error instantiating
source/tinyredis/redis.d(64,31): instantiated from here: toMultiBulk!(char, string, const(char)[])
source/tinyredis/collections/set.d(42,32): instantiated from here: send!(bool, string, const(char)[])
source/tinyredis/collections/set.d(53,12): Error: template instance `tinyredis.redis.Redis.send!(Response, string, const(char)[])` error instantiating
/usr/include/dlang/dmd/std/format.d(6304,26): Error: type char is not an expression
source/tinyredis/redis.d(106,30): Error: template instance `tinyredis.encoder.toMultiBulk!char` error instantiating
source/tinyredis/redis.d(129,32): instantiated from here: pipeline!(immutable(char))
My environment:
$ dmd --version
DMD64 D Compiler v2.087.0
$ dub --version
DUB version 1.16.0, built on Jul 02 2019
$ uname --all
Linux abe 5.1.9-arch1-1-ARCH #1 SMP PREEMPT Tue Jun 11 16:18:09 UTC 2019 x86_64 GNU/Linux
With ldc compiler works.
Thank you
This is a notice to all users of TinyRedis. If you are using this library for your app, website or startup i'd love to hear your feedback. Even a simple mention of your name and your website is nice. Thx!
See modified version below, which seems to work.
import tinyredis.redis;
import std.stdio;
void main()
{
auto redis = new Redis("localhost", 6379);
redis.send("SET name Adil");
writeln("The name's ", redis.send("GET name")); //The name's Adil
//Add data to a set and read it
redis.send("SADD", "fruits", ["apples", "oranges", "bananas"]);
auto fruits = redis.send("SMEMBERS", "fruits");
foreach(k, fruit; fruits)
writeln(k, ") ", fruit);
//Cast your results
//writefln("There are %s fruits", redis.send!(uint)("SCARD", fruits));
//intelligent opCasts for responses!
if(redis.send("EXISTS", fruits))
writefln("Fruits have been defined!");
//Lua scripting is supported! ..
Response r1 = redis.eval("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", ["key1", "key2"], ["first", "second"]);
writeln(r1); // [key1, key2, first, second]
// .. And pipelining
redis.pipeline(["SET person1:name Adil", "SET person1:name Batman", "SET person1:name Robin"]);
//.. And transactions
redis.transaction(["SET ctr 0", "INCR ctr", "INCR ctr"]);
}
http://redis.io/commands/subscribe
You mentioned in the README this just needs a little work. I've added a hack-ish implementation in my fork. I will test for a bit before submitting any kind of pull request. Your code is nice and clean and mine is ...
After fixing #24 please update the dub repo.
Ali
To reproduce:
redis-cli
localhost:6379> set test ""
OK
localhost:6379> get test
""
void main()
{
import tinyredis.redis;
Redis redis = new Redis;
Response arr = redis.send("get test");
}
The program will not exit.
Calls like the below are getting a dmd error saying it can't do Op cast boolean with Response object.
DMD: DMD64 D Compiler v2.066.1
if(redis.send("EXISTS", fruits)) {}
Hi Adil,
Can you please add a new version.
Thank you,
Ali
I've this test (database is empty)
unittest {
auto redis = new Redis();
int cursor;
auto response = redis.send("FLUSHDB");
do {
response = redis.send("SCAN", cursor);
cursor = response.values[0].toInt;
} while (cursor > 0);
}
then
dub test --debug=tinyredis
No source files found in configuration 'library'. Falling back to "dub -b unittest".
Performing "unittest" build using /usr/bin/dmd for x86_64.
tinyredis 2.1.1: target for configuration "default" is up to date.
tinyredis-test ~master: building configuration "application"...
Linking...
To force a rebuild of up-to-date targets, run again with --force.
Running ./tinyredis-test
*1\r\n$7\r\nFLUSHDB\r\n
Response : '+OK\r\n' Length : 5
BUFFER : +OK\r\n
*2\r\n$4\r\nSCAN\r\n$1\r\n0\r\n
Response : '*2\r\n$1\r\n0\r\n*0\r\n' Length : 15
BUFFER : *2\r\n$1\r\n0\r\n*0\r\n
..my application freezes.
If I put same code in Tiny-Redis/source/tinyredis/redis.d :
$ make test
...
...
*1\r\n$7\r\nFLUSHDB\r\n
Response : '+OK\r\n' Length : 5
*2\r\n$4\r\nSCAN\r\n$1\r\n0\r\n
Response : '*2\r\n$1\r\n0\r\n*0\r\n' Length : 15
All unit tests have been run successfully.
it works...
Any suggestion? Thank you
There doesn't seem to be any TLS support atm. (TLS was added in Redis 6.0.)
I'm going to be adding TLS support to TinyRedis, probably using dub openssl. I'm mostly opening this bug to gather "planning review" type feedback before I start working on a PR.
Current idea is to expand connection.d with interface Transport
with class TcpTransport : Transport
and class TlsTransport : Transport
and just make all the networking code call methods on Transport
instead. The whole thing is intended to be hidden behind version (Have_openssl)
, ie. optional dub openssl dependency, so it shouldn't affect existing users. Then Redis::this
just has a new optional parameter to bring up a TLS connection with a certificate.
AUTH stuff can be handled on the userside using sendRaw
.
Look good?
I had version 2.2.1, upgraded to 2.3.1 and the compiler complains:
Error: no property `empty` for type `Response`, perhaps `import std.range;` is needed?
In my code the problem is here:
...
auto list = db.send("LRANGE", name, 0, stop);
if (!list.empty) {
...
so, IMHO this is a breaking change, you should increment version to 3.0.0 .... what do you think?
Thank you very much
When SCAN reach the end of the database, the process is stuck somewhere here:
https://github.com/adilbaig/Tiny-Redis/blob/master/source/tinyredis/connection.d#L100
buffer.length
= 0 and MultiBulks.length
= 1
import tinyredis;
import std.stdio;
void main()
{
auto c=new Redis();
c.send("flushdb");
auto r=c.send("scan",0);
if(r.isArray)
foreach(k,v; r.values[1].values)
writefln("key: %s",v.value);
}
I can't see it in the docs. Just wondering is this can be an issue.
I have this code
auto redis_vals = this.redisdb.send("LRANGE", "vals", 0, -1);
writeln(redis_vals); // This prints [val_a, val_b]
foreach (val; redis_vals)
writeln(val);
it doesn't compile because of Error: cannot uniquely infer foreach argument types
.
I'm following the example at http://adilbaig.github.io/Tiny-Redis/
for(fruit; fruits)
writeln(fruit);
and that also seems wrongly suggesting to use for
instead of foreach
.
Hi,
I can't build my project because of this error in connection.d about the constant EWOULDBLOCK on windows10.
C:\Users\USER\AppData\Local\dub\packages\tinyredis-2.1.1\tinyredis\source\tinyredis\connection.d(145,30): Error: undefined identifier EWOULDBLOCK
dmd failed with exit code 1.
Is there a way to make it work later?
Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.