DAS_2023_1/senkin_alexander_lab_3/service2/server_run.go

465 lines
13 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 (
"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 Config struct {
Port string `env:"USER_HTTP_ADDR" envDefault:"13998"`
PgPort string `env:"PG_PORT" envDefault:"5432"`
PgHost string `env:"PG_HOST" envDefault:"bd2"`
PgDBName string `env:"PG_DB_NAME" envDefault:"service2"`
PgUser string `env:"PG_USER" envDefault:"postgres"`
PgPwd string `env:"PG_PWD" envDefault:"159753"`
}
func main() {
cfg := Config{}
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 Office struct {
Id uuid.UUID `json:"id" gorm:"type:uuid;default:uuid_generate_v4();primaryKey"`
Name string `json:"name" gorm:"name"`
Adress string `json:"adress" gorm:"adress"`
Clercs []Clerc `json:"clercs" gorm:"foreignKey:OfficeId;references:Id;constraint:OnDelete:CASCADE"`
}
type Clerc struct {
Id uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
Office Office `gorm:"foreignKey:OfficeId"`
OfficeId uuid.UUID
}
func InitDb(cfg Config) (*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(&Office{}, &Clerc{})
return gorm.Open(postgres.Open(dsn), &gorm.Config{})
}
type OfficeRepository interface {
Create(ctx context.Context, o *Office) error
Get(ctx context.Context, id uuid.UUID) (*Office, error)
GetList(ctx context.Context) ([]*Office, error)
Update(ctx context.Context, o *Office) error
Delete(ctx context.Context, id uuid.UUID) error
}
type ClercRepository interface {
Create(ctx context.Context, c *Clerc) error
GetList(ctx context.Context) ([]*Clerc, 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) GetList(ctx context.Context) ([]*Clerc, error) {
clercs := []*Clerc{}
err := cs.db.WithContext(ctx).Find(&clercs).Error
return clercs, err
}
type OfficeStorage struct {
db *gorm.DB
}
func NewOs(db *gorm.DB) *OfficeStorage {
return &OfficeStorage{
db: db,
}
}
func (os *OfficeStorage) Create(ctx context.Context, clerc *Office) error {
return os.db.WithContext(ctx).Create(clerc).Error
}
func (os *OfficeStorage) Get(ctx context.Context, id uuid.UUID) (*Office, error) {
c := new(Office)
err := os.db.WithContext(ctx).First(c, id).Error
return c, err
}
func (os *OfficeStorage) GetList(ctx context.Context) ([]*Office, error) {
offices := []*Office{}
err := os.db.WithContext(ctx).Find(&offices).Error
return offices, err
}
func (os *OfficeStorage) Update(ctx context.Context, office *Office) error {
return os.db.WithContext(ctx).Save(office).Error
}
func (os *OfficeStorage) Delete(ctx context.Context, id uuid.UUID) error {
c := new(Office)
return os.db.WithContext(ctx).Where("id = ?", id).Delete(c).Error
}
type Service struct {
officerep OfficeRepository
clercrep ClercRepository
config Config
}
func NewServ(cfg Config, officerep OfficeRepository, clercrep ClercRepository) *Service {
return &Service{
config: cfg,
officerep: officerep,
clercrep: clercrep,
}
}
func (s *Service) GetHandler() http.Handler {
router := mux.NewRouter()
router.HandleFunc("/service2/office/post", s.Post).Methods(http.MethodPost)
router.HandleFunc("/service2/office/get", s.Get).Methods(http.MethodGet)
router.HandleFunc("/service2/office/getall", s.GetAll).Methods(http.MethodGet)
router.HandleFunc("/service2/office/put", s.Put).Methods(http.MethodPut)
router.HandleFunc("/service2/office/delete", s.Delete).Methods(http.MethodDelete)
router.HandleFunc("/service2/office/patch", s.Patch).Methods(http.MethodPatch)
return router
}
type PostRequest struct {
Name string `json:"name"`
Adress string `json:"adress"`
}
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
}
o := Office{
Name: req.Name,
Adress: req.Adress,
}
err := s.officerep.Create(r.Context(), &o)
if err != nil {
log.Println("Не удалось создать офис", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(o)
}
type ClercResponse struct {
Clercs []ClercReq `json:"clerks"`
}
type ClercReq struct {
Id string `json:"id"`
Name string `json:"name"`
Post string `json:"post"`
OfficeId string `json:"office_id"`
}
type GetResponse struct {
Id string `json:"id"`
Name string `json:"name"`
Adress string `json:"adress"`
Clercs []ClercReq `json:"clercs"`
}
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
}
o, err := s.officerep.Get(r.Context(), uuid)
if err != nil {
log.Println("Не удалось получить запись офиса", err)
w.WriteHeader(http.StatusNotFound)
return
}
url := "http://nginx/service1/clerc/getall"
response, err := http.Get(url)
if err != nil {
fmt.Println("Error:", err)
return
}
defer response.Body.Close()
/*body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Println("Не удалось прочитать body из Get response с первого сервиса", err)
w.WriteHeader(http.StatusInternalServerError)
return
}*/
var clercsreq []ClercReq
if err := json.NewDecoder(response.Body).Decode(&clercsreq); err != nil {
log.Println("Не удалось разпарсить ответ с 1 сервиса", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
//var clerksResponse ClercResponse
/*err = json.Unmarshal(body, clercsreq)
if err != nil {
log.Println("Не удалось разпарсить ответ с 1 сервиса", err)
w.WriteHeader(http.StatusInternalServerError)
return
}*/
cs, err := s.clercrep.GetList(r.Context())
if err != nil {
log.Println("Не удалось получить записи клерков из бд", err)
w.WriteHeader(http.StatusNotFound)
return
}
clercsid := make([]string, len(cs))
for _, c := range cs {
if o.Id == c.OfficeId {
clercsid = append(clercsid, c.Id.String())
}
}
clercs := make([]ClercReq, len(o.Clercs))
for _, clercid := range clercsid {
for _, c := range clercsreq {
if clercid == c.Id {
clercs = append(clercs, c)
}
}
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(&GetResponse{
Id: o.Id.String(),
Name: o.Name,
Adress: o.Adress,
Clercs: clercs,
})
}
func (s *Service) GetAll(w http.ResponseWriter, r *http.Request) {
offices, err := s.officerep.GetList(r.Context())
if err != nil {
log.Println("Не удалось получить записи офисов из бд", err)
w.WriteHeader(http.StatusNotFound)
return
}
clercs, err := s.clercrep.GetList(r.Context())
if err != nil {
log.Println("Не удалось получить записи клерков из бд", err)
w.WriteHeader(http.StatusNotFound)
return
}
//log.Println(clercs)
for i, o := range offices {
for _, c := range clercs {
if o.Id == c.OfficeId {
offices[i].Clercs = append(offices[i].Clercs, *c)
}
}
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(offices)
}
type PatchRequest struct {
OfficeId string `json:"office_id"`
ClercId string `json:"clerc_id"`
}
func (s *Service) Patch(w http.ResponseWriter, r *http.Request) {
log.Println("Использована функция добавления клерка в офис")
req := &PatchRequest{}
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
log.Println("Не удалось разкодировать запрос", err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Println(req)
uuidOffice, err := uuid.Parse(req.OfficeId)
if err != nil {
log.Println("Не удалось преобразовать строку в uuid", err)
w.WriteHeader(http.StatusBadRequest)
return
}
uuidClerc, err := uuid.Parse(req.ClercId)
if err != nil {
log.Println("Не удалось преобразовать строку в uuid", err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Println(uuidOffice)
o, err := s.officerep.Get(r.Context(), uuidOffice)
if err != nil {
log.Println("Не удалось получить запись офиса из бд", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
log.Println(*o)
clerc := &Clerc{
Id: uuidClerc,
Office: *o,
}
/*o.Clercs = append(o.Clercs, *clerc)
err = s.officerep.Update(r.Context(), o)
if err != nil {
log.Println("Не удалось обновить информации об офисе")
w.WriteHeader(http.StatusInternalServerError)
return
}*/
err = s.clercrep.Create(r.Context(), clerc)
if err != nil {
log.Println("Не удалось создать запись о клерке", err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Println(*clerc)
w.WriteHeader(http.StatusOK)
}
type PutRequest struct {
Id string `json:"id"`
Name string `json:"name"`
Adress string `json:"adress"`
}
func (s *Service) Put(w http.ResponseWriter, r *http.Request) {
req := &PutRequest{}
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
}
o, err := s.officerep.Get(r.Context(), uuid)
if err != nil {
log.Println("Не удалось получить запись офиса из бд", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
o.Name = req.Name
o.Adress = req.Adress
err = s.officerep.Update(r.Context(), o)
if err != nil {
log.Println("Не удалось обновить запись об офисе", err)
w.WriteHeader(http.StatusNotFound)
return
}
o2, err := s.officerep.Get(r.Context(), uuid)
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(o2)
}
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.officerep.Delete(r.Context(), uuid)
if err != nil {
log.Println("Не удалось удалить запись об офисе", err)
w.WriteHeader(http.StatusNotFound)
return
}
w.WriteHeader(http.StatusOK)
}
func Run(cfg Config) error {
db, err := InitDb(cfg)
if err != nil {
return err
}
serv := NewServ(cfg, NewOs(db), NewCs(db))
s := &http.Server{
Addr: ":13998", //"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()
}