async-redis 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/README.md +15 -8
- data/async-redis.gemspec +2 -0
- data/lib/async/redis/client.rb +30 -13
- data/lib/async/redis/context/{nested.rb → generic.rb} +14 -9
- data/lib/async/redis/context/pipeline.rb +104 -0
- data/lib/async/redis/context/subscribe.rb +3 -4
- data/lib/async/redis/context/transaction.rb +51 -0
- data/lib/async/redis/{methods/server.rb → key.rb} +31 -22
- data/lib/async/redis/pool.rb +1 -1
- data/lib/async/redis/{context/multi.rb → protocol/resp2.rb} +6 -18
- data/lib/async/redis/version.rb +1 -1
- metadata +21 -9
- data/lib/async/redis/methods/keys.rb +0 -140
- data/lib/async/redis/methods/lists.rb +0 -118
- data/lib/async/redis/methods/strings.rb +0 -132
- data/lib/async/redis/protocol/resp.rb +0 -143
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c94ef3534e5271a37e5588ac9906f88e421f03db3a3251de8e3f0b8aa414f91a
|
4
|
+
data.tar.gz: d8503520edb25b468aed41db06ce61a38ddb753bf5ec8034f9b129ec60e2a600
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2926a1fccbba8221ed83b9b46e62f82fc2f4a44104e74d1b29973124375305eb3a3da0cdeef03071adb6b967ab7d72f2747829a243e20db9bebb34139973370
|
7
|
+
data.tar.gz: 57636bc3338aad4c34aa411034a67a586e753e0729c3436b290c9d84a59387b8d2c69a4be8f72f48b34a9f2590d2186c9944eba78fecbfa4c31bfc4f56681177
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -35,7 +35,7 @@ require 'async/redis'
|
|
35
35
|
endpoint = Async::Redis.local_endpoint
|
36
36
|
client = Async::Redis::Client.new(endpoint)
|
37
37
|
|
38
|
-
Async
|
38
|
+
Async do
|
39
39
|
pp client.info
|
40
40
|
ensure
|
41
41
|
client.close
|
@@ -45,12 +45,13 @@ end
|
|
45
45
|
### Variables
|
46
46
|
|
47
47
|
```ruby
|
48
|
+
require 'async'
|
48
49
|
require 'async/redis'
|
49
50
|
|
50
51
|
endpoint = Async::Redis.local_endpoint
|
51
52
|
client = Async::Redis::Client.new(endpoint)
|
52
53
|
|
53
|
-
Async
|
54
|
+
Async do
|
54
55
|
client.set('X', 10)
|
55
56
|
pp client.get('X')
|
56
57
|
ensure
|
@@ -61,24 +62,30 @@ end
|
|
61
62
|
### Subscriptions
|
62
63
|
|
63
64
|
```ruby
|
65
|
+
require 'async'
|
64
66
|
require 'async/redis'
|
65
|
-
require 'json'
|
66
67
|
|
67
68
|
endpoint = Async::Redis.local_endpoint
|
68
69
|
client = Async::Redis::Client.new(endpoint)
|
69
70
|
|
70
|
-
Async
|
71
|
+
Async do |task|
|
72
|
+
condition = Async::Condition.new
|
73
|
+
|
74
|
+
publisher = task.async do
|
75
|
+
condition.wait
|
76
|
+
|
77
|
+
client.publish 'status.frontend', 'good'
|
78
|
+
end
|
79
|
+
|
71
80
|
subscriber = task.async do
|
72
81
|
client.subscribe 'status.frontend' do |context|
|
82
|
+
condition.signal # We are waiting for messages.
|
83
|
+
|
73
84
|
type, name, message = context.listen
|
74
85
|
|
75
86
|
pp type, name, message
|
76
87
|
end
|
77
88
|
end
|
78
|
-
|
79
|
-
publisher = task.async do
|
80
|
-
client.publish 'status.frontend', 'good'
|
81
|
-
end
|
82
89
|
ensure
|
83
90
|
client.close
|
84
91
|
end
|
data/async-redis.gemspec
CHANGED
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.add_dependency("async", "~> 1.8")
|
21
21
|
spec.add_dependency("async-io", "~> 1.10")
|
22
22
|
|
23
|
+
spec.add_dependency("protocol-redis", "~> 0.2.0")
|
24
|
+
|
23
25
|
spec.add_development_dependency "async-rspec", "~> 1.1"
|
24
26
|
spec.add_development_dependency "redis"
|
25
27
|
spec.add_development_dependency "benchmark-ips"
|
data/lib/async/redis/client.rb
CHANGED
@@ -18,31 +18,31 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
require_relative 'protocol/resp'
|
22
21
|
require_relative 'pool'
|
23
|
-
require_relative 'context/
|
22
|
+
require_relative 'context/pipeline'
|
23
|
+
require_relative 'context/transaction'
|
24
24
|
require_relative 'context/subscribe'
|
25
25
|
|
26
|
-
require_relative '
|
27
|
-
require_relative 'methods/keys'
|
28
|
-
require_relative 'methods/lists'
|
29
|
-
require_relative 'methods/server'
|
26
|
+
require_relative 'protocol/resp2'
|
30
27
|
|
31
28
|
require 'async/io'
|
29
|
+
require 'async/io/stream'
|
30
|
+
|
31
|
+
require 'protocol/redis/methods'
|
32
32
|
|
33
33
|
module Async
|
34
34
|
module Redis
|
35
|
+
# Legacy.
|
36
|
+
ServerError = ::Protocol::Redis::ServerError
|
37
|
+
|
35
38
|
def self.local_endpoint
|
36
39
|
Async::IO::Endpoint.tcp('localhost', 6379)
|
37
40
|
end
|
38
41
|
|
39
42
|
class Client
|
40
|
-
include Methods
|
41
|
-
include Methods::Keys
|
42
|
-
include Methods::Lists
|
43
|
-
include Methods::Server
|
43
|
+
include ::Protocol::Redis::Methods
|
44
44
|
|
45
|
-
def initialize(endpoint = Redis.local_endpoint, protocol = Protocol::
|
45
|
+
def initialize(endpoint = Redis.local_endpoint, protocol = Protocol::RESP2, **options)
|
46
46
|
@endpoint = endpoint
|
47
47
|
@protocol = protocol
|
48
48
|
|
@@ -100,8 +100,8 @@ module Async
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
def
|
104
|
-
context = Context::
|
103
|
+
def transaction(&block)
|
104
|
+
context = Context::Transaction.new(@pool)
|
105
105
|
|
106
106
|
return context unless block_given?
|
107
107
|
|
@@ -111,11 +111,28 @@ module Async
|
|
111
111
|
context.close
|
112
112
|
end
|
113
113
|
end
|
114
|
+
|
115
|
+
def pipeline(&block)
|
116
|
+
context = Context::Pipeline.new(@pool)
|
117
|
+
|
118
|
+
return context unless block_given?
|
119
|
+
|
120
|
+
begin
|
121
|
+
yield context
|
122
|
+
ensure
|
123
|
+
context.close
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Deprecated.
|
128
|
+
alias nested pipeline
|
114
129
|
|
115
130
|
def call(*arguments)
|
116
131
|
@pool.acquire do |connection|
|
117
132
|
connection.write_request(arguments)
|
118
133
|
|
134
|
+
connection.flush
|
135
|
+
|
119
136
|
return connection.read_response
|
120
137
|
end
|
121
138
|
end
|
@@ -19,18 +19,12 @@
|
|
19
19
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
20
|
# THE SOFTWARE.
|
21
21
|
|
22
|
-
|
23
|
-
require_relative '../methods/keys'
|
24
|
-
require_relative '../methods/lists'
|
22
|
+
require 'protocol/redis/methods'
|
25
23
|
|
26
24
|
module Async
|
27
25
|
module Redis
|
28
26
|
module Context
|
29
|
-
class
|
30
|
-
include Methods::Strings
|
31
|
-
include Methods::Keys
|
32
|
-
include Methods::Lists
|
33
|
-
|
27
|
+
class Generic
|
34
28
|
def initialize(pool, *args)
|
35
29
|
@pool = pool
|
36
30
|
@connection = pool.acquire
|
@@ -43,10 +37,21 @@ module Async
|
|
43
37
|
end
|
44
38
|
end
|
45
39
|
|
46
|
-
def
|
40
|
+
def write_request(command, *args)
|
47
41
|
@connection.write_request([command, *args])
|
42
|
+
end
|
43
|
+
|
44
|
+
def read_response
|
45
|
+
@connection.flush
|
46
|
+
|
48
47
|
return @connection.read_response
|
49
48
|
end
|
49
|
+
|
50
|
+
def call(command, *args)
|
51
|
+
write_request(command, *args)
|
52
|
+
|
53
|
+
return read_response
|
54
|
+
end
|
50
55
|
end
|
51
56
|
end
|
52
57
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
# Copyright, 2019, by Huba Nagy.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
|
22
|
+
require_relative 'generic'
|
23
|
+
|
24
|
+
module Async
|
25
|
+
module Redis
|
26
|
+
module Context
|
27
|
+
# Send multiple commands without waiting for the response, instead of sending them one by one.
|
28
|
+
class Pipeline < Generic
|
29
|
+
include ::Protocol::Redis::Methods
|
30
|
+
|
31
|
+
class Sync
|
32
|
+
include ::Protocol::Redis::Methods
|
33
|
+
|
34
|
+
def initialize(pipeline)
|
35
|
+
@pipeline = pipeline
|
36
|
+
end
|
37
|
+
|
38
|
+
# This method just accumulates the commands and their params.
|
39
|
+
def call(command, *args)
|
40
|
+
@pipeline.call(command, *args)
|
41
|
+
|
42
|
+
@pipeline.flush(1)
|
43
|
+
|
44
|
+
return @pipeline.read_response
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(pool)
|
49
|
+
super(pool)
|
50
|
+
|
51
|
+
@count = 0
|
52
|
+
@sync = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# Flush responses.
|
56
|
+
# @param count [Integer] leave this many responses.
|
57
|
+
def flush(count = 0)
|
58
|
+
while @count > count
|
59
|
+
read_response
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def sync
|
64
|
+
@sync ||= Sync.new(self)
|
65
|
+
end
|
66
|
+
|
67
|
+
# This method just accumulates the commands and their params.
|
68
|
+
def write_request(*)
|
69
|
+
super
|
70
|
+
|
71
|
+
@count += 1
|
72
|
+
end
|
73
|
+
|
74
|
+
# This method just accumulates the commands and their params.
|
75
|
+
def call(command, *args)
|
76
|
+
write_request(command, *args)
|
77
|
+
|
78
|
+
return nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def read_response
|
82
|
+
if @count > 0
|
83
|
+
@count -= 1
|
84
|
+
super
|
85
|
+
else
|
86
|
+
raise RuntimeError, "No more responses available!"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def collect
|
91
|
+
yield
|
92
|
+
|
93
|
+
@count.times.map{read_response}
|
94
|
+
end
|
95
|
+
|
96
|
+
def close
|
97
|
+
flush
|
98
|
+
|
99
|
+
super
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -19,14 +19,12 @@
|
|
19
19
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
20
|
# THE SOFTWARE.
|
21
21
|
|
22
|
-
require_relative '
|
23
|
-
|
24
|
-
require 'set'
|
22
|
+
require_relative 'generic'
|
25
23
|
|
26
24
|
module Async
|
27
25
|
module Redis
|
28
26
|
module Context
|
29
|
-
class Subscribe <
|
27
|
+
class Subscribe < Generic
|
30
28
|
def initialize(pool, channels)
|
31
29
|
super(pool)
|
32
30
|
|
@@ -43,6 +41,7 @@ module Async
|
|
43
41
|
|
44
42
|
def subscribe(channels)
|
45
43
|
@connection.write_request ['SUBSCRIBE', *channels]
|
44
|
+
@connection.flush
|
46
45
|
|
47
46
|
response = nil
|
48
47
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
# Copyright, 2018, by Huba Nagy.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
|
22
|
+
require_relative 'pipeline'
|
23
|
+
|
24
|
+
module Async
|
25
|
+
module Redis
|
26
|
+
module Context
|
27
|
+
class Transaction < Pipeline
|
28
|
+
def initialize(pool, *args)
|
29
|
+
super(pool)
|
30
|
+
end
|
31
|
+
|
32
|
+
def multi
|
33
|
+
call('MULTI')
|
34
|
+
end
|
35
|
+
|
36
|
+
def watch(*keys)
|
37
|
+
sync.call('WATCH', *keys)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Execute all queued commands, provided that no watched keys have been modified. It's important to note that even when a command fails, all the other commands in the queue are processed – Redis will not stop the processing of commands.
|
41
|
+
def execute
|
42
|
+
sync.call('EXEC')
|
43
|
+
end
|
44
|
+
|
45
|
+
def discard
|
46
|
+
sync.call('DISCARD')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
# Copyright, 2018, by Huba Nagy.
|
3
2
|
#
|
4
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
4
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -21,27 +20,37 @@
|
|
21
20
|
|
22
21
|
module Async
|
23
22
|
module Redis
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
23
|
+
class Key
|
24
|
+
def self.[] path
|
25
|
+
self.new(path)
|
26
|
+
end
|
27
|
+
|
28
|
+
include Comparable
|
29
|
+
|
30
|
+
def initialize(path)
|
31
|
+
@path = path
|
32
|
+
end
|
33
|
+
|
34
|
+
def size
|
35
|
+
@path.bytesize
|
36
|
+
end
|
37
|
+
|
38
|
+
attr :path
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
@path
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_str
|
45
|
+
@path
|
46
|
+
end
|
47
|
+
|
48
|
+
def [] key
|
49
|
+
self.class.new("#{@path}:#{key}")
|
50
|
+
end
|
51
|
+
|
52
|
+
def <=> other
|
53
|
+
@path <=> other.to_str
|
45
54
|
end
|
46
55
|
end
|
47
56
|
end
|
data/lib/async/redis/pool.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
# Copyright, 2018, by Huba Nagy.
|
3
2
|
#
|
4
3
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
4
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -19,27 +18,16 @@
|
|
19
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
19
|
# THE SOFTWARE.
|
21
20
|
|
22
|
-
|
21
|
+
require 'protocol/redis'
|
23
22
|
|
24
23
|
module Async
|
25
24
|
module Redis
|
26
|
-
module
|
27
|
-
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
@connection.write_request(['MULTI'])
|
32
|
-
@connection.read_response
|
33
|
-
end
|
34
|
-
|
35
|
-
def execute
|
36
|
-
return call 'EXEC'
|
37
|
-
end
|
38
|
-
|
39
|
-
def discard
|
40
|
-
return call 'DISCARD'
|
25
|
+
module Protocol
|
26
|
+
module RESP2
|
27
|
+
def self.client(stream)
|
28
|
+
::Protocol::Redis::Connection.new(stream)
|
41
29
|
end
|
42
30
|
end
|
43
31
|
end
|
44
|
-
end
|
32
|
+
end
|
45
33
|
end
|
data/lib/async/redis/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: async
|
@@ -39,6 +39,20 @@ dependencies:
|
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '1.10'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: protocol-redis
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 0.2.0
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 0.2.0
|
42
56
|
- !ruby/object:Gem::Dependency
|
43
57
|
name: async-rspec
|
44
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -169,15 +183,13 @@ files:
|
|
169
183
|
- async-redis.gemspec
|
170
184
|
- lib/async/redis.rb
|
171
185
|
- lib/async/redis/client.rb
|
172
|
-
- lib/async/redis/context/
|
173
|
-
- lib/async/redis/context/
|
186
|
+
- lib/async/redis/context/generic.rb
|
187
|
+
- lib/async/redis/context/pipeline.rb
|
174
188
|
- lib/async/redis/context/subscribe.rb
|
175
|
-
- lib/async/redis/
|
176
|
-
- lib/async/redis/
|
177
|
-
- lib/async/redis/methods/server.rb
|
178
|
-
- lib/async/redis/methods/strings.rb
|
189
|
+
- lib/async/redis/context/transaction.rb
|
190
|
+
- lib/async/redis/key.rb
|
179
191
|
- lib/async/redis/pool.rb
|
180
|
-
- lib/async/redis/protocol/
|
192
|
+
- lib/async/redis/protocol/resp2.rb
|
181
193
|
- lib/async/redis/version.rb
|
182
194
|
homepage: https://github.com/socketry/async-redis
|
183
195
|
licenses: []
|
@@ -1,140 +0,0 @@
|
|
1
|
-
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
# Copyright, 2018, by Huba Nagy.
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
|
22
|
-
require 'date'
|
23
|
-
|
24
|
-
module Async
|
25
|
-
module Redis
|
26
|
-
module Methods
|
27
|
-
module Keys
|
28
|
-
def del(key, *keys)
|
29
|
-
return call('DEL', key, *keys)
|
30
|
-
end
|
31
|
-
|
32
|
-
def dump(key)
|
33
|
-
return call('DUMP', key)
|
34
|
-
end
|
35
|
-
|
36
|
-
def exists(key, *keys)
|
37
|
-
return call('EXISTS', key, *keys)
|
38
|
-
end
|
39
|
-
|
40
|
-
def expire(key, seconds)
|
41
|
-
return call('EXPIRE', key, seconds)
|
42
|
-
end
|
43
|
-
|
44
|
-
def expireat(key, time)
|
45
|
-
case time
|
46
|
-
when DateTime, Time, Date
|
47
|
-
timestamp = time.strftime('%s').to_i
|
48
|
-
else
|
49
|
-
timestamp = time
|
50
|
-
end
|
51
|
-
|
52
|
-
return call('EXPIREAT', key, timestamp)
|
53
|
-
end
|
54
|
-
|
55
|
-
def keys(pattern)
|
56
|
-
return call('KEYS', pattern)
|
57
|
-
end
|
58
|
-
|
59
|
-
def migrate
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
def move(key, db)
|
64
|
-
return call('MOVE', key, db)
|
65
|
-
end
|
66
|
-
|
67
|
-
def object
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
def persist(key)
|
72
|
-
return call('PERSIST', key)
|
73
|
-
end
|
74
|
-
|
75
|
-
def pexpire(key, milliseconds)
|
76
|
-
return call('PEXPIRE', milliseconds)
|
77
|
-
end
|
78
|
-
|
79
|
-
def pexpireat(key, time)
|
80
|
-
case time.class
|
81
|
-
when DateTime, Time, Date
|
82
|
-
timestamp = time.strftime('%Q').to_i
|
83
|
-
else
|
84
|
-
timestamp = time
|
85
|
-
end
|
86
|
-
|
87
|
-
return call('PEXPIREAT', key, timestamp)
|
88
|
-
end
|
89
|
-
|
90
|
-
def pttl(key)
|
91
|
-
return call('PTTL', key)
|
92
|
-
end
|
93
|
-
|
94
|
-
def randomkey
|
95
|
-
return call('RANDOMKEY')
|
96
|
-
end
|
97
|
-
|
98
|
-
def rename(key, new_key)
|
99
|
-
return call('RENAME', key, new_key)
|
100
|
-
end
|
101
|
-
|
102
|
-
def renamenx(key, new_key)
|
103
|
-
return call('RENAMENX', key, new_key)
|
104
|
-
end
|
105
|
-
|
106
|
-
def restore(key, serialized_value, ttl=0)
|
107
|
-
return call('RESTORE', key, ttl, serialized_value)
|
108
|
-
end
|
109
|
-
|
110
|
-
def sort
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
def touch(key, *keys)
|
115
|
-
return call('TOUCH', key, *keys)
|
116
|
-
end
|
117
|
-
|
118
|
-
def ttl(key)
|
119
|
-
return call('TTL', key)
|
120
|
-
end
|
121
|
-
|
122
|
-
def type(key)
|
123
|
-
return call('TYPE', key)
|
124
|
-
end
|
125
|
-
|
126
|
-
def unlink(key)
|
127
|
-
return call('UNLINK', key)
|
128
|
-
end
|
129
|
-
|
130
|
-
def wait(newreplicas, timeout)
|
131
|
-
|
132
|
-
end
|
133
|
-
|
134
|
-
def scan
|
135
|
-
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
@@ -1,118 +0,0 @@
|
|
1
|
-
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
# Copyright, 2018, by Huba Nagy.
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
|
22
|
-
module Async
|
23
|
-
module Redis
|
24
|
-
module Methods
|
25
|
-
module Lists
|
26
|
-
def blpop(*keys, timeout: 0)
|
27
|
-
return call('BLPOP', *keys, timeout)
|
28
|
-
end
|
29
|
-
|
30
|
-
def brpop(*keys, timeout: 0)
|
31
|
-
return call('BRPOP', *keys, timeout)
|
32
|
-
end
|
33
|
-
|
34
|
-
def brpoplpush(source, destination, timeout)
|
35
|
-
return call('BRPOPLPUSH', source, destination, timeout)
|
36
|
-
end
|
37
|
-
|
38
|
-
def lindex(key, index)
|
39
|
-
return call('LINDEX', key, index)
|
40
|
-
end
|
41
|
-
|
42
|
-
def linsert(key, position=:before, index, value)
|
43
|
-
if position == :before
|
44
|
-
offset = 'BEFORE'
|
45
|
-
else
|
46
|
-
offset = 'AFTER'
|
47
|
-
end
|
48
|
-
|
49
|
-
return call('LINSERT', key, offset, index, value)
|
50
|
-
end
|
51
|
-
|
52
|
-
def llen(key)
|
53
|
-
return call('LLEN', key)
|
54
|
-
end
|
55
|
-
|
56
|
-
def lpop(key)
|
57
|
-
return call('LPOP', key)
|
58
|
-
end
|
59
|
-
|
60
|
-
def lpush(key, value, *values)
|
61
|
-
case value
|
62
|
-
when Array
|
63
|
-
values = value
|
64
|
-
else
|
65
|
-
values = [value] + values
|
66
|
-
end
|
67
|
-
|
68
|
-
return call('LPUSH', key, *values)
|
69
|
-
end
|
70
|
-
|
71
|
-
def lpushx(key, value)
|
72
|
-
return call('LPUSHX', key, value)
|
73
|
-
end
|
74
|
-
|
75
|
-
def lrange(key, start, stop)
|
76
|
-
return call('LRANGE', key, start, stop)
|
77
|
-
end
|
78
|
-
|
79
|
-
def lrem(key, count, value)
|
80
|
-
return call('LREM', key, count)
|
81
|
-
end
|
82
|
-
|
83
|
-
def lset(key, index, values)
|
84
|
-
return call('LSET', key, index, values)
|
85
|
-
end
|
86
|
-
|
87
|
-
def ltrim(key, start, stop)
|
88
|
-
return call('LTRIM', key, start, stop)
|
89
|
-
end
|
90
|
-
|
91
|
-
def rpop(key)
|
92
|
-
return call('RPOP', key)
|
93
|
-
end
|
94
|
-
|
95
|
-
def rpoplpush(source, destination=nil)
|
96
|
-
destination = source if destination.nil?
|
97
|
-
|
98
|
-
return call('RPOPLPUSH', source, destination)
|
99
|
-
end
|
100
|
-
|
101
|
-
def rpush(key, value, *values)
|
102
|
-
case value
|
103
|
-
when Array
|
104
|
-
values = value
|
105
|
-
else
|
106
|
-
values = [value] + values
|
107
|
-
end
|
108
|
-
|
109
|
-
return call('RPUSH', key, *values)
|
110
|
-
end
|
111
|
-
|
112
|
-
def rpushx(key, value)
|
113
|
-
return call('RPUSHX', key, value)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
@@ -1,132 +0,0 @@
|
|
1
|
-
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
# Copyright, 2018, by Huba Nagy.
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
|
22
|
-
module Async
|
23
|
-
module Redis
|
24
|
-
module Methods
|
25
|
-
module Strings
|
26
|
-
def append(key, value)
|
27
|
-
return call('APPEND', key, value)
|
28
|
-
end
|
29
|
-
|
30
|
-
def bitcount(key, *range)
|
31
|
-
return call('BITCOUNT', key, *range)
|
32
|
-
end
|
33
|
-
|
34
|
-
def decr(key)
|
35
|
-
return call('DECR', key)
|
36
|
-
end
|
37
|
-
|
38
|
-
def decrby(key, decrement)
|
39
|
-
return call('DECRBY', key, decrement)
|
40
|
-
end
|
41
|
-
|
42
|
-
def get(key)
|
43
|
-
return call('GET', key)
|
44
|
-
end
|
45
|
-
|
46
|
-
def getbit(key, offset)
|
47
|
-
return call('GETBIT', key, offset)
|
48
|
-
end
|
49
|
-
|
50
|
-
def getrange(key, start_index, end_index)
|
51
|
-
return call('GETRANGE', key, start_index, end_index)
|
52
|
-
end
|
53
|
-
|
54
|
-
def getset(key, value)
|
55
|
-
return call('GETSET', key, value)
|
56
|
-
end
|
57
|
-
|
58
|
-
def incr(key)
|
59
|
-
return call('INCR', key)
|
60
|
-
end
|
61
|
-
|
62
|
-
def incrby(key, increment)
|
63
|
-
return call('INCRBY', key, increment)
|
64
|
-
end
|
65
|
-
|
66
|
-
def incrbyfloat(key, increment)
|
67
|
-
return call('INCRBYFLOAT', key, increment)
|
68
|
-
end
|
69
|
-
|
70
|
-
def mget(key, *keys)
|
71
|
-
return call('MGET', key, *keys)
|
72
|
-
end
|
73
|
-
|
74
|
-
def mset(pairs)
|
75
|
-
flattened_pairs = pairs.keys.zip(pairs.values).flatten
|
76
|
-
return call('MSET', *flattened_pairs)
|
77
|
-
end
|
78
|
-
|
79
|
-
def msetnx(pairs)
|
80
|
-
flattened_pairs = pairs.keys.zip(pairs.values).flatten
|
81
|
-
return call('MSETNX', *flattened_pairs)
|
82
|
-
end
|
83
|
-
|
84
|
-
def psetex(key, milliseconds, value)
|
85
|
-
return set key, value, milliseconds: milliseconds
|
86
|
-
end
|
87
|
-
|
88
|
-
def set(key, value, **options)
|
89
|
-
arguments = []
|
90
|
-
|
91
|
-
if options.has_key? :seconds
|
92
|
-
arguments << 'EX'
|
93
|
-
arguments << options[:seconds]
|
94
|
-
end
|
95
|
-
|
96
|
-
if options.has_key? :milliseconds
|
97
|
-
arguments << 'PX'
|
98
|
-
arguments << options[:milliseconds]
|
99
|
-
end
|
100
|
-
|
101
|
-
if options[:condition] == :nx
|
102
|
-
arguments << 'NX'
|
103
|
-
elsif options[:condition] == :xx
|
104
|
-
arguments << 'XX'
|
105
|
-
end
|
106
|
-
|
107
|
-
return call('SET', key, value, *arguments)
|
108
|
-
end
|
109
|
-
|
110
|
-
def setbit(key, offset, value)
|
111
|
-
return call('SETBIT', key, offset, value)
|
112
|
-
end
|
113
|
-
|
114
|
-
def setex(key, seconds, value)
|
115
|
-
return set key, value, seconds: seconds
|
116
|
-
end
|
117
|
-
|
118
|
-
def setnx(key, value)
|
119
|
-
return set key, value, condition: :nx
|
120
|
-
end
|
121
|
-
|
122
|
-
def setrange(key, offset, value)
|
123
|
-
return call('SETRANGE', key, offset, value)
|
124
|
-
end
|
125
|
-
|
126
|
-
def strlen(key)
|
127
|
-
return call('STRLEN', key)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
@@ -1,143 +0,0 @@
|
|
1
|
-
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'async/io/protocol/line'
|
22
|
-
|
23
|
-
module Async
|
24
|
-
module Redis
|
25
|
-
class ServerError < StandardError
|
26
|
-
end
|
27
|
-
|
28
|
-
module Protocol
|
29
|
-
CRLF = "\r\n".freeze
|
30
|
-
|
31
|
-
class RESP < Async::IO::Protocol::Line
|
32
|
-
class << self
|
33
|
-
alias client new
|
34
|
-
end
|
35
|
-
|
36
|
-
def initialize(stream)
|
37
|
-
super(stream, CRLF)
|
38
|
-
end
|
39
|
-
|
40
|
-
def closed?
|
41
|
-
@stream.closed?
|
42
|
-
end
|
43
|
-
|
44
|
-
# The redis server doesn't want actual objects (e.g. integers) but only bulk strings. So, we inline it for performance.
|
45
|
-
def write_request(arguments)
|
46
|
-
write_lines("*#{arguments.count}")
|
47
|
-
|
48
|
-
arguments.each do |argument|
|
49
|
-
string = argument.to_s
|
50
|
-
|
51
|
-
write_lines("$#{string.bytesize}", string)
|
52
|
-
end
|
53
|
-
|
54
|
-
@stream.flush
|
55
|
-
end
|
56
|
-
|
57
|
-
def write_object(object)
|
58
|
-
case object
|
59
|
-
when String
|
60
|
-
write_lines("$#{object.bytesize}", object)
|
61
|
-
when Array
|
62
|
-
write_array(object)
|
63
|
-
when Integer
|
64
|
-
write_lines(":#{object}")
|
65
|
-
else
|
66
|
-
write_object(object.to_redis)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def read_data(length)
|
71
|
-
buffer = @stream.read(length) or @stream.eof!
|
72
|
-
|
73
|
-
# Eat trailing whitespace because length does not include the CRLF:
|
74
|
-
@stream.read(2) or @stream.eof!
|
75
|
-
|
76
|
-
return buffer
|
77
|
-
end
|
78
|
-
|
79
|
-
def read_object
|
80
|
-
line = read_line
|
81
|
-
token = line.slice!(0, 1)
|
82
|
-
|
83
|
-
case token
|
84
|
-
when '$'
|
85
|
-
length = line.to_i
|
86
|
-
|
87
|
-
if length == -1
|
88
|
-
return nil
|
89
|
-
else
|
90
|
-
return read_data(length)
|
91
|
-
end
|
92
|
-
when '*'
|
93
|
-
count = line.to_i
|
94
|
-
|
95
|
-
# Null array (https://redis.io/topics/protocol#resp-arrays):
|
96
|
-
return nil if count == -1
|
97
|
-
|
98
|
-
array = Array.new(count) {read_object}
|
99
|
-
|
100
|
-
return array
|
101
|
-
when ':'
|
102
|
-
return line.to_i
|
103
|
-
|
104
|
-
when '-'
|
105
|
-
raise ServerError.new(line)
|
106
|
-
|
107
|
-
when '+'
|
108
|
-
return line
|
109
|
-
|
110
|
-
else
|
111
|
-
@stream.flush
|
112
|
-
|
113
|
-
raise NotImplementedError, "Implementation for token #{token} missing"
|
114
|
-
end
|
115
|
-
|
116
|
-
# TODO: If an exception (e.g. Async::TimeoutError) propagates out of this function, perhaps @stream should be closed? Otherwise it might be in a weird state.
|
117
|
-
end
|
118
|
-
|
119
|
-
alias read_response read_object
|
120
|
-
|
121
|
-
private
|
122
|
-
|
123
|
-
# Override Async::IO::Protocol::Line#write_line
|
124
|
-
# The original method performs a flush. This one does not and moves the
|
125
|
-
# responsibility of flushing to the caller of the method.
|
126
|
-
# In the case of Redis, we do not want to perform a flush in every line,
|
127
|
-
# because each Redis command contains several lines. Flushing once per
|
128
|
-
# command is more efficient because it avoids unnecessary writes to the
|
129
|
-
# socket.
|
130
|
-
def write_lines(*args)
|
131
|
-
if args.empty?
|
132
|
-
@stream.write(@eol)
|
133
|
-
else
|
134
|
-
args.each do |arg|
|
135
|
-
@stream.write(arg)
|
136
|
-
@stream.write(@eol)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|