Добавлена поддержка восстановления информации об аккаунте, если по какой-то причине её не удалось найти в хранилище

This commit is contained in:
ErickSkrauch 2017-04-10 14:53:26 +03:00
parent 3d73cc9402
commit 8693673a71
5 changed files with 238 additions and 9 deletions

44
lib/external/accounts/AccountInfo.go vendored Normal file
View File

@ -0,0 +1,44 @@
package accounts
import (
"net/http"
"io/ioutil"
"encoding/json"
)
type AccountInfoResponse struct {
Id int `json:"id"`
Uuid string `json:"uuid"`
Username string `json:"username"`
Email string `json:"email"`
}
const internalAccountInfoUrl = domain + "/api/internal/accounts/info"
func (token *Token) AccountInfo(attribute string, value string) (AccountInfoResponse, error) {
request, err := http.NewRequest("GET", internalAccountInfoUrl, nil)
request.Header.Add("Authorization", "Bearer " + token.AccessToken)
query := request.URL.Query()
query.Add(attribute, value)
request.URL.RawQuery = query.Encode()
response, err := Client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
var info AccountInfoResponse
responseError := handleResponse(response)
if responseError != nil {
return info, responseError
}
body, _ := ioutil.ReadAll(response.Body)
println("Raw account info response is " + string(body))
json.Unmarshal(body, &info)
return info, nil
}

49
lib/external/accounts/GetToken.go vendored Normal file
View File

@ -0,0 +1,49 @@
package accounts
import (
"strings"
"net/url"
"io/ioutil"
"encoding/json"
)
type TokenRequest struct {
Id string
Secret string
Scopes []string
}
type Token struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
}
const tokenUrl = domain + "/api/oauth2/v1/token"
func GetToken(request TokenRequest) (Token, error) {
form := url.Values{}
form.Add("client_id", request.Id)
form.Add("client_secret", request.Secret)
form.Add("grant_type", "client_credentials")
form.Add("scope", strings.Join(request.Scopes, ","))
response, err := Client.Post(tokenUrl, "application/x-www-form-urlencoded", strings.NewReader(form.Encode()))
if err != nil {
panic(err)
}
defer response.Body.Close()
var result Token
responseError := handleResponse(response)
if responseError != nil {
return result, responseError
}
body, _ := ioutil.ReadAll(response.Body)
json.Unmarshal(body, &result)
return result, nil
}

51
lib/external/accounts/base.go vendored Normal file
View File

@ -0,0 +1,51 @@
package accounts
import (
"fmt"
"net/http"
)
const domain = "https://dev.account.ely.by"
var Client = &http.Client{}
type UnauthorizedResponse struct {}
func (err UnauthorizedResponse) Error() string {
return "Unauthorized response"
}
type ForbiddenResponse struct {}
func (err ForbiddenResponse) Error() string {
return "Forbidden response"
}
type NotFoundResponse struct {}
func (err NotFoundResponse) Error() string {
return "Not found"
}
type NotSuccessResponse struct {
StatusCode int
}
func (err NotSuccessResponse) Error() string {
return fmt.Sprintf("Response code is \"%d\"", err.StatusCode)
}
func handleResponse(response *http.Response) error {
switch status := response.StatusCode; status {
case 200:
return nil
case 401:
return &UnauthorizedResponse{}
case 403:
return &ForbiddenResponse{}
case 404:
return &NotFoundResponse{}
default:
return &NotSuccessResponse{status}
}
}

View File

@ -1,6 +1,7 @@
package worker
import (
"fmt"
"elyby/minecraft-skinsystem/lib/data"
"elyby/minecraft-skinsystem/lib/services"
)
@ -18,13 +19,23 @@ func handleChangeUsername(model usernameChanged) (bool) {
return true
}
record, err := data.FindSkinByUsername(model.OldUsername)
record, err := data.FindSkinById(model.AccountId)
if (err != nil) {
services.Logger.IncCounter("worker.change_username.username_not_found", 1)
// TODO: я не уверен, что это валидное поведение
// Суть в том, что здесь может возникнуть ошибка в том случае, если записи в базе нету
// а значит его нужно, как минимум, зарегистрировать
return true
services.Logger.IncCounter("worker.change_username.id_not_found", 1)
fmt.Println("Cannot find user id. Trying to search.")
response, err := getById(model.AccountId)
if err != nil {
services.Logger.IncCounter("worker.change_username.id_not_restored", 1)
fmt.Printf("Cannot restore user info. %T\n", err)
// TODO: логгировать в какой-нибудь Sentry, если там не 404
return true
}
services.Logger.IncCounter("worker.change_username.id_restored", 1)
fmt.Println("User info successfully restored.")
record = data.SkinItem{
UserId: response.Id,
}
}
record.Username = model.NewUsername
@ -35,11 +46,23 @@ func handleChangeUsername(model usernameChanged) (bool) {
return true
}
func handleSkinChanged(model skinChanged) (bool) {
func handleSkinChanged(model skinChanged) bool {
record, err := data.FindSkinById(model.AccountId)
if (err != nil) {
if err != nil {
services.Logger.IncCounter("worker.skin_changed.id_not_found", 1)
return true
fmt.Println("Cannot find user id. Trying to search.")
response, err := getById(model.AccountId)
if err != nil {
services.Logger.IncCounter("worker.skin_changed.id_not_restored", 1)
fmt.Printf("Cannot restore user info. %T\n", err)
// TODO: логгировать в какой-нибудь Sentry, если там не 404
return true
}
services.Logger.IncCounter("worker.skin_changed.id_restored", 1)
fmt.Println("User info successfully restored.")
record.UserId = response.Id
record.Username = response.Username
}
record.Uuid = model.Uuid

62
lib/worker/supports.go Normal file
View File

@ -0,0 +1,62 @@
package worker
import (
"strconv"
"elyby/minecraft-skinsystem/lib/external/accounts"
)
var token *accounts.Token
const repeatsLimit = 3
var repeatsCount = 0
func getById(id int) (accounts.AccountInfoResponse, error) {
return _getByField("id", strconv.Itoa(id))
}
func _getByField(field string, value string) (accounts.AccountInfoResponse, error) {
defer resetRepeatsCount()
apiToken, err := getToken()
if err != nil {
return accounts.AccountInfoResponse{}, err
}
result, err := apiToken.AccountInfo(field, value)
if err != nil {
_, ok := err.(*accounts.UnauthorizedResponse)
if !ok || repeatsCount >= repeatsLimit {
return accounts.AccountInfoResponse{}, err
}
repeatsCount++
token = nil
return _getByField(field, value)
}
return result, nil
}
func getToken() (*accounts.Token, error) {
if token == nil {
tempToken, err := accounts.GetToken(accounts.TokenRequest{
Id: "skinsystem",
Secret: "qugFIaCjec3LMA",
Scopes: []string{
"internal_account_info",
},
})
if err != nil {
return &accounts.Token{}, err
}
token = &tempToken
}
return token, nil
}
func resetRepeatsCount() {
repeatsCount = 0
}