305 lines
8.4 KiB
Go
305 lines
8.4 KiB
Go
|
package main
|
|||
|
|
|||
|
import (
|
|||
|
"bytes"
|
|||
|
"context"
|
|||
|
"encoding/json"
|
|||
|
"fmt"
|
|||
|
"github.com/caarlos0/env/v8"
|
|||
|
"github.com/google/uuid"
|
|||
|
"github.com/gorilla/mux"
|
|||
|
"gorm.io/driver/postgres"
|
|||
|
"gorm.io/gorm"
|
|||
|
"log"
|
|||
|
"net/http"
|
|||
|
"os"
|
|||
|
"os/signal"
|
|||
|
"syscall"
|
|||
|
)
|
|||
|
|
|||
|
type Сonfig struct {
|
|||
|
Port string `env:"USER_HTTP_ADDR" envDefault:"13999"`
|
|||
|
|
|||
|
PgPort string `env:"PG_PORT" envDefault:"5432"`
|
|||
|
PgHost string `env:"PG_HOST" envDefault:"bd1"`
|
|||
|
PgDBName string `env:"PG_DB_NAME" envDefault:"service1"`
|
|||
|
PgUser string `env:"PG_USER" envDefault:"postgres"`
|
|||
|
PgPwd string `env:"PG_PWD" envDefault:"159753"`
|
|||
|
}
|
|||
|
|
|||
|
func main() {
|
|||
|
cfg := Сonfig{}
|
|||
|
if err := env.Parse(&cfg); err != nil {
|
|||
|
log.Fatalf("failed to retrieve env variables, %v", err)
|
|||
|
}
|
|||
|
if err := Run(cfg); err != nil {
|
|||
|
log.Fatal("error running grpc server ", err)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
type Clerc struct {
|
|||
|
Id uuid.UUID `json:"id" gorm:"type:uuid;default:uuid_generate_v4();primaryKey"`
|
|||
|
Name string `json:"name" gorm:"name"`
|
|||
|
Post string `json:"post" gorm:"post"`
|
|||
|
OfficeId uuid.UUID `json:"office_id" gorm:"office_id"`
|
|||
|
}
|
|||
|
|
|||
|
func InitDb(cfg Сonfig) (*gorm.DB, error) {
|
|||
|
dsn := fmt.Sprintf(
|
|||
|
"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
|
|||
|
cfg.PgHost, cfg.PgUser, cfg.PgPwd, cfg.PgDBName, cfg.PgPort,
|
|||
|
)
|
|||
|
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
|||
|
if err != nil {
|
|||
|
log.Fatal("Cannot to Connect DataBase", err)
|
|||
|
}
|
|||
|
db.AutoMigrate(&Clerc{})
|
|||
|
return gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
|||
|
}
|
|||
|
|
|||
|
type ClercRepository interface {
|
|||
|
Create(ctx context.Context, c *Clerc) error
|
|||
|
Get(ctx context.Context, id uuid.UUID) (*Clerc, error)
|
|||
|
GetList(ctx context.Context) ([]*Clerc, error)
|
|||
|
Update(ctx context.Context, c *Clerc) error
|
|||
|
Delete(ctx context.Context, id uuid.UUID) error
|
|||
|
}
|
|||
|
|
|||
|
type ClercStorage struct {
|
|||
|
db *gorm.DB
|
|||
|
}
|
|||
|
|
|||
|
func NewCs(db *gorm.DB) *ClercStorage {
|
|||
|
return &ClercStorage{
|
|||
|
db: db,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (cs *ClercStorage) Create(ctx context.Context, clerc *Clerc) error {
|
|||
|
return cs.db.WithContext(ctx).Create(clerc).Error
|
|||
|
}
|
|||
|
|
|||
|
func (cs *ClercStorage) Get(ctx context.Context, id uuid.UUID) (*Clerc, error) {
|
|||
|
c := new(Clerc)
|
|||
|
err := cs.db.WithContext(ctx).First(c, id).Error
|
|||
|
return c, err
|
|||
|
}
|
|||
|
|
|||
|
func (cs *ClercStorage) GetList(ctx context.Context) ([]*Clerc, error) {
|
|||
|
clercs := []*Clerc{}
|
|||
|
err := cs.db.WithContext(ctx).Find(&clercs).Error
|
|||
|
return clercs, err
|
|||
|
}
|
|||
|
|
|||
|
func (cs *ClercStorage) Update(ctx context.Context, clerc *Clerc) error {
|
|||
|
return cs.db.WithContext(ctx).Save(clerc).Error
|
|||
|
}
|
|||
|
|
|||
|
func (cs *ClercStorage) Delete(ctx context.Context, id uuid.UUID) error {
|
|||
|
c := new(Clerc)
|
|||
|
return cs.db.WithContext(ctx).Where("id = ?", id).Delete(c).Error
|
|||
|
}
|
|||
|
|
|||
|
type Service struct {
|
|||
|
clercrep ClercRepository
|
|||
|
config Сonfig
|
|||
|
}
|
|||
|
|
|||
|
func NewServ(cfg Сonfig, clercrep ClercRepository) *Service {
|
|||
|
return &Service{
|
|||
|
config: cfg,
|
|||
|
clercrep: clercrep,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) GetHandler() http.Handler {
|
|||
|
router := mux.NewRouter()
|
|||
|
router.HandleFunc("/service1/clerc/post", s.Post).Methods(http.MethodPost)
|
|||
|
router.HandleFunc("/service1/clerc/get", s.Get).Methods(http.MethodGet)
|
|||
|
router.HandleFunc("/service1/clerc/getall", s.GetAll).Methods(http.MethodGet)
|
|||
|
router.HandleFunc("/service1/clerc/put", s.Put).Methods(http.MethodPut)
|
|||
|
router.HandleFunc("/service1/clerc/delete", s.Delete).Methods(http.MethodDelete)
|
|||
|
return router
|
|||
|
}
|
|||
|
|
|||
|
type PostRequest struct {
|
|||
|
Name string `json:"name"`
|
|||
|
Post string `json:"post"`
|
|||
|
OfficeId string `json:"office_id"`
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) Post(w http.ResponseWriter, r *http.Request) {
|
|||
|
req := &PostRequest{}
|
|||
|
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
|||
|
log.Println("Не удалось разкодировать запрос", err)
|
|||
|
w.WriteHeader(http.StatusBadRequest)
|
|||
|
return
|
|||
|
}
|
|||
|
officeUuid, err := uuid.Parse(req.OfficeId)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось конвертировать строку в uuid", err)
|
|||
|
w.WriteHeader(http.StatusBadRequest)
|
|||
|
return
|
|||
|
}
|
|||
|
c := Clerc{
|
|||
|
Name: req.Name,
|
|||
|
Post: req.Post,
|
|||
|
OfficeId: officeUuid,
|
|||
|
}
|
|||
|
err = s.clercrep.Create(r.Context(), &c)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось создать клерка", err)
|
|||
|
w.WriteHeader(http.StatusInternalServerError)
|
|||
|
return
|
|||
|
}
|
|||
|
log.Println("Пытаемся передать id клерка на второй сервис")
|
|||
|
url := "http://nginx/service2/office/patch"
|
|||
|
data := map[string]interface{}{
|
|||
|
"office_id": c.OfficeId.String(),
|
|||
|
"clerc_id": c.Id.String(),
|
|||
|
}
|
|||
|
log.Println(c.OfficeId.String(), c.Id.String())
|
|||
|
payload, err := json.Marshal(data)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось закодировать данные в json")
|
|||
|
w.WriteHeader(http.StatusInternalServerError)
|
|||
|
return
|
|||
|
}
|
|||
|
request, err := http.NewRequest("PATCH", url, bytes.NewBuffer(payload))
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось создать patch запрос")
|
|||
|
w.WriteHeader(http.StatusInternalServerError)
|
|||
|
return
|
|||
|
}
|
|||
|
client := &http.Client{}
|
|||
|
resp, err := client.Do(request)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось отправить patch запрос")
|
|||
|
return
|
|||
|
}
|
|||
|
defer resp.Body.Close()
|
|||
|
w.WriteHeader(http.StatusCreated)
|
|||
|
w.Header().Set("Content-Type", "application/json")
|
|||
|
_ = json.NewEncoder(w).Encode(c)
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) Get(w http.ResponseWriter, r *http.Request) {
|
|||
|
id := r.URL.Query().Get("id")
|
|||
|
uuid, err := uuid.Parse(id)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось конвертировать строку в uuid", err)
|
|||
|
w.WriteHeader(http.StatusBadRequest)
|
|||
|
return
|
|||
|
}
|
|||
|
c, err := s.clercrep.Get(r.Context(), uuid)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось получить запись клерка", err)
|
|||
|
w.WriteHeader(http.StatusNotFound)
|
|||
|
return
|
|||
|
}
|
|||
|
w.WriteHeader(http.StatusOK)
|
|||
|
w.Header().Set("Content-Type", "application/json")
|
|||
|
_ = json.NewEncoder(w).Encode(c)
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) GetAll(w http.ResponseWriter, r *http.Request) {
|
|||
|
clercs, err := s.clercrep.GetList(r.Context())
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось получить записи клерков из бд", err)
|
|||
|
w.WriteHeader(http.StatusNotFound)
|
|||
|
return
|
|||
|
}
|
|||
|
w.WriteHeader(http.StatusOK)
|
|||
|
w.Header().Set("Content-Type", "application/json")
|
|||
|
_ = json.NewEncoder(w).Encode(clercs)
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) Put(w http.ResponseWriter, r *http.Request) {
|
|||
|
req := &Clerc{}
|
|||
|
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
|||
|
log.Println("Не удалось разкодировать запрос", err)
|
|||
|
w.WriteHeader(http.StatusBadRequest)
|
|||
|
return
|
|||
|
}
|
|||
|
err := s.clercrep.Update(r.Context(), req)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось обновить запись о пользователе", err)
|
|||
|
w.WriteHeader(http.StatusNotFound)
|
|||
|
return
|
|||
|
}
|
|||
|
c, err := s.clercrep.Get(r.Context(), req.Id)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось получить запись пользователя из бд", err)
|
|||
|
w.WriteHeader(http.StatusInternalServerError)
|
|||
|
return
|
|||
|
}
|
|||
|
w.WriteHeader(http.StatusOK)
|
|||
|
w.Header().Set("Content-Type", "application/json")
|
|||
|
_ = json.NewEncoder(w).Encode(c)
|
|||
|
}
|
|||
|
|
|||
|
type DeleteRequest struct {
|
|||
|
Id string `json:"id"`
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
|
|||
|
req := &DeleteRequest{}
|
|||
|
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
|||
|
log.Println("Не удалось разкодировать запрос", err)
|
|||
|
w.WriteHeader(http.StatusBadRequest)
|
|||
|
return
|
|||
|
}
|
|||
|
uuid, err := uuid.Parse(req.Id)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось конвертировать строку в uuid", err)
|
|||
|
w.WriteHeader(http.StatusBadRequest)
|
|||
|
return
|
|||
|
}
|
|||
|
err = s.clercrep.Delete(r.Context(), uuid)
|
|||
|
if err != nil {
|
|||
|
log.Println("Не удалось удалить запись о пользователе", err)
|
|||
|
w.WriteHeader(http.StatusNotFound)
|
|||
|
return
|
|||
|
}
|
|||
|
w.WriteHeader(http.StatusOK)
|
|||
|
}
|
|||
|
|
|||
|
func Run(cfg Сonfig) error {
|
|||
|
db, err := InitDb(cfg)
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
|
|||
|
serv := NewServ(cfg, NewCs(db))
|
|||
|
s := &http.Server{
|
|||
|
Addr: ":13999", //"0.0.0.0:%d", cfg.Port),
|
|||
|
Handler: serv.GetHandler(),
|
|||
|
}
|
|||
|
s.SetKeepAlivesEnabled(true)
|
|||
|
ctx, cancel := context.WithCancel(context.Background())
|
|||
|
|
|||
|
go func() {
|
|||
|
log.Printf("starting http server at %d", cfg.Port)
|
|||
|
if err := s.ListenAndServe(); err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
|
|||
|
}()
|
|||
|
|
|||
|
gracefullyShutdown(ctx, cancel, s)
|
|||
|
|
|||
|
return nil
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
func gracefullyShutdown(ctx context.Context, cancel context.CancelFunc, server *http.Server) {
|
|||
|
ch := make(chan os.Signal, 1)
|
|||
|
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
|||
|
defer signal.Stop(ch)
|
|||
|
<-ch
|
|||
|
if err := server.Shutdown(ctx); err != nil {
|
|||
|
log.Print(err)
|
|||
|
}
|
|||
|
cancel()
|
|||
|
}
|