Skip to content

Proof of Concept: Push Gateway decoding#371

Merged
jfberry merged 13 commits into
nebula-invasion-receiverfrom
push-gateway-receiver
Jun 5, 2026
Merged

Proof of Concept: Push Gateway decoding#371
jfberry merged 13 commits into
nebula-invasion-receiverfrom
push-gateway-receiver

Conversation

@jfberry

@jfberry jfberry commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

As part of a proof of concept for decoding other data sources, this adds a simple raid lobby count tracker (and the Max battle equivalent).

  • New content type on raw_receiver.proto (message_type + payload), parsed on both the gRPC and HTTP /raw inbound paths.
  • The decoder gates on message_type and updates the relevant gym (raid) or station (Max battle).
  • In-memory only fields (db:"-", not written to the database): Gym.RaidLobbyCount / RaidLobbyEndMs and Station.BattleLobbyCount / BattleLobbyEndMs, served through the fort rtree / API.
  • New webhook types: raid_lobby and max_battle_lobby.

Notes

  • Proof of concept — lobby data is ephemeral and intentionally not persisted (no schema change).
  • Updates are deduplicated per fort by message publish timestamp (newer-wins), so overlapping deliveries don't cause repeated webhooks.
  • The new webhook types are separate from gym / raid / max_battle so consumers can opt in given the update frequency.

Test Plan

  • go build ./... and go test (decoder, webhooks, grpc) pass
  • Confirm raid_lobby / max_battle_lobby webhooks fire and the fort API returns the lobby fields

🤖 Generated with Claude Code

jfberry and others added 13 commits June 2, 2026 11:56
Adds updateRaidLobby method on Gym (pub-timestamp dedup guard),
UpdateGymRaidLobby entry-point using minimal in-memory path (no DB
write, no spam webhooks), and buildRaidLobbyWebhook helper. Unknown
gyms are silently dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds updateBattleLobby method on Station (pub-timestamp dedup guard),
UpdateStationBattleLobby entry-point using minimal in-memory path (no
DB write, no spam webhooks), and buildMaxBattleLobbyWebhook helper.
Unknown stations are silently dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds decodePushGateway dispatcher: gates on message_type before
unmarshal (unknown types returned early), then routes raid/Max-battle
lobby payloads to UpdateGymRaidLobby/UpdateStationBattleLobby. Wires
push_contents iteration in grpc_server_raw.go and the push_contents
JSON array in routes.go Raw handler.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a proto marshal/unmarshal round-trip test for RawProtoRequest
with PushGatewayContent to guard against field number regressions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- routes.go: extend the contents-absent guard to also check len(pushItems)==0,
  so a push-only HTTP request (push_contents but no contents/nebula_contents)
  is no longer wrongly rejected with a 422 and its push items discarded.
- decoder/gym_state.go: rename RaidLobbyWebhook json tags lat/lon -> latitude/longitude
  to match every other webhook payload in the codebase.
- decoder/station_state.go: same fix for MaxBattleLobbyWebhook.
- decode_push_gateway_test.go: update ClassifiesRaidLobby and ClassifiesBreadLobby
  to call decodePushGateway with the correct message_type and a valid marshalled
  PushGatewayMessage, exercising gate-pass → unmarshal → dispatch. A recover()
  wraps the call because decoder caches (gymCache/stationCache) are nil in unit
  tests, causing a nil-pointer panic inside Update*Lobby before any DB access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The success path was silent, making it impossible to see whether a lobby
message was received, dropped (gym/station unknown), or emitted as a webhook.
Logs receipt, the unknown-fort drop, and webhook emission with the geofence
area count.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
The dedup guard used pubMs <= lastPubMs, so a message whose message_pub_timestamp_ms
is 0 was dropped on the very first update (0 <= 0). Observed in practice on Max
(bread) lobby messages, which arrive with pub=0. Treat a zero timestamp as
unorderable and always apply; keep the strictly-newer dedup only when a real
timestamp is present.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
The value is a millisecond timestamp, but the field was named lobby_join_end.
Golbat's webhook convention is unix seconds by default with an _ms suffix for
millisecond fields (cf. temp_evolution_finish_ms), so a consumer would misread
this as seconds. Rename to lobby_join_end_ms on both the raid_lobby and
max_battle_lobby webhooks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Push-gateway raid/Max lobby messages never carry message_pub_timestamp_ms
(always 0), so the publish-timestamp ordering was dead weight: the zero-pub
path already applied every message. Remove the Gym.RaidLobbyPubMs /
Station.BattleLobbyPubMs fields, the comparison in updateRaidLobby /
updateBattleLobby (now plain appliers), the pubMs parameter threaded through
the Update* entrypoints and decode, and the unused pub log field. Tests
updated to assert each update applies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jfberry jfberry merged commit 7fe204f into nebula-invasion-receiver Jun 5, 2026
5 checks passed
@jfberry jfberry deleted the push-gateway-receiver branch June 5, 2026 09:14
jfberry added a commit that referenced this pull request Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant