Add per-listener connection limits

Configurable maximum concurrent connections per listener. When the
limit is reached, new connections are closed immediately after accept.
0 means unlimited (default, preserving existing behavior).

Config: Listener gains max_connections field, validated non-negative.

DB: Migration 3 adds listeners.max_connections column.
UpdateListenerMaxConns method for runtime changes via gRPC.
CreateListener updated to persist max_connections on seed.

Server: ListenerState/ListenerData gain MaxConnections. Limit checked
in serve() after Accept but before handleConn — if ActiveConnections
>= MaxConnections, connection is closed and the accept loop continues.
SetMaxConnections method for runtime updates.

Proto: SetListenerMaxConnections RPC added. ListenerStatus gains
max_connections field. Generated code regenerated.

gRPC server: SetListenerMaxConnections implements write-through
(DB first, then in-memory update). GetStatus includes max_connections.

Client: SetListenerMaxConnections method, MaxConnections in
ListenerStatus.

Tests: DB CRUD and UpdateListenerMaxConns, server connection limit
enforcement (accept 2, reject 3rd, close one, accept again), gRPC
SetListenerMaxConnections round-trip with DB persistence, not-found
error handling.

Also updates PROJECT_PLAN.md with phases 6-8 and PROGRESS.md with
tracking for the new features.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 16:42:53 -07:00
parent 5bc8f4fc8e
commit 564e0a9c67
16 changed files with 595 additions and 102 deletions

View File

@@ -730,19 +730,108 @@ func (*RemoveFirewallRuleResponse) Descriptor() ([]byte, []int) {
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{13}
}
type SetListenerMaxConnectionsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
ListenerAddr string `protobuf:"bytes,1,opt,name=listener_addr,json=listenerAddr,proto3" json:"listener_addr,omitempty"`
MaxConnections int64 `protobuf:"varint,2,opt,name=max_connections,json=maxConnections,proto3" json:"max_connections,omitempty"` // 0 = unlimited
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SetListenerMaxConnectionsRequest) Reset() {
*x = SetListenerMaxConnectionsRequest{}
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SetListenerMaxConnectionsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SetListenerMaxConnectionsRequest) ProtoMessage() {}
func (x *SetListenerMaxConnectionsRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SetListenerMaxConnectionsRequest.ProtoReflect.Descriptor instead.
func (*SetListenerMaxConnectionsRequest) Descriptor() ([]byte, []int) {
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{14}
}
func (x *SetListenerMaxConnectionsRequest) GetListenerAddr() string {
if x != nil {
return x.ListenerAddr
}
return ""
}
func (x *SetListenerMaxConnectionsRequest) GetMaxConnections() int64 {
if x != nil {
return x.MaxConnections
}
return 0
}
type SetListenerMaxConnectionsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SetListenerMaxConnectionsResponse) Reset() {
*x = SetListenerMaxConnectionsResponse{}
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SetListenerMaxConnectionsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SetListenerMaxConnectionsResponse) ProtoMessage() {}
func (x *SetListenerMaxConnectionsResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SetListenerMaxConnectionsResponse.ProtoReflect.Descriptor instead.
func (*SetListenerMaxConnectionsResponse) Descriptor() ([]byte, []int) {
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{15}
}
type ListenerStatus struct {
state protoimpl.MessageState `protogen:"open.v1"`
Addr string `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
RouteCount int32 `protobuf:"varint,2,opt,name=route_count,json=routeCount,proto3" json:"route_count,omitempty"`
ActiveConnections int64 `protobuf:"varint,3,opt,name=active_connections,json=activeConnections,proto3" json:"active_connections,omitempty"`
ProxyProtocol bool `protobuf:"varint,4,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
MaxConnections int64 `protobuf:"varint,5,opt,name=max_connections,json=maxConnections,proto3" json:"max_connections,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListenerStatus) Reset() {
*x = ListenerStatus{}
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[14]
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -754,7 +843,7 @@ func (x *ListenerStatus) String() string {
func (*ListenerStatus) ProtoMessage() {}
func (x *ListenerStatus) ProtoReflect() protoreflect.Message {
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[14]
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -767,7 +856,7 @@ func (x *ListenerStatus) ProtoReflect() protoreflect.Message {
// Deprecated: Use ListenerStatus.ProtoReflect.Descriptor instead.
func (*ListenerStatus) Descriptor() ([]byte, []int) {
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{14}
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{16}
}
func (x *ListenerStatus) GetAddr() string {
@@ -798,6 +887,13 @@ func (x *ListenerStatus) GetProxyProtocol() bool {
return false
}
func (x *ListenerStatus) GetMaxConnections() int64 {
if x != nil {
return x.MaxConnections
}
return 0
}
type GetStatusRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
@@ -806,7 +902,7 @@ type GetStatusRequest struct {
func (x *GetStatusRequest) Reset() {
*x = GetStatusRequest{}
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[15]
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -818,7 +914,7 @@ func (x *GetStatusRequest) String() string {
func (*GetStatusRequest) ProtoMessage() {}
func (x *GetStatusRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[15]
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -831,7 +927,7 @@ func (x *GetStatusRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use GetStatusRequest.ProtoReflect.Descriptor instead.
func (*GetStatusRequest) Descriptor() ([]byte, []int) {
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{15}
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{17}
}
type GetStatusResponse struct {
@@ -846,7 +942,7 @@ type GetStatusResponse struct {
func (x *GetStatusResponse) Reset() {
*x = GetStatusResponse{}
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[16]
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -858,7 +954,7 @@ func (x *GetStatusResponse) String() string {
func (*GetStatusResponse) ProtoMessage() {}
func (x *GetStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[16]
mi := &file_proto_mc_proxy_v1_admin_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -871,7 +967,7 @@ func (x *GetStatusResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use GetStatusResponse.ProtoReflect.Descriptor instead.
func (*GetStatusResponse) Descriptor() ([]byte, []int) {
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{16}
return file_proto_mc_proxy_v1_admin_proto_rawDescGZIP(), []int{18}
}
func (x *GetStatusResponse) GetVersion() string {
@@ -940,13 +1036,18 @@ const file_proto_mc_proxy_v1_admin_proto_rawDesc = "" +
"\x17AddFirewallRuleResponse\"J\n" +
"\x19RemoveFirewallRuleRequest\x12-\n" +
"\x04rule\x18\x01 \x01(\v2\x19.mc_proxy.v1.FirewallRuleR\x04rule\"\x1c\n" +
"\x1aRemoveFirewallRuleResponse\"\x9b\x01\n" +
"\x1aRemoveFirewallRuleResponse\"p\n" +
" SetListenerMaxConnectionsRequest\x12#\n" +
"\rlistener_addr\x18\x01 \x01(\tR\flistenerAddr\x12'\n" +
"\x0fmax_connections\x18\x02 \x01(\x03R\x0emaxConnections\"#\n" +
"!SetListenerMaxConnectionsResponse\"\xc4\x01\n" +
"\x0eListenerStatus\x12\x12\n" +
"\x04addr\x18\x01 \x01(\tR\x04addr\x12\x1f\n" +
"\vroute_count\x18\x02 \x01(\x05R\n" +
"routeCount\x12-\n" +
"\x12active_connections\x18\x03 \x01(\x03R\x11activeConnections\x12%\n" +
"\x0eproxy_protocol\x18\x04 \x01(\bR\rproxyProtocol\"\x12\n" +
"\x0eproxy_protocol\x18\x04 \x01(\bR\rproxyProtocol\x12'\n" +
"\x0fmax_connections\x18\x05 \x01(\x03R\x0emaxConnections\"\x12\n" +
"\x10GetStatusRequest\"\xd0\x01\n" +
"\x11GetStatusResponse\x12\x18\n" +
"\aversion\x18\x01 \x01(\tR\aversion\x129\n" +
@@ -958,7 +1059,7 @@ const file_proto_mc_proxy_v1_admin_proto_rawDesc = "" +
"\x1eFIREWALL_RULE_TYPE_UNSPECIFIED\x10\x00\x12\x19\n" +
"\x15FIREWALL_RULE_TYPE_IP\x10\x01\x12\x1b\n" +
"\x17FIREWALL_RULE_TYPE_CIDR\x10\x02\x12\x1e\n" +
"\x1aFIREWALL_RULE_TYPE_COUNTRY\x10\x032\xef\x04\n" +
"\x1aFIREWALL_RULE_TYPE_COUNTRY\x10\x032\xeb\x05\n" +
"\x11ProxyAdminService\x12M\n" +
"\n" +
"ListRoutes\x12\x1e.mc_proxy.v1.ListRoutesRequest\x1a\x1f.mc_proxy.v1.ListRoutesResponse\x12G\n" +
@@ -966,7 +1067,8 @@ const file_proto_mc_proxy_v1_admin_proto_rawDesc = "" +
"\vRemoveRoute\x12\x1f.mc_proxy.v1.RemoveRouteRequest\x1a .mc_proxy.v1.RemoveRouteResponse\x12_\n" +
"\x10GetFirewallRules\x12$.mc_proxy.v1.GetFirewallRulesRequest\x1a%.mc_proxy.v1.GetFirewallRulesResponse\x12\\\n" +
"\x0fAddFirewallRule\x12#.mc_proxy.v1.AddFirewallRuleRequest\x1a$.mc_proxy.v1.AddFirewallRuleResponse\x12e\n" +
"\x12RemoveFirewallRule\x12&.mc_proxy.v1.RemoveFirewallRuleRequest\x1a'.mc_proxy.v1.RemoveFirewallRuleResponse\x12J\n" +
"\x12RemoveFirewallRule\x12&.mc_proxy.v1.RemoveFirewallRuleRequest\x1a'.mc_proxy.v1.RemoveFirewallRuleResponse\x12z\n" +
"\x19SetListenerMaxConnections\x12-.mc_proxy.v1.SetListenerMaxConnectionsRequest\x1a..mc_proxy.v1.SetListenerMaxConnectionsResponse\x12J\n" +
"\tGetStatus\x12\x1d.mc_proxy.v1.GetStatusRequest\x1a\x1e.mc_proxy.v1.GetStatusResponseB:Z8git.wntrmute.dev/kyle/mc-proxy/gen/mc_proxy/v1;mcproxyv1b\x06proto3"
var (
@@ -982,27 +1084,29 @@ func file_proto_mc_proxy_v1_admin_proto_rawDescGZIP() []byte {
}
var file_proto_mc_proxy_v1_admin_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_proto_mc_proxy_v1_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
var file_proto_mc_proxy_v1_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
var file_proto_mc_proxy_v1_admin_proto_goTypes = []any{
(FirewallRuleType)(0), // 0: mc_proxy.v1.FirewallRuleType
(*Route)(nil), // 1: mc_proxy.v1.Route
(*ListRoutesRequest)(nil), // 2: mc_proxy.v1.ListRoutesRequest
(*ListRoutesResponse)(nil), // 3: mc_proxy.v1.ListRoutesResponse
(*AddRouteRequest)(nil), // 4: mc_proxy.v1.AddRouteRequest
(*AddRouteResponse)(nil), // 5: mc_proxy.v1.AddRouteResponse
(*RemoveRouteRequest)(nil), // 6: mc_proxy.v1.RemoveRouteRequest
(*RemoveRouteResponse)(nil), // 7: mc_proxy.v1.RemoveRouteResponse
(*FirewallRule)(nil), // 8: mc_proxy.v1.FirewallRule
(*GetFirewallRulesRequest)(nil), // 9: mc_proxy.v1.GetFirewallRulesRequest
(*GetFirewallRulesResponse)(nil), // 10: mc_proxy.v1.GetFirewallRulesResponse
(*AddFirewallRuleRequest)(nil), // 11: mc_proxy.v1.AddFirewallRuleRequest
(*AddFirewallRuleResponse)(nil), // 12: mc_proxy.v1.AddFirewallRuleResponse
(*RemoveFirewallRuleRequest)(nil), // 13: mc_proxy.v1.RemoveFirewallRuleRequest
(*RemoveFirewallRuleResponse)(nil), // 14: mc_proxy.v1.RemoveFirewallRuleResponse
(*ListenerStatus)(nil), // 15: mc_proxy.v1.ListenerStatus
(*GetStatusRequest)(nil), // 16: mc_proxy.v1.GetStatusRequest
(*GetStatusResponse)(nil), // 17: mc_proxy.v1.GetStatusResponse
(*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp
(FirewallRuleType)(0), // 0: mc_proxy.v1.FirewallRuleType
(*Route)(nil), // 1: mc_proxy.v1.Route
(*ListRoutesRequest)(nil), // 2: mc_proxy.v1.ListRoutesRequest
(*ListRoutesResponse)(nil), // 3: mc_proxy.v1.ListRoutesResponse
(*AddRouteRequest)(nil), // 4: mc_proxy.v1.AddRouteRequest
(*AddRouteResponse)(nil), // 5: mc_proxy.v1.AddRouteResponse
(*RemoveRouteRequest)(nil), // 6: mc_proxy.v1.RemoveRouteRequest
(*RemoveRouteResponse)(nil), // 7: mc_proxy.v1.RemoveRouteResponse
(*FirewallRule)(nil), // 8: mc_proxy.v1.FirewallRule
(*GetFirewallRulesRequest)(nil), // 9: mc_proxy.v1.GetFirewallRulesRequest
(*GetFirewallRulesResponse)(nil), // 10: mc_proxy.v1.GetFirewallRulesResponse
(*AddFirewallRuleRequest)(nil), // 11: mc_proxy.v1.AddFirewallRuleRequest
(*AddFirewallRuleResponse)(nil), // 12: mc_proxy.v1.AddFirewallRuleResponse
(*RemoveFirewallRuleRequest)(nil), // 13: mc_proxy.v1.RemoveFirewallRuleRequest
(*RemoveFirewallRuleResponse)(nil), // 14: mc_proxy.v1.RemoveFirewallRuleResponse
(*SetListenerMaxConnectionsRequest)(nil), // 15: mc_proxy.v1.SetListenerMaxConnectionsRequest
(*SetListenerMaxConnectionsResponse)(nil), // 16: mc_proxy.v1.SetListenerMaxConnectionsResponse
(*ListenerStatus)(nil), // 17: mc_proxy.v1.ListenerStatus
(*GetStatusRequest)(nil), // 18: mc_proxy.v1.GetStatusRequest
(*GetStatusResponse)(nil), // 19: mc_proxy.v1.GetStatusResponse
(*timestamppb.Timestamp)(nil), // 20: google.protobuf.Timestamp
}
var file_proto_mc_proxy_v1_admin_proto_depIdxs = []int32{
1, // 0: mc_proxy.v1.ListRoutesResponse.routes:type_name -> mc_proxy.v1.Route
@@ -1011,24 +1115,26 @@ var file_proto_mc_proxy_v1_admin_proto_depIdxs = []int32{
8, // 3: mc_proxy.v1.GetFirewallRulesResponse.rules:type_name -> mc_proxy.v1.FirewallRule
8, // 4: mc_proxy.v1.AddFirewallRuleRequest.rule:type_name -> mc_proxy.v1.FirewallRule
8, // 5: mc_proxy.v1.RemoveFirewallRuleRequest.rule:type_name -> mc_proxy.v1.FirewallRule
18, // 6: mc_proxy.v1.GetStatusResponse.started_at:type_name -> google.protobuf.Timestamp
15, // 7: mc_proxy.v1.GetStatusResponse.listeners:type_name -> mc_proxy.v1.ListenerStatus
20, // 6: mc_proxy.v1.GetStatusResponse.started_at:type_name -> google.protobuf.Timestamp
17, // 7: mc_proxy.v1.GetStatusResponse.listeners:type_name -> mc_proxy.v1.ListenerStatus
2, // 8: mc_proxy.v1.ProxyAdminService.ListRoutes:input_type -> mc_proxy.v1.ListRoutesRequest
4, // 9: mc_proxy.v1.ProxyAdminService.AddRoute:input_type -> mc_proxy.v1.AddRouteRequest
6, // 10: mc_proxy.v1.ProxyAdminService.RemoveRoute:input_type -> mc_proxy.v1.RemoveRouteRequest
9, // 11: mc_proxy.v1.ProxyAdminService.GetFirewallRules:input_type -> mc_proxy.v1.GetFirewallRulesRequest
11, // 12: mc_proxy.v1.ProxyAdminService.AddFirewallRule:input_type -> mc_proxy.v1.AddFirewallRuleRequest
13, // 13: mc_proxy.v1.ProxyAdminService.RemoveFirewallRule:input_type -> mc_proxy.v1.RemoveFirewallRuleRequest
16, // 14: mc_proxy.v1.ProxyAdminService.GetStatus:input_type -> mc_proxy.v1.GetStatusRequest
3, // 15: mc_proxy.v1.ProxyAdminService.ListRoutes:output_type -> mc_proxy.v1.ListRoutesResponse
5, // 16: mc_proxy.v1.ProxyAdminService.AddRoute:output_type -> mc_proxy.v1.AddRouteResponse
7, // 17: mc_proxy.v1.ProxyAdminService.RemoveRoute:output_type -> mc_proxy.v1.RemoveRouteResponse
10, // 18: mc_proxy.v1.ProxyAdminService.GetFirewallRules:output_type -> mc_proxy.v1.GetFirewallRulesResponse
12, // 19: mc_proxy.v1.ProxyAdminService.AddFirewallRule:output_type -> mc_proxy.v1.AddFirewallRuleResponse
14, // 20: mc_proxy.v1.ProxyAdminService.RemoveFirewallRule:output_type -> mc_proxy.v1.RemoveFirewallRuleResponse
17, // 21: mc_proxy.v1.ProxyAdminService.GetStatus:output_type -> mc_proxy.v1.GetStatusResponse
15, // [15:22] is the sub-list for method output_type
8, // [8:15] is the sub-list for method input_type
15, // 14: mc_proxy.v1.ProxyAdminService.SetListenerMaxConnections:input_type -> mc_proxy.v1.SetListenerMaxConnectionsRequest
18, // 15: mc_proxy.v1.ProxyAdminService.GetStatus:input_type -> mc_proxy.v1.GetStatusRequest
3, // 16: mc_proxy.v1.ProxyAdminService.ListRoutes:output_type -> mc_proxy.v1.ListRoutesResponse
5, // 17: mc_proxy.v1.ProxyAdminService.AddRoute:output_type -> mc_proxy.v1.AddRouteResponse
7, // 18: mc_proxy.v1.ProxyAdminService.RemoveRoute:output_type -> mc_proxy.v1.RemoveRouteResponse
10, // 19: mc_proxy.v1.ProxyAdminService.GetFirewallRules:output_type -> mc_proxy.v1.GetFirewallRulesResponse
12, // 20: mc_proxy.v1.ProxyAdminService.AddFirewallRule:output_type -> mc_proxy.v1.AddFirewallRuleResponse
14, // 21: mc_proxy.v1.ProxyAdminService.RemoveFirewallRule:output_type -> mc_proxy.v1.RemoveFirewallRuleResponse
16, // 22: mc_proxy.v1.ProxyAdminService.SetListenerMaxConnections:output_type -> mc_proxy.v1.SetListenerMaxConnectionsResponse
19, // 23: mc_proxy.v1.ProxyAdminService.GetStatus:output_type -> mc_proxy.v1.GetStatusResponse
16, // [16:24] is the sub-list for method output_type
8, // [8:16] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
@@ -1045,7 +1151,7 @@ func file_proto_mc_proxy_v1_admin_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_mc_proxy_v1_admin_proto_rawDesc), len(file_proto_mc_proxy_v1_admin_proto_rawDesc)),
NumEnums: 1,
NumMessages: 17,
NumMessages: 19,
NumExtensions: 0,
NumServices: 1,
},