vertexcache 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 42487afddcfc0a68780c8ece4a39e7a56d5ce43e9d5119763b8dde6dd0b523c9
4
+ data.tar.gz: 0ede333ce914f2c1030150613b615bb199d62cbd714464e08a3a0758ed7a9368
5
+ SHA512:
6
+ metadata.gz: 1617b92ae33cd851091f74eb27304a73713ac061be14a3c7c7124fbd4e847791b4e6b84fe317d0180788a23283276b1520f733639fe1b60f43d34c1b46ad7dfd
7
+ data.tar.gz: 4bc6093994482292e506b270508c0fa9e8c5796ed6d7ee47ba096ece2cd8d2ea6d293516056ce24b4fbb9f802f02848c52f8eba4b0f1f10282460bb69859910f
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ------------------------------------------------------------------------------
18
+
19
+ require 'socket'
20
+ require 'openssl'
21
+ require 'stringio'
22
+ require 'vertexcache/comm/gcm_crypto_helper'
23
+ require 'vertexcache/comm/key_parser_helper'
24
+ require 'vertexcache/comm/message_codec'
25
+ require 'vertexcache/comm/socket_helper'
26
+ require 'vertexcache/model/vertex_cache_sdk_exception'
27
+
28
+ module VertexCache
29
+ module Comm
30
+ class ClientConnector
31
+ attr_reader :connected
32
+
33
+ def initialize(client_option)
34
+ @options = client_option
35
+ @stream = nil
36
+ @connected = false
37
+ end
38
+
39
+ def connect
40
+ @stream = if @options.enable_tls_encryption
41
+ SocketHelper.create_secure_socket(@options)
42
+ else
43
+ SocketHelper.create_socket_non_tls(@options)
44
+ end
45
+
46
+ writer = @stream.to_io
47
+ ident_command = @options.build_ident_command
48
+ payload = encrypt_if_enabled(ident_command.encode('UTF-8'))
49
+ MessageCodec.write_framed_message(writer, payload)
50
+ writer.flush
51
+
52
+ version, response_payload = MessageCodec.read_framed_message(@stream)
53
+ raise VertexCache::Model::VertexCacheSdkException, 'Missing payload' if response_payload.nil?
54
+
55
+ response = response_payload.force_encoding('UTF-8').strip
56
+ unless response.start_with?('+OK')
57
+ raise VertexCache::Model::VertexCacheSdkException, "Authorization failed: #{response}"
58
+ end
59
+
60
+ @connected = true
61
+ true
62
+ end
63
+
64
+ def send(message)
65
+ raise VertexCache::Model::VertexCacheSdkException, 'No active connection' unless connected?
66
+
67
+ payload = encrypt_if_enabled(message.encode('UTF-8'))
68
+
69
+ writer = @stream.to_io
70
+ MessageCodec.write_framed_message(writer, payload)
71
+ writer.flush
72
+
73
+ _version, response_payload = MessageCodec.read_framed_message(@stream)
74
+ raise VertexCache::Model::VertexCacheSdkException, 'Missing payload' if response_payload.nil?
75
+
76
+ response_payload.force_encoding('UTF-8')
77
+ end
78
+
79
+ def encrypt_if_enabled(plain)
80
+ case @options.encryption_mode
81
+ when VertexCache::Model::EncryptionMode::ASYMMETRIC
82
+ pem = @options.public_key
83
+ raise VertexCache::Model::VertexCacheSdkException, 'Missing public key' if pem.nil?
84
+
85
+ MessageCodec.switch_to_asymmetric
86
+ KeyParserHelper.encrypt_with_rsa(pem, plain)
87
+ when VertexCache::Model::EncryptionMode::SYMMETRIC
88
+ key = @options.shared_encryption_key_as_bytes
89
+ raise VertexCache::Model::VertexCacheSdkException, 'Missing shared encryption key' if key.nil?
90
+
91
+ MessageCodec.switch_to_symmetric
92
+ GcmCryptoHelper.encrypt(plain, key)
93
+ else
94
+ plain
95
+ end
96
+ rescue => e
97
+ raise VertexCache::Model::VertexCacheSdkException, e.message
98
+ end
99
+
100
+ def connected?
101
+ @connected && !@stream.nil?
102
+ end
103
+
104
+ def close
105
+ @stream.close if @stream
106
+ @stream = nil
107
+ @connected = false
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ------------------------------------------------------------------------------
18
+
19
+ require 'openssl'
20
+ require 'base64'
21
+
22
+ module VertexCache
23
+ module Comm
24
+ class GcmCryptoHelper
25
+ IV_LENGTH = 12
26
+ TAG_LENGTH = 16
27
+ KEY_LENGTH = 32
28
+
29
+ def self.encrypt(data, key)
30
+ raise ArgumentError, 'Invalid key length' unless key.bytesize == 16 || key.bytesize == 32
31
+
32
+ iv = OpenSSL::Random.random_bytes(IV_LENGTH)
33
+ cipher = OpenSSL::Cipher.new("aes-#{key.bytesize * 8}-gcm")
34
+ cipher.encrypt
35
+ cipher.key = key
36
+ cipher.iv = iv
37
+
38
+ ciphertext = cipher.update(data) + cipher.final
39
+ tag = cipher.auth_tag(TAG_LENGTH)
40
+
41
+ iv + ciphertext + tag
42
+ end
43
+
44
+ def self.decrypt(encrypted, key)
45
+ raise ArgumentError, 'Encrypted data too short' if encrypted.bytesize < IV_LENGTH + TAG_LENGTH
46
+
47
+ iv = encrypted[0, IV_LENGTH]
48
+ tag = encrypted[-TAG_LENGTH, TAG_LENGTH]
49
+ ciphertext = encrypted[IV_LENGTH..-(TAG_LENGTH + 1)]
50
+
51
+ cipher = OpenSSL::Cipher.new("aes-#{key.bytesize * 8}-gcm")
52
+ cipher.decrypt
53
+ cipher.key = key
54
+ cipher.iv = iv
55
+ cipher.auth_tag = tag
56
+
57
+ cipher.update(ciphertext) + cipher.final
58
+ end
59
+
60
+ def self.encode_base64_key(key)
61
+ Base64.strict_encode64(key)
62
+ end
63
+
64
+ def self.decode_base64_key(encoded)
65
+ Base64.strict_decode64(encoded)
66
+ end
67
+
68
+ def self.generate_base64_key
69
+ Base64.strict_encode64(OpenSSL::Random.random_bytes(KEY_LENGTH))
70
+ end
71
+
72
+ def self.encrypt_with_iv(data, key, iv)
73
+ cipher = OpenSSL::Cipher.new("aes-#{key.bytesize * 8}-gcm")
74
+ cipher.encrypt
75
+ cipher.key = key
76
+ cipher.iv = iv
77
+
78
+ ciphertext = cipher.update(data) + cipher.final
79
+ tag = cipher.auth_tag(TAG_LENGTH)
80
+
81
+ iv + ciphertext + tag
82
+ end
83
+
84
+ def self.decrypt_with_iv(encrypted, key, iv)
85
+ tag = encrypted[-TAG_LENGTH, TAG_LENGTH]
86
+ ciphertext = encrypted[IV_LENGTH..-(TAG_LENGTH + 1)]
87
+
88
+ cipher = OpenSSL::Cipher.new("aes-#{key.bytesize * 8}-gcm")
89
+ cipher.decrypt
90
+ cipher.key = key
91
+ cipher.iv = iv
92
+ cipher.auth_tag = tag
93
+
94
+ cipher.update(ciphertext) + cipher.final
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # You may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ------------------------------------------------------------------------------
18
+
19
+ require 'base64'
20
+ require 'openssl'
21
+ require 'vertexcache/model/vertex_cache_sdk_exception'
22
+
23
+
24
+ module VertexCache
25
+ module Comm
26
+ class KeyParserHelper
27
+ def self.config_public_key_if_enabled(pem_string)
28
+ begin
29
+ cleaned = pem_string.gsub(/-----BEGIN PUBLIC KEY-----/, '')
30
+ .gsub(/-----END PUBLIC KEY-----/, '')
31
+ .gsub(/\s+/, '')
32
+ decoded = Base64.strict_decode64(cleaned)
33
+ OpenSSL::PKey.read(decoded)
34
+ decoded
35
+ rescue
36
+ raise VertexCache::Model::VertexCacheSdkException.new('Invalid public key')
37
+ end
38
+ end
39
+
40
+ def self.config_shared_key_if_enabled(base64_string)
41
+ begin
42
+ decoded = Base64.strict_decode64(base64_string)
43
+ if Base64.strict_encode64(decoded) != base64_string.gsub(/\s+/, '')
44
+ raise VertexCache::Model::VertexCacheSdkException.new('Invalid shared key')
45
+ end
46
+ decoded
47
+ rescue
48
+ raise VertexCache::Model::VertexCacheSdkException.new('Invalid shared key')
49
+ end
50
+ end
51
+
52
+ def self.encrypt_with_rsa(pem_string, plaintext)
53
+ begin
54
+ public_key = OpenSSL::PKey::RSA.new(pem_string)
55
+ cipher_text = public_key.public_encrypt(plaintext, OpenSSL::PKey::RSA::PKCS1_PADDING)
56
+ cipher_text
57
+ rescue
58
+ raise VertexCache::Model::VertexCacheSdkException.new('RSA encryption failed')
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ------------------------------------------------------------------------------
18
+
19
+ require 'stringio'
20
+ require 'vertexcache/model/vertex_cache_sdk_exception'
21
+
22
+ module VertexCache
23
+ module Comm
24
+ class MessageCodec
25
+ HEADER_LEN = 8
26
+ MAX_PAYLOAD_SIZE = 10 * 1024 * 1024
27
+ MAX_MESSAGE_SIZE = 4 * 1024 * 1024
28
+
29
+ PROTOCOL_VERSION_RSA_PKCS1 = 0x00000101
30
+ PROTOCOL_VERSION_AES_GCM = 0x00000181
31
+ DEFAULT_PROTOCOL_VERSION = PROTOCOL_VERSION_RSA_PKCS1
32
+
33
+ @@protocol_version = DEFAULT_PROTOCOL_VERSION
34
+
35
+ def self.switch_to_asymmetric
36
+ @@protocol_version = PROTOCOL_VERSION_RSA_PKCS1
37
+ end
38
+
39
+ def self.switch_to_symmetric
40
+ @@protocol_version = PROTOCOL_VERSION_AES_GCM
41
+ end
42
+
43
+ def self.write_framed_message(io, payload)
44
+ raise VertexCache::Model::VertexCacheSdkException, 'Payload must be non-empty' if payload.nil? || payload.empty?
45
+ raise VertexCache::Model::VertexCacheSdkException, 'Payload too large' if payload.bytesize > MAX_MESSAGE_SIZE
46
+
47
+ length_prefix = [payload.bytesize].pack('N') # 4 bytes big-endian
48
+ version_bytes = [@@protocol_version].pack('N') # 4 bytes big-endian
49
+ io.write(length_prefix + version_bytes + payload)
50
+ io.flush
51
+ end
52
+
53
+ def self.read_framed_message(io)
54
+ header = io.read(HEADER_LEN)
55
+ return nil if header.nil? || header.bytesize < HEADER_LEN
56
+
57
+ length = header[0, 4].unpack1('N')
58
+ version = header[4, 4].unpack1('N')
59
+
60
+ raise VertexCache::Model::VertexCacheSdkException, 'Invalid message length' if length <= 0 || length > MAX_PAYLOAD_SIZE
61
+
62
+ payload = io.read(length)
63
+ raise VertexCache::Model::VertexCacheSdkException, 'Unexpected end of payload' if payload.nil? || payload.bytesize != length
64
+
65
+ [version, payload]
66
+ end
67
+
68
+ def self.hex_dump(payload)
69
+ io = StringIO.new
70
+ write_framed_message(io, payload)
71
+ io.rewind
72
+ io.read.unpack1('H*').upcase
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ------------------------------------------------------------------------------
18
+
19
+ module VertexCache
20
+ module Comm
21
+ class ReadWriteStream
22
+ def initialize(io)
23
+ @io = io
24
+ end
25
+
26
+ def read(n)
27
+ @io.read(n)
28
+ end
29
+
30
+ def write(data)
31
+ @io.write(data)
32
+ end
33
+
34
+ def flush
35
+ @io.flush
36
+ end
37
+
38
+ def close
39
+ @io.close
40
+ end
41
+
42
+ def closed?
43
+ @io.closed?
44
+ end
45
+
46
+ def io
47
+ @io
48
+ end
49
+
50
+ def to_io
51
+ @io
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ------------------------------------------------------------------------------
18
+
19
+ require 'socket'
20
+ require 'openssl'
21
+ require_relative 'ssl_helper'
22
+ require_relative 'read_write_stream'
23
+ require_relative '../model/vertex_cache_sdk_exception'
24
+
25
+ module VertexCache
26
+ module Comm
27
+ class SocketHelper
28
+ def self.create_secure_socket(options)
29
+ begin
30
+ tcp_socket = create_tcp_socket(options)
31
+ context = if options.verify_certificate
32
+ SSLHelper.create_verified_ssl_context(options.tls_certificate)
33
+ else
34
+ SSLHelper.create_insecure_ssl_context
35
+ end
36
+
37
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, context)
38
+ ssl_socket.sync_close = true
39
+ ssl_socket.connect
40
+
41
+ ReadWriteStream.new(ssl_socket)
42
+ rescue => _
43
+ raise VertexCache::Model::VertexCacheSdkException.new("Failed to create Secure Socket")
44
+ end
45
+ end
46
+
47
+ def self.create_socket_non_tls(options)
48
+ begin
49
+ tcp_socket = create_tcp_socket(options)
50
+ ReadWriteStream.new(tcp_socket)
51
+ rescue => _
52
+ raise VertexCache::Model::VertexCacheSdkException.new("Failed to create Non Secure Socket")
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def self.create_tcp_socket(options)
59
+ socket = TCPSocket.new(options.server_host, options.server_port)
60
+ seconds = options.read_timeout.to_i
61
+ timeval = [seconds, 0].pack("l_2")
62
+
63
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, timeval)
64
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, timeval)
65
+
66
+ socket
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ------------------------------------------------------------------------------
18
+
19
+ require 'openssl'
20
+ require 'vertexcache/model/vertex_cache_sdk_exception'
21
+
22
+ module VertexCache
23
+ module Comm
24
+ class SSLHelper
25
+ # Modern secure cipher suites aligned with server and industry standards
26
+ MODERN_CIPHERS = [
27
+ "TLS_AES_128_GCM_SHA256",
28
+ "TLS_AES_256_GCM_SHA384",
29
+ "TLS_CHACHA20_POLY1305_SHA256",
30
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
31
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
32
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
33
+ "TLS_RSA_WITH_AES_128_GCM_SHA256",
34
+ "TLS_RSA_WITH_AES_256_GCM_SHA384"
35
+ ].join(":")
36
+
37
+ def self.create_verified_ssl_context(pem_cert)
38
+ raise_invalid_cert unless valid_cert_format?(pem_cert)
39
+
40
+ cert = OpenSSL::X509::Certificate.new(pem_cert)
41
+ store = OpenSSL::X509::Store.new
42
+ store.add_cert(cert)
43
+
44
+ ctx = OpenSSL::SSL::SSLContext.new
45
+ ctx.cert_store = store
46
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
47
+ ctx.ciphers = MODERN_CIPHERS
48
+ ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
49
+ ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION
50
+ ctx
51
+ rescue OpenSSL::X509::CertificateError
52
+ raise VertexCache::Model::VertexCacheSdkException, 'Failed to parse PEM certificate'
53
+ rescue => e
54
+ raise VertexCache::Model::VertexCacheSdkException, 'Failed to build secure socket context'
55
+ end
56
+
57
+ def self.create_insecure_ssl_context
58
+ ctx = OpenSSL::SSL::SSLContext.new
59
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
60
+ ctx.ciphers = MODERN_CIPHERS
61
+ ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
62
+ ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION
63
+ ctx
64
+ end
65
+
66
+ def self.valid_cert_format?(pem_cert)
67
+ pem_cert && pem_cert.include?("BEGIN CERTIFICATE")
68
+ end
69
+
70
+ def self.raise_invalid_cert
71
+ raise VertexCache::Model::VertexCacheSdkException, "Invalid certificate format"
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # ------------------------------------------------------------------------------
16
+
17
+ require_relative '../comm/client_connector'
18
+ require_relative '../model/vertex_cache_sdk_exception'
19
+
20
+ module VertexCache
21
+ module Command
22
+ class CommandBase
23
+ RESPONSE_OK = 'OK'
24
+ COMMAND_SPACER = ' '
25
+
26
+ attr_reader :success, :response, :error
27
+
28
+ def execute(client)
29
+ begin
30
+ raw = client.send(build_command).strip
31
+
32
+ if raw.start_with?('+')
33
+ @response = raw[1..]
34
+ parse_response(@response)
35
+ @success = @error.nil?
36
+ elsif raw.start_with?('-')
37
+ @success = false
38
+ @error = raw[1..]
39
+ else
40
+ @success = false
41
+ @error = "Unexpected response: #{raw}"
42
+ end
43
+ rescue VertexCache::Model::VertexCacheSdkException => e
44
+ @success = false
45
+ @error = e.message
46
+ end
47
+ self
48
+ end
49
+
50
+ def success?
51
+ @success
52
+ end
53
+
54
+ def get_response
55
+ @response
56
+ end
57
+
58
+ def get_error
59
+ @error
60
+ end
61
+
62
+ def get_status_message
63
+ success? ? get_response : get_error
64
+ end
65
+
66
+ def set_success(response = RESPONSE_OK)
67
+ @success = true
68
+ @response = response
69
+ @error = nil
70
+ end
71
+
72
+ def set_failure(message)
73
+ @success = false
74
+ @error = message
75
+ end
76
+
77
+ # override in subclasses
78
+ def parse_response(_body)
79
+ # default no-op
80
+ end
81
+
82
+ # must override
83
+ def build_command
84
+ raise NotImplementedError, 'Subclasses must implement build_command'
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # Copyright 2025 to Present, Jason Lam - VertexCache (https://github.com/vertexcache/vertexcache)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # ------------------------------------------------------------------------------
16
+
17
+ module VertexCache
18
+ module Command
19
+ module CommandType
20
+ PING = 'PING'
21
+ SET = 'SET'
22
+ DEL = 'DEL'
23
+ IDX1 = 'IDX1'
24
+ IDX2 = 'IDX2'
25
+
26
+ ALL = [PING, SET, DEL, IDX1, IDX2].freeze
27
+ end
28
+ end
29
+ end