smplkit 1.0.11 → 1.0.13
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/README.md +8 -1
- data/lib/smplkit/config/client.rb +15 -5
- data/lib/smplkit/config/helpers.rb +4 -3
- data/lib/smplkit/config_resolution.rb +4 -1
- data/lib/smplkit/management/client.rb +90 -45
- data/lib/smplkit/ws.rb +7 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f74b529f57291b182d674d166e138a61b95bb01c1bdf01a71261405f75a6879
|
|
4
|
+
data.tar.gz: 7e08e3ec63e892ae13bec37446afcd38c7b5d16008a0396d7046efd362598ed9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28aa21a7b049e824c613ab8d53df09a0993abd938cb275ee7a330735623b9e6de99b986f6930bc6bab472a26533abf472d5a6f41301e54d833856fdb6708c882
|
|
7
|
+
data.tar.gz: 738683d247b8a2c557731deaae62c93120899da054dcfb91991d7ee114dd5a40c7f945456916713aa4500aa2a6e1fefe5ea0916f682804c63a4eea2af3ad1afc
|
data/README.md
CHANGED
|
@@ -77,7 +77,14 @@ Two adapters ship at launch (per ADR-046 §2.3):
|
|
|
77
77
|
| `stdlib-logger` | Ruby stdlib `Logger` (and Rails via `ActiveSupport::Logger`) |
|
|
78
78
|
| `semantic-logger` | The [`semantic_logger` gem](https://github.com/reidmorrison/semantic_logger) |
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
Both are auto-loaded by `install` when the corresponding framework is available. To support an additional framework, subclass `Smplkit::Logging::Adapters::Base` and implement the five contract methods (`name`, `discover`, `apply_level`, `install_hook`, `uninstall_hook`), then register before `install`:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
client.logging.register_adapter(MyFrameworkAdapter.new)
|
|
84
|
+
client.logging.install
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Calling `register_adapter` disables auto-loading — only the adapters you register are used.
|
|
81
88
|
|
|
82
89
|
## Rails integration
|
|
83
90
|
|
|
@@ -157,11 +157,21 @@ module Smplkit
|
|
|
157
157
|
|
|
158
158
|
def typed_get(item_key, default, config_key)
|
|
159
159
|
snapshot = config_key ? resolve(config_key) : merged_snapshot
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
key = item_key.to_s
|
|
161
|
+
# Items live under flat dotted keys (e.g. +"api.host"+ — not nested
|
|
162
|
+
# +api → host+). Match Python's +current_values.get(key)+ behavior.
|
|
163
|
+
value = snapshot[key]
|
|
164
|
+
if value.nil? && snapshot.is_a?(Hash)
|
|
165
|
+
# Fallback: support callers that constructed an explicitly-nested
|
|
166
|
+
# snapshot (rare — typed model bindings only).
|
|
167
|
+
parts = key.split(".")
|
|
168
|
+
if parts.length > 1
|
|
169
|
+
value = parts.reduce(snapshot) do |scope, k|
|
|
170
|
+
break nil unless scope.is_a?(Hash)
|
|
171
|
+
|
|
172
|
+
scope[k]
|
|
173
|
+
end
|
|
174
|
+
end
|
|
165
175
|
end
|
|
166
176
|
return default if value.nil?
|
|
167
177
|
|
|
@@ -32,7 +32,7 @@ module Smplkit
|
|
|
32
32
|
key: attrs["key"] || resource["id"],
|
|
33
33
|
name: attrs["name"],
|
|
34
34
|
description: attrs["description"],
|
|
35
|
-
parent_id: attrs["parent_id"],
|
|
35
|
+
parent_id: attrs["parent"] || attrs["parent_id"],
|
|
36
36
|
items: items,
|
|
37
37
|
environments: environments,
|
|
38
38
|
created_at: attrs["created_at"],
|
|
@@ -54,11 +54,12 @@ module Smplkit
|
|
|
54
54
|
out[env] = { "values" => env_obj.values_raw }
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
# The Config schema (per the OpenAPI spec) does not include +key+ in
|
|
58
|
+
# attributes — the resource +id+ carries the customer-facing key.
|
|
57
59
|
attributes = {
|
|
58
|
-
"key" => config.key,
|
|
59
60
|
"name" => config.name,
|
|
60
61
|
"description" => config.description,
|
|
61
|
-
"
|
|
62
|
+
"parent" => config.parent_id,
|
|
62
63
|
"items" => items,
|
|
63
64
|
"environments" => environments
|
|
64
65
|
}.compact
|
|
@@ -81,7 +81,10 @@ module Smplkit
|
|
|
81
81
|
|
|
82
82
|
sections =
|
|
83
83
|
begin
|
|
84
|
-
|
|
84
|
+
# Force UTF-8 — the file may contain comments with non-ASCII bytes
|
|
85
|
+
# (em dashes, smart quotes) and the system's default external
|
|
86
|
+
# encoding is locale-dependent.
|
|
87
|
+
parse_ini(File.read(path, encoding: "UTF-8"))
|
|
85
88
|
rescue StandardError
|
|
86
89
|
return {}
|
|
87
90
|
end
|
|
@@ -143,25 +143,25 @@ module Smplkit
|
|
|
143
143
|
return if batch.empty?
|
|
144
144
|
|
|
145
145
|
body = { "data" => { "type" => "context_bulk_register", "attributes" => { "contexts" => batch } } }
|
|
146
|
-
http_post("/api/contexts/
|
|
146
|
+
http_post("/api/v1/contexts/bulk", body)
|
|
147
147
|
rescue StandardError => e
|
|
148
148
|
Smplkit.debug("registration", "context flush failed: #{e.class}: #{e.message}")
|
|
149
149
|
end
|
|
150
150
|
|
|
151
151
|
def list
|
|
152
|
-
list_resp = http_list("/api/contexts
|
|
152
|
+
list_resp = http_list("/api/v1/contexts")
|
|
153
153
|
list_resp.map { |r| context_from_resource(r) }
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
def get(id_or_type, key = nil)
|
|
157
157
|
type, ckey = split_id(id_or_type, key)
|
|
158
|
-
resource = http_get("/api/contexts
|
|
158
|
+
resource = http_get("/api/v1/contexts/#{type}:#{ckey}")
|
|
159
159
|
context_from_resource(resource["data"])
|
|
160
160
|
end
|
|
161
161
|
|
|
162
162
|
def delete(id_or_type, key = nil)
|
|
163
163
|
type, ckey = split_id(id_or_type, key)
|
|
164
|
-
http_delete("/api/contexts
|
|
164
|
+
http_delete("/api/v1/contexts/#{type}:#{ckey}")
|
|
165
165
|
end
|
|
166
166
|
|
|
167
167
|
def _save_context(ctx)
|
|
@@ -172,7 +172,7 @@ module Smplkit
|
|
|
172
172
|
"attributes" => { "type" => ctx.type, "key" => ctx.key, "attributes" => ctx.attributes }.compact
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
|
-
resp = http_put("/api/contexts
|
|
175
|
+
resp = http_put("/api/v1/contexts/#{ctx.id}", body)
|
|
176
176
|
context_from_resource(resp["data"]).tap { |c| c._bind_client(self) }
|
|
177
177
|
end
|
|
178
178
|
|
|
@@ -210,17 +210,17 @@ module Smplkit
|
|
|
210
210
|
end
|
|
211
211
|
|
|
212
212
|
def list
|
|
213
|
-
list_resp = http_list("/api/context_types
|
|
213
|
+
list_resp = http_list("/api/v1/context_types")
|
|
214
214
|
list_resp.map { |r| from_resource(r) }
|
|
215
215
|
end
|
|
216
216
|
|
|
217
217
|
def get(key)
|
|
218
|
-
resp = http_get("/api/context_types
|
|
218
|
+
resp = http_get("/api/v1/context_types/#{key}")
|
|
219
219
|
from_resource(resp["data"])
|
|
220
220
|
end
|
|
221
221
|
|
|
222
222
|
def delete(key)
|
|
223
|
-
http_delete("/api/context_types
|
|
223
|
+
http_delete("/api/v1/context_types/#{key}")
|
|
224
224
|
end
|
|
225
225
|
|
|
226
226
|
def new_context_type(key, name: nil, description: nil)
|
|
@@ -228,12 +228,12 @@ module Smplkit
|
|
|
228
228
|
end
|
|
229
229
|
|
|
230
230
|
def _create_context_type(ct)
|
|
231
|
-
resp = http_post("/api/context_types
|
|
231
|
+
resp = http_post("/api/v1/context_types", body_for(ct))
|
|
232
232
|
from_resource(resp["data"])
|
|
233
233
|
end
|
|
234
234
|
|
|
235
235
|
def _update_context_type(ct)
|
|
236
|
-
resp = http_put("/api/context_types
|
|
236
|
+
resp = http_put("/api/v1/context_types/#{ct.key}", body_for(ct))
|
|
237
237
|
from_resource(resp["data"])
|
|
238
238
|
end
|
|
239
239
|
|
|
@@ -268,17 +268,17 @@ module Smplkit
|
|
|
268
268
|
end
|
|
269
269
|
|
|
270
270
|
def list
|
|
271
|
-
list_resp = http_list("/api/environments
|
|
271
|
+
list_resp = http_list("/api/v1/environments")
|
|
272
272
|
list_resp.map { |r| from_resource(r) }
|
|
273
273
|
end
|
|
274
274
|
|
|
275
275
|
def get(key)
|
|
276
|
-
resp = http_get("/api/environments
|
|
276
|
+
resp = http_get("/api/v1/environments/#{key}")
|
|
277
277
|
from_resource(resp["data"])
|
|
278
278
|
end
|
|
279
279
|
|
|
280
280
|
def delete(key)
|
|
281
|
-
http_delete("/api/environments
|
|
281
|
+
http_delete("/api/v1/environments/#{key}")
|
|
282
282
|
end
|
|
283
283
|
|
|
284
284
|
def new(key, name: nil, color: nil,
|
|
@@ -293,12 +293,12 @@ module Smplkit
|
|
|
293
293
|
end
|
|
294
294
|
|
|
295
295
|
def _create_environment(env)
|
|
296
|
-
resp = http_post("/api/environments
|
|
296
|
+
resp = http_post("/api/v1/environments", body_for(env))
|
|
297
297
|
from_resource(resp["data"])
|
|
298
298
|
end
|
|
299
299
|
|
|
300
300
|
def _update_environment(env)
|
|
301
|
-
resp = http_put("/api/environments
|
|
301
|
+
resp = http_put("/api/v1/environments/#{env.key}", body_for(env))
|
|
302
302
|
from_resource(resp["data"])
|
|
303
303
|
end
|
|
304
304
|
|
|
@@ -342,12 +342,12 @@ module Smplkit
|
|
|
342
342
|
end
|
|
343
343
|
|
|
344
344
|
def get
|
|
345
|
-
resp = http_get("/api/
|
|
345
|
+
resp = http_get("/api/v1/accounts/current/settings")
|
|
346
346
|
from_resource(resp["data"])
|
|
347
347
|
end
|
|
348
348
|
|
|
349
349
|
def _update_account_settings(settings)
|
|
350
|
-
resp = http_put("/api/
|
|
350
|
+
resp = http_put("/api/v1/accounts/current/settings", body_for(settings))
|
|
351
351
|
from_resource(resp["data"])
|
|
352
352
|
end
|
|
353
353
|
|
|
@@ -385,41 +385,86 @@ module Smplkit
|
|
|
385
385
|
end
|
|
386
386
|
|
|
387
387
|
def list
|
|
388
|
-
list_resp = http_list("/api/configs
|
|
388
|
+
list_resp = http_list("/api/v1/configs")
|
|
389
389
|
list_resp.map { |r| Smplkit::Config::Helpers.config_from_json(self, r) }
|
|
390
390
|
end
|
|
391
391
|
|
|
392
392
|
def get(key)
|
|
393
|
-
resp = http_get("/api/configs
|
|
393
|
+
resp = http_get("/api/v1/configs/#{key}")
|
|
394
394
|
Smplkit::Config::Helpers.config_from_json(self, resp["data"])
|
|
395
395
|
end
|
|
396
396
|
|
|
397
397
|
def delete(key)
|
|
398
|
-
http_delete("/api/configs
|
|
398
|
+
http_delete("/api/v1/configs/#{key}")
|
|
399
399
|
end
|
|
400
400
|
|
|
401
401
|
def new_config(key, name: nil, description: nil, parent: nil)
|
|
402
402
|
Smplkit::Config::Config.new(
|
|
403
|
-
self,
|
|
404
|
-
|
|
403
|
+
self,
|
|
404
|
+
key: key,
|
|
405
|
+
name: name || Smplkit::Helpers.key_to_display_name(key),
|
|
406
|
+
description: description,
|
|
407
|
+
parent_id: parent.is_a?(Smplkit::Config::Config) ? parent.key : parent
|
|
405
408
|
)
|
|
406
409
|
end
|
|
407
410
|
|
|
408
411
|
def _create_config(config)
|
|
409
412
|
body = Smplkit::Config::Helpers.build_config_request_body(config)
|
|
410
|
-
resp = http_post("/api/configs
|
|
413
|
+
resp = http_post("/api/v1/configs", body)
|
|
411
414
|
Smplkit::Config::Helpers.config_from_json(self, resp["data"])
|
|
412
415
|
end
|
|
413
416
|
|
|
414
417
|
def _update_config(config)
|
|
415
418
|
body = Smplkit::Config::Helpers.build_config_request_body(config)
|
|
416
|
-
resp = http_put("/api/configs
|
|
419
|
+
resp = http_put("/api/v1/configs/#{config.key}", body)
|
|
417
420
|
Smplkit::Config::Helpers.config_from_json(self, resp["data"])
|
|
418
421
|
end
|
|
419
422
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
+
# Build the parent-chain for a given config, walking +parent_id+
|
|
424
|
+
# pointers across the full config list. Mirrors the Python SDK's
|
|
425
|
+
# client-side resolution — there is no server +/chain+ endpoint.
|
|
426
|
+
#
|
|
427
|
+
# Each chain entry is a Hash matching the wire shape that
|
|
428
|
+
# +Smplkit::Config::Helpers.resolve_chain+ consumes.
|
|
429
|
+
def fetch_chain(target_key)
|
|
430
|
+
all_configs = list
|
|
431
|
+
by_key = all_configs.to_h { |c| [c.key, c] }
|
|
432
|
+
by_id = all_configs.to_h { |c| [c.id, c] }
|
|
433
|
+
|
|
434
|
+
current = by_key[target_key]
|
|
435
|
+
return [] unless current
|
|
436
|
+
|
|
437
|
+
chain = []
|
|
438
|
+
loop do
|
|
439
|
+
chain << config_to_chain_entry(current)
|
|
440
|
+
parent_id = current.parent_id
|
|
441
|
+
break if parent_id.nil? || parent_id == ""
|
|
442
|
+
|
|
443
|
+
parent = by_id[parent_id]
|
|
444
|
+
break unless parent
|
|
445
|
+
|
|
446
|
+
current = parent
|
|
447
|
+
end
|
|
448
|
+
chain
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
private
|
|
452
|
+
|
|
453
|
+
def config_to_chain_entry(config)
|
|
454
|
+
items_hash = {}
|
|
455
|
+
config.items.each do |item|
|
|
456
|
+
items_hash[item.name] = {
|
|
457
|
+
"value" => item.value,
|
|
458
|
+
"type" => item.type,
|
|
459
|
+
"description" => item.description
|
|
460
|
+
}.compact
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
environments = config.environments.each_with_object({}) do |(env_key, env_obj), out|
|
|
464
|
+
out[env_key] = { "values" => env_obj.values_raw }
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
{ "id" => config.id, "items" => items_hash, "environments" => environments }
|
|
423
468
|
end
|
|
424
469
|
end
|
|
425
470
|
|
|
@@ -441,23 +486,23 @@ module Smplkit
|
|
|
441
486
|
return if batch.empty?
|
|
442
487
|
|
|
443
488
|
body = { "data" => { "type" => "flag_bulk_register", "attributes" => { "flags" => batch } } }
|
|
444
|
-
http_post("/api/flags/
|
|
489
|
+
http_post("/api/v1/flags/bulk", body)
|
|
445
490
|
rescue StandardError => e
|
|
446
491
|
Smplkit.debug("registration", "flag flush failed: #{e.class}: #{e.message}")
|
|
447
492
|
end
|
|
448
493
|
|
|
449
494
|
def list
|
|
450
|
-
list_resp = http_list("/api/flags
|
|
495
|
+
list_resp = http_list("/api/v1/flags")
|
|
451
496
|
list_resp.map { |r| flag_from_resource(r) }
|
|
452
497
|
end
|
|
453
498
|
|
|
454
499
|
def get(id)
|
|
455
|
-
resp = http_get("/api/flags
|
|
500
|
+
resp = http_get("/api/v1/flags/#{id}")
|
|
456
501
|
flag_from_resource(resp["data"])
|
|
457
502
|
end
|
|
458
503
|
|
|
459
504
|
def delete(id)
|
|
460
|
-
http_delete("/api/flags
|
|
505
|
+
http_delete("/api/v1/flags/#{id}")
|
|
461
506
|
end
|
|
462
507
|
|
|
463
508
|
def new_boolean_flag(id, default:, name: nil, description: nil, values: nil)
|
|
@@ -490,23 +535,23 @@ module Smplkit
|
|
|
490
535
|
|
|
491
536
|
def _create_flag(flag)
|
|
492
537
|
body = Smplkit::Flags::Helpers.build_flag_request_body(flag)
|
|
493
|
-
resp = http_post("/api/flags
|
|
538
|
+
resp = http_post("/api/v1/flags", body)
|
|
494
539
|
flag_from_resource(resp["data"])
|
|
495
540
|
end
|
|
496
541
|
|
|
497
542
|
def _update_flag(flag)
|
|
498
543
|
body = Smplkit::Flags::Helpers.build_flag_request_body(flag)
|
|
499
|
-
resp = http_put("/api/flags
|
|
544
|
+
resp = http_put("/api/v1/flags/#{flag.id}", body)
|
|
500
545
|
flag_from_resource(resp["data"])
|
|
501
546
|
end
|
|
502
547
|
|
|
503
548
|
def fetch_flag(id)
|
|
504
|
-
resp = http_get("/api/flags
|
|
549
|
+
resp = http_get("/api/v1/flags/#{id}")
|
|
505
550
|
Smplkit::Flags::Helpers.flag_dict_from_json(resp["data"])
|
|
506
551
|
end
|
|
507
552
|
|
|
508
553
|
def list_flags
|
|
509
|
-
body = http_list("/api/flags
|
|
554
|
+
body = http_list("/api/v1/flags")
|
|
510
555
|
body.map { |r| Smplkit::Flags::Helpers.flag_dict_from_json(r) }
|
|
511
556
|
end
|
|
512
557
|
|
|
@@ -550,30 +595,30 @@ module Smplkit
|
|
|
550
595
|
return if batch.empty?
|
|
551
596
|
|
|
552
597
|
body = { "data" => { "type" => "logger_bulk_register", "attributes" => { "loggers" => batch } } }
|
|
553
|
-
http_post("/api/loggers/
|
|
598
|
+
http_post("/api/v1/loggers/bulk", body)
|
|
554
599
|
rescue StandardError => e
|
|
555
600
|
Smplkit.debug("registration", "logger flush failed: #{e.class}: #{e.message}")
|
|
556
601
|
end
|
|
557
602
|
|
|
558
603
|
def list
|
|
559
|
-
list_resp = http_list("/api/loggers
|
|
604
|
+
list_resp = http_list("/api/v1/loggers")
|
|
560
605
|
list_resp.map { |r| Smplkit::Logging::Helpers.logger_resource_to_model(self, r) }
|
|
561
606
|
end
|
|
562
607
|
|
|
563
608
|
def get(id)
|
|
564
609
|
normalized = Smplkit::Logging::Normalize.normalize_logger_name(id)
|
|
565
|
-
resp = http_get("/api/loggers
|
|
610
|
+
resp = http_get("/api/v1/loggers/#{normalized}")
|
|
566
611
|
Smplkit::Logging::Helpers.logger_resource_to_model(self, resp["data"])
|
|
567
612
|
end
|
|
568
613
|
|
|
569
614
|
def delete(id)
|
|
570
615
|
normalized = Smplkit::Logging::Normalize.normalize_logger_name(id)
|
|
571
|
-
http_delete("/api/loggers
|
|
616
|
+
http_delete("/api/v1/loggers/#{normalized}")
|
|
572
617
|
end
|
|
573
618
|
|
|
574
619
|
def _update_logger(logger)
|
|
575
620
|
body = Smplkit::Logging::Helpers.build_logger_body(logger)
|
|
576
|
-
resp = http_put("/api/loggers
|
|
621
|
+
resp = http_put("/api/v1/loggers/#{logger.id || logger.name}", body)
|
|
577
622
|
Smplkit::Logging::Helpers.logger_resource_to_model(self, resp["data"])
|
|
578
623
|
end
|
|
579
624
|
end
|
|
@@ -586,17 +631,17 @@ module Smplkit
|
|
|
586
631
|
end
|
|
587
632
|
|
|
588
633
|
def list
|
|
589
|
-
list_resp = http_list("/api/log_groups
|
|
634
|
+
list_resp = http_list("/api/v1/log_groups")
|
|
590
635
|
list_resp.map { |r| Smplkit::Logging::Helpers.log_group_resource_to_model(self, r) }
|
|
591
636
|
end
|
|
592
637
|
|
|
593
638
|
def get(key)
|
|
594
|
-
resp = http_get("/api/log_groups
|
|
639
|
+
resp = http_get("/api/v1/log_groups/#{key}")
|
|
595
640
|
Smplkit::Logging::Helpers.log_group_resource_to_model(self, resp["data"])
|
|
596
641
|
end
|
|
597
642
|
|
|
598
643
|
def delete(key)
|
|
599
|
-
http_delete("/api/log_groups
|
|
644
|
+
http_delete("/api/v1/log_groups/#{key}")
|
|
600
645
|
end
|
|
601
646
|
|
|
602
647
|
def new_log_group(key, name: nil, level: nil, description: nil, parent: nil)
|
|
@@ -609,13 +654,13 @@ module Smplkit
|
|
|
609
654
|
|
|
610
655
|
def _create_log_group(group)
|
|
611
656
|
body = Smplkit::Logging::Helpers.build_log_group_body(group)
|
|
612
|
-
resp = http_post("/api/log_groups
|
|
657
|
+
resp = http_post("/api/v1/log_groups", body)
|
|
613
658
|
Smplkit::Logging::Helpers.log_group_resource_to_model(self, resp["data"])
|
|
614
659
|
end
|
|
615
660
|
|
|
616
661
|
def _update_log_group(group)
|
|
617
662
|
body = Smplkit::Logging::Helpers.build_log_group_body(group)
|
|
618
|
-
resp = http_put("/api/log_groups
|
|
663
|
+
resp = http_put("/api/v1/log_groups/#{group.key}", body)
|
|
619
664
|
Smplkit::Logging::Helpers.log_group_resource_to_model(self, resp["data"])
|
|
620
665
|
end
|
|
621
666
|
end
|
data/lib/smplkit/ws.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "async"
|
|
5
5
|
require "async/http/endpoint"
|
|
6
|
+
require "async/http/protocol/http1"
|
|
6
7
|
require "async/websocket/client"
|
|
7
8
|
require "concurrent"
|
|
8
9
|
|
|
@@ -172,7 +173,12 @@ module Smplkit
|
|
|
172
173
|
@connection_status = "connecting"
|
|
173
174
|
Smplkit.debug("websocket", "connecting to #{safe_url}")
|
|
174
175
|
|
|
175
|
-
|
|
176
|
+
# Force HTTP/1.1 for the WebSocket upgrade. async-http defaults to
|
|
177
|
+
# HTTP/2 on TLS endpoints, but the smplkit event gateway speaks the
|
|
178
|
+
# classic RFC 6455 upgrade over HTTP/1.1, not the HTTP/2-tunneled
|
|
179
|
+
# variant from RFC 8441 — without this override the upgrade returns
|
|
180
|
+
# a Protocol::HTTP2::StreamError before any frame is exchanged.
|
|
181
|
+
endpoint = Async::HTTP::Endpoint.parse(url, protocol: Async::HTTP::Protocol::HTTP1)
|
|
176
182
|
headers = { "user-agent" => USER_AGENT }
|
|
177
183
|
connection = Async::WebSocket::Client.connect(endpoint, headers: headers)
|
|
178
184
|
@connection_lock.synchronize { @connection = connection }
|