TheMathemagicians/sevenkeys/logic/update.go

206 lines
4.4 KiB
Go

package logic
import (
"database/sql"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"sevenkeys/database"
"sevenkeys/logic/scryfall"
"strings"
"time"
sqlerr "github.com/go-mysql/errors"
)
const GAME_PAPER = "paper"
func CheckForUpdates(db *sql.DB, bulkData scryfall.BulkData) (bool, error) {
// TODO: We also want to update if:
// - there is no cached version of the all-cards.json file or it is empty
// - The set icon files are missing
cachedFileTimestampStr, err := database.GetCacheTimestampByType(db, database.CacheTypeAllCardsBulkData)
if err == sql.ErrNoRows {
return true, nil
} else if err != nil {
return false, err
}
cachedFileTimestamp, err := time.Parse("2006-01-02 15:04:05", cachedFileTimestampStr)
return bulkData.UpdatedAtTime.After(cachedFileTimestamp), nil
}
func ConfirmUpdate() bool {
fmt.Print("Run update? (y/N) ")
var response string
fmt.Scan(&response)
return strings.ToUpper(response) == "Y"
}
func UpdateSets(db *sql.DB) error {
sets, err := scryfall.GetAllSets()
if err != nil {
return err
}
for _, set := range sets {
// We're only interested in paper cards, so skip importing
// any sets that were only released in a video game
if set.Digital {
continue
}
err := database.InsertSet(db, set)
// If we already have this set in the database, then we can just skip it
if ok, insertErr := sqlerr.Error(err); ok {
if insertErr == sqlerr.ErrDupeKey {
continue
}
}
if err != nil {
return err
}
response, err := http.Get(set.IconSvgUri)
defer response.Body.Close()
if err != nil {
return nil
}
iconFilename := SET_ICON_CACHE_DIR + set.Code + SET_ICON_FILE_EXTENSION
iconFile, err := os.Create(iconFilename)
if err != nil {
return err
}
io.Copy(iconFile, response.Body)
}
fmt.Println("Sets updated.")
return nil
}
func cacheBulkCardsFile(db *sql.DB, bulkData scryfall.BulkData) error {
bulkCardsResponse, err := http.Get(bulkData.DownloadUri)
defer bulkCardsResponse.Body.Close()
if err != nil {
return err
}
cacheFile, err := os.Create(ALL_CARDS_CACHE_FILENAME)
defer cacheFile.Close()
if err != nil {
return err
}
io.Copy(cacheFile, bulkCardsResponse.Body)
err = database.InsertOrUpdateCacheTimestampByType(db, database.CacheTypeAllCardsBulkData, bulkData.UpdatedAtTime)
if err != nil {
return err
}
return nil
}
func isPaper(card scryfall.Card) bool {
var paper bool = false
for _, game := range card.Games {
if game == GAME_PAPER {
paper = true
}
}
return paper
}
func getCardPrintings(card scryfall.Card) []database.CardPrinting {
var printings []database.CardPrinting
if card.Foil {
printings = append(printings, database.CardPrinting{
Id: card.Id + "f",
Name: card.Name,
SetCode: card.Set,
IsFoil: true,
IsPromo: card.Promo,
CollectorNumber: card.CollectorNumber,
Language: card.Language,
})
}
if card.NonFoil {
printings = append(printings, database.CardPrinting{
Id: card.Id + "n",
Name: card.Name,
SetCode: card.Set,
IsFoil: false,
IsPromo: card.Promo,
CollectorNumber: card.CollectorNumber,
Language: card.Language,
})
}
return printings
}
func UpdateCards(db *sql.DB, bulkData scryfall.BulkData) error {
log.Println("Caching bulk cards file")
err := cacheBulkCardsFile(db, bulkData)
if err != nil {
return err
}
log.Println("Cached bulk cards file")
log.Println("Reading cached file")
cardsBytes, err := ioutil.ReadFile(ALL_CARDS_CACHE_FILENAME)
if err != nil {
return err
}
log.Println("Read cached file")
log.Println("Unmarshaling JSON")
var cards []scryfall.Card
err = json.Unmarshal(cardsBytes, &cards)
if err != nil {
return err
}
log.Println("Unmarshaled JSON")
log.Println("INSERTing cards")
for _, card := range cards {
// We're only interested in paper cards, so skip cards or printings of a card which
// aren't available in paper
if !isPaper(card) {
continue
}
cardPrintings := getCardPrintings(card)
for _, cardPrinting := range cardPrintings {
err := database.InsertCardPrinting(db, cardPrinting)
// If we already have this card in the database, then we can just skip it
if ok, insertErr := sqlerr.Error(err); ok {
if insertErr == sqlerr.ErrDupeKey {
continue
}
}
}
if err != nil {
return err
}
}
log.Println("INSERTed cards")
return nil
}