durable_streams-rails 0.5.1 → 0.5.2

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: 51f89c0edb96d7dd54064866985489a744f7f083608c04d8493e06855d1df102
4
- data.tar.gz: 7d6f4830a2a9584ce28a8d05ad970d4ac1daa9c0f4673caeb06c1175d35968a7
3
+ metadata.gz: 79f28df832bb82db8fe2c8bf0204cf5c6ffededd6755c153d2a00aba4ec7f611
4
+ data.tar.gz: 698ea2440a5422124be37cb82ee2f988ad2e34dd008c702943f30d60797b0510
5
5
  SHA512:
6
- metadata.gz: d38b7504d016c6a929d15b0aca88a70842dc8472670eeea125cf96f5418f8dcf9f5415c63b01d25342aefe6b475566cc254e8a738d8f0a4cba64f9877c9ab7ab
7
- data.tar.gz: 973e68cf2d715fc58169e1b4781b169e6b288b4d21b198b4f2b2a07bac7e0924d7ee2688c4eef370f7b9072de7e4aed255092c43b4b49fad6a3c86e9e216cd91
6
+ metadata.gz: 407c2bcb96115a2b19207a3a10d99992b09daa273a39c935ce87adde911df3bc38c7be8b5e5ad409d6313c366ad74607ad9abe3a32eee62a6acfb4b95ce5afd3
7
+ data.tar.gz: 4c91ddfb552668d981f16c355876daa08c616ed42988f4eea157f1848af5b386eb9a93ace96def84a25c7abc9582e3e7d04b24e053b5146e2d15498ec5b95d5a
@@ -4,6 +4,10 @@ require "erb"
4
4
  module DurableStreams
5
5
  module Rails
6
6
  class ServerConfig
7
+ LOG_FORMATS = %w[ console json ].freeze
8
+ LOG_LEVELS = %w[ INFO WARN ERROR DEBUG ].freeze
9
+ STORAGE_DIRECTIVES = %w[ data_dir max_file_handles long_poll_timeout sse_reconnect_interval ].freeze
10
+
7
11
  TEMPLATE = ERB.new(<<~'CADDYFILE', trim_mode: "-")
8
12
  {
9
13
  admin off
@@ -22,16 +26,21 @@ module DurableStreams
22
26
  level <%= log_level %>
23
27
  }
24
28
 
25
- route <%= route_path %> {
26
- forward_auth <%= auth["url"] %> {
27
- uri <%= auth["path"] %>
28
- <%- copy_headers.each do |header| -%>
29
- copy_headers <%= header %>
29
+ <%= route_block %>
30
+ }
31
+ <%- if internal -%>
32
+
33
+ :<%= internal["port"] %> {
34
+ <%- if internal["bind"] -%>
35
+ bind <%= internal["bind"] %>
30
36
  <%- end -%>
31
- }
32
- durable_streams<%= plugin_block %>
37
+ @allowed remote_ip <%= internal_allowed_ips.join(" ") %>
38
+ handle @allowed {
39
+ <%= route_block(indent: 2) %>
33
40
  }
41
+ respond 403
34
42
  }
43
+ <%- end -%>
35
44
  CADDYFILE
36
45
 
37
46
  def self.generate(config_path, environment)
@@ -40,6 +49,7 @@ module DurableStreams
40
49
 
41
50
  def initialize(config_path, environment)
42
51
  @config = YAML.load_file(config_path, aliases: true).fetch(environment)
52
+ validate!
43
53
  end
44
54
 
45
55
  def generate
@@ -47,18 +57,77 @@ module DurableStreams
47
57
  end
48
58
 
49
59
  private
50
- def address
51
- @config["domain"] || ":#{@config.fetch("port", 4437)}"
60
+ def validate!
61
+ validate_internal!
62
+ validate_log!
63
+ end
64
+
65
+ def validate_internal!
66
+ if internal && !internal_allowed_ips
67
+ raise ArgumentError, "internal.allowed_ips is required when internal is configured"
68
+ end
69
+ end
70
+
71
+ def validate_log!
72
+ if log_config.key?("format") && !LOG_FORMATS.include?(log_config["format"])
73
+ raise ArgumentError,
74
+ "log.format must be one of #{LOG_FORMATS.join(", ")}, got: #{log_config["format"].inspect}"
75
+ end
76
+
77
+ if log_config.key?("level") && !LOG_LEVELS.include?(log_config["level"])
78
+ raise ArgumentError,
79
+ "log.level must be one of #{LOG_LEVELS.join(", ")}, got: #{log_config["level"].inspect}"
80
+ end
52
81
  end
53
82
 
83
+ # Template methods — ordered by invocation
84
+
54
85
  def auto_https?
55
86
  @config["domain"] && !tls_config
56
87
  end
57
88
 
89
+ def address
90
+ @config["domain"] || ":#{@config.fetch("port", 4437)}"
91
+ end
92
+
58
93
  def tls_config
59
94
  @config["tls"]
60
95
  end
61
96
 
97
+ def log_format
98
+ log_config.fetch("format", "console")
99
+ end
100
+
101
+ def log_level
102
+ log_config.fetch("level", "INFO")
103
+ end
104
+
105
+ def log_config
106
+ @config.fetch("log", {})
107
+ end
108
+
109
+ def route_block(indent: 1)
110
+ t = "\t" * indent
111
+ lines = []
112
+ lines << "#{t}route #{route_path} {"
113
+ lines << "#{t}\tforward_auth #{auth["url"]} {"
114
+ lines << "#{t}\t\turi #{auth["path"]}"
115
+ copy_headers.each { |h| lines << "#{t}\t\tcopy_headers #{h}" }
116
+ lines << "#{t}\t}"
117
+
118
+ directives = storage_directives
119
+ if directives.any?
120
+ lines << "#{t}\tdurable_streams {"
121
+ directives.each { |d| lines << "#{t}\t\t#{d}" }
122
+ lines << "#{t}\t}"
123
+ else
124
+ lines << "#{t}\tdurable_streams"
125
+ end
126
+
127
+ lines << "#{t}}"
128
+ lines.join("\n")
129
+ end
130
+
62
131
  def route_path
63
132
  @config.fetch("route", "/v1/streams/*")
64
133
  end
@@ -71,25 +140,17 @@ module DurableStreams
71
140
  auth.fetch("copy_headers", [ "Cookie" ])
72
141
  end
73
142
 
74
- def log_format
75
- @config.fetch("log_format", "console")
143
+ def storage_directives
144
+ storage = @config.fetch("storage", {})
145
+ STORAGE_DIRECTIVES.filter_map { |key| "#{key} #{storage[key]}" if storage[key] }
76
146
  end
77
147
 
78
- def log_level
79
- @config.fetch("log_level", "INFO")
148
+ def internal
149
+ @config["internal"]
80
150
  end
81
151
 
82
- def plugin_block
83
- storage = @config.fetch("storage", {})
84
- directives = []
85
- directives << "data_dir #{storage["data_dir"]}" if storage["data_dir"]
86
- directives << "max_file_handles #{storage["max_file_handles"]}" if storage["max_file_handles"]
87
- directives << "long_poll_timeout #{storage["long_poll_timeout"]}" if storage["long_poll_timeout"]
88
- directives << "sse_reconnect_interval #{storage["sse_reconnect_interval"]}" if storage["sse_reconnect_interval"]
89
-
90
- if directives.any?
91
- " {\n" + directives.map { |d| "\t\t\t#{d}" }.join("\n") + "\n\t\t}"
92
- end
152
+ def internal_allowed_ips
153
+ internal&.dig("allowed_ips")
93
154
  end
94
155
  end
95
156
  end
@@ -1,5 +1,5 @@
1
1
  module DurableStreams
2
2
  module Rails
3
- VERSION = "0.5.1"
3
+ VERSION = "0.5.2"
4
4
  end
5
5
  end
@@ -6,9 +6,10 @@
6
6
 
7
7
  default: &default
8
8
  port: 4437
9
- # route: /v1/streams/* # URL path prefix for stream endpoints
10
- # log_format: console # "console" (human-readable) or "json" (structured)
11
- # log_level: INFO # INFO, WARN, or ERROR
9
+ # route: /v1/streams/* # URL path prefix for stream endpoints. Default: /v1/streams/*
10
+ # log:
11
+ # format: console # "console" (human-readable) or "json" (structured). Default: console
12
+ # level: INFO # INFO, WARN, or ERROR. Default: INFO
12
13
  auth:
13
14
  url: http://localhost:3000
14
15
  path: /durable_streams/auth/verify
@@ -24,11 +25,17 @@ test:
24
25
  production:
25
26
  <<: *default
26
27
  domain: streams.example.com
27
- # tls: # Explicit TLS certs (disables ACME). Use with Cloudflare origin certs.
28
+ # tls: # Explicit TLS certs (disables ACME). Use with Cloudflare origin certs.
28
29
  # cert: /etc/caddy/certs/cert.pem
29
30
  # key: /etc/caddy/certs/key.pem
30
- # log_format: json
31
- # log_level: WARN
31
+ # internal: # Server-to-server listener (no TLS). Restrict to private network.
32
+ # port: 4437
33
+ # bind: 10.0.0.5 # Only listen on the private interface.
34
+ # allowed_ips: # Caddy remote_ip check — 403 for everyone else.
35
+ # - 10.0.0.4
36
+ # log:
37
+ # format: json
38
+ # level: WARN
32
39
  auth:
33
40
  url: https://app.example.com
34
41
  path: /durable_streams/auth/verify
@@ -37,6 +44,6 @@ production:
37
44
  - Authorization
38
45
  storage:
39
46
  data_dir: /var/data/durable-streams
40
- # max_file_handles: 100 # Connection pool for segment files. Tune to ~2x concurrent active streams.
41
- # long_poll_timeout: 30s # How long to wait for new data before returning 204.
42
- # sse_reconnect_interval: 60s # Server closes SSE after this interval for CDN collapsing.
47
+ # max_file_handles: 100 # Connection pool for segment files. Default: 100
48
+ # long_poll_timeout: 30s # How long to wait for new data before returning 204. Default: 30s
49
+ # sse_reconnect_interval: 60s # Server closes SSE after this interval for CDN collapsing. Default: 60s
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: durable_streams-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - tokimonki