[hw-3] loms service
3
.gitignore
vendored
@@ -2,4 +2,5 @@
|
||||
.vscode
|
||||
bin
|
||||
.coverage
|
||||
allure-results
|
||||
allure-results
|
||||
vendor-proto/*
|
||||
11
Makefile
@@ -6,6 +6,8 @@ include make/generate.mk
|
||||
PKGS = $(shell go list ./... | grep -vE 'mock|config|generated|header|document|internal/pb')
|
||||
INTEGRATION_TAG = integration
|
||||
|
||||
.PHONY: lint, coverage
|
||||
|
||||
lint: cart-lint loms-lint notifier-lint comments-lint
|
||||
|
||||
build: cart-build loms-build notifier-build comments-build
|
||||
@@ -13,15 +15,20 @@ build: cart-build loms-build notifier-build comments-build
|
||||
coverage: cart-coverage loms-coverage notifier-coverage comments-coverage
|
||||
|
||||
generate: cart-generate loms-generate notifier-generate comments-generate
|
||||
cd pkg && go mod tidy
|
||||
|
||||
run-all:
|
||||
echo "starting build"
|
||||
docker-compose up --build
|
||||
|
||||
.PHONY: .integration-test
|
||||
integration-test:
|
||||
ALLURE_OUTPUT_PATH=$(shell pwd) go test -v -tags=$(INTEGRATION_TAG) ./cart/tests/integration
|
||||
ALLURE_OUTPUT_PATH=$(shell pwd)/allure-results ALLURE_OUTPUT_FOLDER=cart go test -v -tags=$(INTEGRATION_TAG) ./cart/tests/integration
|
||||
ALLURE_OUTPUT_PATH=$(shell pwd)/allure-results ALLURE_OUTPUT_FOLDER=loms go test -v -tags=$(INTEGRATION_TAG) ./loms/tests/integration
|
||||
|
||||
bench:
|
||||
go test -bench=BenchmarkInMemoryRepository -benchmem ./cart/internal/domain/cart/repository -benchtime 3s
|
||||
|
||||
.PHONY: lint, coverage
|
||||
.PHONY: .serve-swagger
|
||||
.serve-swagger:
|
||||
bin/swagger serve api/openapiv2/loms/v1/loms.swagger.json --no-open
|
||||
|
||||
125
api/loms/v1/loms.proto
Normal file
@@ -0,0 +1,125 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "validate/validate.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
|
||||
option go_package = "route256/pkg/api/loms/v1;loms";
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
|
||||
info: {
|
||||
title: "LOMS Service";
|
||||
version: "1.0.0";
|
||||
};
|
||||
schemes: HTTP;
|
||||
schemes: HTTPS;
|
||||
consumes: "application/json";
|
||||
produces: "application/json";
|
||||
};
|
||||
|
||||
service LOMS {
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_tag) = {
|
||||
description: "LOMS Service"
|
||||
external_docs: {
|
||||
url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/examples/internal/proto/examplepb/a_bit_of_everything.proto";
|
||||
description: "Find out more about grpc-gateway";
|
||||
}
|
||||
};
|
||||
|
||||
rpc OrderCreate(OrderCreateRequest) returns (OrderCreateResponse) {
|
||||
option(google.api.http) = {
|
||||
post: "/order/create"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
rpc OrderInfo(OrderInfoRequest) returns (OrderInfoResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/order/info"
|
||||
};
|
||||
}
|
||||
|
||||
rpc OrderPay(OrderPayRequest) returns (google.protobuf.Empty) {
|
||||
option (google.api.http) = {
|
||||
post: "/order/pay"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
rpc OrderCancel(OrderCancelRequest) returns (google.protobuf.Empty) {
|
||||
option (google.api.http) = {
|
||||
post: "/order/cancel"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
rpc StocksInfo(StocksInfoRequest) returns (StocksInfoResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/stock/info"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
message OrderItem {
|
||||
int64 sku = 1 [(validate.rules).int64 = {gt: 0}];
|
||||
uint32 count = 2 [(validate.rules).uint32 = {gt: 0}];
|
||||
}
|
||||
|
||||
// OrderCreate
|
||||
|
||||
message OrderCreateRequest {
|
||||
int64 user_id = 1 [
|
||||
(validate.rules).int64 = {gt: 0}
|
||||
];
|
||||
repeated OrderItem items = 2 [
|
||||
(validate.rules).repeated = {min_items: 1}
|
||||
];
|
||||
}
|
||||
|
||||
message OrderCreateResponse {
|
||||
int64 orderId = 1;
|
||||
}
|
||||
|
||||
// OrderInfo
|
||||
|
||||
message OrderInfoRequest {
|
||||
int64 orderId = 1 [(validate.rules).int64 = {gt: 0}];
|
||||
}
|
||||
|
||||
message OrderInfoResponse {
|
||||
string status = 1;
|
||||
int64 user_id = 2;
|
||||
repeated OrderItem items = 3;
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
ORDER_STATUS_UNSPECIFIED = 0;
|
||||
ORDER_STATUS_NEW = 1;
|
||||
ORDER_STATUS_AWAITING_PAYMENT = 2;
|
||||
ORDER_STATUS_FAILED = 3;
|
||||
ORDER_STATUS_PAYED = 4;
|
||||
ORDER_STATUS_CANCELLED = 5;
|
||||
}
|
||||
|
||||
// OrderPay
|
||||
|
||||
message OrderPayRequest {
|
||||
int64 order_id = 1 [(validate.rules).int64 = {gt: 0}];
|
||||
}
|
||||
|
||||
// OrderCancel
|
||||
|
||||
message OrderCancelRequest {
|
||||
int64 order_id = 1 [(validate.rules).int64 = {gt: 0}];
|
||||
}
|
||||
|
||||
// StocksInfo
|
||||
|
||||
message StocksInfoRequest {
|
||||
int64 sku = 1 [(validate.rules).int64 = {gt: 0}];
|
||||
}
|
||||
|
||||
message StocksInfoResponse {
|
||||
uint32 count = 1;
|
||||
}
|
||||
303
api/openapiv2/loms/v1/loms.swagger.json
Normal file
@@ -0,0 +1,303 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "LOMS Service",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "LOMS",
|
||||
"description": "LOMS Service",
|
||||
"externalDocs": {
|
||||
"description": "Find out more about grpc-gateway",
|
||||
"url": "https://github.com/grpc-ecosystem/grpc-gateway/blob/main/examples/internal/proto/examplepb/a_bit_of_everything.proto"
|
||||
}
|
||||
}
|
||||
],
|
||||
"schemes": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"paths": {
|
||||
"/order/cancel": {
|
||||
"post": {
|
||||
"operationId": "LOMS_OrderCancel",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/OrderCancelRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"LOMS"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/order/create": {
|
||||
"post": {
|
||||
"operationId": "LOMS_OrderCreate",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/OrderCreateResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/OrderCreateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"LOMS"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/order/info": {
|
||||
"get": {
|
||||
"operationId": "LOMS_OrderInfo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/OrderInfoResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "orderId",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"LOMS"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/order/pay": {
|
||||
"post": {
|
||||
"operationId": "LOMS_OrderPay",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/OrderPayRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"LOMS"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/stock/info": {
|
||||
"get": {
|
||||
"operationId": "LOMS_StocksInfo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/StocksInfoResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sku",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"LOMS"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"OrderCancelRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"orderId": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"OrderCreateRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"userId": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/OrderItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"OrderCreateResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"orderId": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"OrderInfoResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"userId": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/OrderItem"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"OrderItem": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sku": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
},
|
||||
"count": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"OrderPayRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"orderId": {
|
||||
"type": "string",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StocksInfoResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"protobufAny": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"@type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": {}
|
||||
},
|
||||
"rpcStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"details": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/protobufAny"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,21 @@
|
||||
FROM golang:1.23.1-alpine as builder
|
||||
FROM golang:1.23.9-alpine as builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
COPY cart/go.mod go.mod
|
||||
COPY cart/go.sum go.sum
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
WORKDIR cart
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /server ./cmd/server/main.go
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder server /bin/server
|
||||
COPY configs/values_local.yaml /bin/config/values_local.yaml
|
||||
COPY cart/configs/values_local.yaml /bin/config/values_local.yaml
|
||||
|
||||
ENV CONFIG_FILE=/bin/config/values_local.yaml
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ go 1.23.9
|
||||
require (
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
google.golang.org/grpc v1.72.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/gojuno/minimock/v3 v3.4.5 h1:Jcb0tEYZvVlQNtAAYpg3jCOoSwss2c1/rNugYTzj304=
|
||||
github.com/gojuno/minimock/v3 v3.4.5/go.mod h1:o9F8i2IT8v3yirA7mmdpNGzh1WNesm6iQakMtQV6KiE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
@@ -147,6 +149,8 @@ go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCRE
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI=
|
||||
|
||||
@@ -9,14 +9,19 @@ import (
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"route256/cart/internal/app/server"
|
||||
"route256/cart/internal/domain/cart/repository"
|
||||
"route256/cart/internal/domain/cart/service"
|
||||
product_service "route256/cart/internal/domain/products/service"
|
||||
loms_service "route256/cart/internal/clients/loms"
|
||||
product_service "route256/cart/internal/clients/products"
|
||||
"route256/cart/internal/domain/repository"
|
||||
"route256/cart/internal/domain/service"
|
||||
"route256/cart/internal/infra/config"
|
||||
"route256/cart/internal/infra/http/middlewares"
|
||||
"route256/cart/internal/infra/http/round_trippers"
|
||||
|
||||
pbLOMS "route256/pkg/api/loms/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -39,9 +44,9 @@ func NewApp(configPath string) (*App, error) {
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
|
||||
if c.Service.LogLevel != "" {
|
||||
level, err := zerolog.ParseLevel(c.Service.LogLevel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unknown log level `%s` provided: %w", c.Service.LogLevel, err)
|
||||
level, logErr := zerolog.ParseLevel(c.Service.LogLevel)
|
||||
if logErr != nil {
|
||||
return nil, fmt.Errorf("unknown log level `%s` provided: %w", c.Service.LogLevel, logErr)
|
||||
}
|
||||
|
||||
zerolog.SetGlobalLevel(level)
|
||||
@@ -52,7 +57,13 @@ func NewApp(configPath string) (*App, error) {
|
||||
app := &App{
|
||||
config: c,
|
||||
}
|
||||
app.server.Handler = app.BootstrapHandlers(app.setupCartService())
|
||||
|
||||
service, err := app.setupCartService()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app.server.Handler = app.BootstrapHandlers(service)
|
||||
|
||||
return app, nil
|
||||
}
|
||||
@@ -70,7 +81,8 @@ func (app *App) ListenAndServe() error {
|
||||
return app.server.Serve(l)
|
||||
}
|
||||
|
||||
func (app *App) setupCartService() *service.CartService {
|
||||
func (app *App) setupCartService() (*service.CartService, error) {
|
||||
// Product service client
|
||||
transport := http.DefaultTransport
|
||||
transport = round_trippers.NewLogRoundTripper(transport)
|
||||
transport = round_trippers.NewRetryRoundTripper(transport, productsRetryAttemptsDefault, productsInitialDelaySecDefault)
|
||||
@@ -86,10 +98,21 @@ func (app *App) setupCartService() *service.CartService {
|
||||
fmt.Sprintf("%s:%s", app.config.ProductService.Host, app.config.ProductService.Port),
|
||||
)
|
||||
|
||||
// LOMS service client
|
||||
conn, err := grpc.NewClient(
|
||||
fmt.Sprintf("%s:%s", app.config.LomsService.Host, app.config.LomsService.Port),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("grpc.NewClient: %w", err)
|
||||
}
|
||||
|
||||
lomsClient := pbLOMS.NewLOMSClient(conn)
|
||||
lomsService := loms_service.NewLomsService(lomsClient)
|
||||
|
||||
const userCartCap = 100
|
||||
cartRepository := repository.NewInMemoryRepository(userCartCap)
|
||||
|
||||
return service.NewCartService(cartRepository, productService)
|
||||
return service.NewCartService(cartRepository, productService, lomsService), nil
|
||||
}
|
||||
|
||||
func (app *App) BootstrapHandlers(cartService *service.CartService) http.Handler {
|
||||
@@ -97,6 +120,7 @@ func (app *App) BootstrapHandlers(cartService *service.CartService) http.Handler
|
||||
|
||||
mx := http.NewServeMux()
|
||||
mx.HandleFunc("POST /user/{user_id}/cart/{sku_id}", s.AddItemHandler)
|
||||
mx.HandleFunc("POST /checkout/{user_id}", s.CheckoutHandler)
|
||||
mx.HandleFunc("GET /user/{user_id}/cart", s.GetItemsByUserIDHandler)
|
||||
mx.HandleFunc("DELETE /user/{user_id}/cart/{sku_id}", s.DeleteItemHandler)
|
||||
mx.HandleFunc("DELETE /user/{user_id}/cart", s.DeleteItemsByUserIDHandler)
|
||||
|
||||
@@ -13,12 +13,12 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type CreateReviewRequest struct {
|
||||
type AddItemRequest struct {
|
||||
Count uint32 `json:"count" validate:"required,gt=0"`
|
||||
}
|
||||
|
||||
func (s *Server) AddItemHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var request CreateReviewRequest
|
||||
var request AddItemRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||
makeErrorResponse(w, err, http.StatusBadRequest)
|
||||
|
||||
@@ -79,7 +79,7 @@ func (s *Server) AddItemHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if err := s.cartService.AddItem(r.Context(), uid, item); err != nil {
|
||||
switch {
|
||||
case errors.Is(err, model.ErrProductNotFound):
|
||||
case errors.Is(err, model.ErrProductNotFound), errors.Is(err, model.ErrNotEnoughStocks):
|
||||
makeErrorResponse(w, err, http.StatusPreconditionFailed)
|
||||
|
||||
log.Trace().Err(err).Msgf("product does not exist")
|
||||
|
||||
58
cart/internal/app/server/checkout_handler.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"route256/cart/internal/domain/entity"
|
||||
"route256/cart/internal/domain/model"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type CheckoutResponse struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
}
|
||||
|
||||
func (s *Server) CheckoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
strUserID := r.PathValue("user_id")
|
||||
userID, err := strconv.ParseInt(strUserID, 10, 64)
|
||||
if err != nil || userID <= 0 {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("user_id must be greater than 0")
|
||||
}
|
||||
|
||||
makeErrorResponse(w, err, http.StatusBadRequest)
|
||||
|
||||
log.Trace().Err(err).Msgf("user_id=`%s`", strUserID)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
orderID, err := s.cartService.CheckoutUserCart(r.Context(), entity.UID(userID))
|
||||
switch {
|
||||
case errors.Is(err, model.ErrCartNotFound):
|
||||
makeErrorResponse(w, err, http.StatusNotFound)
|
||||
|
||||
return
|
||||
case err != nil:
|
||||
makeErrorResponse(w, err, http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
resp := CheckoutResponse{
|
||||
OrderID: orderID,
|
||||
}
|
||||
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
makeErrorResponse(w, err, http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ type CartService interface {
|
||||
GetItemsByUserID(ctx context.Context, userID entity.UID) (*model.Cart, error)
|
||||
DeleteItem(ctx context.Context, userID entity.UID, sku entity.Sku) error
|
||||
DeleteItemsByUserID(ctx context.Context, userID entity.UID) error
|
||||
CheckoutUserCart(ctx context.Context, userID entity.UID) (int64, error)
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
|
||||
56
cart/internal/clients/loms/service.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package loms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"route256/cart/internal/domain/entity"
|
||||
"route256/cart/internal/domain/model"
|
||||
|
||||
pbLoms "route256/pkg/api/loms/v1"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
grpcClient pbLoms.LOMSClient
|
||||
}
|
||||
|
||||
func NewLomsService(grpcClient pbLoms.LOMSClient) *Service {
|
||||
return &Service{
|
||||
grpcClient: grpcClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) OrderCreate(ctx context.Context, cart *model.Cart) (int64, error) {
|
||||
items := make([]*pbLoms.OrderItem, len(cart.Items))
|
||||
for i, item := range cart.Items {
|
||||
items[i] = &pbLoms.OrderItem{
|
||||
Sku: int64(item.Product.Sku),
|
||||
Count: item.Count,
|
||||
}
|
||||
}
|
||||
|
||||
req := &pbLoms.OrderCreateRequest{
|
||||
UserId: int64(cart.UserID),
|
||||
Items: items,
|
||||
}
|
||||
|
||||
resp, err := s.grpcClient.OrderCreate(ctx, req)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("grpcClient.OrderCreate: %w", err)
|
||||
}
|
||||
|
||||
return resp.OrderId, nil
|
||||
}
|
||||
|
||||
func (s *Service) StocksInfo(ctx context.Context, sku entity.Sku) (uint32, error) {
|
||||
req := &pbLoms.StocksInfoRequest{
|
||||
Sku: int64(sku),
|
||||
}
|
||||
|
||||
resp, err := s.grpcClient.StocksInfo(ctx, req)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("grpcClient.StocksInfo: %w", err)
|
||||
}
|
||||
|
||||
return resp.Count, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package service
|
||||
package products
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -1,7 +1,7 @@
|
||||
package entity
|
||||
|
||||
type (
|
||||
UID uint64
|
||||
UID int64
|
||||
Sku int64
|
||||
)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import "errors"
|
||||
|
||||
var (
|
||||
ErrProductNotFound = errors.New("invalid sku")
|
||||
ErrNotEnoughStocks = errors.New("not enough stocks")
|
||||
|
||||
ErrCartNotFound = errors.New("cart not found")
|
||||
ErrItemNotFoundInCart = errors.New("item not found in cart")
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"route256/cart/internal/domain/entity"
|
||||
"route256/cart/internal/domain/model"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
//go:generate minimock -i Repository -o ./mock -s _mock.go
|
||||
@@ -24,15 +24,23 @@ type ProductService interface {
|
||||
GetProductBySku(ctx context.Context, sku entity.Sku) (*model.Product, error)
|
||||
}
|
||||
|
||||
type CartService struct {
|
||||
repository Repository
|
||||
productService ProductService
|
||||
type LomsService interface {
|
||||
OrderCreate(ctx context.Context, cart *model.Cart) (int64, error)
|
||||
StocksInfo(ctx context.Context, sku entity.Sku) (uint32, error)
|
||||
}
|
||||
|
||||
func NewCartService(repository Repository, productService ProductService) *CartService {
|
||||
type CartService struct {
|
||||
repository Repository
|
||||
|
||||
productService ProductService
|
||||
lomsService LomsService
|
||||
}
|
||||
|
||||
func NewCartService(repository Repository, productService ProductService, lomsService LomsService) *CartService {
|
||||
return &CartService{
|
||||
repository: repository,
|
||||
productService: productService,
|
||||
lomsService: lomsService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +58,15 @@ func (s *CartService) AddItem(ctx context.Context, userID entity.UID, item *mode
|
||||
return fmt.Errorf("productService.GetProductBySku: %w", err)
|
||||
}
|
||||
|
||||
count, err := s.lomsService.StocksInfo(ctx, item.Product.Sku)
|
||||
if err != nil {
|
||||
return fmt.Errorf("lomsService.StocksInfo: %w", err)
|
||||
}
|
||||
|
||||
if count < item.Count {
|
||||
return model.ErrNotEnoughStocks
|
||||
}
|
||||
|
||||
if err := s.repository.AddItem(ctx, userID, item); err != nil {
|
||||
return fmt.Errorf("repository.AddItemToCart: %w", err)
|
||||
}
|
||||
@@ -170,3 +187,25 @@ func (s *CartService) DeleteItemsByUserID(ctx context.Context, userID entity.UID
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CartService) CheckoutUserCart(ctx context.Context, userID entity.UID) (int64, error) {
|
||||
if userID <= 0 {
|
||||
return 0, fmt.Errorf("userID invalid")
|
||||
}
|
||||
|
||||
cart, err := s.GetItemsByUserID(ctx, entity.UID(userID))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
orderID, err := s.lomsService.OrderCreate(ctx, cart)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("lomsService.OrderCreate: %w", err)
|
||||
}
|
||||
|
||||
if err := s.DeleteItemsByUserID(ctx, userID); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return orderID, nil
|
||||
}
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"route256/cart/internal/domain/cart/service/mock"
|
||||
"route256/cart/internal/domain/entity"
|
||||
"route256/cart/internal/domain/model"
|
||||
"route256/cart/internal/domain/service/mock"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -19,9 +19,9 @@ const (
|
||||
validName = "some product name"
|
||||
)
|
||||
|
||||
type ProductServiceFake struct{}
|
||||
type productServiceFake struct{}
|
||||
|
||||
func (f *ProductServiceFake) GetProductBySku(_ context.Context, sku entity.Sku) (*model.Product, error) {
|
||||
func (f *productServiceFake) GetProductBySku(_ context.Context, sku entity.Sku) (*model.Product, error) {
|
||||
if sku%2 == 0 {
|
||||
return nil, errors.New("empty shelf")
|
||||
}
|
||||
@@ -33,6 +33,24 @@ func (f *ProductServiceFake) GetProductBySku(_ context.Context, sku entity.Sku)
|
||||
}, nil
|
||||
}
|
||||
|
||||
type lomsServiceFake struct{}
|
||||
|
||||
func (f *lomsServiceFake) StocksInfo(_ context.Context, sku entity.Sku) (uint32, error) {
|
||||
if sku == 1111 {
|
||||
return 0, errors.New("stock error")
|
||||
}
|
||||
|
||||
return 100, nil
|
||||
}
|
||||
|
||||
func (f *lomsServiceFake) OrderCreate(_ context.Context, cart *model.Cart) (int64, error) {
|
||||
if cart.UserID == 1111 {
|
||||
return 0, errors.New("order create error")
|
||||
}
|
||||
|
||||
return 1234, nil
|
||||
}
|
||||
|
||||
func TestCartService_AddItem(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -49,9 +67,20 @@ func TestCartService_AddItem(t *testing.T) {
|
||||
Count: 1,
|
||||
}
|
||||
|
||||
testSKULomsFailing := entity.Sku(1111)
|
||||
testItemLomsFailing := model.Item{
|
||||
Product: &model.Product{
|
||||
Name: validName,
|
||||
Price: validPrice,
|
||||
Sku: testSKULomsFailing,
|
||||
},
|
||||
Count: 1,
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
repository Repository
|
||||
productService ProductService
|
||||
lomsService LomsService
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -72,7 +101,8 @@ func TestCartService_AddItem(t *testing.T) {
|
||||
AddItemMock.
|
||||
Expect(ctx, 1337, &testItem).
|
||||
Return(nil),
|
||||
productService: &ProductServiceFake{},
|
||||
productService: &productServiceFake{},
|
||||
lomsService: &lomsServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
@@ -118,7 +148,8 @@ func TestCartService_AddItem(t *testing.T) {
|
||||
name: "product service error",
|
||||
fields: fields{
|
||||
repository: nil,
|
||||
productService: &ProductServiceFake{},
|
||||
productService: &productServiceFake{},
|
||||
lomsService: &lomsServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
@@ -141,7 +172,8 @@ func TestCartService_AddItem(t *testing.T) {
|
||||
AddItemMock.
|
||||
Expect(ctx, 1337, &testItem).
|
||||
Return(assert.AnError),
|
||||
productService: &ProductServiceFake{},
|
||||
productService: &productServiceFake{},
|
||||
lomsService: &lomsServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
@@ -150,6 +182,41 @@ func TestCartService_AddItem(t *testing.T) {
|
||||
},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
name: "stocks acquiring error",
|
||||
fields: fields{
|
||||
repository: nil,
|
||||
productService: &productServiceFake{},
|
||||
lomsService: &lomsServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
item: &testItemLomsFailing,
|
||||
userID: 1337,
|
||||
},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
name: "not enough stocks",
|
||||
fields: fields{
|
||||
repository: nil,
|
||||
productService: &productServiceFake{},
|
||||
lomsService: &lomsServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
item: &model.Item{
|
||||
Product: &model.Product{
|
||||
Name: validName,
|
||||
Price: validPrice,
|
||||
Sku: testSKU,
|
||||
},
|
||||
Count: 10000,
|
||||
},
|
||||
userID: 1337,
|
||||
},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -158,6 +225,7 @@ func TestCartService_AddItem(t *testing.T) {
|
||||
s := &CartService{
|
||||
repository: tt.fields.repository,
|
||||
productService: tt.fields.productService,
|
||||
lomsService: tt.fields.lomsService,
|
||||
}
|
||||
|
||||
err := s.AddItem(tt.args.ctx, tt.args.userID, tt.args.item)
|
||||
@@ -218,7 +286,7 @@ func TestCartService_GetItemsByUserID(t *testing.T) {
|
||||
GetItemsByUserIDMock.
|
||||
Expect(ctx, testUID).
|
||||
Return(testEntityCart, nil),
|
||||
productService: &ProductServiceFake{},
|
||||
productService: &productServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
@@ -238,7 +306,7 @@ func TestCartService_GetItemsByUserID(t *testing.T) {
|
||||
Items: []entity.Sku{testSKU},
|
||||
ItemCount: map[entity.Sku]uint32{testSKU: 2},
|
||||
}, nil),
|
||||
productService: &ProductServiceFake{},
|
||||
productService: &productServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
@@ -271,7 +339,7 @@ func TestCartService_GetItemsByUserID(t *testing.T) {
|
||||
Items: []entity.Sku{testSKU, 1},
|
||||
ItemCount: map[entity.Sku]uint32{testSKU: 1, 1: 1},
|
||||
}, nil),
|
||||
productService: &ProductServiceFake{},
|
||||
productService: &productServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
@@ -357,7 +425,7 @@ func TestCartService_GetItemsByUserID(t *testing.T) {
|
||||
Items: []entity.Sku{2},
|
||||
ItemCount: map[entity.Sku]uint32{2: 1},
|
||||
}, nil),
|
||||
productService: &ProductServiceFake{},
|
||||
productService: &productServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
@@ -377,7 +445,7 @@ func TestCartService_GetItemsByUserID(t *testing.T) {
|
||||
Items: []entity.Sku{2},
|
||||
ItemCount: map[entity.Sku]uint32{2: 1},
|
||||
}, nil),
|
||||
productService: &ProductServiceFake{},
|
||||
productService: &productServiceFake{},
|
||||
},
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
@@ -573,3 +641,118 @@ func TestCartService_DeleteItemsByUserID(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCartService_CheckoutUserCart(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
mc := minimock.NewController(t)
|
||||
|
||||
testSKU := entity.Sku(199)
|
||||
testCart := entity.Cart{
|
||||
Items: []entity.Sku{testSKU},
|
||||
ItemCount: map[entity.Sku]uint32{testSKU: 1},
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
repository Repository
|
||||
productService ProductService
|
||||
lomsService LomsService
|
||||
}
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
userID entity.UID
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantOrderID int64
|
||||
wantErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
fields: fields{
|
||||
repository: mock.NewRepositoryMock(mc).
|
||||
GetItemsByUserIDMock.
|
||||
Expect(ctx, 1337).
|
||||
Return(testCart, nil).
|
||||
DeleteItemsByUserIDMock.
|
||||
Expect(ctx, 1337).
|
||||
Return(nil),
|
||||
productService: &productServiceFake{},
|
||||
lomsService: &lomsServiceFake{},
|
||||
},
|
||||
args: args{ctx: ctx, userID: 1337},
|
||||
wantOrderID: 1234,
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "invalid user id",
|
||||
fields: fields{},
|
||||
args: args{ctx: ctx, userID: 0},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
name: "get cart error",
|
||||
fields: fields{
|
||||
repository: mock.NewRepositoryMock(mc).
|
||||
GetItemsByUserIDMock.
|
||||
Expect(ctx, 1337).
|
||||
Return(entity.Cart{}, assert.AnError),
|
||||
},
|
||||
args: args{ctx: ctx, userID: 1337},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
name: "order create error",
|
||||
fields: fields{
|
||||
repository: mock.NewRepositoryMock(mc).
|
||||
GetItemsByUserIDMock.
|
||||
Expect(ctx, 1111).
|
||||
Return(testCart, nil),
|
||||
productService: &productServiceFake{},
|
||||
lomsService: &lomsServiceFake{},
|
||||
},
|
||||
args: args{ctx: ctx, userID: 1111},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
name: "delete order error",
|
||||
fields: fields{
|
||||
repository: mock.NewRepositoryMock(mc).
|
||||
GetItemsByUserIDMock.
|
||||
Expect(ctx, 1337).
|
||||
Return(testCart, nil).
|
||||
DeleteItemsByUserIDMock.
|
||||
Expect(ctx, 1337).
|
||||
Return(assert.AnError),
|
||||
productService: &productServiceFake{},
|
||||
lomsService: &lomsServiceFake{},
|
||||
},
|
||||
args: args{ctx: ctx, userID: 1337},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := &CartService{
|
||||
repository: tt.fields.repository,
|
||||
productService: tt.fields.productService,
|
||||
lomsService: tt.fields.lomsService,
|
||||
}
|
||||
|
||||
orderID, err := svc.CheckoutUserCart(tt.args.ctx, tt.args.userID)
|
||||
tt.wantErr(t, err)
|
||||
if err == nil {
|
||||
require.Equal(t, tt.wantOrderID, orderID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
@@ -16,13 +17,17 @@ import (
|
||||
"github.com/ozontech/allure-go/pkg/framework/suite"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
lomsService "route256/cart/internal/adapter/client/loms"
|
||||
productsService "route256/cart/internal/adapter/client/products"
|
||||
"route256/cart/internal/app"
|
||||
"route256/cart/internal/domain/cart/repository"
|
||||
cartService "route256/cart/internal/domain/cart/service"
|
||||
"route256/cart/internal/domain/entity"
|
||||
"route256/cart/internal/domain/model"
|
||||
productsService "route256/cart/internal/domain/products/service"
|
||||
"route256/cart/internal/domain/repository"
|
||||
cartService "route256/cart/internal/domain/service"
|
||||
|
||||
pbLoms "route256/pkg/api/loms/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,12 +39,27 @@ const (
|
||||
testUID = entity.UID(1337)
|
||||
)
|
||||
|
||||
type lomsServerMock struct {
|
||||
pbLoms.UnimplementedLOMSServer
|
||||
}
|
||||
|
||||
func (lomsServerMock) OrderCreate(_ context.Context, _ *pbLoms.OrderCreateRequest) (*pbLoms.OrderCreateResponse, error) {
|
||||
return &pbLoms.OrderCreateResponse{OrderId: 1}, nil
|
||||
}
|
||||
|
||||
func (lomsServerMock) StocksInfo(_ context.Context, _ *pbLoms.StocksInfoRequest) (*pbLoms.StocksInfoResponse, error) {
|
||||
return &pbLoms.StocksInfoResponse{Count: 1000}, nil
|
||||
}
|
||||
|
||||
type CartHandlerSuite struct {
|
||||
suite.Suite
|
||||
|
||||
psContainer testcontainers.Container
|
||||
server *httptest.Server
|
||||
|
||||
lomsSrv *grpc.Server
|
||||
lomsConn *grpc.ClientConn
|
||||
|
||||
server *httptest.Server
|
||||
cartSvc *cartService.CartService
|
||||
}
|
||||
|
||||
@@ -72,6 +92,20 @@ func (s *CartHandlerSuite) BeforeAll(t provider.T) {
|
||||
productURL = endpoint
|
||||
})
|
||||
|
||||
t.WithNewStep("start loms grpc server", func(st provider.StepCtx) {
|
||||
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
st.Require().NoError(err)
|
||||
|
||||
s.lomsSrv = grpc.NewServer()
|
||||
pbLoms.RegisterLOMSServer(s.lomsSrv, &lomsServerMock{})
|
||||
|
||||
go s.lomsSrv.Serve(lis)
|
||||
|
||||
conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure(), grpc.WithBlock())
|
||||
st.Require().NoError(err)
|
||||
s.lomsConn = conn
|
||||
})
|
||||
|
||||
t.WithNewStep("init cart-service", func(sCtx provider.StepCtx) {
|
||||
prodClient := productsService.NewProductService(
|
||||
*http.DefaultClient,
|
||||
@@ -79,8 +113,10 @@ func (s *CartHandlerSuite) BeforeAll(t provider.T) {
|
||||
productURL,
|
||||
)
|
||||
|
||||
lomsClient := pbLoms.NewLOMSClient(s.lomsConn)
|
||||
|
||||
repo := repository.NewInMemoryRepository(10)
|
||||
s.cartSvc = cartService.NewCartService(repo, prodClient)
|
||||
s.cartSvc = cartService.NewCartService(repo, prodClient, lomsService.NewLomsService(lomsClient))
|
||||
|
||||
appSrv := &app.App{}
|
||||
|
||||
@@ -89,8 +125,11 @@ func (s *CartHandlerSuite) BeforeAll(t provider.T) {
|
||||
}
|
||||
|
||||
func (s *CartHandlerSuite) AfterAll(t provider.T) {
|
||||
_ = s.psContainer.Terminate(context.Background())
|
||||
s.server.Close()
|
||||
s.lomsSrv.Stop()
|
||||
s.lomsConn.Close()
|
||||
|
||||
_ = s.psContainer.Terminate(context.Background())
|
||||
}
|
||||
|
||||
// DELETE /user/<user_id>/cart/<sku_id>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
version: "3.7"
|
||||
|
||||
services:
|
||||
cart:
|
||||
build: cart/
|
||||
build:
|
||||
context: .
|
||||
dockerfile: cart/Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
depends_on:
|
||||
@@ -12,3 +12,12 @@ services:
|
||||
image: gitlab-registry.ozon.dev/go/classroom-18/students/homework-draft/products:latest
|
||||
ports:
|
||||
- "8082:8082"
|
||||
|
||||
loms:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: loms/Dockerfile
|
||||
ports:
|
||||
- "8083:8083"
|
||||
- "8084:8084"
|
||||
- "8085:8085"
|
||||
|
||||
@@ -16,3 +16,4 @@
|
||||
|
||||
1. [Основы Go](./homework-1)
|
||||
2. [Тестирование в Go](./homework-2)
|
||||
3. [Межсервисное взаимодействие и основы эксплуатации](./homework-3)
|
||||
|
||||
262
docs/homework-3/README.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# Домашнее задание по модулю "Межсервисное взаимодействие и основы эксплуатации"
|
||||
|
||||
Добавить сервис LOMS и организовать взаимодействие между cart и loms с использованием gRPC.
|
||||
|
||||
## Основное задание
|
||||
|
||||
Необходимо:
|
||||
- Имплементировать сервис, отвечающий за учет заказов и стоки по товарам. Логика работы методов и их контракты описаны ниже.
|
||||
- Реализовать взаимодействие сервисов cart и loms через gRPC.
|
||||
|
||||
Требование к решению:
|
||||
- Создать protobuf контракт сервиса loms.
|
||||
- В каждом проекте нужно добавить в Makefile команды для генерации .go файлов из proto файлов и установки нужных зависимостей (используем protoc).
|
||||
- Состояние храним в in-memory, персистентное хранилище на данный момент не требуется. 2 репозитория - Stock и Order.
|
||||
- Код должен быть покрыт тестами (тесты на методы репозитория - не требуются).
|
||||
- Добавить gRPC интерцептор, который будет валидировать запросы через proto-gen-validator (правила валидации указываются в *.proto).
|
||||
- Добавить HTTP-gateway. HTTP-запросы также должны проходить валидацию через добавленный выше gRPC интерцептор.
|
||||
|
||||
## Дополнительное задание
|
||||
- Добавить swagger-ui и возможность совершать запросы из swagger к сервису.
|
||||
- Написать end-to-end тесты на все новые методы .
|
||||
|
||||
## Спецификация LOMS (Logistics and Order Management System)
|
||||
|
||||
Сервис отвечает за учет заказов и стоки по товарам.
|
||||
|
||||
### OrderCreate
|
||||
|
||||
Создает новый заказ для пользователя из списка переданных товаров с резервированием нужного количества стоков:
|
||||
+ заказ получает статус "new"
|
||||
+ резервирует нужное количество единиц товара
|
||||
+ если удалось зарезервировать стоки, заказ получает статус "awaiting payment"
|
||||
+ если не удалось зарезервировать стоки, заказ получает статус "failed", изменение стоков не происходит
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|------------------------------------------------------------------------------|------------------------|---------------------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением userId | 3 (400) | Идентификатор пользователя должен быть натуральным числом (больше нуля) |
|
||||
| Вызов c пустым списком товаров | 3 (400) | Идентификатор товара должен быть натуральным числом (больше нуля) |
|
||||
| Вызов с нулевыми или отрицательными значениями sku в списке | 3 (400) | Количество должно быть натуральным числом (больше нуля) |
|
||||
| Вызов с нулевыми или отрицательными значениями Count для любого sku в списке | 3 (400) | Count должен быть натуральным числом (больше нуля) |
|
||||
| Превышение стоков хотя бы у одного товара | 9 (400) | Для всех товаров сток должен быть больше или равен запрашиваемому |
|
||||
| Отсутствие информации по стокам в системе | 9 (400) | Невозможно создать заказ, если по хотя бы одному товару нет информации о стоках |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
userId int64
|
||||
items []{
|
||||
sku int64
|
||||
count uint32
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{
|
||||
orderId int64
|
||||
}
|
||||
```
|
||||
|
||||
### OrderInfo
|
||||
|
||||
Показывает информацию по заказу. Товары в ответе должны быть отсортированы по SKU в порядке возрастания.
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|-----------------------------------------------------|------------------------|---------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением orderId | 3 (400) | Идентификатор заказа должен быть натуральным числом (больше нуля) |
|
||||
| Заказ с указанным orderId отсутствует в системе | 5 (404) | Можно получить информацию только для существующего в системе заказа |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
orderId int64
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{
|
||||
status string // (new | awaiting payment | failed | payed | cancelled)
|
||||
userId int64
|
||||
items []{
|
||||
sku int64
|
||||
count uint32
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### OrderPay
|
||||
|
||||
Помечает заказ оплаченным. Зарезервированные товары должны перейти в статус купленных.
|
||||
+ удаляем зарезервированные стоки на товаре
|
||||
+ заказ получает статус "payed"
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|-----------------------------------------------------|------------------------|-------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением orderId | 3 (400) | Идентификатор заказа должен быть натуральным числом (больше нуля) |
|
||||
| Оплата несуществующего заказа | 5 (404) | Можно оплачивать только существующий заказ |
|
||||
| Оплата оплаченного заказа | 0 (200) | Оплата оплаченного заказа разрешается |
|
||||
| Оплата заказа в статусе != "awaiting payment" | 9 (400) | Оплата заказа в невалидном статусе невозможна |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
orderId int64
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{}
|
||||
```
|
||||
|
||||
### OrderCancel
|
||||
|
||||
Отменяет заказ, снимает резерв со всех товаров в заказе.
|
||||
+ зарезервированные стоки на товаре становятся свободными стоками
|
||||
+ заказ получает статус "cancelled"
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|-----------------------------------------------------|------------------------|-------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением orderId | 3 (400) | Идентификатор заказа должен быть натуральным числом (больше нуля) |
|
||||
| Отмена несуществующего заказа | 5 (404) | Можно отменять только существующий заказ |
|
||||
| Отмена отмененного заказа | 0 (200) | Отмена отмененного заказа разрешается (идемпотентность) |
|
||||
| Отмена заказа в статусе == "payed" или "failed" | 9 (400) | Невозможность отменить неудавшийся заказ, а также оплаченный |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
orderId int64
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{}
|
||||
```
|
||||
|
||||
### StocksInfo
|
||||
|
||||
Возвращает количество товаров, которые можно купить. Если товар был зарезервирован у кого-то в заказе и ждет оплаты, его купить нельзя.
|
||||
- данные по товарам берутся из stock-data.json (embed)
|
||||
- структура stock:
|
||||
- sku - товар
|
||||
- total_count - всего товаров
|
||||
- reserved - количество зарезервированных
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | gRPC код ошибки (HTTP) | Описание |
|
||||
|--------------------------------------------------|------------------------|--------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением sku | 3 (400) | Идентификатор товара должен быть натуральным числом (больше нуля) |
|
||||
| Товара в запросе нет в базе стоков | 5 (404) | Можно получить информацию по стокам, если она есть в бд |
|
||||
| Все остальные случаи | 13 или 2 (500) | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
{
|
||||
sku int64
|
||||
}
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{
|
||||
count uint32
|
||||
}
|
||||
```
|
||||
|
||||
## Доработки сервиса cart
|
||||
|
||||
### POST /checkout/<user_id>
|
||||
|
||||
Требуется добавить метод checkout - оформить заказ по всем товарам корзины. Вызывает loms.OrderCreate.
|
||||
Сервис cart имеет HTTP-интерфейс. Взаимодействие с LOMS - через gRPC.
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
|
||||
| Сценарий | HTTP код ошибки | Описание |
|
||||
|-----------------------------------------------------|-----------------|-------------------------------------------------------------------------|
|
||||
| Вызов с нулевым или отрицательным значением user_id | 400 | Идентификатор пользователя должен быть натуральным числом (больше нуля) |
|
||||
| Вызов для пустой корзины | 404 | Невозможно оформить заказ для пустой корзины |
|
||||
| Все остальные случаи | 500 | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
Request
|
||||
```
|
||||
POST /checkout/<user_id> (user_id - int64)
|
||||
```
|
||||
|
||||
Response
|
||||
```
|
||||
{
|
||||
order_id int64
|
||||
}
|
||||
```
|
||||
|
||||
### POST /user/<user_id>/cart/<sku_id>
|
||||
|
||||
Требуется добавить запрос в метод добавления товаров в корзину на проверку наличия стоков с помощью вызова gRPC метода loms.StocksInfo.
|
||||
|
||||
**Параметры ошибочных ответов:**
|
||||
Сценарии из прошлых домашних заданий без изменений.
|
||||
|
||||
| Сценарий | HTTP код ошибки | Описание |
|
||||
|-----------------------------------------|-----------------|--------------------------------------------------------------------|
|
||||
| Превышение стоков при добавлении товара | 412 | Невозможно добавить товара по количеству больше, чем есть в стоках |
|
||||
| Все остальные случаи | 500 | Проблемы из-за неисправностей в системе |
|
||||
|
||||

|
||||
|
||||
# Путь покупки товаров:
|
||||
|
||||
- <cart_host>/user/{user_id}/cart/{sku_id} - Добавляем товар в корзину с проверкой на наличие стоков.
|
||||
- <cart_host>/user/{user_id}/cart || <cart_host>/user/{user_id}/cart/{sku_id} - Можем удалять товары из корзины.
|
||||
- <cart_host>/user/{user_id}/cart - Можем получить состав корзины.
|
||||
- <cart_host>/checkout/{user_id} - Создаем заказ по товарам из корзины.
|
||||
- <order_host>/order/pay with body { "orderId": {order_id} } - Оплачиваем заказ.
|
||||
- <order_host>/order/cancel with body { "orderId": {order_id} } - Можем отменить заказ до оплаты.
|
||||
|
||||
### Примечания
|
||||
* e2e тесты проверяют HTTP коды ошибок, однако gRPC коды должны быть те, что указаны в требованиях. Например, могут быть проблемы с codes.FailedPrecondition, подробнее [тут](https://github.com/grpc-ecosystem/grpc-gateway/blob/main/runtime/errors.go).
|
||||
* Запросы из cart.http, loms.http & loms.grpc основаны на данных, что лежат в stock-data.json
|
||||
|
||||
## Автоматические проверки
|
||||
|
||||
Ваше решение должно проходить автоматические проверки:
|
||||
|
||||
- Компиляция
|
||||
- Линтер
|
||||
- Unit-тесты (если есть)
|
||||
- Автотесты
|
||||
|
||||
Прохождение автоматических проверок влияет на итоговую оценку за домашнюю работу.
|
||||
|
||||
### Дедлайны сдачи и проверки задания:
|
||||
- 7 июня 23:59 (сдача) / 10 июня, 23:59 (проверка)
|
||||
69
docs/homework-3/cart.http
Normal file
@@ -0,0 +1,69 @@
|
||||
### check cart state, expect empty cart
|
||||
GET http://localhost:8080/user/31337/cart
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 (Not Found) {}
|
||||
|
||||
|
||||
### add item to cart, see available stocks in loms db
|
||||
POST http://localhost:8080/user/31337/cart/1076963
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1
|
||||
}
|
||||
### expected: 200 (OK) {}
|
||||
|
||||
|
||||
### check cart state, expect single sku in cart
|
||||
GET http://localhost:8080/user/31337/cart
|
||||
|
||||
### expected: 200 (OK) {"items":[{"sku":1076963,"count":1,"name":"Теория нравственных чувств | Смит Адам","price":3379}],"totalPrice":3379}
|
||||
|
||||
|
||||
#########################
|
||||
### checkout cart
|
||||
POST http://localhost:8080/checkout/31337
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"order_id":1}
|
||||
|
||||
|
||||
### check orderID in LOMS
|
||||
GET http://localhost:8084/order/info?orderId=1
|
||||
Content-Type: application/json
|
||||
### expected: 200 (OK) {"status":"awaiting payment","user":31337,"Items":[{"sku":1076963,"count":1}]}
|
||||
|
||||
|
||||
### check cart, expect empty
|
||||
GET http://localhost:8080/user/31337/cart
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 (Not Found) {}
|
||||
|
||||
|
||||
### add unknown item, expect error
|
||||
POST http://localhost:8080/user/31337/cart/404
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 1
|
||||
}
|
||||
### expected: 412 (Precondition Failed) {}
|
||||
|
||||
|
||||
### add item out of stock, expect error
|
||||
POST http://localhost:8080/user/31337/cart/135937324
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"count": 65534
|
||||
}
|
||||
### expected: 412 (Precondition Failed) {}
|
||||
|
||||
|
||||
### checkout empty cart, expect error
|
||||
POST http://localhost:8080/checkout/31337
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 (Not Found) {}
|
||||
18
docs/homework-3/img/cart-cart-checkout.plantuml
Normal file
@@ -0,0 +1,18 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections Cart as c
|
||||
database CartStorage as cs
|
||||
collections Order as o
|
||||
|
||||
u -> c : POST /checkout/<user_id>
|
||||
activate c
|
||||
c -> cs : cart.GetItemsByUserID
|
||||
c -> o : gRPC Loms.OrderCreate\n\t- user\n\t- []item
|
||||
c -> cs : cart.DeleteItemsByUserID
|
||||
|
||||
c -> u : Response: 200 OK
|
||||
|
||||
deactivate c
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/cart-cart-checkout.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
32
docs/homework-3/img/cart-cart-item-add.plantuml
Normal file
@@ -0,0 +1,32 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections Cart as c
|
||||
database CartStorage as cs
|
||||
collections ProductService as p
|
||||
collections Order as o
|
||||
|
||||
u -> c : POST /user/<user_id>/cart/<sku_id>\n\t- count
|
||||
activate c
|
||||
loop for each item in request
|
||||
c -> p : /get_product\n\t- sku\n\t- token
|
||||
activate p
|
||||
p -> c : \nResponse:\n\t- name\n\t- price
|
||||
deactivate p
|
||||
c -> c : validate product exists
|
||||
|
||||
c -> o : gRPC Loms.StocksInfo\n\t- sku
|
||||
activate o
|
||||
o -> c : Response:\n\t- count
|
||||
deactivate o
|
||||
c -> c : validate stocks
|
||||
alt stocks enough
|
||||
c -> cs : cart.AddItem()
|
||||
c -> u : 200 OK
|
||||
else
|
||||
c -> u : 412 Failed Precondition (insufficient stocks)
|
||||
end
|
||||
end
|
||||
deactivate c
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/cart-cart-item-add.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
18
docs/homework-3/img/loms-order-cancel.plantuml
Normal file
@@ -0,0 +1,18 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database OrdersStorage as os
|
||||
database StocksStorage as ss
|
||||
|
||||
u -> l : gRPC Loms.OrderCancel\n\t- orderID
|
||||
activate l
|
||||
|
||||
l -> os : order.GetByOrderID()
|
||||
l -> ss : stocks.ReserveCancel()
|
||||
l -> os : order.SetStatus(cancelled)
|
||||
deactivate l
|
||||
|
||||
l -> u : Response: OK (code_id=0)
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-order-cancel.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
22
docs/homework-3/img/loms-order-create.plantuml
Normal file
@@ -0,0 +1,22 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database OrdersStorage as os
|
||||
database StocksStorage as ss
|
||||
|
||||
u -> l : gRPC Loms.OrderCreate\n\t- user\n\t- items: []item{\n\t\t- sku\n\t\t- count\n\t }
|
||||
activate l
|
||||
l -> os : order.Create()\n\tstatus=new
|
||||
l -> ss : stocks.Reserve()
|
||||
|
||||
alt Reserve success
|
||||
l -> os : order.SetStatus(awaiting payment)
|
||||
l -> u : Response: OK (code_id=0)\n\t- orderID
|
||||
else
|
||||
l -> os : order.SetStatus(failed)
|
||||
l -> u : Failed Precondition (code_id 9)
|
||||
end
|
||||
deactivate l
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-order-create.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
19
docs/homework-3/img/loms-order-info.plantuml
Normal file
@@ -0,0 +1,19 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database OrdersStorage as os
|
||||
|
||||
u -> l : gRPC Loms.OrderInfo\n\t- orderID int64
|
||||
activate l
|
||||
|
||||
l -> os : order.GetByID()
|
||||
alt order exists
|
||||
l -> u : Response: OK (code_id=0)\n\t- status\n\t- user\n\t- []items{}
|
||||
else
|
||||
l -> u : Response: Not Found (code_id=5)
|
||||
end
|
||||
|
||||
deactivate l
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-order-info.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
17
docs/homework-3/img/loms-order-pay.plantuml
Normal file
@@ -0,0 +1,17 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database OrdersStorage as os
|
||||
database StocksStorage as ss
|
||||
|
||||
u -> l : gRPC Loms.OrderPay\n\t- orderID
|
||||
activate l
|
||||
l -> ss : stocks.ReserveRemove()
|
||||
l -> os : order.SetStatus(payed)
|
||||
|
||||
l -> u : Response: OK (code_id=0)
|
||||
|
||||
deactivate l
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-order-pay.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
15
docs/homework-3/img/loms-stok-info.plantuml
Normal file
@@ -0,0 +1,15 @@
|
||||
@startuml
|
||||
|
||||
actor User as u
|
||||
collections LOMS as l
|
||||
database StocksStorage as ss
|
||||
|
||||
u -> l : gRPC Loms.StocksInfo\n\t- sku
|
||||
activate l
|
||||
|
||||
l -> ss : stocks.GetBySKU()
|
||||
|
||||
l -> u : Response: OK (code_id=0)\n- count
|
||||
deactivate l
|
||||
|
||||
@enduml
|
||||
BIN
docs/homework-3/img/loms-stok-info.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
189
docs/homework-3/loms.grpc
Normal file
@@ -0,0 +1,189 @@
|
||||
### create normal order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCreate <<EOM
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 1076963,
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
EOM
|
||||
### expected: {"orderId":1}
|
||||
|
||||
|
||||
### get info, assert status="awaiting payment"
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
EOM
|
||||
### expected: {"status":"awaiting payment","userId":31337,"Items":[{"sku":1076963,"count":3},{"sku":135717466,"count":2}]}
|
||||
|
||||
|
||||
### pay order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderPay <<EOM
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
EOM
|
||||
### expected: {}
|
||||
|
||||
|
||||
### check actual status is "payed"
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
EOM
|
||||
### expected: {"status":"payed","userId":31337,"Items":[{"sku":1076963,"count":3},{"sku":135717466,"count":2}]}
|
||||
|
||||
|
||||
### unable to cancel payed order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCancel <<EOM
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
EOM
|
||||
### expected: Code: FailedPrecondition ...
|
||||
|
||||
|
||||
### get unknown order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 404
|
||||
}
|
||||
EOM
|
||||
### expected: Code: NotFound
|
||||
|
||||
|
||||
### cancel order not exists
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCancel <<EOM
|
||||
{
|
||||
"orderId": 404
|
||||
}
|
||||
EOM
|
||||
### expected: Code: NotFound
|
||||
|
||||
|
||||
### create order with item that has no stocks info
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCreate <<EOM
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 404,
|
||||
"count": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
EOM
|
||||
### expected: Code: FailedPrecondition
|
||||
|
||||
|
||||
### check order status is failed (not necessary, because no orderId after creation if any fails)
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 2
|
||||
}
|
||||
EOM
|
||||
### expected: {"status":"failed","userId":31337,"Items":[{"sku":404,"count":3}]}
|
||||
|
||||
|
||||
### cancel failed order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCancel <<EOM
|
||||
{
|
||||
"orderId": 2
|
||||
}
|
||||
EOM
|
||||
### expected: Code: FailedPrecondition
|
||||
|
||||
|
||||
|
||||
### stock info for unknown sku
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.StocksInfo <<EOM
|
||||
{
|
||||
"sku": 404
|
||||
}
|
||||
EOM
|
||||
### expected: Code: NotFound
|
||||
|
||||
|
||||
### stock info for normal sku
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.StocksInfo <<EOM
|
||||
{
|
||||
"sku": 135717466
|
||||
}
|
||||
EOM
|
||||
### expected: {"count":78}
|
||||
|
||||
|
||||
### create order with count for sku more than stock
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCreate <<EOM
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 79
|
||||
}
|
||||
]
|
||||
}
|
||||
EOM
|
||||
### expected: Code: FailedPrecondition
|
||||
|
||||
|
||||
### no change in stock info after failed order creation
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.StocksInfo <<EOM
|
||||
{
|
||||
"sku": 135717466
|
||||
}
|
||||
EOM
|
||||
### expected: {"count":500}; 200 OK
|
||||
|
||||
|
||||
### create normal order for cancellation
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCreate <<EOM
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
EOM
|
||||
### expected: {"orderId":4}
|
||||
|
||||
|
||||
### cancel order
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderCancel <<EOM
|
||||
{
|
||||
"orderId": 4
|
||||
}
|
||||
EOM
|
||||
### expected: {}
|
||||
|
||||
|
||||
### check canceled order status
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.OrderInfo <<EOM
|
||||
{
|
||||
"orderId": 4
|
||||
}
|
||||
EOM
|
||||
### expected: {"status":"cancelled","userId":31337,"Items":[{"sku":1076963,"count":2}]}
|
||||
|
||||
|
||||
### check stocks returns
|
||||
grpcurl -plaintext -d @ localhost:8083 loms.Loms.StocksInfo <<EOM
|
||||
{
|
||||
"sku": 135717466
|
||||
}
|
||||
EOM
|
||||
### expected: {"count":78}
|
||||
176
docs/homework-3/loms.http
Normal file
@@ -0,0 +1,176 @@
|
||||
### create normal order
|
||||
POST http://localhost:8084/order/create
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 1076963,
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
### expected: 200 (OK) {"orderId":1}
|
||||
|
||||
|
||||
### get info, assert status="awaiting payment"
|
||||
GET http://localhost:8084/order/info?orderId=1
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"status":"awaiting payment","user":31337,"Items":[{"sku":1076963,"count":3},{"sku":135717466,"count":2}]}
|
||||
|
||||
|
||||
### pay order
|
||||
POST http://localhost:8084/order/pay
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
### expected: 200 (OK) {}
|
||||
|
||||
|
||||
### check actual status is "payed"
|
||||
GET http://localhost:8084/order/info?orderId=1
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"status":"payed","user":31337,"Items":[{"sku":1076963,"count":3},{"sku":135717466,"count":2}]}
|
||||
|
||||
|
||||
### unable to cancel payed order
|
||||
POST http://localhost:8084/order/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 1
|
||||
}
|
||||
### expected: 400 (Bad Request) {"code":9, ... }
|
||||
|
||||
|
||||
### get unknown order
|
||||
GET http://localhost:8084/order/info?orderId=404
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 (Not Found) {"code": 5, ... }
|
||||
|
||||
|
||||
### cancel order not exists
|
||||
POST http://localhost:8084/order/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 404
|
||||
}
|
||||
### expected: 404 (Not Found) {"code": 5, ... }
|
||||
|
||||
|
||||
### create order with item that has no stocks info
|
||||
POST http://localhost:8084/order/create
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 404,
|
||||
"count": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
### expected: 400 (Bad Request) {"code":9, ... }
|
||||
|
||||
|
||||
### check order status is failed (not necessary, because no orderId after creation if any fails)
|
||||
GET http://localhost:8084/order/info?orderId=2
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"status":"failed","userId":31337,"Items":[{"sku":404,"count":3}]}
|
||||
|
||||
### cancel failed order
|
||||
POST http://localhost:8084/order/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 2
|
||||
}
|
||||
### expected: 400 (Bad Request) {"code":9, ... }
|
||||
|
||||
|
||||
### stock info for unknown sku
|
||||
GET http://localhost:8084/stock/info?sku=404
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 404 Not Found {"code":5, ... }
|
||||
|
||||
|
||||
### stock info for normal sku
|
||||
GET http://localhost:8084/stock/info?sku=135717466
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"count":78}
|
||||
|
||||
|
||||
### create order with count for sku more than stock
|
||||
POST http://localhost:8084/order/create
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 79
|
||||
}
|
||||
]
|
||||
}
|
||||
### expected: 400 (Bad Request) {"code":9, ... }
|
||||
|
||||
### no change in stock info after failed order creation
|
||||
GET http://localhost:8084/stock/info?sku=135717466
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: 200 (OK) {"count":78}
|
||||
|
||||
### create normal order for cancellation
|
||||
POST http://localhost:8084/order/create
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"userId": 31337,
|
||||
"items": [
|
||||
{
|
||||
"sku": 135717466,
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
### expected: 200 (OK) {"orderId":4}
|
||||
|
||||
|
||||
### cancel order
|
||||
POST http://localhost:8084/order/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"orderId": 4
|
||||
}
|
||||
### expected: 200 (OK)
|
||||
|
||||
|
||||
### check canceled order status
|
||||
GET http://localhost:8084/order/info?orderId=4
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: {"status":"cancelled","user":31337,"Items":[{"sku":1076963,"count":2}]}
|
||||
|
||||
|
||||
### check stocks returns
|
||||
GET http://localhost:8084/stock/info?sku=135717466
|
||||
Content-Type: application/json
|
||||
|
||||
### expected: {"count":78}; 200 OK
|
||||
37
docs/homework-3/stock-data.json
Normal file
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"sku": 139275865,
|
||||
"total_count": 65534,
|
||||
"reserved": 0
|
||||
},
|
||||
{
|
||||
"sku": 2956315,
|
||||
"total_count": 100,
|
||||
"reserved": 30
|
||||
},
|
||||
{
|
||||
"sku": 1076963,
|
||||
"total_count": 100,
|
||||
"reserved": 35
|
||||
},
|
||||
{
|
||||
"sku": 135717466,
|
||||
"total_count": 100,
|
||||
"reserved": 20
|
||||
},
|
||||
{
|
||||
"sku": 135937324,
|
||||
"total_count": 100,
|
||||
"reserved": 30
|
||||
},
|
||||
{
|
||||
"sku": 1625903,
|
||||
"total_count": 10000,
|
||||
"reserved": 0
|
||||
},
|
||||
{
|
||||
"sku": 1148162,
|
||||
"total_count": 100,
|
||||
"reserved": 0
|
||||
}
|
||||
]
|
||||
9
go.work
@@ -1,8 +1,9 @@
|
||||
go 1.23.9
|
||||
|
||||
use (
|
||||
./cart
|
||||
./loms
|
||||
./notifier
|
||||
./comments
|
||||
./cart
|
||||
./comments
|
||||
./loms
|
||||
./notifier
|
||||
./pkg
|
||||
)
|
||||
|
||||
42
go.work.sum
@@ -1,16 +1,58 @@
|
||||
cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||
github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hexdigest/gowrap v1.4.2/go.mod h1:s+1hE6qakgdaaLqgdwPAj5qKYVBCSbPJhEbx+I1ef/Q=
|
||||
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
|
||||
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
|
||||
22
loms/Dockerfile
Normal file
@@ -0,0 +1,22 @@
|
||||
FROM golang:1.23.9-alpine as builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
COPY loms/go.mod go.mod
|
||||
COPY loms/go.sum go.sum
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
WORKDIR loms
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /server ./cmd/server/main.go
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder server /bin/server
|
||||
COPY loms/configs/values_local.yaml /bin/config/values_local.yaml
|
||||
|
||||
ENV CONFIG_FILE=/bin/config/values_local.yaml
|
||||
|
||||
ENTRYPOINT ["/bin/server"]
|
||||
18
loms/cmd/server/main.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"route256/loms/internal/app"
|
||||
)
|
||||
|
||||
func main() {
|
||||
srv, err := app.NewApp(os.Getenv("CONFIG_FILE"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
service:
|
||||
host: localhost
|
||||
host: "[::]"
|
||||
grpc_port: 8083
|
||||
http_port: 8084
|
||||
log_level: trace
|
||||
|
||||
jaeger:
|
||||
host: localhost
|
||||
|
||||
24
loms/go.mod
@@ -1,3 +1,27 @@
|
||||
module route256/loms
|
||||
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/gojuno/minimock/v3 v3.4.5
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
google.golang.org/grpc v1.73.0
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
)
|
||||
|
||||
72
loms/go.sum
Normal file
@@ -0,0 +1,72 @@
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gojuno/minimock/v3 v3.4.5 h1:Jcb0tEYZvVlQNtAAYpg3jCOoSwss2c1/rNugYTzj304=
|
||||
github.com/gojuno/minimock/v3 v3.4.5/go.mod h1:o9F8i2IT8v3yirA7mmdpNGzh1WNesm6iQakMtQV6KiE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
||||
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
119
loms/internal/app/app.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/reflection"
|
||||
|
||||
"route256/loms/internal/app/server"
|
||||
ordersRepository "route256/loms/internal/domain/repository/orders"
|
||||
stocksRepository "route256/loms/internal/domain/repository/stocks"
|
||||
"route256/loms/internal/domain/service"
|
||||
"route256/loms/internal/infra/config"
|
||||
mw "route256/loms/internal/infra/grpc/middleware"
|
||||
|
||||
pb "route256/pkg/api/loms/v1"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
config *config.Config
|
||||
controller *server.Server
|
||||
}
|
||||
|
||||
func NewApp(configPath string) (*App, error) {
|
||||
c, err := config.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load config: %w", err)
|
||||
}
|
||||
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
|
||||
if c.Service.LogLevel != "" {
|
||||
level, logErr := zerolog.ParseLevel(c.Service.LogLevel)
|
||||
if logErr != nil {
|
||||
return nil, fmt.Errorf("unknown log level `%s` provided: %w", c.Service.LogLevel, logErr)
|
||||
}
|
||||
|
||||
zerolog.SetGlobalLevel(level)
|
||||
}
|
||||
|
||||
log.WithLevel(zerolog.GlobalLevel()).Msgf("using logging level=`%s`", zerolog.GlobalLevel().String())
|
||||
|
||||
stockRepo, err := stocksRepository.NewInMemoryRepository(100)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stocksRepository.NewInMemoryRepository: %w", err)
|
||||
}
|
||||
|
||||
orderRepo := ordersRepository.NewInMemoryRepository(100)
|
||||
service := service.NewLomsService(orderRepo, stockRepo)
|
||||
controller := server.NewServer(service)
|
||||
|
||||
app := &App{
|
||||
config: c,
|
||||
controller: controller,
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func (app *App) ListenAndServe() error {
|
||||
grpcAddr := fmt.Sprintf("%s:%s", app.config.Service.Host, app.config.Service.GRPCPort)
|
||||
l, err := net.Listen("tcp", grpcAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
grpcServer := grpc.NewServer(
|
||||
grpc.ChainUnaryInterceptor(
|
||||
mw.Logging,
|
||||
mw.Validate,
|
||||
),
|
||||
)
|
||||
reflection.Register(grpcServer)
|
||||
|
||||
pb.RegisterLOMSServer(grpcServer, app.controller)
|
||||
|
||||
go func() {
|
||||
if err = grpcServer.Serve(l); err != nil {
|
||||
log.Fatal().Msgf("failed to serve: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Info().Msgf("Serving grpc loms at grpc://%s", l.Addr())
|
||||
|
||||
// Setup HTTP gateway
|
||||
|
||||
conn, err := grpc.NewClient(
|
||||
grpcAddr,
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("grpc.NewClient: %w", err)
|
||||
}
|
||||
|
||||
gwmux := runtime.NewServeMux()
|
||||
if err = pb.RegisterLOMSHandler(context.Background(), gwmux, conn); err != nil {
|
||||
return fmt.Errorf("pb.RegisterLOMSHandler: %w", err)
|
||||
}
|
||||
|
||||
gwServer := &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%s", app.config.Service.Host, app.config.Service.HTTPPort),
|
||||
Handler: gwmux,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
log.Info().Msgf("Serving http loms at http://%s", gwServer.Addr)
|
||||
|
||||
return gwServer.ListenAndServe()
|
||||
}
|
||||
148
loms/internal/app/server/server.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
"route256/loms/internal/domain/entity"
|
||||
"route256/loms/internal/domain/model"
|
||||
|
||||
pb "route256/pkg/api/loms/v1"
|
||||
)
|
||||
|
||||
var _ pb.LOMSServer = (*Server)(nil)
|
||||
|
||||
type LomsService interface {
|
||||
OrderCreate(ctx context.Context, orderReq *pb.OrderCreateRequest) (entity.ID, error)
|
||||
OrderInfo(ctx context.Context, orderID entity.ID) (*entity.Order, error)
|
||||
OrderPay(ctx context.Context, orderID entity.ID) error
|
||||
OrderCancel(ctx context.Context, orderID entity.ID) error
|
||||
StocksInfo(ctx context.Context, sku entity.Sku) (uint32, error)
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
pb.UnimplementedLOMSServer
|
||||
|
||||
service LomsService
|
||||
}
|
||||
|
||||
func NewServer(lomsService LomsService) *Server {
|
||||
return &Server{
|
||||
service: lomsService,
|
||||
}
|
||||
}
|
||||
|
||||
func mapOrderStatus(pbStatus pb.OrderStatus) (string, error) {
|
||||
switch pbStatus {
|
||||
case pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT:
|
||||
return "awaiting payment", nil
|
||||
case pb.OrderStatus_ORDER_STATUS_CANCELLED:
|
||||
return "cancelled", nil
|
||||
case pb.OrderStatus_ORDER_STATUS_FAILED:
|
||||
return "failed", nil
|
||||
case pb.OrderStatus_ORDER_STATUS_NEW:
|
||||
return "new", nil
|
||||
case pb.OrderStatus_ORDER_STATUS_PAYED:
|
||||
return "payed", nil
|
||||
default:
|
||||
return "", fmt.Errorf("unexpected OrderStatus: %v", pbStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) OrderCreate(ctx context.Context, req *pb.OrderCreateRequest) (*pb.OrderCreateResponse, error) {
|
||||
id, err := s.service.OrderCreate(ctx, req)
|
||||
switch {
|
||||
case errors.Is(err, model.ErrInvalidInput):
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Is(err, model.ErrNotEnoughStocks):
|
||||
return nil, status.Error(codes.FailedPrecondition, err.Error())
|
||||
case err != nil:
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
return &pb.OrderCreateResponse{OrderId: int64(id)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) OrderInfo(ctx context.Context, req *pb.OrderInfoRequest) (*pb.OrderInfoResponse, error) {
|
||||
ord, err := s.service.OrderInfo(ctx, entity.ID(req.OrderId))
|
||||
switch {
|
||||
case errors.Is(err, model.ErrInvalidInput):
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Is(err, model.ErrOrderNotFound):
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
case err != nil:
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
items := make([]*pb.OrderItem, len(ord.Items))
|
||||
for i, item := range ord.Items {
|
||||
items[i] = &pb.OrderItem{
|
||||
Sku: int64(item.ID),
|
||||
Count: item.Count,
|
||||
}
|
||||
}
|
||||
|
||||
orderStatus, err := mapOrderStatus(pb.OrderStatus(pb.OrderStatus_value[ord.Status]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := &pb.OrderInfoResponse{
|
||||
Status: orderStatus,
|
||||
UserId: int64(ord.UserID),
|
||||
Items: items,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) OrderPay(ctx context.Context, req *pb.OrderPayRequest) (*emptypb.Empty, error) {
|
||||
err := s.service.OrderPay(ctx, entity.ID(req.OrderId))
|
||||
switch {
|
||||
case errors.Is(err, model.ErrInvalidInput):
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Is(err, model.ErrOrderNotFound):
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
case errors.Is(err, model.ErrOrderInvalidStatus):
|
||||
return nil, status.Error(codes.FailedPrecondition, err.Error())
|
||||
case err != nil:
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) OrderCancel(ctx context.Context, req *pb.OrderCancelRequest) (*emptypb.Empty, error) {
|
||||
err := s.service.OrderCancel(ctx, entity.ID(req.OrderId))
|
||||
switch {
|
||||
case errors.Is(err, model.ErrInvalidInput):
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Is(err, model.ErrOrderNotFound):
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
case errors.Is(err, model.ErrOrderInvalidStatus):
|
||||
return nil, status.Error(codes.FailedPrecondition, err.Error())
|
||||
case err != nil:
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) StocksInfo(ctx context.Context, req *pb.StocksInfoRequest) (*pb.StocksInfoResponse, error) {
|
||||
count, err := s.service.StocksInfo(ctx, entity.Sku(req.Sku))
|
||||
switch {
|
||||
case errors.Is(err, model.ErrInvalidInput):
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Is(err, model.ErrOrderNotFound), errors.Is(err, model.ErrUnknownStock):
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
case err != nil:
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
return &pb.StocksInfoResponse{Count: count}, nil
|
||||
}
|
||||
18
loms/internal/domain/entity/order.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package entity
|
||||
|
||||
type (
|
||||
ID int64
|
||||
Sku int64
|
||||
)
|
||||
|
||||
type Order struct {
|
||||
OrderID ID
|
||||
Status string
|
||||
UserID ID
|
||||
Items []OrderItem
|
||||
}
|
||||
|
||||
type OrderItem struct {
|
||||
ID Sku
|
||||
Count uint32
|
||||
}
|
||||
6
loms/internal/domain/entity/stock.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package entity
|
||||
|
||||
type Stock struct {
|
||||
Item OrderItem
|
||||
Reserved uint32
|
||||
}
|
||||
13
loms/internal/domain/model/errors.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package model
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrInvalidInput = errors.New("invalid input")
|
||||
|
||||
ErrNotEnoughStocks = errors.New("not enough stocks")
|
||||
ErrUnknownStock = errors.New("unknown stock provided")
|
||||
|
||||
ErrOrderNotFound = errors.New("order not found")
|
||||
ErrOrderInvalidStatus = errors.New("invalid order status")
|
||||
)
|
||||
@@ -0,0 +1,77 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"route256/loms/internal/domain/entity"
|
||||
"route256/loms/internal/domain/model"
|
||||
)
|
||||
|
||||
type storage = map[entity.ID]*entity.Order
|
||||
|
||||
type InMemoryRepository struct {
|
||||
storage storage
|
||||
mx sync.RWMutex
|
||||
idCounter entity.ID
|
||||
}
|
||||
|
||||
func NewInMemoryRepository(cap int) *InMemoryRepository {
|
||||
return &InMemoryRepository{
|
||||
storage: make(storage, cap),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InMemoryRepository) OrderCreate(_ context.Context, order *entity.Order) (entity.ID, error) {
|
||||
r.mx.Lock()
|
||||
defer r.mx.Unlock()
|
||||
|
||||
r.idCounter++
|
||||
|
||||
orderCopy := &entity.Order{
|
||||
OrderID: r.idCounter,
|
||||
Status: order.Status,
|
||||
UserID: order.UserID,
|
||||
Items: make([]entity.OrderItem, len(order.Items)),
|
||||
}
|
||||
|
||||
copy(orderCopy.Items, order.Items)
|
||||
|
||||
r.storage[orderCopy.OrderID] = orderCopy
|
||||
|
||||
return r.idCounter, nil
|
||||
}
|
||||
|
||||
func (r *InMemoryRepository) OrderSetStatus(_ context.Context, orderID entity.ID, newStatus string) error {
|
||||
r.mx.Lock()
|
||||
defer r.mx.Unlock()
|
||||
|
||||
if _, ok := r.storage[orderID]; !ok {
|
||||
return model.ErrOrderNotFound
|
||||
}
|
||||
|
||||
r.storage[orderID].Status = newStatus
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InMemoryRepository) OrderGetByID(_ context.Context, orderID entity.ID) (*entity.Order, error) {
|
||||
r.mx.Lock()
|
||||
defer r.mx.Unlock()
|
||||
|
||||
order, ok := r.storage[orderID]
|
||||
if !ok {
|
||||
return nil, model.ErrOrderNotFound
|
||||
}
|
||||
|
||||
orderCopy := &entity.Order{
|
||||
OrderID: order.OrderID,
|
||||
Status: order.Status,
|
||||
UserID: order.UserID,
|
||||
Items: make([]entity.OrderItem, len(order.Items)),
|
||||
}
|
||||
|
||||
copy(orderCopy.Items, order.Items)
|
||||
|
||||
return orderCopy, nil
|
||||
}
|
||||
114
loms/internal/domain/repository/stocks/in_memory_repository.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"route256/loms/internal/domain/entity"
|
||||
"route256/loms/internal/domain/model"
|
||||
)
|
||||
|
||||
//go:embed stock-data.json
|
||||
var stockData []byte
|
||||
|
||||
type storage = map[entity.Sku]*entity.Stock
|
||||
|
||||
type InMemoryRepository struct {
|
||||
storage storage
|
||||
mx sync.RWMutex
|
||||
}
|
||||
|
||||
func NewInMemoryRepository(cap int) (*InMemoryRepository, error) {
|
||||
var rows []struct {
|
||||
Sku entity.Sku `json:"sku"`
|
||||
TotalCount uint32 `json:"total_count"`
|
||||
Reserved uint32 `json:"reserved"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(stockData, &rows); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo := &InMemoryRepository{
|
||||
storage: make(storage, cap),
|
||||
}
|
||||
|
||||
for _, r := range rows {
|
||||
repo.storage[r.Sku] = &entity.Stock{
|
||||
Item: entity.OrderItem{
|
||||
ID: r.Sku,
|
||||
Count: r.TotalCount,
|
||||
},
|
||||
Reserved: r.Reserved,
|
||||
}
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func (r *InMemoryRepository) StockReserve(_ context.Context, stock *entity.Stock) error {
|
||||
r.mx.Lock()
|
||||
defer r.mx.Unlock()
|
||||
|
||||
if _, ok := r.storage[stock.Item.ID]; !ok {
|
||||
return model.ErrNotEnoughStocks
|
||||
}
|
||||
|
||||
if r.storage[stock.Item.ID].Item.Count < stock.Reserved {
|
||||
return model.ErrNotEnoughStocks
|
||||
}
|
||||
|
||||
r.storage[stock.Item.ID].Item.Count -= stock.Reserved
|
||||
r.storage[stock.Item.ID].Reserved += stock.Reserved
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InMemoryRepository) StockReserveRemove(_ context.Context, stock *entity.Stock) error {
|
||||
r.mx.Lock()
|
||||
defer r.mx.Unlock()
|
||||
|
||||
if _, ok := r.storage[stock.Item.ID]; !ok {
|
||||
return model.ErrUnknownStock
|
||||
}
|
||||
|
||||
if r.storage[stock.Item.ID].Reserved < stock.Reserved {
|
||||
return model.ErrNotEnoughStocks
|
||||
}
|
||||
|
||||
r.storage[stock.Item.ID].Reserved -= stock.Reserved
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InMemoryRepository) StockCancel(_ context.Context, stock *entity.Stock) error {
|
||||
r.mx.Lock()
|
||||
defer r.mx.Unlock()
|
||||
|
||||
if _, ok := r.storage[stock.Item.ID]; !ok {
|
||||
return model.ErrUnknownStock
|
||||
}
|
||||
|
||||
if r.storage[stock.Item.ID].Reserved < stock.Reserved {
|
||||
return model.ErrNotEnoughStocks
|
||||
}
|
||||
|
||||
r.storage[stock.Item.ID].Reserved -= stock.Reserved
|
||||
r.storage[stock.Item.ID].Item.Count += stock.Reserved
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InMemoryRepository) StockGetByID(_ context.Context, sku entity.Sku) (*entity.Stock, error) {
|
||||
r.mx.Lock()
|
||||
defer r.mx.Unlock()
|
||||
|
||||
stock, ok := r.storage[sku]
|
||||
if !ok {
|
||||
return nil, model.ErrUnknownStock
|
||||
}
|
||||
|
||||
return stock, nil
|
||||
}
|
||||
37
loms/internal/domain/repository/stocks/stock-data.json
Normal file
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"sku": 139275865,
|
||||
"total_count": 65534,
|
||||
"reserved": 0
|
||||
},
|
||||
{
|
||||
"sku": 2956315,
|
||||
"total_count": 100,
|
||||
"reserved": 30
|
||||
},
|
||||
{
|
||||
"sku": 1076963,
|
||||
"total_count": 100,
|
||||
"reserved": 35
|
||||
},
|
||||
{
|
||||
"sku": 135717466,
|
||||
"total_count": 100,
|
||||
"reserved": 20
|
||||
},
|
||||
{
|
||||
"sku": 135937324,
|
||||
"total_count": 100,
|
||||
"reserved": 30
|
||||
},
|
||||
{
|
||||
"sku": 1625903,
|
||||
"total_count": 10000,
|
||||
"reserved": 0
|
||||
},
|
||||
{
|
||||
"sku": 1148162,
|
||||
"total_count": 100,
|
||||
"reserved": 0
|
||||
}
|
||||
]
|
||||
1160
loms/internal/domain/service/mock/order_repository_mock.go
Normal file
1483
loms/internal/domain/service/mock/stock_repository_mock.go
Normal file
186
loms/internal/domain/service/service.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"route256/loms/internal/domain/entity"
|
||||
"route256/loms/internal/domain/model"
|
||||
|
||||
pb "route256/pkg/api/loms/v1"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
//go:generate minimock -i OrderRepository -o ./mock -s _mock.go
|
||||
type OrderRepository interface {
|
||||
OrderCreate(ctx context.Context, order *entity.Order) (entity.ID, error)
|
||||
OrderSetStatus(ctx context.Context, orderID entity.ID, newStatus string) error
|
||||
OrderGetByID(ctx context.Context, orderID entity.ID) (*entity.Order, error)
|
||||
}
|
||||
|
||||
//go:generate minimock -i StockRepository -o ./mock -s _mock.go
|
||||
type StockRepository interface {
|
||||
StockReserve(ctx context.Context, stock *entity.Stock) error
|
||||
StockReserveRemove(ctx context.Context, stock *entity.Stock) error
|
||||
StockCancel(ctx context.Context, stock *entity.Stock) error
|
||||
StockGetByID(ctx context.Context, sku entity.Sku) (*entity.Stock, error)
|
||||
}
|
||||
|
||||
type LomsService struct {
|
||||
orders OrderRepository
|
||||
stocks StockRepository
|
||||
}
|
||||
|
||||
func NewLomsService(orderRepo OrderRepository, stockRepo StockRepository) *LomsService {
|
||||
return &LomsService{
|
||||
orders: orderRepo,
|
||||
stocks: stockRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LomsService) rollbackStocks(ctx context.Context, stocks []*entity.Stock) {
|
||||
for _, stock := range stocks {
|
||||
if err := s.stocks.StockCancel(ctx, stock); err != nil {
|
||||
log.Error().Err(err).Msg("failed to rollback stock")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LomsService) OrderCreate(ctx context.Context, orderReq *pb.OrderCreateRequest) (entity.ID, error) {
|
||||
if orderReq == nil || orderReq.UserId <= 0 || len(orderReq.Items) == 0 {
|
||||
return 0, model.ErrInvalidInput
|
||||
}
|
||||
|
||||
for _, item := range orderReq.Items {
|
||||
if item.Sku <= 0 || item.Count == 0 {
|
||||
return 0, model.ErrInvalidInput
|
||||
}
|
||||
}
|
||||
|
||||
order := &entity.Order{
|
||||
OrderID: 0,
|
||||
Status: pb.OrderStatus_ORDER_STATUS_NEW.String(),
|
||||
UserID: entity.ID(orderReq.UserId),
|
||||
Items: make([]entity.OrderItem, len(orderReq.Items)),
|
||||
}
|
||||
|
||||
for i, item := range orderReq.Items {
|
||||
order.Items[i] = entity.OrderItem{
|
||||
ID: entity.Sku(item.Sku),
|
||||
Count: item.Count,
|
||||
}
|
||||
}
|
||||
|
||||
slices.SortStableFunc(order.Items, func(a, b entity.OrderItem) int {
|
||||
return int(a.ID - b.ID)
|
||||
})
|
||||
|
||||
id, err := s.orders.OrderCreate(ctx, order)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("orders.OrderCreate: %w", err)
|
||||
}
|
||||
|
||||
order.OrderID = id
|
||||
|
||||
commitedStocks := make([]*entity.Stock, 0, len(order.Items))
|
||||
for _, item := range order.Items {
|
||||
stock := &entity.Stock{
|
||||
Item: item,
|
||||
Reserved: item.Count,
|
||||
}
|
||||
|
||||
if err := s.stocks.StockReserve(ctx, stock); err != nil {
|
||||
s.rollbackStocks(ctx, commitedStocks)
|
||||
|
||||
if statusErr := s.orders.OrderSetStatus(ctx, order.OrderID, pb.OrderStatus_ORDER_STATUS_FAILED.String()); statusErr != nil {
|
||||
log.Error().Err(statusErr).Msg("failed to update status on stock reserve fail")
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("stocks.StockReserve: %w", err)
|
||||
}
|
||||
|
||||
commitedStocks = append(commitedStocks, stock)
|
||||
}
|
||||
|
||||
if err := s.orders.OrderSetStatus(ctx, order.OrderID, pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String()); err != nil {
|
||||
s.rollbackStocks(ctx, commitedStocks)
|
||||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return order.OrderID, nil
|
||||
}
|
||||
|
||||
func (s *LomsService) OrderInfo(ctx context.Context, orderID entity.ID) (*entity.Order, error) {
|
||||
if orderID <= 0 {
|
||||
return nil, model.ErrInvalidInput
|
||||
}
|
||||
|
||||
return s.orders.OrderGetByID(ctx, orderID)
|
||||
}
|
||||
|
||||
func (s *LomsService) OrderPay(ctx context.Context, orderID entity.ID) error {
|
||||
order, err := s.OrderInfo(ctx, orderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch order.Status {
|
||||
case pb.OrderStatus_ORDER_STATUS_PAYED.String():
|
||||
return nil
|
||||
case pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String():
|
||||
for _, item := range order.Items {
|
||||
if err := s.stocks.StockReserveRemove(ctx, &entity.Stock{
|
||||
Item: item,
|
||||
Reserved: item.Count,
|
||||
}); err != nil {
|
||||
log.Error().Err(err).Msg("failed to free stock reservation")
|
||||
}
|
||||
}
|
||||
|
||||
return s.orders.OrderSetStatus(ctx, orderID, pb.OrderStatus_ORDER_STATUS_PAYED.String())
|
||||
default:
|
||||
return model.ErrOrderInvalidStatus
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LomsService) OrderCancel(ctx context.Context, orderID entity.ID) error {
|
||||
order, err := s.OrderInfo(ctx, orderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch order.Status {
|
||||
case pb.OrderStatus_ORDER_STATUS_CANCELLED.String():
|
||||
return nil
|
||||
case pb.OrderStatus_ORDER_STATUS_FAILED.String(), pb.OrderStatus_ORDER_STATUS_PAYED.String():
|
||||
return model.ErrOrderInvalidStatus
|
||||
}
|
||||
|
||||
stocks := make([]*entity.Stock, len(order.Items))
|
||||
for i, item := range order.Items {
|
||||
stocks[i] = &entity.Stock{
|
||||
Item: item,
|
||||
Reserved: item.Count,
|
||||
}
|
||||
}
|
||||
|
||||
s.rollbackStocks(ctx, stocks)
|
||||
|
||||
return s.orders.OrderSetStatus(ctx, orderID, pb.OrderStatus_ORDER_STATUS_CANCELLED.String())
|
||||
}
|
||||
|
||||
func (s *LomsService) StocksInfo(ctx context.Context, sku entity.Sku) (uint32, error) {
|
||||
if sku <= 0 {
|
||||
return 0, model.ErrInvalidInput
|
||||
}
|
||||
|
||||
stock, err := s.stocks.StockGetByID(ctx, sku)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return stock.Item.Count, nil
|
||||
}
|
||||
448
loms/internal/domain/service/service_test.go
Normal file
@@ -0,0 +1,448 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/gojuno/minimock/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"route256/loms/internal/domain/entity"
|
||||
"route256/loms/internal/domain/model"
|
||||
mock "route256/loms/internal/domain/service/mock"
|
||||
|
||||
pb "route256/pkg/api/loms/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
testUser = entity.ID(1337)
|
||||
testSku = entity.Sku(199)
|
||||
)
|
||||
|
||||
func TestLomsService_OrderCreate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
mc := minimock.NewController(t)
|
||||
|
||||
goodReq := &pb.OrderCreateRequest{
|
||||
UserId: int64(testUser),
|
||||
Items: []*pb.OrderItem{
|
||||
{
|
||||
Sku: int64(testSku),
|
||||
Count: 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
badItemReq := &pb.OrderCreateRequest{
|
||||
UserId: int64(testUser),
|
||||
Items: []*pb.OrderItem{
|
||||
{
|
||||
Sku: 0,
|
||||
Count: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
orders OrderRepository
|
||||
stocks StockRepository
|
||||
}
|
||||
type args struct {
|
||||
req *pb.OrderCreateRequest
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderCreateMock.Return(1, nil).
|
||||
OrderSetStatusMock.Return(nil),
|
||||
stocks: mock.NewStockRepositoryMock(mc).
|
||||
StockReserveMock.Return(nil),
|
||||
},
|
||||
args: args{
|
||||
req: goodReq,
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "invalid input",
|
||||
fields: fields{},
|
||||
args: args{
|
||||
req: &pb.OrderCreateRequest{
|
||||
UserId: 0,
|
||||
},
|
||||
},
|
||||
wantErr: func(t require.TestingT, err error, _ ...interface{}) {
|
||||
require.ErrorIs(t, err, model.ErrInvalidInput)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid input with bad items",
|
||||
fields: fields{},
|
||||
args: args{
|
||||
req: badItemReq,
|
||||
},
|
||||
wantErr: func(t require.TestingT, err error, _ ...interface{}) {
|
||||
require.ErrorIs(t, err, model.ErrInvalidInput)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "order create error",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderCreateMock.Return(0, errors.New("order create error")),
|
||||
stocks: nil,
|
||||
},
|
||||
args: args{
|
||||
req: goodReq,
|
||||
},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
name: "stock reserve error",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderCreateMock.Return(1, nil).
|
||||
OrderSetStatusMock.Return(errors.New("status update error")),
|
||||
stocks: mock.NewStockRepositoryMock(mc).
|
||||
StockReserveMock.Return(errors.New("reservation error")),
|
||||
},
|
||||
args: args{
|
||||
req: goodReq,
|
||||
},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
name: "final status update error",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderCreateMock.Return(1, nil).
|
||||
OrderSetStatusMock.Return(errors.New("unexpected error")),
|
||||
stocks: mock.NewStockRepositoryMock(mc).
|
||||
StockReserveMock.Return(nil).
|
||||
StockCancelMock.Return(nil),
|
||||
},
|
||||
args: args{
|
||||
req: goodReq,
|
||||
},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := NewLomsService(tt.fields.orders, tt.fields.stocks)
|
||||
_, err := svc.OrderCreate(ctx, tt.args.req)
|
||||
tt.wantErr(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLomsService_OrderPay(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
mc := minimock.NewController(t)
|
||||
|
||||
awaitingOrder := &entity.Order{
|
||||
OrderID: 1,
|
||||
Status: pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String(),
|
||||
Items: []entity.OrderItem{{
|
||||
ID: testSku,
|
||||
Count: 2,
|
||||
}},
|
||||
}
|
||||
|
||||
payedOrder := &entity.Order{OrderID: 2, Status: pb.OrderStatus_ORDER_STATUS_PAYED.String()}
|
||||
badStatusOrder := &entity.Order{OrderID: 3, Status: pb.OrderStatus_ORDER_STATUS_FAILED.String()}
|
||||
|
||||
type fields struct {
|
||||
orders OrderRepository
|
||||
stocks StockRepository
|
||||
}
|
||||
type args struct {
|
||||
id entity.ID
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderGetByIDMock.Return(awaitingOrder, nil).
|
||||
OrderSetStatusMock.Return(nil),
|
||||
stocks: mock.NewStockRepositoryMock(mc).
|
||||
StockReserveRemoveMock.Return(nil),
|
||||
},
|
||||
args: args{
|
||||
id: awaitingOrder.OrderID,
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "invalid input",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc),
|
||||
stocks: mock.NewStockRepositoryMock(mc),
|
||||
},
|
||||
args: args{
|
||||
id: 0,
|
||||
},
|
||||
wantErr: func(t require.TestingT, err error, _ ...interface{}) {
|
||||
require.ErrorIs(t, err, model.ErrInvalidInput)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "already payed",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderGetByIDMock.Return(payedOrder, nil),
|
||||
},
|
||||
args: args{
|
||||
id: payedOrder.OrderID,
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "invalid status",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderGetByIDMock.Return(badStatusOrder, nil),
|
||||
},
|
||||
args: args{
|
||||
id: badStatusOrder.OrderID,
|
||||
},
|
||||
wantErr: func(t require.TestingT, err error, _ ...interface{}) {
|
||||
require.ErrorIs(t, err, model.ErrOrderInvalidStatus)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unexpected logged error on updating stocks reserves",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderGetByIDMock.Return(awaitingOrder, nil).
|
||||
OrderSetStatusMock.Return(nil),
|
||||
stocks: mock.NewStockRepositoryMock(mc).
|
||||
StockReserveRemoveMock.Return(errors.New("unexpected error")),
|
||||
},
|
||||
args: args{
|
||||
id: badStatusOrder.OrderID,
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := NewLomsService(tt.fields.orders, tt.fields.stocks)
|
||||
err := svc.OrderPay(ctx, tt.args.id)
|
||||
tt.wantErr(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLomsService_OrderInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
mc := minimock.NewController(t)
|
||||
svc := NewLomsService(
|
||||
mock.NewOrderRepositoryMock(mc),
|
||||
mock.NewStockRepositoryMock(mc),
|
||||
)
|
||||
|
||||
err := svc.OrderPay(context.Background(), 0)
|
||||
require.ErrorIs(t, err, model.ErrInvalidInput)
|
||||
}
|
||||
|
||||
func TestLomsService_OrderCancel(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
mc := minimock.NewController(t)
|
||||
|
||||
awaiting := &entity.Order{
|
||||
OrderID: 1,
|
||||
Status: pb.OrderStatus_ORDER_STATUS_AWAITING_PAYMENT.String(),
|
||||
Items: []entity.OrderItem{{
|
||||
ID: testSku, Count: 1,
|
||||
}},
|
||||
}
|
||||
cancelled := &entity.Order{
|
||||
OrderID: 2,
|
||||
Status: pb.OrderStatus_ORDER_STATUS_CANCELLED.String(),
|
||||
}
|
||||
payed := &entity.Order{
|
||||
OrderID: 3,
|
||||
Status: pb.OrderStatus_ORDER_STATUS_PAYED.String(),
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
orders OrderRepository
|
||||
stocks StockRepository
|
||||
}
|
||||
type args struct {
|
||||
id entity.ID
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderGetByIDMock.Return(awaiting, nil).
|
||||
OrderSetStatusMock.Return(nil),
|
||||
stocks: mock.NewStockRepositoryMock(mc).
|
||||
StockCancelMock.Return(nil),
|
||||
},
|
||||
args: args{
|
||||
id: awaiting.OrderID,
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "invalid input",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc),
|
||||
stocks: mock.NewStockRepositoryMock(mc),
|
||||
},
|
||||
args: args{
|
||||
id: 0,
|
||||
},
|
||||
wantErr: func(t require.TestingT, err error, _ ...interface{}) {
|
||||
require.ErrorIs(t, err, model.ErrInvalidInput)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "already cancelled",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderGetByIDMock.Return(cancelled, nil),
|
||||
},
|
||||
args: args{
|
||||
id: cancelled.OrderID,
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "invalid status",
|
||||
fields: fields{
|
||||
orders: mock.NewOrderRepositoryMock(mc).
|
||||
OrderGetByIDMock.Return(payed, nil),
|
||||
},
|
||||
args: args{
|
||||
id: payed.OrderID,
|
||||
},
|
||||
wantErr: func(t require.TestingT, err error, _ ...interface{}) {
|
||||
require.ErrorIs(t, err, model.ErrOrderInvalidStatus)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := NewLomsService(tt.fields.orders, tt.fields.stocks)
|
||||
err := svc.OrderCancel(ctx, tt.args.id)
|
||||
tt.wantErr(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLomsService_StocksInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
mc := minimock.NewController(t)
|
||||
|
||||
type fields struct{ stocks StockRepository }
|
||||
type args struct{ sku entity.Sku }
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want uint32
|
||||
wantErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
fields: fields{
|
||||
stocks: mock.NewStockRepositoryMock(mc).
|
||||
StockGetByIDMock.Return(&entity.Stock{
|
||||
Item: entity.OrderItem{
|
||||
Count: 7,
|
||||
},
|
||||
}, nil),
|
||||
},
|
||||
args: args{
|
||||
sku: testSku,
|
||||
},
|
||||
want: 7,
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "invalid sku",
|
||||
fields: fields{},
|
||||
args: args{
|
||||
sku: 0,
|
||||
},
|
||||
wantErr: func(t require.TestingT, err error, _ ...interface{}) {
|
||||
require.ErrorIs(t, err, model.ErrInvalidInput)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get by id error",
|
||||
fields: fields{
|
||||
stocks: mock.NewStockRepositoryMock(mc).
|
||||
StockGetByIDMock.Return(nil, errors.New("unexpected error")),
|
||||
},
|
||||
args: args{
|
||||
sku: testSku,
|
||||
},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := NewLomsService(nil, tt.fields.stocks)
|
||||
got, err := svc.StocksInfo(ctx, tt.args.sku)
|
||||
tt.wantErr(t, err)
|
||||
if err == nil {
|
||||
assert.Equal(t, tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
74
loms/internal/infra/config/config.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Service struct {
|
||||
Host string `yaml:"host"`
|
||||
GRPCPort string `yaml:"grpc_port"`
|
||||
HTTPPort string `yaml:"http_port"`
|
||||
LogLevel string `yaml:"log_level"`
|
||||
} `yaml:"service"`
|
||||
|
||||
Jaeger struct {
|
||||
Host string `yaml:"host"`
|
||||
Port string `yaml:"port"`
|
||||
} `yaml:"jaeger"`
|
||||
|
||||
DatabaseMaster struct {
|
||||
Host string `yaml:"host"`
|
||||
Port string `yaml:"port"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
DBName string `yaml:"db_name"`
|
||||
} `yaml:"db_master"`
|
||||
|
||||
DatabaseReplica struct {
|
||||
Host string `yaml:"host"`
|
||||
Port string `yaml:"port"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
DBName string `yaml:"db_name"`
|
||||
} `yaml:"db_replica"`
|
||||
|
||||
Kafka struct {
|
||||
Host string `yaml:"host"`
|
||||
Port string `yaml:"port"`
|
||||
OrderTopic string `yaml:"order_topic"`
|
||||
Brokers string `yaml:"brokers"`
|
||||
} `yaml:"kafka"`
|
||||
}
|
||||
|
||||
func LoadConfig(filename string) (*Config, error) {
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgRoot := filepath.Join(workDir, "configs")
|
||||
absCfgRoot, _ := filepath.Abs(cfgRoot)
|
||||
|
||||
filePath := filepath.Join(absCfgRoot, filepath.Clean(filename))
|
||||
if !strings.HasPrefix(filePath, absCfgRoot) {
|
||||
return nil, fmt.Errorf("invalid path")
|
||||
}
|
||||
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
config := &Config{}
|
||||
if err := yaml.NewDecoder(f).Decode(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
24
loms/internal/infra/grpc/middleware/logging.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package mw
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func Logging(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
|
||||
raw, _ := protojson.Marshal((req).(proto.Message))
|
||||
log.Debug().Msgf("request: method: %v, req: %s", info.FullMethod, string(raw))
|
||||
|
||||
if resp, err = handler(ctx, req); err != nil {
|
||||
log.Debug().Msgf("response: method: %v, err: %s", info.FullMethod, err.Error())
|
||||
return
|
||||
}
|
||||
rawResp, _ := protojson.Marshal((resp).(proto.Message))
|
||||
log.Debug().Msgf("response: method: %v, resp: %s", info.FullMethod, string(rawResp))
|
||||
|
||||
return
|
||||
}
|
||||
18
loms/internal/infra/grpc/middleware/validate.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package mw
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func Validate(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
if v, ok := req.(interface{ Validate() error }); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
}
|
||||
return handler(ctx, req)
|
||||
}
|
||||
130
loms/tests/integration/loms_integration_test.go
Normal file
@@ -0,0 +1,130 @@
|
||||
//go:build integration
|
||||
// +build integration
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ozontech/allure-go/pkg/framework/provider"
|
||||
"github.com/ozontech/allure-go/pkg/framework/suite"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"route256/loms/internal/app/server"
|
||||
"route256/loms/internal/domain/entity"
|
||||
ordersRepository "route256/loms/internal/domain/repository/orders"
|
||||
stocksRepository "route256/loms/internal/domain/repository/stocks"
|
||||
lomsService "route256/loms/internal/domain/service"
|
||||
|
||||
pb "route256/pkg/api/loms/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
// "total_count": 100,
|
||||
// "reserved": 35
|
||||
testSKU = entity.Sku(1076963)
|
||||
|
||||
testUID = entity.ID(1337)
|
||||
testCount = uint32(2)
|
||||
)
|
||||
|
||||
type LomsIntegrationSuite struct {
|
||||
suite.Suite
|
||||
|
||||
grpcSrv *grpc.Server
|
||||
grpcConn *grpc.ClientConn
|
||||
lomsClient pb.LOMSClient
|
||||
}
|
||||
|
||||
func TestLomsIntegrationSuite(t *testing.T) {
|
||||
suite.RunSuite(t, new(LomsIntegrationSuite))
|
||||
}
|
||||
|
||||
func (s *LomsIntegrationSuite) BeforeAll(t provider.T) {
|
||||
t.WithNewStep("init cart-service", func(sCtx provider.StepCtx) {
|
||||
orderRepo := ordersRepository.NewInMemoryRepository(100)
|
||||
stockRepo, err := stocksRepository.NewInMemoryRepository(100)
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
svc := lomsService.NewLomsService(orderRepo, stockRepo)
|
||||
lomsServer := server.NewServer(svc)
|
||||
|
||||
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
s.grpcSrv = grpc.NewServer()
|
||||
pb.RegisterLOMSServer(s.grpcSrv, lomsServer)
|
||||
|
||||
go func() { _ = s.grpcSrv.Serve(lis) }()
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
conn, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
s.grpcConn = conn
|
||||
s.lomsClient = pb.NewLOMSClient(conn)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *LomsIntegrationSuite) AfterAll(t provider.T) {
|
||||
s.grpcSrv.Stop()
|
||||
_ = s.grpcConn.Close()
|
||||
}
|
||||
|
||||
func (s *LomsIntegrationSuite) TestOrderProcessPositive(t provider.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
var orderID int64
|
||||
|
||||
t.WithNewStep("create order", func(sCtx provider.StepCtx) {
|
||||
req := &pb.OrderCreateRequest{
|
||||
UserId: int64(testUID),
|
||||
Items: []*pb.OrderItem{{
|
||||
Sku: int64(testSKU),
|
||||
Count: testCount,
|
||||
}},
|
||||
}
|
||||
|
||||
resp, err := s.lomsClient.OrderCreate(ctx, req)
|
||||
sCtx.Require().NoError(err)
|
||||
sCtx.Require().Greater(resp.OrderId, int64(0))
|
||||
orderID = resp.OrderId
|
||||
})
|
||||
|
||||
t.WithNewStep("verify order info (NEW)", func(sCtx provider.StepCtx) {
|
||||
resp, err := s.lomsClient.OrderInfo(ctx, &pb.OrderInfoRequest{OrderId: orderID})
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
sCtx.Require().Equal("awaiting payment", resp.Status)
|
||||
sCtx.Require().Equal(int64(testUID), resp.UserId)
|
||||
sCtx.Require().Len(resp.Items, 1)
|
||||
sCtx.Require().Equal(int64(testSKU), resp.Items[0].Sku)
|
||||
sCtx.Require().Equal(testCount, resp.Items[0].Count)
|
||||
})
|
||||
|
||||
t.WithNewStep("pay order", func(sCtx provider.StepCtx) {
|
||||
_, err := s.lomsClient.OrderPay(ctx, &pb.OrderPayRequest{OrderId: orderID})
|
||||
sCtx.Require().NoError(err)
|
||||
})
|
||||
|
||||
t.WithNewStep("verify order info (PAYED)", func(sCtx provider.StepCtx) {
|
||||
resp, err := s.lomsClient.OrderInfo(ctx, &pb.OrderInfoRequest{OrderId: orderID})
|
||||
sCtx.Require().NoError(err)
|
||||
sCtx.Require().Equal("payed", resp.Status)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *LomsIntegrationSuite) TestStocksInfoPositive(t provider.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.WithNewStep("call StocksInfo", func(sCtx provider.StepCtx) {
|
||||
resp, err := s.lomsClient.StocksInfo(ctx, &pb.StocksInfoRequest{Sku: int64(testSKU)})
|
||||
sCtx.Require().NoError(err)
|
||||
sCtx.Require().Greater(resp.Count, uint32(0))
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,66 @@
|
||||
CURDIR=$(shell pwd)
|
||||
BINDIR=${CURDIR}/bin
|
||||
|
||||
.PHONY: .bin-deps
|
||||
.bin-deps:
|
||||
$(info Installing binary dependencies...)
|
||||
|
||||
GOBIN=$(BINDIR) go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1 && \
|
||||
GOBIN=$(BINDIR) go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0 && \
|
||||
GOBIN=$(BINDIR) go install github.com/envoyproxy/protoc-gen-validate@v1.0.4 && \
|
||||
GOBIN=$(BINDIR) go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.19.1 && \
|
||||
GOBIN=$(BINDIR) go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.19.1 && \
|
||||
GOBIN=$(BINDIR) go install github.com/go-swagger/go-swagger/cmd/swagger@v0.30.5
|
||||
|
||||
# Устанавливаем proto описания google/protobuf
|
||||
vendor-proto/google/protobuf:
|
||||
git clone -b main --single-branch -n --depth=1 \
|
||||
https://github.com/protocolbuffers/protobuf vendor-proto/protobuf &&\
|
||||
cd vendor-proto/protobuf &&\
|
||||
git sparse-checkout set --no-cone src/google/protobuf &&\
|
||||
git checkout
|
||||
mkdir -p vendor-proto/google
|
||||
mv vendor-proto/protobuf/src/google/protobuf vendor-proto/google
|
||||
rm -rf vendor-proto/protobuf
|
||||
|
||||
# Устанавливаем proto описания validate
|
||||
vendor-proto/validate:
|
||||
git clone -b main --single-branch --depth=2 \
|
||||
https://github.com/bufbuild/protoc-gen-validate vendor-proto/tmp && \
|
||||
cd vendor-proto/tmp && \
|
||||
git sparse-checkout set --no-cone validate &&\
|
||||
git checkout
|
||||
mkdir -p vendor-proto/validate
|
||||
mv vendor-proto/tmp/validate vendor-proto/
|
||||
rm -rf vendor-proto/tmp
|
||||
|
||||
# Устанавливаем proto описания google/googleapis
|
||||
vendor-proto/google/api:
|
||||
git clone -b master --single-branch -n --depth=1 \
|
||||
https://github.com/googleapis/googleapis vendor-proto/googleapis && \
|
||||
cd vendor-proto/googleapis && \
|
||||
git sparse-checkout set --no-cone google/api && \
|
||||
git checkout
|
||||
mkdir -p vendor-proto/google
|
||||
mv vendor-proto/googleapis/google/api vendor-proto/google
|
||||
rm -rf vendor-proto/googleapis
|
||||
|
||||
# Устанавливаем proto описания protoc-gen-openapiv2/options
|
||||
vendor-proto/protoc-gen-openapiv2/options:
|
||||
git clone -b main --single-branch -n --depth=1 \
|
||||
https://github.com/grpc-ecosystem/grpc-gateway vendor-proto/grpc-ecosystem && \
|
||||
cd vendor-proto/grpc-ecosystem && \
|
||||
git sparse-checkout set --no-cone protoc-gen-openapiv2/options && \
|
||||
git checkout
|
||||
mkdir -p vendor-proto/protoc-gen-openapiv2
|
||||
mv vendor-proto/grpc-ecosystem/protoc-gen-openapiv2/options vendor-proto/protoc-gen-openapiv2
|
||||
rm -rf vendor-proto/grpc-ecosystem
|
||||
|
||||
.PHONY: .vendor-rm
|
||||
.vendor-rm:
|
||||
rm -rf vendor-proto
|
||||
|
||||
.vendor-proto: .vendor-rm vendor-proto/google/protobuf vendor-proto/validate vendor-proto/google/api vendor-proto/protoc-gen-openapiv2/options
|
||||
|
||||
define generate
|
||||
@if [ -f "$(1)/go.mod" ]; then \
|
||||
@@ -11,12 +73,35 @@ define generate
|
||||
fi
|
||||
endef
|
||||
|
||||
define proto_gen
|
||||
@echo "== generating $(1) =="
|
||||
@protoc \
|
||||
-I api \
|
||||
-I vendor-proto \
|
||||
--plugin=protoc-gen-go=$(BINDIR)/protoc-gen-go \
|
||||
--go_out=pkg/api/ --go_opt paths=source_relative \
|
||||
--plugin=protoc-gen-go-grpc=$(BINDIR)/protoc-gen-go-grpc \
|
||||
--go-grpc_out=pkg/api/ --go-grpc_opt paths=source_relative \
|
||||
--plugin=protoc-gen-validate=$(BINDIR)/protoc-gen-validate \
|
||||
--validate_out="lang=go,paths=source_relative:pkg/api/" \
|
||||
--plugin=protoc-gen-grpc-gateway=$(BINDIR)/protoc-gen-grpc-gateway \
|
||||
--grpc-gateway_out=pkg/api/ \
|
||||
--grpc-gateway_opt=logtostderr=true,paths=source_relative,generate_unbound_methods=true \
|
||||
--plugin=protoc-gen-openapiv2=$(BINDIR)/protoc-gen-openapiv2 \
|
||||
--openapiv2_out=api/openapiv2 \
|
||||
--openapiv2_opt=logtostderr=true \
|
||||
$(1)
|
||||
endef
|
||||
|
||||
cart-generate:
|
||||
$(call generate,cart)
|
||||
cd cart && go mod tidy
|
||||
|
||||
loms-generate:
|
||||
$(call generate,loms)
|
||||
mkdir -p "api/openapiv2"
|
||||
$(foreach f,$(shell find api/loms/v1 -type f -name '*.proto'),$(call proto_gen,$(f),loms))
|
||||
cd loms && go mod tidy
|
||||
|
||||
notifier-generate:
|
||||
$(call generate,notifier)
|
||||
|
||||
827
pkg/api/loms/v1/loms.pb.go
Normal file
@@ -0,0 +1,827 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v6.30.0
|
||||
// source: loms/v1/loms.proto
|
||||
|
||||
package loms
|
||||
|
||||
import (
|
||||
_ "github.com/envoyproxy/protoc-gen-validate/validate"
|
||||
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type OrderStatus int32
|
||||
|
||||
const (
|
||||
OrderStatus_ORDER_STATUS_UNSPECIFIED OrderStatus = 0
|
||||
OrderStatus_ORDER_STATUS_NEW OrderStatus = 1
|
||||
OrderStatus_ORDER_STATUS_AWAITING_PAYMENT OrderStatus = 2
|
||||
OrderStatus_ORDER_STATUS_FAILED OrderStatus = 3
|
||||
OrderStatus_ORDER_STATUS_PAYED OrderStatus = 4
|
||||
OrderStatus_ORDER_STATUS_CANCELLED OrderStatus = 5
|
||||
)
|
||||
|
||||
// Enum value maps for OrderStatus.
|
||||
var (
|
||||
OrderStatus_name = map[int32]string{
|
||||
0: "ORDER_STATUS_UNSPECIFIED",
|
||||
1: "ORDER_STATUS_NEW",
|
||||
2: "ORDER_STATUS_AWAITING_PAYMENT",
|
||||
3: "ORDER_STATUS_FAILED",
|
||||
4: "ORDER_STATUS_PAYED",
|
||||
5: "ORDER_STATUS_CANCELLED",
|
||||
}
|
||||
OrderStatus_value = map[string]int32{
|
||||
"ORDER_STATUS_UNSPECIFIED": 0,
|
||||
"ORDER_STATUS_NEW": 1,
|
||||
"ORDER_STATUS_AWAITING_PAYMENT": 2,
|
||||
"ORDER_STATUS_FAILED": 3,
|
||||
"ORDER_STATUS_PAYED": 4,
|
||||
"ORDER_STATUS_CANCELLED": 5,
|
||||
}
|
||||
)
|
||||
|
||||
func (x OrderStatus) Enum() *OrderStatus {
|
||||
p := new(OrderStatus)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x OrderStatus) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (OrderStatus) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_loms_v1_loms_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (OrderStatus) Type() protoreflect.EnumType {
|
||||
return &file_loms_v1_loms_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x OrderStatus) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OrderStatus.Descriptor instead.
|
||||
func (OrderStatus) EnumDescriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type OrderItem struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Sku int64 `protobuf:"varint,1,opt,name=sku,proto3" json:"sku,omitempty"`
|
||||
Count uint32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OrderItem) Reset() {
|
||||
*x = OrderItem{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OrderItem) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OrderItem) ProtoMessage() {}
|
||||
|
||||
func (x *OrderItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OrderItem.ProtoReflect.Descriptor instead.
|
||||
func (*OrderItem) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *OrderItem) GetSku() int64 {
|
||||
if x != nil {
|
||||
return x.Sku
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *OrderItem) GetCount() uint32 {
|
||||
if x != nil {
|
||||
return x.Count
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type OrderCreateRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
Items []*OrderItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OrderCreateRequest) Reset() {
|
||||
*x = OrderCreateRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OrderCreateRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OrderCreateRequest) ProtoMessage() {}
|
||||
|
||||
func (x *OrderCreateRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OrderCreateRequest.ProtoReflect.Descriptor instead.
|
||||
func (*OrderCreateRequest) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *OrderCreateRequest) GetUserId() int64 {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *OrderCreateRequest) GetItems() []*OrderItem {
|
||||
if x != nil {
|
||||
return x.Items
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type OrderCreateResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
OrderId int64 `protobuf:"varint,1,opt,name=orderId,proto3" json:"orderId,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OrderCreateResponse) Reset() {
|
||||
*x = OrderCreateResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OrderCreateResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OrderCreateResponse) ProtoMessage() {}
|
||||
|
||||
func (x *OrderCreateResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OrderCreateResponse.ProtoReflect.Descriptor instead.
|
||||
func (*OrderCreateResponse) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *OrderCreateResponse) GetOrderId() int64 {
|
||||
if x != nil {
|
||||
return x.OrderId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type OrderInfoRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
OrderId int64 `protobuf:"varint,1,opt,name=orderId,proto3" json:"orderId,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OrderInfoRequest) Reset() {
|
||||
*x = OrderInfoRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OrderInfoRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OrderInfoRequest) ProtoMessage() {}
|
||||
|
||||
func (x *OrderInfoRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OrderInfoRequest.ProtoReflect.Descriptor instead.
|
||||
func (*OrderInfoRequest) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *OrderInfoRequest) GetOrderId() int64 {
|
||||
if x != nil {
|
||||
return x.OrderId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type OrderInfoResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||
UserId int64 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
Items []*OrderItem `protobuf:"bytes,3,rep,name=items,proto3" json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OrderInfoResponse) Reset() {
|
||||
*x = OrderInfoResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OrderInfoResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OrderInfoResponse) ProtoMessage() {}
|
||||
|
||||
func (x *OrderInfoResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OrderInfoResponse.ProtoReflect.Descriptor instead.
|
||||
func (*OrderInfoResponse) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *OrderInfoResponse) GetStatus() string {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *OrderInfoResponse) GetUserId() int64 {
|
||||
if x != nil {
|
||||
return x.UserId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *OrderInfoResponse) GetItems() []*OrderItem {
|
||||
if x != nil {
|
||||
return x.Items
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type OrderPayRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
OrderId int64 `protobuf:"varint,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OrderPayRequest) Reset() {
|
||||
*x = OrderPayRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OrderPayRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OrderPayRequest) ProtoMessage() {}
|
||||
|
||||
func (x *OrderPayRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OrderPayRequest.ProtoReflect.Descriptor instead.
|
||||
func (*OrderPayRequest) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *OrderPayRequest) GetOrderId() int64 {
|
||||
if x != nil {
|
||||
return x.OrderId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type OrderCancelRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
OrderId int64 `protobuf:"varint,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OrderCancelRequest) Reset() {
|
||||
*x = OrderCancelRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OrderCancelRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OrderCancelRequest) ProtoMessage() {}
|
||||
|
||||
func (x *OrderCancelRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OrderCancelRequest.ProtoReflect.Descriptor instead.
|
||||
func (*OrderCancelRequest) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *OrderCancelRequest) GetOrderId() int64 {
|
||||
if x != nil {
|
||||
return x.OrderId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type StocksInfoRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Sku int64 `protobuf:"varint,1,opt,name=sku,proto3" json:"sku,omitempty"`
|
||||
}
|
||||
|
||||
func (x *StocksInfoRequest) Reset() {
|
||||
*x = StocksInfoRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *StocksInfoRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*StocksInfoRequest) ProtoMessage() {}
|
||||
|
||||
func (x *StocksInfoRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use StocksInfoRequest.ProtoReflect.Descriptor instead.
|
||||
func (*StocksInfoRequest) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *StocksInfoRequest) GetSku() int64 {
|
||||
if x != nil {
|
||||
return x.Sku
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type StocksInfoResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Count uint32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"`
|
||||
}
|
||||
|
||||
func (x *StocksInfoResponse) Reset() {
|
||||
*x = StocksInfoResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *StocksInfoResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*StocksInfoResponse) ProtoMessage() {}
|
||||
|
||||
func (x *StocksInfoResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_loms_v1_loms_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use StocksInfoResponse.ProtoReflect.Descriptor instead.
|
||||
func (*StocksInfoResponse) Descriptor() ([]byte, []int) {
|
||||
return file_loms_v1_loms_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *StocksInfoResponse) GetCount() uint32 {
|
||||
if x != nil {
|
||||
return x.Count
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_loms_v1_loms_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_loms_v1_loms_proto_rawDesc = []byte{
|
||||
0x0a, 0x12, 0x6c, 0x6f, 0x6d, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6c, 0x6f, 0x6d, 0x73, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69,
|
||||
0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||
0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f,
|
||||
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x45, 0x0a, 0x09, 0x4f, 0x72, 0x64, 0x65,
|
||||
0x72, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x19, 0x0a, 0x03, 0x73, 0x6b, 0x75, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x03, 0x73, 0x6b, 0x75,
|
||||
0x12, 0x1d, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42,
|
||||
0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x20, 0x00, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22,
|
||||
0x62, 0x0a, 0x12, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52,
|
||||
0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73,
|
||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x74,
|
||||
0x65, 0x6d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x05, 0x69, 0x74,
|
||||
0x65, 0x6d, 0x73, 0x22, 0x2f, 0x0a, 0x13, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72,
|
||||
0x64, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, 0x72, 0x64,
|
||||
0x65, 0x72, 0x49, 0x64, 0x22, 0x35, 0x0a, 0x10, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66,
|
||||
0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x07, 0x6f, 0x72, 0x64, 0x65,
|
||||
0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02,
|
||||
0x20, 0x00, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x22, 0x66, 0x0a, 0x11, 0x4f,
|
||||
0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49,
|
||||
0x64, 0x12, 0x20, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x0a, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74,
|
||||
0x65, 0x6d, 0x73, 0x22, 0x35, 0x0a, 0x0f, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x50, 0x61, 0x79, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20,
|
||||
0x00, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x64, 0x22, 0x38, 0x0a, 0x12, 0x4f, 0x72,
|
||||
0x64, 0x65, 0x72, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x22, 0x0a, 0x08, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52, 0x07, 0x6f, 0x72, 0x64,
|
||||
0x65, 0x72, 0x49, 0x64, 0x22, 0x2e, 0x0a, 0x11, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x73, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x03, 0x73, 0x6b, 0x75,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x22, 0x02, 0x20, 0x00, 0x52,
|
||||
0x03, 0x73, 0x6b, 0x75, 0x22, 0x2a, 0x0a, 0x12, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x73, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
||||
0x2a, 0xb1, 0x01, 0x0a, 0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x12, 0x1c, 0x0a, 0x18, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14,
|
||||
0x0a, 0x10, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4e,
|
||||
0x45, 0x57, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x54,
|
||||
0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x50, 0x41,
|
||||
0x59, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x4f, 0x52, 0x44, 0x45, 0x52,
|
||||
0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03,
|
||||
0x12, 0x16, 0x0a, 0x12, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53,
|
||||
0x5f, 0x50, 0x41, 0x59, 0x45, 0x44, 0x10, 0x04, 0x12, 0x1a, 0x0a, 0x16, 0x4f, 0x52, 0x44, 0x45,
|
||||
0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c,
|
||||
0x45, 0x44, 0x10, 0x05, 0x32, 0xc2, 0x04, 0x0a, 0x04, 0x4c, 0x4f, 0x4d, 0x53, 0x12, 0x52, 0x0a,
|
||||
0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x4f,
|
||||
0x72, 0x64, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x14, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22,
|
||||
0x0d, 0x2f, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x3a, 0x01,
|
||||
0x2a, 0x12, 0x47, 0x0a, 0x09, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x11,
|
||||
0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x12, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f,
|
||||
0x6f, 0x72, 0x64, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x4b, 0x0a, 0x08, 0x4f, 0x72,
|
||||
0x64, 0x65, 0x72, 0x50, 0x61, 0x79, 0x12, 0x10, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x50, 0x61,
|
||||
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
|
||||
0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x22, 0x0a, 0x2f, 0x6f, 0x72, 0x64, 0x65, 0x72,
|
||||
0x2f, 0x70, 0x61, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x54, 0x0a, 0x0b, 0x4f, 0x72, 0x64, 0x65, 0x72,
|
||||
0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x13, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x43, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
|
||||
0x70, 0x74, 0x79, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x22, 0x0d, 0x2f, 0x6f, 0x72,
|
||||
0x64, 0x65, 0x72, 0x2f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x4a, 0x0a,
|
||||
0x0a, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x2e, 0x53, 0x74,
|
||||
0x6f, 0x63, 0x6b, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x13, 0x2e, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x73,
|
||||
0x74, 0x6f, 0x63, 0x6b, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x1a, 0xad, 0x01, 0x92, 0x41, 0xa9, 0x01,
|
||||
0x12, 0x0c, 0x4c, 0x4f, 0x4d, 0x53, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x1a, 0x98,
|
||||
0x01, 0x0a, 0x20, 0x46, 0x69, 0x6e, 0x64, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x6d, 0x6f, 0x72, 0x65,
|
||||
0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65,
|
||||
0x77, 0x61, 0x79, 0x12, 0x74, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f,
|
||||
0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65,
|
||||
0x77, 0x61, 0x79, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x65, 0x78,
|
||||
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x70, 0x62, 0x2f,
|
||||
0x61, 0x5f, 0x62, 0x69, 0x74, 0x5f, 0x6f, 0x66, 0x5f, 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68,
|
||||
0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x61, 0x5a, 0x1d, 0x72, 0x6f, 0x75,
|
||||
0x74, 0x65, 0x32, 0x35, 0x36, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6c, 0x6f,
|
||||
0x6d, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x6c, 0x6f, 0x6d, 0x73, 0x92, 0x41, 0x3f, 0x12, 0x15, 0x0a,
|
||||
0x0c, 0x4c, 0x4f, 0x4d, 0x53, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x32, 0x05, 0x31,
|
||||
0x2e, 0x30, 0x2e, 0x30, 0x2a, 0x02, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c,
|
||||
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_loms_v1_loms_proto_rawDescOnce sync.Once
|
||||
file_loms_v1_loms_proto_rawDescData = file_loms_v1_loms_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_loms_v1_loms_proto_rawDescGZIP() []byte {
|
||||
file_loms_v1_loms_proto_rawDescOnce.Do(func() {
|
||||
file_loms_v1_loms_proto_rawDescData = protoimpl.X.CompressGZIP(file_loms_v1_loms_proto_rawDescData)
|
||||
})
|
||||
return file_loms_v1_loms_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_loms_v1_loms_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_loms_v1_loms_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||
var file_loms_v1_loms_proto_goTypes = []interface{}{
|
||||
(OrderStatus)(0), // 0: OrderStatus
|
||||
(*OrderItem)(nil), // 1: OrderItem
|
||||
(*OrderCreateRequest)(nil), // 2: OrderCreateRequest
|
||||
(*OrderCreateResponse)(nil), // 3: OrderCreateResponse
|
||||
(*OrderInfoRequest)(nil), // 4: OrderInfoRequest
|
||||
(*OrderInfoResponse)(nil), // 5: OrderInfoResponse
|
||||
(*OrderPayRequest)(nil), // 6: OrderPayRequest
|
||||
(*OrderCancelRequest)(nil), // 7: OrderCancelRequest
|
||||
(*StocksInfoRequest)(nil), // 8: StocksInfoRequest
|
||||
(*StocksInfoResponse)(nil), // 9: StocksInfoResponse
|
||||
(*emptypb.Empty)(nil), // 10: google.protobuf.Empty
|
||||
}
|
||||
var file_loms_v1_loms_proto_depIdxs = []int32{
|
||||
1, // 0: OrderCreateRequest.items:type_name -> OrderItem
|
||||
1, // 1: OrderInfoResponse.items:type_name -> OrderItem
|
||||
2, // 2: LOMS.OrderCreate:input_type -> OrderCreateRequest
|
||||
4, // 3: LOMS.OrderInfo:input_type -> OrderInfoRequest
|
||||
6, // 4: LOMS.OrderPay:input_type -> OrderPayRequest
|
||||
7, // 5: LOMS.OrderCancel:input_type -> OrderCancelRequest
|
||||
8, // 6: LOMS.StocksInfo:input_type -> StocksInfoRequest
|
||||
3, // 7: LOMS.OrderCreate:output_type -> OrderCreateResponse
|
||||
5, // 8: LOMS.OrderInfo:output_type -> OrderInfoResponse
|
||||
10, // 9: LOMS.OrderPay:output_type -> google.protobuf.Empty
|
||||
10, // 10: LOMS.OrderCancel:output_type -> google.protobuf.Empty
|
||||
9, // 11: LOMS.StocksInfo:output_type -> StocksInfoResponse
|
||||
7, // [7:12] is the sub-list for method output_type
|
||||
2, // [2:7] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_loms_v1_loms_proto_init() }
|
||||
func file_loms_v1_loms_proto_init() {
|
||||
if File_loms_v1_loms_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_loms_v1_loms_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OrderItem); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_loms_v1_loms_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OrderCreateRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_loms_v1_loms_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OrderCreateResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_loms_v1_loms_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OrderInfoRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_loms_v1_loms_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OrderInfoResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_loms_v1_loms_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OrderPayRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_loms_v1_loms_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OrderCancelRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_loms_v1_loms_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StocksInfoRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_loms_v1_loms_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StocksInfoResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_loms_v1_loms_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 9,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_loms_v1_loms_proto_goTypes,
|
||||
DependencyIndexes: file_loms_v1_loms_proto_depIdxs,
|
||||
EnumInfos: file_loms_v1_loms_proto_enumTypes,
|
||||
MessageInfos: file_loms_v1_loms_proto_msgTypes,
|
||||
}.Build()
|
||||
File_loms_v1_loms_proto = out.File
|
||||
file_loms_v1_loms_proto_rawDesc = nil
|
||||
file_loms_v1_loms_proto_goTypes = nil
|
||||
file_loms_v1_loms_proto_depIdxs = nil
|
||||
}
|
||||
491
pkg/api/loms/v1/loms.pb.gw.go
Normal file
@@ -0,0 +1,491 @@
|
||||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: loms/v1/loms.proto
|
||||
|
||||
/*
|
||||
Package loms is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package loms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Suppress "imported and not used" errors
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
var _ = metadata.Join
|
||||
|
||||
func request_LOMS_OrderCreate_0(ctx context.Context, marshaler runtime.Marshaler, client LOMSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrderCreateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.OrderCreate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_LOMS_OrderCreate_0(ctx context.Context, marshaler runtime.Marshaler, server LOMSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrderCreateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.OrderCreate(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_LOMS_OrderInfo_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_LOMS_OrderInfo_0(ctx context.Context, marshaler runtime.Marshaler, client LOMSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrderInfoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_LOMS_OrderInfo_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.OrderInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_LOMS_OrderInfo_0(ctx context.Context, marshaler runtime.Marshaler, server LOMSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrderInfoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_LOMS_OrderInfo_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.OrderInfo(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_LOMS_OrderPay_0(ctx context.Context, marshaler runtime.Marshaler, client LOMSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrderPayRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.OrderPay(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_LOMS_OrderPay_0(ctx context.Context, marshaler runtime.Marshaler, server LOMSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrderPayRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.OrderPay(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_LOMS_OrderCancel_0(ctx context.Context, marshaler runtime.Marshaler, client LOMSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrderCancelRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.OrderCancel(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_LOMS_OrderCancel_0(ctx context.Context, marshaler runtime.Marshaler, server LOMSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrderCancelRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.OrderCancel(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_LOMS_StocksInfo_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_LOMS_StocksInfo_0(ctx context.Context, marshaler runtime.Marshaler, client LOMSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StocksInfoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_LOMS_StocksInfo_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.StocksInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_LOMS_StocksInfo_0(ctx context.Context, marshaler runtime.Marshaler, server LOMSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StocksInfoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_LOMS_StocksInfo_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.StocksInfo(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterLOMSHandlerServer registers the http handlers for service LOMS to "mux".
|
||||
// UnaryRPC :call LOMSServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterLOMSHandlerFromEndpoint instead.
|
||||
func RegisterLOMSHandlerServer(ctx context.Context, mux *runtime.ServeMux, server LOMSServer) error {
|
||||
|
||||
mux.Handle("POST", pattern_LOMS_OrderCreate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.LOMS/OrderCreate", runtime.WithHTTPPathPattern("/order/create"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_LOMS_OrderCreate_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_OrderCreate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_LOMS_OrderInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.LOMS/OrderInfo", runtime.WithHTTPPathPattern("/order/info"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_LOMS_OrderInfo_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_OrderInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_LOMS_OrderPay_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.LOMS/OrderPay", runtime.WithHTTPPathPattern("/order/pay"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_LOMS_OrderPay_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_OrderPay_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_LOMS_OrderCancel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.LOMS/OrderCancel", runtime.WithHTTPPathPattern("/order/cancel"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_LOMS_OrderCancel_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_OrderCancel_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_LOMS_StocksInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.LOMS/StocksInfo", runtime.WithHTTPPathPattern("/stock/info"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_LOMS_StocksInfo_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_StocksInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterLOMSHandlerFromEndpoint is same as RegisterLOMSHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterLOMSHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.DialContext(ctx, endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterLOMSHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterLOMSHandler registers the http handlers for service LOMS to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterLOMSHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterLOMSHandlerClient(ctx, mux, NewLOMSClient(conn))
|
||||
}
|
||||
|
||||
// RegisterLOMSHandlerClient registers the http handlers for service LOMS
|
||||
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "LOMSClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "LOMSClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "LOMSClient" to call the correct interceptors.
|
||||
func RegisterLOMSHandlerClient(ctx context.Context, mux *runtime.ServeMux, client LOMSClient) error {
|
||||
|
||||
mux.Handle("POST", pattern_LOMS_OrderCreate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.LOMS/OrderCreate", runtime.WithHTTPPathPattern("/order/create"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_LOMS_OrderCreate_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_OrderCreate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_LOMS_OrderInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.LOMS/OrderInfo", runtime.WithHTTPPathPattern("/order/info"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_LOMS_OrderInfo_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_OrderInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_LOMS_OrderPay_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.LOMS/OrderPay", runtime.WithHTTPPathPattern("/order/pay"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_LOMS_OrderPay_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_OrderPay_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_LOMS_OrderCancel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.LOMS/OrderCancel", runtime.WithHTTPPathPattern("/order/cancel"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_LOMS_OrderCancel_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_OrderCancel_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_LOMS_StocksInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.LOMS/StocksInfo", runtime.WithHTTPPathPattern("/stock/info"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_LOMS_StocksInfo_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_LOMS_StocksInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_LOMS_OrderCreate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"order", "create"}, ""))
|
||||
|
||||
pattern_LOMS_OrderInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"order", "info"}, ""))
|
||||
|
||||
pattern_LOMS_OrderPay_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"order", "pay"}, ""))
|
||||
|
||||
pattern_LOMS_OrderCancel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"order", "cancel"}, ""))
|
||||
|
||||
pattern_LOMS_StocksInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"stock", "info"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_LOMS_OrderCreate_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_LOMS_OrderInfo_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_LOMS_OrderPay_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_LOMS_OrderCancel_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_LOMS_StocksInfo_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
1111
pkg/api/loms/v1/loms.pb.validate.go
Normal file
250
pkg/api/loms/v1/loms_grpc.pb.go
Normal file
@@ -0,0 +1,250 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v6.30.0
|
||||
// source: loms/v1/loms.proto
|
||||
|
||||
package loms
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// LOMSClient is the client API for LOMS service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type LOMSClient interface {
|
||||
OrderCreate(ctx context.Context, in *OrderCreateRequest, opts ...grpc.CallOption) (*OrderCreateResponse, error)
|
||||
OrderInfo(ctx context.Context, in *OrderInfoRequest, opts ...grpc.CallOption) (*OrderInfoResponse, error)
|
||||
OrderPay(ctx context.Context, in *OrderPayRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
OrderCancel(ctx context.Context, in *OrderCancelRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
StocksInfo(ctx context.Context, in *StocksInfoRequest, opts ...grpc.CallOption) (*StocksInfoResponse, error)
|
||||
}
|
||||
|
||||
type lOMSClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewLOMSClient(cc grpc.ClientConnInterface) LOMSClient {
|
||||
return &lOMSClient{cc}
|
||||
}
|
||||
|
||||
func (c *lOMSClient) OrderCreate(ctx context.Context, in *OrderCreateRequest, opts ...grpc.CallOption) (*OrderCreateResponse, error) {
|
||||
out := new(OrderCreateResponse)
|
||||
err := c.cc.Invoke(ctx, "/LOMS/OrderCreate", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *lOMSClient) OrderInfo(ctx context.Context, in *OrderInfoRequest, opts ...grpc.CallOption) (*OrderInfoResponse, error) {
|
||||
out := new(OrderInfoResponse)
|
||||
err := c.cc.Invoke(ctx, "/LOMS/OrderInfo", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *lOMSClient) OrderPay(ctx context.Context, in *OrderPayRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, "/LOMS/OrderPay", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *lOMSClient) OrderCancel(ctx context.Context, in *OrderCancelRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, "/LOMS/OrderCancel", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *lOMSClient) StocksInfo(ctx context.Context, in *StocksInfoRequest, opts ...grpc.CallOption) (*StocksInfoResponse, error) {
|
||||
out := new(StocksInfoResponse)
|
||||
err := c.cc.Invoke(ctx, "/LOMS/StocksInfo", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// LOMSServer is the server API for LOMS service.
|
||||
// All implementations must embed UnimplementedLOMSServer
|
||||
// for forward compatibility
|
||||
type LOMSServer interface {
|
||||
OrderCreate(context.Context, *OrderCreateRequest) (*OrderCreateResponse, error)
|
||||
OrderInfo(context.Context, *OrderInfoRequest) (*OrderInfoResponse, error)
|
||||
OrderPay(context.Context, *OrderPayRequest) (*emptypb.Empty, error)
|
||||
OrderCancel(context.Context, *OrderCancelRequest) (*emptypb.Empty, error)
|
||||
StocksInfo(context.Context, *StocksInfoRequest) (*StocksInfoResponse, error)
|
||||
mustEmbedUnimplementedLOMSServer()
|
||||
}
|
||||
|
||||
// UnimplementedLOMSServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedLOMSServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedLOMSServer) OrderCreate(context.Context, *OrderCreateRequest) (*OrderCreateResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method OrderCreate not implemented")
|
||||
}
|
||||
func (UnimplementedLOMSServer) OrderInfo(context.Context, *OrderInfoRequest) (*OrderInfoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method OrderInfo not implemented")
|
||||
}
|
||||
func (UnimplementedLOMSServer) OrderPay(context.Context, *OrderPayRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method OrderPay not implemented")
|
||||
}
|
||||
func (UnimplementedLOMSServer) OrderCancel(context.Context, *OrderCancelRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method OrderCancel not implemented")
|
||||
}
|
||||
func (UnimplementedLOMSServer) StocksInfo(context.Context, *StocksInfoRequest) (*StocksInfoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method StocksInfo not implemented")
|
||||
}
|
||||
func (UnimplementedLOMSServer) mustEmbedUnimplementedLOMSServer() {}
|
||||
|
||||
// UnsafeLOMSServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to LOMSServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeLOMSServer interface {
|
||||
mustEmbedUnimplementedLOMSServer()
|
||||
}
|
||||
|
||||
func RegisterLOMSServer(s grpc.ServiceRegistrar, srv LOMSServer) {
|
||||
s.RegisterService(&LOMS_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _LOMS_OrderCreate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(OrderCreateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(LOMSServer).OrderCreate(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/LOMS/OrderCreate",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(LOMSServer).OrderCreate(ctx, req.(*OrderCreateRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _LOMS_OrderInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(OrderInfoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(LOMSServer).OrderInfo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/LOMS/OrderInfo",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(LOMSServer).OrderInfo(ctx, req.(*OrderInfoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _LOMS_OrderPay_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(OrderPayRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(LOMSServer).OrderPay(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/LOMS/OrderPay",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(LOMSServer).OrderPay(ctx, req.(*OrderPayRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _LOMS_OrderCancel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(OrderCancelRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(LOMSServer).OrderCancel(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/LOMS/OrderCancel",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(LOMSServer).OrderCancel(ctx, req.(*OrderCancelRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _LOMS_StocksInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StocksInfoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(LOMSServer).StocksInfo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/LOMS/StocksInfo",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(LOMSServer).StocksInfo(ctx, req.(*StocksInfoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// LOMS_ServiceDesc is the grpc.ServiceDesc for LOMS service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var LOMS_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "LOMS",
|
||||
HandlerType: (*LOMSServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "OrderCreate",
|
||||
Handler: _LOMS_OrderCreate_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "OrderInfo",
|
||||
Handler: _LOMS_OrderInfo_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "OrderPay",
|
||||
Handler: _LOMS_OrderPay_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "OrderCancel",
|
||||
Handler: _LOMS_OrderCancel_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "StocksInfo",
|
||||
Handler: _LOMS_StocksInfo_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "loms/v1/loms.proto",
|
||||
}
|
||||
18
pkg/go.mod
Normal file
@@ -0,0 +1,18 @@
|
||||
module route256/pkg
|
||||
|
||||
go 1.23.9
|
||||
|
||||
require (
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822
|
||||
google.golang.org/grpc v1.73.0
|
||||
google.golang.org/protobuf v1.36.6
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
)
|
||||
40
pkg/go.sum
Normal file
@@ -0,0 +1,40 @@
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
|
||||
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||