diff --git a/lib/data/CapeItem.go b/lib/data/CapeItem.go new file mode 100644 index 0000000..8f03ad8 --- /dev/null +++ b/lib/data/CapeItem.go @@ -0,0 +1,43 @@ +package data + +import ( + "io" + "os" + "fmt" + "strings" + "crypto/md5" + "encoding/hex" + + "elyby/minecraft-skinsystem/lib/services" +) + +type CapeItem struct { + File *os.File +} + +func FindCapeByUsername(username string) (CapeItem, error) { + var record CapeItem + file, err := os.Open(services.RootFolder + "/data/capes/" + strings.ToLower(username) + ".png") + if (err != nil) { + return record, CapeNotFound{username} + } + + record.File = file + + return record, err +} + +func (cape *CapeItem) CalculateHash() string { + hasher := md5.New() + io.Copy(hasher, cape.File) + + return hex.EncodeToString(hasher.Sum(nil)) +} + +type CapeNotFound struct { + Who string +} + +func (e CapeNotFound) Error() string { + return fmt.Sprintf("Cape file not found. Required username \"%v\"", e.Who) +} diff --git a/lib/data/DataNotFound.go b/lib/data/DataNotFound.go deleted file mode 100644 index 0f5e5c2..0000000 --- a/lib/data/DataNotFound.go +++ /dev/null @@ -1,11 +0,0 @@ -package data - -import "fmt" - -type DataNotFound struct { - Who string -} - -func (e DataNotFound) Error() string { - return fmt.Sprintf("Skin data not found. Required username \"%v\"", e.Who) -} diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go index 0aca44f..8ad55d7 100644 --- a/lib/data/SkinItem.go +++ b/lib/data/SkinItem.go @@ -2,6 +2,7 @@ package data import ( "log" + "fmt" "encoding/json" "elyby/minecraft-skinsystem/lib/services" @@ -59,11 +60,11 @@ func (s *SkinItem) Delete() { pool.Cmd("EXEC") } -func FindByUsername(username string) (SkinItem, error) { +func FindSkinByUsername(username string) (SkinItem, error) { var record SkinItem; response := services.RedisPool.Cmd("GET", tools.BuildKey(username)); if (response.IsType(redis.Nil)) { - return record, DataNotFound{username} + return record, SkinNotFound{username} } result, err := response.Str() @@ -79,13 +80,21 @@ func FindByUsername(username string) (SkinItem, error) { return record, err } -func FindById(id int) (SkinItem, error) { +func FindSkinById(id int) (SkinItem, error) { response := services.RedisPool.Cmd("HGET", accountIdToUsernameKey, id); if (response.IsType(redis.Nil)) { - return SkinItem{}, DataNotFound{"unknown"} + return SkinItem{}, SkinNotFound{"unknown"} } username, _ := response.Str() - return FindByUsername(username) + return FindSkinByUsername(username) +} + +type SkinNotFound struct { + Who string +} + +func (e SkinNotFound) Error() string { + return fmt.Sprintf("Skin data not found. Required username \"%v\"", e.Who) } diff --git a/lib/data/TexturesResponse.go b/lib/data/TexturesResponse.go index 4716a21..9d2d962 100644 --- a/lib/data/TexturesResponse.go +++ b/lib/data/TexturesResponse.go @@ -2,6 +2,7 @@ package data type TexturesResponse struct { Skin *Skin `json:"SKIN"` + Cape *Cape `json:"CAPE,omitempty"` } type Skin struct { @@ -13,3 +14,8 @@ type Skin struct { type SkinMetadata struct { Model string `json:"model"` } + +type Cape struct { + Url string `json:"url"` + Hash string `json:"hash"` +} diff --git a/lib/routes/Cape.go b/lib/routes/Cape.go index c38b087..9d87832 100644 --- a/lib/routes/Cape.go +++ b/lib/routes/Cape.go @@ -1,28 +1,26 @@ package routes import ( - "os" "io" "log" - "strings" "net/http" "github.com/gorilla/mux" "elyby/minecraft-skinsystem/lib/tools" - "elyby/minecraft-skinsystem/lib/services" + "elyby/minecraft-skinsystem/lib/data" ) func Cape(response http.ResponseWriter, request *http.Request) { username := tools.ParseUsername(mux.Vars(request)["username"]) log.Println("request cape for username " + username) - file, err := os.Open(services.RootFolder + "/data/capes/" + strings.ToLower(username) + ".png") + rec, err := data.FindCapeByUsername(username) if (err != nil) { http.Redirect(response, request, "http://skins.minecraft.net/MinecraftCloaks/" + username + ".png", 301) } request.Header.Set("Content-Type", "image/png") - io.Copy(response, file) + io.Copy(response, rec.File) } func CapeGET(w http.ResponseWriter, r *http.Request) { diff --git a/lib/routes/Face.go b/lib/routes/Face.go index 7b99996..8e19018 100644 --- a/lib/routes/Face.go +++ b/lib/routes/Face.go @@ -15,7 +15,7 @@ const defaultHash = "default" func Face(w http.ResponseWriter, r *http.Request) { username := tools.ParseUsername(mux.Vars(r)["username"]) log.Println("request skin for username " + username); - rec, err := data.FindByUsername(username) + rec, err := data.FindSkinByUsername(username) var hash string if (err != nil || rec.SkinId == 0) { hash = defaultHash; diff --git a/lib/routes/Skin.go b/lib/routes/Skin.go index baeaeb2..97a1e5c 100644 --- a/lib/routes/Skin.go +++ b/lib/routes/Skin.go @@ -13,7 +13,7 @@ import ( func Skin(w http.ResponseWriter, r *http.Request) { username := tools.ParseUsername(mux.Vars(r)["username"]) log.Println("request skin for username " + username); - rec, err := data.FindByUsername(username) + rec, err := data.FindSkinByUsername(username) if (err != nil) { http.Redirect(w, r, "http://skins.minecraft.net/MinecraftSkins/" + username + ".png", 301) return diff --git a/lib/routes/Textures.go b/lib/routes/Textures.go index fa9f573..b1cd1ae 100644 --- a/lib/routes/Textures.go +++ b/lib/routes/Textures.go @@ -9,13 +9,14 @@ import ( "elyby/minecraft-skinsystem/lib/data" "elyby/minecraft-skinsystem/lib/tools" + "elyby/minecraft-skinsystem/lib/services" ) func Textures(w http.ResponseWriter, r *http.Request) { username := tools.ParseUsername(mux.Vars(r)["username"]) log.Println("request textures for username " + username) - rec, err := data.FindByUsername(username) + rec, err := data.FindSkinByUsername(username) if (err != nil || rec.SkinId == 0) { rec.Url = "http://skins.minecraft.net/MinecraftSkins/" + username + ".png" rec.Hash = string(tools.BuildNonElyTexturesHash(username)) @@ -36,6 +37,24 @@ func Textures(w http.ResponseWriter, r *http.Request) { } } + capeRec, err := data.FindCapeByUsername(username) + if (err == nil) { + capeUrl, err := services.Router.Get("cloaks").URL("username", username) + if (err != nil) { + log.Println(err.Error()) + } + + var scheme string = "http://"; + if (r.TLS != nil) { + scheme = "https://" + } + + textures.Cape = &data.Cape{ + Url: scheme + r.Host + capeUrl.String(), + Hash: capeRec.CalculateHash(), + } + } + response,_ := json.Marshal(textures) w.Header().Set("Content-Type", "application/json") w.Write(response) diff --git a/lib/services/services.go b/lib/services/services.go index 6f7241b..e4ce93d 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -3,8 +3,11 @@ package services import ( "github.com/mediocregopher/radix.v2/pool" "github.com/streadway/amqp" + "github.com/gorilla/mux" ) +var Router *mux.Router + var RedisPool *pool.Pool var RabbitMQChannel *amqp.Channel diff --git a/lib/worker/handlers.go b/lib/worker/handlers.go index 7986490..36186f8 100644 --- a/lib/worker/handlers.go +++ b/lib/worker/handlers.go @@ -17,7 +17,7 @@ func handleChangeUsername(model usernameChanged) (bool) { return true } - record, err := data.FindByUsername(model.OldUsername) + record, err := data.FindSkinByUsername(model.OldUsername) if (err != nil) { log.Println("Exit by not found record") // TODO: я не уверен, что это валидное поведение @@ -35,7 +35,7 @@ func handleChangeUsername(model usernameChanged) (bool) { } func handleSkinChanged(model skinChanged) (bool) { - record, err := data.FindById(model.AccountId) + record, err := data.FindSkinById(model.AccountId) if (err != nil) { return true } diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 3527e36..2df5aa8 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -62,6 +62,7 @@ func main() { apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") + services.Router = router services.RedisPool = redisPool services.RabbitMQChannel = rabbitChannel