Hallucinate a whole lot of shit...
Too much shit...
This commit is contained in:
45
esi/sso.go
45
esi/sso.go
@@ -16,12 +16,13 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go-eve-pi/repositories"
|
||||||
"go-eve-pi/types"
|
"go-eve-pi/types"
|
||||||
"gorm.io/gorm"
|
|
||||||
|
|
||||||
logger "git.site.quack-lab.dev/dave/cylogger"
|
logger "git.site.quack-lab.dev/dave/cylogger"
|
||||||
"github.com/fasthttp/router"
|
"github.com/fasthttp/router"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -29,18 +30,14 @@ const (
|
|||||||
issuerTokenURL = "https://login.eveonline.com/v2/oauth/token"
|
issuerTokenURL = "https://login.eveonline.com/v2/oauth/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DB interface for database operations
|
// CharacterRepositoryInterface defines the interface for character operations
|
||||||
type DB interface {
|
type CharacterRepositoryInterface = repositories.CharacterRepositoryInterface
|
||||||
GetCharacterByName(characterName string) (*types.Character, error)
|
|
||||||
SaveCharacter(character *types.Character) error
|
|
||||||
AutoMigrate(dst ...interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type SSO struct {
|
type SSO struct {
|
||||||
clientID string
|
clientID string
|
||||||
redirectURI string
|
redirectURI string
|
||||||
scopes []string
|
scopes []string
|
||||||
db DB
|
characterRepo CharacterRepositoryInterface
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
router *router.Router
|
router *router.Router
|
||||||
state string
|
state string
|
||||||
@@ -52,19 +49,14 @@ type SSO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewSSO creates a new SSO instance
|
// NewSSO creates a new SSO instance
|
||||||
func NewSSO(clientID, redirectURI string, scopes []string, db DB) (*SSO, error) {
|
func NewSSO(clientID, redirectURI string, scopes []string, characterRepo CharacterRepositoryInterface) (*SSO, error) {
|
||||||
logger.Info("Creating new SSO instance for clientID %s with redirectURI %s and scopes %v", clientID, redirectURI, scopes)
|
logger.Info("Creating new SSO instance for clientID %s with redirectURI %s and scopes %v", clientID, redirectURI, scopes)
|
||||||
|
|
||||||
s := &SSO{
|
s := &SSO{
|
||||||
clientID: clientID,
|
clientID: clientID,
|
||||||
redirectURI: redirectURI,
|
redirectURI: redirectURI,
|
||||||
scopes: scopes,
|
scopes: scopes,
|
||||||
db: db,
|
characterRepo: characterRepo,
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.initDB(); err != nil {
|
|
||||||
logger.Error("Failed to initialize SSO database %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("SSO instance created successfully")
|
logger.Info("SSO instance created successfully")
|
||||||
@@ -78,16 +70,7 @@ func (s *SSO) SetRouter(r *router.Router) {
|
|||||||
s.setupCallbackHandler()
|
s.setupCallbackHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSO) initDB() error {
|
// initDB is no longer needed as migrations are handled by the repository
|
||||||
logger.Debug("Initializing SSO database schema")
|
|
||||||
err := s.db.AutoMigrate(&types.Character{})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to migrate Token table %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
logger.Debug("SSO database schema initialized successfully")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCharacter returns a valid character object for the given character name
|
// GetCharacter returns a valid character object for the given character name
|
||||||
// If no token exists, it will start the OAuth flow
|
// If no token exists, it will start the OAuth flow
|
||||||
@@ -98,7 +81,7 @@ func (s *SSO) GetCharacter(ctx context.Context, characterName string) (types.Cha
|
|||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
// Try to get existing token from DB
|
// Try to get existing token from DB
|
||||||
char, err := s.db.GetCharacterByName(characterName)
|
char, err := s.characterRepo.GetCharacterByName(characterName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
logger.Info("No existing token found for character %s, starting authentication flow", characterName)
|
logger.Info("No existing token found for character %s, starting authentication flow", characterName)
|
||||||
@@ -107,7 +90,7 @@ func (s *SSO) GetCharacter(ctx context.Context, characterName string) (types.Cha
|
|||||||
return types.Character{}, err
|
return types.Character{}, err
|
||||||
}
|
}
|
||||||
// After authentication, fetch the token from DB
|
// After authentication, fetch the token from DB
|
||||||
char, err = s.db.GetCharacterByName(characterName)
|
char, err = s.characterRepo.GetCharacterByName(characterName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.Character{}, err
|
return types.Character{}, err
|
||||||
}
|
}
|
||||||
@@ -124,7 +107,7 @@ func (s *SSO) GetCharacter(ctx context.Context, characterName string) (types.Cha
|
|||||||
if eveCharID > 0 {
|
if eveCharID > 0 {
|
||||||
char.ID = eveCharID
|
char.ID = eveCharID
|
||||||
logger.Debug("Updating character %s with ID: %d", characterName, eveCharID)
|
logger.Debug("Updating character %s with ID: %d", characterName, eveCharID)
|
||||||
if err := s.db.SaveCharacter(char); err != nil {
|
if err := s.characterRepo.SaveCharacter(char); err != nil {
|
||||||
logger.Warning("Failed to update character %s with ID: %v", characterName, err)
|
logger.Warning("Failed to update character %s with ID: %v", characterName, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -143,7 +126,7 @@ func (s *SSO) GetCharacter(ctx context.Context, characterName string) (types.Cha
|
|||||||
return types.Character{}, err
|
return types.Character{}, err
|
||||||
}
|
}
|
||||||
// After re-authentication, fetch the token from DB
|
// After re-authentication, fetch the token from DB
|
||||||
char, err = s.db.GetCharacterByName(characterName)
|
char, err = s.characterRepo.GetCharacterByName(characterName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.Character{}, err
|
return types.Character{}, err
|
||||||
}
|
}
|
||||||
@@ -213,7 +196,7 @@ func (s *SSO) startAuthFlow(ctx context.Context, characterName string) error {
|
|||||||
_, eveCharID := parseTokenCharacter(char.AccessToken)
|
_, eveCharID := parseTokenCharacter(char.AccessToken)
|
||||||
char.ID = eveCharID
|
char.ID = eveCharID
|
||||||
logger.Debug("Saving token to database for character %s (EVE ID: %d)", characterName, eveCharID)
|
logger.Debug("Saving token to database for character %s (EVE ID: %d)", characterName, eveCharID)
|
||||||
if err := s.db.SaveCharacter(char); err != nil {
|
if err := s.characterRepo.SaveCharacter(char); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,7 +380,7 @@ func (s *SSO) refreshToken(ctx context.Context, char *types.Character) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("Saving refreshed token to database for character %s", char.CharacterName)
|
logger.Debug("Saving refreshed token to database for character %s", char.CharacterName)
|
||||||
if err := s.db.SaveCharacter(char); err != nil {
|
if err := s.characterRepo.SaveCharacter(char); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
main.go
9
main.go
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"go-eve-pi/esi"
|
"go-eve-pi/esi"
|
||||||
"go-eve-pi/options"
|
"go-eve-pi/options"
|
||||||
|
"go-eve-pi/repositories"
|
||||||
"go-eve-pi/routes"
|
"go-eve-pi/routes"
|
||||||
wh "go-eve-pi/webhook"
|
wh "go-eve-pi/webhook"
|
||||||
|
|
||||||
@@ -36,11 +37,19 @@ func main() {
|
|||||||
logger.Init(logger.ParseLevel(options.GlobalOptions.LogLevel))
|
logger.Init(logger.ParseLevel(options.GlobalOptions.LogLevel))
|
||||||
logger.Info("Starting Eve PI")
|
logger.Info("Starting Eve PI")
|
||||||
|
|
||||||
|
// Initialize database with repositories
|
||||||
|
database, err := repositories.NewDatabase()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to initialize database: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Create SSO instance
|
// Create SSO instance
|
||||||
sso, err := esi.NewSSO(
|
sso, err := esi.NewSSO(
|
||||||
options.GlobalOptions.ClientID,
|
options.GlobalOptions.ClientID,
|
||||||
options.GlobalOptions.RedirectURI,
|
options.GlobalOptions.RedirectURI,
|
||||||
options.GlobalOptions.Scopes,
|
options.GlobalOptions.Scopes,
|
||||||
|
database.Character,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to create SSO instance %v", err)
|
logger.Error("Failed to create SSO instance %v", err)
|
||||||
|
|||||||
30
repositories/base.go
Normal file
30
repositories/base.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BaseRepository provides common database operations
|
||||||
|
type BaseRepository struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBaseRepository creates a new base repository
|
||||||
|
func NewBaseRepository(db *gorm.DB) *BaseRepository {
|
||||||
|
return &BaseRepository{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DB returns the underlying gorm.DB instance
|
||||||
|
func (r *BaseRepository) DB() *gorm.DB {
|
||||||
|
return r.db
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw executes raw SQL
|
||||||
|
func (r *BaseRepository) Raw(sql string, args ...any) *gorm.DB {
|
||||||
|
return r.db.Raw(sql, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutoMigrate runs auto migration
|
||||||
|
func (r *BaseRepository) AutoMigrate(dst ...interface{}) error {
|
||||||
|
return r.db.AutoMigrate(dst...)
|
||||||
|
}
|
||||||
44
repositories/cache.go
Normal file
44
repositories/cache.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-eve-pi/types"
|
||||||
|
|
||||||
|
logger "git.site.quack-lab.dev/dave/cylogger"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CacheRepository handles cache-related database operations
|
||||||
|
type CacheRepository struct {
|
||||||
|
*BaseRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCacheRepository creates a new cache repository
|
||||||
|
func NewCacheRepository(db *gorm.DB) *CacheRepository {
|
||||||
|
return &CacheRepository{
|
||||||
|
BaseRepository: NewBaseRepository(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCacheEntry retrieves a cache entry by URL hash
|
||||||
|
func (r *CacheRepository) GetCacheEntry(urlHash string) (*types.CacheEntry, error) {
|
||||||
|
logger.Debug("Fetching cache entry for hash: %s", urlHash)
|
||||||
|
var entry types.CacheEntry
|
||||||
|
err := r.db.Where("url_hash = ?", urlHash).First(&entry).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("No cache entry found for hash %s: %v", urlHash, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
logger.Debug("Cache entry found for hash %s", urlHash)
|
||||||
|
return &entry, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveCacheEntry saves a cache entry to the database
|
||||||
|
func (r *CacheRepository) SaveCacheEntry(entry *types.CacheEntry) error {
|
||||||
|
logger.Debug("Saving cache entry for hash: %s", entry.URLHash)
|
||||||
|
err := r.db.Save(entry).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("Cache entry saved successfully for hash %s", entry.URLHash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
44
repositories/character.go
Normal file
44
repositories/character.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-eve-pi/types"
|
||||||
|
|
||||||
|
logger "git.site.quack-lab.dev/dave/cylogger"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CharacterRepository handles character-related database operations
|
||||||
|
type CharacterRepository struct {
|
||||||
|
*BaseRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCharacterRepository creates a new character repository
|
||||||
|
func NewCharacterRepository(db *gorm.DB) *CharacterRepository {
|
||||||
|
return &CharacterRepository{
|
||||||
|
BaseRepository: NewBaseRepository(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCharacterByName retrieves a character by name
|
||||||
|
func (r *CharacterRepository) GetCharacterByName(characterName string) (*types.Character, error) {
|
||||||
|
logger.Debug("Fetching token for character %s from database", characterName)
|
||||||
|
var char types.Character
|
||||||
|
err := r.db.Where("character_name = ?", characterName).First(&char).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug("No token found for character %s: %v", characterName, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
logger.Debug("Token found for character %s, expires at %v", characterName, char.ExpiresAt)
|
||||||
|
return &char, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveCharacter saves a character to the database
|
||||||
|
func (r *CharacterRepository) SaveCharacter(character *types.Character) error {
|
||||||
|
logger.Debug("Saving token for character %s to database", character.CharacterName)
|
||||||
|
err := r.db.Save(character).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("Token saved successfully for character %s", character.CharacterName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
64
repositories/database.go
Normal file
64
repositories/database.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"go-eve-pi/options"
|
||||||
|
"go-eve-pi/types"
|
||||||
|
|
||||||
|
"gorm.io/driver/sqlite"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
logger "git.site.quack-lab.dev/dave/cylogger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Database manages all repositories and provides a unified interface
|
||||||
|
type Database struct {
|
||||||
|
*gorm.DB
|
||||||
|
Character *CharacterRepository
|
||||||
|
Cache *CacheRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDatabase creates a new database instance with all repositories
|
||||||
|
func NewDatabase() (*Database, error) {
|
||||||
|
// Get database path from options
|
||||||
|
dbPath := options.GlobalOptions.DBPath
|
||||||
|
if dbPath == "" {
|
||||||
|
dbPath = "eve-pi.db"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure directory exists
|
||||||
|
dir := filepath.Dir(dbPath)
|
||||||
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to database
|
||||||
|
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to connect to database: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Connected to database: %s", dbPath)
|
||||||
|
|
||||||
|
// Create repositories
|
||||||
|
characterRepo := NewCharacterRepository(db)
|
||||||
|
cacheRepo := NewCacheRepository(db)
|
||||||
|
|
||||||
|
database := &Database{
|
||||||
|
DB: db,
|
||||||
|
Character: characterRepo,
|
||||||
|
Cache: cacheRepo,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run migrations
|
||||||
|
if err := database.AutoMigrate(&types.Character{}, &types.CacheEntry{}); err != nil {
|
||||||
|
logger.Error("Failed to run database migrations: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Database initialized successfully")
|
||||||
|
return database, nil
|
||||||
|
}
|
||||||
9
repositories/interfaces.go
Normal file
9
repositories/interfaces.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import "go-eve-pi/types"
|
||||||
|
|
||||||
|
// CharacterRepositoryInterface defines the interface for character operations
|
||||||
|
type CharacterRepositoryInterface interface {
|
||||||
|
GetCharacterByName(characterName string) (*types.Character, error)
|
||||||
|
SaveCharacter(character *types.Character) error
|
||||||
|
}
|
||||||
@@ -12,3 +12,11 @@ type Character struct {
|
|||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CacheEntry represents a cached API response
|
||||||
|
type CacheEntry struct {
|
||||||
|
ID uint `gorm:"primaryKey"`
|
||||||
|
URLHash string `gorm:"uniqueIndex"`
|
||||||
|
Response string `gorm:"type:text"`
|
||||||
|
CachedAt time.Time `gorm:"index"`
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user