From 2e4c0b8196b6cb9857278097ca070126f2933885 Mon Sep 17 00:00:00 2001 From: umair Date: Tue, 1 Sep 2026 16:18:53 +0100 Subject: [PATCH 1/5] Restructure into ably-pubsub-core and ably-pubsub-server gems Implements the PubSub package split (PDR-091b) for the Ruby SDK: - Move the implementation into core/ as the ably-pubsub-core gem, an internal package that only Ably packages depend on. The ably-common submodule moves with it. - Add server/ as the ably-pubsub-server gem, whose factory functions are the only recommended entry points: Ably::PubSub::Server.create_http_client and .create_realtime_client. Ruby is a server-only SDK under PDR-091b2, so there is no device gem. - The factories stamp the side-declaring agent entry ably-pubsub-server/ via a new additive :agents client option; the caller's own agent entries are preserved and the side entry wins a collision on its own identifier. The -server suffix is what MAU classification reads, so specs assert it loudly. - Core and server are versioned in lockstep at 2.0.0, with the server gem pinning the core dependency to the exact version. - The old ably gemspec is removed; the ably gem is maintained from a maintenance branch per the 1-year support window, not from here. Co-Authored-By: Claude Fable 5 --- .gitmodules | 2 +- .yardopts | 2 + Gemfile | 7 +- Rakefile | 6 +- core/README.md | 14 +++ ably.gemspec => core/ably-pubsub-core.gemspec | 18 ++-- {lib => core/lib}/ably.rb | 0 {lib => core/lib}/ably/agent.rb | 0 {lib => core/lib}/ably/auth.rb | 0 {lib => core/lib}/ably/exceptions.rb | 0 {lib => core/lib}/ably/logger.rb | 0 {lib => core/lib}/ably/models/auth_details.rb | 0 .../lib}/ably/models/channel_details.rb | 0 .../lib}/ably/models/channel_metrics.rb | 0 .../lib}/ably/models/channel_occupancy.rb | 0 .../lib}/ably/models/channel_options.rb | 0 .../lib}/ably/models/channel_state_change.rb | 0 .../lib}/ably/models/channel_status.rb | 0 .../lib}/ably/models/cipher_params.rb | 0 .../lib}/ably/models/connection_details.rb | 0 .../ably/models/connection_state_change.rb | 0 {lib => core/lib}/ably/models/delta_extras.rb | 0 .../lib}/ably/models/device_details.rb | 0 .../lib}/ably/models/device_push_details.rb | 0 {lib => core/lib}/ably/models/error_info.rb | 0 .../ably/models/http_paginated_response.rb | 0 .../ably/models/idiomatic_ruby_wrapper.rb | 0 {lib => core/lib}/ably/models/message.rb | 0 .../lib}/ably/models/message_encoders/base.rb | 0 .../ably/models/message_encoders/base64.rb | 0 .../ably/models/message_encoders/cipher.rb | 0 .../lib}/ably/models/message_encoders/json.rb | 0 .../lib}/ably/models/message_encoders/utf8.rb | 0 {lib => core/lib}/ably/models/nil_logger.rb | 0 .../lib}/ably/models/paginated_result.rb | 0 .../lib}/ably/models/presence_message.rb | 0 .../lib}/ably/models/protocol_message.rb | 0 .../ably/models/push_channel_subscription.rb | 0 {lib => core/lib}/ably/models/stats.rb | 0 {lib => core/lib}/ably/models/stats_types.rb | 0 .../lib}/ably/models/token_details.rb | 0 .../lib}/ably/models/token_request.rb | 0 {lib => core/lib}/ably/modules/ably.rb | 0 .../lib}/ably/modules/async_wrapper.rb | 0 .../lib}/ably/modules/channels_collection.rb | 0 {lib => core/lib}/ably/modules/conversions.rb | 0 {lib => core/lib}/ably/modules/encodeable.rb | 0 {lib => core/lib}/ably/modules/enum.rb | 0 .../lib}/ably/modules/event_emitter.rb | 0 .../ably/modules/event_machine_helpers.rb | 0 .../lib}/ably/modules/exception_codes.rb | 0 .../lib}/ably/modules/http_helpers.rb | 0 .../lib}/ably/modules/message_emitter.rb | 0 .../lib}/ably/modules/message_pack.rb | 0 .../lib}/ably/modules/model_common.rb | 0 .../lib}/ably/modules/safe_deferrable.rb | 0 {lib => core/lib}/ably/modules/safe_yield.rb | 0 .../lib}/ably/modules/state_emitter.rb | 0 .../lib}/ably/modules/state_machine.rb | 0 .../ably/modules/statesman_monkey_patch.rb | 0 .../lib}/ably/modules/uses_state_machine.rb | 0 {lib => core/lib}/ably/realtime.rb | 0 {lib => core/lib}/ably/realtime/auth.rb | 0 {lib => core/lib}/ably/realtime/channel.rb | 0 .../ably/realtime/channel/channel_manager.rb | 0 .../realtime/channel/channel_properties.rb | 0 .../realtime/channel/channel_state_machine.rb | 0 .../lib}/ably/realtime/channel/publisher.rb | 0 .../ably/realtime/channel/push_channel.rb | 0 {lib => core/lib}/ably/realtime/channels.rb | 0 {lib => core/lib}/ably/realtime/client.rb | 0 .../client/incoming_message_dispatcher.rb | 0 .../client/outgoing_message_dispatcher.rb | 0 {lib => core/lib}/ably/realtime/connection.rb | 0 .../realtime/connection/connection_manager.rb | 0 .../connection/connection_state_machine.rb | 0 .../connection/websocket_transport.rb | 0 .../lib}/ably/realtime/models/nil_channel.rb | 0 {lib => core/lib}/ably/realtime/presence.rb | 0 .../ably/realtime/presence/members_map.rb | 0 .../realtime/presence/presence_manager.rb | 0 .../presence/presence_state_machine.rb | 0 {lib => core/lib}/ably/realtime/push.rb | 0 {lib => core/lib}/ably/realtime/push/admin.rb | 0 .../realtime/push/channel_subscriptions.rb | 0 .../realtime/push/device_registrations.rb | 0 .../ably/realtime/recovery_key_context.rb | 0 {lib => core/lib}/ably/rest.rb | 0 {lib => core/lib}/ably/rest/channel.rb | 0 .../lib}/ably/rest/channel/push_channel.rb | 0 {lib => core/lib}/ably/rest/channels.rb | 0 {lib => core/lib}/ably/rest/client.rb | 7 ++ .../lib}/ably/rest/middleware/encoder.rb | 0 .../lib}/ably/rest/middleware/exceptions.rb | 0 .../rest/middleware/external_exceptions.rb | 0 .../fail_if_unsupported_mime_type.rb | 0 .../lib}/ably/rest/middleware/logger.rb | 0 .../lib}/ably/rest/middleware/parse_json.rb | 0 .../rest/middleware/parse_message_pack.rb | 0 {lib => core/lib}/ably/rest/presence.rb | 0 {lib => core/lib}/ably/rest/push.rb | 0 {lib => core/lib}/ably/rest/push/admin.rb | 0 .../ably/rest/push/channel_subscriptions.rb | 0 .../ably/rest/push/device_registrations.rb | 0 .../lib}/ably/util/ably_extensions.rb | 0 {lib => core/lib}/ably/util/crypto.rb | 0 {lib => core/lib}/ably/util/pub_sub.rb | 0 .../lib}/ably/util/safe_deferrable.rb | 0 {lib => core/lib}/ably/version.rb | 2 +- {lib => core/lib}/submodules/ably-common | 0 server/README.md | 33 +++++++ server/ably-pubsub-server.gemspec | 22 +++++ server/lib/ably/pubsub/server.rb | 70 +++++++++++++ server/lib/ably/pubsub/server/version.rb | 9 ++ spec/acceptance/realtime/message_spec.rb | 4 +- spec/acceptance/rest/message_spec.rb | 2 +- spec/support/test_app.rb | 2 +- spec/unit/pubsub/server_spec.rb | 97 +++++++++++++++++++ spec/unit/util/crypto_spec.rb | 2 +- 119 files changed, 278 insertions(+), 21 deletions(-) create mode 100644 .yardopts create mode 100644 core/README.md rename ably.gemspec => core/ably-pubsub-core.gemspec (76%) rename {lib => core/lib}/ably.rb (100%) rename {lib => core/lib}/ably/agent.rb (100%) rename {lib => core/lib}/ably/auth.rb (100%) rename {lib => core/lib}/ably/exceptions.rb (100%) rename {lib => core/lib}/ably/logger.rb (100%) rename {lib => core/lib}/ably/models/auth_details.rb (100%) rename {lib => core/lib}/ably/models/channel_details.rb (100%) rename {lib => core/lib}/ably/models/channel_metrics.rb (100%) rename {lib => core/lib}/ably/models/channel_occupancy.rb (100%) rename {lib => core/lib}/ably/models/channel_options.rb (100%) rename {lib => core/lib}/ably/models/channel_state_change.rb (100%) rename {lib => core/lib}/ably/models/channel_status.rb (100%) rename {lib => core/lib}/ably/models/cipher_params.rb (100%) rename {lib => core/lib}/ably/models/connection_details.rb (100%) rename {lib => core/lib}/ably/models/connection_state_change.rb (100%) rename {lib => core/lib}/ably/models/delta_extras.rb (100%) rename {lib => core/lib}/ably/models/device_details.rb (100%) rename {lib => core/lib}/ably/models/device_push_details.rb (100%) rename {lib => core/lib}/ably/models/error_info.rb (100%) rename {lib => core/lib}/ably/models/http_paginated_response.rb (100%) rename {lib => core/lib}/ably/models/idiomatic_ruby_wrapper.rb (100%) rename {lib => core/lib}/ably/models/message.rb (100%) rename {lib => core/lib}/ably/models/message_encoders/base.rb (100%) rename {lib => core/lib}/ably/models/message_encoders/base64.rb (100%) rename {lib => core/lib}/ably/models/message_encoders/cipher.rb (100%) rename {lib => core/lib}/ably/models/message_encoders/json.rb (100%) rename {lib => core/lib}/ably/models/message_encoders/utf8.rb (100%) rename {lib => core/lib}/ably/models/nil_logger.rb (100%) rename {lib => core/lib}/ably/models/paginated_result.rb (100%) rename {lib => core/lib}/ably/models/presence_message.rb (100%) rename {lib => core/lib}/ably/models/protocol_message.rb (100%) rename {lib => core/lib}/ably/models/push_channel_subscription.rb (100%) rename {lib => core/lib}/ably/models/stats.rb (100%) rename {lib => core/lib}/ably/models/stats_types.rb (100%) rename {lib => core/lib}/ably/models/token_details.rb (100%) rename {lib => core/lib}/ably/models/token_request.rb (100%) rename {lib => core/lib}/ably/modules/ably.rb (100%) rename {lib => core/lib}/ably/modules/async_wrapper.rb (100%) rename {lib => core/lib}/ably/modules/channels_collection.rb (100%) rename {lib => core/lib}/ably/modules/conversions.rb (100%) rename {lib => core/lib}/ably/modules/encodeable.rb (100%) rename {lib => core/lib}/ably/modules/enum.rb (100%) rename {lib => core/lib}/ably/modules/event_emitter.rb (100%) rename {lib => core/lib}/ably/modules/event_machine_helpers.rb (100%) rename {lib => core/lib}/ably/modules/exception_codes.rb (100%) rename {lib => core/lib}/ably/modules/http_helpers.rb (100%) rename {lib => core/lib}/ably/modules/message_emitter.rb (100%) rename {lib => core/lib}/ably/modules/message_pack.rb (100%) rename {lib => core/lib}/ably/modules/model_common.rb (100%) rename {lib => core/lib}/ably/modules/safe_deferrable.rb (100%) rename {lib => core/lib}/ably/modules/safe_yield.rb (100%) rename {lib => core/lib}/ably/modules/state_emitter.rb (100%) rename {lib => core/lib}/ably/modules/state_machine.rb (100%) rename {lib => core/lib}/ably/modules/statesman_monkey_patch.rb (100%) rename {lib => core/lib}/ably/modules/uses_state_machine.rb (100%) rename {lib => core/lib}/ably/realtime.rb (100%) rename {lib => core/lib}/ably/realtime/auth.rb (100%) rename {lib => core/lib}/ably/realtime/channel.rb (100%) rename {lib => core/lib}/ably/realtime/channel/channel_manager.rb (100%) rename {lib => core/lib}/ably/realtime/channel/channel_properties.rb (100%) rename {lib => core/lib}/ably/realtime/channel/channel_state_machine.rb (100%) rename {lib => core/lib}/ably/realtime/channel/publisher.rb (100%) rename {lib => core/lib}/ably/realtime/channel/push_channel.rb (100%) rename {lib => core/lib}/ably/realtime/channels.rb (100%) rename {lib => core/lib}/ably/realtime/client.rb (100%) rename {lib => core/lib}/ably/realtime/client/incoming_message_dispatcher.rb (100%) rename {lib => core/lib}/ably/realtime/client/outgoing_message_dispatcher.rb (100%) rename {lib => core/lib}/ably/realtime/connection.rb (100%) rename {lib => core/lib}/ably/realtime/connection/connection_manager.rb (100%) rename {lib => core/lib}/ably/realtime/connection/connection_state_machine.rb (100%) rename {lib => core/lib}/ably/realtime/connection/websocket_transport.rb (100%) rename {lib => core/lib}/ably/realtime/models/nil_channel.rb (100%) rename {lib => core/lib}/ably/realtime/presence.rb (100%) rename {lib => core/lib}/ably/realtime/presence/members_map.rb (100%) rename {lib => core/lib}/ably/realtime/presence/presence_manager.rb (100%) rename {lib => core/lib}/ably/realtime/presence/presence_state_machine.rb (100%) rename {lib => core/lib}/ably/realtime/push.rb (100%) rename {lib => core/lib}/ably/realtime/push/admin.rb (100%) rename {lib => core/lib}/ably/realtime/push/channel_subscriptions.rb (100%) rename {lib => core/lib}/ably/realtime/push/device_registrations.rb (100%) rename {lib => core/lib}/ably/realtime/recovery_key_context.rb (100%) rename {lib => core/lib}/ably/rest.rb (100%) rename {lib => core/lib}/ably/rest/channel.rb (100%) rename {lib => core/lib}/ably/rest/channel/push_channel.rb (100%) rename {lib => core/lib}/ably/rest/channels.rb (100%) rename {lib => core/lib}/ably/rest/client.rb (98%) rename {lib => core/lib}/ably/rest/middleware/encoder.rb (100%) rename {lib => core/lib}/ably/rest/middleware/exceptions.rb (100%) rename {lib => core/lib}/ably/rest/middleware/external_exceptions.rb (100%) rename {lib => core/lib}/ably/rest/middleware/fail_if_unsupported_mime_type.rb (100%) rename {lib => core/lib}/ably/rest/middleware/logger.rb (100%) rename {lib => core/lib}/ably/rest/middleware/parse_json.rb (100%) rename {lib => core/lib}/ably/rest/middleware/parse_message_pack.rb (100%) rename {lib => core/lib}/ably/rest/presence.rb (100%) rename {lib => core/lib}/ably/rest/push.rb (100%) rename {lib => core/lib}/ably/rest/push/admin.rb (100%) rename {lib => core/lib}/ably/rest/push/channel_subscriptions.rb (100%) rename {lib => core/lib}/ably/rest/push/device_registrations.rb (100%) rename {lib => core/lib}/ably/util/ably_extensions.rb (100%) rename {lib => core/lib}/ably/util/crypto.rb (100%) rename {lib => core/lib}/ably/util/pub_sub.rb (100%) rename {lib => core/lib}/ably/util/safe_deferrable.rb (100%) rename {lib => core/lib}/ably/version.rb (90%) rename {lib => core/lib}/submodules/ably-common (100%) create mode 100644 server/README.md create mode 100644 server/ably-pubsub-server.gemspec create mode 100644 server/lib/ably/pubsub/server.rb create mode 100644 server/lib/ably/pubsub/server/version.rb create mode 100644 spec/unit/pubsub/server_spec.rb diff --git a/.gitmodules b/.gitmodules index 035940d12..548c849d2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "lib/submodules/ably-common"] - path = lib/submodules/ably-common + path = core/lib/submodules/ably-common url = https://github.com/ably/ably-common.git diff --git a/.yardopts b/.yardopts new file mode 100644 index 000000000..065c0fb12 --- /dev/null +++ b/.yardopts @@ -0,0 +1,2 @@ +core/lib/**/*.rb +server/lib/**/*.rb diff --git a/Gemfile b/Gemfile index 5d0856f56..4f54ce284 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,7 @@ source 'https://rubygems.org' -# Specify your gem's dependencies in ably.gemspec -gemspec +# This repo hosts two gems, released in lockstep at the same version (PDR-091b): +# - core/ ably-pubsub-core: the shared implementation (internal package) +# - server/ ably-pubsub-server: the public server-side package (factory entry points) +gemspec path: 'core' +gemspec path: 'server' diff --git a/Rakefile b/Rakefile index af2d779a8..99569d693 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ require 'rubygems' require 'bundler/setup' -require 'bundler/gem_tasks' + require 'json' require 'yard' @@ -32,8 +32,8 @@ begin desc 'Generate error code constants from ably-common: https://github.com/ably/ably-common/issues/32' task :generate_error_codes do - errors_json_path = File.join(File.dirname(__FILE__), 'lib/submodules/ably-common/protocol/errors.json') - module_path = File.join(File.dirname(__FILE__), 'lib/ably/modules/exception_codes.rb') + errors_json_path = File.join(File.dirname(__FILE__), 'core/lib/submodules/ably-common/protocol/errors.json') + module_path = File.join(File.dirname(__FILE__), 'core/lib/ably/modules/exception_codes.rb') max_length = 0 errors = JSON.parse(File.read(errors_json_path)).each_with_object({}) do |(key, val), hash| diff --git a/core/README.md b/core/README.md new file mode 100644 index 000000000..382d9e8f8 --- /dev/null +++ b/core/README.md @@ -0,0 +1,14 @@ +# ably-pubsub-core + +Internal implementation package for Ably's own Pub/Sub Ruby packages. + +**This gem is not intended for direct external use.** It is published only so that +Ably's public packages can depend on it. Use [`ably-pubsub-server`](../server) instead, +which exposes the supported entry points: + +```ruby +client = Ably::PubSub::Server.create_http_client(key) # stateless HTTP client +client = Ably::PubSub::Server.create_realtime_client(key) # stateful realtime client +``` + +`ably-pubsub-core` and `ably-pubsub-server` are released in lockstep at the same version. diff --git a/ably.gemspec b/core/ably-pubsub-core.gemspec similarity index 76% rename from ably.gemspec rename to core/ably-pubsub-core.gemspec index 765bdb702..b0d301101 100644 --- a/ably.gemspec +++ b/core/ably-pubsub-core.gemspec @@ -4,18 +4,18 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'ably/version' Gem::Specification.new do |spec| - spec.name = 'ably' + spec.name = 'ably-pubsub-core' spec.version = Ably::VERSION - spec.authors = ['Lewis Marshall', "Matthew O'Riordan"] - spec.email = ['lewis@lmars.net', 'matt@ably.io'] - spec.description = %q{A Ruby client library for ably.io realtime messaging} - spec.summary = %q{A Ruby client library for ably.io realtime messaging implemented using EventMachine} - spec.homepage = 'http://github.com/ably/ably-ruby' + spec.authors = ['Ably'] + spec.email = ['support@ably.com'] + spec.description = %q{Internal implementation package for Ably's own Pub/Sub packages. Not intended for direct external use: depend on ably-pubsub-server instead.} + spec.summary = %q{Shared core implementation for Ably Pub/Sub Ruby SDKs (internal)} + spec.homepage = 'https://github.com/ably/ably-ruby' spec.license = 'Apache-2.0' - spec.files = `git ls-files`.split($/) - spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } - spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.files = Dir.chdir(File.expand_path(__dir__)) do + `git ls-files -z lib`.split("\x0").reject { |f| f.start_with?('lib/submodules') } + end spec.require_paths = ['lib'] spec.add_runtime_dependency 'eventmachine', '~> 1.2.6' diff --git a/lib/ably.rb b/core/lib/ably.rb similarity index 100% rename from lib/ably.rb rename to core/lib/ably.rb diff --git a/lib/ably/agent.rb b/core/lib/ably/agent.rb similarity index 100% rename from lib/ably/agent.rb rename to core/lib/ably/agent.rb diff --git a/lib/ably/auth.rb b/core/lib/ably/auth.rb similarity index 100% rename from lib/ably/auth.rb rename to core/lib/ably/auth.rb diff --git a/lib/ably/exceptions.rb b/core/lib/ably/exceptions.rb similarity index 100% rename from lib/ably/exceptions.rb rename to core/lib/ably/exceptions.rb diff --git a/lib/ably/logger.rb b/core/lib/ably/logger.rb similarity index 100% rename from lib/ably/logger.rb rename to core/lib/ably/logger.rb diff --git a/lib/ably/models/auth_details.rb b/core/lib/ably/models/auth_details.rb similarity index 100% rename from lib/ably/models/auth_details.rb rename to core/lib/ably/models/auth_details.rb diff --git a/lib/ably/models/channel_details.rb b/core/lib/ably/models/channel_details.rb similarity index 100% rename from lib/ably/models/channel_details.rb rename to core/lib/ably/models/channel_details.rb diff --git a/lib/ably/models/channel_metrics.rb b/core/lib/ably/models/channel_metrics.rb similarity index 100% rename from lib/ably/models/channel_metrics.rb rename to core/lib/ably/models/channel_metrics.rb diff --git a/lib/ably/models/channel_occupancy.rb b/core/lib/ably/models/channel_occupancy.rb similarity index 100% rename from lib/ably/models/channel_occupancy.rb rename to core/lib/ably/models/channel_occupancy.rb diff --git a/lib/ably/models/channel_options.rb b/core/lib/ably/models/channel_options.rb similarity index 100% rename from lib/ably/models/channel_options.rb rename to core/lib/ably/models/channel_options.rb diff --git a/lib/ably/models/channel_state_change.rb b/core/lib/ably/models/channel_state_change.rb similarity index 100% rename from lib/ably/models/channel_state_change.rb rename to core/lib/ably/models/channel_state_change.rb diff --git a/lib/ably/models/channel_status.rb b/core/lib/ably/models/channel_status.rb similarity index 100% rename from lib/ably/models/channel_status.rb rename to core/lib/ably/models/channel_status.rb diff --git a/lib/ably/models/cipher_params.rb b/core/lib/ably/models/cipher_params.rb similarity index 100% rename from lib/ably/models/cipher_params.rb rename to core/lib/ably/models/cipher_params.rb diff --git a/lib/ably/models/connection_details.rb b/core/lib/ably/models/connection_details.rb similarity index 100% rename from lib/ably/models/connection_details.rb rename to core/lib/ably/models/connection_details.rb diff --git a/lib/ably/models/connection_state_change.rb b/core/lib/ably/models/connection_state_change.rb similarity index 100% rename from lib/ably/models/connection_state_change.rb rename to core/lib/ably/models/connection_state_change.rb diff --git a/lib/ably/models/delta_extras.rb b/core/lib/ably/models/delta_extras.rb similarity index 100% rename from lib/ably/models/delta_extras.rb rename to core/lib/ably/models/delta_extras.rb diff --git a/lib/ably/models/device_details.rb b/core/lib/ably/models/device_details.rb similarity index 100% rename from lib/ably/models/device_details.rb rename to core/lib/ably/models/device_details.rb diff --git a/lib/ably/models/device_push_details.rb b/core/lib/ably/models/device_push_details.rb similarity index 100% rename from lib/ably/models/device_push_details.rb rename to core/lib/ably/models/device_push_details.rb diff --git a/lib/ably/models/error_info.rb b/core/lib/ably/models/error_info.rb similarity index 100% rename from lib/ably/models/error_info.rb rename to core/lib/ably/models/error_info.rb diff --git a/lib/ably/models/http_paginated_response.rb b/core/lib/ably/models/http_paginated_response.rb similarity index 100% rename from lib/ably/models/http_paginated_response.rb rename to core/lib/ably/models/http_paginated_response.rb diff --git a/lib/ably/models/idiomatic_ruby_wrapper.rb b/core/lib/ably/models/idiomatic_ruby_wrapper.rb similarity index 100% rename from lib/ably/models/idiomatic_ruby_wrapper.rb rename to core/lib/ably/models/idiomatic_ruby_wrapper.rb diff --git a/lib/ably/models/message.rb b/core/lib/ably/models/message.rb similarity index 100% rename from lib/ably/models/message.rb rename to core/lib/ably/models/message.rb diff --git a/lib/ably/models/message_encoders/base.rb b/core/lib/ably/models/message_encoders/base.rb similarity index 100% rename from lib/ably/models/message_encoders/base.rb rename to core/lib/ably/models/message_encoders/base.rb diff --git a/lib/ably/models/message_encoders/base64.rb b/core/lib/ably/models/message_encoders/base64.rb similarity index 100% rename from lib/ably/models/message_encoders/base64.rb rename to core/lib/ably/models/message_encoders/base64.rb diff --git a/lib/ably/models/message_encoders/cipher.rb b/core/lib/ably/models/message_encoders/cipher.rb similarity index 100% rename from lib/ably/models/message_encoders/cipher.rb rename to core/lib/ably/models/message_encoders/cipher.rb diff --git a/lib/ably/models/message_encoders/json.rb b/core/lib/ably/models/message_encoders/json.rb similarity index 100% rename from lib/ably/models/message_encoders/json.rb rename to core/lib/ably/models/message_encoders/json.rb diff --git a/lib/ably/models/message_encoders/utf8.rb b/core/lib/ably/models/message_encoders/utf8.rb similarity index 100% rename from lib/ably/models/message_encoders/utf8.rb rename to core/lib/ably/models/message_encoders/utf8.rb diff --git a/lib/ably/models/nil_logger.rb b/core/lib/ably/models/nil_logger.rb similarity index 100% rename from lib/ably/models/nil_logger.rb rename to core/lib/ably/models/nil_logger.rb diff --git a/lib/ably/models/paginated_result.rb b/core/lib/ably/models/paginated_result.rb similarity index 100% rename from lib/ably/models/paginated_result.rb rename to core/lib/ably/models/paginated_result.rb diff --git a/lib/ably/models/presence_message.rb b/core/lib/ably/models/presence_message.rb similarity index 100% rename from lib/ably/models/presence_message.rb rename to core/lib/ably/models/presence_message.rb diff --git a/lib/ably/models/protocol_message.rb b/core/lib/ably/models/protocol_message.rb similarity index 100% rename from lib/ably/models/protocol_message.rb rename to core/lib/ably/models/protocol_message.rb diff --git a/lib/ably/models/push_channel_subscription.rb b/core/lib/ably/models/push_channel_subscription.rb similarity index 100% rename from lib/ably/models/push_channel_subscription.rb rename to core/lib/ably/models/push_channel_subscription.rb diff --git a/lib/ably/models/stats.rb b/core/lib/ably/models/stats.rb similarity index 100% rename from lib/ably/models/stats.rb rename to core/lib/ably/models/stats.rb diff --git a/lib/ably/models/stats_types.rb b/core/lib/ably/models/stats_types.rb similarity index 100% rename from lib/ably/models/stats_types.rb rename to core/lib/ably/models/stats_types.rb diff --git a/lib/ably/models/token_details.rb b/core/lib/ably/models/token_details.rb similarity index 100% rename from lib/ably/models/token_details.rb rename to core/lib/ably/models/token_details.rb diff --git a/lib/ably/models/token_request.rb b/core/lib/ably/models/token_request.rb similarity index 100% rename from lib/ably/models/token_request.rb rename to core/lib/ably/models/token_request.rb diff --git a/lib/ably/modules/ably.rb b/core/lib/ably/modules/ably.rb similarity index 100% rename from lib/ably/modules/ably.rb rename to core/lib/ably/modules/ably.rb diff --git a/lib/ably/modules/async_wrapper.rb b/core/lib/ably/modules/async_wrapper.rb similarity index 100% rename from lib/ably/modules/async_wrapper.rb rename to core/lib/ably/modules/async_wrapper.rb diff --git a/lib/ably/modules/channels_collection.rb b/core/lib/ably/modules/channels_collection.rb similarity index 100% rename from lib/ably/modules/channels_collection.rb rename to core/lib/ably/modules/channels_collection.rb diff --git a/lib/ably/modules/conversions.rb b/core/lib/ably/modules/conversions.rb similarity index 100% rename from lib/ably/modules/conversions.rb rename to core/lib/ably/modules/conversions.rb diff --git a/lib/ably/modules/encodeable.rb b/core/lib/ably/modules/encodeable.rb similarity index 100% rename from lib/ably/modules/encodeable.rb rename to core/lib/ably/modules/encodeable.rb diff --git a/lib/ably/modules/enum.rb b/core/lib/ably/modules/enum.rb similarity index 100% rename from lib/ably/modules/enum.rb rename to core/lib/ably/modules/enum.rb diff --git a/lib/ably/modules/event_emitter.rb b/core/lib/ably/modules/event_emitter.rb similarity index 100% rename from lib/ably/modules/event_emitter.rb rename to core/lib/ably/modules/event_emitter.rb diff --git a/lib/ably/modules/event_machine_helpers.rb b/core/lib/ably/modules/event_machine_helpers.rb similarity index 100% rename from lib/ably/modules/event_machine_helpers.rb rename to core/lib/ably/modules/event_machine_helpers.rb diff --git a/lib/ably/modules/exception_codes.rb b/core/lib/ably/modules/exception_codes.rb similarity index 100% rename from lib/ably/modules/exception_codes.rb rename to core/lib/ably/modules/exception_codes.rb diff --git a/lib/ably/modules/http_helpers.rb b/core/lib/ably/modules/http_helpers.rb similarity index 100% rename from lib/ably/modules/http_helpers.rb rename to core/lib/ably/modules/http_helpers.rb diff --git a/lib/ably/modules/message_emitter.rb b/core/lib/ably/modules/message_emitter.rb similarity index 100% rename from lib/ably/modules/message_emitter.rb rename to core/lib/ably/modules/message_emitter.rb diff --git a/lib/ably/modules/message_pack.rb b/core/lib/ably/modules/message_pack.rb similarity index 100% rename from lib/ably/modules/message_pack.rb rename to core/lib/ably/modules/message_pack.rb diff --git a/lib/ably/modules/model_common.rb b/core/lib/ably/modules/model_common.rb similarity index 100% rename from lib/ably/modules/model_common.rb rename to core/lib/ably/modules/model_common.rb diff --git a/lib/ably/modules/safe_deferrable.rb b/core/lib/ably/modules/safe_deferrable.rb similarity index 100% rename from lib/ably/modules/safe_deferrable.rb rename to core/lib/ably/modules/safe_deferrable.rb diff --git a/lib/ably/modules/safe_yield.rb b/core/lib/ably/modules/safe_yield.rb similarity index 100% rename from lib/ably/modules/safe_yield.rb rename to core/lib/ably/modules/safe_yield.rb diff --git a/lib/ably/modules/state_emitter.rb b/core/lib/ably/modules/state_emitter.rb similarity index 100% rename from lib/ably/modules/state_emitter.rb rename to core/lib/ably/modules/state_emitter.rb diff --git a/lib/ably/modules/state_machine.rb b/core/lib/ably/modules/state_machine.rb similarity index 100% rename from lib/ably/modules/state_machine.rb rename to core/lib/ably/modules/state_machine.rb diff --git a/lib/ably/modules/statesman_monkey_patch.rb b/core/lib/ably/modules/statesman_monkey_patch.rb similarity index 100% rename from lib/ably/modules/statesman_monkey_patch.rb rename to core/lib/ably/modules/statesman_monkey_patch.rb diff --git a/lib/ably/modules/uses_state_machine.rb b/core/lib/ably/modules/uses_state_machine.rb similarity index 100% rename from lib/ably/modules/uses_state_machine.rb rename to core/lib/ably/modules/uses_state_machine.rb diff --git a/lib/ably/realtime.rb b/core/lib/ably/realtime.rb similarity index 100% rename from lib/ably/realtime.rb rename to core/lib/ably/realtime.rb diff --git a/lib/ably/realtime/auth.rb b/core/lib/ably/realtime/auth.rb similarity index 100% rename from lib/ably/realtime/auth.rb rename to core/lib/ably/realtime/auth.rb diff --git a/lib/ably/realtime/channel.rb b/core/lib/ably/realtime/channel.rb similarity index 100% rename from lib/ably/realtime/channel.rb rename to core/lib/ably/realtime/channel.rb diff --git a/lib/ably/realtime/channel/channel_manager.rb b/core/lib/ably/realtime/channel/channel_manager.rb similarity index 100% rename from lib/ably/realtime/channel/channel_manager.rb rename to core/lib/ably/realtime/channel/channel_manager.rb diff --git a/lib/ably/realtime/channel/channel_properties.rb b/core/lib/ably/realtime/channel/channel_properties.rb similarity index 100% rename from lib/ably/realtime/channel/channel_properties.rb rename to core/lib/ably/realtime/channel/channel_properties.rb diff --git a/lib/ably/realtime/channel/channel_state_machine.rb b/core/lib/ably/realtime/channel/channel_state_machine.rb similarity index 100% rename from lib/ably/realtime/channel/channel_state_machine.rb rename to core/lib/ably/realtime/channel/channel_state_machine.rb diff --git a/lib/ably/realtime/channel/publisher.rb b/core/lib/ably/realtime/channel/publisher.rb similarity index 100% rename from lib/ably/realtime/channel/publisher.rb rename to core/lib/ably/realtime/channel/publisher.rb diff --git a/lib/ably/realtime/channel/push_channel.rb b/core/lib/ably/realtime/channel/push_channel.rb similarity index 100% rename from lib/ably/realtime/channel/push_channel.rb rename to core/lib/ably/realtime/channel/push_channel.rb diff --git a/lib/ably/realtime/channels.rb b/core/lib/ably/realtime/channels.rb similarity index 100% rename from lib/ably/realtime/channels.rb rename to core/lib/ably/realtime/channels.rb diff --git a/lib/ably/realtime/client.rb b/core/lib/ably/realtime/client.rb similarity index 100% rename from lib/ably/realtime/client.rb rename to core/lib/ably/realtime/client.rb diff --git a/lib/ably/realtime/client/incoming_message_dispatcher.rb b/core/lib/ably/realtime/client/incoming_message_dispatcher.rb similarity index 100% rename from lib/ably/realtime/client/incoming_message_dispatcher.rb rename to core/lib/ably/realtime/client/incoming_message_dispatcher.rb diff --git a/lib/ably/realtime/client/outgoing_message_dispatcher.rb b/core/lib/ably/realtime/client/outgoing_message_dispatcher.rb similarity index 100% rename from lib/ably/realtime/client/outgoing_message_dispatcher.rb rename to core/lib/ably/realtime/client/outgoing_message_dispatcher.rb diff --git a/lib/ably/realtime/connection.rb b/core/lib/ably/realtime/connection.rb similarity index 100% rename from lib/ably/realtime/connection.rb rename to core/lib/ably/realtime/connection.rb diff --git a/lib/ably/realtime/connection/connection_manager.rb b/core/lib/ably/realtime/connection/connection_manager.rb similarity index 100% rename from lib/ably/realtime/connection/connection_manager.rb rename to core/lib/ably/realtime/connection/connection_manager.rb diff --git a/lib/ably/realtime/connection/connection_state_machine.rb b/core/lib/ably/realtime/connection/connection_state_machine.rb similarity index 100% rename from lib/ably/realtime/connection/connection_state_machine.rb rename to core/lib/ably/realtime/connection/connection_state_machine.rb diff --git a/lib/ably/realtime/connection/websocket_transport.rb b/core/lib/ably/realtime/connection/websocket_transport.rb similarity index 100% rename from lib/ably/realtime/connection/websocket_transport.rb rename to core/lib/ably/realtime/connection/websocket_transport.rb diff --git a/lib/ably/realtime/models/nil_channel.rb b/core/lib/ably/realtime/models/nil_channel.rb similarity index 100% rename from lib/ably/realtime/models/nil_channel.rb rename to core/lib/ably/realtime/models/nil_channel.rb diff --git a/lib/ably/realtime/presence.rb b/core/lib/ably/realtime/presence.rb similarity index 100% rename from lib/ably/realtime/presence.rb rename to core/lib/ably/realtime/presence.rb diff --git a/lib/ably/realtime/presence/members_map.rb b/core/lib/ably/realtime/presence/members_map.rb similarity index 100% rename from lib/ably/realtime/presence/members_map.rb rename to core/lib/ably/realtime/presence/members_map.rb diff --git a/lib/ably/realtime/presence/presence_manager.rb b/core/lib/ably/realtime/presence/presence_manager.rb similarity index 100% rename from lib/ably/realtime/presence/presence_manager.rb rename to core/lib/ably/realtime/presence/presence_manager.rb diff --git a/lib/ably/realtime/presence/presence_state_machine.rb b/core/lib/ably/realtime/presence/presence_state_machine.rb similarity index 100% rename from lib/ably/realtime/presence/presence_state_machine.rb rename to core/lib/ably/realtime/presence/presence_state_machine.rb diff --git a/lib/ably/realtime/push.rb b/core/lib/ably/realtime/push.rb similarity index 100% rename from lib/ably/realtime/push.rb rename to core/lib/ably/realtime/push.rb diff --git a/lib/ably/realtime/push/admin.rb b/core/lib/ably/realtime/push/admin.rb similarity index 100% rename from lib/ably/realtime/push/admin.rb rename to core/lib/ably/realtime/push/admin.rb diff --git a/lib/ably/realtime/push/channel_subscriptions.rb b/core/lib/ably/realtime/push/channel_subscriptions.rb similarity index 100% rename from lib/ably/realtime/push/channel_subscriptions.rb rename to core/lib/ably/realtime/push/channel_subscriptions.rb diff --git a/lib/ably/realtime/push/device_registrations.rb b/core/lib/ably/realtime/push/device_registrations.rb similarity index 100% rename from lib/ably/realtime/push/device_registrations.rb rename to core/lib/ably/realtime/push/device_registrations.rb diff --git a/lib/ably/realtime/recovery_key_context.rb b/core/lib/ably/realtime/recovery_key_context.rb similarity index 100% rename from lib/ably/realtime/recovery_key_context.rb rename to core/lib/ably/realtime/recovery_key_context.rb diff --git a/lib/ably/rest.rb b/core/lib/ably/rest.rb similarity index 100% rename from lib/ably/rest.rb rename to core/lib/ably/rest.rb diff --git a/lib/ably/rest/channel.rb b/core/lib/ably/rest/channel.rb similarity index 100% rename from lib/ably/rest/channel.rb rename to core/lib/ably/rest/channel.rb diff --git a/lib/ably/rest/channel/push_channel.rb b/core/lib/ably/rest/channel/push_channel.rb similarity index 100% rename from lib/ably/rest/channel/push_channel.rb rename to core/lib/ably/rest/channel/push_channel.rb diff --git a/lib/ably/rest/channels.rb b/core/lib/ably/rest/channels.rb similarity index 100% rename from lib/ably/rest/channels.rb rename to core/lib/ably/rest/channels.rb diff --git a/lib/ably/rest/client.rb b/core/lib/ably/rest/client.rb similarity index 98% rename from lib/ably/rest/client.rb rename to core/lib/ably/rest/client.rb index 3dbda2dfb..523f314ec 100644 --- a/lib/ably/rest/client.rb +++ b/core/lib/ably/rest/client.rb @@ -186,6 +186,13 @@ def initialize(options) end @agent = options.delete(:agent) || Ably::AGENT + # Additive agent entries (`identifier => version`), appended to the base agent + # string. This is how a package layered on this one (such as ably-pubsub-server) + # declares itself — including the side-declaring entry that MAU classification + # reads — without replacing the base identifiers the way :agent does. + options.delete(:agents).to_h.each do |identifier, version| + @agent = "#{@agent} #{version ? "#{identifier}/#{version}" : identifier}" + end @realtime_client = options.delete(:realtime_client) @tls = options.delete_with_default(:tls, true) @environment = options.delete(:environment) # nil is production diff --git a/lib/ably/rest/middleware/encoder.rb b/core/lib/ably/rest/middleware/encoder.rb similarity index 100% rename from lib/ably/rest/middleware/encoder.rb rename to core/lib/ably/rest/middleware/encoder.rb diff --git a/lib/ably/rest/middleware/exceptions.rb b/core/lib/ably/rest/middleware/exceptions.rb similarity index 100% rename from lib/ably/rest/middleware/exceptions.rb rename to core/lib/ably/rest/middleware/exceptions.rb diff --git a/lib/ably/rest/middleware/external_exceptions.rb b/core/lib/ably/rest/middleware/external_exceptions.rb similarity index 100% rename from lib/ably/rest/middleware/external_exceptions.rb rename to core/lib/ably/rest/middleware/external_exceptions.rb diff --git a/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb b/core/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb similarity index 100% rename from lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb rename to core/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb diff --git a/lib/ably/rest/middleware/logger.rb b/core/lib/ably/rest/middleware/logger.rb similarity index 100% rename from lib/ably/rest/middleware/logger.rb rename to core/lib/ably/rest/middleware/logger.rb diff --git a/lib/ably/rest/middleware/parse_json.rb b/core/lib/ably/rest/middleware/parse_json.rb similarity index 100% rename from lib/ably/rest/middleware/parse_json.rb rename to core/lib/ably/rest/middleware/parse_json.rb diff --git a/lib/ably/rest/middleware/parse_message_pack.rb b/core/lib/ably/rest/middleware/parse_message_pack.rb similarity index 100% rename from lib/ably/rest/middleware/parse_message_pack.rb rename to core/lib/ably/rest/middleware/parse_message_pack.rb diff --git a/lib/ably/rest/presence.rb b/core/lib/ably/rest/presence.rb similarity index 100% rename from lib/ably/rest/presence.rb rename to core/lib/ably/rest/presence.rb diff --git a/lib/ably/rest/push.rb b/core/lib/ably/rest/push.rb similarity index 100% rename from lib/ably/rest/push.rb rename to core/lib/ably/rest/push.rb diff --git a/lib/ably/rest/push/admin.rb b/core/lib/ably/rest/push/admin.rb similarity index 100% rename from lib/ably/rest/push/admin.rb rename to core/lib/ably/rest/push/admin.rb diff --git a/lib/ably/rest/push/channel_subscriptions.rb b/core/lib/ably/rest/push/channel_subscriptions.rb similarity index 100% rename from lib/ably/rest/push/channel_subscriptions.rb rename to core/lib/ably/rest/push/channel_subscriptions.rb diff --git a/lib/ably/rest/push/device_registrations.rb b/core/lib/ably/rest/push/device_registrations.rb similarity index 100% rename from lib/ably/rest/push/device_registrations.rb rename to core/lib/ably/rest/push/device_registrations.rb diff --git a/lib/ably/util/ably_extensions.rb b/core/lib/ably/util/ably_extensions.rb similarity index 100% rename from lib/ably/util/ably_extensions.rb rename to core/lib/ably/util/ably_extensions.rb diff --git a/lib/ably/util/crypto.rb b/core/lib/ably/util/crypto.rb similarity index 100% rename from lib/ably/util/crypto.rb rename to core/lib/ably/util/crypto.rb diff --git a/lib/ably/util/pub_sub.rb b/core/lib/ably/util/pub_sub.rb similarity index 100% rename from lib/ably/util/pub_sub.rb rename to core/lib/ably/util/pub_sub.rb diff --git a/lib/ably/util/safe_deferrable.rb b/core/lib/ably/util/safe_deferrable.rb similarity index 100% rename from lib/ably/util/safe_deferrable.rb rename to core/lib/ably/util/safe_deferrable.rb diff --git a/lib/ably/version.rb b/core/lib/ably/version.rb similarity index 90% rename from lib/ably/version.rb rename to core/lib/ably/version.rb index 64eef5be7..ed629fa87 100644 --- a/lib/ably/version.rb +++ b/core/lib/ably/version.rb @@ -1,5 +1,5 @@ module Ably - VERSION = '1.2.8' + VERSION = '2.0.0' # The level of compatibility with the Ably service that this SDK supports. # Also referred to as the 'wire protocol version'. # spec : CSV2 diff --git a/lib/submodules/ably-common b/core/lib/submodules/ably-common similarity index 100% rename from lib/submodules/ably-common rename to core/lib/submodules/ably-common diff --git a/server/README.md b/server/README.md new file mode 100644 index 000000000..da5eab247 --- /dev/null +++ b/server/README.md @@ -0,0 +1,33 @@ +# ably-pubsub-server + +Ably Pub/Sub client for servers: backend services and other trusted runtimes. + +Installing this package declares that its traffic originates from the server side — +[MAU classification](https://ably.com/pricing) is a side effect of the install decision. + +## Installation + +```ruby +gem 'ably-pubsub-server' +``` + +## Usage + +The factory functions are the only recommended entry points: + +```ruby +require 'ably/pubsub/server' + +# Stateless HTTP client: publish, history, presence reads, token issuance +http_client = Ably::PubSub::Server.create_http_client('your-api-key') +http_client.channels.get('example').publish('event', 'payload') + +# Stateful realtime client: a persistent, live connection (EventMachine-based) +realtime_client = Ably::PubSub::Server.create_realtime_client('your-api-key') +``` + +Both factories accept everything the underlying constructors accept: an options `Hash`, +an API key `String`, or a token `String`. + +This gem is built on `ably-pubsub-core`, an internal implementation package. Depend on +this gem, not on the core. diff --git a/server/ably-pubsub-server.gemspec b/server/ably-pubsub-server.gemspec new file mode 100644 index 000000000..57cfcbb54 --- /dev/null +++ b/server/ably-pubsub-server.gemspec @@ -0,0 +1,22 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'ably/pubsub/server/version' + +Gem::Specification.new do |spec| + spec.name = 'ably-pubsub-server' + spec.version = Ably::PubSub::Server::VERSION + spec.authors = ['Ably'] + spec.email = ['support@ably.com'] + spec.description = %q{Ably Pub/Sub client for servers: backend services and other trusted runtimes. Construct clients with Ably::PubSub::Server.create_http_client or Ably::PubSub::Server.create_realtime_client.} + spec.summary = %q{Ably Pub/Sub client for servers} + spec.homepage = 'https://github.com/ably/ably-ruby' + spec.license = 'Apache-2.0' + + spec.files = Dir.chdir(File.expand_path(__dir__)) { `git ls-files -z lib README.md`.split("\x0") } + spec.require_paths = ['lib'] + + # Exact pin: core and server are released in lockstep at the same version (PDR-091b), + # which also guarantees a consumer can never resolve two different core versions. + spec.add_runtime_dependency 'ably-pubsub-core', "= #{Ably::PubSub::Server::VERSION}" +end diff --git a/server/lib/ably/pubsub/server.rb b/server/lib/ably/pubsub/server.rb new file mode 100644 index 000000000..56b1ac346 --- /dev/null +++ b/server/lib/ably/pubsub/server.rb @@ -0,0 +1,70 @@ +require 'ably' +require 'ably/pubsub/server/version' + +module Ably + module PubSub + # The Ably Pub/Sub SDK for servers. The factory functions here are the only + # recommended entry points of the +ably-pubsub-server+ gem. + module Server + # The agent identifier declaring the server side. + # + # The `-server` suffix is load-bearing, not cosmetic. On API-key auth the realtime + # system grants the MAU server exemption by matching an agent entry ending in + # `-server`, and an identifier that is not yet in the ably-common registry is + # classified by that suffix alone. Renaming it without preserving the suffix + # silently reclassifies every client this package constructs. + SERVER_AGENT_IDENTIFIER = 'ably-pubsub-server' + + class << self + # Creates a stateless HTTP (REST) client declaring the server side. + # + # Accepts everything {Ably::Rest::Client#initialize} accepts: an options Hash, + # an API key String, or a token String. + # + # @return [Ably::Rest::Client] + def create_http_client(options) + Ably::Rest::Client.new(options_with_side_agent(options)) + end + + # Creates a stateful realtime client declaring the server side. + # + # Accepts everything {Ably::Realtime::Client#initialize} accepts: an options Hash, + # an API key String, or a token String. + # + # @return [Ably::Realtime::Client] + def create_realtime_client(options) + Ably::Realtime::Client.new(options_with_side_agent(options)) + end + + private + + # Returns a copy of the caller's options carrying the agent entry that declares + # this package's side. + # + # The caller's own +:agents+ entries are preserved, so an SDK layered on top of + # this package keeps its attribution. The side entry is merged last and so wins a + # collision on its own identifier: which side the package declares is the + # package's to state, not the caller's to redefine. + # + # A nil argument passes through unchanged so the caller gets the core + # constructor's own initialization error rather than a vaguer failure later. + def options_with_side_agent(options) + return options if options.nil? + + options = if options.kind_of?(String) + if options.match(Ably::Auth::API_KEY_REGEX) + { key: options } + else + { token: options } + end + else + options.clone + end + + agents = options[:agents].to_h.merge(SERVER_AGENT_IDENTIFIER => VERSION) + options.merge(agents: agents) + end + end + end + end +end diff --git a/server/lib/ably/pubsub/server/version.rb b/server/lib/ably/pubsub/server/version.rb new file mode 100644 index 000000000..13d294b22 --- /dev/null +++ b/server/lib/ably/pubsub/server/version.rb @@ -0,0 +1,9 @@ +module Ably + module PubSub + module Server + # Must match Ably::VERSION in ably-pubsub-core: core and server are released in + # lockstep at the same version (PDR-091b). The release workflow and a spec assert this. + VERSION = '2.0.0' + end + end +end diff --git a/spec/acceptance/realtime/message_spec.rb b/spec/acceptance/realtime/message_spec.rb index b218a8e13..655ae93cf 100644 --- a/spec/acceptance/realtime/message_spec.rb +++ b/spec/acceptance/realtime/message_spec.rb @@ -485,7 +485,7 @@ def publish_and_check_extras(extras) end end - resources_root = File.expand_path('../../../../lib/submodules/ably-common/test-resources', __FILE__) + resources_root = File.expand_path('../../../../core/lib/submodules/ably-common/test-resources', __FILE__) shared_examples 'add_tests_for_data' do |data| data['items'].each_with_index do |item, index| @@ -823,7 +823,7 @@ def publish_and_check_extras(extras) let(:client_options) { { key: api_key, environment: environment, protocol: :json } } let(:channel_name) { "subscribe_send_text-#{random_str}" } - fixtures_path = File.expand_path('../../../../lib/submodules/ably-common/test-resources/messages-encoding.json', __FILE__) + fixtures_path = File.expand_path('../../../../core/lib/submodules/ably-common/test-resources/messages-encoding.json', __FILE__) context 'over a JSON transport' do let(:realtime_client) do diff --git a/spec/acceptance/rest/message_spec.rb b/spec/acceptance/rest/message_spec.rb index 49960226e..b9ac0ac67 100644 --- a/spec/acceptance/rest/message_spec.rb +++ b/spec/acceptance/rest/message_spec.rb @@ -395,7 +395,7 @@ def mock_for_two_publish_failures end end - resources_root = File.expand_path('../../../../lib/submodules/ably-common/test-resources', __FILE__) + resources_root = File.expand_path('../../../../core/lib/submodules/ably-common/test-resources', __FILE__) def self.add_tests_for_data(data) data['items'].each_with_index do |item, index| diff --git a/spec/support/test_app.rb b/spec/support/test_app.rb index 2e7fc3944..89b1b5cfc 100644 --- a/spec/support/test_app.rb +++ b/spec/support/test_app.rb @@ -1,7 +1,7 @@ require 'singleton' class TestApp - TEST_RESOURCES_PATH = File.expand_path('../../../lib/submodules/ably-common/test-resources', __FILE__) + TEST_RESOURCES_PATH = File.expand_path('../../../core/lib/submodules/ably-common/test-resources', __FILE__) # App configuration for test app # See https://github.com/ably/ably-common/blob/main/test-resources/test-app-setup.json diff --git a/spec/unit/pubsub/server_spec.rb b/spec/unit/pubsub/server_spec.rb new file mode 100644 index 000000000..10c126328 --- /dev/null +++ b/spec/unit/pubsub/server_spec.rb @@ -0,0 +1,97 @@ +# encoding: utf-8 +require 'spec_helper' +require 'ably/pubsub/server' + +# The agent value asserted here is what MAU billing classification reads (PDR-091). +# These specs must fail loudly if the side-declaring entry is renamed, dropped, or +# becomes overridable by the caller. +describe Ably::PubSub::Server do + let(:api_key) { 'appid.keyuid:keysecret' } + let(:side_entry) { "ably-pubsub-server/#{Ably::PubSub::Server::VERSION}" } + + it 'releases in lockstep with ably-pubsub-core' do + expect(Ably::PubSub::Server::VERSION).to eql(Ably::VERSION) + end + + it 'declares an identifier whose -server suffix billing classification depends on' do + expect(Ably::PubSub::Server::SERVER_AGENT_IDENTIFIER).to match(/-server\z/) + end + + describe '.create_http_client' do + subject(:client) { Ably::PubSub::Server.create_http_client(api_key) } + + it 'returns an HTTP (REST) client' do + expect(client).to be_a(Ably::Rest::Client) + end + + it 'appends the side-declaring agent entry to the base agent' do + expect(client.agent).to eql("#{Ably::AGENT} #{side_entry}") + end + + it 'sends the side-declaring agent entry in the Ably-Agent header' do + expect(client.send(:connection_options)[:headers]['Ably-Agent']).to eql("#{Ably::AGENT} #{side_entry}") + end + + context 'with an options hash' do + subject(:client) { Ably::PubSub::Server.create_http_client(key: api_key, environment: 'sandbox') } + + it 'passes the options through and stamps the side' do + expect(client.environment).to eql('sandbox') + expect(client.agent).to end_with(side_entry) + end + end + + context 'with a token string' do + subject(:client) { Ably::PubSub::Server.create_http_client('tokenstring') } + + it 'constructs a token-auth client with the side stamped' do + expect(client.auth.options[:token]).to eql('tokenstring') + expect(client.agent).to end_with(side_entry) + end + end + + context 'when the caller supplies their own agents' do + subject(:client) { Ably::PubSub::Server.create_http_client(key: api_key, agents: { 'example-sdk' => '1.0.0' }) } + + it 'preserves the caller entries and appends the side entry' do + expect(client.agent).to eql("#{Ably::AGENT} example-sdk/1.0.0 #{side_entry}") + end + end + + context 'when the caller tries to override the side entry' do + subject(:client) { Ably::PubSub::Server.create_http_client(key: api_key, agents: { 'ably-pubsub-server' => 'not-the-version' }) } + + it 'the package wins the collision on its own identifier' do + expect(client.agent).to include(side_entry) + expect(client.agent).to_not include('not-the-version') + end + + it 'does not mutate the caller options' do + options = { key: api_key, agents: { 'example-sdk' => '1.0.0' } } + Ably::PubSub::Server.create_http_client(options) + expect(options[:agents]).to eql({ 'example-sdk' => '1.0.0' }) + end + end + end + + describe '.create_realtime_client' do + subject(:client) { Ably::PubSub::Server.create_realtime_client(auto_connect: false, key: api_key) } + + it 'returns a realtime client' do + expect(client).to be_a(Ably::Realtime::Client) + end + + it 'appends the side-declaring agent entry sent as the realtime agent connection param' do + # Ably::Realtime::Connection sends client.rest_client.agent as the `agent` param + expect(client.rest_client.agent).to eql("#{Ably::AGENT} #{side_entry}") + end + + context 'with an API key string' do + subject(:client) { Ably::PubSub::Server.create_realtime_client(api_key) } + + it 'constructs a key-auth client with the side stamped' do + expect(client.rest_client.agent).to end_with(side_entry) + end + end + end +end diff --git a/spec/unit/util/crypto_spec.rb b/spec/unit/util/crypto_spec.rb index d3a7729e9..56abc1da0 100644 --- a/spec/unit/util/crypto_spec.rb +++ b/spec/unit/util/crypto_spec.rb @@ -96,7 +96,7 @@ end context 'using shared client lib fixture data' do - let(:resources_root) { File.expand_path('../../../../lib/submodules/ably-common/test-resources', __FILE__) } + let(:resources_root) { File.expand_path('../../../../core/lib/submodules/ably-common/test-resources', __FILE__) } let(:encryption_data_128) { JSON.parse(File.read(File.join(resources_root, 'crypto-data-128.json'))) } let(:encryption_data_256) { JSON.parse(File.read(File.join(resources_root, 'crypto-data-256.json'))) } From e694f240490c673a202f4e1ed4a99343a8c65697 Mon Sep 17 00:00:00 2001 From: umair Date: Tue, 1 Sep 2026 16:38:59 +0100 Subject: [PATCH 2/5] Fix agent param spec to accept multi-digit version segments Ruby 3.3.11 and similar patch versions no longer match the previous single-digit \d.\d.\d pattern, which made this spec fail on current CI runners regardless of this branch's changes. Co-Authored-By: Claude Fable 5 --- spec/acceptance/realtime/connection_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/acceptance/realtime/connection_spec.rb b/spec/acceptance/realtime/connection_spec.rb index 36ca720fd..be3f59a6b 100644 --- a/spec/acceptance/realtime/connection_spec.rb +++ b/spec/acceptance/realtime/connection_spec.rb @@ -2005,7 +2005,7 @@ def self.available_states it 'sends the lib version param agent (#RCS7d)' do expect(EventMachine).to receive(:connect) do |host, port, transport, object, url| uri = URI.parse(url) - expect(CGI::parse(uri.query)['agent'][0]).to match(/^ably-ruby\/\d\.\d\.\d ruby\/\d\.\d\.\d$/) + expect(CGI::parse(uri.query)['agent'][0]).to match(/^ably-ruby\/\d+\.\d+\.\d+ ruby\/\d+\.\d+\.\d+$/) stop_reactor end client From 8847f7b48fc0542e5450de2b641e5a06f2bb6af2 Mon Sep 17 00:00:00 2001 From: umair Date: Wed, 2 Sep 2026 11:22:49 +0100 Subject: [PATCH 3/5] Stamp the side-declaring agent entry without a version Matches the entry's registration in the ably-common agents registry (ably/ably-common#361): the side entry is a pure flag, like browser. Under lockstep versioning a version on the flag always duplicates the ably-ruby entry beside it, which keeps carrying identity, version and support status. Wire shape: ably-ruby/2.0.0 ruby/3.3.0 ably-pubsub-server Co-Authored-By: Claude Fable 5 --- server/lib/ably/pubsub/server.rb | 8 +++++++- spec/unit/pubsub/server_spec.rb | 10 +++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/server/lib/ably/pubsub/server.rb b/server/lib/ably/pubsub/server.rb index 56b1ac346..c0cf04818 100644 --- a/server/lib/ably/pubsub/server.rb +++ b/server/lib/ably/pubsub/server.rb @@ -13,6 +13,12 @@ module Server # `-server`, and an identifier that is not yet in the ably-common registry is # classified by that suffix alone. Renaming it without preserving the suffix # silently reclassifies every client this package constructs. + # + # The entry is stamped WITHOUT a version, matching its registration in the + # ably-common agents registry (a pure flag, like `browser`): under lockstep + # versioning a version here always duplicates the ably-ruby entry beside it, + # which keeps carrying identity, version and support status. Wire shape: + # ably-ruby/2.0.0 ruby/3.3.0 ably-pubsub-server SERVER_AGENT_IDENTIFIER = 'ably-pubsub-server' class << self @@ -61,7 +67,7 @@ def options_with_side_agent(options) options.clone end - agents = options[:agents].to_h.merge(SERVER_AGENT_IDENTIFIER => VERSION) + agents = options[:agents].to_h.merge(SERVER_AGENT_IDENTIFIER => nil) options.merge(agents: agents) end end diff --git a/spec/unit/pubsub/server_spec.rb b/spec/unit/pubsub/server_spec.rb index 10c126328..452cd7c2e 100644 --- a/spec/unit/pubsub/server_spec.rb +++ b/spec/unit/pubsub/server_spec.rb @@ -7,7 +7,9 @@ # becomes overridable by the caller. describe Ably::PubSub::Server do let(:api_key) { 'appid.keyuid:keysecret' } - let(:side_entry) { "ably-pubsub-server/#{Ably::PubSub::Server::VERSION}" } + # The side entry is a versionless flag, matching its ably-common registration: the + # ably-ruby/x.y.z entry beside it carries identity and version (see ably-common#361). + let(:side_entry) { 'ably-pubsub-server' } it 'releases in lockstep with ably-pubsub-core' do expect(Ably::PubSub::Server::VERSION).to eql(Ably::VERSION) @@ -24,8 +26,9 @@ expect(client).to be_a(Ably::Rest::Client) end - it 'appends the side-declaring agent entry to the base agent' do + it 'appends the side-declaring agent entry to the base agent, versionless' do expect(client.agent).to eql("#{Ably::AGENT} #{side_entry}") + expect(client.agent).to_not include('ably-pubsub-server/') end it 'sends the side-declaring agent entry in the Ably-Agent header' do @@ -62,8 +65,9 @@ subject(:client) { Ably::PubSub::Server.create_http_client(key: api_key, agents: { 'ably-pubsub-server' => 'not-the-version' }) } it 'the package wins the collision on its own identifier' do - expect(client.agent).to include(side_entry) + expect(client.agent).to end_with(side_entry) expect(client.agent).to_not include('not-the-version') + expect(client.agent).to_not include('ably-pubsub-server/') end it 'does not mutate the caller options' do From 11b33308e234ea9bb7059811c5f79de236ce5cff Mon Sep 17 00:00:00 2001 From: umair Date: Wed, 2 Sep 2026 12:52:05 +0100 Subject: [PATCH 4/5] Rename the SDK agent identifier to ably-pubsub-ruby The family identifier follows the package split, per the agent identifier convention proposed on PDR-091b2 and registered in ably/ably-common#361: because it flips exactly at the split and the maintenance branch is never touched, the identifier alone partitions the fleet - ably-ruby/* is legacy-gem traffic, ably-pubsub-ruby/* is new-package traffic. It names the family rather than any one published gem; the side a client declares travels as the separate versionless entry stamped by the server factories: ably-pubsub-ruby/2.0.0 ruby/3.3.0 ably-pubsub-server Requires the ably-pubsub-ruby registry entry (ably/ably-common#361) before any release from this branch. Mirrors ably/ably-js#2297 and ably/ably-java#1233. Co-Authored-By: Claude Fable 5 --- core/lib/ably/agent.rb | 7 ++++++- core/lib/ably/rest/client.rb | 2 +- server/lib/ably/pubsub/server.rb | 4 ++-- spec/acceptance/realtime/connection_spec.rb | 2 +- spec/unit/pubsub/server_spec.rb | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/core/lib/ably/agent.rb b/core/lib/ably/agent.rb index 39ea39e09..c4442ef73 100644 --- a/core/lib/ably/agent.rb +++ b/core/lib/ably/agent.rb @@ -1,3 +1,8 @@ module Ably - AGENT = "ably-ruby/#{Ably::VERSION} ruby/#{RUBY_VERSION}" + # The SDK family identifier renamed from `ably-ruby` with the per-side package split, so the + # identifier alone partitions the fleet: `ably-ruby/*` is legacy-gem traffic, + # `ably-pubsub-ruby/*` is new-package traffic. It names the family rather than any one + # published gem; the side a client declares travels as a separate versionless agent entry + # (see Ably::PubSub::Server and the agents registry in ably-common). + AGENT = "ably-pubsub-ruby/#{Ably::VERSION} ruby/#{RUBY_VERSION}" end diff --git a/core/lib/ably/rest/client.rb b/core/lib/ably/rest/client.rb index 523f314ec..04e60a5be 100644 --- a/core/lib/ably/rest/client.rb +++ b/core/lib/ably/rest/client.rb @@ -51,7 +51,7 @@ class Client # @return [Symbol] attr_reader :protocol - # Client agent i.e. `example-gem/1.2.0 ably-ruby/1.1.5 ruby/3.1.1` + # Client agent i.e. `example-gem/1.2.0 ably-pubsub-ruby/1.1.5 ruby/3.1.1` # @return [String] attr_reader :agent diff --git a/server/lib/ably/pubsub/server.rb b/server/lib/ably/pubsub/server.rb index c0cf04818..436546cb1 100644 --- a/server/lib/ably/pubsub/server.rb +++ b/server/lib/ably/pubsub/server.rb @@ -16,9 +16,9 @@ module Server # # The entry is stamped WITHOUT a version, matching its registration in the # ably-common agents registry (a pure flag, like `browser`): under lockstep - # versioning a version here always duplicates the ably-ruby entry beside it, + # versioning a version here always duplicates the ably-pubsub-ruby entry beside it, # which keeps carrying identity, version and support status. Wire shape: - # ably-ruby/2.0.0 ruby/3.3.0 ably-pubsub-server + # ably-pubsub-ruby/2.0.0 ruby/3.3.0 ably-pubsub-server SERVER_AGENT_IDENTIFIER = 'ably-pubsub-server' class << self diff --git a/spec/acceptance/realtime/connection_spec.rb b/spec/acceptance/realtime/connection_spec.rb index be3f59a6b..d23b0cadb 100644 --- a/spec/acceptance/realtime/connection_spec.rb +++ b/spec/acceptance/realtime/connection_spec.rb @@ -2005,7 +2005,7 @@ def self.available_states it 'sends the lib version param agent (#RCS7d)' do expect(EventMachine).to receive(:connect) do |host, port, transport, object, url| uri = URI.parse(url) - expect(CGI::parse(uri.query)['agent'][0]).to match(/^ably-ruby\/\d+\.\d+\.\d+ ruby\/\d+\.\d+\.\d+$/) + expect(CGI::parse(uri.query)['agent'][0]).to match(/^ably-pubsub-ruby\/\d+\.\d+\.\d+ ruby\/\d+\.\d+\.\d+$/) stop_reactor end client diff --git a/spec/unit/pubsub/server_spec.rb b/spec/unit/pubsub/server_spec.rb index 452cd7c2e..9b2f20f2e 100644 --- a/spec/unit/pubsub/server_spec.rb +++ b/spec/unit/pubsub/server_spec.rb @@ -8,7 +8,7 @@ describe Ably::PubSub::Server do let(:api_key) { 'appid.keyuid:keysecret' } # The side entry is a versionless flag, matching its ably-common registration: the - # ably-ruby/x.y.z entry beside it carries identity and version (see ably-common#361). + # ably-pubsub-ruby/x.y.z entry beside it carries identity and version (see ably-common#361). let(:side_entry) { 'ably-pubsub-server' } it 'releases in lockstep with ably-pubsub-core' do From b57ccd568ad70e6973ef1831d20ff199708dee57 Mon Sep 17 00:00:00 2001 From: umair Date: Thu, 3 Sep 2026 09:55:50 +0100 Subject: [PATCH 5/5] Update server gemspec homepage for the repo rename Co-Authored-By: Claude Fable 5 --- server/ably-pubsub-server.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/ably-pubsub-server.gemspec b/server/ably-pubsub-server.gemspec index 57cfcbb54..8b8fb157e 100644 --- a/server/ably-pubsub-server.gemspec +++ b/server/ably-pubsub-server.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |spec| spec.email = ['support@ably.com'] spec.description = %q{Ably Pub/Sub client for servers: backend services and other trusted runtimes. Construct clients with Ably::PubSub::Server.create_http_client or Ably::PubSub::Server.create_realtime_client.} spec.summary = %q{Ably Pub/Sub client for servers} - spec.homepage = 'https://github.com/ably/ably-ruby' + spec.homepage = 'https://github.com/ably/ably-pubsub-ruby' spec.license = 'Apache-2.0' spec.files = Dir.chdir(File.expand_path(__dir__)) { `git ls-files -z lib README.md`.split("\x0") }