From b38b78bd1e60f81a092422e810a16ba4c52404bb Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Sun, 3 Jul 2016 21:47:13 +0300 Subject: [PATCH 01/17] =?UTF-8?q?=D0=97=D0=B0=D1=87=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - .htaccess | 5 --- app.php | 90 --------------------------------------------- cloaks/.gitignore | 2 - config/config.php | 15 -------- config/loader.php | 12 ------ config/services.php | 46 ----------------------- models/Skins.php | 39 -------------------- public/.htaccess | 7 ---- public/index.php | 24 ------------ 10 files changed, 241 deletions(-) delete mode 100644 .htaccess delete mode 100644 app.php delete mode 100644 cloaks/.gitignore delete mode 100644 config/config.php delete mode 100644 config/loader.php delete mode 100644 config/services.php delete mode 100644 models/Skins.php delete mode 100644 public/.htaccess delete mode 100644 public/index.php diff --git a/.gitignore b/.gitignore index df1697c..a09c56d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ /.idea -/awstat \ No newline at end of file diff --git a/.htaccess b/.htaccess deleted file mode 100644 index aa6a7f7..0000000 --- a/.htaccess +++ /dev/null @@ -1,5 +0,0 @@ - - RewriteEngine on - RewriteRule ^$ public/ [L] - RewriteRule (.*) public/$1 [L] - \ No newline at end of file diff --git a/app.php b/app.php deleted file mode 100644 index cb14912..0000000 --- a/app.php +++ /dev/null @@ -1,90 +0,0 @@ -get('/skins/{nickname}', function ($nickname) use ($app) { - // $systemVersion = $app->request->get('version', 'int'); - // $minecraftVersion = $app->request->get('minecraft_version', 'string'); - - // На всякий случай проверка на наличие .png для файла - if (strrpos($nickname, '.png') != -1) { - $nickname = explode('.', $nickname)[0]; - } - - // TODO: восстановить функцию деградации скинов - - $skin = Skins::findByNickname($nickname); - if (!$skin || $skin->skinId == 0) { - return $app->response->redirect('http://skins.minecraft.net/MinecraftSkins/' . $nickname . '.png', true); - } - - return $app->response->redirect($skin->url); -})->setName('skinSystem'); - -$app->get('/cloaks/{nickname}', function ($nickname) use ($app) { - // На всякий случай проверка на наличие .png для файла - if (strrpos($nickname, '.png') != -1) { - $nickname = explode('.', $nickname)[0]; - } - - return $app->response->redirect('http://skins.minecraft.net/MinecraftCloaks/'.$nickname.'.png'); -}); - -$app->get('/textures/{nickname}', function($nickname) use ($app) { - $skin = Skins::findByNickname($nickname); - if ($skin && $skin->skinId != 0) { - $url = $skin->url; - $hash = $skin->hash; - } else { - $url = 'http://skins.minecraft.net/MinecraftSkins/'.$nickname.'.png'; - $hash = md5('non-ely-' . mktime(date('H'), 0, 0) . '-' . $nickname); - } - - // TODO: в authserver.ely.by есть готовый класс для работы с форматом текстур. Так что если мы его вынесем в - // common library, то нужно будет заменить его здесь - - $textures = [ - 'SKIN' => [ - 'url' => $url, - 'hash' => $hash, - ], - ]; - - if ($skin && $skin->isSlim) { - $textures['SKIN']['metadata']['model'] = 'slim'; - } - - return $app->response->setContentType('application/json')->setJsonContent($textures); -}); - -$app->post('/system/setSkin', function() use ($app) { - $headers = getallheaders(); - if (!array_key_exists('X-Ely-key', $headers) || $headers['X-Ely-key'] != '43fd2ce61b3f5704dfd729c1f2d6ffdb') { - return $app->response->setStatusCode(403, 'Forbidden')->setContent('Хорошая попытка, мерзкий хакер.'); - } - - $request = $app->request; - $nickname = mb_convert_case($request->getPost('nickname', 'string'), MB_CASE_LOWER, ENCODING); - - $skin = Skins::findByNickname($nickname); - if (!$skin) { - $skin = new Skins(); - $skin->nickname = $nickname; - } - - $skin->userId = (int) $request->getPost('userId', 'int'); - $skin->skinId = (int) $request->getPost('skinId', 'int'); - $skin->hash = $request->getPost('hash', 'string'); - $skin->is1_8 = (bool) $request->getPost('is1_8', 'int'); - $skin->isSlim = (bool) $request->getPost('isSlim', 'int'); - $skin->url = $request->getPost('url', 'string'); - - return $app->view->setContent($skin->save() ? 'OK' : 'ERROR'); -}); - -$app->notFound(function () use ($app) { - $app->response - ->setStatusCode(404, 'Not Found') - ->setContent('Not Found
Система скинов Ely.by.') - ->send(); -}); diff --git a/cloaks/.gitignore b/cloaks/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/cloaks/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/config/config.php b/config/config.php deleted file mode 100644 index 4060a06..0000000 --- a/config/config.php +++ /dev/null @@ -1,15 +0,0 @@ - [ - 'host' => 'localhost', - 'port' => 27017, - 'username' => '', - 'password' => '', - 'dbname' => 'ely_skins', - ], - 'application' => [ - 'modelsDir' => __DIR__ . '/../models/', - 'baseUri' => '/', - ] -]); diff --git a/config/loader.php b/config/loader.php deleted file mode 100644 index eda8dce..0000000 --- a/config/loader.php +++ /dev/null @@ -1,12 +0,0 @@ -registerDirs(array( - $config->application->modelsDir -)); - -$loader->register(); diff --git a/config/services.php b/config/services.php deleted file mode 100644 index f245bda..0000000 --- a/config/services.php +++ /dev/null @@ -1,46 +0,0 @@ -set('view', function () { - $view = new View(); - $view->disable(); - - return $view; -}); - -/** - * The URL component is used to generate all kind of urls in the application - */ -$di->set('url', function () use ($config) { - $url = new UrlResolver(); - $url->setBaseUri($config->application->baseUri); - - return $url; -}); - -$di->set('mongo', function() use ($config) { - /** @var StdClass $mongoConfig */ - $mongoConfig = $config->mongo; - $connectionString = 'mongodb://'; - if ($mongoConfig->username && $mongoConfig->password) { - $connectionString .= "{$mongoConfig->username}:{$mongoConfig->password}@"; - } - - $connectionString .= $mongoConfig->host . ':' . $mongoConfig->port; - $mongo = new MongoClient($connectionString); - - return $mongo->selectDb($mongoConfig->dbname); -}); - -$di->setShared('collectionManager', function() { - return new Manager(); -}); diff --git a/models/Skins.php b/models/Skins.php deleted file mode 100644 index 07a69cc..0000000 --- a/models/Skins.php +++ /dev/null @@ -1,39 +0,0 @@ -_id; - } - - public function getSource() { - return 'skins'; - } - - /** - * @param string $nickname - * @return bool|Skins - */ - public static function findByNickname($nickname) { - return static::findFirst([ - [ - 'nickname' => mb_convert_case($nickname, MB_CASE_LOWER, ENCODING), - ], - ]); - } - -} diff --git a/public/.htaccess b/public/.htaccess deleted file mode 100644 index 297b8a6..0000000 --- a/public/.htaccess +++ /dev/null @@ -1,7 +0,0 @@ -AddDefaultCharset UTF-8 - - - RewriteEngine On - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L] - \ No newline at end of file diff --git a/public/index.php b/public/index.php deleted file mode 100644 index 3583edf..0000000 --- a/public/index.php +++ /dev/null @@ -1,24 +0,0 @@ -handle(); - -} catch (Phalcon\Exception $e) { - echo $e->getMessage(); -} catch (PDOException $e) { - echo $e->getMessage(); -} From baa1cd3010696bc9564f66c247a4c7d0c1f90019 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Mon, 4 Jul 2016 00:20:41 +0300 Subject: [PATCH 02/17] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D0=B5=D0=BD=D0=B0=20=D0=B8=D0=BC=D0=BF=D0=BB=D0=B5=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BD=D0=B0=20Go,?= =?UTF-8?q?=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=BE=20Docker=20compos?= =?UTF-8?q?e=20=D0=BE=D0=BA=D1=80=D1=83=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + Dockerfile | 15 ++++ data/.gitignore | 2 + docker-compose.yml | 20 +++++ docker/nginx/Dockerfile | 8 ++ docker/nginx/nginx.conf | 31 +++++++ docker/nginx/skinsystem.ely.by.conf | 63 +++++++++++++ nginx.conf | 40 --------- src/main.go | 133 ++++++++++++++++++++++++++++ 9 files changed, 273 insertions(+), 40 deletions(-) create mode 100644 Dockerfile create mode 100644 data/.gitignore create mode 100644 docker-compose.yml create mode 100644 docker/nginx/Dockerfile create mode 100644 docker/nginx/nginx.conf create mode 100644 docker/nginx/skinsystem.ely.by.conf delete mode 100644 nginx.conf create mode 100644 src/main.go diff --git a/.gitignore b/.gitignore index a09c56d..08c26dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +# IDEA /.idea diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2c08e63 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM golang:1.7 + +RUN mkdir -p /go/src/app +WORKDIR /go/src/app + +COPY ./src /go/src/app + +RUN go-wrapper download +RUN go-wrapper install + +EXPOSE 80 + +VOLUME ["/go/src/app"] + +CMD ["go-wrapper", "run"] diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0e31b24 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +version: '2' +services: + app: + build: . + links: + - redis + + web: + build: ./docker/nginx + ports: + - "80:80" + links: + - app + volumes_from: + - app + + redis: + image: redis:3.0 + volumes: + - ./data/:/data diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile new file mode 100644 index 0000000..5440e75 --- /dev/null +++ b/docker/nginx/Dockerfile @@ -0,0 +1,8 @@ +FROM nginx:1.11 + +COPY nginx.conf /etc/nginx/nginx.conf +COPY skinsystem.ely.by.conf /etc/nginx/conf.d/default.conf + +RUN mkdir -p /data/cache \ + /data/logs \ + && chown nginx:nginx -R /data diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf new file mode 100644 index 0000000..dd75a2d --- /dev/null +++ b/docker/nginx/nginx.conf @@ -0,0 +1,31 @@ +user nginx; +worker_processes auto; + +events { + worker_connections 4048; + multi_accept on; + use epoll; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 15; + types_hash_max_size 2048; + server_tokens off; + + access_log /data/logs/access.log combined buffer=32k; + error_log /data/logs/error.log crit; + + gzip off; + + client_max_body_size 1M; + + proxy_cache_path /data/cache levels=1:2 keys_zone=cache:30m max_size=1G; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/docker/nginx/skinsystem.ely.by.conf b/docker/nginx/skinsystem.ely.by.conf new file mode 100644 index 0000000..829ceef --- /dev/null +++ b/docker/nginx/skinsystem.ely.by.conf @@ -0,0 +1,63 @@ +server { + listen 80; + + charset utf-8; + set $root_path '/go/src/app'; + root $root_path; + + proxy_cache_use_stale error timeout invalid_header http_502; + proxy_cache_min_uses 1; + + location / { + proxy_pass http://app; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + + proxy_cache cache; + proxy_cache_valid 30m; + } + + location /minecraft.php { + if ($arg_name = "") { + return 400; + } + + if ($arg_type = "cloack") { + rewrite .* http://skins.minecraft.net/MinecraftCloaks/$arg_name.png? permanent; + break; + } + + if ($arg_type = "skin") { + rewrite .* /skins/$arg_name last; + break; + } + + return 404; + } + + location /cloaks/ { + try_files $uri $uri.png @cloaks; + } + + location @cloaks { + rewrite ^/cloaks/(.+?)(\.[^.]*$|$)$ http://skins.minecraft.net/MinecraftCloaks/$1.png? permanent; + } + + location ~* ^/skins/$ { + if ($arg_name = "") { + return 400; + } + + rewrite .* /skins/$arg_name last; + } + + location ~* ^/cloaks/$ { + if ($arg_name = "") { + return 400; + } + + rewrite .* /cloaks/$arg_name last; + } +} diff --git a/nginx.conf b/nginx.conf deleted file mode 100644 index 2073d57..0000000 --- a/nginx.conf +++ /dev/null @@ -1,40 +0,0 @@ -location /minecraft.php { - if ($arg_name = "") { - return 400; - } - - if ($arg_type = "cloack") { - rewrite .* http://skins.minecraft.net/MinecraftCloaks/$arg_name.png? permanent; - break; - } - - if ($arg_type = "skin") { - rewrite .* /skins/$arg_name last; - } - - return 404; -} - -location /cloaks/ { - try_files $uri $uri.png @cloaks; -} - -location @cloaks { - rewrite ^/cloaks/(.+?)(\.[^.]*$|$)$ http://skins.minecraft.net/MinecraftCloaks/$1.png? permanent; -} - -location ~* ^/skins/$ { - if ($arg_name = "") { - return 400; - } - - rewrite .* /skins/$arg_name permanent; -} - -location ~* ^/cloaks/$ { - if ($arg_name = "") { - return 400; - } - - rewrite .* /cloaks/$arg_name permanent; -} diff --git a/src/main.go b/src/main.go new file mode 100644 index 0000000..1e1406b --- /dev/null +++ b/src/main.go @@ -0,0 +1,133 @@ +package main + +import ( + "log" + "net/http" + + "github.com/gorilla/mux" + "github.com/mediocregopher/radix.v2/redis" + "encoding/json" + "strings" + "time" + "strconv" + "crypto/md5" + "encoding/hex" +) + +var client, redisErr = redis.Dial("tcp", "redis:6379") + +func main() { + if redisErr != nil { + log.Fatal("Redis unavailable") + } + + router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/skins/{username}", GetSkin) + router.HandleFunc("/textures/{username}", GetTextures) + + log.Fatal(http.ListenAndServe(":80", router)) +} + +func GetSkin(w http.ResponseWriter, r *http.Request) { + username := ParseUsername(mux.Vars(r)["username"]) + log.Println("request skin for username " + username); + rec, err := FindRecord(username) + if (err != nil) { + http.Redirect(w, r, "http://skins.minecraft.net/MinecraftSkins/" + username + ".png", 301) + log.Println("Cannot get skin for username " + username) + return + } + + http.Redirect(w, r, rec.Url, 301); +} + +func GetTextures(w http.ResponseWriter, r *http.Request) { + username := ParseUsername(mux.Vars(r)["username"]) + log.Println("request textures for username " + username) + + rec, err := FindRecord(username) + if (err != nil || rec.SkinId == 0) { + rec.Url = "http://skins.minecraft.net/MinecraftSkins/" + username + ".png" + rec.Hash = string(BuildNonElyTexturesHash(username)) + } + + textures := TexturesResponse{ + Skin: &Skin{ + Url: rec.Url, + Hash: rec.Hash, + }, + } + + if (rec.IsSlim) { + textures.Skin.Metadata = &SkinMetadata{ + Model: "slim", + } + } + + response,_ := json.Marshal(textures) + w.Header().Set("Content-Type", "application/json") + w.Write(response) +} + +// STRUCTURES + +type SkinItem struct { + UserId int `json:"userId"` + Nickname string `json:"nickname"` + SkinId int `json:"skinId"` + Url string `json:"url"` + Is1_8 bool `json:"is1_8"` + IsSlim bool `json:"isSlim"` + Hash string `json:"hash"` +} + +type TexturesResponse struct { + Skin *Skin `json:"SKIN"` +} + +type Skin struct { + Url string `json:"url"` + Hash string `json:"hash"` + Metadata *SkinMetadata `json:"metadata,omitempty"` +} + +type SkinMetadata struct { + Model string `json:"model"` +} + +// TOOLS + +func ParseUsername(username string) string { + const suffix = ".png" + if strings.HasSuffix(username, suffix) { + username = strings.TrimSuffix(username, suffix) + } + + return username +} + +func BuildNonElyTexturesHash(username string) string { + n := time.Now() + hour := time.Date(n.Year(), n.Month(), n.Day(), n.Hour(), 0, 0, 0, time.UTC).Unix() + hasher := md5.New() + hasher.Write([]byte("non-ely-" + strconv.FormatInt(hour, 10) + "-" + username)) + + return hex.EncodeToString(hasher.Sum(nil)) +} + +func FindRecord(username string) (SkinItem, error) { + var record SkinItem; + result, err := client.Cmd("GET", BuildKey(username)).Str(); + if (err == nil) { + decodeErr := json.Unmarshal([]byte(result), &record) + if (decodeErr != nil) { + log.Println("Cannot decode record data") + } + } + + return record, err +} + +func BuildKey(username string) string { + return "username:" + strings.ToLower(username) +} From 6a7cc9ae77956ecc29d0b656f5167a12f466e469 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 5 Jul 2016 01:28:09 +0300 Subject: [PATCH 03/17] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B5=D0=BA=D1=82=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=B1=D0=B8=D1=82=20=D0=BD=D0=B0=20=D0=B1?= =?UTF-8?q?=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=BC=D0=B5=D0=BB=D0=BA=D0=B8=D0=B5?= =?UTF-8?q?=20=D1=87=D0=B0=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + Dockerfile | 7 +- lib/routes/Skins.go | 21 +++++ lib/routes/Textures.go | 38 +++++++++ lib/services/services.go | 7 ++ lib/structures/Skin.go | 7 ++ lib/structures/SkinItem.go | 11 +++ lib/structures/SkinMetadata.go | 5 ++ lib/structures/TexturesResponse.go | 5 ++ lib/tools/tools.go | 48 +++++++++++ minecraft-skinsystem.go | 31 +++++++ src/main.go | 133 ----------------------------- 12 files changed, 181 insertions(+), 135 deletions(-) create mode 100644 lib/routes/Skins.go create mode 100644 lib/routes/Textures.go create mode 100644 lib/services/services.go create mode 100644 lib/structures/Skin.go create mode 100644 lib/structures/SkinItem.go create mode 100644 lib/structures/SkinMetadata.go create mode 100644 lib/structures/TexturesResponse.go create mode 100644 lib/tools/tools.go create mode 100644 minecraft-skinsystem.go delete mode 100644 src/main.go diff --git a/.gitignore b/.gitignore index 08c26dc..c153235 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ # IDEA /.idea + +# Docker Compose override file +docker-compose.override.yml diff --git a/Dockerfile b/Dockerfile index 2c08e63..c72d9d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,12 @@ FROM golang:1.7 -RUN mkdir -p /go/src/app +RUN mkdir -p /go/src/elyby/minecraft-skinsystem \ + && ln -s /go/src/elyby/minecraft-skinsystem /go/src/app + WORKDIR /go/src/app -COPY ./src /go/src/app +COPY ./minecraft-skinsystem.go /go/src/app/ +COPY ./lib /go/src/app/lib RUN go-wrapper download RUN go-wrapper install diff --git a/lib/routes/Skins.go b/lib/routes/Skins.go new file mode 100644 index 0000000..fd8eb6c --- /dev/null +++ b/lib/routes/Skins.go @@ -0,0 +1,21 @@ +package routes + +import ( + "net/http" + "github.com/gorilla/mux" + "log" + "elyby/minecraft-skinsystem/lib/tools" +) + +func GetSkin(w http.ResponseWriter, r *http.Request) { + username := tools.ParseUsername(mux.Vars(r)["username"]) + log.Println("request skin for username " + username); + rec, err := tools.FindRecord(username) + if (err != nil) { + http.Redirect(w, r, "http://skins.minecraft.net/MinecraftSkins/" + username + ".png", 301) + log.Println("Cannot get skin for username " + username) + return + } + + http.Redirect(w, r, rec.Url, 301); +} diff --git a/lib/routes/Textures.go b/lib/routes/Textures.go new file mode 100644 index 0000000..36fbf6c --- /dev/null +++ b/lib/routes/Textures.go @@ -0,0 +1,38 @@ +package routes + +import ( + "net/http" + "github.com/gorilla/mux" + "log" + "elyby/minecraft-skinsystem/lib/structures" + "encoding/json" + "elyby/minecraft-skinsystem/lib/tools" +) + +func GetTextures(w http.ResponseWriter, r *http.Request) { + username := tools.ParseUsername(mux.Vars(r)["username"]) + log.Println("request textures for username " + username) + + rec, err := tools.FindRecord(username) + if (err != nil || rec.SkinId == 0) { + rec.Url = "http://skins.minecraft.net/MinecraftSkins/" + username + ".png" + rec.Hash = string(tools.BuildNonElyTexturesHash(username)) + } + + textures := structures.TexturesResponse{ + Skin: &structures.Skin{ + Url: rec.Url, + Hash: rec.Hash, + }, + } + + if (rec.IsSlim) { + textures.Skin.Metadata = &structures.SkinMetadata{ + Model: "slim", + } + } + + 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 new file mode 100644 index 0000000..6f0421b --- /dev/null +++ b/lib/services/services.go @@ -0,0 +1,7 @@ +package services + +import ( + "github.com/mediocregopher/radix.v2/redis" +) + +var Redis *redis.Client diff --git a/lib/structures/Skin.go b/lib/structures/Skin.go new file mode 100644 index 0000000..93ee16e --- /dev/null +++ b/lib/structures/Skin.go @@ -0,0 +1,7 @@ +package structures + +type Skin struct { + Url string `json:"url"` + Hash string `json:"hash"` + Metadata *SkinMetadata `json:"metadata,omitempty"` +} diff --git a/lib/structures/SkinItem.go b/lib/structures/SkinItem.go new file mode 100644 index 0000000..8877975 --- /dev/null +++ b/lib/structures/SkinItem.go @@ -0,0 +1,11 @@ +package structures + +type SkinItem struct { + UserId int `json:"userId"` + Nickname string `json:"nickname"` + SkinId int `json:"skinId"` + Url string `json:"url"` + Is1_8 bool `json:"is1_8"` + IsSlim bool `json:"isSlim"` + Hash string `json:"hash"` +} diff --git a/lib/structures/SkinMetadata.go b/lib/structures/SkinMetadata.go new file mode 100644 index 0000000..31afd0d --- /dev/null +++ b/lib/structures/SkinMetadata.go @@ -0,0 +1,5 @@ +package structures + +type SkinMetadata struct { + Model string `json:"model"` +} diff --git a/lib/structures/TexturesResponse.go b/lib/structures/TexturesResponse.go new file mode 100644 index 0000000..687d53a --- /dev/null +++ b/lib/structures/TexturesResponse.go @@ -0,0 +1,5 @@ +package structures + +type TexturesResponse struct { + Skin *Skin `json:"SKIN"` +} diff --git a/lib/tools/tools.go b/lib/tools/tools.go new file mode 100644 index 0000000..2c0ff10 --- /dev/null +++ b/lib/tools/tools.go @@ -0,0 +1,48 @@ +package tools + +import ( + "strings" + "time" + "crypto/md5" + "strconv" + "encoding/hex" + "elyby/minecraft-skinsystem/lib/structures" + "elyby/minecraft-skinsystem/lib/services" + "encoding/json" + "log" +) + +func ParseUsername(username string) string { + const suffix = ".png" + if strings.HasSuffix(username, suffix) { + username = strings.TrimSuffix(username, suffix) + } + + return username +} + +func BuildNonElyTexturesHash(username string) string { + n := time.Now() + hour := time.Date(n.Year(), n.Month(), n.Day(), n.Hour(), 0, 0, 0, time.UTC).Unix() + hasher := md5.New() + hasher.Write([]byte("non-ely-" + strconv.FormatInt(hour, 10) + "-" + username)) + + return hex.EncodeToString(hasher.Sum(nil)) +} + +func FindRecord(username string) (structures.SkinItem, error) { + var record structures.SkinItem; + result, err := services.Redis.Cmd("GET", BuildKey(username)).Str(); + if (err == nil) { + decodeErr := json.Unmarshal([]byte(result), &record) + if (decodeErr != nil) { + log.Println("Cannot decode record data") + } + } + + return record, err +} + +func BuildKey(username string) string { + return "username:" + strings.ToLower(username) +} diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go new file mode 100644 index 0000000..662fe5d --- /dev/null +++ b/minecraft-skinsystem.go @@ -0,0 +1,31 @@ +package main + +import ( + "log" + "net/http" + + "github.com/gorilla/mux" + "github.com/mediocregopher/radix.v2/redis" + + "elyby/minecraft-skinsystem/lib/routes" + "elyby/minecraft-skinsystem/lib/services" +) + +var client, redisErr = redis.Dial("tcp", "redis:6379") + +func main() { + if redisErr != nil { + log.Fatal("Redis unavailable") + } + + services.Redis = client + + router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/skins/{username}", routes.GetSkin) + router.HandleFunc("/textures/{username}", routes.GetTextures) + router.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) { + w.Write([]byte("Hello")) + }) + + log.Fatal(http.ListenAndServe(":80", router)) +} diff --git a/src/main.go b/src/main.go deleted file mode 100644 index 1e1406b..0000000 --- a/src/main.go +++ /dev/null @@ -1,133 +0,0 @@ -package main - -import ( - "log" - "net/http" - - "github.com/gorilla/mux" - "github.com/mediocregopher/radix.v2/redis" - "encoding/json" - "strings" - "time" - "strconv" - "crypto/md5" - "encoding/hex" -) - -var client, redisErr = redis.Dial("tcp", "redis:6379") - -func main() { - if redisErr != nil { - log.Fatal("Redis unavailable") - } - - router := mux.NewRouter().StrictSlash(true) - router.HandleFunc("/skins/{username}", GetSkin) - router.HandleFunc("/textures/{username}", GetTextures) - - log.Fatal(http.ListenAndServe(":80", router)) -} - -func GetSkin(w http.ResponseWriter, r *http.Request) { - username := ParseUsername(mux.Vars(r)["username"]) - log.Println("request skin for username " + username); - rec, err := FindRecord(username) - if (err != nil) { - http.Redirect(w, r, "http://skins.minecraft.net/MinecraftSkins/" + username + ".png", 301) - log.Println("Cannot get skin for username " + username) - return - } - - http.Redirect(w, r, rec.Url, 301); -} - -func GetTextures(w http.ResponseWriter, r *http.Request) { - username := ParseUsername(mux.Vars(r)["username"]) - log.Println("request textures for username " + username) - - rec, err := FindRecord(username) - if (err != nil || rec.SkinId == 0) { - rec.Url = "http://skins.minecraft.net/MinecraftSkins/" + username + ".png" - rec.Hash = string(BuildNonElyTexturesHash(username)) - } - - textures := TexturesResponse{ - Skin: &Skin{ - Url: rec.Url, - Hash: rec.Hash, - }, - } - - if (rec.IsSlim) { - textures.Skin.Metadata = &SkinMetadata{ - Model: "slim", - } - } - - response,_ := json.Marshal(textures) - w.Header().Set("Content-Type", "application/json") - w.Write(response) -} - -// STRUCTURES - -type SkinItem struct { - UserId int `json:"userId"` - Nickname string `json:"nickname"` - SkinId int `json:"skinId"` - Url string `json:"url"` - Is1_8 bool `json:"is1_8"` - IsSlim bool `json:"isSlim"` - Hash string `json:"hash"` -} - -type TexturesResponse struct { - Skin *Skin `json:"SKIN"` -} - -type Skin struct { - Url string `json:"url"` - Hash string `json:"hash"` - Metadata *SkinMetadata `json:"metadata,omitempty"` -} - -type SkinMetadata struct { - Model string `json:"model"` -} - -// TOOLS - -func ParseUsername(username string) string { - const suffix = ".png" - if strings.HasSuffix(username, suffix) { - username = strings.TrimSuffix(username, suffix) - } - - return username -} - -func BuildNonElyTexturesHash(username string) string { - n := time.Now() - hour := time.Date(n.Year(), n.Month(), n.Day(), n.Hour(), 0, 0, 0, time.UTC).Unix() - hasher := md5.New() - hasher.Write([]byte("non-ely-" + strconv.FormatInt(hour, 10) + "-" + username)) - - return hex.EncodeToString(hasher.Sum(nil)) -} - -func FindRecord(username string) (SkinItem, error) { - var record SkinItem; - result, err := client.Cmd("GET", BuildKey(username)).Str(); - if (err == nil) { - decodeErr := json.Unmarshal([]byte(result), &record) - if (decodeErr != nil) { - log.Println("Cannot decode record data") - } - } - - return record, err -} - -func BuildKey(username string) string { - return "username:" + strings.ToLower(username) -} From 87ca1191eb34995d4822ab3de7b393d24e079ced Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 5 Jul 2016 01:42:58 +0300 Subject: [PATCH 04/17] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D0=BE=D0=B5?= =?UTF-8?q?=20Readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..77e7af0 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# Это заготовка для нормального файла + +Для настройки Dev-окружения нужно склонировать проект в удобное место, +за тем сделать символьную ссылку в свой GOPATH: + +```sh +# Выполнять, находясь внутри директории репозитория +mkdir -p $GOPATH/src/elyby +ln -s $PWD $GOPATH/src/elyby/minecraft-skinsystem +``` + +Или можно склонировать репозиторий сразу в нужную локацию: + +```sh +git clone git@bitbucket.org:elyby/minecraft-skinsystem.git $GOPATH/src/elyby/minecraft-skinsystem +``` + +Поднять репозиторий можно командой: + +```sh +docker-compose up -d +``` + +Рекомендуемый файл `docker-compose.override.yml` для dev-окружения: + +```sh +version: '2' +services: + app: + volumes: + - ./:/go/src/app + command: ["go", "run", "minecraft-skinsystem.go"] +``` + +В таком случае, для перезапуска контейнера (при условии, что не появляется +новых зависимостей) будет достаточно выполнить только одну команду: + +```sh +docker-compose restart app +``` + +Если нужно пересобрать весь контейнер, то выполняем следующее: + +``` +docker-compose stop app # Останавливаем конейтнер, если он ещё работает +docker-compose rm -f app # Удаляем конейтнер +docker-compose build app # Запускаем билд по новой +docker-compose up -d app # Поднимаем свежесобранный контейнер обратно +``` From c4cd95cddc14cf93451fed273ae79da7ea27c07d Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 6 Jul 2016 01:25:05 +0300 Subject: [PATCH 05/17] =?UTF-8?q?=D0=9D=D0=B5=D0=BC=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=80=D0=B5=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83?= =?UTF-8?q?=D1=80=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D1=80=D0=BE=D1=83=D1=82=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BC=D0=B5=D0=BD=D1=8B=20=D1=81?= =?UTF-8?q?=D0=BA=D0=B8=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/SkinItem.go | 37 ++++++++++++++++++++++++++++++ lib/data/TexturesResponse.go | 15 ++++++++++++ lib/routes/SetSkin.go | 30 ++++++++++++++++++++++++ lib/routes/{Skins.go => Skin.go} | 11 +++++---- lib/routes/Textures.go | 18 ++++++++------- lib/structures/Skin.go | 7 ------ lib/structures/SkinItem.go | 11 --------- lib/structures/SkinMetadata.go | 5 ---- lib/structures/TexturesResponse.go | 5 ---- lib/tools/tools.go | 17 -------------- lib/tools/tools_test.go | 22 ++++++++++++++++++ minecraft-skinsystem.go | 11 +++++---- 12 files changed, 127 insertions(+), 62 deletions(-) create mode 100644 lib/data/SkinItem.go create mode 100644 lib/data/TexturesResponse.go create mode 100644 lib/routes/SetSkin.go rename lib/routes/{Skins.go => Skin.go} (77%) delete mode 100644 lib/structures/Skin.go delete mode 100644 lib/structures/SkinItem.go delete mode 100644 lib/structures/SkinMetadata.go delete mode 100644 lib/structures/TexturesResponse.go create mode 100644 lib/tools/tools_test.go diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go new file mode 100644 index 0000000..3916ccd --- /dev/null +++ b/lib/data/SkinItem.go @@ -0,0 +1,37 @@ +package data + +import ( + "log" + "encoding/json" + + "elyby/minecraft-skinsystem/lib/services" + "elyby/minecraft-skinsystem/lib/tools" +) + +type SkinItem struct { + UserId int `json:"userId"` + Nickname string `json:"nickname"` + SkinId int `json:"skinId"` + Url string `json:"url"` + Is1_8 bool `json:"is1_8"` + IsSlim bool `json:"isSlim"` + Hash string `json:"hash"` +} + +func (s *SkinItem) Save() { + str, _ := json.Marshal(s) + services.Redis.Cmd("SET", tools.BuildKey(s.Nickname), str) +} + +func FindRecord(username string) (SkinItem, error) { + var record SkinItem; + result, err := services.Redis.Cmd("GET", tools.BuildKey(username)).Str(); + if (err == nil) { + decodeErr := json.Unmarshal([]byte(result), &record) + if (decodeErr != nil) { + log.Println("Cannot decode record data") + } + } + + return record, err +} diff --git a/lib/data/TexturesResponse.go b/lib/data/TexturesResponse.go new file mode 100644 index 0000000..4716a21 --- /dev/null +++ b/lib/data/TexturesResponse.go @@ -0,0 +1,15 @@ +package data + +type TexturesResponse struct { + Skin *Skin `json:"SKIN"` +} + +type Skin struct { + Url string `json:"url"` + Hash string `json:"hash"` + Metadata *SkinMetadata `json:"metadata,omitempty"` +} + +type SkinMetadata struct { + Model string `json:"model"` +} diff --git a/lib/routes/SetSkin.go b/lib/routes/SetSkin.go new file mode 100644 index 0000000..897e4c6 --- /dev/null +++ b/lib/routes/SetSkin.go @@ -0,0 +1,30 @@ +package routes + +import ( + "net/http" + "strings" + "strconv" + + "elyby/minecraft-skinsystem/lib/data" +) + +func SetSkin(w http.ResponseWriter, r *http.Request) { + key := r.Header.Get("X-Ely-key") + if key != "43fd2ce61b3f5704dfd729c1f2d6ffdb" { + w.WriteHeader(http.StatusForbidden) + w.Write([]byte("Nice try")) + return + } + + skin := new(data.SkinItem) + skin.Nickname = strings.ToLower(r.PostFormValue("nickname")) + skin.UserId, _ = strconv.Atoi(r.PostFormValue("userId")) + skin.SkinId, _ = strconv.Atoi(r.PostFormValue("skinId")) + skin.Hash = r.PostFormValue("hash") + skin.Is1_8, _ = strconv.ParseBool(r.PostFormValue("is1_8")) + skin.IsSlim, _ = strconv.ParseBool(r.PostFormValue("isSlim")) + skin.Url = r.PostFormValue("url") + skin.Save() + + w.Write([]byte("OK")) +} diff --git a/lib/routes/Skins.go b/lib/routes/Skin.go similarity index 77% rename from lib/routes/Skins.go rename to lib/routes/Skin.go index fd8eb6c..161ea8f 100644 --- a/lib/routes/Skins.go +++ b/lib/routes/Skin.go @@ -1,16 +1,19 @@ package routes import ( - "net/http" - "github.com/gorilla/mux" "log" + "net/http" + + "github.com/gorilla/mux" + "elyby/minecraft-skinsystem/lib/tools" + "elyby/minecraft-skinsystem/lib/data" ) -func GetSkin(w http.ResponseWriter, r *http.Request) { +func Skin(w http.ResponseWriter, r *http.Request) { username := tools.ParseUsername(mux.Vars(r)["username"]) log.Println("request skin for username " + username); - rec, err := tools.FindRecord(username) + rec, err := data.FindRecord(username) if (err != nil) { http.Redirect(w, r, "http://skins.minecraft.net/MinecraftSkins/" + username + ".png", 301) log.Println("Cannot get skin for username " + username) diff --git a/lib/routes/Textures.go b/lib/routes/Textures.go index 36fbf6c..72ac663 100644 --- a/lib/routes/Textures.go +++ b/lib/routes/Textures.go @@ -1,33 +1,35 @@ package routes import ( - "net/http" - "github.com/gorilla/mux" "log" - "elyby/minecraft-skinsystem/lib/structures" + "net/http" "encoding/json" + + "github.com/gorilla/mux" + + "elyby/minecraft-skinsystem/lib/data" "elyby/minecraft-skinsystem/lib/tools" ) -func GetTextures(w http.ResponseWriter, r *http.Request) { +func Textures(w http.ResponseWriter, r *http.Request) { username := tools.ParseUsername(mux.Vars(r)["username"]) log.Println("request textures for username " + username) - rec, err := tools.FindRecord(username) + rec, err := data.FindRecord(username) if (err != nil || rec.SkinId == 0) { rec.Url = "http://skins.minecraft.net/MinecraftSkins/" + username + ".png" rec.Hash = string(tools.BuildNonElyTexturesHash(username)) } - textures := structures.TexturesResponse{ - Skin: &structures.Skin{ + textures := data.TexturesResponse{ + Skin: &data.Skin{ Url: rec.Url, Hash: rec.Hash, }, } if (rec.IsSlim) { - textures.Skin.Metadata = &structures.SkinMetadata{ + textures.Skin.Metadata = &data.SkinMetadata{ Model: "slim", } } diff --git a/lib/structures/Skin.go b/lib/structures/Skin.go deleted file mode 100644 index 93ee16e..0000000 --- a/lib/structures/Skin.go +++ /dev/null @@ -1,7 +0,0 @@ -package structures - -type Skin struct { - Url string `json:"url"` - Hash string `json:"hash"` - Metadata *SkinMetadata `json:"metadata,omitempty"` -} diff --git a/lib/structures/SkinItem.go b/lib/structures/SkinItem.go deleted file mode 100644 index 8877975..0000000 --- a/lib/structures/SkinItem.go +++ /dev/null @@ -1,11 +0,0 @@ -package structures - -type SkinItem struct { - UserId int `json:"userId"` - Nickname string `json:"nickname"` - SkinId int `json:"skinId"` - Url string `json:"url"` - Is1_8 bool `json:"is1_8"` - IsSlim bool `json:"isSlim"` - Hash string `json:"hash"` -} diff --git a/lib/structures/SkinMetadata.go b/lib/structures/SkinMetadata.go deleted file mode 100644 index 31afd0d..0000000 --- a/lib/structures/SkinMetadata.go +++ /dev/null @@ -1,5 +0,0 @@ -package structures - -type SkinMetadata struct { - Model string `json:"model"` -} diff --git a/lib/structures/TexturesResponse.go b/lib/structures/TexturesResponse.go deleted file mode 100644 index 687d53a..0000000 --- a/lib/structures/TexturesResponse.go +++ /dev/null @@ -1,5 +0,0 @@ -package structures - -type TexturesResponse struct { - Skin *Skin `json:"SKIN"` -} diff --git a/lib/tools/tools.go b/lib/tools/tools.go index 2c0ff10..6268c21 100644 --- a/lib/tools/tools.go +++ b/lib/tools/tools.go @@ -6,10 +6,6 @@ import ( "crypto/md5" "strconv" "encoding/hex" - "elyby/minecraft-skinsystem/lib/structures" - "elyby/minecraft-skinsystem/lib/services" - "encoding/json" - "log" ) func ParseUsername(username string) string { @@ -30,19 +26,6 @@ func BuildNonElyTexturesHash(username string) string { return hex.EncodeToString(hasher.Sum(nil)) } -func FindRecord(username string) (structures.SkinItem, error) { - var record structures.SkinItem; - result, err := services.Redis.Cmd("GET", BuildKey(username)).Str(); - if (err == nil) { - decodeErr := json.Unmarshal([]byte(result), &record) - if (decodeErr != nil) { - log.Println("Cannot decode record data") - } - } - - return record, err -} - func BuildKey(username string) string { return "username:" + strings.ToLower(username) } diff --git a/lib/tools/tools_test.go b/lib/tools/tools_test.go new file mode 100644 index 0000000..54b49f1 --- /dev/null +++ b/lib/tools/tools_test.go @@ -0,0 +1,22 @@ +package tools_test + +import ( + "testing" + . "elyby/minecraft-skinsystem/lib/tools" +) + +func TestParseUsername(t *testing.T) { + if ParseUsername("test.png") != "test" { + t.Error("Function should trim .png at end") + } + + if ParseUsername("test") != "test" { + t.Error("Function should return string itself, if it not contains .png at end") + } +} + +func TestBuildKey(t *testing.T) { + if BuildKey("Test") != "username:test" { + t.Error("Function shound convert string to lover case and concatenate it with usernmae:") + } +} diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 662fe5d..3946b1b 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -21,11 +21,12 @@ func main() { services.Redis = client router := mux.NewRouter().StrictSlash(true) - router.HandleFunc("/skins/{username}", routes.GetSkin) - router.HandleFunc("/textures/{username}", routes.GetTextures) - router.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) { - w.Write([]byte("Hello")) - }) + router.HandleFunc("/skins/{username}", routes.Skin).Methods("GET") + router.HandleFunc("/textures/{username}", routes.Textures).Methods("GET") + router.HandleFunc("/system/setSkin", routes.SetSkin).Methods("POST") // TODO: убрать этого, т.к. он стар + + apiRouter := router.PathPrefix("/api").Subrouter() + apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") log.Fatal(http.ListenAndServe(":80", router)) } From 3d65529d2e668b212ea7949dd23c2ee72efdf2de Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 6 Jul 2016 14:45:14 +0300 Subject: [PATCH 06/17] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=87?= =?UTF-8?q?=D0=B8=D0=BA=20NotFound=20=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D0=BF=D0=B5=D1=87=D0=B0=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=B2=20=D1=82=D0=B5=D1=81=D1=82=D0=B5=20=D0=A0?= =?UTF-8?q?=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3=D0=B8=D0=BA=D0=B0=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?=20BuildNonElyTexturesHash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/routes/NotFound.go | 18 ++++++++++++++++++ lib/tools/tools.go | 8 ++++++-- lib/tools/tools_test.go | 2 +- minecraft-skinsystem.go | 1 + 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 lib/routes/NotFound.go diff --git a/lib/routes/NotFound.go b/lib/routes/NotFound.go new file mode 100644 index 0000000..8460956 --- /dev/null +++ b/lib/routes/NotFound.go @@ -0,0 +1,18 @@ +package routes + +import ( + "net/http" + "encoding/json" +) + +func NotFound(w http.ResponseWriter, r *http.Request) { + json, _ := json.Marshal(map[string]string{ + "status": "404", + "message": "Not Found", + "link": "http://docs.ely.by", + }) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + w.Write(json) +} diff --git a/lib/tools/tools.go b/lib/tools/tools.go index 6268c21..0814856 100644 --- a/lib/tools/tools.go +++ b/lib/tools/tools.go @@ -18,8 +18,7 @@ func ParseUsername(username string) string { } func BuildNonElyTexturesHash(username string) string { - n := time.Now() - hour := time.Date(n.Year(), n.Month(), n.Day(), n.Hour(), 0, 0, 0, time.UTC).Unix() + hour := getCurrentHour() hasher := md5.New() hasher.Write([]byte("non-ely-" + strconv.FormatInt(hour, 10) + "-" + username)) @@ -29,3 +28,8 @@ func BuildNonElyTexturesHash(username string) string { func BuildKey(username string) string { return "username:" + strings.ToLower(username) } + +func getCurrentHour() int64 { + n := time.Now() + return time.Date(n.Year(), n.Month(), n.Day(), n.Hour(), 0, 0, 0, time.UTC).Unix() +} diff --git a/lib/tools/tools_test.go b/lib/tools/tools_test.go index 54b49f1..bf7b7f1 100644 --- a/lib/tools/tools_test.go +++ b/lib/tools/tools_test.go @@ -17,6 +17,6 @@ func TestParseUsername(t *testing.T) { func TestBuildKey(t *testing.T) { if BuildKey("Test") != "username:test" { - t.Error("Function shound convert string to lover case and concatenate it with usernmae:") + t.Error("Function shound convert string to lower case and concatenate it with usernmae:") } } diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 3946b1b..64f03ca 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -21,6 +21,7 @@ func main() { services.Redis = client router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/", routes.NotFound) router.HandleFunc("/skins/{username}", routes.Skin).Methods("GET") router.HandleFunc("/textures/{username}", routes.Textures).Methods("GET") router.HandleFunc("/system/setSkin", routes.SetSkin).Methods("POST") // TODO: убрать этого, т.к. он стар From 2b8266b2244e487c88b0c1bbeaec0122014492e8 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Thu, 7 Jul 2016 00:43:42 +0300 Subject: [PATCH 07/17] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=83=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20GOMAXPROCS=20=D0=A1=D0=B5=D1=80=D0=B2=D0=B8=D1=81=20=D1=80?= =?UTF-8?q?=D0=BE=D1=83=D1=82=D0=B5=D1=80=D0=B0=20=D0=B2=D1=8B=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D0=B5=D0=BD=20=D0=B2=20=D0=B3=D0=BB=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/services/services.go | 3 +++ minecraft-skinsystem.go | 18 +++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/services/services.go b/lib/services/services.go index 6f0421b..d62f7ac 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -2,6 +2,9 @@ package services import ( "github.com/mediocregopher/radix.v2/redis" + "github.com/gorilla/mux" ) var Redis *redis.Client + +var Router *mux.Router diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 64f03ca..c4ac5e0 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -2,6 +2,7 @@ package main import ( "log" + "runtime" "net/http" "github.com/gorilla/mux" @@ -11,23 +12,26 @@ import ( "elyby/minecraft-skinsystem/lib/services" ) -var client, redisErr = redis.Dial("tcp", "redis:6379") - func main() { + runtime.GOMAXPROCS(runtime.NumCPU()) + + client, redisErr := redis.Dial("tcp", "redis:6379") if redisErr != nil { log.Fatal("Redis unavailable") } - services.Redis = client - router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", routes.NotFound) - router.HandleFunc("/skins/{username}", routes.Skin).Methods("GET") - router.HandleFunc("/textures/{username}", routes.Textures).Methods("GET") - router.HandleFunc("/system/setSkin", routes.SetSkin).Methods("POST") // TODO: убрать этого, т.к. он стар + router.HandleFunc("/skins/{username}", routes.Skin).Methods("GET").Name("skins") + router.HandleFunc("/textures/{username}", routes.Textures).Methods("GET").Name("textures") + // TODO: убрать этого, т.к. он стар + router.HandleFunc("/system/setSkin", routes.SetSkin).Methods("POST") apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") + services.Redis = client + services.Router = router + log.Fatal(http.ListenAndServe(":80", router)) } From e3f744ed10cc216f586420a90823de8e410160fb Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Thu, 7 Jul 2016 00:46:32 +0300 Subject: [PATCH 08/17] =?UTF-8?q?Nginx=20=D1=83=D0=B4=D0=B0=D0=BB=D1=91?= =?UTF-8?q?=D0=BD=20=D0=B7=D0=B0=20=D1=81=D0=B2=D0=BE=D0=B5=D0=B9=20=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=D0=B4=D0=BE=D0=B1=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 7 ---- docker/nginx/Dockerfile | 8 ---- docker/nginx/nginx.conf | 31 -------------- docker/nginx/skinsystem.ely.by.conf | 63 ----------------------------- 4 files changed, 109 deletions(-) delete mode 100644 docker/nginx/Dockerfile delete mode 100644 docker/nginx/nginx.conf delete mode 100644 docker/nginx/skinsystem.ely.by.conf diff --git a/docker-compose.yml b/docker-compose.yml index 0e31b24..99380c2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,15 +4,8 @@ services: build: . links: - redis - - web: - build: ./docker/nginx ports: - "80:80" - links: - - app - volumes_from: - - app redis: image: redis:3.0 diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile deleted file mode 100644 index 5440e75..0000000 --- a/docker/nginx/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM nginx:1.11 - -COPY nginx.conf /etc/nginx/nginx.conf -COPY skinsystem.ely.by.conf /etc/nginx/conf.d/default.conf - -RUN mkdir -p /data/cache \ - /data/logs \ - && chown nginx:nginx -R /data diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf deleted file mode 100644 index dd75a2d..0000000 --- a/docker/nginx/nginx.conf +++ /dev/null @@ -1,31 +0,0 @@ -user nginx; -worker_processes auto; - -events { - worker_connections 4048; - multi_accept on; - use epoll; -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 15; - types_hash_max_size 2048; - server_tokens off; - - access_log /data/logs/access.log combined buffer=32k; - error_log /data/logs/error.log crit; - - gzip off; - - client_max_body_size 1M; - - proxy_cache_path /data/cache levels=1:2 keys_zone=cache:30m max_size=1G; - - include /etc/nginx/conf.d/*.conf; -} diff --git a/docker/nginx/skinsystem.ely.by.conf b/docker/nginx/skinsystem.ely.by.conf deleted file mode 100644 index 829ceef..0000000 --- a/docker/nginx/skinsystem.ely.by.conf +++ /dev/null @@ -1,63 +0,0 @@ -server { - listen 80; - - charset utf-8; - set $root_path '/go/src/app'; - root $root_path; - - proxy_cache_use_stale error timeout invalid_header http_502; - proxy_cache_min_uses 1; - - location / { - proxy_pass http://app; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Real-IP $remote_addr; - - proxy_cache cache; - proxy_cache_valid 30m; - } - - location /minecraft.php { - if ($arg_name = "") { - return 400; - } - - if ($arg_type = "cloack") { - rewrite .* http://skins.minecraft.net/MinecraftCloaks/$arg_name.png? permanent; - break; - } - - if ($arg_type = "skin") { - rewrite .* /skins/$arg_name last; - break; - } - - return 404; - } - - location /cloaks/ { - try_files $uri $uri.png @cloaks; - } - - location @cloaks { - rewrite ^/cloaks/(.+?)(\.[^.]*$|$)$ http://skins.minecraft.net/MinecraftCloaks/$1.png? permanent; - } - - location ~* ^/skins/$ { - if ($arg_name = "") { - return 400; - } - - rewrite .* /skins/$arg_name last; - } - - location ~* ^/cloaks/$ { - if ($arg_name = "") { - return 400; - } - - rewrite .* /cloaks/$arg_name last; - } -} From 4da7a566f73d07866dde5c26e5b97d40ec02a350 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Thu, 7 Jul 2016 13:10:39 +0300 Subject: [PATCH 09/17] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D1=87=D0=B8=D0=BA=D0=B8=20=D0=B4=D0=BB=D1=8F=20Legacy=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/routes/Cape.go | 25 +++++++++++++++++++++++++ lib/routes/MinecraftPHP.go | 28 ++++++++++++++++++++++++++++ lib/routes/Skin.go | 11 +++++++++++ minecraft-skinsystem.go | 6 ++++++ 4 files changed, 70 insertions(+) create mode 100644 lib/routes/Cape.go create mode 100644 lib/routes/MinecraftPHP.go diff --git a/lib/routes/Cape.go b/lib/routes/Cape.go new file mode 100644 index 0000000..ff58a28 --- /dev/null +++ b/lib/routes/Cape.go @@ -0,0 +1,25 @@ +package routes + +import ( + "net/http" + + "github.com/gorilla/mux" + + "elyby/minecraft-skinsystem/lib/tools" +) + +func Cape(w http.ResponseWriter, r *http.Request) { + username := tools.ParseUsername(mux.Vars(r)["username"]) + http.Redirect(w, r, "http://skins.minecraft.net/MinecraftCloaks/" + username + ".png", 301) +} + +func CapeGET(w http.ResponseWriter, r *http.Request) { + username := r.URL.Query().Get("name") + if username == "" { + w.WriteHeader(http.StatusBadRequest) + return + } + + mux.Vars(r)["username"] = username + Cape(w, r) +} diff --git a/lib/routes/MinecraftPHP.go b/lib/routes/MinecraftPHP.go new file mode 100644 index 0000000..3457662 --- /dev/null +++ b/lib/routes/MinecraftPHP.go @@ -0,0 +1,28 @@ +package routes + +import ( + "net/http" + + "github.com/gorilla/mux" +) + +// Метод-наследие от первой версии системы скинов. +// Всё ещё иногда используется +// Просто конвертируем данные и отправляем их в основной обработчик +func MinecraftPHP(w http.ResponseWriter, r *http.Request) { + username := r.URL.Query().Get("name") + required := r.URL.Query().Get("type") + if username == "" || required == "" { + w.WriteHeader(http.StatusBadRequest) + return + } + + mux.Vars(r)["username"] = username + switch required { + case "skin": Skin(w, r) + case "cloack": Cape(w, r) + default: { + w.WriteHeader(http.StatusNotFound) + } + } +} diff --git a/lib/routes/Skin.go b/lib/routes/Skin.go index 161ea8f..9fed97d 100644 --- a/lib/routes/Skin.go +++ b/lib/routes/Skin.go @@ -22,3 +22,14 @@ func Skin(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, rec.Url, 301); } + +func SkinGET(w http.ResponseWriter, r *http.Request) { + username := r.URL.Query().Get("name") + if username == "" { + w.WriteHeader(http.StatusBadRequest) + return + } + + mux.Vars(r)["username"] = username + Skin(w, r) +} diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index c4ac5e0..0090ff5 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -23,7 +23,13 @@ func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", routes.NotFound) router.HandleFunc("/skins/{username}", routes.Skin).Methods("GET").Name("skins") + router.HandleFunc("/cloaks/{username}", routes.Cape).Methods("GET").Name("cloaks") router.HandleFunc("/textures/{username}", routes.Textures).Methods("GET").Name("textures") + // Legacy + router.HandleFunc("/minecraft.php", routes.MinecraftPHP).Methods("GET") + router.HandleFunc("/skins/", routes.SkinGET).Methods("GET") + router.HandleFunc("/cloaks/", routes.CapeGET).Methods("GET") + // TODO: убрать этого, т.к. он стар router.HandleFunc("/system/setSkin", routes.SetSkin).Methods("POST") From 915c46522445eb721af9eb62ff5d1b649a30f07c Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Thu, 7 Jul 2016 22:01:45 +0300 Subject: [PATCH 10/17] =?UTF-8?q?=D0=9E=D1=82=D0=BD=D1=8B=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=BC=D1=8B=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83?= =?UTF-8?q?=D0=B5=D0=BC=20=D0=BF=D1=83=D0=BB=20=D1=81=D0=BE=D0=B5=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B4=D0=B8=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/SkinItem.go | 4 ++-- lib/services/services.go | 4 ++-- minecraft-skinsystem.go | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go index 3916ccd..ae0de56 100644 --- a/lib/data/SkinItem.go +++ b/lib/data/SkinItem.go @@ -20,12 +20,12 @@ type SkinItem struct { func (s *SkinItem) Save() { str, _ := json.Marshal(s) - services.Redis.Cmd("SET", tools.BuildKey(s.Nickname), str) + services.RedisPool.Cmd("SET", tools.BuildKey(s.Nickname), str) } func FindRecord(username string) (SkinItem, error) { var record SkinItem; - result, err := services.Redis.Cmd("GET", tools.BuildKey(username)).Str(); + result, err := services.RedisPool.Cmd("GET", tools.BuildKey(username)).Str(); if (err == nil) { decodeErr := json.Unmarshal([]byte(result), &record) if (decodeErr != nil) { diff --git a/lib/services/services.go b/lib/services/services.go index d62f7ac..f0f612d 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -1,10 +1,10 @@ package services import ( - "github.com/mediocregopher/radix.v2/redis" + "github.com/mediocregopher/radix.v2/pool" "github.com/gorilla/mux" ) -var Redis *redis.Client +var RedisPool *pool.Pool var Router *mux.Router diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 0090ff5..b1bf97f 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -6,7 +6,7 @@ import ( "net/http" "github.com/gorilla/mux" - "github.com/mediocregopher/radix.v2/redis" + "github.com/mediocregopher/radix.v2/pool" "elyby/minecraft-skinsystem/lib/routes" "elyby/minecraft-skinsystem/lib/services" @@ -15,7 +15,7 @@ import ( func main() { runtime.GOMAXPROCS(runtime.NumCPU()) - client, redisErr := redis.Dial("tcp", "redis:6379") + pool, redisErr := pool.New("tcp", "redis:6379", 10) if redisErr != nil { log.Fatal("Redis unavailable") } @@ -36,7 +36,7 @@ func main() { apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") - services.Redis = client + services.RedisPool = pool services.Router = router log.Fatal(http.ListenAndServe(":80", router)) From 283f4e0e3f3adc612ebe1ce7488ffebc1a25df8e Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Thu, 7 Jul 2016 23:41:21 +0300 Subject: [PATCH 11/17] =?UTF-8?q?=D0=9E=D1=82=D0=BD=D1=8B=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=BC=D1=8B=20=D0=BD=D0=B5=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D1=83=D0=B5=D0=BC=20=D0=BF=D1=83=D0=BB=20=D1=81?= =?UTF-8?q?=D0=BE=D0=B5=D0=B4=D0=B8=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=80=D0=B5=D0=B4=D0=B8=D1=81=D0=B0=20(Revert,?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B3=D0=BD=D0=B0=D0=BB=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=8B,=20=D1=83=D0=B1=D0=B5=D0=B4=D0=B8=D0=BB?= =?UTF-8?q?=D1=81=D1=8F,=20=D1=87=D1=82=D0=BE=20=D1=82=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=BA=D0=BE=20=D1=85=D1=83=D0=B6=D0=B5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 915c46522445eb721af9eb62ff5d1b649a30f07c. --- lib/data/SkinItem.go | 4 ++-- lib/services/services.go | 4 ++-- minecraft-skinsystem.go | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go index ae0de56..3916ccd 100644 --- a/lib/data/SkinItem.go +++ b/lib/data/SkinItem.go @@ -20,12 +20,12 @@ type SkinItem struct { func (s *SkinItem) Save() { str, _ := json.Marshal(s) - services.RedisPool.Cmd("SET", tools.BuildKey(s.Nickname), str) + services.Redis.Cmd("SET", tools.BuildKey(s.Nickname), str) } func FindRecord(username string) (SkinItem, error) { var record SkinItem; - result, err := services.RedisPool.Cmd("GET", tools.BuildKey(username)).Str(); + result, err := services.Redis.Cmd("GET", tools.BuildKey(username)).Str(); if (err == nil) { decodeErr := json.Unmarshal([]byte(result), &record) if (decodeErr != nil) { diff --git a/lib/services/services.go b/lib/services/services.go index f0f612d..d62f7ac 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -1,10 +1,10 @@ package services import ( - "github.com/mediocregopher/radix.v2/pool" + "github.com/mediocregopher/radix.v2/redis" "github.com/gorilla/mux" ) -var RedisPool *pool.Pool +var Redis *redis.Client var Router *mux.Router diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index b1bf97f..0090ff5 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -6,7 +6,7 @@ import ( "net/http" "github.com/gorilla/mux" - "github.com/mediocregopher/radix.v2/pool" + "github.com/mediocregopher/radix.v2/redis" "elyby/minecraft-skinsystem/lib/routes" "elyby/minecraft-skinsystem/lib/services" @@ -15,7 +15,7 @@ import ( func main() { runtime.GOMAXPROCS(runtime.NumCPU()) - pool, redisErr := pool.New("tcp", "redis:6379", 10) + client, redisErr := redis.Dial("tcp", "redis:6379") if redisErr != nil { log.Fatal("Redis unavailable") } @@ -36,7 +36,7 @@ func main() { apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") - services.RedisPool = pool + services.Redis = client services.Router = router log.Fatal(http.ListenAndServe(":80", router)) From c2d0cb93cbf49c7409c763b773c5cf3e5cc072e5 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Thu, 28 Jul 2016 18:17:12 +0300 Subject: [PATCH 12/17] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=86=D0=B0=20404=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=20Redis=20=D0=B2?= =?UTF-8?q?=20=D1=81=D0=BB=D1=83=D1=87=D0=B0=D0=B5,=20=D0=B5=D1=81=D0=BB?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BE=D0=B5=D0=B4=D0=B8=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=83=D0=BF=D0=B0=D0=B4=D1=91=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/SkinItem.go | 2 ++ lib/routes/NotFound.go | 2 +- minecraft-skinsystem.go | 27 +++++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go index 3916ccd..fdad40a 100644 --- a/lib/data/SkinItem.go +++ b/lib/data/SkinItem.go @@ -31,6 +31,8 @@ func FindRecord(username string) (SkinItem, error) { if (decodeErr != nil) { log.Println("Cannot decode record data") } + } else { + log.Println("Error on request user data") } return record, err diff --git a/lib/routes/NotFound.go b/lib/routes/NotFound.go index 8460956..9cd1a44 100644 --- a/lib/routes/NotFound.go +++ b/lib/routes/NotFound.go @@ -9,7 +9,7 @@ func NotFound(w http.ResponseWriter, r *http.Request) { json, _ := json.Marshal(map[string]string{ "status": "404", "message": "Not Found", - "link": "http://docs.ely.by", + "link": "http://docs.ely.by/skin-system.html", }) w.Header().Set("Content-Type", "application/json") diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 0090ff5..044e776 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -3,6 +3,7 @@ package main import ( "log" "runtime" + "time" "net/http" "github.com/gorilla/mux" @@ -12,16 +13,17 @@ import ( "elyby/minecraft-skinsystem/lib/services" ) +const redisString string = "redis:6379" + func main() { runtime.GOMAXPROCS(runtime.NumCPU()) - client, redisErr := redis.Dial("tcp", "redis:6379") + client, redisErr := redis.Dial("tcp", redisString) if redisErr != nil { log.Fatal("Redis unavailable") } router := mux.NewRouter().StrictSlash(true) - router.HandleFunc("/", routes.NotFound) router.HandleFunc("/skins/{username}", routes.Skin).Methods("GET").Name("skins") router.HandleFunc("/cloaks/{username}", routes.Cape).Methods("GET").Name("cloaks") router.HandleFunc("/textures/{username}", routes.Textures).Methods("GET").Name("textures") @@ -29,6 +31,8 @@ func main() { router.HandleFunc("/minecraft.php", routes.MinecraftPHP).Methods("GET") router.HandleFunc("/skins/", routes.SkinGET).Methods("GET") router.HandleFunc("/cloaks/", routes.CapeGET).Methods("GET") + // 404 + router.NotFoundHandler = http.HandlerFunc(routes.NotFound) // TODO: убрать этого, т.к. он стар router.HandleFunc("/system/setSkin", routes.SetSkin).Methods("POST") @@ -39,5 +43,24 @@ func main() { services.Redis = client services.Router = router + go func() { + for { + time.Sleep(5 * time.Second) + + resp := services.Redis.Cmd("PING") + if (resp.Err != nil) { + log.Println("Redis not pinged. Try to reconnect") + newClient, redisErr := redis.Dial("tcp", redisString) + if (redisErr != nil) { + log.Println("Cannot reconnect to redis") + } else { + services.Redis = newClient + log.Println("Reconnected") + } + } + } + }() + + log.Println("Started"); log.Fatal(http.ListenAndServe(":80", router)) } From 64bf7deb791a27b0170504d9a8b11795de38bfde Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Fri, 29 Jul 2016 01:13:09 +0300 Subject: [PATCH 13/17] =?UTF-8?q?=D0=9A=D0=BE=D1=80=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BF=D0=BE=D0=B4?= =?UTF-8?q?=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5-=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=B5=20=D1=84=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D1=83=D1=8E?= =?UTF-8?q?=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8E=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D0=BA=D0=BE=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/SkinItem.go | 4 ++-- lib/routes/SetSkin.go | 3 +-- lib/routes/Skin.go | 2 +- lib/routes/Textures.go | 2 +- lib/tools/tools.go | 5 +++++ minecraft-skinsystem.go | 3 --- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go index fdad40a..8fe0f86 100644 --- a/lib/data/SkinItem.go +++ b/lib/data/SkinItem.go @@ -10,7 +10,7 @@ import ( type SkinItem struct { UserId int `json:"userId"` - Nickname string `json:"nickname"` + Username string `json:"username"` SkinId int `json:"skinId"` Url string `json:"url"` Is1_8 bool `json:"is1_8"` @@ -20,7 +20,7 @@ type SkinItem struct { func (s *SkinItem) Save() { str, _ := json.Marshal(s) - services.Redis.Cmd("SET", tools.BuildKey(s.Nickname), str) + services.Redis.Cmd("SET", tools.BuildKey(s.Username), str) } func FindRecord(username string) (SkinItem, error) { diff --git a/lib/routes/SetSkin.go b/lib/routes/SetSkin.go index 897e4c6..b1acb87 100644 --- a/lib/routes/SetSkin.go +++ b/lib/routes/SetSkin.go @@ -2,7 +2,6 @@ package routes import ( "net/http" - "strings" "strconv" "elyby/minecraft-skinsystem/lib/data" @@ -17,7 +16,7 @@ func SetSkin(w http.ResponseWriter, r *http.Request) { } skin := new(data.SkinItem) - skin.Nickname = strings.ToLower(r.PostFormValue("nickname")) + skin.Username = r.PostFormValue("username") skin.UserId, _ = strconv.Atoi(r.PostFormValue("userId")) skin.SkinId, _ = strconv.Atoi(r.PostFormValue("skinId")) skin.Hash = r.PostFormValue("hash") diff --git a/lib/routes/Skin.go b/lib/routes/Skin.go index 9fed97d..ca4f42f 100644 --- a/lib/routes/Skin.go +++ b/lib/routes/Skin.go @@ -20,7 +20,7 @@ func Skin(w http.ResponseWriter, r *http.Request) { return } - http.Redirect(w, r, rec.Url, 301); + http.Redirect(w, r, tools.BuildElyUrl(rec.Url), 301); } func SkinGET(w http.ResponseWriter, r *http.Request) { diff --git a/lib/routes/Textures.go b/lib/routes/Textures.go index 72ac663..b05df03 100644 --- a/lib/routes/Textures.go +++ b/lib/routes/Textures.go @@ -23,7 +23,7 @@ func Textures(w http.ResponseWriter, r *http.Request) { textures := data.TexturesResponse{ Skin: &data.Skin{ - Url: rec.Url, + Url: tools.BuildElyUrl(rec.Url), Hash: rec.Hash, }, } diff --git a/lib/tools/tools.go b/lib/tools/tools.go index 0814856..7e5158b 100644 --- a/lib/tools/tools.go +++ b/lib/tools/tools.go @@ -29,7 +29,12 @@ func BuildKey(username string) string { return "username:" + strings.ToLower(username) } +func BuildElyUrl(route string) string { + return "http://ely.by" + route +} + func getCurrentHour() int64 { n := time.Now() return time.Date(n.Year(), n.Month(), n.Day(), n.Hour(), 0, 0, 0, time.UTC).Unix() } + diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 044e776..119e522 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -34,9 +34,6 @@ func main() { // 404 router.NotFoundHandler = http.HandlerFunc(routes.NotFound) - // TODO: убрать этого, т.к. он стар - router.HandleFunc("/system/setSkin", routes.SetSkin).Methods("POST") - apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") From c03021403aad34459aef89904ce45477e01b42c4 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Fri, 29 Jul 2016 01:20:09 +0300 Subject: [PATCH 14/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= =?UTF-8?q?,=20=D0=BA=D0=BE=D0=B3=D0=B4=D0=B0=20=D0=BA=20=D1=81=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD=D0=B0=D0=BC=20=D0=BC=D0=BE=D1=8F=D0=BD=D0=B3=D0=B0?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B8=D0=BA=D0=BB=D0=B5=D0=B8=D0=B2=D0=B0=D0=BB?= =?UTF-8?q?=D1=81=D1=8F=20=D0=BD=D0=B0=D1=88=20=D0=B4=D0=BE=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/routes/Skin.go | 1 - lib/routes/Textures.go | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/routes/Skin.go b/lib/routes/Skin.go index ca4f42f..650fd37 100644 --- a/lib/routes/Skin.go +++ b/lib/routes/Skin.go @@ -16,7 +16,6 @@ func Skin(w http.ResponseWriter, r *http.Request) { rec, err := data.FindRecord(username) if (err != nil) { http.Redirect(w, r, "http://skins.minecraft.net/MinecraftSkins/" + username + ".png", 301) - log.Println("Cannot get skin for username " + username) return } diff --git a/lib/routes/Textures.go b/lib/routes/Textures.go index b05df03..e298922 100644 --- a/lib/routes/Textures.go +++ b/lib/routes/Textures.go @@ -19,11 +19,13 @@ func Textures(w http.ResponseWriter, r *http.Request) { if (err != nil || rec.SkinId == 0) { rec.Url = "http://skins.minecraft.net/MinecraftSkins/" + username + ".png" rec.Hash = string(tools.BuildNonElyTexturesHash(username)) + } else { + rec.Url = tools.BuildElyUrl(rec.Url) } textures := data.TexturesResponse{ Skin: &data.Skin{ - Url: tools.BuildElyUrl(rec.Url), + Url: rec.Url, Hash: rec.Hash, }, } From 22f80576bd903bd63c38bb29570e410ce8fb5b7c Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Fri, 29 Jul 2016 09:56:25 +0300 Subject: [PATCH 15/17] =?UTF-8?q?Revert=20"=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=86=D0=B0=20404=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D0=B8"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit c2d0cb93cbf49c7409c763b773c5cf3e5cc072e5. --- lib/data/SkinItem.go | 2 -- lib/routes/NotFound.go | 2 +- minecraft-skinsystem.go | 27 ++------------------------- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go index 8fe0f86..1a7ad61 100644 --- a/lib/data/SkinItem.go +++ b/lib/data/SkinItem.go @@ -31,8 +31,6 @@ func FindRecord(username string) (SkinItem, error) { if (decodeErr != nil) { log.Println("Cannot decode record data") } - } else { - log.Println("Error on request user data") } return record, err diff --git a/lib/routes/NotFound.go b/lib/routes/NotFound.go index 9cd1a44..8460956 100644 --- a/lib/routes/NotFound.go +++ b/lib/routes/NotFound.go @@ -9,7 +9,7 @@ func NotFound(w http.ResponseWriter, r *http.Request) { json, _ := json.Marshal(map[string]string{ "status": "404", "message": "Not Found", - "link": "http://docs.ely.by/skin-system.html", + "link": "http://docs.ely.by", }) w.Header().Set("Content-Type", "application/json") diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 119e522..b7163f2 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -3,7 +3,6 @@ package main import ( "log" "runtime" - "time" "net/http" "github.com/gorilla/mux" @@ -13,17 +12,16 @@ import ( "elyby/minecraft-skinsystem/lib/services" ) -const redisString string = "redis:6379" - func main() { runtime.GOMAXPROCS(runtime.NumCPU()) - client, redisErr := redis.Dial("tcp", redisString) + client, redisErr := redis.Dial("tcp", "redis:6379") if redisErr != nil { log.Fatal("Redis unavailable") } router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/", routes.NotFound) router.HandleFunc("/skins/{username}", routes.Skin).Methods("GET").Name("skins") router.HandleFunc("/cloaks/{username}", routes.Cape).Methods("GET").Name("cloaks") router.HandleFunc("/textures/{username}", routes.Textures).Methods("GET").Name("textures") @@ -31,8 +29,6 @@ func main() { router.HandleFunc("/minecraft.php", routes.MinecraftPHP).Methods("GET") router.HandleFunc("/skins/", routes.SkinGET).Methods("GET") router.HandleFunc("/cloaks/", routes.CapeGET).Methods("GET") - // 404 - router.NotFoundHandler = http.HandlerFunc(routes.NotFound) apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") @@ -40,24 +36,5 @@ func main() { services.Redis = client services.Router = router - go func() { - for { - time.Sleep(5 * time.Second) - - resp := services.Redis.Cmd("PING") - if (resp.Err != nil) { - log.Println("Redis not pinged. Try to reconnect") - newClient, redisErr := redis.Dial("tcp", redisString) - if (redisErr != nil) { - log.Println("Cannot reconnect to redis") - } else { - services.Redis = newClient - log.Println("Reconnected") - } - } - } - }() - - log.Println("Started"); log.Fatal(http.ListenAndServe(":80", router)) } From 58c05533f3628c50044ed95afb7354ad8b7eabd2 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Fri, 29 Jul 2016 12:14:32 +0300 Subject: [PATCH 16/17] =?UTF-8?q?Revert=20"Revert=20"=D0=A0=D0=B5=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D0=B0=20404=20=D0=BE=D1=88=D0=B8?= =?UTF-8?q?=D0=B1=D0=BA=D0=B8""?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 22f80576bd903bd63c38bb29570e410ce8fb5b7c. --- lib/data/SkinItem.go | 2 ++ lib/routes/NotFound.go | 2 +- minecraft-skinsystem.go | 27 +++++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go index 1a7ad61..8fe0f86 100644 --- a/lib/data/SkinItem.go +++ b/lib/data/SkinItem.go @@ -31,6 +31,8 @@ func FindRecord(username string) (SkinItem, error) { if (decodeErr != nil) { log.Println("Cannot decode record data") } + } else { + log.Println("Error on request user data") } return record, err diff --git a/lib/routes/NotFound.go b/lib/routes/NotFound.go index 8460956..9cd1a44 100644 --- a/lib/routes/NotFound.go +++ b/lib/routes/NotFound.go @@ -9,7 +9,7 @@ func NotFound(w http.ResponseWriter, r *http.Request) { json, _ := json.Marshal(map[string]string{ "status": "404", "message": "Not Found", - "link": "http://docs.ely.by", + "link": "http://docs.ely.by/skin-system.html", }) w.Header().Set("Content-Type", "application/json") diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index b7163f2..119e522 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -3,6 +3,7 @@ package main import ( "log" "runtime" + "time" "net/http" "github.com/gorilla/mux" @@ -12,16 +13,17 @@ import ( "elyby/minecraft-skinsystem/lib/services" ) +const redisString string = "redis:6379" + func main() { runtime.GOMAXPROCS(runtime.NumCPU()) - client, redisErr := redis.Dial("tcp", "redis:6379") + client, redisErr := redis.Dial("tcp", redisString) if redisErr != nil { log.Fatal("Redis unavailable") } router := mux.NewRouter().StrictSlash(true) - router.HandleFunc("/", routes.NotFound) router.HandleFunc("/skins/{username}", routes.Skin).Methods("GET").Name("skins") router.HandleFunc("/cloaks/{username}", routes.Cape).Methods("GET").Name("cloaks") router.HandleFunc("/textures/{username}", routes.Textures).Methods("GET").Name("textures") @@ -29,6 +31,8 @@ func main() { router.HandleFunc("/minecraft.php", routes.MinecraftPHP).Methods("GET") router.HandleFunc("/skins/", routes.SkinGET).Methods("GET") router.HandleFunc("/cloaks/", routes.CapeGET).Methods("GET") + // 404 + router.NotFoundHandler = http.HandlerFunc(routes.NotFound) apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") @@ -36,5 +40,24 @@ func main() { services.Redis = client services.Router = router + go func() { + for { + time.Sleep(5 * time.Second) + + resp := services.Redis.Cmd("PING") + if (resp.Err != nil) { + log.Println("Redis not pinged. Try to reconnect") + newClient, redisErr := redis.Dial("tcp", redisString) + if (redisErr != nil) { + log.Println("Cannot reconnect to redis") + } else { + services.Redis = newClient + log.Println("Reconnected") + } + } + } + }() + + log.Println("Started"); log.Fatal(http.ListenAndServe(":80", router)) } From 8abb5f6bc5de1603ce237042b38c477be2fb2b7e Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Fri, 29 Jul 2016 12:24:31 +0300 Subject: [PATCH 17/17] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=8B=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=D0=B5=D1=80=D0=BD=D1=83=D1=82=D1=8C=20=D0=BF?= =?UTF-8?q?=D1=83=D0=BB=20=D1=81=D0=BE=D0=B5=D0=B4=D0=B8=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/SkinItem.go | 6 +++--- lib/services/services.go | 4 ++-- minecraft-skinsystem.go | 13 +++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/data/SkinItem.go b/lib/data/SkinItem.go index 8fe0f86..c381ed5 100644 --- a/lib/data/SkinItem.go +++ b/lib/data/SkinItem.go @@ -20,19 +20,19 @@ type SkinItem struct { func (s *SkinItem) Save() { str, _ := json.Marshal(s) - services.Redis.Cmd("SET", tools.BuildKey(s.Username), str) + services.RedisPool.Cmd("SET", tools.BuildKey(s.Username), str) } func FindRecord(username string) (SkinItem, error) { var record SkinItem; - result, err := services.Redis.Cmd("GET", tools.BuildKey(username)).Str(); + result, err := services.RedisPool.Cmd("GET", tools.BuildKey(username)).Str(); if (err == nil) { decodeErr := json.Unmarshal([]byte(result), &record) if (decodeErr != nil) { log.Println("Cannot decode record data") } } else { - log.Println("Error on request user data") + log.Println("Error on request user data: " + err.Error()) } return record, err diff --git a/lib/services/services.go b/lib/services/services.go index d62f7ac..f0f612d 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -1,10 +1,10 @@ package services import ( - "github.com/mediocregopher/radix.v2/redis" + "github.com/mediocregopher/radix.v2/pool" "github.com/gorilla/mux" ) -var Redis *redis.Client +var RedisPool *pool.Pool var Router *mux.Router diff --git a/minecraft-skinsystem.go b/minecraft-skinsystem.go index 119e522..04c2b0b 100644 --- a/minecraft-skinsystem.go +++ b/minecraft-skinsystem.go @@ -3,14 +3,15 @@ package main import ( "log" "runtime" - "time" + //"time" "net/http" "github.com/gorilla/mux" - "github.com/mediocregopher/radix.v2/redis" + "github.com/mediocregopher/radix.v2/pool" "elyby/minecraft-skinsystem/lib/routes" "elyby/minecraft-skinsystem/lib/services" + //"github.com/mediocregopher/radix.v2/redis" ) const redisString string = "redis:6379" @@ -18,7 +19,7 @@ const redisString string = "redis:6379" func main() { runtime.GOMAXPROCS(runtime.NumCPU()) - client, redisErr := redis.Dial("tcp", redisString) + pool, redisErr := pool.New("tcp", redisString, 10) if redisErr != nil { log.Fatal("Redis unavailable") } @@ -37,10 +38,10 @@ func main() { apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.HandleFunc("/user/{username}/skin", routes.SetSkin).Methods("POST") - services.Redis = client + services.RedisPool = pool services.Router = router - go func() { + /*go func() { for { time.Sleep(5 * time.Second) @@ -56,7 +57,7 @@ func main() { } } } - }() + }()*/ log.Println("Started"); log.Fatal(http.ListenAndServe(":80", router))