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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4cf3ca6e7a1400dd30aa057b8688fe5c36dfd259ed6a62e74452e72706026434
4
- data.tar.gz: 377bb98eb47f7e21bde259224c2cbc61fa9e960804d6037c4b7e8556d1892bb1
3
+ metadata.gz: c94ef3534e5271a37e5588ac9906f88e421f03db3a3251de8e3f0b8aa414f91a
4
+ data.tar.gz: d8503520edb25b468aed41db06ce61a38ddb753bf5ec8034f9b129ec60e2a600
5
5
  SHA512:
6
- metadata.gz: 1ab1e184597d78757881a5a692763e00d0be075480a98600bb2ec87b87484bd17b3840692cd07bdc7d024ab3860b5ed410ae4c618df26a8bb0b8743425a68dff
7
- data.tar.gz: b4ce7600597fea36ba4f9e5b6d68db84fe286a259f4946e001a7ebade416989694a5c760eac08285f446b49956b8569402adfa0f7ed9a61189feec61d1e5df30
6
+ metadata.gz: b2926a1fccbba8221ed83b9b46e62f82fc2f4a44104e74d1b29973124375305eb3a3da0cdeef03071adb6b967ab7d72f2747829a243e20db9bebb34139973370
7
+ data.tar.gz: 57636bc3338aad4c34aa411034a67a586e753e0729c3436b290c9d84a59387b8d2c69a4be8f72f48b34a9f2590d2186c9944eba78fecbfa4c31bfc4f56681177
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+ .covered.db
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in async-io.gemspec
4
4
  gemspec
5
5
 
6
+ # gem "protocol-redis", path: "../protocol-redis"
7
+
6
8
  group :development do
7
9
  gem 'pry'
8
10
  end
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.run do
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.run do
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.run do |task|
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
@@ -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"
@@ -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/multi'
22
+ require_relative 'context/pipeline'
23
+ require_relative 'context/transaction'
24
24
  require_relative 'context/subscribe'
25
25
 
26
- require_relative 'methods/strings'
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::Strings
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::RESP, **options)
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 nested(&block)
104
- context = Context::Nested.new(@pool)
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
- require_relative '../methods/strings'
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 Nested
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 call(command, *args)
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 'nested'
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 < Nested
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
- module Methods
25
- module Server
26
- # Get info from server.
27
- # @return [Hash] the server metadata.
28
- def info
29
- metadata = {}
30
-
31
- call('INFO').each_line(Protocol::CRLF) do |line|
32
- key, value = line.split(':')
33
-
34
- if value
35
- metadata[key.to_sym] = value.chomp!
36
- end
37
- end
38
-
39
- return metadata
40
- end
41
-
42
- def flushdb!
43
- call 'FLUSHDB'
44
- end
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
@@ -72,7 +72,7 @@ module Async
72
72
  end
73
73
 
74
74
  def to_s
75
- "\#<#{self.class} resources=#{resources.count} limit=#{@limit}>"
75
+ "\#<#{self.class} resources=#{resources.size} limit=#{@limit}>"
76
76
  end
77
77
 
78
78
  protected
@@ -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
- require_relative 'nested'
21
+ require 'protocol/redis'
23
22
 
24
23
  module Async
25
24
  module Redis
26
- module Context
27
- class Multi < Nested
28
- def initialize(pool, *args)
29
- super(pool)
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
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module Redis
23
- VERSION = "0.3.4"
23
+ VERSION = "0.4.0"
24
24
  end
25
25
  end
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.3.4
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-05-05 00:00:00.000000000 Z
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/multi.rb
173
- - lib/async/redis/context/nested.rb
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/methods/keys.rb
176
- - lib/async/redis/methods/lists.rb
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/resp.rb
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