package test_test import ( "crypto/rand" "crypto/sha256" "encoding/hex" "fmt" "io" "log" "os" "time" "git.ali33.ru/fcg-xvii/go-tools/json" "git.ali33.ru/fcg-xvii/rest" ) // AvatarApp по запросу веб сервера создает объекты команд и возвращает их серверу type AvatarApp struct { imagePath string } // ImagePath формирует путь к файлу аватара пользователя по его хэшу func (s *AvatarApp) ImagePath(hash string) string { return fmt.Sprintf("%s/%s.jpg", s.imagePath, hash) } // Executer создает команду по запросу веб сервера func (s *AvatarApp) Executer(r *rest.Request) (rest.IExecuter, bool) { // проверяем входной URL switch r.RPath() { case "/register": // Регистрация нового порльзователя return &RequestReg{}, true } return nil, false } /////////////////////////////////////// // RequestReg реализует команду регистрации нового пользователя. type RequestReg struct { // имя пользователя Name string `rest:"required" json:"name"` } // HashString генерирует хэш для строки. // Возвращает хэш-строку и возможную ошибку. func (s *RequestReg) HashString() (string, error) { data := make([]byte, 16) if _, err := rand.Read(data); err != nil { return "", err } hash := sha256.Sum256(data) hashString := hex.EncodeToString(hash[:]) return hashString, nil } // Validate проверяет запрос на корректность входных данных (не обязательный метод). func (s *RequestReg) Validate(r *rest.Request) *rest.Response { if r.IsAuth() { return rest.ResponseError("AlreadyAuth", nil, 500) } return nil } // Execute реализует логику команды. Выполняется после валидации func (s *RequestReg) Execute(r *rest.Request) *rest.Response { // генерируем хэш нового пользователя hash, err := s.HashString() if err != nil { return rest.ResponseErrorMessage("HashGenerate", err.Error(), 500) } // создаем токен авторизации (бессрочный) token, err := r.GenerateToken( json.Map{ "name": s.Name, "hash": hash, }, 0, ) if err != nil { return rest.ResponseErrorMessage("AuthTokenGenerate", err.Error(), 500) } // создаем ответ resp := rest.NewResponse() resp.KeySet("token", token) return resp } // swagger:response registrationResponse type RegistrationResponseWrapper struct { // Встроенный объект ответа // // in: body Body struct { // Токен авторизации для пользователя Token string `json:"token"` } } //////////////////////////////////////////////////////////////// type RequestUpload struct { app *AvatarApp AvatarJpg io.Reader `rest:"required;file"` } func (s *RequestUpload) Validate(r *rest.Request) *rest.Response { if !r.IsAuth() { return rest.ResponseError("NotAuth", nil, 500) } return nil } func (s *RequestUpload) Execute(r *rest.Request) *rest.Response { mAuth := r.Auth() // открываем файл для обновления f, err := os.OpenFile(s.app.ImagePath(mAuth.String("hash", "")), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) if err != nil { return rest.ResponseErrorMessage("AvatarFileOpen", err.Error(), 500) } defer f.Close() // обновляем файл if _, err = io.Copy(f, s.AvatarJpg); err != nil { return rest.ResponseErrorMessage("AvatarFileWrite", err.Error(), 500) } // файл обновлён resp := rest.NewResponse() resp.KeySet("ok", true) return resp } ///////////////////////////////////////////////////////////////// func RestNew() { // адрес и порт веб сервера addr := ":7000" // ключ шифрования токена авторизации secret := []byte("top-secret") // люъект приложения (rest.IApp) app := &AvatarApp{} // создание сервера rest := rest.New(addr, secret, app) // запуск if err := rest.Listen(time.Second); err != nil { log.Fatal(err) } } func ExampleRestNew() { RestNew() ch := make(chan struct{}) <-ch }