From 51d68e741385c4d535bfa67f3bb7e06edd0717b0 Mon Sep 17 00:00:00 2001 From: Ben D'Angelo Date: Sat, 18 Nov 2023 19:24:19 -0500 Subject: [PATCH 1/7] Normalize text input into search / ingest channels --- lib/sonic/channels/ingest.rb | 4 ++-- lib/sonic/channels/search.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/sonic/channels/ingest.rb b/lib/sonic/channels/ingest.rb index eed89fa..c436be9 100644 --- a/lib/sonic/channels/ingest.rb +++ b/lib/sonic/channels/ingest.rb @@ -2,14 +2,14 @@ module Sonic module Channels class Ingest < Base def push(collection, bucket, object, text, lang = nil) - arr = [collection, bucket, object, quote(text)] + arr = [collection, bucket, object, normalize(text)] arr << "LANG(#{lang})" if lang execute('PUSH', *arr) end def pop(collection, bucket, object, text) - execute('POP', collection, bucket, object, quote(text)) + execute('POP', collection, bucket, object, normalize(text)) end def count(collection, bucket = nil, object = nil) diff --git a/lib/sonic/channels/search.rb b/lib/sonic/channels/search.rb index 79a1acb..f78cb20 100644 --- a/lib/sonic/channels/search.rb +++ b/lib/sonic/channels/search.rb @@ -2,7 +2,7 @@ module Sonic module Channels class Search < Base def query(collection, bucket, terms, limit = nil, offset = nil, lang = nil) # rubocop:disable Metrics/ParameterLists, Metrics/LineLength - arr = [collection, bucket, quote(terms)] + arr = [collection, bucket, normalize(terms)] arr << "LIMIT(#{limit})" if limit arr << "OFFSET(#{offset})" if offset arr << "LANG(#{lang})" if lang @@ -13,7 +13,7 @@ def query(collection, bucket, terms, limit = nil, offset = nil, lang = nil) # ru end def suggest(collection, bucket, word, limit = nil) - arr = [collection, bucket, quote(word)] + arr = [collection, bucket, normalize(word)] arr << "LIMIT(#{limit})" if limit execute('SUGGEST', *arr) do From 2f97e0b3ab6ca636bb1bee51b04eaa28a2787027 Mon Sep 17 00:00:00 2001 From: Ben D'Angelo Date: Sat, 18 Nov 2023 19:14:40 -0500 Subject: [PATCH 2/7] Reconnect if client closes connection --- lib/sonic/connection.rb | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/sonic/connection.rb b/lib/sonic/connection.rb index b137515..c24f89e 100644 --- a/lib/sonic/connection.rb +++ b/lib/sonic/connection.rb @@ -13,7 +13,7 @@ def initialize(host, port, channel_type, password = nil) end def connect - read # ... + socket.gets # ... write(['START', @channel_type, @password].compact.join(' ')) read.start_with?('STARTED ') end @@ -23,20 +23,36 @@ def disconnect end def read - data = socket.gets.chomp + data = socket.gets&.chomp + + raise ServerError, data if data.nil? + raise ServerError, data if data.start_with?('ENDED ') raise ServerError, data if data.start_with?('ERR ') data end def write(data) - socket.puts(data) + begin + socket.puts(data) + rescue Errno::EPIPE + reconnect + socket.puts(data) + end end + private def socket @socket ||= TCPSocket.open(@host, @port) end + + def reconnect + @socket.close if @socket + @socket = TCPSocket.open(@host, @port) + + connect + end end end From f192223adf25586d40d1fd1406ee9ea27d6b0a54 Mon Sep 17 00:00:00 2001 From: Ben D'Angelo Date: Sun, 26 Nov 2023 13:58:05 -0500 Subject: [PATCH 3/7] Added close to client, output last command in error --- lib/sonic/channels/base.rb | 17 +++++++++++++++-- lib/sonic/connection.rb | 39 ++++++++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/lib/sonic/channels/base.rb b/lib/sonic/channels/base.rb index e0f2d9d..935bf72 100644 --- a/lib/sonic/channels/base.rb +++ b/lib/sonic/channels/base.rb @@ -16,10 +16,23 @@ def help(manual) end def quit - execute('QUIT') + if connection.connected? + execute('QUIT') + connection.disconnect + return true + end + + return false + end + + def close connection.disconnect end + def connected? + connection.connected? + end + private def execute(*args) @@ -33,7 +46,7 @@ def normalize(value) end def sanitize(value) - value.gsub('"', '\\"').gsub(/[\r\n]+/, ' ') + value.gsub('"', '\\"').gsub(/[\r\n]+/, '\\n').gsub(/\\/, '\\\\') end def quote(value) diff --git a/lib/sonic/connection.rb b/lib/sonic/connection.rb index c24f89e..a0b3fbc 100644 --- a/lib/sonic/connection.rb +++ b/lib/sonic/connection.rb @@ -19,25 +19,37 @@ def connect end def disconnect - socket.close + socket&.close + socket = nil + end + + def connected? + !socket.nil? end def read data = socket.gets&.chomp - raise ServerError, data if data.nil? - raise ServerError, data if data.start_with?('ENDED ') - raise ServerError, data if data.start_with?('ERR ') + if data.nil? + # connection was dropped from timeout + disconnect + raise ServerError, "Connection expired. Please reconnect." + end + + raise ServerError, "#{data} (#{@last_write})" if data.start_with?('ENDED ') + raise ServerError, "#{data} (#{@last_write})" if data.start_with?('ERR ') data end def write(data) + @last_write = data + begin socket.puts(data) - rescue Errno::EPIPE - reconnect - socket.puts(data) + rescue Errno::EPIPE => error + disconnect + raise ServerError, "Connection expired. Please reconnect.", error.backtrace end end @@ -45,14 +57,13 @@ def write(data) private def socket - @socket ||= TCPSocket.open(@host, @port) + @socket ||= begin + socket = TCPSocket.open(@host, @port) + # disables Nagle's Algorithm, prevents multiple round trips with MULTI + socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) + socket + end end - def reconnect - @socket.close if @socket - @socket = TCPSocket.open(@host, @port) - - connect - end end end From 1744a52b5fbaa0609514cf4e367fb66f950a71a1 Mon Sep 17 00:00:00 2001 From: Ben D'Angelo Date: Mon, 4 Dec 2023 00:50:59 -0500 Subject: [PATCH 4/7] Return suggest / query responses as an array --- lib/sonic/channels/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sonic/channels/base.rb b/lib/sonic/channels/base.rb index 935bf72..0e069e4 100644 --- a/lib/sonic/channels/base.rb +++ b/lib/sonic/channels/base.rb @@ -59,7 +59,7 @@ def type_cast_response(value) elsif value.start_with?('RESULT ') value.split(' ').last.to_i elsif value.start_with?('EVENT ') - value.split(' ')[3..-1].join(' ') + value.split(' ')[3..-1] else value end From 965d63771c9331c660b958cbb0422f2e30d3952c Mon Sep 17 00:00:00 2001 From: Ben D'Angelo Date: Sun, 17 Dec 2023 15:44:52 -0500 Subject: [PATCH 5/7] Force utf8 encoding --- lib/sonic/connection.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sonic/connection.rb b/lib/sonic/connection.rb index a0b3fbc..40b608d 100644 --- a/lib/sonic/connection.rb +++ b/lib/sonic/connection.rb @@ -36,8 +36,8 @@ def read raise ServerError, "Connection expired. Please reconnect." end - raise ServerError, "#{data} (#{@last_write})" if data.start_with?('ENDED ') - raise ServerError, "#{data} (#{@last_write})" if data.start_with?('ERR ') + raise ServerError, "#{data.force_encoding('UTF-8')} (#{@last_write})" if data.start_with?('ENDED ') + raise ServerError, "#{data.force_encoding('UTF-8')} (#{@last_write})" if data.start_with?('ERR ') data end From 6f7143fada7aab23d6d69d725b93a7545e40e48d Mon Sep 17 00:00:00 2001 From: Ben D'Angelo Date: Sun, 17 Dec 2023 18:50:37 -0500 Subject: [PATCH 6/7] Remove backslases entirely to avoid cases of double escaping --- lib/sonic/channels/base.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/sonic/channels/base.rb b/lib/sonic/channels/base.rb index 0e069e4..0f89471 100644 --- a/lib/sonic/channels/base.rb +++ b/lib/sonic/channels/base.rb @@ -46,7 +46,8 @@ def normalize(value) end def sanitize(value) - value.gsub('"', '\\"').gsub(/[\r\n]+/, '\\n').gsub(/\\/, '\\\\') + # remove backslashes entirely + value.gsub(/\\/, "").gsub('"', '\\"').gsub(/[\r\n]+/, '\\n') end def quote(value) From 9ffe3bfa02a024c093075504946c113f13902cc1 Mon Sep 17 00:00:00 2001 From: Ben D'Angelo Date: Thu, 4 Jan 2024 23:12:56 -0500 Subject: [PATCH 7/7] Added info and list commands --- lib/sonic/channels/control.rb | 4 ++++ lib/sonic/channels/search.rb | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/sonic/channels/control.rb b/lib/sonic/channels/control.rb index c56f1a9..ce1f575 100644 --- a/lib/sonic/channels/control.rb +++ b/lib/sonic/channels/control.rb @@ -4,6 +4,10 @@ class Control < Base def trigger(action) execute('TRIGGER', action) end + + def info + execute('INFO') + end end end end diff --git a/lib/sonic/channels/search.rb b/lib/sonic/channels/search.rb index f78cb20..e13a332 100644 --- a/lib/sonic/channels/search.rb +++ b/lib/sonic/channels/search.rb @@ -20,6 +20,16 @@ def suggest(collection, bucket, word, limit = nil) connection.read # ... end end + + def list(collection, bucket, limit = nil, offset = nil) + arr = [collection, bucket] + arr << "LIMIT(#{limit})" if limit + arr << "OFFSET(#{offset})" if offset + + execute('LIST', *arr) do + connection.read # ... + end + end end end end