Skip to content
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ type scanRule struct {
ProcessCells *bool `koanf:"cells"`
ProcessPokestops *bool `koanf:"pokestops"`
ProcessGyms *bool `koanf:"gyms"`
ProcessLobbies *bool `koanf:"lobbies"`
}

var Config configDefinition
110 changes: 69 additions & 41 deletions decoder/gym.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ type Gym struct {
PowerUpPoints null.Int `db:"power_up_points"`
PowerUpEndTimestamp null.Int `db:"power_up_end_timestamp"`
Description null.String `db:"description"`
LobbyPlayerCount int32
LobbyJoinEndMs int64
//`id` varchar(35) NOT NULL,
//`lat` double(18,14) NOT NULL,
//`lon` double(18,14) NOT NULL,
Expand Down Expand Up @@ -379,11 +381,75 @@ func createGymFortWebhooks(oldGym *Gym, gym *Gym) {
}
}

func makeRaidWebhook(gym *Gym) (payload map[string]interface{}) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main advantage (as I understand it) of using named returns is that you have immediately created the return type. You then go on and re-assign it, which gives rise to an additional allocation rather than having pre-made one.

Whilst this is not the world's biggest thing, I haven't wrapped my head around when it is good stylistically to use this, vs not recommended.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that is not already optimized by the compiler already, a map allocation should still be virtually for free.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect you're right, it was more a style discussion. It seems the go language recommendations are only to use it on short functions where you can see the definition and the return on a single page, and warning against re-using the variable because it can be shadowed.

payload = map[string]interface{}{
"gym_id": gym.Id,
"gym_name": func() string {
if !gym.Name.Valid {
return "Unknown"
} else {
return gym.Name.String
}
}(),
"gym_url": gym.Url.ValueOrZero(),
"latitude": gym.Lat,
"longitude": gym.Lon,
"team_id": gym.TeamId.ValueOrZero(),
"spawn": gym.RaidSpawnTimestamp.ValueOrZero(),
"start": gym.RaidBattleTimestamp.ValueOrZero(),
"end": gym.RaidEndTimestamp.ValueOrZero(),
"level": gym.RaidLevel.ValueOrZero(),
"pokemon_id": gym.RaidPokemonId.ValueOrZero(),
"cp": gym.RaidPokemonCp.ValueOrZero(),
"gender": gym.RaidPokemonGender.ValueOrZero(),
"form": gym.RaidPokemonForm.ValueOrZero(),
"alignment": gym.RaidPokemonAlignment.ValueOrZero(),
"costume": gym.RaidPokemonCostume.ValueOrZero(),
"evolution": gym.RaidPokemonEvolution.ValueOrZero(),
"move_1": gym.RaidPokemonMove1.ValueOrZero(),
"move_2": gym.RaidPokemonMove2.ValueOrZero(),
"ex_raid_eligible": gym.ExRaidEligible.ValueOrZero(),
"is_exclusive": gym.RaidIsExclusive.ValueOrZero(),
"sponsor_id": gym.SponsorId.ValueOrZero(),
"partner_id": gym.PartnerId.ValueOrZero(),
"power_up_points": gym.PowerUpPoints.ValueOrZero(),
"power_up_level": gym.PowerUpLevel.ValueOrZero(),
"power_up_end_timestamp": gym.PowerUpEndTimestamp.ValueOrZero(),
"ar_scan_eligible": gym.ArScanEligible.ValueOrZero(),
"lobby_player_count": gym.LobbyPlayerCount,
"lobby_join_end_ms": gym.LobbyJoinEndMs,
}
return
}

func CreateRaidLobbyPlayerCountWebhooks(ctx context.Context, db db.DbDetails, lobby *pogo.RaidLobbyPlayerCountProto) bool {
gymMutex, _ := gymStripedMutex.GetLock(lobby.GymId)
gymMutex.Lock()
defer gymMutex.Unlock()

gym, _ := getGymRecord(ctx, db, lobby.GymId)
if gym == nil { // skip reporting for unseen gyms
return false
}
if gym.LobbyPlayerCount == lobby.PlayerCount &&
(lobby.PlayerCount == 0 || gym.LobbyJoinEndMs == lobby.LobbyJoinUntilMs) {
// skip unchanged lobbies or empty lobby updates
return false
}
gym.LobbyPlayerCount = lobby.PlayerCount
gym.LobbyJoinEndMs = lobby.LobbyJoinUntilMs
gymCache.Set(gym.Id, *gym, ttlcache.DefaultTTL)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you're doing here - reproducing the change logic in save. I wonder if this is the clearest way (I'm not objecting here, just musing). The other alternative would be to call saveRecord as normal and have it decide there is no need to commit to database (ie there are no record changes), but still worth sending a webhook since there are raid lobby changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like the best option for now.

payload := makeRaidWebhook(gym)
areas := MatchStatsGeofence(gym.Lat, gym.Lon)
webhooks.AddMessage(webhooks.Raid, payload, areas)
return true
}

func createGymWebhooks(oldGym *Gym, gym *Gym) {
areas := MatchStatsGeofence(gym.Lat, gym.Lon)
if oldGym == nil ||
(oldGym.AvailableSlots != gym.AvailableSlots || oldGym.TeamId != gym.TeamId || oldGym.InBattle != gym.InBattle) {
gymDetails := GymDetailsWebhook{
webhooks.AddMessage(webhooks.GymDetails, GymDetailsWebhook{
Id: gym.Id,
Name: gym.Name.ValueOrZero(),
Url: gym.Url.ValueOrZero(),
Expand All @@ -400,9 +466,7 @@ func createGymWebhooks(oldGym *Gym, gym *Gym) {
}(),
ExRaidEligible: gym.ExRaidEligible.ValueOrZero(),
InBattle: func() bool { return gym.InBattle.ValueOrZero() != 0 }(),
}

webhooks.AddMessage(webhooks.GymDetails, gymDetails, areas)
}, areas)
}

if gym.RaidSpawnTimestamp.ValueOrZero() > 0 &&
Expand All @@ -415,43 +479,7 @@ func createGymWebhooks(oldGym *Gym, gym *Gym) {

if (raidBattleTime > now && gym.RaidLevel.ValueOrZero() > 0) ||
(raidEndTime > now && gym.RaidPokemonId.ValueOrZero() > 0) {
raidHook := map[string]interface{}{
"gym_id": gym.Id,
"gym_name": func() string {
if !gym.Name.Valid {
return "Unknown"
} else {
return gym.Name.String
}
}(),
"gym_url": gym.Url.ValueOrZero(),
"latitude": gym.Lat,
"longitude": gym.Lon,
"team_id": gym.TeamId.ValueOrZero(),
"spawn": gym.RaidSpawnTimestamp.ValueOrZero(),
"start": gym.RaidBattleTimestamp.ValueOrZero(),
"end": gym.RaidEndTimestamp.ValueOrZero(),
"level": gym.RaidLevel.ValueOrZero(),
"pokemon_id": gym.RaidPokemonId.ValueOrZero(),
"cp": gym.RaidPokemonCp.ValueOrZero(),
"gender": gym.RaidPokemonGender.ValueOrZero(),
"form": gym.RaidPokemonForm.ValueOrZero(),
"alignment": gym.RaidPokemonAlignment.ValueOrZero(),
"costume": gym.RaidPokemonCostume.ValueOrZero(),
"evolution": gym.RaidPokemonEvolution.ValueOrZero(),
"move_1": gym.RaidPokemonMove1.ValueOrZero(),
"move_2": gym.RaidPokemonMove2.ValueOrZero(),
"ex_raid_eligible": gym.ExRaidEligible.ValueOrZero(),
"is_exclusive": gym.RaidIsExclusive.ValueOrZero(),
"sponsor_id": gym.SponsorId.ValueOrZero(),
"partner_id": gym.PartnerId.ValueOrZero(),
"power_up_points": gym.PowerUpPoints.ValueOrZero(),
"power_up_level": gym.PowerUpLevel.ValueOrZero(),
"power_up_end_timestamp": gym.PowerUpEndTimestamp.ValueOrZero(),
"ar_scan_eligible": gym.ArScanEligible.ValueOrZero(),
}

webhooks.AddMessage(webhooks.Raid, raidHook, areas)
webhooks.AddMessage(webhooks.Raid, makeRaidWebhook(gym), areas)
}
}

Expand Down
3 changes: 3 additions & 0 deletions decoder/scanarea.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type ScanParameters struct {
ProcessPokestops bool
ProcessGyms bool
ProcessCells bool
ProcessLobbies bool
}

func FindScanConfiguration(scanContext string, lat, lon float64) ScanParameters {
Expand Down Expand Up @@ -59,6 +60,7 @@ func FindScanConfiguration(scanContext string, lat, lon float64) ScanParameters
ProcessWeather: defaultTrue(rule.ProcessWeather),
ProcessPokestops: defaultTrue(rule.ProcessPokestops),
ProcessGyms: defaultTrue(rule.ProcessGyms),
ProcessLobbies: defaultTrue(rule.ProcessLobbies),
}
}

Expand All @@ -70,5 +72,6 @@ func FindScanConfiguration(scanContext string, lat, lon float64) ScanParameters
ProcessWeather: true,
ProcessGyms: true,
ProcessPokestops: true,
ProcessLobbies: true,
}
}
29 changes: 29 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ func decode(ctx context.Context, method int, protoData *ProtoData) {
case pogo.Method_METHOD_GET_MAP_FORTS:
result = decodeGetMapForts(ctx, protoData.Data)
processed = true
case pogo.Method_METHOD_GET_RAID_LOBBY_COUNTER:
if getScanParameters(protoData).ProcessLobbies {
result = decodeGetRaidLobbyCounter(ctx, protoData.Data)
}
processed = true
default:
log.Debugf("Did not process hook type %s", pogo.Method(method))
}
Expand Down Expand Up @@ -458,6 +463,30 @@ func decodeGetMapForts(ctx context.Context, sDec []byte) string {
return "No forts updated"
}

func decodeGetRaidLobbyCounter(ctx context.Context, sDec []byte) string {
decodedRaidLobbyCounter := &pogo.GetRaidLobbyCounterOutProto{}
if err := proto.Unmarshal(sDec, decodedRaidLobbyCounter); err != nil {
log.Errorf("Failed to parse %s", err)
return fmt.Sprintf("Failed to parse %s", err)
}

if decodedRaidLobbyCounter.Result != pogo.GetRaidLobbyCounterOutProto_SUCCESS {
return fmt.Sprintf(`GetRaidLobbyCounterOutProto: Ignored non-success value %d:%s`,
decodedRaidLobbyCounter.Result,
decodedRaidLobbyCounter.Result.String())
}

processedLobbies := 0
for _, lobby := range decodedRaidLobbyCounter.RaidLobbyPlayerCount {
if decoder.CreateRaidLobbyPlayerCountWebhooks(ctx, dbDetails, lobby) {
processedLobbies += 1
}
}

return fmt.Sprintf("Updated %d/%d lobbies",
processedLobbies, len(decodedRaidLobbyCounter.RaidLobbyPlayerCount))
}

func decodeGetGymInfo(ctx context.Context, sDec []byte) string {
decodedGymInfo := &pogo.GymGetInfoOutProto{}
if err := proto.Unmarshal(sDec, decodedGymInfo); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions protos.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ requires the proto request to be present in the raw.

- Provides confirmation of a real or decoy Giovanni

`Method_METHOD_GET_RAID_LOBBY_COUNTER`

- Bulk lobby query for gyms

# Social actions

- The master `ClientAction_CLIENT_ACTION_PROXY_SOCIAL_ACTION` proto will be
Expand Down