streamforce 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -8
- data/README.md +69 -1
- data/lib/streamforce/client.rb +55 -55
- data/lib/streamforce/extension/logging.rb +88 -9
- data/lib/streamforce/extension/replay.rb +22 -0
- data/lib/streamforce/message.rb +49 -0
- data/lib/streamforce/version.rb +1 -1
- data/lib/streamforce.rb +0 -1
- metadata +54 -12
- data/lib/streamforce/extension/subscription_tracking.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d03ff265d884babb70b8db70637c9814a5819834ed83109b2b26537cb5c992b
|
4
|
+
data.tar.gz: b7b87b62347f92e9a27139536655ee95339e8a3b22bf2c1980db1eca00fa66e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4dc737d70d28c061ee3c89379b97274983c14008184acbe7c99139b59c3ed79b3ef79893ba3d486d3f142172d30461260237d171bdb7a230c6f92471769a605
|
7
|
+
data.tar.gz: 6a3bbd281947060861c34e5cceab6814cfad52a80e964c80ef4da4956a3c40287e1315ef05419c69b31e60ac2bd20b394336e85a087c8fd41e22691543f6f7d7
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,76 @@
|
|
1
1
|
# Streamforce
|
2
2
|
|
3
|
+
In most cases, processing events received from the Salesforce Streaming API can be
|
4
|
+
broken down into three very specific steps:
|
5
|
+
|
6
|
+
1. Connecting to the Salesforce API and listening for messaging
|
7
|
+
2. Ingesting received messages into some sort of internal event bus (e.g. RabbitMQ,
|
8
|
+
Kafka, Redis, etc)
|
9
|
+
3. Processing the stored messages
|
10
|
+
|
11
|
+
Streamforce aims to handle #1 and simplify the work done for #2.
|
12
|
+
|
13
|
+
[Restforce](https://github.com/restforce/restforce) provides a simple API to connect
|
14
|
+
to the Streaming API and consume messages:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
# Restforce uses faye as the underlying implementation for CometD.
|
18
|
+
require 'faye'
|
19
|
+
|
20
|
+
# Initialize a client with your username/password/oauth token/etc.
|
21
|
+
client = Restforce.new(username: 'foo',
|
22
|
+
password: 'bar',
|
23
|
+
security_token: 'security token',
|
24
|
+
client_id: 'client_id',
|
25
|
+
client_secret: 'client_secret')
|
26
|
+
|
27
|
+
EM.run do
|
28
|
+
# Subscribe to the PushTopic.
|
29
|
+
client.subscription '/topic/AllAccounts' do |message|
|
30
|
+
puts message.inspect
|
31
|
+
end
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
However, the above code is usable in a production environment because:
|
36
|
+
|
37
|
+
* The interactions with the Streaming API need to be logged using the correct severity
|
38
|
+
(e.g. handshakes should use `Logger::DEBUG` while subscription errors should use
|
39
|
+
`Logger::ERROR` for better visibility)
|
40
|
+
* Replay IDs need to be stored using a persistent storage like Redis and not in-memory
|
41
|
+
|
42
|
+
Streamforce comes with all the batteries included.
|
43
|
+
|
44
|
+
## Usage
|
45
|
+
|
46
|
+
A very simple client, which automatically connects based on the following environment
|
47
|
+
variables:
|
48
|
+
|
49
|
+
* `SALESFORCE_USERNAME`
|
50
|
+
* `SALESFORCE_PASSWORD`
|
51
|
+
* `SALESFORCE_SECURITY_TOKEN`
|
52
|
+
* `SALESFORCE_CLIENT_ID`
|
53
|
+
* `SALESFORCE_CLIENT_SECRET`
|
54
|
+
* `REDIS_URL`
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
require "streamforce"
|
58
|
+
|
59
|
+
client = Streamforce::Client.new
|
60
|
+
|
61
|
+
subscriptions = %w[
|
62
|
+
/topic/account-monitor
|
63
|
+
/event/AccountUpdated__e
|
64
|
+
]
|
65
|
+
|
66
|
+
client.subscribe(subscriptions) do |subscription, message|
|
67
|
+
# Your code
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
3
71
|
## Contributing
|
4
72
|
|
5
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/andreimaxim/streamforce
|
73
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/andreimaxim/streamforce>.
|
6
74
|
|
7
75
|
## License
|
8
76
|
|
data/lib/streamforce/client.rb
CHANGED
@@ -1,79 +1,79 @@
|
|
1
1
|
class Streamforce::Client
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def password
|
20
|
-
ENV["SALESFORCE_PASSWORD"]
|
21
|
-
end
|
22
|
-
|
23
|
-
def security_token
|
24
|
-
ENV["SALESFORCE_SECURITY_TOKEN"]
|
25
|
-
end
|
2
|
+
attr_reader :host, :username, :password, :client_id, :client_secret, :security_token,
|
3
|
+
:api_version
|
4
|
+
|
5
|
+
def initialize(opts = {})
|
6
|
+
@host = opts.fetch(:host, ENV["SALESFORCE_HOST"])
|
7
|
+
@username = opts.fetch(:username, ENV["SALESFORCE_USERNAME"])
|
8
|
+
@password = opts.fetch(:password, ENV["SALESFORCE_PASSWORD"])
|
9
|
+
@client_id = opts.fetch(:client_id, ENV["SALESFORCE_CLIENT_ID"])
|
10
|
+
@client_secret = opts.fetch(:client_secret, ENV["SALESFORCE_CLIENT_SECRET"])
|
11
|
+
@security_token = opts.fetch(:security_token, ENV["SALESFORCE_SECURITY_TOKEN"])
|
12
|
+
@api_version = opts.fetch(:api_version, ENV["SALESFORCE_API_VERSION"])
|
13
|
+
|
14
|
+
@logger = opts.fetch(:logger, Logger.new($stdout))
|
15
|
+
@logger.level = ENV.fetch("STREAMFORCE_LOG_LEVEL", Logger::INFO)
|
16
|
+
end
|
26
17
|
|
27
|
-
|
28
|
-
|
29
|
-
|
18
|
+
def subscribe(channels = [], &blk)
|
19
|
+
EM.run { subscribe_to_channels(faye, Array(channels), &blk) }
|
20
|
+
end
|
30
21
|
|
31
|
-
|
32
|
-
URI.parse("https://#{host}/services/oauth2/token")
|
33
|
-
end
|
22
|
+
private
|
34
23
|
|
35
|
-
|
36
|
-
|
37
|
-
grant_type: "password",
|
38
|
-
client_id: client_id,
|
39
|
-
client_secret: client_secret,
|
40
|
-
username: username,
|
41
|
-
password: "#{password}#{security_token}"
|
42
|
-
}
|
43
|
-
end
|
24
|
+
def instance_url
|
25
|
+
authentication["instance_url"]
|
44
26
|
end
|
45
27
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
28
|
+
def access_token
|
29
|
+
authentication["access_token"]
|
30
|
+
end
|
49
31
|
|
50
|
-
|
51
|
-
|
32
|
+
def authentication_url
|
33
|
+
URI.parse("https://#{host}/services/oauth2/token")
|
52
34
|
end
|
53
35
|
|
54
|
-
def
|
55
|
-
|
36
|
+
def authentication_params
|
37
|
+
{
|
38
|
+
grant_type: "password",
|
39
|
+
username: username,
|
40
|
+
password: "#{password}#{security_token}",
|
41
|
+
client_id: client_id,
|
42
|
+
client_secret: client_secret
|
43
|
+
}
|
44
|
+
end
|
56
45
|
|
57
|
-
|
46
|
+
def authentication
|
47
|
+
@authentication ||= fetch_authentication_credentials
|
48
|
+
end
|
58
49
|
|
59
|
-
|
50
|
+
def fetch_authentication_credentials
|
51
|
+
response = Net::HTTP.post_form(authentication_url, authentication_params)
|
52
|
+
JSON.parse(response.body)
|
60
53
|
end
|
61
54
|
|
62
55
|
def faye
|
63
|
-
@faye ||= Faye::Client.new(
|
64
|
-
client.set_header "Authorization", "OAuth #{
|
56
|
+
@faye ||= Faye::Client.new("#{instance_url}/cometd/#{api_version}").tap do |client|
|
57
|
+
client.set_header "Authorization", "OAuth #{access_token}"
|
65
58
|
|
66
59
|
client.add_extension Streamforce::Extension::Replay.new
|
67
|
-
client.add_extension Streamforce::Extension::
|
68
|
-
client.add_extension Streamforce::Extension::Logging.new
|
60
|
+
client.add_extension Streamforce::Extension::Logging.new(@logger)
|
69
61
|
end
|
70
62
|
end
|
71
63
|
|
72
64
|
def subscribe_to_channels(client, channels, &blk)
|
73
65
|
return if channels.empty?
|
74
66
|
|
75
|
-
|
76
|
-
|
77
|
-
|
67
|
+
# Subscribe to a single channel, otherwise Salesforce will return a 403 Unknown Client error
|
68
|
+
subscription = client.subscribe(channels.shift)
|
69
|
+
|
70
|
+
# Allow clients to receive [ channel, message ] block params
|
71
|
+
subscription.with_channel(&blk)
|
72
|
+
|
73
|
+
# Continue subscribing to the rest of the channels, regadless of the current subscription
|
74
|
+
# status
|
75
|
+
subscription
|
76
|
+
.callback { subscribe_to_channels(client, channels, &blk) }
|
77
|
+
.errback { subscribe_to_channels(client, channels, &blk) }
|
78
78
|
end
|
79
79
|
end
|
@@ -1,18 +1,97 @@
|
|
1
1
|
class Streamforce::Extension::Logging
|
2
|
-
def initialize(
|
3
|
-
@logger =
|
4
|
-
@logger.level = log_level
|
2
|
+
def initialize(logger)
|
3
|
+
@logger = logger
|
5
4
|
end
|
6
5
|
|
7
|
-
def incoming(
|
8
|
-
|
6
|
+
def incoming(payload, callback)
|
7
|
+
message = Streamforce::Message.new(payload)
|
8
|
+
log_incoming_message(message)
|
9
9
|
|
10
|
-
callback.call(
|
10
|
+
callback.call(payload)
|
11
11
|
end
|
12
12
|
|
13
|
-
def outgoing(
|
14
|
-
|
13
|
+
def outgoing(payload, callback)
|
14
|
+
message = Streamforce::Message.new(payload)
|
15
|
+
log_outgoing_message(message)
|
15
16
|
|
16
|
-
callback.call(
|
17
|
+
callback.call(payload)
|
18
|
+
end
|
19
|
+
|
20
|
+
def log_incoming_message(message)
|
21
|
+
if message.channel_type == "meta"
|
22
|
+
public_send("log_incoming_#{message.channel_name}", message)
|
23
|
+
else
|
24
|
+
@logger.debug "[#{message.channel_name}] #{message.data}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def log_outgoing_message(message)
|
29
|
+
if message.channel_type == "meta"
|
30
|
+
public_send("log_outgoing_#{message.channel_name}", message)
|
31
|
+
else
|
32
|
+
@logger.debug "[#{message.channel_name}] #{message.data}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def log_outgoing_handshake(message)
|
37
|
+
@logger.debug "[Client] Handshake requested..."
|
38
|
+
end
|
39
|
+
|
40
|
+
def log_incoming_handshake(message)
|
41
|
+
if message.success?
|
42
|
+
@logger.debug "[Server] Handshake accepted, assigning client_id=#{message.client_id}"
|
43
|
+
else
|
44
|
+
@logger.error "[Server] Connection was refused: #{message.error_message}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def log_outgoing_connect(message)
|
49
|
+
debug message, "Sending connection request"
|
50
|
+
end
|
51
|
+
|
52
|
+
def log_incoming_connect(message)
|
53
|
+
if message.success?
|
54
|
+
debug message, "Connection successful!"
|
55
|
+
else
|
56
|
+
error message, "Connection failed: #{message.error_message}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def log_outgoing_subscribe(message)
|
61
|
+
replay_id = message.replay_id
|
62
|
+
|
63
|
+
replay_info = if replay_id == -1
|
64
|
+
"for all new messages"
|
65
|
+
elsif replay_id == -2
|
66
|
+
"and requesting all stored messages"
|
67
|
+
else
|
68
|
+
"and requesting all messages newer than ##{replay_id}"
|
69
|
+
end
|
70
|
+
|
71
|
+
info message, "Subscribing to #{message.subscription} #{replay_info}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def log_incoming_subscribe(message)
|
75
|
+
if message.success?
|
76
|
+
info message, "Successfully subscribed to #{message.subscription}"
|
77
|
+
else
|
78
|
+
error message, "Subscription for #{message.subscription} failed: #{message.error_message}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def debug(message, text)
|
83
|
+
@logger.debug "[#{message.client_id}##{message.id}] #{text}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def info(message, text)
|
87
|
+
@logger.info "[#{message.client_id}##{message.id}] #{text}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def warn(message, text)
|
91
|
+
@logger.warn "[#{message.client_id}##{message.id}] #{text}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def error(message, text)
|
95
|
+
@logger.error "[#{message.client_id}##{message.id}] #{text}"
|
17
96
|
end
|
18
97
|
end
|
@@ -1,14 +1,36 @@
|
|
1
|
+
require "redis"
|
2
|
+
|
1
3
|
class Streamforce::Extension::Replay
|
2
4
|
def initialize(log_level = Logger::INFO)
|
3
5
|
@logger = Logger.new($stdout)
|
4
6
|
@logger.level = log_level
|
7
|
+
@redis = Redis.new
|
5
8
|
end
|
6
9
|
|
7
10
|
def incoming(message, callback)
|
11
|
+
replay_id = message.dig "data", "event", "replayId"
|
12
|
+
channel = message["channel"]
|
13
|
+
|
14
|
+
store(channel, replay_id)
|
8
15
|
callback.call(message)
|
9
16
|
end
|
10
17
|
|
11
18
|
def outgoing(message, callback)
|
19
|
+
return callback.call(message) unless message["channel"] == "/meta/subscribe"
|
20
|
+
|
21
|
+
channel = message["subscription"]
|
22
|
+
message["ext"] = { "replay" => { channel => replay_id(channel).to_i } }
|
23
|
+
|
12
24
|
callback.call(message)
|
13
25
|
end
|
26
|
+
|
27
|
+
def store(channel, replay_id)
|
28
|
+
return if channel.nil? || replay_id.nil?
|
29
|
+
|
30
|
+
@redis.set channel, replay_id, ex: 86400
|
31
|
+
end
|
32
|
+
|
33
|
+
def replay_id(channel)
|
34
|
+
@redis.get(channel) || -1
|
35
|
+
end
|
14
36
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Streamforce::Message
|
2
|
+
def initialize(payload)
|
3
|
+
@payload = payload
|
4
|
+
end
|
5
|
+
|
6
|
+
def success?
|
7
|
+
@payload["successful"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def id
|
11
|
+
@payload["id"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def replay_id
|
15
|
+
@payload.dig "ext", "replay", subscription
|
16
|
+
end
|
17
|
+
|
18
|
+
def channel
|
19
|
+
@payload["channel"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def client_id
|
23
|
+
@payload["clientId"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def channel_type
|
27
|
+
channel.split("/")[1]
|
28
|
+
end
|
29
|
+
|
30
|
+
def channel_name
|
31
|
+
channel.split("/")[2]
|
32
|
+
end
|
33
|
+
|
34
|
+
def data
|
35
|
+
@payload["data"]
|
36
|
+
end
|
37
|
+
|
38
|
+
def subscription
|
39
|
+
@payload["subscription"]
|
40
|
+
end
|
41
|
+
|
42
|
+
def subscription?
|
43
|
+
channel == "/meta/subscribe"
|
44
|
+
end
|
45
|
+
|
46
|
+
def error_message
|
47
|
+
@payload["error"]
|
48
|
+
end
|
49
|
+
end
|
data/lib/streamforce/version.rb
CHANGED
data/lib/streamforce.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: streamforce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrei Maxim
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-06-
|
11
|
+
date: 2024-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: zeitwerk
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: faye
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: relaxed_cookiejar
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: redis
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -66,7 +66,49 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
-
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest
|
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: rubocop-rails-omakase
|
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
|
+
description:
|
70
112
|
email:
|
71
113
|
- andrei@andreimaxim.ro
|
72
114
|
executables: []
|
@@ -82,7 +124,7 @@ files:
|
|
82
124
|
- lib/streamforce/client.rb
|
83
125
|
- lib/streamforce/extension/logging.rb
|
84
126
|
- lib/streamforce/extension/replay.rb
|
85
|
-
- lib/streamforce/
|
127
|
+
- lib/streamforce/message.rb
|
86
128
|
- lib/streamforce/version.rb
|
87
129
|
homepage: https://github.com/andreimaxim/streamforce
|
88
130
|
licenses:
|
@@ -91,7 +133,7 @@ metadata:
|
|
91
133
|
homepage_uri: https://github.com/andreimaxim/streamforce
|
92
134
|
source_code_uri: https://github.com/andreimaxim/streamforce
|
93
135
|
changelog_uri: https://github.com/andreimaxim/streamforce/blob/main/CHANGELOG.md
|
94
|
-
post_install_message:
|
136
|
+
post_install_message:
|
95
137
|
rdoc_options: []
|
96
138
|
require_paths:
|
97
139
|
- lib
|
@@ -99,7 +141,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
99
141
|
requirements:
|
100
142
|
- - ">="
|
101
143
|
- !ruby/object:Gem::Version
|
102
|
-
version: 3.
|
144
|
+
version: 3.0.0
|
103
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
146
|
requirements:
|
105
147
|
- - ">="
|
@@ -107,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
149
|
version: '0'
|
108
150
|
requirements: []
|
109
151
|
rubygems_version: 3.5.9
|
110
|
-
signing_key:
|
152
|
+
signing_key:
|
111
153
|
specification_version: 4
|
112
154
|
summary: Small wrapper over the Salesforce Streaming API
|
113
155
|
test_files: []
|
@@ -1,58 +0,0 @@
|
|
1
|
-
class Streamforce::Extension::SubscriptionTracking
|
2
|
-
def initialize(log_level = Logger::DEBUG)
|
3
|
-
@logger = Logger.new($stdout)
|
4
|
-
@logger.level = log_level
|
5
|
-
|
6
|
-
@subscriptions = []
|
7
|
-
end
|
8
|
-
|
9
|
-
def incoming(message, callback)
|
10
|
-
if subscription?(message)
|
11
|
-
log_subscription_status(message)
|
12
|
-
else
|
13
|
-
log_subscription_payload(message)
|
14
|
-
end
|
15
|
-
|
16
|
-
callback.call(message)
|
17
|
-
end
|
18
|
-
|
19
|
-
def outgoing(message, callback)
|
20
|
-
@logger.debug "Requested subscription for #{message["subscription"]}" if subscription?(message)
|
21
|
-
|
22
|
-
callback.call(message)
|
23
|
-
end
|
24
|
-
|
25
|
-
def log_subscription_status(message)
|
26
|
-
subscription = message["subscription"]
|
27
|
-
|
28
|
-
if message["successful"]
|
29
|
-
@subscriptions << subscription
|
30
|
-
|
31
|
-
@logger.info "Subscription for #{subscription} was successful"
|
32
|
-
else
|
33
|
-
@logger.warn "Subscription for #{subscription} failed: #{message["error"]}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def log_subscription_payload(message)
|
38
|
-
channel = message["channel"]
|
39
|
-
payload = message["data"].to_json
|
40
|
-
|
41
|
-
type = case channel.split("/")[1]
|
42
|
-
when "topic"
|
43
|
-
"PushTopic"
|
44
|
-
when "event"
|
45
|
-
"PlatformEvent"
|
46
|
-
else
|
47
|
-
"Unknown"
|
48
|
-
end
|
49
|
-
|
50
|
-
name = channel.split("/")[2]
|
51
|
-
|
52
|
-
@logger.info "[#{type}][#{name}]: #{payload}" if @subscriptions.include?(channel)
|
53
|
-
end
|
54
|
-
|
55
|
-
def subscription?(message)
|
56
|
-
message["channel"] == "/meta/subscribe"
|
57
|
-
end
|
58
|
-
end
|