turbo-train 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 848a9382896a69a3cb1d57a569c0fd2fc3908a3599dc5338cd26acf732ee9992
4
- data.tar.gz: 1672959f0bbae5254a6f97904db3322607080ffa7da940f1553732b883d96fcb
3
+ metadata.gz: d8f44643f00dc3a0c248fd990ffc95631a63bf9df53768ecb8e740a5dda4bc45
4
+ data.tar.gz: 92d303ac07e6402c9dc9ce4f71dcb9c56345c78980184c59692b7c7508daaf4d
5
5
  SHA512:
6
- metadata.gz: 245d52890779c61021ac9b5e3877b164e93535dae1211e351dc883c1c024bd429b1ed4f48d09401d204de16cdf971ccaba1b9daea403c43ff38e47dc874039f9
7
- data.tar.gz: a66cebab47ba27702446128492dfceac83bc6ae2382bf072547681de7989f9a98c81e2e20482d3d9fa9509c4c5d01a421b443b7349afc734b326bdfe5099327a
6
+ metadata.gz: 229de6bb9a249571e03daddb1b1288aa9138ddee9a1711538961bce90a6bc02e92ba2b83dd4f0062a78c75bb27cf92202126a40034303c10ae127bb9786eb34d
7
+ data.tar.gz: f2cd4ebef097ffc2d66fd6ec081537ae57b54c7318c132ed0cf508f26dfe03cdc2b13d3386839c209269062c344f9eb127ff8728593a7b82807db8407cb70dd2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uscreentv/turbo-train",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "",
5
5
  "main": "turbo-train.js",
6
6
  "type": "module",
@@ -2,7 +2,7 @@ import { Turbo } from "@hotwired/turbo-rails"
2
2
 
3
3
  export default class TurboTrain extends HTMLElement {
4
4
  static get observedAttributes() {
5
- return [ 'href', 'session', 'name' ];
5
+ return [ 'href' ];
6
6
  }
7
7
 
8
8
  constructor() {
@@ -10,7 +10,7 @@ export default class TurboTrain extends HTMLElement {
10
10
  }
11
11
 
12
12
  connectedCallback() {
13
- this.eventSource = new EventSource(`${this.href}/mercure?topic=${this.name}&authorization=${this.session}`);
13
+ this.eventSource = new EventSource(this.href);
14
14
  Turbo.connectStreamSource(this.eventSource);
15
15
  }
16
16
 
@@ -21,14 +21,6 @@ export default class TurboTrain extends HTMLElement {
21
21
  get href() {
22
22
  return this.getAttribute('href');
23
23
  }
24
-
25
- get session() {
26
- return this.getAttribute('session');
27
- }
28
-
29
- get name() {
30
- return this.getAttribute('name');
31
- }
32
24
  }
33
25
 
34
26
  if (
@@ -1 +1 @@
1
- import{Turbo as e}from"@hotwired/turbo-rails";export default class t extends HTMLElement{static get observedAttributes(){return["href","session","name"]}constructor(){super()}connectedCallback(){this.eventSource=new EventSource(`${this.href}/mercure?topic=${this.name}&authorization=${this.session}`),e.connectStreamSource(this.eventSource)}disconnectedCallback(){e.disconnectStreamSource(this.eventSource)}get href(){return this.getAttribute("href")}get session(){return this.getAttribute("session")}get name(){return this.getAttribute("name")}};"undefined"==typeof window||window.customElements.get("turbo-train-stream-source")||window.customElements.define("turbo-train-stream-source",t);
1
+ import{Turbo as e}from"@hotwired/turbo-rails";export default class t extends HTMLElement{static get observedAttributes(){return["href"]}constructor(){super()}connectedCallback(){this.eventSource=new EventSource(this.href),e.connectStreamSource(this.eventSource)}disconnectedCallback(){e.disconnectStreamSource(this.eventSource)}get href(){return this.getAttribute("href")}};"undefined"==typeof window||window.customElements.get("turbo-train-stream-source")||window.customElements.define("turbo-train-stream-source",t);
@@ -1,8 +1,6 @@
1
1
  module Turbo::Train::StreamsHelper
2
2
  def turbo_train_from(*streamables, **attributes)
3
- attributes[:name] = Turbo::Train.signed_stream_name(streamables)
4
- attributes[:session] = Turbo::Train.encode({ platform: "web" })
5
- attributes[:href] = Turbo::Train.configuration.url
3
+ attributes[:href] = Turbo::Train.server(attributes[:server]&.to_sym).listen_url(streamables, platform: "web")
6
4
  tag.turbo_train_stream_source(**attributes)
7
5
  end
8
6
  end
@@ -0,0 +1,27 @@
1
+ module Turbo
2
+ module Train
3
+ class BaseServer
4
+ attr_reader :configuration
5
+
6
+ def initialize(configuration)
7
+ @configuration = configuration
8
+ end
9
+
10
+ def publish(topics:, data:)
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def server_config
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def publish_url
19
+ server_config.publish_url
20
+ end
21
+
22
+ def listen_url(topic, **options)
23
+ server_config.listen_url(topic, **options)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,5 +1,5 @@
1
1
  module Turbo::Train::Broadcasts
2
- def broadcast(streamables, content:)
2
+ def broadcast(streamables, content:, server: nil)
3
3
  topics = if streamables.is_a?(Array)
4
4
  streamables.map { |s| signed_stream_name(s) }
5
5
  else
@@ -11,13 +11,13 @@ module Turbo::Train::Broadcasts
11
11
  data: content
12
12
  }
13
13
 
14
- Turbo::Train.server.publish(topics: topics, data: data)
14
+ Turbo::Train.server(server).publish(topics: topics, data: data)
15
15
  end
16
16
 
17
17
  def broadcast_action_to(*streamables, action:, target: nil, targets: nil, **rendering)
18
18
  broadcast(streamables, content: turbo_stream_action_tag(action, target: target, targets: targets, template:
19
19
  rendering.delete(:content) || rendering.delete(:html) || (rendering.any? ? render_format(:html, **rendering) : nil)
20
- ))
20
+ ), server: rendering.delete(:server))
21
21
  end
22
22
 
23
23
  def broadcast_render_to(*streamables, **rendering)
@@ -1,18 +1,74 @@
1
1
  module Turbo
2
2
  module Train
3
- class Configuration
4
- attr_accessor :mercure_domain, :publisher_key, :subscriber_key, :skip_ssl_verification
3
+ class MercureConfiguration
4
+ attr_accessor :mercure_domain, :publisher_key, :subscriber_key
5
5
 
6
6
  def initialize
7
+ super
7
8
  @mercure_domain = 'localhost'
8
9
  @publisher_key = 'test'
9
10
  @subscriber_key = 'testing'
10
- @skip_ssl_verification = Rails.env.development? || Rails.env.test?
11
11
  end
12
12
 
13
13
  def url
14
14
  "https://#{mercure_domain}/.well-known"
15
15
  end
16
+
17
+ def publish_url
18
+ "#{url}/mercure"
19
+ end
20
+
21
+ def listen_url(topic, platform: 'web')
22
+ "#{url}/mercure?topic=#{Turbo::Train.signed_stream_name(topic)}&authorization=#{jwt_auth_token({ platform: platform })}"
23
+ end
24
+
25
+ def jwt_auth_token(payload)
26
+ structured_payload = { mercure: { payload: payload } }
27
+ JWT.encode structured_payload, subscriber_key, ALGORITHM
28
+ end
29
+ end
30
+
31
+ class FanoutConfiguration
32
+ attr_accessor :fastly_api_url, :service_url, :fastly_key, :service_id
33
+
34
+ def initialize
35
+ super
36
+ @fastly_api_url = 'https://api.fastly.com'
37
+ @service_url = 'https://johnny-cage-fake-url.edgecompute.app'
38
+ @fastly_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
39
+ end
40
+
41
+ def publish_url
42
+ "#{@fastly_api_url}/service/#{@service_id}/publish/"
43
+ end
44
+
45
+ def listen_url(topic, **)
46
+ "#{service_url}/stream/sse?topic=#{Turbo::Train.signed_stream_name(topic)}"
47
+ end
48
+ end
49
+
50
+ class Configuration
51
+ attr_accessor :skip_ssl_verification, :mercure, :fanout, :default_server
52
+
53
+ def initialize
54
+ @skip_ssl_verification = Rails.env.development? || Rails.env.test?
55
+ @mercure = nil
56
+ @fanout = nil
57
+ @default_server = :mercure
58
+ end
59
+
60
+ def server(server_name)
61
+ case server_name
62
+ when :mercure
63
+ @mercure ||= MercureConfiguration.new
64
+ yield(@mercure)
65
+ when :fanout
66
+ @fanout ||= FanoutConfiguration.new
67
+ yield(@fanout)
68
+ else
69
+ raise ArgumentError, "Unknown server name: #{server_name}"
70
+ end
71
+ end
16
72
  end
17
73
 
18
74
  class << self
@@ -0,0 +1,36 @@
1
+ module Turbo
2
+ module Train
3
+ class FanoutServer < BaseServer
4
+ def publish(topics:, data:)
5
+ uri = URI(server_config.publish_url)
6
+ req = Net::HTTP::Post.new(uri)
7
+ req['Fastly-Key'] = server_config.fastly_key
8
+
9
+ message = data[:data].gsub("\n", "")
10
+ payload = {items: []}
11
+
12
+ Array(topics).each do |topic|
13
+ payload[:items] << {channel: topic, formats: { 'http-stream': { content: "event: message\ndata: #{message}\n\n" } } }
14
+ end
15
+
16
+ req.body = payload.to_json
17
+
18
+ opts = {
19
+ use_ssl: uri.scheme == 'https'
20
+ }
21
+
22
+ if configuration.skip_ssl_verification
23
+ opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
24
+ end
25
+
26
+ Net::HTTP.start(uri.host, uri.port, opts) do |http|
27
+ http.request(req)
28
+ end
29
+ end
30
+
31
+ def server_config
32
+ configuration.fanout
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,17 +1,11 @@
1
1
  module Turbo
2
2
  module Train
3
- class Server
4
- attr_reader :configuration
5
-
6
- def initialize(configuration)
7
- @configuration = configuration
8
- end
9
-
3
+ class MercureServer < BaseServer
10
4
  def publish(topics:, data:)
11
5
  payload = { mercure: { publish: topics } }
12
- token = JWT.encode payload, configuration.publisher_key, ALGORITHM
6
+ token = JWT.encode payload, server_config.publisher_key, ALGORITHM
13
7
 
14
- uri = URI("#{configuration.url}/mercure")
8
+ uri = URI(publish_url)
15
9
 
16
10
  req = Net::HTTP::Post.new(uri)
17
11
  req['Content-Type'] = 'application/x-www-form-urlencoded'
@@ -30,6 +24,10 @@ module Turbo
30
24
  http.request(req)
31
25
  end
32
26
  end
27
+
28
+ def server_config
29
+ configuration.mercure
30
+ end
33
31
  end
34
32
  end
35
33
  end
@@ -3,13 +3,31 @@ module Turbo
3
3
  module Train
4
4
  module TestHelper
5
5
  def before_setup
6
- Turbo::Train.instance_variable_set(:@server, Turbo::Train::TestServer.new(Turbo::Train.configuration))
6
+ test_server = case ENV.fetch('TURBO_TRAIN_TEST_SERVER', 'mercure').to_sym
7
+ when :mercure
8
+ Turbo::Train::TestServer.new(Turbo::Train.mercure_server, Turbo::Train.configuration)
9
+ when :fanout
10
+ Turbo::Train::TestServer.new(Turbo::Train.fanout_server, Turbo::Train.configuration)
11
+ else
12
+ raise "Unknown test server: #{ENV['TURBO_TRAIN_TEST_SERVER']}"
13
+ end
14
+
15
+ Turbo::Train.instance_variable_set(:@server, test_server)
7
16
  super
8
17
  end
9
18
 
10
19
  def after_teardown
20
+ test_server = case ENV.fetch('TURBO_TRAIN_TEST_SERVER', 'mercure').to_sym
21
+ when :mercure
22
+ Turbo::Train.mercure_server
23
+ when :fanout
24
+ Turbo::Train.fanout_server
25
+ else
26
+ raise "Unknown test server: #{ENV['TURBO_TRAIN_TEST_SERVER']}"
27
+ end
28
+
11
29
  super
12
- Turbo::Train.instance_variable_set(:@server, Turbo::Train::Server.new(Turbo::Train.configuration))
30
+ Turbo::Train.instance_variable_set(:@server, test_server)
13
31
  end
14
32
 
15
33
  def assert_broadcast_on(stream, data, &block)
@@ -36,6 +54,26 @@ module Turbo
36
54
 
37
55
  assert message, "No messages sent with #{data} to #{Turbo::Train.stream_name_from(stream)}"
38
56
  end
57
+
58
+ def assert_body_match(r)
59
+ if Turbo::Train.server.real_server.is_a?(Turbo::Train::FanoutServer)
60
+ assert_match "Published\n", r.body
61
+ elsif Turbo::Train.server.real_server.is_a?(Turbo::Train::MercureServer)
62
+ assert_match /urn:uuid:.*/, r.body
63
+ else
64
+ raise "Unknown server type"
65
+ end
66
+ end
67
+
68
+ def assert_response_from_mercure_server(r)
69
+ assert_equal r.code, '200'
70
+ assert_match /urn:uuid:.*/, r.body
71
+ end
72
+
73
+ def assert_response_from_fanout_server(r)
74
+ assert_equal r.code, '200'
75
+ assert_match "Published\n", r.body
76
+ end
39
77
  end
40
78
  end
41
79
  end
@@ -1,11 +1,12 @@
1
1
  module Turbo
2
2
  module Train
3
- class TestServer < Server
4
- attr_reader :configuration, :channels_data
3
+ class TestServer < BaseServer
4
+ attr_reader :configuration, :channels_data, :real_server
5
5
 
6
- def initialize(configuration)
6
+ def initialize(real_server, configuration)
7
7
  @configuration = configuration
8
8
  @channels_data = {}
9
+ @real_server = real_server
9
10
  end
10
11
 
11
12
  def publish(topics:, data:)
@@ -14,7 +15,7 @@ module Turbo
14
15
  @channels_data[topic] << data[:data]
15
16
  end
16
17
 
17
- super
18
+ real_server.publish(topics: topics, data: data) if real_server
18
19
  end
19
20
 
20
21
  def broadcasts(channel)
@@ -18,8 +18,27 @@ module Turbo
18
18
  Turbo.signed_stream_verifier.generate stream_name_from(streamables)
19
19
  end
20
20
 
21
- def server
22
- @server ||= Server.new(configuration)
21
+ def server(server = nil)
22
+ @server ||= case server || configuration.default_server
23
+ when :mercure
24
+ mercure_server
25
+ when :fanout
26
+ fanout_server
27
+ else
28
+ raise ArgumentError, "Unknown server: #{server}"
29
+ end
30
+ end
31
+
32
+ def mercure_server
33
+ raise ArgumentError, "Mercure configuration is missing" unless configuration.mercure
34
+
35
+ @mercure_server ||= MercureServer.new(configuration)
36
+ end
37
+
38
+ def fanout_server
39
+ raise ArgumentError, "Fanout configuration is missing" unless configuration.fanout
40
+
41
+ @fanout_server ||= FanoutServer.new(configuration)
23
42
  end
24
43
 
25
44
  def stream_name_from(streamables)
@@ -30,10 +49,6 @@ module Turbo
30
49
  end
31
50
  end
32
51
 
33
- def url
34
- configuration.url
35
- end
36
-
37
52
  private
38
53
 
39
54
  def render_format(format, **rendering)
@@ -1,5 +1,5 @@
1
1
  module Turbo
2
2
  module Train
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
data/lib/turbo/train.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require "turbo/train/version"
2
2
  require "turbo/train/config"
3
3
  require 'turbo/train/broadcasts'
4
- require 'turbo/train/server'
4
+ require 'turbo/train/base_server'
5
+ require 'turbo/train/mercure_server'
6
+ require 'turbo/train/fanout_server'
5
7
  require 'turbo/train/test_server'
6
8
  require 'turbo/train/test_helper'
7
9
  require "turbo/train/engine"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo-train
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Savrov
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-05-15 00:00:00.000000000 Z
12
+ date: 2023-05-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -84,10 +84,12 @@ files:
84
84
  - lib/install/install_node.rb
85
85
  - lib/tasks/install_tasks.rake
86
86
  - lib/turbo/train.rb
87
+ - lib/turbo/train/base_server.rb
87
88
  - lib/turbo/train/broadcasts.rb
88
89
  - lib/turbo/train/config.rb
89
90
  - lib/turbo/train/engine.rb
90
- - lib/turbo/train/server.rb
91
+ - lib/turbo/train/fanout_server.rb
92
+ - lib/turbo/train/mercure_server.rb
91
93
  - lib/turbo/train/test_helper.rb
92
94
  - lib/turbo/train/test_server.rb
93
95
  - lib/turbo/train/train.rb