turbo-train 0.3.0 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8f44643f00dc3a0c248fd990ffc95631a63bf9df53768ecb8e740a5dda4bc45
4
- data.tar.gz: 92d303ac07e6402c9dc9ce4f71dcb9c56345c78980184c59692b7c7508daaf4d
3
+ metadata.gz: 4ad7e01b88eb8b09c2eecdffee7a4ede7b383c35573a194eec411a24674ae44e
4
+ data.tar.gz: 26289d3f1a518cc8208f7b0b1db5ad8b06b00f8489d2bfffe3fd89d90ad10a93
5
5
  SHA512:
6
- metadata.gz: 229de6bb9a249571e03daddb1b1288aa9138ddee9a1711538961bce90a6bc02e92ba2b83dd4f0062a78c75bb27cf92202126a40034303c10ae127bb9786eb34d
7
- data.tar.gz: f2cd4ebef097ffc2d66fd6ec081537ae57b54c7318c132ed0cf508f26dfe03cdc2b13d3386839c209269062c344f9eb127ff8728593a7b82807db8407cb70dd2
6
+ metadata.gz: 5f000e44026c4e4d675eb5e6fa09ffab8b1f370ffd8f242f8582276542b9f5860b4ee8513a9f9f8350a4f5094b44d032894a10ca044f1d78c710e6a9ce42bad1
7
+ data.tar.gz: 84fd805f8e22ef1f1686cbe50a0cc7e4c3753f9f1f91225fab5c73be392d2a710acf2e9fe563166c1e28af7e9cf56e5b1f06a8c277d89486b7199f876ee951fd
data/README.md CHANGED
@@ -4,19 +4,19 @@
4
4
 
5
5
  <img align="right" width="220" title="Turbo::Train logo"
6
6
  src="https://user-images.githubusercontent.com/3010927/210603861-4b265489-a4a7-4d2a-bceb-40ceccebcd96.jpg">
7
-
8
7
 
9
- Real-time page updates for your Rails app over SSE with [Mercure](https://mercure.rocks) and [Hotwire Turbo](https://turbo.hotwired.dev/handbook/streams#integration-with-server-side-frameworks).
8
+
9
+ Real-time page updates for your Rails app over SSE with [Mercure](https://mercure.rocks), [Fanout Cloud](https://fanout.io/cloud) or [AnyCable](https://anycable.io/) and [Hotwire Turbo](https://turbo.hotwired.dev/handbook/streams#integration-with-server-side-frameworks).
10
10
 
11
11
  * **Uses [SSE](https://html.spec.whatwg.org/multipage/server-sent-events.html)**. No more websockets, client libraries, JS code and handling reconnects. Just an HTTP connection. Let the [browser](https://caniuse.com/eventsource) do the work.
12
12
  * **Seamless Hotwire integration.** Use it exactly like [ActionCable](https://github.com/hotwired/turbo-rails#come-alive-with-turbo-streams). Drop-in replacement for `broadcast_action_to` and usual helpers.
13
- * **Simple.** Get running in minutes, scale easily in production 🚀
13
+ * **Simple.** Get running in minutes, scale easily in production 🚀
14
14
 
15
15
  ## Before your proceed
16
16
 
17
17
  Using this gem requires some knowledge of ActionCable and broadcasting turbo streams. Turbo::Train is designed to mimic those, so it is highly recommended to first try the original to understand the concept.
18
18
 
19
- You can start [here](https://hotwired.dev/) and proceed with the [Turbo Handbook](https://turbo.hotwired.dev/handbook/introduction). One of its chapters will be covering [Turbo Streams](https://turbo.hotwired.dev/handbook/streams). Specifically [this section](https://turbo.hotwired.dev/handbook/streams#integration-with-server-side-frameworks) would be the main prerequisite to understanding what this gem is about: it covers [Broadcastable](https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb) and the overall idea of working with Mercure.
19
+ You can start [here](https://hotwired.dev/) and proceed with the [Turbo Handbook](https://turbo.hotwired.dev/handbook/introduction). One of its chapters will be covering [Turbo Streams](https://turbo.hotwired.dev/handbook/streams). Specifically [this section](https://turbo.hotwired.dev/handbook/streams#integration-with-server-side-frameworks) would be the main prerequisite to understanding what this gem is about: it covers [Broadcastable](https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb) and the overall idea of working with Mercure or Fanout Cloud.
20
20
 
21
21
  ## Prerequisites
22
22
 
@@ -40,7 +40,8 @@ Instructions for Rails 6
40
40
  1. Install [turbo-rails](https://github.com/hotwired/turbo-rails#installation)
41
41
  2. Repeat steps for Rails 7 above
42
42
 
43
- ### Step 2. Mercure
43
+ ### Step 2. Server
44
+ #### Mercure
44
45
 
45
46
  Mercure is installed as a plugin to [Caddy](https://github.com/caddyserver/caddy) server. For mac users everything is pretty easy:
46
47
 
@@ -57,6 +58,21 @@ Now you are ready to run 🚀
57
58
  ```
58
59
  caddy run
59
60
  ```
61
+ #### Fanout Cloud
62
+
63
+ We only support the cloud version today. To use [Fanout](https://fanout.io/cloud/) you must purchase a paid account with a contract for Fastly's services.
64
+
65
+ #### Fanout self-hosted (Pushpin)
66
+
67
+ Coming soon.
68
+
69
+ #### AnyCable
70
+
71
+ ```
72
+ anycable-go --host=localhost --port=8080 --sse --broadcast_adapter=http --broadcast_key=test --public_streams --noauth
73
+ ```
74
+
75
+ Coming soon.
60
76
 
61
77
  ## Usage
62
78
 
@@ -98,17 +114,35 @@ You have the same options as original Rails Turbo helpers: rendering partials, p
98
114
 
99
115
  ## Configuration
100
116
 
101
- To specify different Mercure server settings, please adjust the generated `config/initializers/turbo_train.rb` file:
117
+ To specify different Mercure or Fanout server settings, please adjust the generated `config/initializers/turbo_train.rb` file:
102
118
 
103
119
  ```ruby
104
120
  Turbo::Train.configure do |config|
105
- config.mercure_domain = ...
106
- config.publisher_key = ...
107
- config.subscriber_key = ...
121
+ config.skip_ssl_verification = true # Development only; don't do this in production
122
+ config.default_server = :fanout # Default value is :mercure
123
+
124
+ config.server :mercure do |mercure|
125
+ mercure.mercure_domain = ...
126
+ mercure.publisher_key = ...
127
+ mercure.subscriber_key = ...
128
+ end
129
+
130
+ config.server :fanout do |fanout|
131
+ fanout.service_url = ...
132
+ fanout.service_id = ...
133
+ fanout.fastly_key = ...
134
+ end
135
+
136
+ config.server :anycable do |fanout|
137
+ ac.anycable_url = 'http://0.0.0.0:8080'
138
+ ac.broadcast_key = 'test'
139
+ end
108
140
  end
109
141
  ```
110
142
 
111
- * Your SSE will connect to `https://#{configuration.mercure_domain}/.well-known`.
143
+ ### Mercure
144
+
145
+ * Your SSE will connect to `https://#{configuration.mercure_domain}/.well-known`.
112
146
  * The publisher/subscriber key correspond to the [configuration](https://mercure.rocks/docs/hub/config) or your Mercure server.
113
147
 
114
148
  By default, these are set to `localhost`/`test`/`testing` to match the configuration of the local development server from the installation instructions above.
@@ -2,10 +2,20 @@ say "Creating initializer"
2
2
  create_file Rails.root.join("config/initializers/turbo_train.rb") do
3
3
  %{
4
4
  Turbo::Train.configure do |config|
5
- config.mercure_domain = 'localhost'
6
- config.publisher_key = 'testing'
7
- config.subscriber_key = 'test'
8
5
  config.skip_ssl_verification = true # Development only; don't do this in production
6
+ config.default_server = # Default value is :mercure
7
+
8
+ config.server :mercure do |mercure|
9
+ mercure.mercure_domain = 'localhost'
10
+ mercure.publisher_key = 'testing'
11
+ mercure.subscriber_key = 'test'
12
+ end
13
+
14
+ config.server :fanout do |fanout|
15
+ fanout.service_url = ''
16
+ fanout.service_id = ''
17
+ fanout.fastly_key = ''
18
+ end
9
19
  end
10
20
  }
11
21
  end
@@ -0,0 +1,36 @@
1
+ module Turbo
2
+ module Train
3
+ class AnycableServer < BaseServer
4
+ def publish(topics:, data:)
5
+ uri = URI(server_config.publish_url)
6
+ req = Net::HTTP::Post.new(uri)
7
+ req['Content-Type'] = 'application/json'
8
+ req['Authorization'] = "Bearer #{server_config.broadcast_key}"
9
+
10
+ message = data[:data].gsub("\n", '')
11
+
12
+ opts = {
13
+ use_ssl: uri.scheme == 'https'
14
+ }
15
+
16
+ payload = []
17
+
18
+ Array(topics).each do |topic|
19
+ payload << { stream: topic, data: message }
20
+ end
21
+
22
+ req.body = payload.to_json
23
+
24
+ opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if configuration.skip_ssl_verification
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.anycable
33
+ end
34
+ end
35
+ end
36
+ end
@@ -47,13 +47,32 @@ module Turbo
47
47
  end
48
48
  end
49
49
 
50
+ class AnycableConfiguration
51
+ attr_accessor :anycable_url, :broadcast_key
52
+
53
+ def initialize
54
+ super
55
+ @anycable_url = 'http://localhost:8080'
56
+ @broadcast_key = 'test'
57
+ end
58
+
59
+ def publish_url
60
+ "#{@anycable_url}/_broadcast"
61
+ end
62
+
63
+ def listen_url(topic, **)
64
+ "#{@anycable_url}/events?stream=#{Turbo::Train.signed_stream_name(topic)}"
65
+ end
66
+ end
67
+
50
68
  class Configuration
51
- attr_accessor :skip_ssl_verification, :mercure, :fanout, :default_server
69
+ attr_accessor :skip_ssl_verification, :mercure, :fanout, :anycable, :default_server
52
70
 
53
71
  def initialize
54
72
  @skip_ssl_verification = Rails.env.development? || Rails.env.test?
55
73
  @mercure = nil
56
74
  @fanout = nil
75
+ @anycable = nil
57
76
  @default_server = :mercure
58
77
  end
59
78
 
@@ -65,6 +84,9 @@ module Turbo
65
84
  when :fanout
66
85
  @fanout ||= FanoutConfiguration.new
67
86
  yield(@fanout)
87
+ when :anycable
88
+ @anycable ||= AnycableConfiguration.new
89
+ yield(@anycable)
68
90
  else
69
91
  raise ArgumentError, "Unknown server name: #{server_name}"
70
92
  end
@@ -8,6 +8,8 @@ module Turbo
8
8
  Turbo::Train::TestServer.new(Turbo::Train.mercure_server, Turbo::Train.configuration)
9
9
  when :fanout
10
10
  Turbo::Train::TestServer.new(Turbo::Train.fanout_server, Turbo::Train.configuration)
11
+ when :anycable
12
+ Turbo::Train::TestServer.new(Turbo::Train.anycable_server, Turbo::Train.configuration)
11
13
  else
12
14
  raise "Unknown test server: #{ENV['TURBO_TRAIN_TEST_SERVER']}"
13
15
  end
@@ -22,6 +24,8 @@ module Turbo
22
24
  Turbo::Train.mercure_server
23
25
  when :fanout
24
26
  Turbo::Train.fanout_server
27
+ when :anycable
28
+ Turbo::Train.anycable_server
25
29
  else
26
30
  raise "Unknown test server: #{ENV['TURBO_TRAIN_TEST_SERVER']}"
27
31
  end
@@ -60,6 +64,20 @@ module Turbo
60
64
  assert_match "Published\n", r.body
61
65
  elsif Turbo::Train.server.real_server.is_a?(Turbo::Train::MercureServer)
62
66
  assert_match /urn:uuid:.*/, r.body
67
+ elsif Turbo::Train.server.real_server.is_a?(Turbo::Train::AnycableServer)
68
+ assert_match '', r.body
69
+ else
70
+ raise "Unknown server type"
71
+ end
72
+ end
73
+
74
+ def assert_code_ok(r)
75
+ if Turbo::Train.server.real_server.is_a?(Turbo::Train::FanoutServer)
76
+ assert_equal r.code, '200'
77
+ elsif Turbo::Train.server.real_server.is_a?(Turbo::Train::MercureServer)
78
+ assert_equal r.code, '200'
79
+ elsif Turbo::Train.server.real_server.is_a?(Turbo::Train::AnycableServer)
80
+ assert_equal r.code, '201'
63
81
  else
64
82
  raise "Unknown server type"
65
83
  end
@@ -24,6 +24,8 @@ module Turbo
24
24
  mercure_server
25
25
  when :fanout
26
26
  fanout_server
27
+ when :anycable
28
+ anycable_server
27
29
  else
28
30
  raise ArgumentError, "Unknown server: #{server}"
29
31
  end
@@ -41,6 +43,12 @@ module Turbo
41
43
  @fanout_server ||= FanoutServer.new(configuration)
42
44
  end
43
45
 
46
+ def anycable_server
47
+ raise ArgumentError, "Anycable configuration is missing" unless configuration.anycable
48
+
49
+ @anycable_server ||= AnycableServer.new(configuration)
50
+ end
51
+
44
52
  def stream_name_from(streamables)
45
53
  if streamables.is_a?(Array)
46
54
  streamables.map { |streamable| stream_name_from(streamable) }.join(":")
@@ -1,5 +1,5 @@
1
1
  module Turbo
2
2
  module Train
3
- VERSION = "0.3.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
data/lib/turbo/train.rb CHANGED
@@ -4,6 +4,7 @@ require 'turbo/train/broadcasts'
4
4
  require 'turbo/train/base_server'
5
5
  require 'turbo/train/mercure_server'
6
6
  require 'turbo/train/fanout_server'
7
+ require 'turbo/train/anycable_server'
7
8
  require 'turbo/train/test_server'
8
9
  require 'turbo/train/test_helper'
9
10
  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.3.0
4
+ version: 0.4.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-29 00:00:00.000000000 Z
12
+ date: 2024-05-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -84,6 +84,7 @@ 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/anycable_server.rb
87
88
  - lib/turbo/train/base_server.rb
88
89
  - lib/turbo/train/broadcasts.rb
89
90
  - lib/turbo/train/config.rb