mirror of
https://github.com/hanzoai/base.git
synced 2026-10-21 03:41:50 +00:00
Bumps github.com/hanzoai/sqlite v0.2.3 → v0.3.2. v0.3.2 vendors its pure-Go engine,
so modernc.org/{sqlite,libc,mathutil,memory} and mattn/go-sqlite3 drop out of the
module graph entirely — Base now runs on hanzoai/sqlite's named root API
(HookRegisterer, PragmaDSN, DefaultPragmas, CommitHookRegisterer) with zero modernc.
Comments that named the old modernc/mattn backends are corrected to the current
pure-Go (!cgo) and hanzoai/sqlcipher (cgo) backends.
go build ./... green (cgo + nocgo); go test ./apis ./store/... ./core/... ./plugins/waitlist
green under CGO_ENABLED=0 (Base's build config).
Co-authored-by: Hanzo Dev <[email protected]>
92 lines
3.1 KiB
Go
92 lines
3.1 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"github.com/hanzoai/base/network"
|
|
"github.com/hanzoai/dbx"
|
|
"github.com/hanzoai/sqlite"
|
|
)
|
|
|
|
// baseNetwork is a local alias for network.Network so the BaseApp field can
|
|
// use a short name without shadowing the imported package.
|
|
type baseNetwork = network.Network
|
|
|
|
// attachNetwork is the one hook point into BaseApp that network integration
|
|
// requires. It is called at the end of initDataDB — standalone mode (the
|
|
// default) is a fast-path return with zero cost.
|
|
//
|
|
// When BASE_NETWORK=quasar, it builds a Network from the environment,
|
|
// starts it, and installs a commit hook on one pooled concurrentDB
|
|
// connection per shard key. Today we register a single hook against the
|
|
// default shard ("_") so baseline replication works; multi-shard
|
|
// registration is driven by per-request shard resolution upstream.
|
|
func (app *BaseApp) attachNetwork(ctx context.Context) error {
|
|
net, err := network.FromEnv()
|
|
if err != nil {
|
|
return fmt.Errorf("network from env: %w", err)
|
|
}
|
|
if !net.Enabled() {
|
|
return nil
|
|
}
|
|
if err := net.Start(ctx); err != nil {
|
|
return fmt.Errorf("network start: %w", err)
|
|
}
|
|
app.network = net
|
|
|
|
db := app.concurrentDB
|
|
if db == nil {
|
|
return nil
|
|
}
|
|
return installCommitHook(ctx, db, net, "_")
|
|
}
|
|
|
|
// installCommitHook reserves one *sql.Conn from the pool and wires the
|
|
// network commit hook onto its driver conn. The conn is retained for the
|
|
// lifetime of the process so the hook outlives pool churn.
|
|
//
|
|
// Failure here is soft: we log but do not block Bootstrap — a broken
|
|
// transport is less harmful than a refusal to start.
|
|
func installCommitHook(ctx context.Context, db dbx.Builder, net network.Network, shardID string) error {
|
|
sqlDB, ok := unwrapSQL(db)
|
|
if !ok {
|
|
return fmt.Errorf("network: db is not *sql.DB (got %T)", db)
|
|
}
|
|
raw, err := sqlDB.Conn(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("network: reserve conn: %w", err)
|
|
}
|
|
return raw.Raw(func(driverConn any) error {
|
|
reg, ok := sqlite.CommitHookRegisterer(driverConn)
|
|
if !ok {
|
|
return fmt.Errorf("network: driver conn %T has no commit hook", driverConn)
|
|
}
|
|
return net.InstallWALHook(commitHookAdapter{reg}, shardID)
|
|
})
|
|
}
|
|
|
|
// commitHookAdapter narrows hanzoai/sqlite's HookRegisterer to the network
|
|
// package's own HookRegisterer shape, which takes func() int32 directly rather
|
|
// than the sqlite.CommitHookFn named type. This adapter is the ONE place in Base
|
|
// where the sqlite driver type touches the integration surface: the network
|
|
// package stays backend-agnostic, and hanzoai/sqlite hides whether the pure-Go
|
|
// or hanzoai/sqlcipher backend is active (CommitHookRegisterer resolves the raw conn).
|
|
type commitHookAdapter struct{ inner sqlite.HookRegisterer }
|
|
|
|
func (c commitHookAdapter) RegisterCommitHook(cb func() int32) {
|
|
c.inner.RegisterCommitHook(sqlite.CommitHookFn(cb))
|
|
}
|
|
|
|
// unwrapSQL pulls the underlying *sql.DB out of a dbx.Builder. dbx.DB
|
|
// exposes DB() explicitly; other builders (transactions, wrappers) return
|
|
// false so the caller can degrade gracefully.
|
|
func unwrapSQL(b dbx.Builder) (*sql.DB, bool) {
|
|
type hasDB interface{ DB() *sql.DB }
|
|
if v, ok := b.(hasDB); ok {
|
|
return v.DB(), true
|
|
}
|
|
return nil, false
|
|
}
|