sonic-ruby 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/README.md +97 -0
- data/Rakefile +12 -0
- data/bin/console +7 -0
- data/lib/sonic-ruby.rb +1 -0
- data/lib/sonic.rb +7 -0
- data/lib/sonic/channels.rb +4 -0
- data/lib/sonic/channels/base.rb +48 -0
- data/lib/sonic/channels/control.rb +9 -0
- data/lib/sonic/channels/ingest.rb +32 -0
- data/lib/sonic/channels/search.rb +25 -0
- data/lib/sonic/client.rb +24 -0
- data/lib/sonic/connection.rb +42 -0
- data/lib/sonic/errors.rb +4 -0
- data/lib/sonic/version.rb +3 -0
- data/sonic-ruby.gemspec +19 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11f88ebf448e0353b9a260f54f223b9013bf184079f350e6ec9fe23782d3b274
|
4
|
+
data.tar.gz: 4522c74a64130e54a6990355999575f9e557fa51a59ae9b847a162acd182a8c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7fde18e4818984c29d07354706a907e04664eca736fe17bbe5584212532520009a41162cd86a7807cc1f316dd707fc34f44e4294439f231b1c8fef38c134ac7
|
7
|
+
data.tar.gz: 378de35eb10db30414aa16dc0c746b44b748c94ac74790ced01729c3ed4330eba245ff17b1f815644a935401ebcc84eeebc1e6a62e1982a3ba45d972f449b3e2
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# sonic-ruby
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/sonic-ruby)
|
4
|
+
[](https://travis-ci.com/atipugin/sonic-ruby)
|
5
|
+
[](https://codeclimate.com/github/atipugin/sonic-ruby/maintainability)
|
6
|
+
|
7
|
+
A Ruby client for [Sonic search backend](https://github.com/valeriansaliou/sonic).
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add following line to your Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'sonic-ruby'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
```shell
|
20
|
+
$ bundle
|
21
|
+
```
|
22
|
+
|
23
|
+
Or install it system-wide:
|
24
|
+
|
25
|
+
```shell
|
26
|
+
$ gem install sonic-ruby
|
27
|
+
```
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
Start with creating new client:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
client = Sonic::Client.new('localhost', 1491, 'SecretPassword')
|
35
|
+
```
|
36
|
+
|
37
|
+
Now you can use `#channel` method in order to connect to specific channels:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
control = client.channel(:control)
|
41
|
+
ingest = client.channel(:ingest)
|
42
|
+
search = client.channel(:search)
|
43
|
+
```
|
44
|
+
|
45
|
+
[Learn more about Sonic Channels](https://github.com/valeriansaliou/sonic/blob/master/PROTOCOL.md).
|
46
|
+
|
47
|
+
## Indexing
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# Init `ingest` channel
|
51
|
+
ingest = client.channel(:ingest)
|
52
|
+
|
53
|
+
# Add data to index
|
54
|
+
ingest.push('users', 'all', 1, 'Alexander Tipugin')
|
55
|
+
# => true
|
56
|
+
|
57
|
+
# Remove data from index
|
58
|
+
ingest.pop('users', 'all', 1, 'Alexander Tipugin')
|
59
|
+
# => 2
|
60
|
+
|
61
|
+
# Count collection/bucket/object items
|
62
|
+
ingest.count('users', 'all', 1)
|
63
|
+
# => 1
|
64
|
+
|
65
|
+
# Flush entire collection
|
66
|
+
ingest.flushc('users')
|
67
|
+
# => 1
|
68
|
+
|
69
|
+
# Flush entire bucket inside collection
|
70
|
+
ingest.flushb('users', 'all')
|
71
|
+
# => 1
|
72
|
+
|
73
|
+
# Flush specific object inside bucket
|
74
|
+
ingest.flusho('users', 'all', 1)
|
75
|
+
# => 2
|
76
|
+
```
|
77
|
+
|
78
|
+
## Searching
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
# Init `search` channel
|
82
|
+
search = client.channel(:search)
|
83
|
+
|
84
|
+
# Find indexed object by term
|
85
|
+
search.query('users', 'all', 'tipugin')
|
86
|
+
# => 1
|
87
|
+
|
88
|
+
# Auto-complete word
|
89
|
+
search.suggest('users', 'all', 'alex')
|
90
|
+
# => alexander
|
91
|
+
```
|
92
|
+
|
93
|
+
## TODO
|
94
|
+
|
95
|
+
- [ ] Take into account maximum buffer size.
|
96
|
+
- [ ] Consider using connection pool.
|
97
|
+
- [x] Return more meaningful responses from commands (i.e. bool `true` instead of string `OK`, int `1` instead of string `RESULT 1` etc).
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
7
|
+
task.patterns = %w[lib/**/*.rb]
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new(:spec)
|
11
|
+
|
12
|
+
task default: :spec
|
data/bin/console
ADDED
data/lib/sonic-ruby.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'sonic'
|
data/lib/sonic.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Sonic
|
2
|
+
module Channels
|
3
|
+
class Base
|
4
|
+
attr_reader :connection
|
5
|
+
|
6
|
+
def initialize(connection)
|
7
|
+
@connection = connection
|
8
|
+
end
|
9
|
+
|
10
|
+
def ping
|
11
|
+
execute('PING')
|
12
|
+
end
|
13
|
+
|
14
|
+
def help(manual)
|
15
|
+
execute('HELP', manual)
|
16
|
+
end
|
17
|
+
|
18
|
+
def quit
|
19
|
+
execute('QUIT')
|
20
|
+
connection.disconnect
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def execute(*args)
|
26
|
+
connection.write(*args.join(' '))
|
27
|
+
yield if block_given?
|
28
|
+
type_cast_response(connection.read)
|
29
|
+
end
|
30
|
+
|
31
|
+
def quote(value)
|
32
|
+
"\"#{value}\""
|
33
|
+
end
|
34
|
+
|
35
|
+
def type_cast_response(value)
|
36
|
+
if value == 'OK'
|
37
|
+
true
|
38
|
+
elsif value.start_with?('RESULT ')
|
39
|
+
value.split(' ').last.to_i
|
40
|
+
elsif value.start_with?('EVENT ')
|
41
|
+
value.split(' ')[3..-1].join(' ')
|
42
|
+
else
|
43
|
+
value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Sonic
|
2
|
+
module Channels
|
3
|
+
class Ingest < Base
|
4
|
+
def push(collection, bucket, object, text, lang = nil)
|
5
|
+
arr = [collection, bucket, object, quote(text)]
|
6
|
+
arr << "LANG(#{lang})" if lang
|
7
|
+
|
8
|
+
execute('PUSH', *arr)
|
9
|
+
end
|
10
|
+
|
11
|
+
def pop(collection, bucket, object, text)
|
12
|
+
execute('POP', collection, bucket, object, quote(text))
|
13
|
+
end
|
14
|
+
|
15
|
+
def count(collection, bucket = nil, object = nil)
|
16
|
+
execute('COUNT', *[collection, bucket, object].compact)
|
17
|
+
end
|
18
|
+
|
19
|
+
def flushc(collection)
|
20
|
+
execute('FLUSHC', collection)
|
21
|
+
end
|
22
|
+
|
23
|
+
def flushb(collection, bucket)
|
24
|
+
execute('FLUSHB', collection, bucket)
|
25
|
+
end
|
26
|
+
|
27
|
+
def flusho(collection, bucket, object)
|
28
|
+
execute('FLUSHO', collection, bucket, object)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Sonic
|
2
|
+
module Channels
|
3
|
+
class Search < Base
|
4
|
+
def query(collection, bucket, terms, limit = nil, offset = nil, lang = nil) # rubocop:disable Metrics/ParameterLists, Metrics/LineLength
|
5
|
+
arr = [collection, bucket, quote(terms)]
|
6
|
+
arr << "LIMIT(#{limit})" if limit
|
7
|
+
arr << "OFFSET(#{offset})" if offset
|
8
|
+
arr << "LANG(#{lang})" if lang
|
9
|
+
|
10
|
+
execute('QUERY', *arr) do
|
11
|
+
connection.read # ...
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def suggest(collection, bucket, word, limit = nil)
|
16
|
+
arr = [collection, bucket, quote(word)]
|
17
|
+
arr << "LIMIT(#{limit})" if limit
|
18
|
+
|
19
|
+
execute('SUGGEST', *arr) do
|
20
|
+
connection.read # ...
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/sonic/client.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Sonic
|
2
|
+
class Client
|
3
|
+
def initialize(host, port, password = nil)
|
4
|
+
@host = host
|
5
|
+
@port = port
|
6
|
+
@password = password
|
7
|
+
end
|
8
|
+
|
9
|
+
def channel(type)
|
10
|
+
channel_class(type).new(Connection.connect(@host, @port, type, @password))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def channel_class(type)
|
16
|
+
case type.to_sym
|
17
|
+
when :control then Channels::Control
|
18
|
+
when :ingest then Channels::Ingest
|
19
|
+
when :search then Channels::Search
|
20
|
+
else raise ArgumentError, "`#{type}` channel type is not supported"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Sonic
|
2
|
+
class Connection
|
3
|
+
def self.connect(*args)
|
4
|
+
connection = new(*args)
|
5
|
+
connection if connection.connect
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(host, port, channel_type, password = nil)
|
9
|
+
@host = host
|
10
|
+
@port = port
|
11
|
+
@channel_type = channel_type
|
12
|
+
@password = password
|
13
|
+
end
|
14
|
+
|
15
|
+
def connect
|
16
|
+
read # ...
|
17
|
+
write(['START', @channel_type, @password].compact.join(' '))
|
18
|
+
read.start_with?('STARTED ')
|
19
|
+
end
|
20
|
+
|
21
|
+
def disconnect
|
22
|
+
socket.close
|
23
|
+
end
|
24
|
+
|
25
|
+
def read
|
26
|
+
data = socket.gets.chomp
|
27
|
+
raise ServerError, data if data.start_with?('ERR ')
|
28
|
+
|
29
|
+
data
|
30
|
+
end
|
31
|
+
|
32
|
+
def write(data)
|
33
|
+
socket.puts(data)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def socket
|
39
|
+
@socket ||= TCPSocket.open(@host, @port)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/sonic/errors.rb
ADDED
data/sonic-ruby.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require 'sonic/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'sonic-ruby'
|
8
|
+
spec.version = Sonic::VERSION
|
9
|
+
spec.summary = 'Ruby client for Sonic'
|
10
|
+
spec.authors = ['Alexander Tipugin']
|
11
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f|
|
12
|
+
f.match(%r{^(test|spec|features)/})
|
13
|
+
} - ['.rubocop.yml', '.travis.yml', 'Gemfile.lock', '.gitignore', '.rspec']
|
14
|
+
|
15
|
+
spec.add_development_dependency 'pry'
|
16
|
+
spec.add_development_dependency 'rake'
|
17
|
+
spec.add_development_dependency 'rspec'
|
18
|
+
spec.add_development_dependency 'rubocop', '~> 0.66.0'
|
19
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sonic-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Tipugin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -71,7 +71,23 @@ email:
|
|
71
71
|
executables: []
|
72
72
|
extensions: []
|
73
73
|
extra_rdoc_files: []
|
74
|
-
files:
|
74
|
+
files:
|
75
|
+
- Gemfile
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- bin/console
|
79
|
+
- lib/sonic-ruby.rb
|
80
|
+
- lib/sonic.rb
|
81
|
+
- lib/sonic/channels.rb
|
82
|
+
- lib/sonic/channels/base.rb
|
83
|
+
- lib/sonic/channels/control.rb
|
84
|
+
- lib/sonic/channels/ingest.rb
|
85
|
+
- lib/sonic/channels/search.rb
|
86
|
+
- lib/sonic/client.rb
|
87
|
+
- lib/sonic/connection.rb
|
88
|
+
- lib/sonic/errors.rb
|
89
|
+
- lib/sonic/version.rb
|
90
|
+
- sonic-ruby.gemspec
|
75
91
|
homepage:
|
76
92
|
licenses: []
|
77
93
|
metadata: {}
|