Merge pull request 'senkin_alexander_lab_3 is ready' (#9) from senkin_alexander_lab_3 into main
Reviewed-on: http://student.git.athene.tech/Alexey/DAS_2023_1/pulls/9
1
senkin_alexander_lab_3/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
./idea
|
52
senkin_alexander_lab_3/README.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Лабораторная работа №3 - REST API, Gateway и синхронный обмен между микросервисами
|
||||||
|
Цель: изучение шаблона проектирования gateway, построения синхронного обмена между микросервисами и архитектурного стиля RESTful API.
|
||||||
|
|
||||||
|
Задачи:
|
||||||
|
- Создать 2 микросервиса, реализующих CRUD на связанных сущностях.
|
||||||
|
- Реализовать механизм синхронного обмена сообщениями между микросервисами.
|
||||||
|
- Реализовать шлюз на основе прозрачного прокси-сервера nginx.
|
||||||
|
|
||||||
|
# Разработка двух распределенных приложений
|
||||||
|
Было решено на первом сервисе(service1) сделать реализацию рабочего(clerc), на втором сервисе(service2) сделать реализацию офиса(office), которая хранит uuid работников.
|
||||||
|
Было решено сделать как принято в микросервисной архитектуре бд на микросервис, поэтому реализовано 2 базы данных на PostgreSQL.
|
||||||
|
Также реализован nginx - proxy сервер на общения сервисов между друг другом, а также для доступа к сервам снаружи через ngnix.
|
||||||
|
|
||||||
|
![img.png](img.png)
|
||||||
|
|
||||||
|
# Запуск
|
||||||
|
Запуск контейнеров производится командой "docker-compose up -d"
|
||||||
|
|
||||||
|
# Работа программы
|
||||||
|
- Создание репозиторий service1 и service2 для сервисов, bd1 и bd2 для образов баз данных
|
||||||
|
- Создание go.mod для подтягивания зависимостей.
|
||||||
|
- Описание Dockerfile для создания образов для сервисов, одинковые для обоих сервисов:
|
||||||
|
- ![img_1.png](img_1.png)
|
||||||
|
- Описание Dockerfile для создания образов для бд, одинаковые для обоих:
|
||||||
|
- ![img_2.png](img_2.png)
|
||||||
|
- Создание файлов server_run.go с логикой работ сервисов.
|
||||||
|
- Создаем файл nginx.conf с конфигурацией работы nginx:
|
||||||
|
- ![img_3.png](img_3.png)
|
||||||
|
- Создаем файл docker-compose.yml для описания запуска контейнеров в одной сети:
|
||||||
|
- ![img_4.png](img_4.png)
|
||||||
|
- ![img_5.png](img_5.png)
|
||||||
|
- Сборка и запуска контейнеров.
|
||||||
|
- ![img_6.png](img_6.png)
|
||||||
|
- ![img_7.png](img_7.png)
|
||||||
|
- Проверка работы докер сети и контейнеров, все работает стабильно:
|
||||||
|
- ![img_8.png](img_8.png)
|
||||||
|
- Делаем запросы через insomnia:
|
||||||
|
- ![img_9.png](img_9.png)
|
||||||
|
- ![img_10.png](img_10.png)
|
||||||
|
- ![img_11.png](img_11.png)
|
||||||
|
- ![img_12.png](img_12.png)
|
||||||
|
- ![img_13.png](img_13.png)
|
||||||
|
- ![img_14.png](img_14.png)
|
||||||
|
- ![img_15.png](img_15.png)
|
||||||
|
- ![img_16.png](img_16.png)
|
||||||
|
- ![img_17.png](img_17.png)
|
||||||
|
- ![img_18.png](img_18.png)
|
||||||
|
- Все запросы работают.
|
||||||
|
|
||||||
|
# Видео
|
||||||
|
Видео с разбором лабораторной работы - https://youtu.be/RQCwqW9jwH4
|
||||||
|
|
3
senkin_alexander_lab_3/bd1/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM postgres:latest
|
||||||
|
|
||||||
|
COPY init.sql /docker-entrypoint-initdb.d/init.sql
|
2
senkin_alexander_lab_3/bd1/init.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
-- init.sql
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
3
senkin_alexander_lab_3/bd2/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM postgres:latest
|
||||||
|
|
||||||
|
COPY init.sql /docker-entrypoint-initdb.d/init.sql
|
2
senkin_alexander_lab_3/bd2/init.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
-- init.sql
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
53
senkin_alexander_lab_3/docker-compose.yml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
services:
|
||||||
|
bd1:
|
||||||
|
build:
|
||||||
|
context: /bd1
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: "service1"
|
||||||
|
POSTGRES_USER: "postgres"
|
||||||
|
POSTGRES_PASSWORD: "159753"
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
bd2:
|
||||||
|
build:
|
||||||
|
context: /bd2
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: "service2"
|
||||||
|
POSTGRES_USER: "postgres"
|
||||||
|
POSTGRES_PASSWORD: "159753"
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
service1:
|
||||||
|
build:
|
||||||
|
context: /service1
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
depends_on:
|
||||||
|
- bd1
|
||||||
|
service2:
|
||||||
|
build:
|
||||||
|
context: /service2
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
depends_on:
|
||||||
|
- bd2
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
depends_on:
|
||||||
|
- service1
|
||||||
|
- service2
|
||||||
|
|
||||||
|
networks:
|
||||||
|
network:
|
||||||
|
driver: bridge
|
||||||
|
|
BIN
senkin_alexander_lab_3/img.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
senkin_alexander_lab_3/img_1.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
senkin_alexander_lab_3/img_10.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
senkin_alexander_lab_3/img_11.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
senkin_alexander_lab_3/img_12.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
senkin_alexander_lab_3/img_13.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
senkin_alexander_lab_3/img_14.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
senkin_alexander_lab_3/img_15.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
senkin_alexander_lab_3/img_16.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
senkin_alexander_lab_3/img_17.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
senkin_alexander_lab_3/img_18.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
senkin_alexander_lab_3/img_2.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
senkin_alexander_lab_3/img_3.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
senkin_alexander_lab_3/img_4.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
senkin_alexander_lab_3/img_5.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
senkin_alexander_lab_3/img_6.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
senkin_alexander_lab_3/img_7.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
senkin_alexander_lab_3/img_8.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
senkin_alexander_lab_3/img_9.png
Normal file
After Width: | Height: | Size: 12 KiB |
20
senkin_alexander_lab_3/nginx.conf
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location /service1/ {
|
||||||
|
proxy_pass http://service1:13999;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /service2/ {
|
||||||
|
proxy_pass http://service2:13998;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
14
senkin_alexander_lab_3/service1/Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM golang:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY go.mod .
|
||||||
|
COPY go.sum .
|
||||||
|
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY server_run.go .
|
||||||
|
|
||||||
|
RUN go build -o myapp
|
||||||
|
|
||||||
|
CMD ["/app/myapp"]
|
18
senkin_alexander_lab_3/service1/go.mod
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
module DAS_2023_1/senkin_alexander_lab_3/service1
|
||||||
|
|
||||||
|
go 1.21.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0 // indirect
|
||||||
|
github.com/google/uuid v1.4.0 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
golang.org/x/crypto v0.14.0 // indirect
|
||||||
|
golang.org/x/text v0.13.0 // indirect
|
||||||
|
gorm.io/driver/postgres v1.5.4 // indirect
|
||||||
|
gorm.io/gorm v1.25.5 // indirect
|
||||||
|
)
|
31
senkin_alexander_lab_3/service1/go.sum
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
github.com/caarlos0/env/v8 v8.0.0 h1:POhxHhSpuxrLMIdvTGARuZqR4Jjm8AYmoi/JKlcScs0=
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0/go.mod h1:7K4wMY9bH0esiXSSHlfHLX5xKGQMnkH5Fk4TDSSSzfo=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||||
|
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||||
|
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo=
|
||||||
|
gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0=
|
||||||
|
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
||||||
|
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
304
senkin_alexander_lab_3/service1/server_run.go
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
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()
|
||||||
|
}
|
14
senkin_alexander_lab_3/service2/Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM golang:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY go.mod .
|
||||||
|
COPY go.sum .
|
||||||
|
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY server_run.go .
|
||||||
|
|
||||||
|
RUN go build -o myapp
|
||||||
|
|
||||||
|
CMD ["/app/myapp"]
|
18
senkin_alexander_lab_3/service2/go.mod
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
module DAS_2023_1/senkin_alexander_lab_3/service2
|
||||||
|
|
||||||
|
go 1.21.3
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0 // indirect
|
||||||
|
github.com/google/uuid v1.4.0 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
golang.org/x/crypto v0.14.0 // indirect
|
||||||
|
golang.org/x/text v0.13.0 // indirect
|
||||||
|
gorm.io/driver/postgres v1.5.4 // indirect
|
||||||
|
gorm.io/gorm v1.25.5 // indirect
|
||||||
|
)
|
31
senkin_alexander_lab_3/service2/go.sum
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
github.com/caarlos0/env/v8 v8.0.0 h1:POhxHhSpuxrLMIdvTGARuZqR4Jjm8AYmoi/JKlcScs0=
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0/go.mod h1:7K4wMY9bH0esiXSSHlfHLX5xKGQMnkH5Fk4TDSSSzfo=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||||
|
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||||
|
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo=
|
||||||
|
gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0=
|
||||||
|
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
||||||
|
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
464
senkin_alexander_lab_3/service2/server_run.go
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
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()
|
||||||
|
}
|