fly-atc 0.0.3-aarch64-linux
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +85 -0
- data/README.md +104 -0
- data/exe/aarch64-linux/fly-atc +0 -0
- data/exe/fly-atc +11 -0
- data/lib/fly-atc/version.rb +3 -0
- data/lib/fly-atc.rb +11 -0
- data/lib/generators/atc_generator.rb +44 -0
- data/lib/generators/templates/application.html.erb +1 -0
- data/lib/generators/templates/routes.erb +1 -0
- data/lib/helpers/atc-cable.rb +17 -0
- data/lib/tasks/atc.rake +49 -0
- data/lib/tasks/templates/litestream.yml.erb +14 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a223fd1bbe328ff2b5f07554de34188cc3a81e5ab635530a2f8b853cae14ad19
|
4
|
+
data.tar.gz: 60893cedfa624e8a4ab1e327caa1e20fcb685b8933ef853528f10ac29e249b77
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b9680e441b1de9e03ca8637a4969baa86f179eeac2b4b89213d0b392a12293e691674fd5aa50c4525451d275ec95ab190b6570ef1c7a769bbde04402a26cf8f2
|
7
|
+
data.tar.gz: 8e9c9ab093d43b38e17380772d1ccdc763e6ed6361521f55f8c831d0e3335508fc91556e2318a4880f69f84123c3d1b63ba0ff8b4236a8d045496959a207bc16
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
Copyright (c) Sam Ruby
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
---
|
23
|
+
|
24
|
+
Includes code made available under the same license:
|
25
|
+
|
26
|
+
Copyright (c) 37signals, LLC
|
27
|
+
|
28
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
29
|
+
a copy of this software and associated documentation files (the
|
30
|
+
"Software"), to deal in the Software without restriction, including
|
31
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
32
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
33
|
+
permit persons to whom the Software is furnished to do so, subject to
|
34
|
+
the following conditions:
|
35
|
+
|
36
|
+
The above copyright notice and this permission notice shall be
|
37
|
+
included in all copies or substantial portions of the Software.
|
38
|
+
|
39
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
40
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
41
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
42
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
43
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
44
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
45
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
46
|
+
Copyright (c) 37signals, LLC
|
47
|
+
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
49
|
+
a copy of this software and associated documentation files (the
|
50
|
+
"Software"), to deal in the Software without restriction, including
|
51
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
52
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
53
|
+
permit persons to whom the Software is furnished to do so, subject to
|
54
|
+
the following conditions:
|
55
|
+
|
56
|
+
The above copyright notice and this permission notice shall be
|
57
|
+
included in all copies or substantial portions of the Software.
|
58
|
+
|
59
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
60
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
61
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
62
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
63
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
64
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
65
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
66
|
+
Copyright (c) 37signals, LLC
|
67
|
+
|
68
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
69
|
+
a copy of this software and associated documentation files (the
|
70
|
+
"Software"), to deal in the Software without restriction, including
|
71
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
72
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
73
|
+
permit persons to whom the Software is furnished to do so, subject to
|
74
|
+
the following conditions:
|
75
|
+
|
76
|
+
The above copyright notice and this permission notice shall be
|
77
|
+
included in all copies or substantial portions of the Software.
|
78
|
+
|
79
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
80
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
81
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
82
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
83
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
84
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
85
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# fly-atc
|
2
|
+
|
3
|
+
A SaaS toolkit for converting a personal application into a efficient, siloed, multi-tenant application, where each user of your application is assigned a dedicated virtual machine.
|
4
|
+
|
5
|
+
** Work in Progress **
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
### Quickstart (single tenant):
|
10
|
+
|
11
|
+
```
|
12
|
+
bundle add fly-atc
|
13
|
+
bundle binstubs fly-atc
|
14
|
+
```
|
15
|
+
|
16
|
+
Replace `thruster` with `fly-atc` in Dockerfile.
|
17
|
+
|
18
|
+
### Quickstart (multi-tenant):
|
19
|
+
|
20
|
+
```
|
21
|
+
bundle add fly-atc
|
22
|
+
bin/rails generate atc
|
23
|
+
```
|
24
|
+
|
25
|
+
Edit `config/atc.yml` as needed.
|
26
|
+
|
27
|
+
Fly.io's dockerfile generators will be able to help with this.
|
28
|
+
|
29
|
+
For approximately $1 US per month, you can run:
|
30
|
+
* [1 performance machine with 2Gb of RAM, 10GB of bandwidth, and 5GB of storage for 15 hours/month](https://fly.io/calculator?m=0_0_0_0_0&f=c&b=iad.10&a=no_none&r=shared_0_1_iad&t=10_100_5&u=0_1_100&g=1_performance_15_1_2048_iad_1024_0).
|
31
|
+
* [1 shared machine with 1Gb of RAM, 10GB of bandwidth, and 5GB of storage for 80 hours/month](https://fly.io/calculator?m=0_0_0_0_0&f=c&b=iad.10&a=no_none&r=shared_0_1_iad&t=10_100_5&u=0_1_100&g=1_shared_80_1_1048_iad_1024_0).
|
32
|
+
|
33
|
+
Vertical scaling can be achieved by adding more machines.
|
34
|
+
|
35
|
+
## Motivation
|
36
|
+
|
37
|
+
I've been running my [Showcase](https://github.com/rubys/showcase?tab=readme-ov-file#showcase) software for nearly three years. Things have changed over time that I now want to take advantage of. I want take the opportunity to package those changes in the form of a toolkit that others can take advantage of.
|
38
|
+
|
39
|
+
From Wikipedia description of [SaaS](https://en.wikipedia.org/wiki/Software_as_a_service):
|
40
|
+
|
41
|
+
> SaaS customers have the abstraction of limitless computing resources, while [economy of scale](https://en.wikipedia.org/wiki/Economy_of_scale) drives down the cost. SaaS architectures are typically [multi-tenant](https://en.wikipedia.org/wiki/Multi-tenant); usually they share resources between clients for efficiency, but sometimes they offer a siloed environment for an additional fee.
|
42
|
+
|
43
|
+
The focus of this toolkit is efficient, siloed, multi-tenant applications *with no changes to the application*, taking advantage of:
|
44
|
+
|
45
|
+
* [Auto-suspend](https://community.fly.io/t/autosuspend-is-here-machine-suspension-is-enabled-everywhere/20942) - Virtual Machines that pop into existence when needed and disappear when not in use.
|
46
|
+
* [SQLite ready for production](https://rubyonrails.org/2024/11/7/rails-8-no-paas-required#getting-sqlite-ready-for-production) - raw performance coupled with operational compression of complexity; see [Supercharge the One Person Framework with SQLite: Rails World 2024](https://fractaledmind.github.io/2024/10/16/sqlite-supercharges-rails/).
|
47
|
+
* [Litestream](https://litestream.io/) - No-worry backups. Virtual machines can be literally destroyed and recreated elsewhere and start back up exactly where they left off.
|
48
|
+
* [Tigris Global Storage](https://fly.io/docs/tigris/) - globally caching, S3-compatible object storage.
|
49
|
+
|
50
|
+
That's a lot of moving parts. I've documented my [current architecture](https://github.com/rubys/showcase/blob/main/ARCHITECTURE.md) and published a [blueprint](https://fly.io/docs/blueprints/shared-nothing/).
|
51
|
+
|
52
|
+
The goal of fly-atc is to enable you configure multiple tenants and then not worry about this further, enabling you to focus on your application.
|
53
|
+
|
54
|
+
## Approach
|
55
|
+
|
56
|
+
For illustrative purposes consider a SaaS Calender application implemented in Ruby on Rails using SQLite3 as the database. (My showcase application is a bit more involved than a calendar, but those details aren't important).
|
57
|
+
|
58
|
+
Key concepts:
|
59
|
+
|
60
|
+
* Each user/customer has a primarly location, and is assigned a single machine near that location. Such machines can be accessed from anywhere, but have lower latency near that location.
|
61
|
+
* Each user can have multiple calendars. Each calendar is associated with a single tenant on the user's machine. Each tenant consists a running instance of the web server application with one ([or more](https://rubyonrails.org/2024/11/7/rails-8-no-paas-required#a-solid-reduction-of-dependencies)) databases.
|
62
|
+
|
63
|
+
With that in mind, consider the following URL paths:
|
64
|
+
|
65
|
+
* `/bellevue/2025/winter/`
|
66
|
+
* `/bellevue/2025/summer-medal-ball/`
|
67
|
+
* `/bellevue/2025/summer-showcase/`
|
68
|
+
* `/boston/2025/april/`
|
69
|
+
* `/boston/2025/mini-comp/`
|
70
|
+
* `/boston/2025/october/`
|
71
|
+
* `/livermore/2025/the-music-of-prince/`
|
72
|
+
* `/livermore/2025/james-bond/`
|
73
|
+
* `/raleigh/2025/disney/`
|
74
|
+
* `/raleigh/2025/in-house/`
|
75
|
+
|
76
|
+
The first segment of the path identifies the user, and therefore the machine. The next two segments combined identify the tenant on that machine. This is but a subset of the planned showcases, you can see a [full list](https://smooth.fly.dev/showcase/) or even a [map](https://smooth.fly.dev/showcase/regions/) (click on the arrows under the map to move to different continents).
|
77
|
+
|
78
|
+
`fly-atc`'s responsibilities are to:
|
79
|
+
* Route requests to the correct machine
|
80
|
+
* Ensure databases are present/restored from backup
|
81
|
+
* Start/stop tenants as required
|
82
|
+
* Hand off requests to tenants
|
83
|
+
|
84
|
+
Rails 8 introduces [thruster](https://rubyonrails.org/2024/11/7/rails-8-no-paas-required#enter-kamal-2--thruster). `fly-atc` is a replacement for thruster:
|
85
|
+
* thruster requires no configuration, is limited to a single tenant.
|
86
|
+
* fly-atc enables multiple tenants, based on your configuration.
|
87
|
+
|
88
|
+
## Implementation
|
89
|
+
|
90
|
+
Based on:
|
91
|
+
* [Thruster](https://github.com/basecamp/thruster) ([announcement](https://dev.37signals.com/thruster-released/))
|
92
|
+
* [tinyrp](https://github.com/pgaijin66/tinyrp) ([docs](https://prabeshthapa.medium.com/learn-reverse-proxy-by-creating-one-yourself-using-go-87be2a29d1e))
|
93
|
+
|
94
|
+
Near term plans:
|
95
|
+
|
96
|
+
* Remove certificate/https support
|
97
|
+
* Add launch on request / shutdown on idle
|
98
|
+
* Add [fly-replay](https://fly.io/docs/networking/dynamic-request-routing/)
|
99
|
+
|
100
|
+
On the radar:
|
101
|
+
|
102
|
+
* Support for targets other than fly.io.
|
103
|
+
* Support for platforms other than Rails, likely starting with Node, and focusing on popular ORMs: [Prisma](https://www.prisma.io/), [TypeORM](https://typeorm.io/), and [Sequelize](https://sequelize.org/).
|
104
|
+
* Dashboard. One should be able to deploy new users and make other configuration changes using only your cell phone. I [do this today](https://github.com/rubys/showcase/blob/main/ARCHITECTURE.md#administration) with my showcase application.
|
Binary file
|
data/exe/fly-atc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
PLATFORM = [ :cpu, :os ].map { |m| Gem::Platform.local.send(m) }.join("-")
|
4
|
+
EXECUTABLE = File.expand_path(File.join(__dir__, PLATFORM, "fly-atc"))
|
5
|
+
|
6
|
+
if File.exist?(EXECUTABLE)
|
7
|
+
exec(EXECUTABLE, *ARGV)
|
8
|
+
else
|
9
|
+
STDERR.puts("ERROR: Unsupported platform: #{PLATFORM}")
|
10
|
+
exit 1
|
11
|
+
end
|
data/lib/fly-atc.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
class AtcGenerator < Rails::Generators::Base
|
2
|
+
def generate_app
|
3
|
+
source_paths.push File.expand_path("./templates", __dir__)
|
4
|
+
|
5
|
+
### config/routes.rb
|
6
|
+
|
7
|
+
@routes = IO.read("config/routes.rb")
|
8
|
+
|
9
|
+
unless @routes.include? "fly_atc_scope"
|
10
|
+
_, prolog, routes = routes.split(/(.*Rails.application.routes.draw do\n)/m,2)
|
11
|
+
routes, epilog, _ = @routes.split(/^(end.*)/m,2)
|
12
|
+
routes = routes.split(/\n\s*\n/)
|
13
|
+
scoped = routes.select {|route| route =~ /^\s*\w/ && !route.include?('as:')}
|
14
|
+
|
15
|
+
@routes = <<~EOF
|
16
|
+
#{prolog.rstrip}
|
17
|
+
fly_atc_scope = ENV.fetch("FLY_ATC_SCOPE", "")
|
18
|
+
|
19
|
+
unless fly_atc_scope == ""
|
20
|
+
mount ActionCable.server => "/\#{fly_atc_scope}/cable"
|
21
|
+
end
|
22
|
+
|
23
|
+
scope fly_atc_scope do
|
24
|
+
#{scoped.join("\n\n").gsub(/^ /, " ")}
|
25
|
+
end
|
26
|
+
|
27
|
+
#{(routes-scoped).join("\n\n").rstrip}
|
28
|
+
#{epilog.rstrip}
|
29
|
+
EOF
|
30
|
+
end
|
31
|
+
|
32
|
+
template "routes.erb", "config/routes.rb"
|
33
|
+
|
34
|
+
### app/views/layouts/application.html.erb
|
35
|
+
|
36
|
+
@layout = IO.read("app/views/layouts/application.html.erb")
|
37
|
+
|
38
|
+
unless @layout.include? "action_cable_meta_tag_dynamic"
|
39
|
+
@layout[/<meta.*?\n()\r?\n/m, 1] = " <%= action_cable_meta_tag_dynamic %>\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
template "application.html.erb", "app/views/layouts/application.html.erb"
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= @layout -%>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= @routes -%>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ApplicationHelper
|
2
|
+
def action_cable_meta_tag_dynamic
|
3
|
+
scheme = (request.env['HTTP_X_FORWARDED_PROTO'] || request.env["rack.url_scheme"] || '').split(',').last
|
4
|
+
return '' if scheme.blank?
|
5
|
+
host = request.env['HTTP_X_FORWARDED_HOST'] || request.env["HTTP_HOST"]
|
6
|
+
scope = ENV.fetch('FLY_ATC_SCOPE', "")
|
7
|
+
root = request.env['RAILS_RELATIVE_URL_ROOT']
|
8
|
+
|
9
|
+
if scope != ""
|
10
|
+
websocket = "#{scheme.sub('http', 'ws')}://#{host}#{root}#{scope}/cable"
|
11
|
+
else
|
12
|
+
websocket = "#{scheme.sub('http', 'ws')}://#{host}#{root}/cable"
|
13
|
+
end
|
14
|
+
|
15
|
+
"<meta name=\"action-cable-url\" content=\"#{websocket}\" />".html_safe
|
16
|
+
end
|
17
|
+
end
|
data/lib/tasks/atc.rake
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
actions = Rake::Task["db:prepare"].actions.clone
|
2
|
+
|
3
|
+
namespace :db do
|
4
|
+
task :atc_prepare => "db:load_config" do
|
5
|
+
actions.each {|action| action.call}
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Rake::Task["db:prepare"].clear
|
10
|
+
|
11
|
+
namespace :litestream do
|
12
|
+
task :atc_config => "db:load_config" do
|
13
|
+
require 'erubi'
|
14
|
+
|
15
|
+
@dbs =
|
16
|
+
ActiveRecord::Base
|
17
|
+
.configurations
|
18
|
+
.configs_for(env_name: "production", include_hidden: true)
|
19
|
+
.select { |config| ["sqlite3", "litedb"].include? config.adapter }
|
20
|
+
.map(&:database)
|
21
|
+
|
22
|
+
@config = ENV["LITESTREAM_CONFIG"] || Rails.root.join("config/litestream.yml")
|
23
|
+
|
24
|
+
template = File.read(File.join(File.dirname(__FILE__), "templates/litestream.yml.erb"))
|
25
|
+
result = eval(Erubi::Engine.new(template).src)
|
26
|
+
|
27
|
+
unless File.exist?(@config) && File.read(@config) == result
|
28
|
+
File.write(@config, result)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
task :atc_restore => "litestream:atc_config" do
|
33
|
+
next unless ENV["BUCKET_NAME"]
|
34
|
+
|
35
|
+
@dbs.each do |database|
|
36
|
+
next if File.exist? database
|
37
|
+
sh "bundle exec litestream restore -config #{@config} -if-replica-exists #{database}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :atc_replicate => "litestream:atc_config" do
|
42
|
+
next unless ENV["BUCKET_NAME"]
|
43
|
+
sh "bundle exec litestream replicate -config #{@config}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
namespace :atc do
|
48
|
+
task :prepare => ["litestream:atc_restore", "db:atc_prepare"]
|
49
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# This is the configuration file for litestream.
|
2
|
+
#
|
3
|
+
# For more details, see: https://litestream.io/reference/config/
|
4
|
+
#
|
5
|
+
dbs:
|
6
|
+
<% for db in @dbs -%>
|
7
|
+
- path: <%= db %>
|
8
|
+
replicas:
|
9
|
+
- type: s3
|
10
|
+
bucket: $BUCKET_NAME
|
11
|
+
path: storage/<%= File.basename(db) %>
|
12
|
+
access-key-id: $AWS_ACCESS_KEY_ID
|
13
|
+
secret-access-key: $AWS_SECRET_ACCESS_KEY
|
14
|
+
<% end -%>
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fly-atc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: aarch64-linux
|
6
|
+
authors:
|
7
|
+
- Sam Ruby
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-11-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 7.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 7.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: litestream
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.10'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.10'
|
41
|
+
description: An HTTP/2 proxy for mutli-tenant production deployments
|
42
|
+
email: rubys@intertwingly.net
|
43
|
+
executables:
|
44
|
+
- fly-atc
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- MIT-LICENSE
|
49
|
+
- README.md
|
50
|
+
- exe/aarch64-linux/fly-atc
|
51
|
+
- exe/fly-atc
|
52
|
+
- lib/fly-atc.rb
|
53
|
+
- lib/fly-atc/version.rb
|
54
|
+
- lib/generators/atc_generator.rb
|
55
|
+
- lib/generators/templates/application.html.erb
|
56
|
+
- lib/generators/templates/routes.erb
|
57
|
+
- lib/helpers/atc-cable.rb
|
58
|
+
- lib/tasks/atc.rake
|
59
|
+
- lib/tasks/templates/litestream.yml.erb
|
60
|
+
homepage: https://github.com/rubys/fly-atc
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata:
|
64
|
+
homepage_uri: https://github.com/rubys/fly-atc
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubygems_version: 3.5.18
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: A SaaS toolkit
|
84
|
+
test_files: []
|