streamforce 0.0.1 → 0.1.1
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -8
- data/README.md +46 -1
- data/lib/streamforce/client.rb +55 -55
- data/lib/streamforce/extension/logging.rb +84 -9
- data/lib/streamforce/extension/replay.rb +22 -0
- data/lib/streamforce/message.rb +61 -0
- data/lib/streamforce/version.rb +1 -1
- data/lib/streamforce.rb +0 -1
- metadata +50 -8
- 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: 39b60e818f6a705ee63949e7ff6a48858565917a737691cb6a94c109e37f7342
|
|
4
|
+
data.tar.gz: ca563677771ec54e9fbef2a3ddf4de157d59d3e879ad9f7ad8841269da02bed3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1491f1d6772bf34b393879dfdec8b18b6310e28fcfcafe6f8136994b9c7667c09e07221a8dd52f032e9d746771802f80b87356534b65f33b2ba1a33290520f9a
|
|
7
|
+
data.tar.gz: fde46e8c412e01be566741d5474216ea55ea3e77f83cf29f19a3cd417017d646c64f9140cf153bd727a88997e9698fc7f54decf906cf0581b586e6c21c77e226
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
|
@@ -1,8 +1,53 @@
|
|
|
1
1
|
# Streamforce
|
|
2
2
|
|
|
3
|
+
In most cases, consuming 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 messages
|
|
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 be an abstraction for the first step, by implementing some of the
|
|
12
|
+
common tasks that need to be performed by any well-behaved client:
|
|
13
|
+
|
|
14
|
+
* The interactions with the Streaming API need to be logged using the correct severity
|
|
15
|
+
(e.g. handshakes should use `Logger::DEBUG` while subscription errors should use
|
|
16
|
+
`Logger::ERROR` for better visibility)
|
|
17
|
+
* Replay IDs need to be stored using a persistent storage like Redis and not in-memory
|
|
18
|
+
|
|
19
|
+
As an alternative, checkout [Restforce](https://github.com/restforce/restforce).
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
A very simple client, which automatically connects based on the following environment
|
|
24
|
+
variables:
|
|
25
|
+
|
|
26
|
+
* `SALESFORCE_USERNAME`
|
|
27
|
+
* `SALESFORCE_PASSWORD`
|
|
28
|
+
* `SALESFORCE_SECURITY_TOKEN`
|
|
29
|
+
* `SALESFORCE_CLIENT_ID`
|
|
30
|
+
* `SALESFORCE_CLIENT_SECRET`
|
|
31
|
+
* `REDIS_URL`
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require "streamforce"
|
|
35
|
+
|
|
36
|
+
client = Streamforce::Client.new
|
|
37
|
+
|
|
38
|
+
subscriptions = %w[
|
|
39
|
+
/topic/account-monitor
|
|
40
|
+
/event/AccountUpdated__e
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
client.subscribe(subscriptions) do |subscription, message|
|
|
44
|
+
# Your code
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
3
48
|
## Contributing
|
|
4
49
|
|
|
5
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/andreimaxim/streamforce
|
|
50
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/andreimaxim/streamforce>.
|
|
6
51
|
|
|
7
52
|
## License
|
|
8
53
|
|
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,93 @@
|
|
|
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)
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
case message.channel
|
|
10
|
+
when "/meta/handshake"
|
|
11
|
+
log_incoming_handshake(message)
|
|
12
|
+
when "/meta/connect"
|
|
13
|
+
log_incoming_connect(message)
|
|
14
|
+
when "/meta/subscribe"
|
|
15
|
+
log_incoming_subscribe(message)
|
|
16
|
+
else
|
|
17
|
+
@logger.debug "[#{message.channel}] #{message.data}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
callback.call(payload)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def outgoing(payload, callback)
|
|
24
|
+
message = Streamforce::Message.new(payload)
|
|
25
|
+
|
|
26
|
+
case message.channel
|
|
27
|
+
when "/meta/handshake"
|
|
28
|
+
@logger.debug "[Client] Handshake requested..."
|
|
29
|
+
when "/meta/connect"
|
|
30
|
+
debug message, "Sending connection request"
|
|
31
|
+
when "/meta/subscribe"
|
|
32
|
+
log_outgoing_subscribe(message)
|
|
33
|
+
else
|
|
34
|
+
@logger.debug "[#{message.channel}] #{message.data}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
callback.call(payload)
|
|
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_incoming_connect(message)
|
|
49
|
+
if message.success?
|
|
50
|
+
debug message, "Connection successful!"
|
|
51
|
+
else
|
|
52
|
+
error message, "Connection failed: #{message.error_message}"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def log_outgoing_subscribe(message)
|
|
57
|
+
replay_id = message.replay_id
|
|
58
|
+
|
|
59
|
+
replay_info = if message.no_replay?
|
|
60
|
+
"for all new messages"
|
|
61
|
+
elsif message.replay_available_messages?
|
|
62
|
+
"and requesting all stored messages"
|
|
63
|
+
else
|
|
64
|
+
"and requesting all messages newer than ##{replay_id}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
info message, "Subscribing to #{message.subscription} #{replay_info}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def log_incoming_subscribe(message)
|
|
71
|
+
if message.success?
|
|
72
|
+
info message, "Successfully subscribed to #{message.subscription}"
|
|
73
|
+
else
|
|
74
|
+
error message, "Subscription for #{message.subscription} failed: #{message.error_message}"
|
|
75
|
+
end
|
|
11
76
|
end
|
|
12
77
|
|
|
13
|
-
def
|
|
14
|
-
@logger.debug "
|
|
78
|
+
def debug(message, text)
|
|
79
|
+
@logger.debug "[#{message.client_id}##{message.id}] #{text}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def info(message, text)
|
|
83
|
+
@logger.info "[#{message.client_id}##{message.id}] #{text}"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def warn(message, text)
|
|
87
|
+
@logger.warn "[#{message.client_id}##{message.id}] #{text}"
|
|
88
|
+
end
|
|
15
89
|
|
|
16
|
-
|
|
90
|
+
def error(message, text)
|
|
91
|
+
@logger.error "[#{message.client_id}##{message.id}] #{text}"
|
|
17
92
|
end
|
|
18
93
|
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,61 @@
|
|
|
1
|
+
class Streamforce::Message
|
|
2
|
+
def initialize(payload)
|
|
3
|
+
@payload = payload
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def client_id
|
|
7
|
+
@payload["clientId"]
|
|
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 channel_type
|
|
23
|
+
channel.split("/")[1]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def channel_name
|
|
27
|
+
channel.split("/")[2]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def success?
|
|
31
|
+
@payload["successful"]
|
|
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 replay_from_message?
|
|
47
|
+
replay_id && replay_id != -1 && replay_id != -2
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def replay_available_messages?
|
|
51
|
+
replay_id == -2
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def no_replay?
|
|
55
|
+
replay_id.nil? || replay_id == -1
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def error_message
|
|
59
|
+
@payload["error"]
|
|
60
|
+
end
|
|
61
|
+
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.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Maxim
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-06-
|
|
11
|
+
date: 2024-06-18 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,6 +66,48 @@ dependencies:
|
|
|
66
66
|
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
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'
|
|
69
111
|
description:
|
|
70
112
|
email:
|
|
71
113
|
- andrei@andreimaxim.ro
|
|
@@ -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:
|
|
@@ -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
|
- - ">="
|
|
@@ -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
|