package rpc import ( "net" "net/url" "time" app2 "gitlab.com/inetmock/inetmock/internal/app" "gitlab.com/inetmock/inetmock/pkg/logging" "go.uber.org/zap" "google.golang.org/grpc" ) type INetMockAPI interface { StartServer() error StopServer() } type inetmockAPI struct { app app2.App url *url.URL server *grpc.Server logger logging.Logger serverRunning bool } func NewINetMockAPI( app app2.App, ) INetMockAPI { return &inetmockAPI{ app: app, url: app.Config().APIConfig().ListenURL(), logger: app.Logger().Named("api"), } } func (i *inetmockAPI) StartServer() (err error) { var lis net.Listener if lis, err = createListenerFromURL(i.url); err != nil { return } i.server = grpc.NewServer() RegisterHandlersServer(i.server, &handlersServer{ registry: i.app.HandlerRegistry(), }) RegisterEndpointsServer(i.server, &endpointsServer{ endpointsManager: i.app.EndpointManager(), }) RegisterHealthServer(i.server, &healthServer{ app: i.app, }) RegisterAuditServer(i.server, &auditServer{ app: i.app, }) go i.startServerAsync(lis) return } func (i *inetmockAPI) StopServer() { if !i.serverRunning { i.logger.Info( "Skipping API server shutdown because server is not running", ) return } gracefulStopChan := make(chan struct{}) go func() { i.server.GracefulStop() close(gracefulStopChan) }() select { case <-gracefulStopChan: case <-time.After(5 * time.Second): i.server.Stop() } } func (i *inetmockAPI) startServerAsync(listener net.Listener) { i.serverRunning = true if err := i.server.Serve(listener); err != nil { i.serverRunning = false i.logger.Error( "failed to start INetMock API", zap.Error(err), ) } } func createListenerFromURL(url *url.URL) (lis net.Listener, err error) { switch url.Scheme { case "unix": lis, err = net.Listen(url.Scheme, url.Path) default: lis, err = net.Listen(url.Scheme, url.Host) } return }