DAS_2023_1/senkin_alexander_lab_3/service1/server_run.go

305 lines
8.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}