feat(app): add character location tracking and display

This commit is contained in:
2025-08-09 20:54:05 +02:00
parent 2a098ec0d2
commit fb3ebc10ff
7 changed files with 139 additions and 1 deletions

View File

@@ -78,6 +78,21 @@ type CharacterInfo struct {
CharacterName string `json:"character_name"`
}
// CharacterLocation represents a character's current location
type CharacterLocation struct {
CharacterID int64 `json:"character_id"`
CharacterName string `json:"character_name"`
SolarSystemID int64 `json:"solar_system_id"`
SolarSystemName string `json:"solar_system_name"`
RetrievedAt time.Time `json:"retrieved_at"`
}
type esiCharacterLocationResponse struct {
SolarSystemID int64 `json:"solar_system_id"`
StationID int64 `json:"station_id"`
StructureID int64 `json:"structure_id"`
}
func NewESISSO(clientID string, redirectURI string, scopes []string) *ESISSO {
s := &ESISSO{
clientID: clientID,
@@ -105,6 +120,43 @@ func (s *ESISSO) initDB() error {
return nil
}
// resolveSystemNameByID returns the system name for an ID from the local DB, or empty if not found
func (s *ESISSO) resolveSystemNameByID(id int64) string {
if s.db == nil || id == 0 { return "" }
var ss SolarSystem
if err := s.db.Select("solarSystemName").First(&ss, "solarSystemID = ?", id).Error; err != nil { return "" }
return ss.SolarSystemName
}
// GetCharacterLocations returns current locations for all stored characters
func (s *ESISSO) GetCharacterLocations(ctx context.Context) ([]CharacterLocation, error) {
if s.db == nil { return nil, errors.New("db not initialised") }
var tokens []ESIToken
if err := s.db.Find(&tokens).Error; err != nil { return nil, err }
out := make([]CharacterLocation, 0, len(tokens))
client := &http.Client{ Timeout: 5 * time.Second }
for i := range tokens {
t := &tokens[i]
tok, err := s.ensureAccessTokenFor(ctx, t)
if err != nil { continue }
req, err := http.NewRequestWithContext(ctx, http.MethodGet, esiBase+"/v2/characters/"+strconv.FormatInt(t.CharacterID,10)+"/location", nil)
if err != nil { continue }
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer "+tok)
resp, err := client.Do(req)
if err != nil { continue }
func() {
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { return }
var lr esiCharacterLocationResponse
if err := json.NewDecoder(resp.Body).Decode(&lr); err != nil { return }
name := s.resolveSystemNameByID(lr.SolarSystemID)
out = append(out, CharacterLocation{ CharacterID: t.CharacterID, CharacterName: t.CharacterName, SolarSystemID: lr.SolarSystemID, SolarSystemName: name, RetrievedAt: time.Now() })
}()
}
return out, nil
}
func (s *ESISSO) saveToken() {
if s.db == nil || s.characterID == 0 {
return