diff --git a/decoder/fort_tracker.go b/decoder/fort_tracker.go index d9839e67..162dce78 100644 --- a/decoder/fort_tracker.go +++ b/decoder/fort_tracker.go @@ -2,6 +2,7 @@ package decoder import ( "context" + "fmt" "sync" "time" @@ -409,6 +410,76 @@ func GetFortTracker() *FortTracker { return fortTracker } +// CellFortInfo holds information about forts in a cell for API response +type CellFortInfo struct { + CellId string `json:"cell_id"` + LastSeen int64 `json:"last_seen"` + Pokestops []string `json:"pokestops"` + Gyms []string `json:"gyms"` +} + +// FortTrackerInfo holds information about a fort for API response +type FortTrackerInfo struct { + FortId string `json:"fort_id"` + CellId string `json:"cell_id"` + LastSeen int64 `json:"last_seen"` + IsGym bool `json:"is_gym"` +} + +// GetCellInfo returns information about a specific cell +func (ft *FortTracker) GetCellInfo(cellId uint64) *CellFortInfo { + if ft == nil { + return nil + } + + ft.mu.RLock() + defer ft.mu.RUnlock() + + cell, exists := ft.cells[cellId] + if !exists { + return nil + } + + pokestops := make([]string, 0, len(cell.pokestops)) + for stopId := range cell.pokestops { + pokestops = append(pokestops, stopId) + } + + gyms := make([]string, 0, len(cell.gyms)) + for gymId := range cell.gyms { + gyms = append(gyms, gymId) + } + + return &CellFortInfo{ + CellId: fmt.Sprintf("%d", cellId), + LastSeen: cell.lastSeen, + Pokestops: pokestops, + Gyms: gyms, + } +} + +// GetFortInfo returns information about a specific fort +func (ft *FortTracker) GetFortInfo(fortId string) *FortTrackerInfo { + if ft == nil { + return nil + } + + ft.mu.RLock() + defer ft.mu.RUnlock() + + fort, exists := ft.forts[fortId] + if !exists { + return nil + } + + return &FortTrackerInfo{ + FortId: fortId, + CellId: fmt.Sprintf("%d", fort.cellId), + LastSeen: fort.lastSeen, + IsGym: fort.isGym, + } +} + // clearGymWithLock marks a gym as deleted while holding the striped mutex func clearGymWithLock(ctx context.Context, dbDetails db.DbDetails, gymId string, cellId uint64, removeFromTracker bool) { gymMutex, _ := gymStripedMutex.GetLock(gymId) diff --git a/main.go b/main.go index 02cae765..4c9a8e90 100644 --- a/main.go +++ b/main.go @@ -311,6 +311,8 @@ func main() { apiGroup.GET("/tappable/id/:tappable_id", GetTappable) apiGroup.GET("/devices/all", GetDevices) + apiGroup.GET("/fort-tracker/cell/:cell_id", GetFortTrackerCell) + apiGroup.GET("/fort-tracker/forts/:fort_id", GetFortTrackerFort) debugGroup := r.Group("/debug") diff --git a/routes.go b/routes.go index e68c16a6..3b6a5030 100644 --- a/routes.go +++ b/routes.go @@ -739,3 +739,44 @@ func GetTappable(c *gin.Context) { func GetDevices(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"devices": GetAllDevices()}) } + +func GetFortTrackerCell(c *gin.Context) { + cellIdStr := c.Param("cell_id") + cellId, err := strconv.ParseUint(cellIdStr, 10, 64) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid cell ID"}) + return + } + + fortTracker := decoder.GetFortTracker() + if fortTracker == nil { + c.JSON(http.StatusServiceUnavailable, gin.H{"error": "FortTracker not initialized"}) + return + } + + cellInfo := fortTracker.GetCellInfo(cellId) + if cellInfo == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Cell not found"}) + return + } + + c.JSON(http.StatusOK, cellInfo) +} + +func GetFortTrackerFort(c *gin.Context) { + fortId := c.Param("fort_id") + + fortTracker := decoder.GetFortTracker() + if fortTracker == nil { + c.JSON(http.StatusServiceUnavailable, gin.H{"error": "FortTracker not initialized"}) + return + } + + fortInfo := fortTracker.GetFortInfo(fortId) + if fortInfo == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Fort not found"}) + return + } + + c.JSON(http.StatusOK, fortInfo) +}