Skip to content

Commit 5f39530

Browse files
committed
🥩🖱️ ↝ Expeditions, stations and docking locations are all now being synced
1 parent c4d0bf2 commit 5f39530

File tree

13 files changed

+386
-208
lines changed

13 files changed

+386
-208
lines changed

backend/cmd/simple-sync-docking_locations.go

Lines changed: 0 additions & 113 deletions
This file was deleted.

backend/cmd/sync-docking_locations/main.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ package main
22

33
import (
44
"log"
5-
"os"
65

76
"github.com/signal-k/notifs/internal/sync"
87
)
98

109
func main() {
11-
if err := sync.SyncMostRecentDockingLocation(); err != nil {
12-
log.Printf("❌ Docking location sync failed: %v", err)
13-
os.Exit(1)
10+
log.Println("🛰️ Fetching docking locations...")
11+
12+
if err := sync.SyncDockingLocations(); err != nil {
13+
log.Fatalf("Sync failed: %v", err)
1414
}
15-
log.Println("✅ Docking location sync completed successfully.")
15+
16+
log.Println("✅ Docking location sync completed.")
1617
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/signal-k/notifs/internal/sync"
7+
)
8+
9+
func main() {
10+
log.Println("🧭 Fetching space expeditions...")
11+
if err := sync.SyncExpeditions(); err != nil {
12+
log.Fatalf("Sync failed: failed to parse expedition JSON: %v", err)
13+
}
14+
}

backend/cmd/sync-stations/main.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/signal-k/notifs/internal/sync"
7+
)
8+
9+
func main() {
10+
log.Println("🛰️ Fetching space stations...")
11+
12+
if err := sync.SyncStations(); err != nil {
13+
log.Fatalf("Sync failed: %v", err)
14+
}
15+
16+
log.Println("✅ Sync completed successfully.")
17+
}

backend/internal/sync/sync_docking_locations.go

Lines changed: 69 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,39 @@ import (
55
"encoding/json"
66
"fmt"
77
"io"
8+
"log"
89
"net/http"
10+
"net/url"
911
"time"
1012
)
1113

12-
type SpaceDevsDockingLocationResponse struct {
13-
Results []SpaceDevsDockingLocation `json:"results"`
14-
}
15-
1614
type SpaceDevsDockingLocation struct {
1715
ID int `json:"id"`
1816
Name string `json:"name"`
1917
Spacestation struct {
2018
ID int `json:"id"`
21-
URL string `json:"url"`
2219
Name string `json:"name"`
20+
URL string `json:"url"`
2321
Image struct {
24-
ID int `json:"id"`
25-
Name string `json:"name"`
26-
ImageURL string `json:"image_url"`
27-
ThumbnailURL string `json:"thumbnail_url"`
28-
Credit string `json:"credit"`
29-
License struct {
30-
ID int `json:"id"`
31-
Name string `json:"name"`
32-
Priority int `json:"priority"`
33-
Link string `json:"link"`
22+
ImageURL string `json:"image_url"`
23+
Credit string `json:"credit"`
24+
License struct {
25+
Name string `json:"name"`
26+
Link string `json:"link"`
3427
} `json:"license"`
35-
SingleUse bool `json:"single_use"`
3628
} `json:"image"`
3729
} `json:"spacestation"`
38-
Spacecraft *struct {
39-
Name string `json:"name"`
40-
} `json:"spacecraft"`
41-
Payload *struct {
42-
Name string `json:"name"`
43-
} `json:"payload"`
4430
}
4531

46-
// SyncMostRecentDockingLocation fetches and stores the most recent docking location
47-
func SyncMostRecentDockingLocation() error {
48-
fmt.Println("🛰️ Fetching most recent docking location...")
32+
type SpaceDevsDockingLocationResponse struct {
33+
Results []SpaceDevsDockingLocation `json:"results"`
34+
}
4935

50-
resp, err := http.Get("https://ll.thespacedevs.com/2.3.0/config/docking_locations/?limit=1&ordering=-id&format=json")
36+
func SyncDockingLocations() error {
37+
apiURL := "https://ll.thespacedevs.com/2.3.0/config/docking_locations/?limit=30&format=json"
38+
resp, err := http.Get(apiURL)
5139
if err != nil {
52-
return fmt.Errorf("failed to fetch docking location: %w", err)
40+
return fmt.Errorf("failed to fetch docking locations: %w", err)
5341
}
5442
defer resp.Body.Close()
5543

@@ -60,104 +48,95 @@ func SyncMostRecentDockingLocation() error {
6048

6149
var data SpaceDevsDockingLocationResponse
6250
if err := json.Unmarshal(body, &data); err != nil {
63-
return fmt.Errorf("failed to parse docking location response: %w", err)
64-
}
65-
if len(data.Results) == 0 {
66-
return fmt.Errorf("no docking location results found")
51+
return fmt.Errorf("failed to parse JSON: %w", err)
6752
}
6853

69-
docking := data.Results[0]
70-
if err := createDockingLocationInPocketbase(docking); err != nil {
71-
return fmt.Errorf("failed to insert docking location: %w", err)
72-
}
54+
log.Printf("✅ Fetched %d docking locations\n", len(data.Results))
7355

74-
fmt.Println("✅ Most Recent Docking Location:")
75-
fmt.Printf("- Name: %s\n", docking.Name)
76-
fmt.Printf("- Station: %s\n", docking.Spacestation.Name)
77-
fmt.Printf(" • Image: %s\n", docking.Spacestation.Image.ImageURL)
78-
fmt.Printf(" • Credit: %s\n", docking.Spacestation.Image.Credit)
79-
fmt.Printf(" • License: %s (%s)\n", docking.Spacestation.Image.License.Name, docking.Spacestation.Image.License.Link)
80-
if docking.Spacecraft != nil {
81-
fmt.Printf("- Spacecraft: %s\n", docking.Spacecraft.Name)
82-
} else {
83-
fmt.Println("- Spacecraft: None")
84-
}
85-
if docking.Payload != nil {
86-
fmt.Printf("- Payload: %s\n", docking.Payload.Name)
87-
} else {
88-
fmt.Println("- Payload: None")
56+
for _, loc := range data.Results {
57+
if err := insertDockingLocation(loc); err != nil {
58+
log.Printf("❌ Failed to insert docking location %s: %v", loc.Name, err)
59+
} else {
60+
log.Printf("✅ Inserted: %s (Station: %s)", loc.Name, loc.Spacestation.Name)
61+
}
8962
}
9063

9164
return nil
9265
}
9366

94-
func createDockingLocationInPocketbase(d SpaceDevsDockingLocation) error {
95-
// Replace with your actual Pocketbase station record mapping logic
96-
stationPbID, err := findStationPocketbaseID(d.Spacestation.ID)
67+
func insertDockingLocation(loc SpaceDevsDockingLocation) error {
68+
// Find the corresponding station in Pocketbase by name
69+
stationID, err := findStationIDByName(loc.Spacestation.Name)
9770
if err != nil {
98-
return fmt.Errorf("could not resolve station: %w", err)
71+
return fmt.Errorf("station lookup failed: %w", err)
9972
}
10073

101-
payload := map[string]interface{}{
102-
"api_id": d.ID,
103-
"name": d.Name,
104-
"station": stationPbID,
105-
"spacecraft_name": derefString(d.Spacecraft),
106-
"payload_name": derefString(d.Payload),
107-
"station_image_url": d.Spacestation.Image.ImageURL,
108-
"station_image_credit": d.Spacestation.Image.Credit,
109-
"station_license_name": d.Spacestation.Image.License.Name,
110-
"station_license_url": d.Spacestation.Image.License.Link,
111-
"api_url": fmt.Sprintf("https://ll.thespacedevs.com/2.3.0/config/docking_locations/%d/", d.ID),
74+
pbURL := "http://127.0.0.1:8080/api/collections/docking_locations/records"
75+
payload := map[string]any{
76+
"api_id": loc.ID,
77+
"name": loc.Name,
78+
"station": stationID,
79+
"station_url": loc.Spacestation.URL,
80+
"image_url": loc.Spacestation.Image.ImageURL,
81+
"image_credit": loc.Spacestation.Image.Credit,
82+
"license_name": loc.Spacestation.Image.License.Name,
83+
"license_url": loc.Spacestation.Image.License.Link,
11284
}
11385

11486
jsonData, err := json.Marshal(payload)
11587
if err != nil {
116-
return err
88+
return fmt.Errorf("marshal payload: %w", err)
11789
}
11890

119-
req, err := http.NewRequest("POST", "http://127.0.0.1:8080/api/collections/docking_locations/records", bytes.NewBuffer(jsonData))
91+
req, err := http.NewRequest("POST", pbURL, bytes.NewBuffer(jsonData))
12092
if err != nil {
121-
return err
93+
return fmt.Errorf("create request: %w", err)
12294
}
12395
req.Header.Set("Content-Type", "application/json")
12496

12597
client := &http.Client{Timeout: 10 * time.Second}
12698
res, err := client.Do(req)
12799
if err != nil {
128-
return err
100+
return fmt.Errorf("POST to Pocketbase: %w", err)
129101
}
130102
defer res.Body.Close()
131103

132104
if res.StatusCode >= 400 {
133105
body, _ := io.ReadAll(res.Body)
134-
return fmt.Errorf("HTTP %d: %s", res.StatusCode, body)
106+
return fmt.Errorf("Pocketbase error %d: %s", res.StatusCode, body)
135107
}
136108

137109
return nil
138110
}
139111

140-
// Helper to safely dereference name field from *structs
141-
func derefString(ptr interface{}) string {
142-
switch v := ptr.(type) {
143-
case *struct{ Name string }:
144-
if v != nil {
145-
return v.Name
146-
}
147-
case nil:
148-
return ""
112+
func findStationIDByName(stationName string) (string, error) {
113+
query := url.QueryEscape(fmt.Sprintf("name='%s'", stationName))
114+
apiURL := fmt.Sprintf("http://127.0.0.1:8080/api/collections/stations/records?filter=%s", query)
115+
116+
res, err := http.Get(apiURL)
117+
if err != nil {
118+
return "", fmt.Errorf("station lookup HTTP error: %w", err)
149119
}
150-
return ""
151-
}
120+
defer res.Body.Close()
152121

153-
// Replace with real lookup (from Pocketbase stations by api_id)
154-
func findStationPocketbaseID(spaceDevsStationID int) (string, error) {
155-
// TEMPORARY placeholder — replace with Pocketbase fetch (GET /collections/stations)
156-
// that maps api_id -> Pocketbase ID
157-
switch spaceDevsStationID {
158-
case 4:
159-
return "RECORD_ID_FOR_ISS", nil
160-
default:
161-
return "", fmt.Errorf("no known mapping for station ID %d", spaceDevsStationID)
122+
if res.StatusCode != 200 {
123+
body, _ := io.ReadAll(res.Body)
124+
return "", fmt.Errorf("station lookup failed: HTTP %d: %s", res.StatusCode, body)
162125
}
126+
127+
var response struct {
128+
Items []struct {
129+
ID string `json:"id"`
130+
} `json:"items"`
131+
}
132+
133+
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
134+
return "", fmt.Errorf("decode station lookup: %w", err)
135+
}
136+
137+
if len(response.Items) == 0 {
138+
return "", fmt.Errorf("station not found for name: %s", stationName)
139+
}
140+
141+
return response.Items[0].ID, nil
163142
}

0 commit comments

Comments
 (0)