linstrom/storage/storage.go

163 lines
4.3 KiB
Go
Raw Normal View History

2024-09-13 09:58:29 +00:00
// 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
2024-05-31 09:54:39 +00:00
package storage
import (
"crypto/ed25519"
"fmt"
"github.com/rs/zerolog/log"
"gitlab.com/mstarongitlab/linstrom/config"
2024-09-12 06:56:57 +00:00
"gitlab.com/mstarongitlab/linstrom/storage/cache"
"gitlab.com/mstarongitlab/linstrom/util"
2024-05-31 09:54:39 +00:00
"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
2024-05-31 15:21:29 +00:00
// Storage is responsible for all database, cache and media related actions
// and serves as the lowest layer of the cake
2024-05-31 09:54:39 +00:00
type Storage struct {
2024-09-12 06:56:57 +00:00
db *gorm.DB
cache *cache.Cache
2024-05-31 09:54:39 +00:00
}
func NewStorage(dbUrl string, cache *cache.Cache) (*Storage, error) {
defer util.Untrace(util.Trace(&log.Logger))
db, err := gorm.Open(postgres.Open(dbUrl), &gorm.Config{
Logger: newGormLogger(log.Logger),
})
2024-05-31 09:54:39 +00:00
if err != nil {
return nil, err
}
err = db.AutoMigrate(
2024-09-13 07:18:05 +00:00
MediaMetadata{},
2024-08-28 15:20:38 +00:00
Account{},
RemoteServer{},
Note{},
Role{},
PasskeySession{},
InboundJob{},
OutboundJob{},
AccessToken{},
Emote{},
UserInfoField{},
2024-05-31 15:21:29 +00:00
)
2024-09-12 06:56:57 +00:00
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.insertPlaceholderFile(); err != nil {
return nil, fmt.Errorf("placeholder file insertion failed: %w", err)
}
if err = s.insertSelfFromConfig(); err != nil {
return nil, fmt.Errorf("self insertion failed: %w", err)
2024-09-12 06:56:57 +00:00
}
2024-05-31 15:21:29 +00:00
return s, nil
}
func (s *Storage) insertSelfFromConfig() error {
defer util.Untrace(util.Trace(&log.Logger))
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: "placeholder", // 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{},
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,
Icon: "placeholder",
Background: nil,
Banner: nil,
}).
FirstOrCreate(&serverActor).Error
if err != nil {
return err
}
return nil
2024-05-31 09:54:39 +00:00
}
func (s *Storage) insertDefaultRoles() error {
defer util.Untrace(util.Trace(&log.Logger))
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
}
func (s *Storage) insertPlaceholderFile() error {
defer util.Untrace(util.Trace(&log.Logger))
return s.db.Model(&MediaMetadata{}).Assign(&MediaMetadata{
ID: "placeholder",
Type: "image/webp",
Name: "placeholderFile",
Blurred: false,
Remote: false,
Location: "/placeholder-file",
AltText: "Greyscale image of a pidgeon, captioned with the text \"Duck\"",
}).FirstOrCreate(&MediaMetadata{}).Error
}