splitclient-rb 8.9.0.pre.rc1-java → 8.10.0-java
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/.github/workflows/ci.yml +9 -2
- data/CHANGES.txt +6 -0
- data/lib/splitclient-rb/sse/event_source/client.rb +84 -26
- data/lib/splitclient-rb/validators.rb +6 -2
- data/lib/splitclient-rb/version.rb +1 -1
- data/sonar-project.properties +1 -0
- data/splitclient-rb.gemspec +0 -1
- metadata +2 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fbfbcf5444639de1b0940978ab696d218c7ad2cf8801e5ae1f28a5399af45a50
|
|
4
|
+
data.tar.gz: a6cd50e2bdb8a7ff8c941630f1cd2ce5f9ed1a3f02fbc559ba807badfc3d3cf1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7b7ebb55330d9c812b520786f067ced5c6d6c5da5311f0203b92ed338b241a1195cbd374d3ff6b5a5e08e3ca03f81ba830d2cffd9bdf0586397fef362327e34
|
|
7
|
+
data.tar.gz: 4ec00a7c3405421ba6ec0370b431861e44159ae23dbe6c77278d95b9b1366242cb27eee002cf19e85613627b0ea51ca2e54945ff08b44e4bb8b553d0e78509c4
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -35,6 +35,12 @@ jobs:
|
|
|
35
35
|
with:
|
|
36
36
|
fetch-depth: 0
|
|
37
37
|
|
|
38
|
+
- name: Set up Java
|
|
39
|
+
uses: actions/setup-java@v2
|
|
40
|
+
with:
|
|
41
|
+
java-version: 17
|
|
42
|
+
distribution: "temurin"
|
|
43
|
+
|
|
38
44
|
- name: Setup Ruby ${{ matrix.version }}
|
|
39
45
|
uses: ruby/setup-ruby@v1
|
|
40
46
|
with:
|
|
@@ -57,7 +63,7 @@ jobs:
|
|
|
57
63
|
|
|
58
64
|
- name: SonarQube Scan (Push)
|
|
59
65
|
if: matrix.version == '3.2.2' && github.event_name == 'push'
|
|
60
|
-
uses: SonarSource/sonarcloud-github-action@
|
|
66
|
+
uses: SonarSource/sonarcloud-github-action@v5.0.0
|
|
61
67
|
env:
|
|
62
68
|
SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
|
|
63
69
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -69,13 +75,14 @@ jobs:
|
|
|
69
75
|
|
|
70
76
|
- name: SonarQube Scan (Pull Request)
|
|
71
77
|
if: matrix.version == '3.2.2' && github.event_name == 'pull_request'
|
|
72
|
-
uses: SonarSource/sonarcloud-github-action@
|
|
78
|
+
uses: SonarSource/sonarcloud-github-action@v5.0.0
|
|
73
79
|
env:
|
|
74
80
|
SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
|
|
75
81
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
76
82
|
with:
|
|
77
83
|
projectBaseDir: .
|
|
78
84
|
args: >
|
|
85
|
+
-Dsonar.java.source=17
|
|
79
86
|
-Dsonar.host.url=${{ secrets.SONARQUBE_HOST }}
|
|
80
87
|
-Dsonar.projectVersion=${{ env.VERSION }}
|
|
81
88
|
-Dsonar.pullrequest.key=${{ github.event.pull_request.number }}
|
data/CHANGES.txt
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
CHANGES
|
|
2
2
|
|
|
3
|
+
8.10.0 (Nov 28, 2025)
|
|
4
|
+
- Replaced socketry gem used in streaming feature with built-in socket lib.
|
|
5
|
+
|
|
6
|
+
8.9.0 (Oct 8, 2025)
|
|
7
|
+
- Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs.
|
|
8
|
+
|
|
3
9
|
8.8.0 (Sep 26, 2025)
|
|
4
10
|
- Added a maximum size payload when posting unique keys telemetry in batches
|
|
5
11
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: false
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'socket'
|
|
4
|
+
require 'openssl'
|
|
4
5
|
require 'uri'
|
|
6
|
+
require 'timeout'
|
|
5
7
|
|
|
6
8
|
module SplitIoClient
|
|
7
9
|
module SSE
|
|
@@ -36,12 +38,15 @@ module SplitIoClient
|
|
|
36
38
|
|
|
37
39
|
def close(status = nil)
|
|
38
40
|
unless connected?
|
|
39
|
-
@config.logger.
|
|
41
|
+
@config.logger.debug('SSEClient already disconected.')
|
|
40
42
|
return
|
|
41
43
|
end
|
|
44
|
+
@config.logger.debug("Closing SSEClient socket")
|
|
42
45
|
|
|
43
46
|
@connected.make_false
|
|
44
|
-
@socket
|
|
47
|
+
@socket.sync_close = true if @socket.is_a? OpenSSL::SSL::SSLSocket
|
|
48
|
+
@socket.close
|
|
49
|
+
@config.logger.debug("SSEClient socket state #{@socket.state}") if @socket.is_a? OpenSSL::SSL::SSLSocket
|
|
45
50
|
push_status(status)
|
|
46
51
|
rescue StandardError => e
|
|
47
52
|
@config.logger.error("SSEClient close Error: #{e.inspect}")
|
|
@@ -55,7 +60,6 @@ module SplitIoClient
|
|
|
55
60
|
|
|
56
61
|
@uri = URI(url)
|
|
57
62
|
latch = Concurrent::CountDownLatch.new(1)
|
|
58
|
-
|
|
59
63
|
connect_thread(latch)
|
|
60
64
|
|
|
61
65
|
return false unless latch.wait(CONNECT_TIMEOUT)
|
|
@@ -74,42 +78,73 @@ module SplitIoClient
|
|
|
74
78
|
|
|
75
79
|
def connect_thread(latch)
|
|
76
80
|
@config.threads[:connect_stream] = Thread.new do
|
|
77
|
-
@config.logger.info('Starting connect_stream thread ...')
|
|
81
|
+
@config.logger.info('Starting connect_stream thread ...')
|
|
78
82
|
new_status = connect_stream(latch)
|
|
79
83
|
push_status(new_status)
|
|
80
|
-
@config.logger.info('connect_stream thread finished.')
|
|
84
|
+
@config.logger.info('connect_stream thread finished.')
|
|
81
85
|
end
|
|
82
86
|
end
|
|
83
87
|
|
|
84
88
|
def connect_stream(latch)
|
|
85
89
|
return Constants::PUSH_NONRETRYABLE_ERROR unless socket_write(latch)
|
|
86
|
-
|
|
87
90
|
while connected? || @first_event.value
|
|
88
|
-
begin
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
91
|
+
begin
|
|
92
|
+
if IO.select([@socket], nil, nil, @read_timeout)
|
|
93
|
+
begin
|
|
94
|
+
partial_data = @socket.readpartial(10_000)
|
|
95
|
+
read_first_event(partial_data, latch)
|
|
96
|
+
|
|
97
|
+
raise 'eof exception' if partial_data == :eof
|
|
98
|
+
rescue IO::WaitReadable => e
|
|
99
|
+
@config.logger.debug("SSE client IO::WaitReadable transient error: #{e.inspect}")
|
|
100
|
+
IO.select([@socket], nil, nil, @read_timeout)
|
|
101
|
+
retry
|
|
102
|
+
rescue Errno::EAGAIN => e
|
|
103
|
+
@config.logger.debug("SSE client transient error: #{e.inspect}")
|
|
104
|
+
IO.select([@socket], nil, nil, @read_timeout)
|
|
105
|
+
retry
|
|
106
|
+
rescue Errno::ETIMEDOUT => e
|
|
107
|
+
@config.logger.error("SSE read operation timed out!: #{e.inspect}")
|
|
108
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
109
|
+
rescue EOFError => e
|
|
110
|
+
puts "SSE read operation EOF Exception!: #{e.inspect}"
|
|
111
|
+
@config.logger.error("SSE read operation EOF Exception!: #{e.inspect}")
|
|
112
|
+
raise 'eof exception'
|
|
113
|
+
rescue Errno::EBADF, IOError => e
|
|
114
|
+
@config.logger.error("SSE read operation EBADF or IOError: #{e.inspect}")
|
|
115
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
116
|
+
rescue StandardError => e
|
|
117
|
+
@config.logger.error("SSE read operation StandardError: #{e.inspect}")
|
|
118
|
+
return nil if ENV['SPLITCLIENT_ENV'] == 'test'
|
|
119
|
+
|
|
120
|
+
@config.logger.error("Error reading partial data: #{e.inspect}")
|
|
121
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
122
|
+
end
|
|
123
|
+
else
|
|
124
|
+
@config.logger.error("SSE read operation timed out, no data available.")
|
|
125
|
+
return Constants::PUSH_RETRYABLE_ERROR
|
|
126
|
+
end
|
|
127
|
+
rescue Errno::EBADF
|
|
128
|
+
@config.logger.debug("SSE socket is not connected (Errno::EBADF)")
|
|
129
|
+
break
|
|
130
|
+
rescue RuntimeError
|
|
131
|
+
raise 'eof exception'
|
|
132
|
+
rescue Exception => e
|
|
133
|
+
@config.logger.debug("SSE socket is not connected: #{e.inspect}")
|
|
134
|
+
break
|
|
102
135
|
end
|
|
103
136
|
|
|
104
137
|
process_data(partial_data)
|
|
105
138
|
end
|
|
139
|
+
@config.logger.info("SSE read operation exited: #{connected?}")
|
|
140
|
+
|
|
106
141
|
nil
|
|
107
142
|
end
|
|
108
143
|
|
|
109
144
|
def socket_write(latch)
|
|
110
145
|
@first_event.make_true
|
|
111
146
|
@socket = socket_connect
|
|
112
|
-
@socket.
|
|
147
|
+
@socket.puts(build_request(@uri))
|
|
113
148
|
true
|
|
114
149
|
rescue StandardError => e
|
|
115
150
|
@config.logger.error("Error during connecting to #{@uri.host}. Error: #{e.inspect}")
|
|
@@ -130,6 +165,7 @@ module SplitIoClient
|
|
|
130
165
|
|
|
131
166
|
if response_code == OK_CODE && !error_event
|
|
132
167
|
@connected.make_true
|
|
168
|
+
@config.logger.debug("SSE client first event Connected is true")
|
|
133
169
|
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::SSE_CONNECTION_ESTABLISHED, nil)
|
|
134
170
|
push_status(Constants::PUSH_CONNECTED)
|
|
135
171
|
end
|
|
@@ -138,15 +174,37 @@ module SplitIoClient
|
|
|
138
174
|
end
|
|
139
175
|
|
|
140
176
|
def socket_connect
|
|
141
|
-
|
|
177
|
+
tcp_socket = TCPSocket.new(@uri.host, @uri.port)
|
|
178
|
+
if @uri.scheme.casecmp('https').zero?
|
|
179
|
+
begin
|
|
180
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
|
181
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, ssl_context)
|
|
182
|
+
ssl_socket.hostname = @uri.host
|
|
183
|
+
|
|
184
|
+
begin
|
|
185
|
+
ssl_socket.connect_nonblock
|
|
186
|
+
rescue IO::WaitReadable
|
|
187
|
+
IO.select([ssl_socket])
|
|
188
|
+
retry
|
|
189
|
+
rescue IO::WaitWritable
|
|
190
|
+
IO.select(nil, [ssl_socket])
|
|
191
|
+
retry
|
|
192
|
+
end
|
|
193
|
+
return ssl_socket
|
|
194
|
+
|
|
195
|
+
rescue Exception => e
|
|
196
|
+
@config.logger.error("socket connect error: #{e.inspect}")
|
|
197
|
+
return nil
|
|
198
|
+
end
|
|
199
|
+
end
|
|
142
200
|
|
|
143
|
-
|
|
201
|
+
tcp_socket
|
|
144
202
|
end
|
|
145
203
|
|
|
146
204
|
def process_data(partial_data)
|
|
205
|
+
@config.logger.debug("Event partial data: #{partial_data}")
|
|
147
206
|
return if partial_data.nil? || partial_data == KEEP_ALIVE_RESPONSE
|
|
148
207
|
|
|
149
|
-
@config.logger.debug("Event partial data: #{partial_data}") if @config.debug_enabled
|
|
150
208
|
events = @event_parser.parse(partial_data)
|
|
151
209
|
events.each { |event| process_event(event) }
|
|
152
210
|
rescue StandardError => e
|
|
@@ -162,7 +220,7 @@ module SplitIoClient
|
|
|
162
220
|
req << "SplitSDKMachineName: #{@config.machine_name}\r\n"
|
|
163
221
|
req << "SplitSDKClientKey: #{@api_key.split(//).last(4).join}\r\n" unless @api_key.nil?
|
|
164
222
|
req << "Cache-Control: no-cache\r\n\r\n"
|
|
165
|
-
@config.logger.debug("Request info: #{req}")
|
|
223
|
+
@config.logger.debug("Request info: #{req}")
|
|
166
224
|
req
|
|
167
225
|
end
|
|
168
226
|
|
|
@@ -57,8 +57,12 @@ module SplitIoClient
|
|
|
57
57
|
end
|
|
58
58
|
without_nil = Array.new
|
|
59
59
|
flag_sets.each { |flag_set|
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
if !flag_set.nil?
|
|
61
|
+
without_nil.push(flag_set)
|
|
62
|
+
next
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
log_nil("flag set", method)
|
|
62
66
|
}
|
|
63
67
|
if without_nil.length() == 0
|
|
64
68
|
log_invalid_flag_set_type(method)
|
data/sonar-project.properties
CHANGED
data/splitclient-rb.gemspec
CHANGED
|
@@ -59,6 +59,5 @@ Gem::Specification.new do |spec|
|
|
|
59
59
|
spec.add_runtime_dependency 'lru_redux', '~> 1.1'
|
|
60
60
|
spec.add_runtime_dependency 'net-http-persistent', '>= 2.9', '< 5.0'
|
|
61
61
|
spec.add_runtime_dependency 'redis', '>= 4.0.0', '< 6.0'
|
|
62
|
-
spec.add_runtime_dependency 'socketry', '>= 0.4', '< 1.0'
|
|
63
62
|
spec.add_runtime_dependency 'thread_safe', '~> 0.3'
|
|
64
63
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: splitclient-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.
|
|
4
|
+
version: 8.10.0
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Split Software
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2025-
|
|
10
|
+
date: 2025-11-26 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: allocation_stats
|
|
@@ -361,26 +361,6 @@ dependencies:
|
|
|
361
361
|
- - "<"
|
|
362
362
|
- !ruby/object:Gem::Version
|
|
363
363
|
version: '6.0'
|
|
364
|
-
- !ruby/object:Gem::Dependency
|
|
365
|
-
name: socketry
|
|
366
|
-
requirement: !ruby/object:Gem::Requirement
|
|
367
|
-
requirements:
|
|
368
|
-
- - ">="
|
|
369
|
-
- !ruby/object:Gem::Version
|
|
370
|
-
version: '0.4'
|
|
371
|
-
- - "<"
|
|
372
|
-
- !ruby/object:Gem::Version
|
|
373
|
-
version: '1.0'
|
|
374
|
-
type: :runtime
|
|
375
|
-
prerelease: false
|
|
376
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
377
|
-
requirements:
|
|
378
|
-
- - ">="
|
|
379
|
-
- !ruby/object:Gem::Version
|
|
380
|
-
version: '0.4'
|
|
381
|
-
- - "<"
|
|
382
|
-
- !ruby/object:Gem::Version
|
|
383
|
-
version: '1.0'
|
|
384
364
|
- !ruby/object:Gem::Dependency
|
|
385
365
|
name: thread_safe
|
|
386
366
|
requirement: !ruby/object:Gem::Requirement
|