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 79% rename from ably.gemspec rename to core/ably-pubsub-core.gemspec index 27366368f..89e9cc881 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.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-pubsub-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/core/lib/ably/agent.rb b/core/lib/ably/agent.rb new file mode 100644 index 000000000..c4442ef73 --- /dev/null +++ b/core/lib/ably/agent.rb @@ -0,0 +1,8 @@ +module Ably + # 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/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..04e60a5be 100644 --- a/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 @@ -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/lib/ably/agent.rb b/lib/ably/agent.rb deleted file mode 100644 index 39ea39e09..000000000 --- a/lib/ably/agent.rb +++ /dev/null @@ -1,3 +0,0 @@ -module Ably - AGENT = "ably-ruby/#{Ably::VERSION} ruby/#{RUBY_VERSION}" -end 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..8b8fb157e --- /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-pubsub-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..436546cb1 --- /dev/null +++ b/server/lib/ably/pubsub/server.rb @@ -0,0 +1,76 @@ +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. + # + # 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-pubsub-ruby entry beside it, + # which keeps carrying identity, version and support status. Wire shape: + # ably-pubsub-ruby/2.0.0 ruby/3.3.0 ably-pubsub-server + 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 => nil) + 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/connection_spec.rb b/spec/acceptance/realtime/connection_spec.rb index 36ca720fd..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/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..9b2f20f2e --- /dev/null +++ b/spec/unit/pubsub/server_spec.rb @@ -0,0 +1,101 @@ +# 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' } + # The side entry is a versionless flag, matching its ably-common registration: the + # 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 + 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, 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 + 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 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 + 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'))) }