Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ go mod tidy
# Set the .env
mv .env.example .env
# Source the env variables
. <(cat .env | grep -v -e '^$' | grep -v "#")
export $(grep -v '^#' .env | grep -v '^$' | xargs)
```

## Build and Run
Expand Down
26 changes: 13 additions & 13 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"controtto/src/gateways/sqlite"
"controtto/src/rest"
"log/slog"
"os"
)

const (
Expand All @@ -21,23 +20,25 @@ const (
)

func main() {
// Database
dbPath := "pnl.db"
if dbPathEnv := os.Getenv("CONTROTTO_DB_PATH"); dbPathEnv != "" {
dbPath = dbPathEnv
// Load configuration
cfg, err := config.LoadFromEnv()
if err != nil {
slog.Error("Error loading config from env:", "error", err)
panic("Bye")
}
slog.Info("Initiating SQLite path", "path", dbPath)
sqliteDB, err := sqlite.NewSQLite(dbPath)
cfgManager := config.NewManager(cfg)

// Database
slog.Info("Initiating SQLite path", "path", cfgManager.Get().DBPath)
sqliteDB, err := sqlite.NewSQLite(cfgManager)
if err != nil {
slog.Error("Error creating SQLite:", "error", err)
panic("Bye")
}

// Load configuration
cfg := config.NewConfig(PREFIX)
config := config.NewService(cfg)
// Use Cases
ac := managing.NewAssetCreator(sqliteDB)
pc := managing.NewPairManager(cfg, sqliteDB, sqliteDB)
pc := managing.NewPairManager(cfgManager, sqliteDB, sqliteDB)
pq := querying.NewPairQuerier(sqliteDB)
mm := managing.NewMarketManager(marketsConfig)
ppm := managing.NewPriceProviderManager(pricers)
Expand All @@ -47,9 +48,8 @@ func main() {
tr := trading.NewTradeRecorder(sqliteDB)
at := trading.NewAssetTrader(mm, sqliteDB)
trader := trading.NewService(*at, *tr)
// *trading.NewAssetTrader(markets map[string]pnl.Market)

port := cfg.Port
slog.Info("Initiating server", "port", port)
rest.Run(&config, &manager, &querier, &trader)
rest.Run(cfgManager, &manager, &querier, &trader)
}
13 changes: 5 additions & 8 deletions src/app/config/config.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package config

// Service just hols all the managing use cases
type Service struct {
ConfigManager *ConfigManager
}

// NewService is the interctor for all Managing Use cases
func NewService(cfg *ConfigManager) Service {
return Service{cfg}
type Config struct {
Port int // CONTROTTO_PORT
DBPath string // CONTROTTO_DB_PATH
UncommonPairs bool // CONTROTTO_UNCOMMON_PAIRS
LoadSampleData bool // CONTROTTO_LOAD_SAMPLE_DATA
}
61 changes: 0 additions & 61 deletions src/app/config/configManager.go

This file was deleted.

75 changes: 75 additions & 0 deletions src/app/config/load.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package config

import (
"log/slog"
"os"
"strconv"
)

const (
DefaultPort = 8000
DefaultDBPath = "./data/pnl.db"
DefaultUncommonPairs = false
DefaultLoadSampleData = false
)

func LoadFromEnv() (*Config, error) {
port, err := getEnvInt("CONTROTTO_PORT", DefaultPort)
if err != nil {
return nil, err
}

dbPath := getEnvString("CONTROTTO_DB_PATH", DefaultDBPath)

uncommonPairs, err := getEnvBool("CONTROTTO_UNCOMMON_PAIRS", DefaultUncommonPairs)
if err != nil {
return nil, err
}

loadSampleData, err := getEnvBool("CONTROTTO_LOAD_SAMPLE_DATA", DefaultLoadSampleData)
if err != nil {
return nil, err
}

cfg := &Config{
Port: port,
DBPath: dbPath,
UncommonPairs: uncommonPairs,
LoadSampleData: loadSampleData,
}

return cfg, nil
}

func getEnvString(key string, defaultVal string) string {
val := os.Getenv(key)
slog.Info("Loading env var", "key", key, "value", val)
if val == "" {
return defaultVal
}
return val
}

func getEnvBool(key string, defaultVal bool) (bool, error) {
valStr := os.Getenv(key)
if valStr == "" {
return defaultVal, nil
}
val, err := strconv.ParseBool(valStr)
if err != nil {
return false, err
}
return val, nil
}

func getEnvInt(key string, defaultVal int) (int, error) {
valStr := os.Getenv(key)
if valStr == "" {
return defaultVal, nil
}
val, err := strconv.Atoi(valStr)
if err != nil {
return 0, err
}
return val, nil
}
33 changes: 33 additions & 0 deletions src/app/config/manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package config

import "sync"

// Manager holds the application configuration and provides thread-safe access to it.
type Manager struct {
mu sync.RWMutex
config *Config
}

// NewManager creates a new ConfigManager.
func NewManager(config *Config) *Manager {
return &Manager{config: config}
}

// Get returns the current configuration.
func (m *Manager) Get() *Config {
m.mu.RLock()
defer m.mu.RUnlock()
return m.config
}

// Update updates the configuration.
func (m *Manager) Update(config *Config) {
// If Config is updated on runtime, we don't want to change the env vars. Config will be re-loaded to env var value on restart.
m.mu.Lock()
defer m.mu.Unlock()
// We are re-setting these values to their original ones, as they are not expected to be changed at runtime.
config.DBPath = m.config.DBPath
config.Port = m.config.Port
config.LoadSampleData = m.config.LoadSampleData
m.config = config
}
6 changes: 3 additions & 3 deletions src/app/managing/pairManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ type CreatePairReq struct {
}

type PairsManager struct {
config *config.ConfigManager
config *config.Manager
assets pnl.Assets
tradingPairs pnl.Pairs
}

func NewPairManager(cfg *config.ConfigManager, a pnl.Assets, tp pnl.Pairs) *PairsManager {
func NewPairManager(cfg *config.Manager, a pnl.Assets, tp pnl.Pairs) *PairsManager {
return &PairsManager{cfg, a, tp}
}

Expand Down Expand Up @@ -65,7 +65,7 @@ func (tpm *PairsManager) Create(req CreatePairReq) (*CreatePairResp, error) {
}

// // Uncommon pairs validation
if !tpm.config.GetUncommonPairs() {
if !tpm.config.Get().UncommonPairs {
bt := base.Type // Assuming these are strings like "Crypto", "Forex", etc.
qt := quote.Type
valid := (bt == "Crypto" && qt == "Crypto") ||
Expand Down
9 changes: 5 additions & 4 deletions src/gateways/sqlite/sqlite.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package sqlite

import (
"controtto/src/app/config"
"controtto/src/domain/pnl"
"database/sql"
"fmt"
"log/slog"
"os"

_ "github.com/mattn/go-sqlite3"
)
Expand Down Expand Up @@ -156,14 +156,15 @@ type SQLiteStorage struct {
}

// NewStorage creates a new instance of SQLite.
func NewSQLite(dbPath string) (*SQLiteStorage, error) {
db, err := sql.Open("sqlite3", dbPath)
func NewSQLite(cfg *config.Manager) (*SQLiteStorage, error) {
db, err := sql.Open("sqlite3", cfg.Get().DBPath)
if err != nil {
return nil, err
}
// Create the Pair and Trade tables if they don't exist.
qString := tables
if os.Getenv("LOAD_SAMPLE_DATA") == "true" {
if cfg.Get().LoadSampleData {
slog.Info("Loading sample data into the database.")
qString += demo
}
_, err = db.Exec(qString)
Expand Down
9 changes: 5 additions & 4 deletions src/rest/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import (
"controtto/src/app/managing"
"controtto/src/app/querying"
"controtto/src/app/trading"
"fmt"
"log"

"github.com/gofiber/fiber/v2"
"github.com/gofiber/template/html/v2"
)

func Run(c *config.Service, m *managing.Service, q *querying.Service, t *trading.Service) {
func Run(c *config.Manager, m *managing.Service, q *querying.Service, t *trading.Service) {
engine := html.New("./views", ".html")
engine.Debug(true)
app := fiber.New(fiber.Config{
Expand Down Expand Up @@ -42,7 +43,7 @@ func Run(c *config.Service, m *managing.Service, q *querying.Service, t *trading
app.Get("/ui/pairs/:id/newTrade/form", newTradeForm(q.PairQuerier, m.PriceProviderManager))
// In rest/rest.go, add this line to the GET section:
app.Get("/pairs/:id/market/:mktkey/trades", fetchMarketTrades(t.AssetTrader, m.MarketManager))
app.Get("/settings", settingsSection(m.PriceProviderManager, m.MarketManager, c.ConfigManager))
app.Get("/settings", settingsSection(m.PriceProviderManager, m.MarketManager, c))
// app.Get("/settings/anyMarket", marketsSetAPI(c.ConfigManager))
// app.Get("/markets", marketsSection(m.MarketManager))
app.Get("/ui/pairs/:id/market", getMarketAssets(q.PairQuerier, m.MarketManager))
Expand All @@ -57,7 +58,7 @@ func Run(c *config.Service, m *managing.Service, q *querying.Service, t *trading
app.Post("/pairs/:id/trades", newTrade(t.TradeRecorder))
app.Post("/pairs/:id/trades/mktImport", importMarketTrades(t.TradeRecorder))
app.Post("/pairs/:id/trades/csvImport", newTradeImport(t.TradeRecorder))
app.Post("/settings/edit", saveSettingsForm(m.PriceProviderManager, m.MarketManager, c.ConfigManager))
app.Post("/settings/edit", saveSettingsForm(m.PriceProviderManager, m.MarketManager, c))

log.Fatal(app.Listen("0.0.0.0" + ":" + c.ConfigManager.GetPort()))
log.Fatal(app.Listen("0.0.0.0" + ":" + fmt.Sprint(c.Get().Port)))
}
6 changes: 4 additions & 2 deletions src/rest/settingsHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
// return c.SendString(fmt.Sprintf("%t", marketsSet(marketManager)))
// }
// }
func saveSettingsForm(priceProviderManager *managing.PriceProviderManager, marketManager *managing.MarketManager, cfg *config.ConfigManager) func(*fiber.Ctx) error {
func saveSettingsForm(priceProviderManager *managing.PriceProviderManager, marketManager *managing.MarketManager, cfg *config.Manager) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
// Update price providers
providers := priceProviderManager.ListProviders(true) // true = get all providers
Expand Down Expand Up @@ -58,7 +58,9 @@ func saveSettingsForm(priceProviderManager *managing.PriceProviderManager, marke

// Update uncommon pairs setting
uncommon := c.FormValue("uncommon_pairs") != ""
cfg.SetUncommonPairs(uncommon)
cfg.Update(&config.Config{
UncommonPairs: uncommon,
})

c.Append("HX-Trigger", "reloadSettings")
slog.Info("Config updated successfully")
Expand Down
4 changes: 2 additions & 2 deletions src/rest/uiHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func pairSection() func(*fiber.Ctx) error {
}
}

func settingsSection(priceProviderManager *managing.PriceProviderManager, marketManager *managing.MarketManager, cfg *config.ConfigManager) func(*fiber.Ctx) error {
func settingsSection(priceProviderManager *managing.PriceProviderManager, marketManager *managing.MarketManager, cfg *config.Manager) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
if c.Get("HX-Request") != "true" {
return c.Render("main", fiber.Map{
Expand All @@ -86,7 +86,7 @@ func settingsSection(priceProviderManager *managing.PriceProviderManager, market

return c.Render("settingsSection", fiber.Map{
"Today": time.Now().Format("Mon Jan 02 15:04 2006"),
"Uncommon": cfg.GetUncommonPairs(),
"Uncommon": cfg.Get().UncommonPairs,
"PriceProviders": providers,
"MarketTraders": traders,
})
Expand Down