// Package pocketbase is the placeholder for the PocketBase storage driver. // // The plan (PLAN.md section 4) is an appliance deployment: one binary that // also brings admin auth, a filesystem abstraction for media (local or S3) // and realtime for the admin panel. The event DAG is a poor fit for // PocketBase's record model, so the roomserver and syncapi tables will use // its underlying dbx connection directly rather than its collection API. // // Until that work starts (Phase 10) the driver is compiled in, registered // and fails loudly, so that `database.driver: pocketbase` is a clear error // instead of an unknown-driver one, and so the interface stays honest: // every method the other drivers implement exists here too. package pocketbase import ( "context" "fmt" "log/slog" "github.com/dariuszjaniak/warp/server/internal/storage" ) func init() { storage.Register(storage.DriverPocketBase, Open) } // Database is the not-yet-implemented PocketBase driver. type Database struct{} // Open always fails with storage.ErrNotImplemented. func Open(context.Context, storage.Config, *slog.Logger) (storage.Database, error) { return nil, fmt.Errorf( "pocketbase driver is not implemented yet (planned for Phase 10); use %q or %q: %w", storage.DriverSQLite, storage.DriverPostgres, storage.ErrNotImplemented) } // Driver implements storage.Database. func (*Database) Driver() string { return storage.DriverPocketBase } // Ping implements storage.Database. func (*Database) Ping(context.Context) error { return storage.ErrNotImplemented } // Migrate implements storage.Database. func (*Database) Migrate(context.Context) error { return storage.ErrNotImplemented } // PendingMigrations implements storage.Database. func (*Database) PendingMigrations(context.Context) ([]string, error) { return nil, storage.ErrNotImplemented } // Settings implements storage.Database. func (*Database) Settings() storage.SettingsStore { return notImplementedSettings{} } // Users implements storage.Database. func (*Database) Users() storage.UserStore { return notImplementedUsers{} } // Rooms implements storage.Database. func (*Database) Rooms() storage.RoomStore { return notImplementedRooms{} } // Sync implements storage.Database. func (*Database) Sync() storage.SyncStore { return notImplementedSync{} } // Close implements storage.Database. func (*Database) Close() error { return nil } // notImplementedSettings satisfies storage.SettingsStore by refusing every // call, so a partially wired-up PocketBase deployment cannot silently lose // an admin's federation switch. type notImplementedSettings struct{} func (notImplementedSettings) Get(context.Context, string) (string, bool, error) { return "", false, storage.ErrNotImplemented } func (notImplementedSettings) GetAll(context.Context) (map[string]string, error) { return nil, storage.ErrNotImplemented } func (notImplementedSettings) Set(context.Context, string, string) error { return storage.ErrNotImplemented } func (notImplementedSettings) Delete(context.Context, string) error { return storage.ErrNotImplemented } // notImplementedUsers satisfies storage.UserStore the same way: a // half-wired PocketBase deployment must not accept a registration it cannot // store, or hand out an access token it cannot look up again. type notImplementedUsers struct{} func (notImplementedUsers) CreateAccount(context.Context, storage.NewAccount) (storage.Account, error) { return storage.Account{}, storage.ErrNotImplemented } func (notImplementedUsers) Account(context.Context, string) (storage.Account, error) { return storage.Account{}, storage.ErrNotImplemented } func (notImplementedUsers) PasswordHash(context.Context, string) (string, error) { return "", storage.ErrNotImplemented } func (notImplementedUsers) SetPasswordHash(context.Context, string, string) error { return storage.ErrNotImplemented } func (notImplementedUsers) SetAdmin(context.Context, string, bool) error { return storage.ErrNotImplemented } func (notImplementedUsers) SetDisplayName(context.Context, string, string) error { return storage.ErrNotImplemented } func (notImplementedUsers) SetAvatarURL(context.Context, string, string) error { return storage.ErrNotImplemented } func (notImplementedUsers) ListAccounts(context.Context, storage.AccountFilter) ([]storage.Account, int, error) { return nil, 0, storage.ErrNotImplemented } func (notImplementedUsers) Stats(context.Context) (storage.Stats, error) { return storage.Stats{}, storage.ErrNotImplemented } func (notImplementedUsers) CreateSession(context.Context, storage.NewSession) (storage.Device, error) { return storage.Device{}, storage.ErrNotImplemented } func (notImplementedUsers) RefreshSession(context.Context, storage.RefreshedSession) (storage.TokenInfo, error) { return storage.TokenInfo{}, storage.ErrNotImplemented } func (notImplementedUsers) TokenInfo(context.Context, string) (storage.TokenInfo, error) { return storage.TokenInfo{}, storage.ErrNotImplemented } func (notImplementedUsers) TouchDevice(context.Context, string, string, string, string, int64) error { return storage.ErrNotImplemented } func (notImplementedUsers) Device(context.Context, string, string) (storage.Device, error) { return storage.Device{}, storage.ErrNotImplemented } func (notImplementedUsers) Devices(context.Context, string) ([]storage.Device, error) { return nil, storage.ErrNotImplemented } func (notImplementedUsers) SetDeviceDisplayName(context.Context, string, string, string) error { return storage.ErrNotImplemented } func (notImplementedUsers) DeleteDevices(context.Context, string, []string) (int, error) { return 0, storage.ErrNotImplemented } func (notImplementedUsers) DeleteAllDevices(context.Context, string) (int, error) { return 0, storage.ErrNotImplemented } func (notImplementedUsers) AccountData(context.Context, string, string, string) ([]byte, error) { return nil, storage.ErrNotImplemented } func (notImplementedUsers) SetAccountData(context.Context, string, string, string, []byte) error { return storage.ErrNotImplemented } // notImplementedRooms satisfies storage.RoomStore the same way. It matters // more here than anywhere else: a room whose create event was accepted and // not stored would hand a client a room ID that refers to nothing. type notImplementedRooms struct{} func (notImplementedRooms) CreateRoom(context.Context, storage.NewRoom) error { return storage.ErrNotImplemented } func (notImplementedRooms) Room(context.Context, string) (storage.Room, error) { return storage.Room{}, storage.ErrNotImplemented } func (notImplementedRooms) Write(context.Context, storage.RoomWrite) (int64, error) { return 0, storage.ErrNotImplemented } func (notImplementedRooms) Event(context.Context, string, string) (storage.StoredEvent, error) { return storage.StoredEvent{}, storage.ErrNotImplemented } func (notImplementedRooms) EventsByID(context.Context, string, []string) ([]storage.StoredEvent, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) CurrentState(context.Context, string) ([]storage.StateEntry, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) CurrentStateEvents(context.Context, string) ([]storage.StoredEvent, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) CurrentStateEvent(context.Context, string, string, string) (storage.StoredEvent, error) { return storage.StoredEvent{}, storage.ErrNotImplemented } func (notImplementedRooms) StateBefore(context.Context, string, string) ([]storage.StateEntry, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) Extremities(context.Context, string) ([]storage.StoredEvent, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) Members(context.Context, string, []string) ([]storage.StoredEvent, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) MembershipEntries(context.Context, string, []string) ([]storage.MembershipEntry, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) Membership(context.Context, string, string) (storage.MembershipEntry, error) { return storage.MembershipEntry{}, storage.ErrNotImplemented } func (notImplementedRooms) RoomsForUser(context.Context, string, []string) ([]string, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) MembershipsForUser(context.Context, string, []string) ([]storage.SyncMembership, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) UserMembershipEvents(context.Context, string, string) ([]storage.StoredEvent, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) MaxStreamOrdering(context.Context) (int64, error) { return 0, storage.ErrNotImplemented } func (notImplementedRooms) Timeline(context.Context, storage.TimelineRequest) ([]storage.StoredEvent, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) RoomsWithEvents(context.Context, []string, int64, int64) ([]string, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) StateAtStream(context.Context, string, int64) ([]storage.StateEntry, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) TransactionEvent(context.Context, storage.TransactionRef) (string, error) { return "", storage.ErrNotImplemented } func (notImplementedRooms) CreateAlias(context.Context, storage.RoomAlias) error { return storage.ErrNotImplemented } func (notImplementedRooms) DeleteAlias(context.Context, string) error { return storage.ErrNotImplemented } func (notImplementedRooms) Alias(context.Context, string) (storage.RoomAlias, error) { return storage.RoomAlias{}, storage.ErrNotImplemented } func (notImplementedRooms) AliasesForRoom(context.Context, string) ([]string, error) { return nil, storage.ErrNotImplemented } func (notImplementedRooms) SetPublished(context.Context, string, bool) error { return storage.ErrNotImplemented } func (notImplementedRooms) PublishedRooms(context.Context, storage.RoomFilter) ([]storage.RoomSummary, int, error) { return nil, 0, storage.ErrNotImplemented } func (notImplementedRooms) ListRooms(context.Context, storage.RoomFilter) ([]storage.RoomSummary, int, error) { return nil, 0, storage.ErrNotImplemented } func (notImplementedRooms) RoomSummary(context.Context, string) (storage.RoomSummary, error) { return storage.RoomSummary{}, storage.ErrNotImplemented } func (notImplementedRooms) PurgeRoom(context.Context, string) error { return storage.ErrNotImplemented } func (notImplementedRooms) RoomStats(context.Context) (storage.RoomStats, error) { return storage.RoomStats{}, storage.ErrNotImplemented } // notImplementedSync satisfies storage.SyncStore the same way. A sync that // returned an empty success would be worse than an error: a client would // take it for "nothing has happened" and stop asking. type notImplementedSync struct{} func (notImplementedSync) StreamPositions(context.Context) (storage.StreamPositions, error) { return storage.StreamPositions{}, storage.ErrNotImplemented } func (notImplementedSync) SetReceipt(context.Context, storage.Receipt) (int64, bool, error) { return 0, false, storage.ErrNotImplemented } func (notImplementedSync) Receipts(context.Context, []string, int64, int64) ([]storage.Receipt, error) { return nil, storage.ErrNotImplemented } func (notImplementedSync) ReceiptsForUser(context.Context, string, []string) ([]storage.Receipt, error) { return nil, storage.ErrNotImplemented } func (notImplementedSync) SendToDevice(context.Context, []storage.NewToDeviceMessage) (int64, error) { return 0, storage.ErrNotImplemented } func (notImplementedSync) ToDeviceMessages(context.Context, string, string, int64, int64, int) ([]storage.ToDeviceMessage, error) { return nil, storage.ErrNotImplemented } func (notImplementedSync) DeleteToDeviceMessages(context.Context, string, string, int64) error { return storage.ErrNotImplemented } func (notImplementedSync) SetPresence(context.Context, storage.PresenceState) (int64, bool, error) { return 0, false, storage.ErrNotImplemented } func (notImplementedSync) Presence(context.Context, string) (storage.PresenceState, error) { return storage.PresenceState{}, storage.ErrNotImplemented } func (notImplementedSync) PresenceForUsers(context.Context, []string, int64, int64) ([]storage.PresenceState, error) { return nil, storage.ErrNotImplemented } func (notImplementedSync) AccountDataChanges(context.Context, string, int64, int64) ([]storage.AccountDataEntry, error) { return nil, storage.ErrNotImplemented } func (notImplementedSync) AccountDataAt(context.Context, string, int64) ([]storage.AccountDataEntry, error) { return nil, storage.ErrNotImplemented } func (notImplementedSync) SaveFilter(context.Context, string, []byte, int64) (string, error) { return "", storage.ErrNotImplemented } func (notImplementedSync) Filter(context.Context, string, string) ([]byte, error) { return nil, storage.ErrNotImplemented } // Compile-time proof that the stub keeps up with the interfaces. var ( _ storage.Database = (*Database)(nil) _ storage.UserStore = notImplementedUsers{} _ storage.RoomStore = notImplementedRooms{} _ storage.SyncStore = notImplementedSync{} )