pushr-fcm 1.0.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1a3a8192542a24aa3bd443d64dd96c220ee562ff24f65adc70291d35500ef3e8
4
+ data.tar.gz: 181f1c7c19232b6df6739e453560f8078c228c0d62197d1794010819511abc93
5
+ SHA512:
6
+ metadata.gz: ef695a56126a6ac381cbd4bba16b738226e08eaffa709155fa237b11400e0352bb7007915fb8b9f9f8c91305cef404e2ce6830d14709518a41856b9b8c95bd25
7
+ data.tar.gz: 7dc9d51daf53a39f3f3178388813777416764f971ce1fcedb4ef4e3cd623538872be50bce9ee63063a87fdd74290cb23fa99b1b53c1eb0f45dbea06cb9c4f547
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,7 @@
1
+ # PushrFCM
2
+
3
+ [![Build Status](https://travis-ci.org/9to5/pushr-fcm.svg?branch=master)](https://travis-ci.org/9to5/pushr-fcm)
4
+ [![Code Climate](https://codeclimate.com/github/9to5/pushr-fcm.png)](https://codeclimate.com/github/9to5/pushr-fcm)
5
+ [![Coverage Status](https://coveralls.io/repos/9to5/pushr-fcm/badge.png)](https://coveralls.io/r/9to5/pushr-fcm)
6
+
7
+ Please see [pushr-core](https://github.com/9to5/pushr-core) for more information.
@@ -0,0 +1,3 @@
1
+ module PushrFcm
2
+ VERSION = '1.0.0.pre'
3
+ end
@@ -0,0 +1,16 @@
1
+ module Pushr
2
+ class ConfigurationFcm < Pushr::Configuration
3
+ attr_accessor :service_account, :project_id
4
+ validates :service_account, presence: true
5
+ validates :project_id, presence: true
6
+
7
+ def name
8
+ :fcm
9
+ end
10
+
11
+ def to_hash
12
+ { type: self.class.to_s, app: app, enabled: enabled, connections: connections, service_account: service_account,
13
+ project_id: project_id }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ module Pushr
2
+ module Daemon
3
+ class Fcm
4
+ attr_accessor :configuration, :handlers
5
+
6
+ def initialize(options)
7
+ @configuration = options
8
+ @handlers = []
9
+ end
10
+
11
+ def start
12
+ configuration.connections.times do |i|
13
+ connection = FcmSupport::ConnectionFcm.new(configuration, i + 1)
14
+ connection.connect
15
+
16
+ handler = MessageHandler.new("pushr:#{configuration.key}", connection, configuration.app, i + 1)
17
+ handler.start
18
+ @handlers << handler
19
+ end
20
+ end
21
+
22
+ def stop
23
+ @handlers.map(&:stop)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ module Pushr
2
+ module Daemon
3
+ module FcmSupport
4
+ class JsonReader
5
+ def initialize(configuration)
6
+ @configuration = configuration
7
+ end
8
+
9
+ def read
10
+ @configuration.service_account
11
+ end
12
+ end
13
+
14
+ class Authenticator
15
+ attr_reader :configuration
16
+ SCOPE = 'https://www.googleapis.com/auth/firebase.messaging'.freeze
17
+
18
+ def initialize(configuration, i)
19
+ @configuration = configuration
20
+ @name = "#{@configuration.app}: AuthenticatorFcm #{i}"
21
+ end
22
+
23
+ def fetch_access_token
24
+ if @response.nil? || (@request_at + @response['expires_in'] < Time.now)
25
+ Pushr::Daemon.logger.info("[#{@name}] Refresh access token")
26
+ authorizer = fetch_credentials
27
+ @request_at = Time.now
28
+ @response = authorizer.fetch_access_token!
29
+ end
30
+ puts @response['access_token'].inspect
31
+ @response['access_token']
32
+ end
33
+
34
+ private
35
+
36
+ def fetch_credentials
37
+ ::Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: JsonReader.new(@configuration), scope: SCOPE)
38
+ # authorizer = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: File.open('/Users/tom/Downloads/api-7505019477374111882-459984-firebase-adminsdk-o569m-8d9bc31fb7.json'), scope: scope)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,101 @@
1
+ module Pushr
2
+ module Daemon
3
+ module FcmSupport
4
+ class ConnectionError < StandardError; end
5
+
6
+ class ConnectionFcm
7
+ attr_reader :response, :name, :configuration, :authenticator, :url
8
+ IDLE_PERIOD = 5 * 60
9
+
10
+ def initialize(configuration, i)
11
+ @configuration = configuration
12
+ @name = "#{@configuration.app}: ConnectionFcm #{i}"
13
+ @authenticator = Pushr::Daemon::FcmSupport::Authenticator.new(configuration, i)
14
+ @url = "https://fcm.googleapis.com/v1/projects/#{configuration.project_id}/messages:send"
15
+ end
16
+
17
+ def connect
18
+ @last_use = Time.now
19
+ uri = URI.parse(@url)
20
+ @connection = open_http(uri.host, uri.port)
21
+ @connection.start
22
+ Pushr::Daemon.logger.info("[#{@name}] Connected to #{@url}")
23
+ end
24
+
25
+ def write(data)
26
+ retry_count = 0
27
+ begin
28
+ puts data.to_message
29
+ response = notification_request(data.to_message)
30
+ handler = Pushr::Daemon::FcmSupport::ResponseHandler.new(response, data, retry_count)
31
+ handler.handle
32
+ rescue => e
33
+ retry_count += 1
34
+ if retry_count < 10
35
+ retry
36
+ else
37
+ raise e
38
+ end
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def open_http(host, port)
45
+ http = Net::HTTP.new(host, port)
46
+ http.use_ssl = true
47
+ http
48
+ end
49
+
50
+ def notification_request(data)
51
+ headers = { 'Authorization' => "Bearer #{@authenticator.fetch_access_token}",
52
+ 'Content-type' => 'application/json' }
53
+ uri = URI.parse(@url)
54
+ post(uri, data, headers)
55
+ end
56
+
57
+ def post(uri, data, headers)
58
+ reconnect_idle if idle_period_exceeded?
59
+
60
+ retry_count = 0
61
+
62
+ begin
63
+ response = @connection.post(uri.path, data, headers)
64
+ puts response.inspect
65
+ @last_use = Time.now
66
+ rescue EOFError, Errno::ECONNRESET, Timeout::Error => e
67
+ retry_count += 1
68
+
69
+ Pushr::Daemon.logger.error("[#{@name}] Lost connection to #{@url} (#{e.class.name}), reconnecting ##{retry_count}...")
70
+
71
+ if retry_count <= 3
72
+ reconnect
73
+ sleep 1
74
+ retry
75
+ else
76
+ raise ConnectionError, "#{@name} tried #{retry_count - 1} times to reconnect but failed (#{e.class.name})."
77
+ end
78
+ end
79
+
80
+ response
81
+ end
82
+
83
+ def idle_period_exceeded?
84
+ # Timeout on the http connection is 5 minutes, reconnect after 5 minutes
85
+ @last_use + IDLE_PERIOD < Time.now
86
+ end
87
+
88
+ def reconnect_idle
89
+ Pushr::Daemon.logger.info("[#{@name}] Idle period exceeded, reconnecting...")
90
+ reconnect
91
+ end
92
+
93
+ def reconnect
94
+ @connection.finish
95
+ @last_use = Time.now
96
+ @connection.start
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,49 @@
1
+ module Pushr
2
+ module Daemon
3
+ module FcmSupport
4
+ class ResponseHandler
5
+ attr_accessor :response, :data, :retry_count
6
+ def initialize(response, data, retry_count)
7
+ @response = response
8
+ @data = data
9
+ @retry_count = retry_count
10
+ end
11
+
12
+ def handle
13
+ case @response.code.to_i
14
+ when 200
15
+ handle_success_response
16
+ when 400
17
+ # Pushr::Daemon.logger.error("[#{@name}] JSON formatting exception received.")
18
+ Pushr::Daemon::DeliveryError.new(@response.code, @data, 'JSON formatting exception', 'FCM', false)
19
+ when 401
20
+ # Pushr::Daemon.logger.error("[#{@name}] Authentication exception received.")
21
+ Pushr::Daemon::DeliveryError.new(@response.code, @data, 'Authentication exception', 'FCM', false)
22
+ when 500..599
23
+ # internal error FCM server || service unavailable: exponential back-off
24
+ handle_error_5xx_response()
25
+ else
26
+ # Pushr::Daemon.logger.error("[#{@name}] Unknown error: #{@response.code} #{response.message}")
27
+ Pushr::Daemon::DeliveryError.new(@response.code, @data, "Unknown error: #{response.message}", 'FCM', false)
28
+ end
29
+ end
30
+
31
+ # sleep if there is a Retry-After header
32
+ def handle_error_5xx_response
33
+ value = @response.header['Retry-After']
34
+ if value && value.to_i.positive?
35
+ sleep value.to_i # Retry-After: 3600
36
+ elsif value && Date.rfc2822(value) # Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
37
+ sleep Time.now.utc - Date.rfc2822(value).to_time.utc
38
+ else
39
+ sleep 2**@retry_count
40
+ end
41
+ end
42
+
43
+ def handle_success_response()
44
+ puts @response.body.inspect
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'googleauth'
4
+ require 'active_model'
5
+ require 'pushr-fcm/version'
6
+ require 'pushr/configuration'
7
+ require 'pushr/configuration_fcm'
8
+ require 'pushr/message'
9
+ require 'pushr/message_fcm'
10
+ require 'pushr/feedback'
11
+ require 'pushr/feedback_fcm'
12
+ require 'pushr/daemon/fcm'
13
+ require 'pushr/daemon/fcm_support/response_handler'
14
+ require 'pushr/daemon/fcm_support/authenticator'
15
+ require 'pushr/daemon/fcm_support/connection_fcm'
@@ -0,0 +1,10 @@
1
+ module Pushr
2
+ class FeedbackFcm < Pushr::Feedback
3
+ attr_accessor :device, :follow_up, :failed_at, :update_to
4
+ validates :follow_up, inclusion: { in: %w(delete update), message: '%{value} is not a valid follow-up' }
5
+
6
+ def to_hash
7
+ { type: 'Pushr::FeedbackFcm', app: app, device: device, follow_up: follow_up, failed_at: failed_at, update_to: update_to }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,48 @@
1
+ module Pushr
2
+ class MessageFcm < Pushr::Message
3
+ POSTFIX = 'fcm'.freeze
4
+
5
+ attr_accessor :name, :data, :notification, :android, :webpush, :apns, :token, :topic, :condition
6
+
7
+ # {
8
+ # "name": string,
9
+ # "data": {
10
+ # string: string,
11
+ # ...
12
+ # },
13
+ # "notification": {
14
+ # object(Notification)
15
+ # },
16
+ # "android": {
17
+ # object(AndroidConfig)
18
+ # },
19
+ # "webpush": {
20
+ # object(WebpushConfig)
21
+ # },
22
+ # "apns": {
23
+ # object(ApnsConfig)
24
+ # },
25
+ #
26
+ # // Union field target can be only one of the following:
27
+ # "token": string,
28
+ # "topic": string,
29
+ # "condition": string
30
+ # // End of list of possible types for union field target.
31
+ # }
32
+
33
+ def to_message
34
+ hsh = {}
35
+ %w[name data notification android webpush apns token topic condition].each do |variable|
36
+ hsh[variable] = send(variable) if send(variable)
37
+ end
38
+ MultiJson.dump(message: hsh)
39
+ end
40
+
41
+ def to_hash
42
+ hsh = { type: self.class.to_s, app: app, name: name, data: data, notification: notification, android: android,
43
+ webpush: webpush, apns: apns, token: token, topic: topic, condition: condition }
44
+ hsh[Pushr::Core.external_id_tag] = external_id if external_id
45
+ hsh
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ require 'pushr/configuration_fcm'
3
+
4
+ describe Pushr::ConfigurationFcm do
5
+ before(:each) do
6
+ Pushr::Core.configure do |config|
7
+ config.redis = ConnectionPool.new(size: 1, timeout: 1) { MockRedis.new }
8
+ end
9
+ end
10
+
11
+ describe 'all' do
12
+ it 'returns all configurations' do
13
+ expect(Pushr::Configuration.all).to eql([])
14
+ end
15
+ end
16
+
17
+ describe 'create' do
18
+ it 'should create a configuration' do
19
+ config = Pushr::ConfigurationFcm.new(app: 'app_name', connections: 2, enabled: true)
20
+ expect(config.key).to eql('app_name:fcm')
21
+ end
22
+ end
23
+
24
+ describe 'save' do
25
+ let(:config) {
26
+ Pushr::ConfigurationFcm.new(app: 'app_name', connections: 2, enabled: true, project_id: 'project_id',
27
+ service_account: '{}')
28
+ }
29
+ it 'should save a configuration' do
30
+ config.save
31
+ expect(Pushr::Configuration.all.count).to eql(1)
32
+ expect(Pushr::Configuration.all[0].class).to eql(Pushr::ConfigurationFcm)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'pushr/daemon/fcm'
3
+ require 'pushr/daemon/fcm_support/connection_fcm'
4
+
5
+ describe Pushr::Daemon::Fcm do
6
+ let(:fcm) { Pushr::Daemon::Fcm.new(test: 'test') }
7
+
8
+ describe 'responds to' do
9
+ it 'configuration' do
10
+ expect(fcm.configuration).to eql(test: 'test')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+ require 'pushr/daemon'
3
+ require 'pushr/fcm'
4
+ require 'pushr/daemon/logger'
5
+ require 'pushr/message_fcm'
6
+ require 'pushr/configuration_fcm'
7
+ require 'pushr/daemon/delivery_error'
8
+
9
+ describe Pushr::Daemon::FcmSupport::ConnectionFcm do
10
+ before(:each) do
11
+ Pushr::Core.configure do |config|
12
+ config.redis = ConnectionPool.new(size: 1, timeout: 1) { MockRedis.new }
13
+ end
14
+
15
+ class_double('Pushr::Daemon::FcmSupport::Authenticator',
16
+ new: instance_double('Pushr::Daemon::FcmSupport::Authenticator',
17
+ fetch_access_token: 'mock_access_token')).as_stubbed_const
18
+
19
+ logger = double('logger')
20
+ allow(logger).to receive(:info)
21
+ allow(logger).to receive(:error)
22
+ allow(logger).to receive(:warn)
23
+ Pushr::Daemon.logger = logger
24
+ end
25
+
26
+ let(:config) do
27
+ Pushr::ConfigurationFcm.new(app: 'app_name', connections: 2, enabled: true, project_id: 'project_id',
28
+ service_account: '{}')
29
+ end
30
+ let(:connection) { Pushr::Daemon::FcmSupport::ConnectionFcm.new(config, 1) }
31
+
32
+ describe 'sends a message to topic' do
33
+ let(:message) do
34
+ hsh = { app: 'app_name', topic: 'test' }
35
+ Pushr::MessageFcm.new(hsh)
36
+ end
37
+
38
+ it 'succesful', :vcr do
39
+ connection.connect
40
+ connection.write(message)
41
+ # TODO: expect(connection.write(message).code).to eql '200'
42
+ end
43
+
44
+ # it 'fails and should Retry-After', :vcr do
45
+ # expect_any_instance_of(Pushr::Daemon::FcmSupport::ConnectionFcm).to receive(:sleep)
46
+ # connection.connect
47
+ # connection.write(message)
48
+ # end
49
+ #
50
+ # it 'fails and should Retry-After with date', :vcr do
51
+ # expect_any_instance_of(Pushr::Daemon::FcmSupport::ConnectionFcm).to receive(:sleep)
52
+ # connection.connect
53
+ # connection.write(message)
54
+ # end
55
+ #
56
+ # it 'fails and should sleep after fail', :vcr do
57
+ # expect_any_instance_of(Pushr::Daemon::FcmSupport::ConnectionFcm).to receive(:sleep)
58
+ # connection.connect
59
+ # connection.write(message)
60
+ # end
61
+ #
62
+ # it 'fails of a json formatting execption', :vcr do
63
+ # connection.connect
64
+ # connection.write(message)
65
+ # # TODO: assert
66
+ # end
67
+ #
68
+ # it 'fails of a not authenticated execption', :vcr do
69
+ # connection.connect
70
+ # connection.write(message)
71
+ # # TODO: assert
72
+ # end
73
+ end
74
+
75
+ describe 'sends a message to token' do
76
+ let(:message) do
77
+ hsh = { app: 'app_name', token: 'token', notification: { title: 'test', body: 'message' } }
78
+ Pushr::MessageFcm.new(hsh)
79
+ end
80
+
81
+ it 'succesful', :vcr do
82
+ connection.connect
83
+ connection.write(message)
84
+ # TODO: expect(connection.write(message).code).to eql '200'
85
+ end
86
+ end
87
+
88
+ describe 'sends a message to condition' do
89
+ let(:message) do
90
+ hsh = { app: 'app_name', condition: "'foo' in topics && 'bar' in topics'" }
91
+ Pushr::MessageFcm.new(hsh)
92
+ end
93
+
94
+ it 'succesful', :vcr do
95
+ connection.connect
96
+ connection.write(message)
97
+ # TODO: expect(connection.write(message).code).to eql '200'
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ require 'pushr/daemon'
3
+ require 'pushr/fcm'
4
+ require 'pushr/feedback_fcm'
5
+ require 'pushr/message_fcm'
6
+
7
+ describe Pushr::Daemon::FcmSupport::ResponseHandler do
8
+ it 'should handle no errors' do
9
+ json = '{"name": "projects/project_id/messages/9216177826578065331"}'
10
+ response = double('response')
11
+ allow(response).to receive(:body).and_return(json)
12
+ allow(response).to receive(:code).and_return('200')
13
+
14
+ message = double('message')
15
+ handler = Pushr::Daemon::FcmSupport::ResponseHandler.new(response, message, 0)
16
+ handler.handle
17
+ # TODO: assert
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'pushr/feedback_fcm'
3
+
4
+ describe Pushr::FeedbackFcm do
5
+ before(:each) do
6
+ Pushr::Core.configure do |config|
7
+ config.redis = ConnectionPool.new(size: 1, timeout: 1) { MockRedis.new }
8
+ end
9
+ end
10
+
11
+ describe 'create' do
12
+ it 'should create a feedback' do
13
+ feedback = Pushr::FeedbackFcm.new(app: 'app_name', device: 'ab' * 20, follow_up: 'delete', failed_at: Time.now, update_to: nil)
14
+ expect(feedback.app).to eql('app_name')
15
+ end
16
+ end
17
+
18
+ describe 'save' do
19
+ let!(:feedback) do
20
+ Pushr::FeedbackFcm.create(app: 'app_name', device: 'ab' * 20, follow_up: 'delete', failed_at: Time.now,
21
+ update_to: nil)
22
+ end
23
+ it 'should save a feedback' do
24
+ expect(Pushr::Feedback.next.class).to eql(Pushr::FeedbackFcm)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require 'pushr/message_fcm'
3
+
4
+ describe Pushr::MessageFcm do
5
+ before(:each) do
6
+ Pushr::Core.configure do |config|
7
+ config.redis = ConnectionPool.new(size: 1, timeout: 1) { MockRedis.new }
8
+ end
9
+ end
10
+
11
+ describe 'next' do
12
+ it 'returns next message' do
13
+ expect(Pushr::Message.next('pushr:app_name:fcm')).to eql(nil)
14
+ end
15
+ end
16
+
17
+ describe 'save' do
18
+ let(:message) do
19
+ hsh = { app: 'app_name', token: 'test' }
20
+ Pushr::MessageFcm.new(hsh)
21
+ end
22
+
23
+ it 'should return true' do
24
+ expect(message.save).to eql true
25
+ end
26
+ it 'should save a message' do
27
+ message.save
28
+ expect(Pushr::Message.next('pushr:app_name:fcm')).to be_kind_of(Pushr::MessageFcm)
29
+ end
30
+ it 'should respond to to_message' do
31
+ expect(message.to_message).to be_kind_of(String)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+
6
+ require 'simplecov'
7
+ require 'coveralls'
8
+
9
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
10
+ SimpleCov::Formatter::HTMLFormatter,
11
+ Coveralls::SimpleCov::Formatter
12
+ ])
13
+ SimpleCov.start
14
+
15
+ require 'vcr'
16
+ require 'pushr/core'
17
+ require 'mock_redis'
18
+
19
+ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
20
+
21
+ RSpec.configure do |config|
22
+ config.raise_errors_for_deprecations!
23
+ config.run_all_when_everything_filtered = true
24
+ # config.filter_run :focus
25
+
26
+ # Run specs in random order to surface order dependencies. If you find an
27
+ # order dependency and want to debug it, you can fix the order by providing
28
+ # the seed, which is printed after each run.
29
+ # --seed 1234
30
+ config.order = 'random'
31
+
32
+ config.around(:each, :vcr) do |example|
33
+ name = example.metadata[:full_description].split(/\s+/, 2).join('/').underscore.gsub(/[^\w\/]+/, '_')
34
+ options = example.metadata.slice(:record, :match_requests_on).except(:example_group)
35
+ VCR.use_cassette(name, options) { example.call }
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ VCR.configure do |c|
2
+ c.cassette_library_dir = File.join(Dir.pwd, 'spec', 'vcr')
3
+ c.hook_into :webmock
4
+ end
@@ -0,0 +1,55 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://fcm.googleapis.com/v1/projects/project_id/messages:send
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"message":{"condition":"''foo'' in topics && ''bar'' in topics''"}}'
9
+ headers:
10
+ Authorization:
11
+ - Bearer mock_access_token
12
+ Content-Type:
13
+ - application/json
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Content-Type:
26
+ - application/json; charset=UTF-8
27
+ Vary:
28
+ - Origin
29
+ - Referer
30
+ - X-Origin
31
+ Date:
32
+ - Thu, 18 Oct 2018 10:51:49 GMT
33
+ Server:
34
+ - ESF
35
+ Cache-Control:
36
+ - private
37
+ X-Xss-Protection:
38
+ - 1; mode=block
39
+ X-Frame-Options:
40
+ - SAMEORIGIN
41
+ X-Content-Type-Options:
42
+ - nosniff
43
+ Alt-Svc:
44
+ - quic=":443"; ma=2592000; v="44,43,39,35"
45
+ Transfer-Encoding:
46
+ - chunked
47
+ body:
48
+ encoding: ASCII-8BIT
49
+ string: |
50
+ {
51
+ "name": "projects/project_id/messages/6508272921236107021"
52
+ }
53
+ http_version:
54
+ recorded_at: Thu, 18 Oct 2018 10:51:49 GMT
55
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,55 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://fcm.googleapis.com/v1/projects/project_id/messages:send
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"message":{"notification":{"title":"test","body":"message"},"token":"token"}}'
9
+ headers:
10
+ Authorization:
11
+ - Bearer mock_access_token
12
+ Content-Type:
13
+ - application/json
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Content-Type:
26
+ - application/json; charset=UTF-8
27
+ Vary:
28
+ - Origin
29
+ - Referer
30
+ - X-Origin
31
+ Date:
32
+ - Thu, 18 Oct 2018 10:45:32 GMT
33
+ Server:
34
+ - ESF
35
+ Cache-Control:
36
+ - private
37
+ X-Xss-Protection:
38
+ - 1; mode=block
39
+ X-Frame-Options:
40
+ - SAMEORIGIN
41
+ X-Content-Type-Options:
42
+ - nosniff
43
+ Alt-Svc:
44
+ - quic=":443"; ma=2592000; v="44,43,39,35"
45
+ Transfer-Encoding:
46
+ - chunked
47
+ body:
48
+ encoding: ASCII-8BIT
49
+ string: |
50
+ {
51
+ "name": "projects/project_id/messages/0:1539859532406104%b949fa49b949fa49"
52
+ }
53
+ http_version:
54
+ recorded_at: Thu, 18 Oct 2018 10:45:32 GMT
55
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,55 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://fcm.googleapis.com/v1/projects/project_id/messages:send
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"message":{"topic":"test"}}'
9
+ headers:
10
+ Authorization:
11
+ - Bearer mock_access_token
12
+ Content-Type:
13
+ - application/json
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Content-Type:
26
+ - application/json; charset=UTF-8
27
+ Vary:
28
+ - Origin
29
+ - Referer
30
+ - X-Origin
31
+ Date:
32
+ - Thu, 18 Oct 2018 07:37:33 GMT
33
+ Server:
34
+ - ESF
35
+ Cache-Control:
36
+ - private
37
+ X-Xss-Protection:
38
+ - 1; mode=block
39
+ X-Frame-Options:
40
+ - SAMEORIGIN
41
+ X-Content-Type-Options:
42
+ - nosniff
43
+ Alt-Svc:
44
+ - quic=":443"; ma=2592000; v="44,43,39,35"
45
+ Transfer-Encoding:
46
+ - chunked
47
+ body:
48
+ encoding: ASCII-8BIT
49
+ string: |
50
+ {
51
+ "name": "projects/project_id/messages/9216177826578065331"
52
+ }
53
+ http_version:
54
+ recorded_at: Thu, 18 Oct 2018 07:37:33 GMT
55
+ recorded_with: VCR 4.0.0
metadata ADDED
@@ -0,0 +1,273 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pushr-fcm
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.pre
5
+ platform: ruby
6
+ authors:
7
+ - Tom Pesman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-10-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: multi_json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pushr-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activemodel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: googleauth
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: mock_redis
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: webmock
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: vcr
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rake
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: coveralls
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: rubocop
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ description: FCM support for the modular push daemon.
210
+ email:
211
+ - tom@tnux.net
212
+ executables: []
213
+ extensions: []
214
+ extra_rdoc_files: []
215
+ files:
216
+ - MIT-LICENSE
217
+ - README.md
218
+ - lib/pushr-fcm/version.rb
219
+ - lib/pushr/configuration_fcm.rb
220
+ - lib/pushr/daemon/fcm.rb
221
+ - lib/pushr/daemon/fcm_support/authenticator.rb
222
+ - lib/pushr/daemon/fcm_support/connection_fcm.rb
223
+ - lib/pushr/daemon/fcm_support/response_handler.rb
224
+ - lib/pushr/fcm.rb
225
+ - lib/pushr/feedback_fcm.rb
226
+ - lib/pushr/message_fcm.rb
227
+ - spec/lib/pushr/configuration_fcm_spec.rb
228
+ - spec/lib/pushr/daemon/fcm_spec.rb
229
+ - spec/lib/pushr/daemon/fcm_support/connection_fcm_spec.rb
230
+ - spec/lib/pushr/daemon/fcm_support/response_handler_spec.rb
231
+ - spec/lib/pushr/feedback_fcm_spec.rb
232
+ - spec/lib/pushr/message_fcm_spec.rb
233
+ - spec/spec_helper.rb
234
+ - spec/support/vcr.rb
235
+ - spec/vcr/pushr/daemon/fcm_support/connection_fcm/sends_a_message_to_condition_succesful.yml
236
+ - spec/vcr/pushr/daemon/fcm_support/connection_fcm/sends_a_message_to_token_succesful.yml
237
+ - spec/vcr/pushr/daemon/fcm_support/connection_fcm/sends_a_message_to_topic_succesful.yml
238
+ homepage: https://github.com/9to5/pushr-fcm
239
+ licenses:
240
+ - MIT
241
+ metadata: {}
242
+ post_install_message:
243
+ rdoc_options: []
244
+ require_paths:
245
+ - lib
246
+ required_ruby_version: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: 2.2.0
251
+ required_rubygems_version: !ruby/object:Gem::Requirement
252
+ requirements:
253
+ - - ">"
254
+ - !ruby/object:Gem::Version
255
+ version: 1.3.1
256
+ requirements: []
257
+ rubyforge_project:
258
+ rubygems_version: 2.7.6
259
+ signing_key:
260
+ specification_version: 4
261
+ summary: FCM (Android) part of the modular push daemon.
262
+ test_files:
263
+ - spec/lib/pushr/configuration_fcm_spec.rb
264
+ - spec/lib/pushr/daemon/fcm_spec.rb
265
+ - spec/lib/pushr/daemon/fcm_support/connection_fcm_spec.rb
266
+ - spec/lib/pushr/daemon/fcm_support/response_handler_spec.rb
267
+ - spec/lib/pushr/feedback_fcm_spec.rb
268
+ - spec/lib/pushr/message_fcm_spec.rb
269
+ - spec/spec_helper.rb
270
+ - spec/support/vcr.rb
271
+ - spec/vcr/pushr/daemon/fcm_support/connection_fcm/sends_a_message_to_condition_succesful.yml
272
+ - spec/vcr/pushr/daemon/fcm_support/connection_fcm/sends_a_message_to_token_succesful.yml
273
+ - spec/vcr/pushr/daemon/fcm_support/connection_fcm/sends_a_message_to_topic_succesful.yml