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 +4 -4
- data/README.md +44 -10
- data/lib/install/create_initializer.rb +13 -3
- data/lib/turbo/train/anycable_server.rb +36 -0
- data/lib/turbo/train/config.rb +23 -1
- data/lib/turbo/train/test_helper.rb +18 -0
- data/lib/turbo/train/train.rb +8 -0
- data/lib/turbo/train/version.rb +1 -1
- data/lib/turbo/train.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ad7e01b88eb8b09c2eecdffee7a4ede7b383c35573a194eec411a24674ae44e
|
4
|
+
data.tar.gz: 26289d3f1a518cc8208f7b0b1db5ad8b06b00f8489d2bfffe3fd89d90ad10a93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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.
|
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.
|
106
|
-
config.
|
107
|
-
|
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
|
-
|
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
|
data/lib/turbo/train/config.rb
CHANGED
@@ -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
|
data/lib/turbo/train/train.rb
CHANGED
@@ -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(":")
|
data/lib/turbo/train/version.rb
CHANGED
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.
|
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:
|
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
|