working build - no ui

This commit is contained in:
2025-08-25 16:34:45 -07:00
parent 8fb9028cf8
commit b370173873
6 changed files with 51 additions and 36 deletions

BIN
garminsync Executable file

Binary file not shown.

View File

@@ -20,15 +20,15 @@ func NewSQLiteDB(dbPath string) (*SQLiteDB, error) {
sqlite := &SQLiteDB{db: db} sqlite := &SQLiteDB{db: db}
// Create tables // Create tables
if err := sqlite.createTables(); err != nil { if err := sqlite.CreateTables(); err != nil {
return nil, err return nil, err
} }
return sqlite, nil return sqlite, nil
} }
func (s *SQLiteDB) createTables() error { func (s *SQLiteDB) CreateTables() error {
schema := ` schema := `
CREATE TABLE IF NOT EXISTS activities ( CREATE TABLE IF NOT EXISTS activities (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -134,6 +134,10 @@ func (s *SQLiteDB) ActivityExists(activityID int) (bool, error) {
return count > 0, nil return count > 0, nil
} }
func (s *SQLiteDB) DB() *sql.DB {
return s.db
}
func (s *SQLiteDB) GetActivity(activityID int) (*Activity, error) { func (s *SQLiteDB) GetActivity(activityID int) (*Activity, error) {
query := ` query := `
SELECT id, activity_id, start_time, activity_type, duration, distance, SELECT id, activity_id, start_time, activity_type, duration, distance,

View File

@@ -156,15 +156,20 @@ func (c *Client) GetActivities(start, limit int) ([]GarminActivity, error) {
return nil, fmt.Errorf("failed to get activities: status %d", resp.StatusCode) return nil, fmt.Errorf("failed to get activities: status %d", resp.StatusCode)
} }
var activities []GarminActivity // Garmin API returns an object containing the activity list
if err := json.NewDecoder(resp.Body).Decode(&activities); err != nil { type responseStruct struct {
ActivityList []GarminActivity `json:"activityList"`
}
var response responseStruct
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, err return nil, err
} }
// Rate limiting // Rate limiting
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
return activities, nil return response.ActivityList, nil
} }
func (c *Client) DownloadActivity(activityID int, format string) ([]byte, error) { func (c *Client) DownloadActivity(activityID int, format string) ([]byte, error) {

View File

@@ -12,21 +12,21 @@ import (
"github.com/sstent/garminsync-go/internal/parser" "github.com/sstent/garminsync-go/internal/parser"
) )
type Syncer struct { type SyncService struct {
garminClient *garmin.Client garminClient *garmin.Client
db *database.SQLiteDB db *database.SQLiteDB
dataDir string dataDir string
} }
func NewSyncer(garminClient *garmin.Client, db *database.SQLiteDB, dataDir string) *Syncer { func NewSyncService(garminClient *garmin.Client, db *database.SQLiteDB, dataDir string) *SyncService {
return &Syncer{ return &SyncService{
garminClient: garminClient, garminClient: garminClient,
db: db, db: db,
dataDir: dataDir, dataDir: dataDir,
} }
} }
func (s *Syncer) FullSync(ctx context.Context) error { func (s *SyncService) FullSync(ctx context.Context) error {
fmt.Println("Starting full sync...") fmt.Println("Starting full sync...")
defer fmt.Println("Sync completed") defer fmt.Println("Sync completed")
@@ -53,7 +53,7 @@ func (s *Syncer) FullSync(ctx context.Context) error {
return nil return nil
} }
func (s *Syncer) syncActivity(activity *garmin.GarminActivity) error { func (s *SyncService) syncActivity(activity *garmin.GarminActivity) error {
// Skip if already downloaded // Skip if already downloaded
if exists, _ := s.db.ActivityExists(activity.ActivityID); exists { if exists, _ := s.db.ActivityExists(activity.ActivityID); exists {
return nil return nil
@@ -111,6 +111,11 @@ func (s *Syncer) syncActivity(activity *garmin.GarminActivity) error {
return nil return nil
} }
// Add missing Sync method
func (s *SyncService) Sync(ctx context.Context) error {
return s.FullSync(ctx)
}
func getActivityType(activity *garmin.GarminActivity) string { func getActivityType(activity *garmin.GarminActivity) string {
if activityType, ok := activity.ActivityType["typeKey"]; ok { if activityType, ok := activity.ActivityType["typeKey"]; ok {
return activityType.(string) return activityType.(string)

View File

@@ -13,12 +13,12 @@ import (
type WebHandler struct { type WebHandler struct {
db *database.SQLiteDB db *database.SQLiteDB
syncer *sync.Syncer syncer *sync.SyncService
garmin *garmin.Client garmin *garmin.Client
templates map[string]interface{} // Placeholder for template handling templates map[string]interface{} // Placeholder for template handling
} }
func NewWebHandler(db *database.SQLiteDB, syncer *sync.Syncer, garmin *garmin.Client) *WebHandler { func NewWebHandler(db *database.SQLiteDB, syncer *sync.SyncService, garmin *garmin.Client) *WebHandler {
return &WebHandler{ return &WebHandler{
db: db, db: db,
syncer: syncer, syncer: syncer,
@@ -27,6 +27,11 @@ func NewWebHandler(db *database.SQLiteDB, syncer *sync.Syncer, garmin *garmin.Cl
} }
} }
func (h *WebHandler) LoadTemplates(templateDir string) error {
// For now, just return nil - templates will be handled later
return nil
}
func (h *WebHandler) RegisterRoutes(router *gin.Engine) { func (h *WebHandler) RegisterRoutes(router *gin.Engine) {
router.GET("/", h.Index) router.GET("/", h.Index)
router.GET("/activities", h.ActivityList) router.GET("/activities", h.ActivityList)
@@ -79,7 +84,7 @@ func (h *WebHandler) ActivityDetail(c *gin.Context) {
} }
func (h *WebHandler) Sync(c *gin.Context) { func (h *WebHandler) Sync(c *gin.Context) {
err := h.syncer.FullSync(context.Background()) err := h.syncer.Sync(context.Background())
if err != nil { if err != nil {
c.AbortWithStatus(http.StatusInternalServerError) c.AbortWithStatus(http.StatusInternalServerError)
return return

36
main.go
View File

@@ -21,6 +21,7 @@ import (
"github.com/sstent/garminsync-go/internal/web" "github.com/sstent/garminsync-go/internal/web"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
) )
@@ -30,7 +31,7 @@ type App struct {
server *http.Server server *http.Server
garmin *garmin.Client garmin *garmin.Client
shutdown chan os.Signal shutdown chan os.Signal
syncService *sync.SyncService syncService *sync.SyncService // This should now work
} }
func main() { func main() {
@@ -63,11 +64,10 @@ func (app *App) init() error {
var err error var err error
// Initialize database // Initialize database
dbConn, err := initDatabase() app.db, err = initDatabase()
if err != nil { if err != nil {
return err return err
} }
app.db = database.NewSQLiteDBFromDB(dbConn)
// Initialize Garmin client // Initialize Garmin client
app.garmin = garmin.NewClient() app.garmin = garmin.NewClient()
@@ -77,13 +77,13 @@ func (app *App) init() error {
if dataDir == "" { if dataDir == "" {
dataDir = "./data" dataDir = "./data"
} }
app.syncService = sync.NewSyncService(app.garmin, database.NewSQLiteDBFromDB(app.db), dataDir) app.syncService = sync.NewSyncService(app.garmin, app.db, dataDir)
// Setup cron scheduler // Setup cron scheduler
app.cron = cron.New() app.cron = cron.New()
// Setup HTTP server // Setup HTTP server
webHandler := web.NewWebHandler(app.db) webHandler := web.NewWebHandler(app.db, app.syncService, app.garmin)
templateDir := os.Getenv("TEMPLATE_DIR") templateDir := os.Getenv("TEMPLATE_DIR")
if templateDir == "" { if templateDir == "" {
templateDir = "./internal/web/templates" templateDir = "./internal/web/templates"
@@ -142,7 +142,7 @@ func (app *App) stop() {
} }
// Database initialization // Database initialization
func initDatabase() (*sql.DB, error) { func initDatabase() (*database.SQLiteDB, error) {
// Get database path from environment or use default // Get database path from environment or use default
dbPath := os.Getenv("DB_PATH") dbPath := os.Getenv("DB_PATH")
if dbPath == "" { if dbPath == "" {
@@ -172,28 +172,24 @@ func initDatabase() (*sql.DB, error) {
} }
// Create tables if they don't exist // Create tables if they don't exist
sqliteDB := &database.SQLiteDB{db: db} sqliteDB := database.NewSQLiteDBFromDB(db)
if err := sqliteDB.createTables(); err != nil { if err := sqliteDB.CreateTables(); err != nil {
return nil, fmt.Errorf("failed to create tables: %v", err) return nil, fmt.Errorf("failed to create tables: %v", err)
} }
return db, nil return sqliteDB, nil
} }
// Application routes func (app *App) setupRoutes(webHandler *web.WebHandler) http.Handler {
func (app *App) setupRoutes(webHandler *web.WebHandler) *http.ServeMux { router := gin.Default()
mux := http.NewServeMux()
// Health check // Health check
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { router.GET("/health", func(c *gin.Context) {
w.WriteHeader(http.StatusOK) c.String(http.StatusOK, "OK")
w.Write([]byte("OK"))
}) })
// Web UI routes // Register web routes
mux.HandleFunc("/", webHandler.Index) webHandler.RegisterRoutes(router)
mux.HandleFunc("/activities", webHandler.ActivityList)
mux.HandleFunc("/activity", webHandler.ActivityDetail)
return mux return router
} }