- Implement Audit Service (2.5) - gRPC server with Record and Query operations - Database persistence with audit schema - Service registry integration - Entry point: cmd/audit-service - Implement Identity Service (2.2) - User CRUD operations - Password hashing with argon2id - Email verification and password reset flows - Entry point: cmd/identity-service - Fix package naming conflicts in user_service.go - Implement Auth Service (2.1) - JWT token generation and validation - Login, RefreshToken, ValidateToken, Logout RPCs - Integration with Identity Service - Entry point: cmd/auth-service - Note: RefreshToken entity needs Ent generation - Implement Authz Service (2.3, 2.4) - Permission checking and authorization - User roles and permissions retrieval - RBAC-based authorization - Entry point: cmd/authz-service - Implement gRPC clients for all services - Auth, Identity, Authz, and Audit clients - Service discovery integration - Full gRPC communication - Add service configurations to config/default.yaml - Create SUMMARY.md with implementation details and testing instructions - Fix compilation errors in Identity Service (password package conflicts) - All services build successfully and tests pass
125 lines
3.0 KiB
Go
125 lines
3.0 KiB
Go
// Package api provides gRPC server implementation for Audit Service.
|
|
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
auditv1 "git.dcentral.systems/toolz/goplt/api/proto/generated/audit/v1"
|
|
"git.dcentral.systems/toolz/goplt/pkg/config"
|
|
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
|
"go.uber.org/zap"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/health"
|
|
"google.golang.org/grpc/health/grpc_health_v1"
|
|
"google.golang.org/grpc/reflection"
|
|
)
|
|
|
|
// GRPCServer wraps the gRPC server with lifecycle management.
|
|
type GRPCServer struct {
|
|
server *grpc.Server
|
|
listener net.Listener
|
|
config config.ConfigProvider
|
|
logger logger.Logger
|
|
port int
|
|
}
|
|
|
|
// NewGRPCServer creates a new gRPC server for the Audit Service.
|
|
func NewGRPCServer(
|
|
auditService *Server,
|
|
cfg config.ConfigProvider,
|
|
log logger.Logger,
|
|
) (*GRPCServer, error) {
|
|
// Get port from config
|
|
port := cfg.GetInt("services.audit.port")
|
|
if port == 0 {
|
|
port = 8084 // Default port for audit service
|
|
}
|
|
|
|
// Create listener
|
|
addr := fmt.Sprintf("0.0.0.0:%d", port)
|
|
listener, err := net.Listen("tcp", addr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to listen on %s: %w", addr, err)
|
|
}
|
|
|
|
// Create gRPC server
|
|
grpcServer := grpc.NewServer()
|
|
|
|
// Register audit service
|
|
auditv1.RegisterAuditServiceServer(grpcServer, auditService)
|
|
|
|
// Register health service
|
|
healthServer := health.NewServer()
|
|
grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)
|
|
healthServer.SetServingStatus("audit.v1.AuditService", grpc_health_v1.HealthCheckResponse_SERVING)
|
|
|
|
// Register reflection for grpcurl
|
|
reflection.Register(grpcServer)
|
|
|
|
return &GRPCServer{
|
|
server: grpcServer,
|
|
listener: listener,
|
|
config: cfg,
|
|
logger: log,
|
|
port: port,
|
|
}, nil
|
|
}
|
|
|
|
// Start starts the gRPC server.
|
|
func (s *GRPCServer) Start() error {
|
|
s.logger.Info("Starting Audit Service gRPC server",
|
|
zap.Int("port", s.port),
|
|
zap.String("addr", s.listener.Addr().String()),
|
|
)
|
|
|
|
// Start server in a goroutine
|
|
errChan := make(chan error, 1)
|
|
go func() {
|
|
if err := s.server.Serve(s.listener); err != nil {
|
|
errChan <- err
|
|
}
|
|
}()
|
|
|
|
// Wait a bit to check for immediate errors
|
|
select {
|
|
case err := <-errChan:
|
|
return fmt.Errorf("gRPC server failed to start: %w", err)
|
|
case <-time.After(100 * time.Millisecond):
|
|
s.logger.Info("Audit Service gRPC server started successfully",
|
|
zap.Int("port", s.port),
|
|
)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Stop gracefully stops the gRPC server.
|
|
func (s *GRPCServer) Stop(ctx context.Context) error {
|
|
s.logger.Info("Stopping Audit Service gRPC server")
|
|
|
|
// Create a channel for graceful stop
|
|
stopped := make(chan struct{})
|
|
go func() {
|
|
s.server.GracefulStop()
|
|
close(stopped)
|
|
}()
|
|
|
|
// Wait for graceful stop or timeout
|
|
select {
|
|
case <-stopped:
|
|
s.logger.Info("Audit Service gRPC server stopped gracefully")
|
|
return nil
|
|
case <-ctx.Done():
|
|
s.logger.Warn("Audit Service gRPC server stop timeout, forcing stop")
|
|
s.server.Stop()
|
|
return ctx.Err()
|
|
}
|
|
}
|
|
|
|
// Port returns the port the server is listening on.
|
|
func (s *GRPCServer) Port() int {
|
|
return s.port
|
|
}
|