···11-package knotserver
22-33-import (
44- "compress/gzip"
55- "fmt"
66- "net/http"
77- "strings"
88-99- securejoin "github.com/cyphar/filepath-securejoin"
1010- "github.com/go-chi/chi/v5"
1111- "github.com/go-git/go-git/v5/plumbing"
1212- "tangled.org/core/knotserver/git"
1313-)
1414-1515-func (h *Knot) Archive(w http.ResponseWriter, r *http.Request) {
1616- var (
1717- did = chi.URLParam(r, "did")
1818- name = chi.URLParam(r, "name")
1919- ref = chi.URLParam(r, "ref")
2020- )
2121- repo, err := securejoin.SecureJoin(did, name)
2222- if err != nil {
2323- gitError(w, "repository not found", http.StatusNotFound)
2424- h.l.Error("git: failed to secure join repo path", "handler", "InfoRefs", "error", err)
2525- return
2626- }
2727-2828- repoPath, err := securejoin.SecureJoin(h.c.Repo.ScanPath, repo)
2929- if err != nil {
3030- gitError(w, "repository not found", http.StatusNotFound)
3131- h.l.Error("git: failed to secure join repo path", "handler", "InfoRefs", "error", err)
3232- return
3333- }
3434-3535- gr, err := git.Open(repoPath, ref)
3636-3737- immutableLink := fmt.Sprintf(
3838- "https://%s/%s/%s/archive/%s",
3939- h.c.Server.Hostname,
4040- did,
4141- name,
4242- gr.Hash(),
4343- )
4444-4545- safeRefFilename := strings.ReplaceAll(plumbing.ReferenceName(ref).Short(), "/", "-")
4646- filename := fmt.Sprintf("%s-%s.tar.gz", name, safeRefFilename)
4747- w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
4848- w.Header().Set("Content-Type", "application/gzip")
4949- w.Header().Set("Link", fmt.Sprintf("<%s>; rel=\"immutable\"", immutableLink))
5050-5151- gw := gzip.NewWriter(w)
5252- defer gw.Close()
5353-5454- err = gr.WriteTar(gw, "")
5555- if err != nil {
5656- // once we start writing to the body we can't report error anymore
5757- // so we are only left with logging the error
5858- h.l.Error("writing tar file", "error", err)
5959- return
6060- }
6161-6262- err = gw.Flush()
6363- if err != nil {
6464- // once we start writing to the body we can't report error anymore
6565- // so we are only left with logging the error
6666- h.l.Error("flushing", "error", err.Error())
6767- return
6868- }
6969-}
+81
knotserver/db/db.go
···11+package db
22+33+import (
44+ "context"
55+ "database/sql"
66+ "log/slog"
77+ "strings"
88+99+ _ "github.com/mattn/go-sqlite3"
1010+ "tangled.org/core/log"
1111+)
1212+1313+type DB struct {
1414+ db *sql.DB
1515+ logger *slog.Logger
1616+}
1717+1818+func Setup(ctx context.Context, dbPath string) (*DB, error) {
1919+ // https://github.com/mattn/go-sqlite3#connection-string
2020+ opts := []string{
2121+ "_foreign_keys=1",
2222+ "_journal_mode=WAL",
2323+ "_synchronous=NORMAL",
2424+ "_auto_vacuum=incremental",
2525+ }
2626+2727+ logger := log.FromContext(ctx)
2828+ logger = log.SubLogger(logger, "db")
2929+3030+ db, err := sql.Open("sqlite3", dbPath+"?"+strings.Join(opts, "&"))
3131+ if err != nil {
3232+ return nil, err
3333+ }
3434+3535+ conn, err := db.Conn(ctx)
3636+ if err != nil {
3737+ return nil, err
3838+ }
3939+ defer conn.Close()
4040+4141+ _, err = conn.ExecContext(ctx, `
4242+ create table if not exists known_dids (
4343+ did text primary key
4444+ );
4545+4646+ create table if not exists public_keys (
4747+ id integer primary key autoincrement,
4848+ did text not null,
4949+ key text not null,
5050+ created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
5151+ unique(did, key),
5252+ foreign key (did) references known_dids(did) on delete cascade
5353+ );
5454+5555+ create table if not exists _jetstream (
5656+ id integer primary key autoincrement,
5757+ last_time_us integer not null
5858+ );
5959+6060+ create table if not exists events (
6161+ rkey text not null,
6262+ nsid text not null,
6363+ event text not null, -- json
6464+ created integer not null default (strftime('%s', 'now')),
6565+ primary key (rkey, nsid)
6666+ );
6767+6868+ create table if not exists migrations (
6969+ id integer primary key autoincrement,
7070+ name text unique
7171+ );
7272+ `)
7373+ if err != nil {
7474+ return nil, err
7575+ }
7676+7777+ return &DB{
7878+ db: db,
7979+ logger: logger,
8080+ }, nil
8181+}
-64
knotserver/db/init.go
···11-package db
22-33-import (
44- "database/sql"
55- "strings"
66-77- _ "github.com/mattn/go-sqlite3"
88-)
99-1010-type DB struct {
1111- db *sql.DB
1212-}
1313-1414-func Setup(dbPath string) (*DB, error) {
1515- // https://github.com/mattn/go-sqlite3#connection-string
1616- opts := []string{
1717- "_foreign_keys=1",
1818- "_journal_mode=WAL",
1919- "_synchronous=NORMAL",
2020- "_auto_vacuum=incremental",
2121- }
2222-2323- db, err := sql.Open("sqlite3", dbPath+"?"+strings.Join(opts, "&"))
2424- if err != nil {
2525- return nil, err
2626- }
2727-2828- // NOTE: If any other migration is added here, you MUST
2929- // copy the pattern in appview: use a single sql.Conn
3030- // for every migration.
3131-3232- _, err = db.Exec(`
3333- create table if not exists known_dids (
3434- did text primary key
3535- );
3636-3737- create table if not exists public_keys (
3838- id integer primary key autoincrement,
3939- did text not null,
4040- key text not null,
4141- created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
4242- unique(did, key),
4343- foreign key (did) references known_dids(did) on delete cascade
4444- );
4545-4646- create table if not exists _jetstream (
4747- id integer primary key autoincrement,
4848- last_time_us integer not null
4949- );
5050-5151- create table if not exists events (
5252- rkey text not null,
5353- nsid text not null,
5454- event text not null, -- json
5555- created integer not null default (strftime('%s', 'now')),
5656- primary key (rkey, nsid)
5757- );
5858- `)
5959- if err != nil {
6060- return nil, err
6161- }
6262-6363- return &DB{db: db}, nil
6464-}