diff --git a/main.go b/main.go index b7ee5f8..5c63189 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "reflect" "strconv" "strings" + "sync" "time" "github.com/darenliang/jikan-go" @@ -22,20 +23,35 @@ type AnimeEntry struct { TvdbId int `json:"tvdb_id"` MalId interface{} `json:"mal_id"` } -type IdList struct { +type ConcurrentMap struct { + m map[int]int + mut sync.RWMutex } +func (m *ConcurrentMap) Get(i int) int { + m.mut.RLock() + defer m.mut.RUnlock() + return m.m[i] +} + +var lastBuiltAnimeIdList time.Time + func main() { log.Println("Building Anime ID Associations...") - malToTvdb := buildIdMap() + var malToTvdb = new(ConcurrentMap) + buildIdMap(malToTvdb) http.HandleFunc("/anime", handleAnimeSearch(malToTvdb)) log.Println("Listening on :3333") log.Fatal(http.ListenAndServe(":3333", nil)) } -func handleAnimeSearch(malToTvdb map[int]int) func(w http.ResponseWriter, r *http.Request) { +func handleAnimeSearch(malToTvdb *ConcurrentMap) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { log.Printf("%s %s?%s", r.Method, r.URL.Path, r.URL.RawQuery) + if time.Since(lastBuiltAnimeIdList) > 24*time.Hour { + log.Println("Anime ID association table expired, building new table...") + buildIdMap(malToTvdb) + } search, err := getAnimeSearch(malToTvdb, r) if err != nil { w.WriteHeader(500) @@ -45,7 +61,7 @@ func handleAnimeSearch(malToTvdb map[int]int) func(w http.ResponseWriter, r *htt } } -func getAnimeSearch(malToTvdb map[int]int, r *http.Request) (string, error) { +func getAnimeSearch(malToTvdb *ConcurrentMap, r *http.Request) (string, error) { q := r.URL.Query() limit, err := strconv.Atoi(q.Get("limit")) @@ -72,7 +88,7 @@ func getAnimeSearch(malToTvdb map[int]int, r *http.Request) (string, error) { // map the data for _, item := range result.Data { - if malToTvdb[item.MalId] == 0 { + if malToTvdb.Get(item.MalId) == 0 { log.Printf("MyAnimeList ID %d (%s a.k.a. %s) has no associated TVDB ID, skipping...\n", item.MalId, item.Title, item.TitleEnglish) continue } @@ -84,7 +100,7 @@ func getAnimeSearch(malToTvdb map[int]int, r *http.Request) (string, error) { ResponseItem{ item.Title, item.MalId, - malToTvdb[item.MalId], + malToTvdb.Get(item.MalId), }) } hasNextPage = result.Pagination.HasNextPage @@ -104,8 +120,10 @@ func getAnimeSearch(malToTvdb map[int]int, r *http.Request) (string, error) { return string(respJson), nil } -func buildIdMap() map[int]int { - // build the mal -> tvdb association table +func buildIdMap(idMap *ConcurrentMap) { + // build/re-build the mal -> tvdb association table + idMap.mut.Lock() + defer idMap.mut.Unlock() var idListBytes []byte resp, err := http.Get("https://raw.githubusercontent.com/Kometa-Team/Anime-IDs/master/anime_ids.json") if err != nil { @@ -121,7 +139,7 @@ func buildIdMap() map[int]int { if err != nil { log.Fatal("Error unmarshalling anime_ids.json: ", err) } - malToTvdb := make(map[int]int, 0) + idMap.m = make(map[int]int, 0) for _, entry := range animeMap { if entry.MalId == nil { continue @@ -141,8 +159,8 @@ func buildIdMap() map[int]int { malIdList = append(malIdList, int(entry.MalId.(float64))) } for _, val := range malIdList { - malToTvdb[val] = entry.TvdbId + idMap.m[val] = entry.TvdbId } } - return malToTvdb + lastBuiltAnimeIdList = time.Now() }