Skip to content

Commit af4f404

Browse files
goreleaser
1 parent 6057246 commit af4f404

13 files changed

Lines changed: 279 additions & 50 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
*.so
2+
*.dll
3+
*.dylib
24
*.db
35
*.db-shm
46
*.db-wal
57

8+
# Added by goreleaser init:
9+
dist/

.goreleaser.yaml

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
2+
3+
version: 2
4+
5+
before:
6+
hooks:
7+
- go mod tidy
8+
9+
builds:
10+
- id: httpcache
11+
binary: httpcache
12+
buildmode: "c-shared"
13+
ldflags:
14+
- -s -w -X github.com/walterwanderley/sqlite-http-cache/extension.version={{.Version}} -X github.com/walterwanderley/sqlite-http-cache/extension.commit={{.Commit}} -X github.com/walterwanderley/sqlite-http-cache/extension.date={{.Date}}
15+
goos:
16+
- linux
17+
goarch:
18+
- amd64
19+
env:
20+
- CGO_ENABLED=1
21+
22+
- id: sqlite-http-proxy
23+
main: ./cmd/sqlite-http-proxy
24+
binary: sqlite-http-proxy
25+
goos:
26+
- linux
27+
goarch:
28+
- amd64
29+
env:
30+
- CGO_ENABLED=1
31+
32+
- id: sqlite-http-refresh
33+
main: ./cmd/sqlite-http-refresh
34+
binary: sqlite-http-refresh
35+
goos:
36+
- linux
37+
goarch:
38+
- amd64
39+
env:
40+
- CGO_ENABLED=1
41+
42+
- id: libsql-http-proxy
43+
main: ./cmd/libsql-http-proxy
44+
binary: libsql-http-proxy
45+
goos:
46+
- linux
47+
goarch:
48+
- amd64
49+
env:
50+
- CGO_ENABLED=1
51+
52+
archives:
53+
- id: httpcache
54+
formats: [tar.gz]
55+
ids: [httpcache]
56+
# this name template makes the OS and Arch compatible with the results of `uname`.
57+
name_template: >-
58+
{{- .Binary }}_
59+
{{- title .Os }}_
60+
{{- if eq .Arch "amd64" }}x86_64
61+
{{- else if eq .Arch "386" }}i386
62+
{{- else }}{{ .Arch }}{{ end }}
63+
{{- if .Arm }}v{{ .Arm }}{{ end }}
64+
# use zip for windows archives
65+
format_overrides:
66+
- goos: windows
67+
formats: [zip]
68+
files:
69+
- none*
70+
71+
- id: sqlite-http-proxy
72+
formats: [tar.gz]
73+
ids: [sqlite-http-proxy]
74+
# this name template makes the OS and Arch compatible with the results of `uname`.
75+
name_template: >-
76+
{{- .Binary }}_
77+
{{- title .Os }}_
78+
{{- if eq .Arch "amd64" }}x86_64
79+
{{- else if eq .Arch "386" }}i386
80+
{{- else }}{{ .Arch }}{{ end }}
81+
{{- if .Arm }}v{{ .Arm }}{{ end }}
82+
# use zip for windows archives
83+
format_overrides:
84+
- goos: windows
85+
formats: [zip]
86+
files:
87+
- none*
88+
89+
- id: sqlite-http-refresh
90+
formats: [tar.gz]
91+
ids: [sqlite-http-refresh]
92+
# this name template makes the OS and Arch compatible with the results of `uname`.
93+
name_template: >-
94+
{{- .Binary }}_
95+
{{- title .Os }}_
96+
{{- if eq .Arch "amd64" }}x86_64
97+
{{- else if eq .Arch "386" }}i386
98+
{{- else }}{{ .Arch }}{{ end }}
99+
{{- if .Arm }}v{{ .Arm }}{{ end }}
100+
# use zip for windows archives
101+
format_overrides:
102+
- goos: windows
103+
formats: [zip]
104+
files:
105+
- none*
106+
107+
- id: libsql-http-proxy
108+
formats: [tar.gz]
109+
ids: [libsql-http-proxy]
110+
# this name template makes the OS and Arch compatible with the results of `uname`.
111+
name_template: >-
112+
{{- .Binary }}_
113+
{{- title .Os }}_
114+
{{- if eq .Arch "amd64" }}x86_64
115+
{{- else if eq .Arch "386" }}i386
116+
{{- else }}{{ .Arch }}{{ end }}
117+
{{- if .Arm }}v{{ .Arm }}{{ end }}
118+
# use zip for windows archives
119+
format_overrides:
120+
- goos: windows
121+
formats: [zip]
122+
files:
123+
- none*
124+
125+
changelog:
126+
disable: true
127+
128+
release:
129+
github:
130+
owner: walterwanderley
131+
name: sqlite-http-cache
132+
133+
draft: true

README.md

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,27 @@ go build -ldflags="-s -w" -buildmode=c-shared -o httpcache.so
1313
sqlite3
1414

1515
# Load the extension
16-
.load /path/to/httpcache.so
16+
.load ./httpcache
17+
18+
# Check extension info
19+
SELECT cache_info();
1720

1821
# Insert URL into the temp.http_request virtual table to trigger the HTTP Request
1922
INSERT INTO temp.http_request VALUES('https://swapi.tech/api/films/1');
2023

24+
# Set output mode (optional)
25+
.mode qbox
26+
2127
# Fetch data from http_response table (created by the extension)
2228
SELECT JSON_EXTRACT(body, '$.result.properties.title') AS title,
2329
JSON_EXTRACT(body, '$.result.properties.release_date') AS release_date
2430
FROM http_response;
2531

26-
# Use cacheage, cachelifetime or cachexpired function to check cache validity based on RFC9111
27-
SELECT url, cacheage(header, request_time, response_time) AS age,
28-
cachelifetime(header, response_time) AS lifetime,
29-
cachexpired(header, request_time, response_time, false) AS expired,
30-
cachexpiredttl(header, request_time, response_time, false, 3600) AS expiredTTLFallback
32+
# Use cache_age, cache_lifetime or cache_expired function to check cache validity based on RFC9111
33+
SELECT url, cache_age(header, request_time, response_time) AS age,
34+
cache_lifetime(header, response_time) AS lifetime,
35+
cache_expired(header, request_time, response_time, false) AS expired,
36+
cache_expired_ttl(header, request_time, response_time, false, 3600) AS expiredTTLFallback
3137
FROM http_response;
3238
```
3339

@@ -105,16 +111,17 @@ sqlite-http-refresh file:example.db?_journal=WAL&_sync=NORMAL&_timeout=5000&_txl
105111

106112
### Operating System Schedulers
107113

108-
- **Cron (Linux/macOS):** You can set up cron jobs to execute a script at specified intervals (e.g., every minute, hour, or day). This script would then connect to your SQLite database and perform the desired INSERT operations.
114+
You can set up Cron Jobs (or Task Scheduler) to execute a script at specified intervals (e.g., every minute, hour, or day). This script would then connect to your SQLite database and perform the desired INSERT operations.
109115

110116
Example:
111117

112118
```sql
113-
INSERT INTO temp.http_request SELECT url FROM http_response WHERE unixepoch() - unixepoch(response_time) > :ttl
119+
INSERT INTO temp.http_request
120+
SELECT url FROM http_response
121+
WHERE unixepoch() - unixepoch(response_time) > :ttl ;
114122
```
115123
*ttl is Time to Live in seconds*
116124

117-
- **Task Scheduler (Windows):** Similar to cron, Windows Task Scheduler allows you to schedule tasks, including running scripts or programs that interact with SQLite.
118125

119126
### Programming Language Libraries
120127

cmd/libsql-http-proxy/main.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func main() {
5454
}
5555

5656
if len(fs.GetArgs()) == 0 {
57-
log.Fatalf("Usage: %s <FLAGS> [DatabasePath1] [DatabasePathN\n\nExample:\n\t%s example.db example2.db example3.db\n", os.Args[0], os.Args[0])
57+
log.Fatalf("Usage: %s <FLAGS> [DatabaseDirectory] [local:DatabaseFile]\n\nExample:\n\t%s local:example.db /tmp/example2 \n", os.Args[0], os.Args[0])
5858
}
5959

6060
if *verbose {
@@ -81,10 +81,14 @@ func main() {
8181
}
8282

8383
fnRegisterResonseTables := func(sqlDB *sql.DB, dbPath string) {
84+
err := sqlDB.Ping()
85+
if err != nil {
86+
log.Fatalf("failed to validade database connection: %v", err)
87+
}
8488
if responseTables == nil || len(*responseTables) == 0 {
8589
tableList, err = db.ResponseTables(sqlDB)
8690
if err != nil {
87-
log.Fatalf("discovery response tables: %v", err)
91+
log.Fatalf("discovery response tables: %v\n\tSet the response table name with --response-table flag. \n\n\tExample: --response-table=http_response", err)
8892
}
8993
} else {
9094
tableList = *responseTables
@@ -105,13 +109,18 @@ func main() {
105109
dbs = append(dbs, sqlDB)
106110
continue
107111
}
108-
dir, err := os.MkdirTemp("", "libsql-*")
109-
if err != nil {
110-
log.Fatalf("creating database directory: %v", err)
112+
if *dbPrimaryURL == "" {
113+
log.Fatal("inform --db-primary-url to embbed replication or use local database path. Example: local:app.db")
114+
}
115+
116+
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
117+
err := os.MkdirAll(dbPath, 0750)
118+
if err != nil {
119+
log.Fatalf("creating directory %q: %v", dbPath, err)
120+
}
111121
}
112-
defer os.RemoveAll(dir)
113122

114-
connector, err := libsql.NewEmbeddedReplicaConnector(filepath.Join(dir, dbPath), *dbPrimaryURL, dbOpts...)
123+
connector, err := libsql.NewEmbeddedReplicaConnector(filepath.Join(dbPath, strings.TrimSuffix(filepath.Base(dbPath), ".db"))+".db", *dbPrimaryURL, dbOpts...)
115124
if err != nil {
116125
log.Fatalf("creating database connector: %v", err)
117126
}

cmd/sqlite-http-proxy/main.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func main() {
3636
caCertKey := fs.StringLong("ca-cert-key", "", "Path to CA Certificate Key file (required to HTTPS proxy)")
3737
readOnly := fs.BoolLong("ro", "Read Only mode. Do not store new HTTP responses")
3838
rfc9111 := fs.BoolLong("rfc9111", "Use RFC9111 spec")
39-
shared := fs.BoolLong("shared", "Enable shared cache mode")
39+
shared := fs.BoolLong("shared", "Enable shared cache mode for RFC9111")
4040
_ = fs.String('c', "config", "", "config file (optional)")
4141

4242
if err := ff.Parse(fs, os.Args[1:],
@@ -87,6 +87,9 @@ func main() {
8787
}
8888

8989
}
90+
if len(dsnList) == 0 {
91+
log.Fatal("no database found")
92+
}
9093

9194
for _, dsn := range dsnList {
9295
sqlDB, err := sql.Open("sqlite3", dsn)
@@ -95,12 +98,17 @@ func main() {
9598
}
9699
defer sqlDB.Close()
97100

101+
err = sqlDB.Ping()
102+
if err != nil {
103+
log.Fatalf("failed to validade database connection: %v", err)
104+
}
105+
98106
dbs = append(dbs, sqlDB)
99107

100108
if responseTables == nil || len(*responseTables) == 0 {
101109
tableList, err = db.ResponseTables(sqlDB)
102110
if err != nil {
103-
log.Fatalf("discovery response tables: %v", err)
111+
log.Fatalf("discovery response tables: %v\n\tSet the response table name with --response-table flag. \n\n\tExample: --response-table=http_response", err)
104112
}
105113
} else {
106114
tableList = *responseTables

cmd/sqlite-http-refresh/main.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func main() {
4848
ttl = fs.IntLong("ttl", 30*60, "Time to Live in seconds. Fallback if not use RFC9111")
4949
matchURL = fs.StringLong("match-url", "%", "Filter URLs (SQL syntax)")
5050
rfc9111 = fs.BoolLong("rfc9111", "Refresh data based on RFC9111")
51-
shared = fs.BoolLong("shared", "Enable shared cache mode to RFC9111")
51+
shared = fs.BoolLong("shared", "Enable shared cache mode (RFC9111)")
5252
// Request/Store config
5353
timeout = fs.UintLong("timeout", 30*1000, "Timeout in milliseconds")
5454
insecure = fs.BoolLong("insecure", "Disable TLS verification")
@@ -86,6 +86,11 @@ func main() {
8686
}
8787
defer sqlDB.Close()
8888

89+
err = sqlDB.Ping()
90+
if err != nil {
91+
log.Fatalf("failed to validade database connection: %v", err)
92+
}
93+
8994
var tableList []string
9095
if len(*responseTables) == 0 {
9196
tableList, err = db.ResponseTables(sqlDB)
@@ -104,7 +109,7 @@ func main() {
104109
fn = refreshDataRFC9111
105110
queryTemplate = fmt.Sprintf(`INSERT INTO temp.%%s_refresh(url)
106111
SELECT url FROM %%s
107-
WHERE url LIKE ? AND cachexpiredttl(header, request_time, response_time, %s, ?) = 'true'`, fmt.Sprint(*shared))
112+
WHERE url LIKE ? AND cache_expired_ttl(header, request_time, response_time, %s, ?) = 1`, fmt.Sprint(*shared))
108113
} else {
109114
fn = refreshDataTTL
110115
queryTemplate = `INSERT INTO temp.%s_refresh(url)

extension/age.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ func (m *Age) Args() int {
1818
return 3
1919
}
2020

21-
func (m *Age) Deterministic() bool { return true }
21+
func (m *Age) Deterministic() bool {
22+
return true
23+
}
24+
2225
func (m *Age) Apply(ctx *sqlite.Context, values ...sqlite.Value) {
2326
var header http.Header
2427
if err := json.Unmarshal([]byte(values[0].Text()), &header); err != nil {

extension/entrypoint.go

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,39 @@ import (
1212
//
1313
// #include "sqlite3.h"
1414
//
15-
// extern int sqlite3_extension_init(sqlite3*, char**, const sqlite3_api_routines*);
15+
// extern int sqlite3_extension_init(sqlite3*, char**, const sqlite3_api_routines);
1616
import "C"
1717

1818
func init() {
19-
sqlite.RegisterNamed("default", func(api *sqlite.ExtensionApi) (sqlite.ErrorCode, error) {
20-
if err := api.CreateModule(config.DefaultVirtualTableName, &CacheModule{}, sqlite.ReadOnly(false)); err != nil {
21-
return sqlite.SQLITE_ERROR, err
22-
}
23-
if err := api.CreateFunction("cacheage", &Age{}); err != nil {
24-
return sqlite.SQLITE_ERROR, err
25-
}
26-
if err := api.CreateFunction("cachelifetime", &FreshnessLifetime{}); err != nil {
27-
return sqlite.SQLITE_ERROR, err
28-
}
29-
if err := api.CreateFunction("cachelifetimeshared", &FreshnessLifetime{
30-
shared: true,
31-
}); err != nil {
32-
return sqlite.SQLITE_ERROR, err
33-
}
34-
if err := api.CreateFunction("cachexpired", &Expired{}); err != nil {
35-
return sqlite.SQLITE_ERROR, err
36-
}
37-
if err := api.CreateFunction("cachexpiredttl", &Expired{
38-
fallbackTTL: true,
39-
}); err != nil {
40-
return sqlite.SQLITE_ERROR, err
41-
}
42-
return sqlite.SQLITE_OK, nil
43-
})
19+
sqlite.Register(registerFunc)
4420
C.sqlite3_auto_extension((*[0]byte)(C.sqlite3_extension_init))
4521
}
22+
23+
func registerFunc(api *sqlite.ExtensionApi) (sqlite.ErrorCode, error) {
24+
if err := api.CreateModule(config.DefaultVirtualTableName, &CacheModule{}, sqlite.ReadOnly(false)); err != nil {
25+
return sqlite.SQLITE_ERROR, err
26+
}
27+
if err := api.CreateFunction("cache_info", &Info{}); err != nil {
28+
return sqlite.SQLITE_ERROR, err
29+
}
30+
if err := api.CreateFunction("cache_age", &Age{}); err != nil {
31+
return sqlite.SQLITE_ERROR, err
32+
}
33+
if err := api.CreateFunction("cache_lifetime", &FreshnessLifetime{}); err != nil {
34+
return sqlite.SQLITE_ERROR, err
35+
}
36+
if err := api.CreateFunction("cache_lifetime_shared", &FreshnessLifetime{
37+
shared: true,
38+
}); err != nil {
39+
return sqlite.SQLITE_ERROR, err
40+
}
41+
if err := api.CreateFunction("cache_expired", &Expired{}); err != nil {
42+
return sqlite.SQLITE_ERROR, err
43+
}
44+
if err := api.CreateFunction("cache_expired_ttl", &Expired{
45+
fallbackTTL: true,
46+
}); err != nil {
47+
return sqlite.SQLITE_ERROR, err
48+
}
49+
return sqlite.SQLITE_OK, nil
50+
}

0 commit comments

Comments
 (0)