syntropy 0.35.0 → 0.37.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/CHANGELOG.md +20 -0
- data/TODO.md +0 -2
- data/cmd/new/template/.gitignore +2 -1
- data/cmd/new/template/Gemfile +1 -1
- data/cmd/new/template/app/_lib/storage.rb +13 -0
- data/cmd/new/template/config/Caddyfile +5 -0
- data/cmd/new/template/docker-compose.yml +28 -3
- data/cmd/new.rb +7 -1
- data/cmd/serve.rb +3 -1
- data/examples/basic/counter_api.rb +1 -1
- data/examples/blog/app/_lib/posts.rb +3 -3
- data/examples/blog/app/_lib/storage.rb +13 -0
- data/lib/syntropy/http/io_extensions.rb +9 -0
- data/lib/syntropy/http/server_connection.rb +1 -0
- data/lib/syntropy/json_api.rb +5 -0
- data/lib/syntropy/module_loader.rb +1 -3
- data/lib/syntropy/{db → storage}/connection_pool.rb +2 -1
- data/lib/syntropy/storage/kv_store.rb +68 -0
- data/lib/syntropy/storage/prepared_query.rb +36 -0
- data/lib/syntropy/{db → storage}/schema.rb +4 -4
- data/lib/syntropy/{db → storage}/store.rb +1 -1
- data/lib/syntropy/storage.rb +6 -0
- data/lib/syntropy/test.rb +4 -2
- data/lib/syntropy/version.rb +1 -1
- data/lib/syntropy.rb +5 -7
- data/test/fixtures/app/_lib/klass.rb +1 -1
- data/test/fixtures/app/api+.rb +1 -1
- data/test/{test_db_connection_pool.rb → test_connection_pool.rb} +4 -4
- data/test/test_http_protocol.rb +54 -0
- data/test/test_kv_store.rb +84 -0
- data/test/test_module_loader.rb +1 -2
- data/test/{test_db_schema.rb → test_schema.rb} +5 -5
- data/test/{test_db_store.rb → test_store.rb} +3 -3
- metadata +14 -32
- data/cmd/new/template/app/_lib/database.rb +0 -13
- data/cmd/new/template_old/site/.gitignore +0 -57
- data/cmd/new/template_old/site/Dockerfile +0 -32
- data/cmd/new/template_old/site/Gemfile +0 -3
- data/cmd/new/template_old/site/README.md +0 -0
- data/cmd/new/template_old/site/bin/console +0 -0
- data/cmd/new/template_old/site/bin/restart +0 -0
- data/cmd/new/template_old/site/bin/server +0 -0
- data/cmd/new/template_old/site/bin/start +0 -0
- data/cmd/new/template_old/site/bin/stop +0 -0
- data/cmd/new/template_old/site/docker-compose.yml +0 -51
- data/cmd/new/template_old/site/proxy/Dockerfile +0 -5
- data/cmd/new/template_old/site/proxy/etc/Caddyfile +0 -7
- data/cmd/new/template_old/site/proxy/etc/tls_auto +0 -2
- data/cmd/new/template_old/site/proxy/etc/tls_cloudflare +0 -4
- data/cmd/new/template_old/site/proxy/etc/tls_custom +0 -1
- data/cmd/new/template_old/site/proxy/etc/tls_selfsigned +0 -1
- data/cmd/new/template_old/site/site/_layout/default.rb +0 -11
- data/cmd/new/template_old/site/site/about.md +0 -6
- data/cmd/new/template_old/site/site/articles/cage.rb +0 -29
- data/cmd/new/template_old/site/site/articles/index.rb +0 -3
- data/cmd/new/template_old/site/site/assets/css/style.css +0 -40
- data/cmd/new/template_old/site/site/assets/img/syntropy.png +0 -0
- data/cmd/new/template_old/site/site/index.rb +0 -15
- data/examples/blog/app/_lib/database.rb +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eb6c66cfca4b2d7be9060c5571028b5356950fb34f8fba634b0d43b97169cd48
|
|
4
|
+
data.tar.gz: 447b2442d22332e0642869e01eee03889d8c85ba31e58909d603382be51f4c7d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19d092f17b75b7cc3290cb2802f46bd19efbb30855f3acf78e1cfc2f88084e0c0dca68bbfcd661545bd50def484cc9526d8a2f4057c9a6da8d6639c95b2cd8c4
|
|
7
|
+
data.tar.gz: 34d839e355da94f8993ffefa1a48c9bebfecb6da9c6b43cfe7f934d4fe8a804889d2a7a75874f0107b3226bd6a880037466610f4cffd87d48bdab2f19c5e0545
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
# 0.37.0 2026-06-07
|
|
2
|
+
|
|
3
|
+
- Call `IO#clear` before closing server connection
|
|
4
|
+
- syntropy new:
|
|
5
|
+
- Remove socket mapping for backend in docker-compose.yml
|
|
6
|
+
- Add caddy reverse proxy to template
|
|
7
|
+
- Add overwrite confirmation, better file copying
|
|
8
|
+
- Verify storage module `migrate!` method exists
|
|
9
|
+
- Fix `set_schema_version` for usage in PG DB
|
|
10
|
+
- Do not raise exception on missing config module
|
|
11
|
+
- Do not convert class export value to class instance, allow exporting a
|
|
12
|
+
class
|
|
13
|
+
- Fix HTTP protocol error when pipelining post requests with empty body
|
|
14
|
+
- Setup fiber scheduler when running server
|
|
15
|
+
|
|
16
|
+
# 0.36.0 2026-06-04
|
|
17
|
+
|
|
18
|
+
- Rename `DB` to `Storage`
|
|
19
|
+
- Add `PreparedQuery`, `KVStore`
|
|
20
|
+
|
|
1
21
|
# 0.35.0 2026-06-04
|
|
2
22
|
|
|
3
23
|
- Add `syntropy new` command
|
data/TODO.md
CHANGED
data/cmd/new/template/.gitignore
CHANGED
data/cmd/new/template/Gemfile
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export self
|
|
2
|
+
|
|
3
|
+
def connection_pool
|
|
4
|
+
@connection_pool ||= Storage::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def schema
|
|
8
|
+
Storage::Schema.new(module_loader: @module_loader, schema_root: '_schema')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def migrate!
|
|
12
|
+
schema.apply(connection_pool)
|
|
13
|
+
end
|
|
@@ -7,17 +7,18 @@ services:
|
|
|
7
7
|
- seccomp:unconfined
|
|
8
8
|
volumes:
|
|
9
9
|
- .:/syntropy
|
|
10
|
-
ports:
|
|
11
|
-
- "1234:1234"
|
|
12
10
|
stop_signal: SIGINT
|
|
13
11
|
stop_grace_period: 10s
|
|
14
|
-
restart:
|
|
12
|
+
restart: unless-stopped
|
|
15
13
|
healthcheck:
|
|
16
14
|
test: "curl 'http://localhost:1234/'"
|
|
17
15
|
interval: "30s"
|
|
18
16
|
timeout: "3s"
|
|
19
17
|
start_period: "5s"
|
|
20
18
|
retries: 3
|
|
19
|
+
networks:
|
|
20
|
+
- proxy_network
|
|
21
|
+
|
|
21
22
|
console:
|
|
22
23
|
build: .
|
|
23
24
|
command: bundle exec syntropy console
|
|
@@ -31,6 +32,7 @@ services:
|
|
|
31
32
|
- .:/syntropy
|
|
32
33
|
stop_signal: SIGINT
|
|
33
34
|
restart: never
|
|
35
|
+
|
|
34
36
|
test:
|
|
35
37
|
build: .
|
|
36
38
|
command: bundle exec syntropy test -w
|
|
@@ -44,3 +46,26 @@ services:
|
|
|
44
46
|
- .:/syntropy
|
|
45
47
|
stop_signal: SIGINT
|
|
46
48
|
restart: never
|
|
49
|
+
|
|
50
|
+
proxy:
|
|
51
|
+
depends_on:
|
|
52
|
+
- app_server
|
|
53
|
+
image: caddy:2-alpine
|
|
54
|
+
build:
|
|
55
|
+
context: ./proxy
|
|
56
|
+
dockerfile: Dockerfile
|
|
57
|
+
restart: unless-stopped
|
|
58
|
+
ports:
|
|
59
|
+
- "80:80"
|
|
60
|
+
- "443:443"
|
|
61
|
+
- "443:443/udp"
|
|
62
|
+
volumes:
|
|
63
|
+
- ./config/Caddyfile:/etc/caddy/Caddyfile
|
|
64
|
+
- ./storage/caddy/data:/data
|
|
65
|
+
- ./storage/caddy/config:/config
|
|
66
|
+
networks:
|
|
67
|
+
- proxy_network
|
|
68
|
+
|
|
69
|
+
networks:
|
|
70
|
+
proxy_network:
|
|
71
|
+
name: proxy_network
|
data/cmd/new.rb
CHANGED
|
@@ -3,9 +3,15 @@
|
|
|
3
3
|
require 'optparse'
|
|
4
4
|
require 'fileutils'
|
|
5
5
|
|
|
6
|
+
opts = {}
|
|
7
|
+
|
|
6
8
|
parser = OptionParser.new do |o|
|
|
7
9
|
o.banner = 'Usage: syntropy new NAME [options]'
|
|
8
10
|
|
|
11
|
+
o.on('-y', '--yes', 'Confirm all overwrites') do
|
|
12
|
+
opts[:yes] = true
|
|
13
|
+
end
|
|
14
|
+
|
|
9
15
|
o.on('-h', '--help', 'Show this help message') do
|
|
10
16
|
puts o
|
|
11
17
|
exit
|
|
@@ -37,7 +43,7 @@ template_path = File.join(__dir__, 'new/template')
|
|
|
37
43
|
|
|
38
44
|
begin
|
|
39
45
|
`mkdir -p "#{path}"`
|
|
40
|
-
|
|
46
|
+
system("cp -rv#{opts[:yes] ? '' : 'i'} #{template_path}/* \"#{path}/\"")
|
|
41
47
|
puts "Your app is ready in #{path}"
|
|
42
48
|
rescue => e
|
|
43
49
|
p e
|
data/cmd/serve.rb
CHANGED
|
@@ -94,7 +94,9 @@ env[:banner] = false
|
|
|
94
94
|
env[:machine] = Syntropy.machine = UM.new
|
|
95
95
|
env[:logger] = env[:logger] && Syntropy::Logger.new(env[:machine], **env)
|
|
96
96
|
|
|
97
|
-
require '
|
|
97
|
+
require 'uringmachine/fiber_scheduler'
|
|
98
|
+
Fiber.set_scheduler(UM::FiberScheduler.new(env[:machine]))
|
|
99
|
+
|
|
98
100
|
require 'syntropy/dev_mode' if Syntropy.dev_mode
|
|
99
101
|
|
|
100
102
|
app = Syntropy::App.load(env)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
Storage = import '/_lib/storage'
|
|
2
2
|
|
|
3
|
-
class PostStore < Syntropy::
|
|
3
|
+
class PostStore < Syntropy::Storage::Store
|
|
4
4
|
# @return [Integer] post id
|
|
5
5
|
def create(title, body)
|
|
6
6
|
query_single_value <<~SQL, title:, body:
|
|
@@ -46,4 +46,4 @@ class PostStore < Syntropy::DB::Store
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
export PostStore.new(
|
|
49
|
+
export PostStore.new(Storage.connection_pool)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export self
|
|
2
|
+
|
|
3
|
+
def connection_pool
|
|
4
|
+
@connection_pool ||= Storage::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def schema
|
|
8
|
+
Storage::Schema.new(module_loader: @module_loader, schema_root: '_schema')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def migrate!
|
|
12
|
+
schema.apply(connection_pool)
|
|
13
|
+
end
|
|
@@ -76,6 +76,9 @@ module Syntropy
|
|
|
76
76
|
def http_read_body(headers)
|
|
77
77
|
content_length = headers['content-length']
|
|
78
78
|
if content_length
|
|
79
|
+
content_length = content_length.to_i
|
|
80
|
+
return nil if content_length == 0
|
|
81
|
+
|
|
79
82
|
chunk = read(content_length.to_i)
|
|
80
83
|
return chunk
|
|
81
84
|
end
|
|
@@ -95,6 +98,9 @@ module Syntropy
|
|
|
95
98
|
def http_skip_body(headers)
|
|
96
99
|
content_length = headers['content-length']
|
|
97
100
|
if content_length
|
|
101
|
+
content_length = content_length.to_i
|
|
102
|
+
return if content_length == 0
|
|
103
|
+
|
|
98
104
|
return skip(content_length.to_i)
|
|
99
105
|
end
|
|
100
106
|
|
|
@@ -110,6 +116,9 @@ module Syntropy
|
|
|
110
116
|
def http_read_body_chunk(headers)
|
|
111
117
|
content_length = headers['content-length']
|
|
112
118
|
if content_length
|
|
119
|
+
content_length = content_length.to_i
|
|
120
|
+
return nil if content_length == 0
|
|
121
|
+
|
|
113
122
|
chunk = read(content_length.to_i)
|
|
114
123
|
return chunk
|
|
115
124
|
end
|
data/lib/syntropy/json_api.rb
CHANGED
|
@@ -167,8 +167,6 @@ module Syntropy
|
|
|
167
167
|
raise Syntropy::Error, "No export found in #{fn}" if raise_on_missing
|
|
168
168
|
when String
|
|
169
169
|
->(req) { req.respond(export_value) }
|
|
170
|
-
when Class
|
|
171
|
-
export_value.new(@env)
|
|
172
170
|
else
|
|
173
171
|
export_value
|
|
174
172
|
end
|
|
@@ -200,7 +198,7 @@ module Syntropy
|
|
|
200
198
|
m
|
|
201
199
|
rescue SyntaxError => e
|
|
202
200
|
env[:logger]&.error(message: "Error while loading module at #{fn}", error: e)
|
|
203
|
-
STDERR.puts("\n#{e.message}")
|
|
201
|
+
STDERR.puts("\n#{e.message}") if !Syntropy.test_mode
|
|
204
202
|
|
|
205
203
|
if (m = e.message.match(/^(.+)\: syntax/))
|
|
206
204
|
location = m[1]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'syntropy/storage/store'
|
|
4
|
+
|
|
5
|
+
module Syntropy
|
|
6
|
+
module Storage
|
|
7
|
+
# The KVStore class implements an SQLite-backed key-value store
|
|
8
|
+
class KVStore < Store
|
|
9
|
+
attr_reader :q_get, :q_set
|
|
10
|
+
|
|
11
|
+
def self.apply_schema(db, table_name)
|
|
12
|
+
db.execute <<~SQL
|
|
13
|
+
create table if not exists #{table_name} (key text primary key, value, expires float);
|
|
14
|
+
create index if not exists idx_#{table_name}_expires on #{table_name} (expires) where expires is not null;
|
|
15
|
+
SQL
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize(connection_pool, table_name)
|
|
19
|
+
super(connection_pool)
|
|
20
|
+
@table_name = table_name
|
|
21
|
+
|
|
22
|
+
setup_queries
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def get(db, key)
|
|
26
|
+
db[@q_get].bind(key).next
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def set(db, key, value)
|
|
30
|
+
db[@q_set].execute(key, value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def setex(db, key, value, ttl)
|
|
34
|
+
db[@q_setex].execute(key, value, ttl ? Time.now.to_f + ttl : nil)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def sweep(db)
|
|
38
|
+
db[@q_sweep].execute(Time.now.to_f)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def setup_queries
|
|
44
|
+
@q_get = Storage.prepare_splat <<~SQL
|
|
45
|
+
select value from #{@table_name}
|
|
46
|
+
where key = ?
|
|
47
|
+
SQL
|
|
48
|
+
|
|
49
|
+
@q_set = Storage.prepare <<~SQL
|
|
50
|
+
insert into #{@table_name} (key, value)
|
|
51
|
+
values($1, $2)
|
|
52
|
+
on conflict (key) do update set value = $2, expires = null
|
|
53
|
+
SQL
|
|
54
|
+
|
|
55
|
+
@q_setex = Storage.prepare <<~SQL
|
|
56
|
+
insert into #{@table_name} (key, value, expires)
|
|
57
|
+
values($1, $2, $3)
|
|
58
|
+
on conflict (key) do update set value = $2, expires = $3
|
|
59
|
+
SQL
|
|
60
|
+
|
|
61
|
+
@q_sweep = Storage.prepare <<~SQL
|
|
62
|
+
delete from #{@table_name}
|
|
63
|
+
where expires < ?
|
|
64
|
+
SQL
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'extralite'
|
|
4
|
+
|
|
5
|
+
module Syntropy
|
|
6
|
+
module Storage
|
|
7
|
+
class << self
|
|
8
|
+
def prepare(sql)
|
|
9
|
+
PreparedQuery.new(sql)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def prepare_splat(sql)
|
|
13
|
+
PreparedQuery.new(sql, :prepare_splat)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Represents information about a prepared query
|
|
18
|
+
class PreparedQuery
|
|
19
|
+
attr_reader :sql, :mode
|
|
20
|
+
|
|
21
|
+
def initialize(sql, mode = :prepare)
|
|
22
|
+
@sql = sql
|
|
23
|
+
@mode = mode
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Extensions for Extralite::Database
|
|
28
|
+
module ExtraliteDatabaseExtensions
|
|
29
|
+
def [](pq)
|
|
30
|
+
(@prepared_queries ||= {})[pq] ||= send(pq.mode, pq.sql)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
::Extralite::Database.include(ExtraliteDatabaseExtensions)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Syntropy
|
|
4
|
-
module
|
|
4
|
+
module Storage
|
|
5
5
|
class Schema
|
|
6
6
|
def initialize(module_loader: nil, schema_root: '_schema', &)
|
|
7
7
|
@migrations = {}
|
|
@@ -81,10 +81,10 @@ module Syntropy
|
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
def set_schema_version(db, version)
|
|
84
|
-
db.execute <<~SQL,
|
|
84
|
+
db.execute <<~SQL, version
|
|
85
85
|
insert into __syntropy_schema__ (k, v)
|
|
86
|
-
values ('version',
|
|
87
|
-
on conflict(k) do update set v =
|
|
86
|
+
values ('version', $1)
|
|
87
|
+
on conflict(k) do update set v = $1
|
|
88
88
|
SQL
|
|
89
89
|
end
|
|
90
90
|
end
|
data/lib/syntropy/test.rb
CHANGED
|
@@ -118,8 +118,8 @@ module Syntropy
|
|
|
118
118
|
)
|
|
119
119
|
@test_harness = Syntropy::TestHarness.new(@app)
|
|
120
120
|
|
|
121
|
-
@db = load_module('/_lib/
|
|
122
|
-
@db&.migrate!
|
|
121
|
+
@db = load_module('/_lib/storage', raise_on_missing: false)
|
|
122
|
+
@db&.migrate! if @db.respond_to?(:migrate!)
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
# Cleans up a test instance.
|
|
@@ -241,3 +241,5 @@ module Syntropy
|
|
|
241
241
|
|
|
242
242
|
Request.include TestRequestExtensions
|
|
243
243
|
end
|
|
244
|
+
|
|
245
|
+
Syntropy.test_mode = true
|
data/lib/syntropy/version.rb
CHANGED
data/lib/syntropy.rb
CHANGED
|
@@ -9,9 +9,7 @@ require 'syntropy/logger'
|
|
|
9
9
|
require 'syntropy/http'
|
|
10
10
|
require 'syntropy/mime_types'
|
|
11
11
|
require 'syntropy/app'
|
|
12
|
-
require 'syntropy/
|
|
13
|
-
require 'syntropy/db/schema'
|
|
14
|
-
require 'syntropy/db/store'
|
|
12
|
+
require 'syntropy/storage'
|
|
15
13
|
require 'syntropy/errors'
|
|
16
14
|
require 'syntropy/markdown'
|
|
17
15
|
require 'syntropy/module_loader'
|
|
@@ -29,7 +27,7 @@ module Syntropy
|
|
|
29
27
|
extend Utilities
|
|
30
28
|
|
|
31
29
|
class << self
|
|
32
|
-
attr_accessor :machine, :dev_mode
|
|
30
|
+
attr_accessor :machine, :dev_mode, :test_mode
|
|
33
31
|
|
|
34
32
|
# Runs the given block on a separate thread. Use this method for running
|
|
35
33
|
# code that is not fiber-aware (i.e. does not use UringMachine).
|
|
@@ -85,9 +83,9 @@ module Syntropy
|
|
|
85
83
|
logger: nil
|
|
86
84
|
)
|
|
87
85
|
loader = ModuleLoader.new(loader_env)
|
|
88
|
-
config = loader.load(env[:mode])
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
if (config = loader.load(env[:mode], raise_on_missing: false))
|
|
87
|
+
env[:config] = config
|
|
88
|
+
end
|
|
91
89
|
end
|
|
92
90
|
|
|
93
91
|
private
|
data/test/fixtures/app/api+.rb
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'helper'
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class ConnectionPoolTest < Minitest::Test
|
|
6
6
|
def setup
|
|
7
7
|
@machine = UM.new
|
|
8
8
|
@fn = "/tmp/#{rand(100000)}.db"
|
|
9
|
-
@cp = Syntropy::
|
|
9
|
+
@cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
|
|
10
10
|
|
|
11
11
|
FileUtils.rm(@fn) rescue nil
|
|
12
12
|
@standalone_db = Extralite::Database.new(@fn)
|
|
@@ -19,7 +19,7 @@ class DBConnectionPoolTest < Minitest::Test
|
|
|
19
19
|
@cp.close
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def
|
|
22
|
+
def test_connection_pool_with_db
|
|
23
23
|
assert_equal 0, @cp.count
|
|
24
24
|
|
|
25
25
|
@cp.with_db do |db|
|
|
@@ -74,7 +74,7 @@ class DBConnectionPoolTest < Minitest::Test
|
|
|
74
74
|
assert_equal 4, @cp.count
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
def
|
|
77
|
+
def test_connection_pool_with_db_reentrant
|
|
78
78
|
dbs = @cp.with_db do |db1|
|
|
79
79
|
@cp.with_db do |db2|
|
|
80
80
|
[db1, db2]
|
data/test/test_http_protocol.rb
CHANGED
|
@@ -248,3 +248,57 @@ class HTTPProtocolResponseTest < HTTPProtocolTest
|
|
|
248
248
|
assert_raises(Syntropy::ProtocolError) { @io.http_read_response_headers }
|
|
249
249
|
end
|
|
250
250
|
end
|
|
251
|
+
|
|
252
|
+
class PipelineTest < HTTPProtocolTest
|
|
253
|
+
def test_pipeline_post_zero_content_length
|
|
254
|
+
msg = "POST /counter_api?q=incr HTTP/1.1\r\n" +
|
|
255
|
+
"Host: localhost:1234\r\n" +
|
|
256
|
+
"User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0\r\n" +
|
|
257
|
+
"Accept: */*\r\n" +
|
|
258
|
+
"Accept-Language: en-US,en;q=0.9\r\n" +
|
|
259
|
+
"Accept-Encoding: gzip, deflate, br, zstd\r\n" +
|
|
260
|
+
"Referer: http://localhost:1234/counter\r\n" +
|
|
261
|
+
"Origin: http://localhost:1234\r\n" +
|
|
262
|
+
"Connection: keep-alive\r\n" +
|
|
263
|
+
"Sec-Fetch-Dest: empty\r\n" +
|
|
264
|
+
"Sec-Fetch-Mode: cors\r\n" +
|
|
265
|
+
"Sec-Fetch-Site: same-origin\r\n" +
|
|
266
|
+
"Priority: u=0\r\nPragma: no-cache\r\n" +
|
|
267
|
+
"Cache-Control: no-cache\r\n" +
|
|
268
|
+
"Content-Length: 0\r\n\r\n"
|
|
269
|
+
|
|
270
|
+
write(msg * 3)
|
|
271
|
+
3.times {
|
|
272
|
+
h = @io.http_read_request_headers
|
|
273
|
+
assert_equal '*/*', h['accept']
|
|
274
|
+
assert_nil @io.http_read_body_chunk(h)
|
|
275
|
+
}
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def test_pipeline_post_with_body
|
|
279
|
+
msg = "POST /counter_api?q=incr HTTP/1.1\r\n" +
|
|
280
|
+
"Host: localhost:1234\r\n" +
|
|
281
|
+
"User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0\r\n" +
|
|
282
|
+
"Accept: */*\r\n" +
|
|
283
|
+
"Accept-Language: en-US,en;q=0.9\r\n" +
|
|
284
|
+
"Accept-Encoding: gzip, deflate, br, zstd\r\n" +
|
|
285
|
+
"Referer: http://localhost:1234/counter\r\n" +
|
|
286
|
+
"Origin: http://localhost:1234\r\n" +
|
|
287
|
+
"Connection: keep-alive\r\n" +
|
|
288
|
+
"Sec-Fetch-Dest: empty\r\n" +
|
|
289
|
+
"Sec-Fetch-Mode: cors\r\n" +
|
|
290
|
+
"Sec-Fetch-Site: same-origin\r\n" +
|
|
291
|
+
"Priority: u=0\r\nPragma: no-cache\r\n" +
|
|
292
|
+
"Cache-Control: no-cache\r\n" +
|
|
293
|
+
"Content-Length: 3\r\n\r\n" +
|
|
294
|
+
"abc"
|
|
295
|
+
|
|
296
|
+
write(msg * 3)
|
|
297
|
+
3.times {
|
|
298
|
+
h = @io.http_read_request_headers
|
|
299
|
+
assert_equal '*/*', h['accept']
|
|
300
|
+
assert_equal 'abc', @io.http_read_body_chunk(h)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
end
|
|
304
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helper'
|
|
4
|
+
require 'syntropy/storage/kv_store'
|
|
5
|
+
|
|
6
|
+
class KVStoreTest < Minitest::Test
|
|
7
|
+
def setup
|
|
8
|
+
@machine = UM.new
|
|
9
|
+
@fn = "/tmp/#{rand(100000)}.db"
|
|
10
|
+
FileUtils.rm(@fn) rescue nil
|
|
11
|
+
@cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def teardown
|
|
15
|
+
@cp.close
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_connection_pool_prepare
|
|
19
|
+
pq = Syntropy::Storage.prepare('select ? as a, 42 as b')
|
|
20
|
+
assert_kind_of Syntropy::Storage::PreparedQuery, pq
|
|
21
|
+
assert_equal 'select ? as a, 42 as b', pq.sql
|
|
22
|
+
assert_equal :prepare, pq.mode
|
|
23
|
+
|
|
24
|
+
assert_kind_of Extralite::Query, @cp.with_db { it[pq] }
|
|
25
|
+
assert_equal [{ a: 'foo', b: 42 }], @cp.with_db { it[pq].bind('foo').to_a }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_connection_pool_prepare_splat
|
|
29
|
+
pq = Syntropy::Storage.prepare_splat('select ?')
|
|
30
|
+
assert_kind_of Syntropy::Storage::PreparedQuery, pq
|
|
31
|
+
assert_equal 'select ?', pq.sql
|
|
32
|
+
assert_equal :prepare_splat, pq.mode
|
|
33
|
+
|
|
34
|
+
assert_kind_of Extralite::Query, @cp.with_db { it[pq] }
|
|
35
|
+
assert_equal ['foo'], @cp.with_db { it[pq].bind('foo').to_a }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_kv_store_apply_schema
|
|
39
|
+
assert_respond_to Syntropy::Storage::KVStore, :apply_schema
|
|
40
|
+
|
|
41
|
+
assert_raises(Extralite::SQLError) { @cp.query('select * from kv') }
|
|
42
|
+
Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
|
|
43
|
+
assert_equal [], @cp.query('select * from kv')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_kv_store_get_set
|
|
47
|
+
Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
|
|
48
|
+
kv_store = Syntropy::Storage::KVStore.new(@cp, 'kv')
|
|
49
|
+
|
|
50
|
+
@cp.with_db do |db|
|
|
51
|
+
assert_nil kv_store.get(db, 'foo')
|
|
52
|
+
assert_nil kv_store.get(db, 'bar')
|
|
53
|
+
|
|
54
|
+
kv_store.set(db, 'foo', '123')
|
|
55
|
+
|
|
56
|
+
assert_equal '123', kv_store.get(db, 'foo')
|
|
57
|
+
assert_nil kv_store.get(db, 'bar')
|
|
58
|
+
|
|
59
|
+
kv_store.set(db, 'bar', '456')
|
|
60
|
+
assert_equal '123', kv_store.get(db, 'foo')
|
|
61
|
+
assert_equal '456', kv_store.get(db, 'bar')
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_kv_store_setex_sweep
|
|
66
|
+
Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
|
|
67
|
+
kv_store = Syntropy::Storage::KVStore.new(@cp, 'kv')
|
|
68
|
+
|
|
69
|
+
@cp.with_db do |db|
|
|
70
|
+
kv_store.set(db, 'foo', '123')
|
|
71
|
+
kv_store.setex(db, 'bar', '456', 0.05)
|
|
72
|
+
assert_equal 0, kv_store.sweep(db)
|
|
73
|
+
|
|
74
|
+
assert_equal '123', kv_store.get(db, 'foo')
|
|
75
|
+
assert_equal '456', kv_store.get(db, 'bar')
|
|
76
|
+
|
|
77
|
+
sleep 0.1
|
|
78
|
+
assert_equal 1, kv_store.sweep(db)
|
|
79
|
+
|
|
80
|
+
assert_equal '123', kv_store.get(db, 'foo')
|
|
81
|
+
assert_nil kv_store.get(db, 'bar')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
data/test/test_module_loader.rb
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'helper'
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class SchemaTest < Minitest::Test
|
|
6
6
|
def setup
|
|
7
7
|
@machine = UM.new
|
|
8
8
|
@fn = "/tmp/#{rand(100000)}.db"
|
|
9
9
|
FileUtils.rm(@fn) rescue nil
|
|
10
|
-
@cp = Syntropy::
|
|
10
|
+
@cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def teardown
|
|
@@ -15,7 +15,7 @@ class DBSchemaTest < Minitest::Test
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def test_db_schema_initial
|
|
18
|
-
schema = Syntropy::
|
|
18
|
+
schema = Syntropy::Storage::Schema.new do
|
|
19
19
|
initial do |db|
|
|
20
20
|
db.execute <<~SQL
|
|
21
21
|
create table posts (
|
|
@@ -35,7 +35,7 @@ class DBSchemaTest < Minitest::Test
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def test_db_schema_version_blocks
|
|
38
|
-
schema = Syntropy::
|
|
38
|
+
schema = Syntropy::Storage::Schema.new do
|
|
39
39
|
initial do |db|
|
|
40
40
|
db.execute <<~SQL
|
|
41
41
|
create table posts (
|
|
@@ -79,7 +79,7 @@ class DBSchemaTest < Minitest::Test
|
|
|
79
79
|
module_loader = Syntropy::ModuleLoader.new({
|
|
80
80
|
app_root: File.join(__dir__, 'fixtures/schema')
|
|
81
81
|
})
|
|
82
|
-
schema = Syntropy::
|
|
82
|
+
schema = Syntropy::Storage::Schema.new(module_loader:, schema_root: '/')
|
|
83
83
|
|
|
84
84
|
assert_nil schema.current_version(@cp)
|
|
85
85
|
schema.apply(@cp)
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'helper'
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class StoreTest < Minitest::Test
|
|
6
6
|
def setup
|
|
7
7
|
@machine = UM.new
|
|
8
8
|
@fn = "/tmp/#{rand(100000)}.db"
|
|
9
9
|
FileUtils.rm(@fn) rescue nil
|
|
10
|
-
@cp = Syntropy::
|
|
10
|
+
@cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def teardown
|
|
@@ -15,7 +15,7 @@ class DBStoreTest < Minitest::Test
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def test_db_store
|
|
18
|
-
store = Syntropy::
|
|
18
|
+
store = Syntropy::Storage::Store.new(@cp)
|
|
19
19
|
|
|
20
20
|
assert_equal [{a: 42}], store.query("select ? as a", 42)
|
|
21
21
|
assert_equal({a: 42}, store.query_single_row("select ? as a", 42))
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: syntropy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.37.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sharon Rosner
|
|
@@ -176,39 +176,17 @@ files:
|
|
|
176
176
|
- cmd/new/template/Gemfile
|
|
177
177
|
- cmd/new/template/README.md
|
|
178
178
|
- cmd/new/template/app/_layout/default.rb
|
|
179
|
-
- cmd/new/template/app/_lib/
|
|
179
|
+
- cmd/new/template/app/_lib/storage.rb
|
|
180
180
|
- cmd/new/template/app/_schema/2026-01-01-initial.rb
|
|
181
181
|
- cmd/new/template/app/assets/style.css
|
|
182
182
|
- cmd/new/template/app/index.rb
|
|
183
183
|
- cmd/new/template/app/test.rb
|
|
184
|
+
- cmd/new/template/config/Caddyfile
|
|
184
185
|
- cmd/new/template/config/development.rb
|
|
185
186
|
- cmd/new/template/config/production.rb
|
|
186
187
|
- cmd/new/template/config/test.rb
|
|
187
188
|
- cmd/new/template/docker-compose.yml
|
|
188
189
|
- cmd/new/template/test/test_app.rb
|
|
189
|
-
- cmd/new/template_old/site/.gitignore
|
|
190
|
-
- cmd/new/template_old/site/Dockerfile
|
|
191
|
-
- cmd/new/template_old/site/Gemfile
|
|
192
|
-
- cmd/new/template_old/site/README.md
|
|
193
|
-
- cmd/new/template_old/site/bin/console
|
|
194
|
-
- cmd/new/template_old/site/bin/restart
|
|
195
|
-
- cmd/new/template_old/site/bin/server
|
|
196
|
-
- cmd/new/template_old/site/bin/start
|
|
197
|
-
- cmd/new/template_old/site/bin/stop
|
|
198
|
-
- cmd/new/template_old/site/docker-compose.yml
|
|
199
|
-
- cmd/new/template_old/site/proxy/Dockerfile
|
|
200
|
-
- cmd/new/template_old/site/proxy/etc/Caddyfile
|
|
201
|
-
- cmd/new/template_old/site/proxy/etc/tls_auto
|
|
202
|
-
- cmd/new/template_old/site/proxy/etc/tls_cloudflare
|
|
203
|
-
- cmd/new/template_old/site/proxy/etc/tls_custom
|
|
204
|
-
- cmd/new/template_old/site/proxy/etc/tls_selfsigned
|
|
205
|
-
- cmd/new/template_old/site/site/_layout/default.rb
|
|
206
|
-
- cmd/new/template_old/site/site/about.md
|
|
207
|
-
- cmd/new/template_old/site/site/articles/cage.rb
|
|
208
|
-
- cmd/new/template_old/site/site/articles/index.rb
|
|
209
|
-
- cmd/new/template_old/site/site/assets/css/style.css
|
|
210
|
-
- cmd/new/template_old/site/site/assets/img/syntropy.png
|
|
211
|
-
- cmd/new/template_old/site/site/index.rb
|
|
212
190
|
- cmd/serve.rb
|
|
213
191
|
- cmd/test.rb
|
|
214
192
|
- docker-compose.yml
|
|
@@ -222,8 +200,8 @@ files:
|
|
|
222
200
|
- examples/basic/templates.rb
|
|
223
201
|
- examples/blog/.gitignore
|
|
224
202
|
- examples/blog/app/_layout/default.rb
|
|
225
|
-
- examples/blog/app/_lib/database.rb
|
|
226
203
|
- examples/blog/app/_lib/posts.rb
|
|
204
|
+
- examples/blog/app/_lib/storage.rb
|
|
227
205
|
- examples/blog/app/_schema/2026-01-01-initial.rb
|
|
228
206
|
- examples/blog/app/assets/style.css
|
|
229
207
|
- examples/blog/app/index.rb
|
|
@@ -262,9 +240,6 @@ files:
|
|
|
262
240
|
- lib/syntropy/applets/builtin/json_api.js
|
|
263
241
|
- lib/syntropy/applets/builtin/ping.rb
|
|
264
242
|
- lib/syntropy/applets/builtin/req.rb
|
|
265
|
-
- lib/syntropy/db/connection_pool.rb
|
|
266
|
-
- lib/syntropy/db/schema.rb
|
|
267
|
-
- lib/syntropy/db/store.rb
|
|
268
243
|
- lib/syntropy/dev_mode.rb
|
|
269
244
|
- lib/syntropy/errors.rb
|
|
270
245
|
- lib/syntropy/http.rb
|
|
@@ -288,6 +263,12 @@ files:
|
|
|
288
263
|
- lib/syntropy/routing_tree.rb
|
|
289
264
|
- lib/syntropy/session.rb
|
|
290
265
|
- lib/syntropy/side_run.rb
|
|
266
|
+
- lib/syntropy/storage.rb
|
|
267
|
+
- lib/syntropy/storage/connection_pool.rb
|
|
268
|
+
- lib/syntropy/storage/kv_store.rb
|
|
269
|
+
- lib/syntropy/storage/prepared_query.rb
|
|
270
|
+
- lib/syntropy/storage/schema.rb
|
|
271
|
+
- lib/syntropy/storage/store.rb
|
|
291
272
|
- lib/syntropy/test.rb
|
|
292
273
|
- lib/syntropy/utils.rb
|
|
293
274
|
- lib/syntropy/version.rb
|
|
@@ -340,23 +321,24 @@ files:
|
|
|
340
321
|
- test/run.rb
|
|
341
322
|
- test/test_app.rb
|
|
342
323
|
- test/test_caching.rb
|
|
343
|
-
- test/
|
|
344
|
-
- test/test_db_schema.rb
|
|
345
|
-
- test/test_db_store.rb
|
|
324
|
+
- test/test_connection_pool.rb
|
|
346
325
|
- test/test_errors.rb
|
|
347
326
|
- test/test_http_client.rb
|
|
348
327
|
- test/test_http_client_connection.rb
|
|
349
328
|
- test/test_http_protocol.rb
|
|
350
329
|
- test/test_http_server_connection.rb
|
|
351
330
|
- test/test_json_api.rb
|
|
331
|
+
- test/test_kv_store.rb
|
|
352
332
|
- test/test_mock_adapter.rb
|
|
353
333
|
- test/test_module_loader.rb
|
|
354
334
|
- test/test_request.rb
|
|
355
335
|
- test/test_request_session.rb
|
|
356
336
|
- test/test_response.rb
|
|
357
337
|
- test/test_routing_tree.rb
|
|
338
|
+
- test/test_schema.rb
|
|
358
339
|
- test/test_server.rb
|
|
359
340
|
- test/test_side_run.rb
|
|
341
|
+
- test/test_store.rb
|
|
360
342
|
- test/test_test.rb
|
|
361
343
|
homepage: https://github.com/digital-fabric/syntropy
|
|
362
344
|
licenses:
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export self
|
|
2
|
-
|
|
3
|
-
def connection_pool
|
|
4
|
-
@connection_pool ||= DB::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def schema
|
|
8
|
-
DB::Schema.new(module_loader: @module_loader, schema_root: '_schema')
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def migrate!
|
|
12
|
-
schema.apply(connection_pool)
|
|
13
|
-
end
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
*.gem
|
|
2
|
-
*.rbc
|
|
3
|
-
/.config
|
|
4
|
-
/coverage/
|
|
5
|
-
/InstalledFiles
|
|
6
|
-
/pkg/
|
|
7
|
-
/spec/reports/
|
|
8
|
-
/spec/examples.txt
|
|
9
|
-
/test/tmp/
|
|
10
|
-
/test/version_tmp/
|
|
11
|
-
/tmp/
|
|
12
|
-
|
|
13
|
-
# Used by dotenv library to load environment variables.
|
|
14
|
-
# .env
|
|
15
|
-
|
|
16
|
-
# Ignore Byebug command history file.
|
|
17
|
-
.byebug_history
|
|
18
|
-
|
|
19
|
-
## Specific to RubyMotion:
|
|
20
|
-
.dat*
|
|
21
|
-
.repl_history
|
|
22
|
-
build/
|
|
23
|
-
*.bridgesupport
|
|
24
|
-
build-iPhoneOS/
|
|
25
|
-
build-iPhoneSimulator/
|
|
26
|
-
|
|
27
|
-
## Specific to RubyMotion (use of CocoaPods):
|
|
28
|
-
#
|
|
29
|
-
# We recommend against adding the Pods directory to your .gitignore. However
|
|
30
|
-
# you should judge for yourself, the pros and cons are mentioned at:
|
|
31
|
-
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
32
|
-
#
|
|
33
|
-
# vendor/Pods/
|
|
34
|
-
|
|
35
|
-
## Documentation cache and generated files:
|
|
36
|
-
/.yardoc/
|
|
37
|
-
/_yardoc/
|
|
38
|
-
/doc/
|
|
39
|
-
/rdoc/
|
|
40
|
-
|
|
41
|
-
## Environment normalization:
|
|
42
|
-
/.bundle/
|
|
43
|
-
/vendor/bundle
|
|
44
|
-
/lib/bundler/man/
|
|
45
|
-
|
|
46
|
-
# for a library or gem, you might want to ignore these files since the code is
|
|
47
|
-
# intended to run in multiple environments; otherwise, check them in:
|
|
48
|
-
# Gemfile.lock
|
|
49
|
-
# .ruby-version
|
|
50
|
-
# .ruby-gemset
|
|
51
|
-
|
|
52
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
53
|
-
.rvmrc
|
|
54
|
-
|
|
55
|
-
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
|
56
|
-
# .rubocop-https?--*
|
|
57
|
-
log
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
ARG RUBY_BASE_IMAGE=ruby:3.4.1-alpine
|
|
2
|
-
ARG GEM_CACHE_IMAGE=${RUBY_BASE_IMAGE}
|
|
3
|
-
|
|
4
|
-
# base image
|
|
5
|
-
FROM ${RUBY_BASE_IMAGE} AS base
|
|
6
|
-
RUN apk add --update sqlite-dev openssl-dev tzdata bash curl zip git
|
|
7
|
-
RUN apk add --update build-base
|
|
8
|
-
RUN gem install bundler:2.6.9
|
|
9
|
-
|
|
10
|
-
# gem cache
|
|
11
|
-
FROM ${GEM_CACHE_IMAGE} AS gem-cache
|
|
12
|
-
RUN mkdir -p /usr/local/bundle
|
|
13
|
-
|
|
14
|
-
FROM base AS gems
|
|
15
|
-
COPY --from=gem-cache /usr/local/bundle /usr/local/bundle
|
|
16
|
-
COPY Gemfile Gemfile.lock ./
|
|
17
|
-
RUN bundle install --jobs=4 --retry=5
|
|
18
|
-
|
|
19
|
-
# Final backend image
|
|
20
|
-
FROM base AS deploy
|
|
21
|
-
|
|
22
|
-
RUN adduser -D app
|
|
23
|
-
RUN chown app:app /home/app
|
|
24
|
-
WORKDIR /home/app
|
|
25
|
-
USER app
|
|
26
|
-
|
|
27
|
-
RUN mkdir -p /tmp
|
|
28
|
-
COPY --from=gems --chown=app:app /usr/local/bundle /usr/local/bundle
|
|
29
|
-
|
|
30
|
-
EXPOSE 1234
|
|
31
|
-
|
|
32
|
-
CMD ["bundle", "exec", "syntropy", "."]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
services:
|
|
2
|
-
backend:
|
|
3
|
-
build: .
|
|
4
|
-
privileged: true
|
|
5
|
-
restart: always
|
|
6
|
-
ports:
|
|
7
|
-
- 127.0.0.1:1234:1234
|
|
8
|
-
# expose:
|
|
9
|
-
# - 1234
|
|
10
|
-
volumes:
|
|
11
|
-
- .:/home/app
|
|
12
|
-
deploy:
|
|
13
|
-
# replicas: 1
|
|
14
|
-
resources:
|
|
15
|
-
limits:
|
|
16
|
-
memory: 500M
|
|
17
|
-
# restart: unless-stopped
|
|
18
|
-
logging:
|
|
19
|
-
driver: "json-file"
|
|
20
|
-
options:
|
|
21
|
-
max-size: "1M"
|
|
22
|
-
max-file: "10"
|
|
23
|
-
|
|
24
|
-
# healthcheck:
|
|
25
|
-
# test: "curl 'http://localhost:1234/?q=ping'"
|
|
26
|
-
# interval: "30s"
|
|
27
|
-
# timeout: "3s"
|
|
28
|
-
# start_period: "5s"
|
|
29
|
-
# retries: 3
|
|
30
|
-
|
|
31
|
-
proxy:
|
|
32
|
-
depends_on:
|
|
33
|
-
- backend
|
|
34
|
-
build:
|
|
35
|
-
context: ./proxy
|
|
36
|
-
dockerfile: Dockerfile
|
|
37
|
-
restart: always
|
|
38
|
-
volumes:
|
|
39
|
-
- ./proxy/etc/Caddyfile:/etc/caddy/Caddyfile
|
|
40
|
-
ports:
|
|
41
|
-
- "80:80"
|
|
42
|
-
- "443:443"
|
|
43
|
-
- "443:443/udp"
|
|
44
|
-
# env_file:
|
|
45
|
-
# - ./conf/caddy.env
|
|
46
|
-
# - ./conf/caddy_sensitive.env
|
|
47
|
-
logging:
|
|
48
|
-
driver: "json-file"
|
|
49
|
-
options:
|
|
50
|
-
max-size: "1M"
|
|
51
|
-
max-file: "10"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
tls {$TLS_CUSTOM_CERT} {$TLS_CUSTOM_KEY}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
tls internal
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
layout = import('_layout/default')
|
|
2
|
-
|
|
3
|
-
poem = [
|
|
4
|
-
" in ten\xA0", 'M', 'inutes',
|
|
5
|
-
' ', 'C', 'ome back: you will',
|
|
6
|
-
'have taught me chi', 'N', 'ese',
|
|
7
|
-
' (s', 'A', 'tie).',
|
|
8
|
-
' shall I ret', 'U', 'rn the favor?',
|
|
9
|
-
' ', 'G', 'ive you',
|
|
10
|
-
' ot', 'H', 'er lessons',
|
|
11
|
-
' (', 'T', 'ing!)?',
|
|
12
|
-
' ', 'O', 'r would you prefer',
|
|
13
|
-
' sile', 'N', 'ce?',
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
export Papercraft.apply(layout) {
|
|
17
|
-
article(class: 'mesostic') {
|
|
18
|
-
h2 'For William McN. who studied with Ezra Pound'
|
|
19
|
-
|
|
20
|
-
content {
|
|
21
|
-
span(_for: poem) { text it }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
author {
|
|
25
|
-
span "-\xA0"
|
|
26
|
-
a 'John cage', href: 'https://en.wikipedia.org/wiki/John_Cage'
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
font-family: sans-serif;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
article.mesostic {
|
|
6
|
-
width: 600px;
|
|
7
|
-
margin: 2em auto;
|
|
8
|
-
font-size: 1.4em;
|
|
9
|
-
|
|
10
|
-
* {
|
|
11
|
-
font-family: monospace;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
h2 {
|
|
15
|
-
text-align: center;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
content {
|
|
19
|
-
display: grid;
|
|
20
|
-
margin: 2em 0;
|
|
21
|
-
grid-template-columns: 1fr auto 1fr;
|
|
22
|
-
|
|
23
|
-
span {
|
|
24
|
-
display: inline-block;
|
|
25
|
-
}
|
|
26
|
-
span:nth-child(3n + 1) {
|
|
27
|
-
text-align: right;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
span:nth-child(3n + 2) {
|
|
31
|
-
text-align: center;
|
|
32
|
-
font-weight: bold;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
author {
|
|
37
|
-
display: block;
|
|
38
|
-
text-align: right;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
File without changes
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
layout = import('_layout/default')
|
|
2
|
-
|
|
3
|
-
export Papercraft.apply(layout) {
|
|
4
|
-
h1 'Hello from Syntropy'
|
|
5
|
-
p {
|
|
6
|
-
span "Here's an "
|
|
7
|
-
a 'about', href: 'about'
|
|
8
|
-
span ' page.'
|
|
9
|
-
}
|
|
10
|
-
p {
|
|
11
|
-
span "Here's an "
|
|
12
|
-
a 'article', href: 'articles/cage'
|
|
13
|
-
span ' page.'
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export self
|
|
2
|
-
|
|
3
|
-
def connection_pool
|
|
4
|
-
@connection_pool ||= DB::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def schema
|
|
8
|
-
DB::Schema.new(module_loader: @module_loader, schema_root: '_schema')
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def migrate!
|
|
12
|
-
schema.apply(connection_pool)
|
|
13
|
-
end
|