// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.1.0
// - protoc             v3.17.0
// source: go.chromium.org/luci/cipd/client/cipd/plugin/protocol/admission.proto

package protocol

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

// AdmissionsClient is the client API for Admissions 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 AdmissionsClient interface {
	// ListAdmissions returns a stream of admission requests to process.
	ListAdmissions(ctx context.Context, in *ListAdmissionsRequest, opts ...grpc.CallOption) (Admissions_ListAdmissionsClient, error)
	// ResolveAdmission submits a decision on an admission request.
	ResolveAdmission(ctx context.Context, in *ResolveAdmissionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
}

type admissionsClient struct {
	cc grpc.ClientConnInterface
}

func NewAdmissionsClient(cc grpc.ClientConnInterface) AdmissionsClient {
	return &admissionsClient{cc}
}

func (c *admissionsClient) ListAdmissions(ctx context.Context, in *ListAdmissionsRequest, opts ...grpc.CallOption) (Admissions_ListAdmissionsClient, error) {
	stream, err := c.cc.NewStream(ctx, &Admissions_ServiceDesc.Streams[0], "/cipd.plugin.Admissions/ListAdmissions", opts...)
	if err != nil {
		return nil, err
	}
	x := &admissionsListAdmissionsClient{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
}

type Admissions_ListAdmissionsClient interface {
	Recv() (*Admission, error)
	grpc.ClientStream
}

type admissionsListAdmissionsClient struct {
	grpc.ClientStream
}

func (x *admissionsListAdmissionsClient) Recv() (*Admission, error) {
	m := new(Admission)
	if err := x.ClientStream.RecvMsg(m); err != nil {
		return nil, err
	}
	return m, nil
}

func (c *admissionsClient) ResolveAdmission(ctx context.Context, in *ResolveAdmissionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
	out := new(emptypb.Empty)
	err := c.cc.Invoke(ctx, "/cipd.plugin.Admissions/ResolveAdmission", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// AdmissionsServer is the server API for Admissions service.
// All implementations must embed UnimplementedAdmissionsServer
// for forward compatibility
type AdmissionsServer interface {
	// ListAdmissions returns a stream of admission requests to process.
	ListAdmissions(*ListAdmissionsRequest, Admissions_ListAdmissionsServer) error
	// ResolveAdmission submits a decision on an admission request.
	ResolveAdmission(context.Context, *ResolveAdmissionRequest) (*emptypb.Empty, error)
	mustEmbedUnimplementedAdmissionsServer()
}

// UnimplementedAdmissionsServer must be embedded to have forward compatible implementations.
type UnimplementedAdmissionsServer struct {
}

func (UnimplementedAdmissionsServer) ListAdmissions(*ListAdmissionsRequest, Admissions_ListAdmissionsServer) error {
	return status.Errorf(codes.Unimplemented, "method ListAdmissions not implemented")
}
func (UnimplementedAdmissionsServer) ResolveAdmission(context.Context, *ResolveAdmissionRequest) (*emptypb.Empty, error) {
	return nil, status.Errorf(codes.Unimplemented, "method ResolveAdmission not implemented")
}
func (UnimplementedAdmissionsServer) mustEmbedUnimplementedAdmissionsServer() {}

// UnsafeAdmissionsServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to AdmissionsServer will
// result in compilation errors.
type UnsafeAdmissionsServer interface {
	mustEmbedUnimplementedAdmissionsServer()
}

func RegisterAdmissionsServer(s grpc.ServiceRegistrar, srv AdmissionsServer) {
	s.RegisterService(&Admissions_ServiceDesc, srv)
}

func _Admissions_ListAdmissions_Handler(srv interface{}, stream grpc.ServerStream) error {
	m := new(ListAdmissionsRequest)
	if err := stream.RecvMsg(m); err != nil {
		return err
	}
	return srv.(AdmissionsServer).ListAdmissions(m, &admissionsListAdmissionsServer{stream})
}

type Admissions_ListAdmissionsServer interface {
	Send(*Admission) error
	grpc.ServerStream
}

type admissionsListAdmissionsServer struct {
	grpc.ServerStream
}

func (x *admissionsListAdmissionsServer) Send(m *Admission) error {
	return x.ServerStream.SendMsg(m)
}

func _Admissions_ResolveAdmission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(ResolveAdmissionRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(AdmissionsServer).ResolveAdmission(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/cipd.plugin.Admissions/ResolveAdmission",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(AdmissionsServer).ResolveAdmission(ctx, req.(*ResolveAdmissionRequest))
	}
	return interceptor(ctx, in, info, handler)
}

// Admissions_ServiceDesc is the grpc.ServiceDesc for Admissions service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Admissions_ServiceDesc = grpc.ServiceDesc{
	ServiceName: "cipd.plugin.Admissions",
	HandlerType: (*AdmissionsServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "ResolveAdmission",
			Handler:    _Admissions_ResolveAdmission_Handler,
		},
	},
	Streams: []grpc.StreamDesc{
		{
			StreamName:    "ListAdmissions",
			Handler:       _Admissions_ListAdmissions_Handler,
			ServerStreams: true,
		},
	},
	Metadata: "go.chromium.org/luci/cipd/client/cipd/plugin/protocol/admission.proto",
}
