package db import ( "database/sql" _ "embed" "errors" "fmt" "os" "strings" "time" "git.tilde.town/tildetown/bbj2/server/cmd/config" _ "github.com/mattn/go-sqlite3" ) //go:embed schema.sql var schemaSQL string // TODO I'm not sold on this hash system; without transport encryption, it // doesn't really help anything. I'd rather have plaintext + transport // encryption and then, on the server side, proper salted hashing. I can't // figure out if there was a reason for this approach that I'm just // overlooking. type User struct { ID string Username string Hash string } type Thread struct { ID string `json:"thread_id"` Author string Title string LastMod time.Time `json:"last_mod"` Created time.Time ReplyCount int `json:"reply_count"` Pinned int // TODO bool LastAuthor string `json:"last_author"` Messages []Message } type Message struct { ThreadID string `json:"thread_id"` PostID string `json:"post_id"` Author string Created time.Time Edited int // TODO bool Body string SendRaw int `json:"send_raw"` // TODO bool } func Setup(opts config.Options) (func(), error) { db, err := sql.Open("sqlite3", opts.Config.DBPath) opts.DB = db return func() { db.Close() }, err } func EnsureSchema(opts config.Options) error { db := opts.DB if opts.Reset { err := os.Remove(opts.Config.DBPath) if err != nil { return fmt.Errorf("failed to delete database: %w", err) } } rows, err := db.Query("select version from meta") if err == nil { defer rows.Close() rows.Next() var version string err = rows.Scan(&version) if err != nil { return fmt.Errorf("failed to check database schema version: %w", err) } else if version == "" { return errors.New("database is in unknown state") } return nil } if !strings.Contains(err.Error(), "no such table") { return fmt.Errorf("got error checking database state: %w", err) } _, err = db.Exec(schemaSQL) if err != nil { return fmt.Errorf("failed to initialize database schema: %w", err) } return nil }