mirror of
https://github.com/bestnite/igdb-database.git
synced 2025-06-04 12:35:00 +08:00
220 lines
7.8 KiB
Go
220 lines
7.8 KiB
Go
package collector
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"igdb-database/config"
|
|
"igdb-database/db"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"slices"
|
|
|
|
pb "github.com/bestnite/go-igdb/proto"
|
|
|
|
"github.com/bestnite/go-igdb"
|
|
"github.com/bestnite/go-igdb/endpoint"
|
|
"go.mongodb.org/mongo-driver/v2/mongo"
|
|
)
|
|
|
|
func StartWebhookServer(client *igdb.Client) {
|
|
baseUrl, err := url.Parse(config.C().ExternalUrl)
|
|
if err != nil {
|
|
log.Fatalf("failed to parse url: %v", err)
|
|
}
|
|
|
|
http.HandleFunc(webhook(client.AgeRatingCategories, client))
|
|
http.HandleFunc(webhook(client.AgeRatingContentDescriptions, client))
|
|
http.HandleFunc(webhook(client.AgeRatingContentDescriptionsV2, client))
|
|
http.HandleFunc(webhook(client.AgeRatingOrganizations, client))
|
|
http.HandleFunc(webhook(client.AgeRatings, client))
|
|
http.HandleFunc(webhook(client.AlternativeNames, client))
|
|
http.HandleFunc(webhook(client.Artworks, client))
|
|
http.HandleFunc(webhook(client.CharacterGenders, client))
|
|
http.HandleFunc(webhook(client.CharacterMugShots, client))
|
|
http.HandleFunc(webhook(client.Characters, client))
|
|
http.HandleFunc(webhook(client.CharacterSpecies, client))
|
|
http.HandleFunc(webhook(client.CollectionMemberships, client))
|
|
http.HandleFunc(webhook(client.CollectionMembershipTypes, client))
|
|
http.HandleFunc(webhook(client.CollectionRelations, client))
|
|
http.HandleFunc(webhook(client.CollectionRelationTypes, client))
|
|
http.HandleFunc(webhook(client.Collections, client))
|
|
http.HandleFunc(webhook(client.CollectionTypes, client))
|
|
http.HandleFunc(webhook(client.Companies, client))
|
|
http.HandleFunc(webhook(client.CompanyLogos, client))
|
|
http.HandleFunc(webhook(client.CompanyStatuses, client))
|
|
http.HandleFunc(webhook(client.CompanyWebsites, client))
|
|
http.HandleFunc(webhook(client.Covers, client))
|
|
http.HandleFunc(webhook(client.DateFormats, client))
|
|
http.HandleFunc(webhook(client.EventLogos, client))
|
|
http.HandleFunc(webhook(client.EventNetworks, client))
|
|
http.HandleFunc(webhook(client.Events, client))
|
|
http.HandleFunc(webhook(client.ExternalGames, client))
|
|
http.HandleFunc(webhook(client.ExternalGameSources, client))
|
|
http.HandleFunc(webhook(client.Franchises, client))
|
|
http.HandleFunc(webhook(client.GameEngineLogos, client))
|
|
http.HandleFunc(webhook(client.GameEngines, client))
|
|
http.HandleFunc(webhook(client.GameLocalizations, client))
|
|
http.HandleFunc(webhook(client.GameModes, client))
|
|
http.HandleFunc(webhook(client.GameReleaseFormats, client))
|
|
http.HandleFunc(webhook(client.Games, client))
|
|
http.HandleFunc(webhook(client.GameStatuses, client))
|
|
http.HandleFunc(webhook(client.GameTimeToBeats, client))
|
|
http.HandleFunc(webhook(client.GameTypes, client))
|
|
http.HandleFunc(webhook(client.GameVersionFeatures, client))
|
|
http.HandleFunc(webhook(client.GameVersionFeatureValues, client))
|
|
http.HandleFunc(webhook(client.GameVersions, client))
|
|
http.HandleFunc(webhook(client.GameVideos, client))
|
|
http.HandleFunc(webhook(client.Genres, client))
|
|
http.HandleFunc(webhook(client.InvolvedCompanies, client))
|
|
http.HandleFunc(webhook(client.Keywords, client))
|
|
http.HandleFunc(webhook(client.Languages, client))
|
|
http.HandleFunc(webhook(client.LanguageSupports, client))
|
|
http.HandleFunc(webhook(client.LanguageSupportTypes, client))
|
|
http.HandleFunc(webhook(client.MultiplayerModes, client))
|
|
http.HandleFunc(webhook(client.NetworkTypes, client))
|
|
http.HandleFunc(webhook(client.PlatformFamilies, client))
|
|
http.HandleFunc(webhook(client.PlatformLogos, client))
|
|
http.HandleFunc(webhook(client.Platforms, client))
|
|
http.HandleFunc(webhook(client.PlatformTypes, client))
|
|
http.HandleFunc(webhook(client.PlatformVersionCompanies, client))
|
|
http.HandleFunc(webhook(client.PlatformVersionReleaseDates, client))
|
|
http.HandleFunc(webhook(client.PlatformVersions, client))
|
|
http.HandleFunc(webhook(client.PlatformWebsites, client))
|
|
http.HandleFunc(webhook(client.PlayerPerspectives, client))
|
|
http.HandleFunc(webhook(client.PopularityTypes, client))
|
|
http.HandleFunc(webhook(client.Regions, client))
|
|
http.HandleFunc(webhook(client.ReleaseDateRegions, client))
|
|
http.HandleFunc(webhook(client.ReleaseDates, client))
|
|
http.HandleFunc(webhook(client.ReleaseDateStatuses, client))
|
|
http.HandleFunc(webhook(client.Screenshots, client))
|
|
http.HandleFunc(webhook(client.Themes, client))
|
|
http.HandleFunc(webhook(client.Websites, client))
|
|
http.HandleFunc(webhook(client.WebsiteTypes, client))
|
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(200)
|
|
if _, err := w.Write([]byte("Hello World!")); err != nil {
|
|
log.Printf("failed to write response: %v", err)
|
|
}
|
|
})
|
|
|
|
serverStart := make(chan bool)
|
|
go func() {
|
|
defer close(serverStart)
|
|
log.Printf("starting webhook server on %s", config.C().Address)
|
|
err = http.ListenAndServe(config.C().Address, nil)
|
|
if err != nil {
|
|
log.Fatalf("failed to start webhook server: %v", err)
|
|
}
|
|
}()
|
|
|
|
enabledEndpoint := endpoint.AllNames
|
|
enabledEndpoint = slices.DeleteFunc(enabledEndpoint, func(e endpoint.Name) bool {
|
|
return e == endpoint.EPWebhooks || e == endpoint.EPSearch || e == endpoint.EPPopularityPrimitives
|
|
})
|
|
|
|
ip := net.ParseIP(baseUrl.Hostname())
|
|
if baseUrl.Hostname() == "localhost" || (ip != nil && ip.IsLoopback()) {
|
|
log.Printf("extral url is localhost. webhook will not be registered")
|
|
} else {
|
|
for _, ep := range enabledEndpoint {
|
|
Url := baseUrl.JoinPath(fmt.Sprintf("/webhook/%s", string(ep)))
|
|
log.Printf("registering webhook \"%s\" to \"%s\"", ep, Url.String())
|
|
_, err = client.Webhooks.Register(ep, config.C().WebhookSecret, Url.String(), endpoint.WebhookMethodCreate)
|
|
if err != nil {
|
|
log.Fatalf("failed to register webhook \"%s\": %v", ep, err)
|
|
}
|
|
_, err = client.Webhooks.Register(ep, config.C().WebhookSecret, Url.String(), endpoint.WebhookMethodUpdate)
|
|
if err != nil {
|
|
log.Fatalf("failed to register webhook \"%s\": %v", ep, err)
|
|
}
|
|
log.Printf("webhook \"%s\" registered", ep)
|
|
}
|
|
log.Printf("all webhook registered")
|
|
}
|
|
|
|
<-serverStart
|
|
}
|
|
|
|
func webhook[T any](
|
|
e endpoint.EntityEndpoint[T],
|
|
client *igdb.Client,
|
|
) (string, func(w http.ResponseWriter, r *http.Request)) {
|
|
return fmt.Sprintf("/webhook/%s", e.GetEndpointName()), func(w http.ResponseWriter, r *http.Request) {
|
|
secret := r.Header.Get("X-Secret")
|
|
if secret != config.C().WebhookSecret {
|
|
w.WriteHeader(401)
|
|
return
|
|
}
|
|
w.WriteHeader(200)
|
|
data := struct {
|
|
ID uint64 `json:"id"`
|
|
}{}
|
|
jsonBytes, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
log.Printf("failed to read request body: %v", err)
|
|
return
|
|
}
|
|
err = json.Unmarshal(jsonBytes, &data)
|
|
if err != nil {
|
|
log.Printf("failed to unmarshal request body: %v", err)
|
|
return
|
|
}
|
|
if data.ID == 0 {
|
|
return
|
|
}
|
|
item, err := e.GetByID(data.ID)
|
|
if err != nil {
|
|
log.Printf("failed to get %s: %v", e.GetEndpointName(), err)
|
|
return
|
|
}
|
|
|
|
if _, ok := any(e).(*endpoint.Games); ok {
|
|
game := any(item).(*pb.Game)
|
|
g, err := db.ConvertGame(game, client)
|
|
if err != nil {
|
|
log.Printf("failed to convert game: %v", err)
|
|
} else {
|
|
_ = db.SaveGame(g)
|
|
log.Printf("game %d aggregated", data.ID)
|
|
}
|
|
}
|
|
|
|
err = db.SaveItem(e.GetEndpointName(), item)
|
|
if err != nil {
|
|
log.Printf("failed to save %s: %v", e.GetEndpointName(), err)
|
|
return
|
|
}
|
|
|
|
// update associated game
|
|
type gameGetter interface {
|
|
GetGame() *pb.Game
|
|
}
|
|
|
|
if v, ok := any(item).(gameGetter); ok {
|
|
game, err := db.GetItemById[pb.Game](endpoint.EPGames, v.GetGame().Id)
|
|
if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
|
|
log.Printf("failed to get game: %v", err)
|
|
goto END
|
|
}
|
|
g, err := db.ConvertGame(game, client)
|
|
if err != nil {
|
|
log.Printf("failed to convert game: %v", err)
|
|
goto END
|
|
}
|
|
err = db.SaveGame(g)
|
|
if err != nil {
|
|
log.Printf("failed to save game: %v", err)
|
|
goto END
|
|
}
|
|
log.Printf("game %d aggregated", data.ID)
|
|
}
|
|
|
|
END:
|
|
log.Printf("%s %d saved", e.GetEndpointName(), data.ID)
|
|
}
|
|
}
|