diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..dd69578 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +# Игнорим данные, т.к. они не нужны для внутреннего содержимого этого контейнера +data diff --git a/Dockerfile b/Dockerfile index c72d9d7..7e6d16d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM golang:1.7 RUN mkdir -p /go/src/elyby/minecraft-skinsystem \ + /go/src/elyby/minecraft-skinsystem/data/capes \ && ln -s /go/src/elyby/minecraft-skinsystem /go/src/app WORKDIR /go/src/app diff --git a/data/capes/.gitignore b/data/capes/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/data/capes/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore 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 20020b6..9d87832 100644 --- a/lib/routes/Cape.go +++ b/lib/routes/Cape.go @@ -1,18 +1,26 @@ package routes import ( + "io" "log" "net/http" "github.com/gorilla/mux" "elyby/minecraft-skinsystem/lib/tools" + "elyby/minecraft-skinsystem/lib/data" ) -func Cape(w http.ResponseWriter, r *http.Request) { - username := tools.ParseUsername(mux.Vars(r)["username"]) +func Cape(response http.ResponseWriter, request *http.Request) { + username := tools.ParseUsername(mux.Vars(request)["username"]) log.Println("request cape for username " + username) - http.Redirect(w, r, "http://skins.minecraft.net/MinecraftCloaks/" + username + ".png", 301) + 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, 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 5f4e996..e4ce93d 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -3,8 +3,13 @@ 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 + +var RootFolder string 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 1f99e2a..2df5aa8 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -13,6 +13,7 @@ import ( "elyby/minecraft-skinsystem/lib/routes" "elyby/minecraft-skinsystem/lib/services" "elyby/minecraft-skinsystem/lib/worker" + "path/filepath" ) const redisString string = "redis:6379" @@ -61,9 +62,13 @@ 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 + _, file, _, _ := runtime.Caller(0) + services.RootFolder = filepath.Dir(file) + go func() { period := 5 for {