Skip to content
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

Iter9 #9

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7d47269
iter2 completed
ByteDSM Oct 9, 2023
bc38f9a
iter3 completed
ByteDSM Oct 9, 2023
bbb404c
iter4 completed
ByteDSM Oct 9, 2023
0d3cc7b
iter5 completed
ByteDSM Oct 9, 2023
4df6ae4
iter5 completed
ByteDSM Oct 9, 2023
e9e515c
iter5 completed
ByteDSM Oct 9, 2023
7dfe8c7
iter5 completed
ByteDSM Oct 9, 2023
fec9b71
iter5 completed
ByteDSM Oct 9, 2023
be9c58e
iter5 completed
ByteDSM Oct 9, 2023
f4a3084
iter5 check environments
ByteDSM Oct 10, 2023
44f17b7
iter5 check environments
ByteDSM Oct 10, 2023
49684d6
iter5 check environments
ByteDSM Oct 10, 2023
91dd87f
iter5 [BLOCKER] completed
ByteDSM Oct 11, 2023
ef68905
iter5 delete unused code
ByteDSM Oct 11, 2023
9bee7ad
iter5 delete unused code and add empty tests
ByteDSM Oct 11, 2023
3c65740
iter6 processing
ByteDSM Oct 23, 2023
f51458c
iter6 processing
ByteDSM Oct 23, 2023
399d05d
iter7 completed
ByteDSM Oct 28, 2023
5bcd270
iter8 start
ByteDSM Oct 28, 2023
1f67955
iter8 completed
ByteDSM Oct 29, 2023
dda4cfa
iter8 some fix like Location
ByteDSM Oct 30, 2023
7e73691
iter8 fix Generate func
ByteDSM Oct 30, 2023
d7b2e42
iter9 start
ByteDSM Oct 30, 2023
2c0328b
iter8 last changes
ByteDSM Nov 7, 2023
25dcc0b
iter8 last changes
ByteDSM Nov 7, 2023
f331979
iter8 last changes
ByteDSM Nov 8, 2023
d48883a
iter8 last changes
ByteDSM Nov 9, 2023
1244e26
iter8 winter is coming
ByteDSM Nov 9, 2023
6e364a4
iter8 winter is coming
ByteDSM Nov 9, 2023
236661d
iter9 is completed
ByteDSM Nov 11, 2023
fa152c5
iter9 is completed
ByteDSM Nov 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions cmd/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package config
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[BLOCKER] Сделай merge, пожалуйста, первого спринта. Чтобы было понятно какие изменения были


import (
"github.com/nabbat/23_kogorta_shotener/internal/envirements"
"github.com/nabbat/23_kogorta_shotener/internal/flags"
"github.com/nabbat/23_kogorta_shotener/internal/liblog"
"github.com/nabbat/23_kogorta_shotener/internal/storage"
"github.com/nabbat/23_kogorta_shotener/internal/storage/filestorage"
urlstorage "github.com/nabbat/23_kogorta_shotener/internal/storage/internalstorage"
)

type Config struct {
RunAddr string
ResultURL string
FileName string
}

func SetEnv(log liblog.Logger) (storage.Storage, *Config, error) {
fl := flags.ParseFlags()
en := envirements.ParseEnv()
c := &Config{}

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
}

if en.FileName != "" {
c.FileName = en.FileName
st, _ := filestorage.NewFileStorage(c.FileName, log, &filestorage.NewFile{})

return st, c, nil
}

if fl.FileName != "" {
c.FileName = "/tmp/" + fl.FileName
st, _ := filestorage.NewFileStorage(c.FileName, log, &filestorage.NewFile{})

return st, c, nil
}

st := urlstorage.NewURLStorage()
return st, c, nil
}
48 changes: 47 additions & 1 deletion cmd/shortener/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,49 @@
package main

func main() {}
import (
"github.com/gorilla/mux"
"github.com/nabbat/23_kogorta_shotener/cmd/config"
"github.com/nabbat/23_kogorta_shotener/internal/handlers"
"github.com/nabbat/23_kogorta_shotener/internal/liblog"
"github.com/nabbat/23_kogorta_shotener/internal/middlewares"
"net/http"
)

func main() {
//TODO make test MF!!! 🤬

// Инициализируем логер
log := liblog.NewLogger()

// Получаем переменные если они есть
storage, c, err := config.SetEnv(log)
if err != nil {
log.Info(err)
}

defer storage.Close()

// Создаем хэндлеры
redirectHandler := &handlers.RedirectHandler{}
shortenURLHandler := &handlers.ShortenURLHandler{}

r := mux.NewRouter()
r.Use(middlewares.GzipMiddleware(log))
// Регистрируем middleware для логирования запросов
r.Use(middlewares.RequestLoggingMiddleware(log))
// Регистрируем middleware для логирования ответов
r.Use(middlewares.ResponseLoggingMiddleware(log))
r.Use(middlewares.PanicHandler) // Добавляем PanicHandler middleware

r.HandleFunc("/api/shorten", shortenURLHandler.HandleShortenURLJSON(storage, c, log)).Methods("POST")
r.HandleFunc("/", shortenURLHandler.HandleShortenURL(storage, c, log)).Methods("POST")
r.HandleFunc("/{idShortenURL}", redirectHandler.HandleRedirect(storage, log)).Methods("GET")

log.Info("RunAddr: ", c.RunAddr, " | ", "ResultURL: ", c.ResultURL)
log.Info("Running server on ", c.RunAddr)

err = http.ListenAndServe(c.RunAddr, r)
if err != nil {
panic(err)
}
}
14 changes: 14 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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
go.uber.org/zap v1.25.0
)

require (
github.com/stretchr/testify v1.8.4 // indirect
go.uber.org/multierr v1.10.0 // indirect
)
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
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/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/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
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/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
3 changes: 0 additions & 3 deletions internal/app/README.md

This file was deleted.

25 changes: 25 additions & 0 deletions internal/envirements/envirements.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package envirements

import (
"os"
"strings"
)

type EnvConfig struct {
RunAddr string
ResultURL string
FileName string
}

// ParseEnv Get system environments
func ParseEnv() *EnvConfig {
env := &EnvConfig{}
env.RunAddr = os.Getenv("RUN_ADDR")
env.ResultURL = os.Getenv("SERVER_ADDRESS")
env.FileName = os.Getenv("FILE_STORAGE_PATH")
// парсим переданные серверу аргументы в зарегистрированные переменные
if !strings.HasPrefix(env.ResultURL, "http://") && env.ResultURL != "" {
env.ResultURL = "http://" + env.ResultURL
}
return env
}
29 changes: 29 additions & 0 deletions internal/flags/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package flags

import (
flag "github.com/spf13/pflag"
"strings"
)

// Flags структура для хранения настроек
type Flags struct {
RunAddr string
ResultURL string
FileName 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.StringVarP(&flg.FileName, "f", "f", "short-url-db.json", "Имя файла для записи на диск. пустое значение отключает функцию записи на диск")
// парсим переданные серверу аргументы в зарегистрированные переменные
flag.Parse()
if !strings.HasPrefix(flg.ResultURL, "http://") {
flg.ResultURL = "http://" + flg.ResultURL
}
return flg
}
115 changes: 115 additions & 0 deletions internal/handlers/urlhandlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package handlers

import (
"bytes"
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"github.com/nabbat/23_kogorta_shotener/cmd/config"
"github.com/nabbat/23_kogorta_shotener/internal/liblog"
"github.com/nabbat/23_kogorta_shotener/internal/shotenermaker"
urlstorage "github.com/nabbat/23_kogorta_shotener/internal/storage"
"io"
"net/http"
)

type RedirectHandler struct{}

func (rh *RedirectHandler) HandleRedirect(storage urlstorage.Storage, log liblog.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LINT] это сам роут проверяет, можно убрать првоерку

http.Error(w, "invalid request type", http.StatusBadRequest)
log.Info("invalid request type")
return
}

// Получаем идентификатор из URL-пути
vars := mux.Vars(r)
shortURL := vars["idShortenURL"]

// Получаем оригинальный URL
originalURL, err := storage.GetOriginalURL(shortURL)
if err != nil {
log.Info(err)
}

if originalURL == "" {
http.Error(w, "Ссылка не найдена", http.StatusBadRequest)
log.Info("Ссылка не найдена")
return
}
// Устанавливаем заголовок Location и возвращаем ответ с кодом 307
w.Header().Set("Location", originalURL)
w.WriteHeader(http.StatusTemporaryRedirect)
log.Info("Location set:" + originalURL)

}
}

type ShortenURLHandler struct{}

func (sh *ShortenURLHandler) HandleShortenURL(storage urlstorage.Storage, c *config.Config, log liblog.Logger) 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.Info("Ошибка записи ответа", err)
}
}
}

func (sh *ShortenURLHandler) HandleShortenURLJSON(storage urlstorage.Storage, c *config.Config, log liblog.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Читаем JSON из тела запроса
type URLJSONRequest struct {
URL string `json:"url"`
}
var urlJSONRequest URLJSONRequest
var buf bytes.Buffer

// читаем тело запроса
_, err := buf.ReadFrom(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// десериализуем JSON
if err = json.Unmarshal(buf.Bytes(), &urlJSONRequest); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// Генерируем уникальный идентификатор сокращенного URL
shortURL := shotenermaker.GenerateID([]byte(urlJSONRequest.URL))

// Добавляем соответствие в словарь
storage.AddURL(shortURL, urlJSONRequest.URL)

// Формируем JSON-ответ с сокращенным URL
response := map[string]string{"result": c.ResultURL + "/" + shortURL}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
if err := json.NewEncoder(w).Encode(response); err != nil {
log.Error("Ошибка записи JSON-ответа:", err)
http.Error(w, "Ошибка записи JSON-ответа", http.StatusInternalServerError)
}
}
}
31 changes: 31 additions & 0 deletions internal/liblog/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package liblog

import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

type Logger interface {
Debug(args ...interface{})
Info(args ...interface{})
Warn(args ...interface{})
Error(fields ...interface{})
}

func NewLogger() *zap.SugaredLogger {
config := zap.Config{
Level: zap.NewAtomicLevelAt(zapcore.DebugLevel),
Development: true,
Encoding: "json",
EncoderConfig: zap.NewProductionEncoderConfig(),
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
}

logger, _ := config.Build()
defer logger.Sync()

sugar := logger.Sugar()

return sugar
}
Loading
Loading