116 lines
2.6 KiB
Go
116 lines
2.6 KiB
Go
package services
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"hash/fnv"
|
|
"sync"
|
|
models "vibeStonk/server/models/v1"
|
|
"vibeStonk/server/repository"
|
|
)
|
|
|
|
var (
|
|
ErrExistingStock = errors.New("stock with symbol exists")
|
|
)
|
|
|
|
func NewStockService(config *repository.Config) (StockService, error) {
|
|
db, err := repository.GetStockConnector(config)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize stock service: %w", err)
|
|
}
|
|
|
|
stockRepo, err := repository.NewStockRepo(config, db)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize stockRepo: %w", err)
|
|
}
|
|
|
|
return &stockService{db: db, lock: &sync.Mutex{}, stockRepo: stockRepo}, nil
|
|
}
|
|
|
|
type StockService interface {
|
|
NewStock(symbol, name string) (*models.Stock, error)
|
|
// Update(*models.Stock)(*models.Stock, error)
|
|
Get(id int) (*models.Stock, error)
|
|
GetBySymbol(symbol string) (*models.Stock, error)
|
|
GetAll() ([]*models.Stock, error)
|
|
GetByIDs(ids []int) ([]*models.Stock, error)
|
|
|
|
Close() error
|
|
}
|
|
|
|
type stockService struct {
|
|
db *sql.DB
|
|
lock *sync.Mutex
|
|
stockRepo repository.StockRepo
|
|
}
|
|
|
|
func (s *stockService) Get(id int) (*models.Stock, error) {
|
|
return s.stockRepo.Get(int64(id))
|
|
}
|
|
|
|
func (s *stockService) GetBySymbol(symbol string) (*models.Stock, error) {
|
|
return s.stockRepo.GetBySymbol(symbol)
|
|
}
|
|
|
|
func (s *stockService) NewStock(symbol, name string) (*models.Stock, error) {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
stock := &models.Stock{
|
|
Id: -1,
|
|
Symbol: symbol,
|
|
Name: name,
|
|
Color: createColor(symbol, name),
|
|
}
|
|
|
|
stonk, err := s.stockRepo.GetBySymbol(stock.Symbol)
|
|
if err == nil || stonk != nil {
|
|
return nil, ErrExistingStock
|
|
}
|
|
|
|
stock, err = s.stockRepo.Create(stock)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create new stock: %w", err)
|
|
}
|
|
|
|
return stock, nil
|
|
}
|
|
|
|
func (s *stockService) GetAll() ([]*models.Stock, error) {
|
|
stocks, err := s.stockRepo.List()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get all stocks: %w", err)
|
|
}
|
|
|
|
return stocks, nil
|
|
}
|
|
|
|
func (s *stockService) GetByIDs(ids []int) ([]*models.Stock, error) {
|
|
stocks, err := s.stockRepo.GetByIDs(ids)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to filter stocks by IDs: %w", err)
|
|
}
|
|
return stocks, nil
|
|
}
|
|
|
|
func (s *stockService) Close() error {
|
|
return s.db.Close()
|
|
}
|
|
|
|
// helpers
|
|
func createColor(symbol, name string) string {
|
|
// Generate a deterministic color based on symbol+name formatted as #RRGGBB hex
|
|
h := fnv.New32a()
|
|
h.Write([]byte(symbol + name))
|
|
hash := h.Sum32()
|
|
|
|
// Use the hash to generate RGB values
|
|
r := (hash & 0xFF0000) >> 16
|
|
g := (hash & 0x00FF00) >> 8
|
|
b := hash & 0x0000FF
|
|
|
|
// Format as #RRGGBB hex
|
|
return fmt.Sprintf("#%02X%02X%02X", r, g, b)
|
|
}
|