chore: project refactoring

This commit is contained in:
ITQ
2025-10-27 22:16:11 +03:00
parent 7a1b6fc309
commit b38c3ed90c
12 changed files with 374 additions and 183 deletions
+40
View File
@@ -0,0 +1,40 @@
package config
import (
"log"
"os"
"strconv"
"github.com/joho/godotenv"
)
type Config struct {
GRPCPort int
LogLevel string
}
func Load() (*Config, error) {
if err := godotenv.Load(); err != nil {
log.Printf("Warning: .env file not found: %v", err)
}
config := &Config{}
portStr := getEnv("GRPC_PORT", "50051")
port, err := strconv.Atoi(portStr)
if err != nil {
return nil, err
}
config.GRPCPort = port
config.LogLevel = getEnv("LOG_LEVEL", "info")
return config, nil
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
+75
View File
@@ -0,0 +1,75 @@
package interceptor
import (
"context"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
)
type LoggerInterceptor struct{}
func NewLoggerInterceptor() *LoggerInterceptor {
return &LoggerInterceptor{}
}
func (i *LoggerInterceptor) Unary() grpc.UnaryServerInterceptor {
return func(
ctx context.Context,
req any,
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (any, error) {
start := time.Now()
log.Printf("gRPC method %s called", info.FullMethod)
log.Printf("Request: %+v", req)
resp, err := handler(ctx, req)
duration := time.Since(start)
if err != nil {
if st, ok := status.FromError(err); ok {
log.Printf("Error: %s, Code: %s, Duration: %v",
st.Message(), st.Code(), duration)
} else {
log.Printf("Error: %v, Duration: %v", err, duration)
}
} else {
log.Printf("Response: %+v", resp)
log.Printf("Method %s completed in %v", info.FullMethod, duration)
}
return resp, err
}
}
func (i *LoggerInterceptor) Stream() grpc.StreamServerInterceptor {
return func(
srv any,
stream grpc.ServerStream,
info *grpc.StreamServerInfo,
handler grpc.StreamHandler,
) error {
start := time.Now()
log.Printf("gRPC stream method %s started", info.FullMethod)
err := handler(srv, stream)
duration := time.Since(start)
if err != nil {
log.Printf("Stream method %s failed: %v, Duration: %v",
info.FullMethod, err, duration)
} else {
log.Printf("Stream method %s completed in %v",
info.FullMethod, duration)
}
return err
}
}
+60
View File
@@ -0,0 +1,60 @@
package server
import (
"fmt"
"log"
"net"
"orderservice/internal/config"
"orderservice/internal/interceptor"
"orderservice/internal/service"
pb "orderservice/pkg/api/order"
"google.golang.org/grpc"
)
type Server struct {
grpcServer *grpc.Server
config *config.Config
}
func New(cfg *config.Config) *Server {
loggerInterceptor := interceptor.NewLoggerInterceptor()
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(loggerInterceptor.Unary()),
grpc.StreamInterceptor(loggerInterceptor.Stream()),
)
return &Server{
grpcServer: grpcServer,
config: cfg,
}
}
func (s *Server) RegisterServices() {
orderService := service.NewOrderServiceServer()
pb.RegisterOrderServiceServer(s.grpcServer, orderService)
}
func (s *Server) Start() error {
addr := fmt.Sprintf(":%d", s.config.GRPCPort)
lis, err := net.Listen("tcp", addr) //nolint:noctx // no need to use context here
if err != nil {
return fmt.Errorf("failed to listen: %w", err)
}
log.Printf("Starting gRPC server on port %d", s.config.GRPCPort)
if err := s.grpcServer.Serve(lis); err != nil {
return fmt.Errorf("failed to serve: %w", err)
}
return nil
}
func (s *Server) Stop() {
s.grpcServer.GracefulStop()
log.Println("gRPC server stopped gracefully")
}
+110
View File
@@ -0,0 +1,110 @@
package service
import (
"context"
"errors"
"sync"
pb "orderservice/pkg/api/order"
"github.com/google/uuid"
)
var ErrOrderNotFound = errors.New("order not found")
func generateOrderID() string {
return uuid.NewString()
}
type OrderServiceServer struct {
pb.UnimplementedOrderServiceServer
mu sync.RWMutex
orders map[string]*pb.Order
}
func NewOrderServiceServer() *OrderServiceServer {
return &OrderServiceServer{
orders: make(map[string]*pb.Order),
}
}
func (s *OrderServiceServer) CreateOrder(
_ context.Context,
req *pb.CreateOrderRequest,
) (*pb.CreateOrderResponse, error) {
s.mu.Lock()
defer s.mu.Unlock()
id := generateOrderID()
order := &pb.Order{
Id: id,
Item: req.GetItem(),
Quantity: req.GetQuantity(),
}
s.orders[id] = order
return &pb.CreateOrderResponse{Id: id}, nil
}
func (s *OrderServiceServer) GetOrder(_ context.Context, req *pb.GetOrderRequest) (*pb.GetOrderResponse, error) {
s.mu.RLock()
defer s.mu.RUnlock()
order, ok := s.orders[req.GetId()]
if !ok {
return nil, ErrOrderNotFound
}
return &pb.GetOrderResponse{Order: order}, nil
}
func (s *OrderServiceServer) UpdateOrder(
_ context.Context,
req *pb.UpdateOrderRequest,
) (*pb.UpdateOrderResponse, error) {
s.mu.Lock()
defer s.mu.Unlock()
order, ok := s.orders[req.GetId()]
if !ok {
return nil, ErrOrderNotFound
}
order.Item = req.GetItem()
order.Quantity = req.GetQuantity()
return &pb.UpdateOrderResponse{Order: order}, nil
}
func (s *OrderServiceServer) DeleteOrder(
_ context.Context,
req *pb.DeleteOrderRequest,
) (*pb.DeleteOrderResponse, error) {
s.mu.Lock()
defer s.mu.Unlock()
_, ok := s.orders[req.GetId()]
if !ok {
return nil, ErrOrderNotFound
}
delete(s.orders, req.GetId())
return &pb.DeleteOrderResponse{Success: true}, nil
}
func (s *OrderServiceServer) ListOrders(
_ context.Context,
_ *pb.ListOrdersRequest,
) (*pb.ListOrdersResponse, error) {
s.mu.RLock()
defer s.mu.RUnlock()
orders := make([]*pb.Order, 0, len(s.orders))
for _, o := range s.orders {
orders = append(orders, o)
}
return &pb.ListOrdersResponse{Orders: orders}, nil
}