-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Iter5 #3
Iter5 #3
Changes from all commits
7d47269
bc38f9a
bbb404c
0d3cc7b
4df6ae4
e9e515c
7dfe8c7
fec9b71
be9c58e
f4a3084
44f17b7
49684d6
91dd87f
ef68905
9bee7ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package config | ||
|
||
import ( | ||
"fmt" | ||
"github.com/nabbat/23_kogorta_shotener/internal/envirements" | ||
"github.com/nabbat/23_kogorta_shotener/internal/flags" | ||
) | ||
|
||
func SetEnv() *envirements.EnvConfig { | ||
fl := flags.ParseFlags() | ||
en := envirements.ParseEnv() | ||
c := &envirements.EnvConfig{} | ||
|
||
if en.RunAddr != "" { | ||
c.RunAddr = en.RunAddr | ||
} else { | ||
c.RunAddr = fl.RunAddr | ||
} | ||
|
||
if en.ResultURL != "" && en.RunAddr != "http://" { | ||
c.ResultURL = en.ResultURL | ||
} else { | ||
c.ResultURL = fl.ResultURL | ||
} | ||
fmt.Println(c) | ||
return c | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package config | ||
|
||
import ( | ||
"github.com/nabbat/23_kogorta_shotener/internal/envirements" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestSetEnv(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
want *envirements.EnvConfig | ||
}{ | ||
// TODO: Add test cases. | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := SetEnv(); !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("SetEnv() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,34 @@ | ||
package main | ||
|
||
func main() {} | ||
import ( | ||
"fmt" | ||
"github.com/gorilla/mux" | ||
"github.com/nabbat/23_kogorta_shotener/cmd/config" | ||
"github.com/nabbat/23_kogorta_shotener/internal/handlers" | ||
urlstorage "github.com/nabbat/23_kogorta_shotener/internal/storage" | ||
"net/http" | ||
) | ||
|
||
func main() { | ||
// Получаем переменные если они есть | ||
c := config.SetEnv() | ||
|
||
// Создаем хранилище | ||
storage := urlstorage.NewURLStorage() | ||
// Создаем хэндлеры | ||
redirectHandler := &handlers.RedirectHandler{} | ||
shortenURLHandler := &handlers.ShortenURLHandler{} | ||
|
||
r := mux.NewRouter() | ||
r.Use(handlers.PanicHandler) // Добавляем PanicHandler middleware | ||
|
||
r.HandleFunc("/", shortenURLHandler.HandleShortenURL(storage, c)).Methods("POST") | ||
r.HandleFunc("/{idShortenURL}", redirectHandler.HandleRedirect(storage)).Methods("GET") | ||
|
||
fmt.Println("RunAddr: ResultURL: ", c.RunAddr, c.ResultURL) | ||
fmt.Println("Running server on", c.RunAddr) | ||
err := http.ListenAndServe(c.RunAddr, r) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [FYI] Здесь так же было бы хорошо слушать сигналы ОС и корректно завершать http сервис чтобы пользователи в момент редеплоя приложения или принудительного завершения получили ответ. |
||
if err != nil { | ||
panic(err) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module github.com/nabbat/23_kogorta_shotener | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/gorilla/mux v1.8.0 | ||
github.com/spf13/pflag v1.0.5 | ||
github.com/stretchr/testify v1.8.4 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
go.uber.org/multierr v1.10.0 // indirect | ||
go.uber.org/zap v1.25.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= | ||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= | ||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= | ||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= | ||
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= | ||
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package envirements | ||
|
||
import ( | ||
"os" | ||
"strings" | ||
) | ||
|
||
type EnvConfig struct { | ||
RunAddr string | ||
ResultURL string | ||
} | ||
|
||
// ParseEnv Get system environments | ||
func ParseEnv() *EnvConfig { | ||
env := &EnvConfig{} | ||
env.RunAddr = os.Getenv("RUN_ADDR") | ||
env.ResultURL = os.Getenv("SERVER_ADDRESS") | ||
// парсим переданные серверу аргументы в зарегистрированные переменные | ||
if !strings.HasPrefix(env.ResultURL, "http://") && env.ResultURL != "" { | ||
env.ResultURL = "http://" + env.ResultURL | ||
} | ||
return env | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package envirements | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestParseEnv(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
want *EnvConfig | ||
}{ | ||
// TODO: Add test cases. | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := ParseEnv(); !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("ParseEnv() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package flags | ||
|
||
import ( | ||
flag "github.com/spf13/pflag" | ||
"strings" | ||
) | ||
|
||
// Flags структура для хранения настроек | ||
type Flags struct { | ||
RunAddr string | ||
ResultURL string | ||
} | ||
|
||
// ParseFlags обрабатывает аргументы командной строки | ||
// и сохраняет их значения в соответствующих переменных | ||
func ParseFlags() *Flags { | ||
// Create a Config instance | ||
flg := &Flags{} | ||
flag.StringVarP(&flg.RunAddr, "a", "a", "localhost:8080", "Адрес запуска HTTP-сервера.") | ||
flag.StringVarP(&flg.ResultURL, "b", "b", "http://localhost:8080", "Адрес результирующего сокращённого URL.") | ||
// парсим переданные серверу аргументы в зарегистрированные переменные | ||
flag.Parse() | ||
if !strings.HasPrefix(flg.ResultURL, "http://") { | ||
flg.ResultURL = "http://" + flg.ResultURL | ||
} | ||
return flg | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package flags | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestParseFlags(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
want *Flags | ||
}{ | ||
// TODO: Add test cases. | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := ParseFlags(); !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("ParseFlags() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package handlers | ||
|
||
import ( | ||
"fmt" | ||
"github.com/gorilla/mux" | ||
"github.com/nabbat/23_kogorta_shotener/internal/envirements" | ||
"github.com/nabbat/23_kogorta_shotener/internal/shotenermaker" | ||
urlstorage "github.com/nabbat/23_kogorta_shotener/internal/storage" | ||
"io" | ||
"log" | ||
"net/http" | ||
) | ||
|
||
type RedirectHandlerInterface interface { | ||
HandleRedirect(storage *urlstorage.URLStorage) http.HandlerFunc | ||
} | ||
|
||
type ShortenURLHandlerInterface interface { | ||
HandleShortenURL(storage *urlstorage.URLStorage, c *envirements.EnvConfig) http.HandlerFunc | ||
} | ||
|
||
type RedirectHandler struct{} | ||
|
||
func (rh *RedirectHandler) HandleRedirect(storage *urlstorage.URLStorage) http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
if r.Method != http.MethodGet { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [LINT] Эту проверку можно удалить т.к. здесь указывается метод |
||
http.Error(w, "invalid request type", http.StatusBadRequest) | ||
return | ||
} | ||
|
||
// Получаем идентификатор из URL-пути | ||
vars := mux.Vars(r) | ||
shortURL := vars["idShortenURL"] | ||
|
||
// Получаем оригинальный URL | ||
originalURL := storage.GetOriginalURL(shortURL) | ||
|
||
if originalURL == "" { | ||
http.Error(w, "Ссылка не найдена", http.StatusBadRequest) | ||
return | ||
} | ||
// Устанавливаем заголовок Location и возвращаем ответ с кодом 307 | ||
w.Header().Set("Location", originalURL) | ||
w.WriteHeader(http.StatusTemporaryRedirect) | ||
|
||
} | ||
} | ||
|
||
type ShortenURLHandler struct{} | ||
|
||
func (sh *ShortenURLHandler) HandleShortenURL(storage *urlstorage.URLStorage, c *envirements.EnvConfig) http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
// Читаем тело запроса (URL) | ||
defer r.Body.Close() | ||
urlBytes, err := io.ReadAll(r.Body) | ||
if err != nil { | ||
http.Error(w, "Ошибка чтения запроса", http.StatusBadRequest) | ||
return | ||
} | ||
|
||
// Генерируем уникальный идентификатор сокращённого URL | ||
shortURL := shotenermaker.GenerateID(urlBytes) | ||
|
||
// Добавляем соответствие в словарь | ||
storage.AddURL(shortURL, string(urlBytes)) | ||
|
||
// Отправляем ответ с сокращённым URL | ||
shortenedURL := fmt.Sprintf("%s/%s", c.ResultURL, shortURL) | ||
w.Header().Set("Content-Type", "text/plain") | ||
w.WriteHeader(http.StatusCreated) | ||
if _, err := io.WriteString(w, shortenedURL); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
func PanicHandler(next http.Handler) http.Handler { | ||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
defer func() { | ||
if err := recover(); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [LINT] Вообще если в приложении по какой-то причине произошла паника, приложение должно упасть и панику надо исправить. Здесь же паника просто игнорируется, так лучше не делать |
||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | ||
} | ||
}() | ||
next.ServeHTTP(w, r) | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package handlers | ||
|
||
import ( | ||
"github.com/nabbat/23_kogorta_shotener/internal/envirements" | ||
urlstorage "github.com/nabbat/23_kogorta_shotener/internal/storage" | ||
"net/http" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestPanicHandler(t *testing.T) { | ||
type args struct { | ||
next http.Handler | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want http.Handler | ||
}{ | ||
// TODO: Add test cases. | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := PanicHandler(tt.args.next); !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("PanicHandler() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestRedirectHandler_HandleRedirect(t *testing.T) { | ||
type args struct { | ||
storage *urlstorage.URLStorage | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want http.HandlerFunc | ||
}{ | ||
// TODO: Add test cases. | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
rh := &RedirectHandler{} | ||
if got := rh.HandleRedirect(tt.args.storage); !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("HandleRedirect() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestShortenURLHandler_HandleShortenURL(t *testing.T) { | ||
type args struct { | ||
storage *urlstorage.URLStorage | ||
c *envirements.EnvConfig | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want http.HandlerFunc | ||
}{ | ||
// TODO: Add test cases. | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
sh := &ShortenURLHandler{} | ||
if got := sh.HandleShortenURL(tt.args.storage, tt.args.c); !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("HandleShortenURL() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Комментарии разделены на несколько типов:
[BLOCKER] - Проблема, не решив которую принять работу нельзя
[LINT] - Заменичение, опционально к выполнению.
[FYI] - просто ремарка