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
43 changes: 43 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
version: 2
updates:
# Enable version updates for Python dependencies
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "03:00"
open-pull-requests-limit: 10
reviewers:
- "surrealwolf"
labels:
- "dependencies"
- "python"
allow:
- dependency-type: "all"
# Group patch updates together
groups:
patch-minor-updates:
patterns:
- patch
- minor
major-updates:
patterns:
- major
commit-message:
prefix: "build"
prefix-scope: "deps"
include: "scope"

# Enable version updates for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "03:00"
reviewers:
- "surrealwolf"
labels:
- "dependencies"
- "github-actions"
73 changes: 57 additions & 16 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,17 @@ async def refresh_war_status():

@app.get("/api/campaigns", tags=["Campaigns"])
async def get_campaigns():
"""Get campaign information"""
"""Get campaign information (with cache fallback)"""
# Try live API first
data = scraper.get_campaign_info()
if data:

# Fallback to cache if live API fails
if data is None:
data = db.get_latest_campaigns_snapshot()

if data is not None:
return data
raise HTTPException(status_code=404, detail="Failed to fetch campaigns")
raise HTTPException(status_code=503, detail="No campaign data available (live fetch failed and no cached data)")


@app.get("/api/campaigns/active", tags=["Campaigns"])
Expand All @@ -103,20 +109,36 @@ async def get_active_campaigns():

@app.get("/api/planets", tags=["Planets"])
async def get_planets():
"""Get all planets"""
"""Get all planets (with cache fallback)"""
# Try live API first
data = scraper.get_planets()
if data:

# Fallback to cache if live API fails
if data is None:
data = db.get_latest_planets_snapshot()

if data is not None:
return data
raise HTTPException(status_code=404, detail="Failed to fetch planets")
raise HTTPException(status_code=503, detail="Failed to fetch planets and no cached data available")


@app.get("/api/planets/{planet_index}", tags=["Planets"])
async def get_planet_status(planet_index: int):
"""Get status of a specific planet"""
"""Get status of a specific planet (with cache fallback)"""
# Try live API first
data = collector.collect_planet_data(planet_index)
if data:

# Fallback to cache if live API fails
if data is None:
history = db.get_planet_status_history(planet_index, limit=1)
if history and isinstance(history[0], dict) and "data" in history[0]:
data = history[0]["data"]
elif history:
data = history[0]

if data is not None:
return data
raise HTTPException(status_code=404, detail=f"Failed to fetch planet {planet_index}")
raise HTTPException(status_code=503, detail=f"Failed to fetch planet {planet_index} and no cached data available")


@app.get("/api/planets/{planet_index}/history", tags=["Planets"])
Expand Down Expand Up @@ -168,11 +190,17 @@ async def refresh_statistics():

@app.get("/api/factions", tags=["Factions"])
async def get_factions():
"""Get all factions"""
"""Get all factions (with cache fallback)"""
# Try live API first
data = scraper.get_factions()
if data:

# Fallback to cache if live API fails
if data is None:
data = db.get_latest_factions_snapshot()

if data is not None:
return data
raise HTTPException(status_code=404, detail="Failed to fetch factions")
raise HTTPException(status_code=503, detail="Failed to fetch factions and no cached data available")


# ========================
Expand All @@ -182,11 +210,17 @@ async def get_factions():

@app.get("/api/biomes", tags=["Biomes"])
async def get_biomes():
"""Get all biomes"""
"""Get all biomes (with cache fallback)"""
# Try live API first
data = scraper.get_biomes()
if data:

# Fallback to cache if live API fails
if data is None:
data = db.get_latest_biomes_snapshot()

if data is not None:
return data
raise HTTPException(status_code=404, detail="Failed to fetch biomes")
raise HTTPException(status_code=503, detail="Failed to fetch biomes and no cached data available")


# ========================
Expand All @@ -197,7 +231,14 @@ async def get_biomes():
@app.get("/api/health", tags=["Health"])
async def health_check():
"""Health check endpoint"""
return {"status": "healthy", "collector_running": collector.is_running}
# Returns local service status and upstream API status
# No external API calls made here to avoid blocking event loop or consuming rate limits
upstream_status = db.get_upstream_status()
return {
"status": "healthy",
"collector_running": collector.is_running,
"upstream_api": "online" if upstream_status else "offline"
}


# ========================
Expand Down
81 changes: 57 additions & 24 deletions src/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,57 +45,90 @@ def collect_all_data(self):
try:
# Collect war status
war_data = self.scraper.get_war_status()
if war_data:
if war_data is not None:
self.db.save_war_status(war_data)
logger.info("War status collected")
else:
logger.warning("Failed to collect war status")

# Collect statistics (extracted from war status)
# Collect statistics
stats_data = self.scraper.get_statistics()
if stats_data:
if stats_data is not None:
self.db.save_statistics(stats_data)
logger.info("Statistics collected")
else:
logger.warning("Failed to collect statistics")

# Collect planets
planets = self.scraper.get_planets()
if planets:
for planet in planets:
planet_index = planet.get("index")
if planet_index:
self.db.save_planet_status(planet_index, planet)
logger.info(f"Collected data for {len(planets)} planets")
if planets is not None:
if planets:
for planet in planets:
planet_index = planet.get("index")
if planet_index:
self.db.save_planet_status(planet_index, planet)
logger.info(f"Collected data for {len(planets)} planets")
else:
logger.info("Collected 0 planets (empty response)")
else:
logger.warning("Failed to collect planets")

# Collect campaigns
campaigns = self.scraper.get_campaign_info()
if campaigns:
for campaign in campaigns:
campaign_id = campaign.get("id")
if campaign_id and campaign.get("planet") and "index" in campaign["planet"]:
planet_index = campaign["planet"].get("index")
self.db.save_campaign(campaign_id, planet_index, campaign)
logger.info(f"Collected {len(campaigns)} campaigns")
if campaigns is not None:
if campaigns:
for campaign in campaigns:
campaign_id = campaign.get("id")
if campaign_id and campaign.get("planet") and "index" in campaign["planet"]:
planet_index = campaign["planet"].get("index")
self.db.save_campaign(campaign_id, planet_index, campaign)
logger.info(f"Collected {len(campaigns)} campaigns")
else:
logger.info("Collected 0 campaigns (empty response)")
else:
logger.warning("Failed to collect campaigns")

# Collect assignments (Major Orders)
assignments = self.scraper.get_assignments()
if assignments:
self.db.save_assignments(assignments)
logger.info(f"Collected {len(assignments)} assignments")
if assignments is not None:
if assignments:
self.db.save_assignments(assignments)
logger.info(f"Collected {len(assignments)} assignments")
else:
logger.info("Collected 0 assignments (empty response)")
else:
logger.warning("Failed to collect assignments")

# Collect dispatches (news)
dispatches = self.scraper.get_dispatches()
if dispatches:
self.db.save_dispatches(dispatches)
logger.info(f"Collected {len(dispatches)} dispatches")
if dispatches is not None:
if dispatches:
self.db.save_dispatches(dispatches)
logger.info(f"Collected {len(dispatches)} dispatches")
else:
logger.info("Collected 0 dispatches (empty response)")
else:
logger.warning("Failed to collect dispatches")

# Collect planet events
events = self.scraper.get_planet_events()
if events is not None:
self.db.save_planet_events(events)
logger.info(f"Collected {len(events)} planet events")
if events:
self.db.save_planet_events(events)
logger.info(f"Collected {len(events)} planet events")
else:
logger.info("Collected 0 planet events (empty response)")
else:
logger.warning("Failed to collect planet events")

logger.info("Data collection cycle completed successfully")
# Mark upstream as available after successful collection
self.db.set_upstream_status(True)

except Exception as e:
logger.error(f"Error during data collection: {e}")
# Mark upstream as unavailable on any collection error
self.db.set_upstream_status(False)

def collect_planet_data(self, planet_index: int):
"""Collect data for a specific planet"""
Expand Down
Loading