forked from UnownHash/Fletchling
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebhooks.go
153 lines (129 loc) · 4.66 KB
/
webhooks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package httpserver
import (
"encoding/json"
"log"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"gopkg.in/guregu/null.v4"
"github.com/UnownHash/Fletchling/processor/models"
)
type decoderFn func([]byte, *WebhookMessage) error
var decoderTypes = map[string]decoderFn{
"pokemon": func(b []byte, msg *WebhookMessage) error {
return json.Unmarshal(b, &msg.Pokemon)
},
}
type WebhookMessage struct {
Type string `json:"type"`
Pokemon *PokemonWebhook
}
func (msg *WebhookMessage) UnmarshalJSON(b []byte) error {
var hook struct {
Type string `json:"type"`
Message json.RawMessage `json:"message"`
}
err := json.Unmarshal(b, &hook)
if err != nil {
return err
}
decoder := decoderTypes[hook.Type]
if decoder == nil {
log.Printf("unknown hook type: %s", hook.Type)
// silently drop unknown webhook types
return nil
}
return decoder([]byte(hook.Message), msg)
}
type PokemonWebhook struct {
SpawnpointId string `json:"spawnpoint_id"`
PokestopId string `json:"pokestop_id"`
EncounterId string `json:"encounter_id"`
PokemonId int `json:"pokemon_id"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
DisappearTime int64 `json:"disappear_time"`
DisappearTimeVerified bool `json:"disappear_time_verified"`
FirstSeen int64 `json:"first_seen"`
LastModifiedTime null.Int `json:"last_modified_time"`
Gender null.Int `json:"gender"`
Cp null.Int `json:"cp"`
Form null.Int `json:"form"`
Costume null.Int `json:"costume"`
IndividualAttack null.Int `json:"individual_attack"`
IndividualDefense null.Int `json:"individual_defense"`
IndividualStamina null.Int `json:"individual_stamina"`
PokemonLevel null.Int `json:"pokemon_level"`
Move1 null.Int `json:"move_1"`
Move2 null.Int `json:"move_2"`
Weight null.Float `json:"weight"`
Size null.Int `json:"size"`
Height null.Float `json:"height"`
Weather null.Int `json:"weather"`
Capture1 float64 `json:"capture_1"`
Capture2 float64 `json:"capture_2"`
Capture3 float64 `json:"capture_3"`
Shiny null.Bool `json:"shiny"`
Username null.String `json:"username"`
DisplayPokemonId null.Int `json:"display_pokemon_id"`
IsEvent int8 `json:"is_event"`
SeenType null.String `json:"seen_type"`
PVP json.RawMessage `json:"pvp"`
}
func (wh *PokemonWebhook) SpawnpointIdAsInt() (uint64, error) {
return strconv.ParseUint(wh.SpawnpointId, 16, 64)
}
func (wh *PokemonWebhook) EncounterIdAsInt() (uint64, error) {
return strconv.ParseUint(wh.EncounterId, 0, 64)
}
func (srv *HTTPServer) processMessages(msgs []WebhookMessage) {
var numProcessed int
for _, msg := range msgs {
pokemon := msg.Pokemon
if pokemon == nil {
srv.logger.Warnf("ignoring webhook for type '%s': please only send me pokemon!", msg.Type)
continue
}
if pokemon.PokemonId <= 0 {
srv.logger.Warnf("ignoring pokemon webhook with bad pokemon id (%#v)", *pokemon)
continue
}
spawnpointId, err := pokemon.SpawnpointIdAsInt()
if err != nil {
if pokemon.SpawnpointId != "None" && pokemon.SpawnpointId != "" {
srv.logger.Warnf("ignoring pokemon webhook with no or bad spawnpoint id: %s (%#v)", err, *pokemon)
continue
}
// lured pokemon, likely. Will match by area.
spawnpointId = 0
}
if !pokemon.IndividualAttack.Valid {
// only look at encounters.
continue
}
npPokemon := models.Pokemon{
PokemonId: pokemon.PokemonId,
FormId: int(pokemon.Form.ValueOrZero()),
SpawnpointId: spawnpointId,
Lat: pokemon.Latitude,
Lon: pokemon.Longitude,
}
srv.nestProcessorManager.ProcessPokemon(&npPokemon)
numProcessed++
}
srv.logger.Debugf("processed %d pokemon from single webhook", numProcessed)
}
func (srv *HTTPServer) handleWebhook(c *gin.Context) {
var msgs []WebhookMessage
decoder := json.NewDecoder(c.Request.Body)
err := decoder.Decode(&msgs)
if err != nil {
srv.logger.Warnf("received unprocessable webhook: %s", err)
// Bad format? I guess treat as success so caller doesn't
// retry. Tho Golbat doesn't retry at all, anyway.
c.Status(http.StatusOK)
return
}
go srv.processMessages(msgs)
c.Status(http.StatusOK)
}