package agentv1 import ( "context" "google.golang.org/grpc" ) // ServiceName is the fully-qualified gRPC service name. It MUST match the value // the mTLS interceptor whitelists for Enroll (server/internal/mtls/identity.go). const ServiceName = "pangolin.agent.v1.AgentService" // Fully-qualified method names. const ( MethodEnroll = "/" + ServiceName + "/Enroll" MethodRegister = "/" + ServiceName + "/Register" MethodHeartbeat = "/" + ServiceName + "/Heartbeat" MethodSubscribe = "/" + ServiceName + "/Subscribe" MethodAck = "/" + ServiceName + "/Ack" MethodReportUsage = "/" + ServiceName + "/ReportUsage" ) // withCodec forces the JSON content-subtype on every call so the contract does // not depend on the caller remembering to set dial-level call options. func withCodec(opts []grpc.CallOption) []grpc.CallOption { return append([]grpc.CallOption{grpc.CallContentSubtype(CodecName)}, opts...) } // ─── server interface ────────────────────────────────────────────────────────── // AgentServiceServer is implemented by the control plane. type AgentServiceServer interface { Enroll(context.Context, *EnrollRequest) (*EnrollResponse, error) Register(context.Context, *RegisterRequest) (*ConfigSnapshot, error) Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) Subscribe(*SubscribeRequest, AgentService_SubscribeServer) error Ack(context.Context, *AckRequest) (*AckResponse, error) ReportUsage(context.Context, *UsageReport) (*UsageAck, error) } // AgentService_SubscribeServer is the server side of the Command stream. type AgentService_SubscribeServer interface { Send(*Command) error grpc.ServerStream } type subscribeServer struct{ grpc.ServerStream } func (s *subscribeServer) Send(m *Command) error { return s.ServerStream.SendMsg(m) } // RegisterAgentServiceServer wires srv into a gRPC server (or any ServiceRegistrar). func RegisterAgentServiceServer(s grpc.ServiceRegistrar, srv AgentServiceServer) { s.RegisterService(&serviceDesc, srv) } func handlerEnroll(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(EnrollRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(AgentServiceServer).Enroll(ctx, in) } info := &grpc.UnaryServerInfo{Server: srv, FullMethod: MethodEnroll} return interceptor(ctx, in, info, func(ctx context.Context, req any) (any, error) { return srv.(AgentServiceServer).Enroll(ctx, req.(*EnrollRequest)) }) } func handlerRegister(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(RegisterRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(AgentServiceServer).Register(ctx, in) } info := &grpc.UnaryServerInfo{Server: srv, FullMethod: MethodRegister} return interceptor(ctx, in, info, func(ctx context.Context, req any) (any, error) { return srv.(AgentServiceServer).Register(ctx, req.(*RegisterRequest)) }) } func handlerHeartbeat(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(HeartbeatRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(AgentServiceServer).Heartbeat(ctx, in) } info := &grpc.UnaryServerInfo{Server: srv, FullMethod: MethodHeartbeat} return interceptor(ctx, in, info, func(ctx context.Context, req any) (any, error) { return srv.(AgentServiceServer).Heartbeat(ctx, req.(*HeartbeatRequest)) }) } func handlerAck(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(AckRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(AgentServiceServer).Ack(ctx, in) } info := &grpc.UnaryServerInfo{Server: srv, FullMethod: MethodAck} return interceptor(ctx, in, info, func(ctx context.Context, req any) (any, error) { return srv.(AgentServiceServer).Ack(ctx, req.(*AckRequest)) }) } func handlerReportUsage(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(UsageReport) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(AgentServiceServer).ReportUsage(ctx, in) } info := &grpc.UnaryServerInfo{Server: srv, FullMethod: MethodReportUsage} return interceptor(ctx, in, info, func(ctx context.Context, req any) (any, error) { return srv.(AgentServiceServer).ReportUsage(ctx, req.(*UsageReport)) }) } func handlerSubscribe(srv any, stream grpc.ServerStream) error { m := new(SubscribeRequest) if err := stream.RecvMsg(m); err != nil { return err } return srv.(AgentServiceServer).Subscribe(m, &subscribeServer{stream}) } var serviceDesc = grpc.ServiceDesc{ ServiceName: ServiceName, HandlerType: (*AgentServiceServer)(nil), Methods: []grpc.MethodDesc{ {MethodName: "Enroll", Handler: handlerEnroll}, {MethodName: "Register", Handler: handlerRegister}, {MethodName: "Heartbeat", Handler: handlerHeartbeat}, {MethodName: "Ack", Handler: handlerAck}, {MethodName: "ReportUsage", Handler: handlerReportUsage}, }, Streams: []grpc.StreamDesc{ {StreamName: "Subscribe", Handler: handlerSubscribe, ServerStreams: true}, }, Metadata: "proto/agent/v1/agent.proto", } // ─── client ───────────────────────────────────────────────────────────────────── // AgentServiceClient is consumed by the node agent. type AgentServiceClient interface { Enroll(ctx context.Context, in *EnrollRequest, opts ...grpc.CallOption) (*EnrollResponse, error) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*ConfigSnapshot, error) Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (AgentService_SubscribeClient, error) Ack(ctx context.Context, in *AckRequest, opts ...grpc.CallOption) (*AckResponse, error) ReportUsage(ctx context.Context, in *UsageReport, opts ...grpc.CallOption) (*UsageAck, error) } // AgentService_SubscribeClient is the client side of the Command stream. type AgentService_SubscribeClient interface { Recv() (*Command, error) grpc.ClientStream } type subscribeClient struct{ grpc.ClientStream } func (c *subscribeClient) Recv() (*Command, error) { m := new(Command) if err := c.ClientStream.RecvMsg(m); err != nil { return nil, err } return m, nil } type agentServiceClient struct{ cc grpc.ClientConnInterface } // NewAgentServiceClient returns a client bound to cc. All calls use the JSON codec. func NewAgentServiceClient(cc grpc.ClientConnInterface) AgentServiceClient { return &agentServiceClient{cc} } func (c *agentServiceClient) Enroll(ctx context.Context, in *EnrollRequest, opts ...grpc.CallOption) (*EnrollResponse, error) { out := new(EnrollResponse) if err := c.cc.Invoke(ctx, MethodEnroll, in, out, withCodec(opts)...); err != nil { return nil, err } return out, nil } func (c *agentServiceClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*ConfigSnapshot, error) { out := new(ConfigSnapshot) if err := c.cc.Invoke(ctx, MethodRegister, in, out, withCodec(opts)...); err != nil { return nil, err } return out, nil } func (c *agentServiceClient) Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) { out := new(HeartbeatResponse) if err := c.cc.Invoke(ctx, MethodHeartbeat, in, out, withCodec(opts)...); err != nil { return nil, err } return out, nil } func (c *agentServiceClient) Ack(ctx context.Context, in *AckRequest, opts ...grpc.CallOption) (*AckResponse, error) { out := new(AckResponse) if err := c.cc.Invoke(ctx, MethodAck, in, out, withCodec(opts)...); err != nil { return nil, err } return out, nil } func (c *agentServiceClient) ReportUsage(ctx context.Context, in *UsageReport, opts ...grpc.CallOption) (*UsageAck, error) { out := new(UsageAck) if err := c.cc.Invoke(ctx, MethodReportUsage, in, out, withCodec(opts)...); err != nil { return nil, err } return out, nil } func (c *agentServiceClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (AgentService_SubscribeClient, error) { stream, err := c.cc.NewStream(ctx, &serviceDesc.Streams[0], MethodSubscribe, withCodec(opts)...) if err != nil { return nil, err } x := &subscribeClient{stream} if err := x.ClientStream.SendMsg(in); err != nil { return nil, err } if err := x.ClientStream.CloseSend(); err != nil { return nil, err } return x, nil }