// TODO: Unify function names // Storage is the handler for cache and db access // It handles storing various data in the database as well as caching that data // Said data includes notes, accounts, metadata about media files, servers and similar package storage import ( "crypto/ed25519" "fmt" "github.com/rs/zerolog/log" "gitlab.com/mstarongitlab/linstrom/config" "gitlab.com/mstarongitlab/linstrom/storage/cache" "gorm.io/driver/postgres" "gorm.io/gorm" ) // Always keep a reference of the server's own RemoteServer entry here // Removes the need to perform a db request every time a new local anything // is created var serverSelf RemoteServer // Storage is responsible for all database, cache and media related actions // and serves as the lowest layer of the cake type Storage struct { db *gorm.DB cache *cache.Cache } func NewStorage(dbUrl string, cache *cache.Cache) (*Storage, error) { db, err := gorm.Open(postgres.Open(dbUrl), &gorm.Config{ Logger: newGormLogger(log.Logger), }) if err != nil { return nil, err } err = db.AutoMigrate( MediaMetadata{}, Account{}, RemoteServer{}, Note{}, Role{}, PasskeySession{}, InboundJob{}, OutboundJob{}, AccessToken{}, Emote{}, ) if err != nil { return nil, fmt.Errorf("failed to apply migrations: %w", err) } s := &Storage{db, cache} if err = s.insertDefaultRoles(); err != nil { return nil, fmt.Errorf("default roles insertion failed: %w", err) } if err = s.insertSelfFromConfig(); err != nil { return nil, fmt.Errorf("self insertion failed: %w", err) } return s, nil } func (s *Storage) insertSelfFromConfig() error { const ServerActorId = "self" var err error // Insert server info serverData := RemoteServer{} err = s.db.Where("id = 1"). // Set once on creation Attrs(RemoteServer{ Domain: config.GlobalConfig.General.GetFullDomain(), }). // Set every time Assign(RemoteServer{ IsSelf: true, Name: config.GlobalConfig.Self.ServerDisplayName, ServerType: REMOTE_SERVER_LINSTROM, // Icon: "", // TODO: Set to server icon media }).FirstOrCreate(&serverData).Error if err != nil { return err } // Set module specific global var serverSelf = serverData // Insert server actor serverActor := Account{} serverActorPublicKey, serverActorPrivateKey, err := ed25519.GenerateKey(nil) if err != nil { return err } err = s.db.Where(Account{ID: ServerActorId}). // Values to always (re)set after launch Assign(Account{ Username: "self", DisplayName: config.GlobalConfig.Self.ServerActorDisplayName, // Server: serverData, ServerId: serverData.ID, // CustomFields: []uint{}, Description: "Server actor of a Linstrom server", // Tags: []string{}, IsBot: true, // Followers: []string{}, // Follows: []string{}, // Icon: "", // TODO: Replace with reference to server icon // Background: "", // TODO: Replace with reference to background media // Banner: "", // TODO: Replace with reference to banner media Indexable: false, RestrictedFollow: false, IdentifiesAs: []Being{}, Gender: []string{}, Roles: []string{"ServerActor"}, // TODO: Add server actor role once created }). // Values that'll only be set on first creation Attrs(Account{ PublicKey: serverActorPublicKey, PrivateKey: serverActorPrivateKey, }). FirstOrCreate(&serverActor).Error if err != nil { return err } return nil } func (s *Storage) insertDefaultRoles() error { for _, role := range allDefaultRoles { log.Debug().Str("role-name", role.Name).Msg("Inserting default role") if err := s.db.FirstOrCreate(role).Error; err != nil { return err } } return nil }