fly-atc 0.0.3-x86_64-linux
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 +7 -0
- data/MIT-LICENSE +85 -0
- data/README.md +104 -0
- data/exe/fly-atc +11 -0
- data/exe/x86_64-linux/fly-atc +0 -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: a3e73181e40f1c2b1c8e8001465b63a6c212a652b8680e6a3e7a68cf5f162ec4
|
4
|
+
data.tar.gz: 3a378a5b22b364599268c5bf490f387a52bf211d5ba2c8dc6f355f5a665b65d5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4539778e9eee897c5ef2612d0cf35de36898237862ccca9072e051b3b9afb27d89da601285bb5a9cafaba07f5a909a4f1dbd1da1d406346981eac17917aee47d
|
7
|
+
data.tar.gz: b1cf03d2f33915db24cccca977ed85daa8b5399c63515bfc2790b69da1c58b0490354b0071687a1c951d0cdca8d3e0be0cb5ad91f5161a482f3cbed7b3821a3c
|
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.
|
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
|
Binary file
|
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: x86_64-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/fly-atc
|
51
|
+
- exe/x86_64-linux/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: []
|