diff --git a/.gitignore b/.gitignore index 0cb6eeb..b827cff 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ /doc/ /pkg/ /spec/reports/ +/spec/examples.txt /tmp/ diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..437459c --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.5.0 diff --git a/.travis.yml b/.travis.yml index bb45ab6..bdf3580 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: ruby rvm: - - 2.1.9 - - 2.2.5 - - 2.3.1 + - 2.4.1 + - 2.5.0 before_install: gem update bundler diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9ba175e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] +### Added +- Ability to specify `last_id` of a channel +- Get access to `message_id` if specified in the callback diff --git a/Gemfile b/Gemfile index a7f86bd..a550366 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,5 @@ source 'https://rubygems.org' # Specify your gem's dependencies in message_bus-client.gemspec gemspec + +gem "pry-byebug" diff --git a/README.md b/README.md index 02f36d3..58be5de 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ The API is mostly equivalent with the JavaScript client: ```ruby client = MessageBus::Client.new('http://chat.samsaffron.com/') -client.subscribe('/message') do |payload| +client.subscribe('/message') do |payload, message_id| # Do stuff end diff --git a/Rakefile b/Rakefile index 7c6aacf..bde1bec 100644 --- a/Rakefile +++ b/Rakefile @@ -11,9 +11,18 @@ task :server do end at_exit do - $stderr.puts "Killing pid #{pid}" - Process.kill('KILL', pid) - Process.wait(pid) + if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ + $stderr.puts "Killing pid #{pid}" + Process.kill('KILL', pid) + Process.wait(pid) + else + child_pid = `pgrep -P #{pid}`.to_i + pids = [child_pid, pid] + pids.each do |pid| + $stderr.puts "Killing pid #{pid}" + Process.kill('KILL', pid) + end + end end sleep 3 diff --git a/lib/message_bus/client.rb b/lib/message_bus/client.rb index 5bb8184..709e5a1 100644 --- a/lib/message_bus/client.rb +++ b/lib/message_bus/client.rb @@ -1,5 +1,6 @@ require 'excon' require 'json' +require "securerandom" require 'message_bus/client/version' require 'message_bus/client/configuration' diff --git a/lib/message_bus/client/message_handler.rb b/lib/message_bus/client/message_handler.rb index 71bb0bc..08d6fc1 100644 --- a/lib/message_bus/client/message_handler.rb +++ b/lib/message_bus/client/message_handler.rb @@ -1,13 +1,13 @@ module MessageBus::Client::MessageHandler SubscribedChannel = Struct.new(:callbacks, :last_id) do - def initialize(last_id = -1) + def initialize(last_id) self.callbacks = [] self.last_id = last_id end - def callback(payload) + def callback(payload, message_id) callbacks.each do |callback| - callback.call(payload) + callback.call(payload, message_id) end end end @@ -20,14 +20,16 @@ def initialize(base_url) @pending_messages = [] @subscribed_channels = {} - @subscribed_channels.default_proc = proc do |hash, key| - hash[key] = SubscribedChannel.new - end @payload = String.new end - def subscribe(channel, &callback) - @subscribed_channels[channel].callbacks << callback + def subscribe(channel, last_id=-1, &callback) + subscribed_channel = @subscribed_channels[channel] + if subscribed_channel.nil? + subscribed_channel = @subscribed_channels[channel] = + SubscribedChannel.new(last_id) + end + subscribed_channel.callbacks << callback end def unsubscribe @@ -80,8 +82,9 @@ def handle_message(message) subscription = @subscribed_channels[message['channel']] return unless subscription - subscription.last_id = message['message_id'] - subscription.callback(message['data']) + message_id = message['message_id'] + subscription.last_id = message_id + subscription.callback(message['data'], message_id) end def handle_status_message(message) diff --git a/spec/coverage_helper.rb b/spec/coverage_helper.rb deleted file mode 100644 index 27fee81..0000000 --- a/spec/coverage_helper.rb +++ /dev/null @@ -1,65 +0,0 @@ -# Simultaneous code coverage reporting to Coveralls and Code Climate. -# Latest version can be found at https://gist.github.com/lowjoel/6c2f2d3a08bb3786994f -require 'simplecov' - -module CoverageHelper - class << self - # Helper to include Coveralls/Code Climate coverage, but not require developers to install the - # gem. - # - # @param [String] name The name of the module to require. - # @param [Proc] initializer The block to execute when the module is required successfully. - def load(name, &initializer) - old_formatter = SimpleCov.formatter - require name - initializer.call - - merge_formatters(old_formatter, SimpleCov.formatter) - rescue LoadError => e - if e.path == name - puts format('Cannot find \'%s\', ignoring', name) if ENV['CI'] - else - raise e - end - end - - private - - # Merge two SimpleCov formatters into a single MultiFormatter. - # - # This method is idempotent if the old and new formatters are the same. - def merge_formatters(old_formatter, new_formatter) - return if old_formatter == new_formatter - - old_formatter = [*expand_formatter(old_formatter)] - new_formatter = [*expand_formatter(new_formatter)] - formatters = old_formatter + new_formatter - - SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(formatters) - end - - # Extracts the formatters from a MultiFormatter so we do not nest them. - def expand_formatter(formatter) - return formatter unless formatter.is_a?(SimpleCov::Formatter::MultiFormatter) - formatter.formatters - end - end -end - -if ENV['CI'] - # Coveralls - CoverageHelper.load('coveralls') do - Coveralls.wear!('rails') - end - - # Code Climate - CoverageHelper.load('codeclimate-test-reporter') do - CodeClimate::TestReporter.start - end - - # Code coverage exclusions - SimpleCov.start do - # SimpleCov configuration - # add_filter '/lib/extensions/active_record/connection_adapters/table_definition.rb' - end -end diff --git a/spec/message_bus/client_spec.rb b/spec/message_bus/client_spec.rb index 26511de..809a5dd 100644 --- a/spec/message_bus/client_spec.rb +++ b/spec/message_bus/client_spec.rb @@ -37,7 +37,7 @@ def write_message(message, user = 'message_bus-client') end end - it 'receives messages' do + it 'receives new messages by default (last_id of -1)' do subject.start text = "Hello World! #{Random.rand}" @@ -72,7 +72,7 @@ def write_message(message, user = 'message_bus-client') subject.stop end - it 'receives messages' do + it 'receives new messages by default (last_id of -1)' do subject.start text = "Hello World! #{Random.rand}" @@ -113,4 +113,20 @@ def write_message(message, user = 'message_bus-client') subject.resume expect(result).to eq(true) end + + it 'allows subscription exposing the message_id' do + subject.start + + text = "Hello World! #{Random.rand}" + result = false + subject.subscribe('/message') do |payload, message_id| + result = true if payload['data'] == text + expect(message_id).to be_an Integer + end + + until result + write_message(text) # Keep writing because the message bus might not have started. + sleep(1) + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 81db7d9..febe631 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,6 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) -require 'coverage_helper' require 'message_bus/client' +require "pry-byebug" # This file was generated by the `rspec --init` command. Conventionally, all # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.