162 lines
4.3 KiB
Go
162 lines
4.3 KiB
Go
// 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"
|
|
"gitlab.com/mstarongitlab/linstrom/util"
|
|
"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) {
|
|
defer util.Untrace(util.Trace(&log.Logger))
|
|
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{},
|
|
UserInfoField{},
|
|
)
|
|
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)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|