diff --git a/fleetspeak/src/server/admin/admin.go b/fleetspeak/src/server/admin/admin.go index 6fa2e291..437570de 100644 --- a/fleetspeak/src/server/admin/admin.go +++ b/fleetspeak/src/server/admin/admin.go @@ -123,6 +123,15 @@ func (s adminServer) ListClients(ctx context.Context, req *spb.ListClientsReques }, nil } +func (s adminServer) StreamClientIds(_ *spb.StreamClientIdsRequest, srv spb.Admin_StreamClientIdsServer) error { + callback := func(id common.ClientID) error { + return srv.Send(&spb.StreamClientIdsResponse{ + ClientId: id.Bytes(), + }) + } + return s.store.StreamClientIds(srv.Context(), callback) +} + func (s adminServer) ListClientContacts(ctx context.Context, req *spb.ListClientContactsRequest) (*spb.ListClientContactsResponse, error) { id, err := common.BytesToClientID(req.ClientId) if err != nil { @@ -138,6 +147,19 @@ func (s adminServer) ListClientContacts(ctx context.Context, req *spb.ListClient }, nil } +func (s adminServer) StreamClientContacts(req *spb.StreamClientContactsRequest, srv spb.Admin_StreamClientContactsServer) error { + callback := func(contact *spb.ClientContact) error { + return srv.Send(&spb.StreamClientContactsResponse{ + Contact: contact, + }) + } + id, err := common.BytesToClientID(req.ClientId) + if err != nil { + return err + } + return s.store.StreamClientContacts(srv.Context(), id, callback) +} + func (s adminServer) InsertMessage(ctx context.Context, m *fspb.Message) (*fspb.EmptyMessage, error) { // At this point, we mostly trust the message we get, but do some basic // sanity checks and generate missing metadata. diff --git a/fleetspeak/src/server/db/store.go b/fleetspeak/src/server/db/store.go index 57faefb7..1f098efb 100644 --- a/fleetspeak/src/server/db/store.go +++ b/fleetspeak/src/server/db/store.go @@ -199,6 +199,9 @@ type ClientStore interface { // returns all clients. ListClients(ctx context.Context, ids []common.ClientID) ([]*spb.Client, error) + // StreamClientIds streams the IDs of all available clients. + StreamClientIds(ctx context.Context, callback func(common.ClientID) error) error + // GetClientData retrieves the current data about the client identified // by id. GetClientData(ctx context.Context, id common.ClientID) (*ClientData, error) @@ -229,6 +232,9 @@ type ClientStore interface { // older than a few weeks. ListClientContacts(ctx context.Context, id common.ClientID) ([]*spb.ClientContact, error) + // StreamClientContacts is a streaming version of ListClientContacts. + StreamClientContacts(ctx context.Context, id common.ClientID, callback func(*spb.ClientContact) error) error + // LinkMessagesToContact associates messages with a contact - it records // that they were sent or received during the given contact. LinkMessagesToContact(ctx context.Context, contact ContactID, msgs []common.MessageID) error diff --git a/fleetspeak/src/server/dbtesting/clientstore_suite.go b/fleetspeak/src/server/dbtesting/clientstore_suite.go index 81f02d72..45184f0a 100644 --- a/fleetspeak/src/server/dbtesting/clientstore_suite.go +++ b/fleetspeak/src/server/dbtesting/clientstore_suite.go @@ -250,23 +250,42 @@ func clientStoreTest(t *testing.T, ds db.Store) { t.Errorf("ListClients error: want [%v] got [%v]", want, got) } - contacts, err := ds.ListClientContacts(ctx, clientID) - if err != nil { - t.Errorf("ListClientContacts returned error: %v", err) - } - if len(contacts) != 1 { - t.Errorf("ListClientContacts returned %d results, expected 1.", len(contacts)) - } else { - if contacts[0].SentNonce != 42 || contacts[0].ReceivedNonce != 54 { - t.Errorf("ListClientContact[0] should return nonces (42, 54), got (%d, %d)", - contacts[0].SentNonce, contacts[0].ReceivedNonce) - } - if contacts[0].ObservedAddress != longAddr { - t.Errorf("ListClientContact[0] should return address %s, got %s", - longAddr, contacts[0].ObservedAddress) + checkClientContacts := func(t *testing.T, contacts []*spb.ClientContact) { + if len(contacts) != 1 { + t.Errorf("ListClientContacts returned %d results, expected 1.", len(contacts)) + } else { + if contacts[0].SentNonce != 42 || contacts[0].ReceivedNonce != 54 { + t.Errorf("ListClientContact[0] should return nonces (42, 54), got (%d, %d)", + contacts[0].SentNonce, contacts[0].ReceivedNonce) + } + if contacts[0].ObservedAddress != longAddr { + t.Errorf("ListClientContact[0] should return address %s, got %s", + longAddr, contacts[0].ObservedAddress) + } } } + t.Run("ListClientContacts", func(t *testing.T) { + contacts, err := ds.ListClientContacts(ctx, clientID) + if err != nil { + t.Errorf("ListClientContacts returned error: %v", err) + } + checkClientContacts(t, contacts) + }) + + t.Run("StreamClientContacts", func(t *testing.T) { + var contacts []*spb.ClientContact + callback := func(contact *spb.ClientContact) error { + contacts = append(contacts, contact) + return nil + } + err := ds.StreamClientContacts(ctx, clientID, callback) + if err != nil { + t.Errorf("StreamClientContacts returned error: %v", err) + } + checkClientContacts(t, contacts) + }) + if err := ds.BlacklistClient(ctx, clientID); err != nil { t.Errorf("Error blacklisting client: %v", err) } @@ -350,6 +369,38 @@ Cases: } } +func streamClientIdsTest(t *testing.T, ds db.Store) { + ctx := context.Background() + + clientIds := []common.ClientID{clientID, clientID2, clientID3} + + for _, cid := range clientIds { + if err := ds.AddClient(ctx, cid, &db.ClientData{Key: []byte("test key")}); err != nil { + t.Fatalf("AddClient [%v] failed: %v", clientID, err) + } + } + + var result []common.ClientID + + callback := func(id common.ClientID) error { + result = append(result, id) + return nil + } + + err := ds.StreamClientIds(ctx, callback) + if err != nil { + t.Fatalf("StreamClientIds failed", err) + } + + sort.Slice(result, func(i int, j int) bool { + return bytes.Compare(result[i].Bytes(), result[j].Bytes()) < 0 + }) + + if !reflect.DeepEqual(result, clientIds) { + t.Errorf("StreamClientIds returned unexpected result. Got: [%v]. Want: [%v].", result, clientIds) + } +} + func fetchResourceUsageRecordsTest(t *testing.T, ds db.Store) { ctx := context.Background() key := []byte("Test key") @@ -486,6 +537,7 @@ func clientStoreTestSuite(t *testing.T, env DbTestEnv) { runTestSuite(t, env, map[string]func(*testing.T, db.Store){ "ClientStoreTest": clientStoreTest, "ListClientsTest": listClientsTest, + "StreamClientIdsTest": streamClientIdsTest, "FetchResourceUsageRecordsTest": fetchResourceUsageRecordsTest, }) }) diff --git a/fleetspeak/src/server/mysql/clientstore.go b/fleetspeak/src/server/mysql/clientstore.go index 2a712d31..baae5061 100644 --- a/fleetspeak/src/server/mysql/clientstore.go +++ b/fleetspeak/src/server/mysql/clientstore.go @@ -51,6 +51,32 @@ func uint64ToBytes(i uint64) []byte { return b } +func (d *Datastore) StreamClientIds(ctx context.Context, callback func(common.ClientID) error) error { + return d.runOnce(ctx, true, func(tx *sql.Tx) error { + rs, err := tx.QueryContext(ctx, "SELECT client_id FROM clients") + if err != nil { + return err + } + defer rs.Close() + for rs.Next() { + var bid []byte + err := rs.Scan(&bid) + if err != nil { + return err + } + id, err := common.BytesToClientID(bid) + if err != nil { + return err + } + err = callback(id) + if err != nil { + return err + } + } + return nil + }) +} + func (d *Datastore) ListClients(ctx context.Context, ids []common.ClientID) ([]*spb.Client, error) { // Return value map, maps string client ids to the return values. var retm map[string]*spb.Client @@ -265,53 +291,67 @@ func (d *Datastore) RecordClientContact(ctx context.Context, data db.ContactData return res, err } -func (d *Datastore) ListClientContacts(ctx context.Context, id common.ClientID) ([]*spb.ClientContact, error) { - var res []*spb.ClientContact - if err := d.runInTx(ctx, true, func(tx *sql.Tx) error { - res = nil - rows, err := tx.QueryContext( - ctx, - "SELECT time, sent_nonce, received_nonce, address FROM client_contacts WHERE client_id = ?", - id.Bytes()) +func (d *Datastore) streamClientContacts(ctx context.Context, tx *sql.Tx, id common.ClientID, callback func(*spb.ClientContact) error) error { + rows, err := tx.QueryContext( + ctx, + "SELECT time, sent_nonce, received_nonce, address FROM client_contacts WHERE client_id = ?", + id.Bytes()) + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var addr sql.NullString + var timeNS int64 + var sn, rn []byte + c := &spb.ClientContact{} + if err := rows.Scan(&timeNS, &sn, &rn, &addr); err != nil { + return err + } + c.SentNonce, err = bytesToUint64(sn) + if err != nil { + return err + } + c.ReceivedNonce, err = bytesToUint64(rn) if err != nil { return err } - defer rows.Close() - for rows.Next() { - var addr sql.NullString - var timeNS int64 - var sn, rn []byte - c := &spb.ClientContact{} - if err := rows.Scan(&timeNS, &sn, &rn, &addr); err != nil { - return err - } - c.SentNonce, err = bytesToUint64(sn) - if err != nil { - return err - } - c.ReceivedNonce, err = bytesToUint64(rn) - if err != nil { - return err - } - if addr.Valid { - c.ObservedAddress = addr.String - } + if addr.Valid { + c.ObservedAddress = addr.String + } - ts, err := ptypes.TimestampProto(time.Unix(0, timeNS)) - if err != nil { - return err - } - c.Timestamp = ts + ts, err := ptypes.TimestampProto(time.Unix(0, timeNS)) + if err != nil { + return err + } + c.Timestamp = ts - res = append(res, c) + err = callback(c) + if err != nil { + return err } - return nil - }); err != nil { - return nil, err } + return nil +} + +func (d *Datastore) StreamClientContacts(ctx context.Context, id common.ClientID, callback func(*spb.ClientContact) error) error { + return d.runOnce(ctx, true, func(tx *sql.Tx) error { + return d.streamClientContacts(ctx, tx, id, callback) + }) +} - return res, nil +func (d *Datastore) ListClientContacts(ctx context.Context, id common.ClientID) ([]*spb.ClientContact, error) { + var res []*spb.ClientContact + callback := func(c *spb.ClientContact) error { + res = append(res, c) + return nil + } + err := d.runInTx(ctx, true, func(tx *sql.Tx) error { + res = res[:0] + return d.streamClientContacts(ctx, tx, id, callback) + }) + return res, err } func (d *Datastore) LinkMessagesToContact(ctx context.Context, contact db.ContactID, ids []common.MessageID) error { diff --git a/fleetspeak/src/server/proto/fleetspeak_server/admin.pb.go b/fleetspeak/src/server/proto/fleetspeak_server/admin.pb.go index 3fc06552..7049ee8d 100644 --- a/fleetspeak/src/server/proto/fleetspeak_server/admin.pb.go +++ b/fleetspeak/src/server/proto/fleetspeak_server/admin.pb.go @@ -272,6 +272,91 @@ func (x *ListClientsResponse) GetClients() []*Client { return nil } +type StreamClientIdsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StreamClientIdsRequest) Reset() { + *x = StreamClientIdsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamClientIdsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamClientIdsRequest) ProtoMessage() {} + +func (x *StreamClientIdsRequest) ProtoReflect() protoreflect.Message { + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamClientIdsRequest.ProtoReflect.Descriptor instead. +func (*StreamClientIdsRequest) Descriptor() ([]byte, []int) { + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{5} +} + +type StreamClientIdsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId []byte `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` +} + +func (x *StreamClientIdsResponse) Reset() { + *x = StreamClientIdsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamClientIdsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamClientIdsResponse) ProtoMessage() {} + +func (x *StreamClientIdsResponse) ProtoReflect() protoreflect.Message { + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamClientIdsResponse.ProtoReflect.Descriptor instead. +func (*StreamClientIdsResponse) Descriptor() ([]byte, []int) { + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{6} +} + +func (x *StreamClientIdsResponse) GetClientId() []byte { + if x != nil { + return x.ClientId + } + return nil +} + type Client struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -289,7 +374,7 @@ type Client struct { func (x *Client) Reset() { *x = Client{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[5] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -302,7 +387,7 @@ func (x *Client) String() string { func (*Client) ProtoMessage() {} func (x *Client) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[5] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -315,7 +400,7 @@ func (x *Client) ProtoReflect() protoreflect.Message { // Deprecated: Use Client.ProtoReflect.Descriptor instead. func (*Client) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{5} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{7} } func (x *Client) GetClientId() []byte { @@ -378,7 +463,7 @@ type GetMessageStatusRequest struct { func (x *GetMessageStatusRequest) Reset() { *x = GetMessageStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[6] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -391,7 +476,7 @@ func (x *GetMessageStatusRequest) String() string { func (*GetMessageStatusRequest) ProtoMessage() {} func (x *GetMessageStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[6] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -404,7 +489,7 @@ func (x *GetMessageStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMessageStatusRequest.ProtoReflect.Descriptor instead. func (*GetMessageStatusRequest) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{6} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{8} } func (x *GetMessageStatusRequest) GetMessageId() []byte { @@ -425,7 +510,7 @@ type DeletePendingMessagesRequest struct { func (x *DeletePendingMessagesRequest) Reset() { *x = DeletePendingMessagesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[7] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -438,7 +523,7 @@ func (x *DeletePendingMessagesRequest) String() string { func (*DeletePendingMessagesRequest) ProtoMessage() {} func (x *DeletePendingMessagesRequest) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[7] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -451,7 +536,7 @@ func (x *DeletePendingMessagesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletePendingMessagesRequest.ProtoReflect.Descriptor instead. func (*DeletePendingMessagesRequest) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{7} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{9} } func (x *DeletePendingMessagesRequest) GetClientIds() [][]byte { @@ -475,7 +560,7 @@ type GetPendingMessagesRequest struct { func (x *GetPendingMessagesRequest) Reset() { *x = GetPendingMessagesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[8] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -488,7 +573,7 @@ func (x *GetPendingMessagesRequest) String() string { func (*GetPendingMessagesRequest) ProtoMessage() {} func (x *GetPendingMessagesRequest) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[8] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -501,7 +586,7 @@ func (x *GetPendingMessagesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPendingMessagesRequest.ProtoReflect.Descriptor instead. func (*GetPendingMessagesRequest) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{8} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{10} } func (x *GetPendingMessagesRequest) GetClientIds() [][]byte { @@ -543,7 +628,7 @@ type GetPendingMessagesResponse struct { func (x *GetPendingMessagesResponse) Reset() { *x = GetPendingMessagesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[9] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -556,7 +641,7 @@ func (x *GetPendingMessagesResponse) String() string { func (*GetPendingMessagesResponse) ProtoMessage() {} func (x *GetPendingMessagesResponse) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[9] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -569,7 +654,7 @@ func (x *GetPendingMessagesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPendingMessagesResponse.ProtoReflect.Descriptor instead. func (*GetPendingMessagesResponse) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{9} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{11} } func (x *GetPendingMessagesResponse) GetMessages() []*fleetspeak.Message { @@ -590,7 +675,7 @@ type GetPendingMessageCountRequest struct { func (x *GetPendingMessageCountRequest) Reset() { *x = GetPendingMessageCountRequest{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[10] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -603,7 +688,7 @@ func (x *GetPendingMessageCountRequest) String() string { func (*GetPendingMessageCountRequest) ProtoMessage() {} func (x *GetPendingMessageCountRequest) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[10] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -616,7 +701,7 @@ func (x *GetPendingMessageCountRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPendingMessageCountRequest.ProtoReflect.Descriptor instead. func (*GetPendingMessageCountRequest) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{10} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{12} } func (x *GetPendingMessageCountRequest) GetClientIds() [][]byte { @@ -637,7 +722,7 @@ type GetPendingMessageCountResponse struct { func (x *GetPendingMessageCountResponse) Reset() { *x = GetPendingMessageCountResponse{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[11] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -650,7 +735,7 @@ func (x *GetPendingMessageCountResponse) String() string { func (*GetPendingMessageCountResponse) ProtoMessage() {} func (x *GetPendingMessageCountResponse) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[11] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -663,7 +748,7 @@ func (x *GetPendingMessageCountResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPendingMessageCountResponse.ProtoReflect.Descriptor instead. func (*GetPendingMessageCountResponse) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{11} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{13} } func (x *GetPendingMessageCountResponse) GetCount() uint64 { @@ -685,7 +770,7 @@ type GetMessageStatusResponse struct { func (x *GetMessageStatusResponse) Reset() { *x = GetMessageStatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[12] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -698,7 +783,7 @@ func (x *GetMessageStatusResponse) String() string { func (*GetMessageStatusResponse) ProtoMessage() {} func (x *GetMessageStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[12] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -711,7 +796,7 @@ func (x *GetMessageStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMessageStatusResponse.ProtoReflect.Descriptor instead. func (*GetMessageStatusResponse) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{12} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{14} } func (x *GetMessageStatusResponse) GetCreationTime() *timestamp.Timestamp { @@ -741,7 +826,7 @@ type StoreFileRequest struct { func (x *StoreFileRequest) Reset() { *x = StoreFileRequest{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[13] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -754,7 +839,7 @@ func (x *StoreFileRequest) String() string { func (*StoreFileRequest) ProtoMessage() {} func (x *StoreFileRequest) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[13] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -767,7 +852,7 @@ func (x *StoreFileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StoreFileRequest.ProtoReflect.Descriptor instead. func (*StoreFileRequest) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{13} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{15} } func (x *StoreFileRequest) GetServiceName() string { @@ -802,7 +887,7 @@ type ListClientContactsRequest struct { func (x *ListClientContactsRequest) Reset() { *x = ListClientContactsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[14] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -815,7 +900,7 @@ func (x *ListClientContactsRequest) String() string { func (*ListClientContactsRequest) ProtoMessage() {} func (x *ListClientContactsRequest) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[14] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -828,7 +913,7 @@ func (x *ListClientContactsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListClientContactsRequest.ProtoReflect.Descriptor instead. func (*ListClientContactsRequest) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{14} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{16} } func (x *ListClientContactsRequest) GetClientId() []byte { @@ -849,7 +934,7 @@ type ListClientContactsResponse struct { func (x *ListClientContactsResponse) Reset() { *x = ListClientContactsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[15] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -862,7 +947,7 @@ func (x *ListClientContactsResponse) String() string { func (*ListClientContactsResponse) ProtoMessage() {} func (x *ListClientContactsResponse) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[15] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -875,7 +960,7 @@ func (x *ListClientContactsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListClientContactsResponse.ProtoReflect.Descriptor instead. func (*ListClientContactsResponse) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{15} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{17} } func (x *ListClientContactsResponse) GetContacts() []*ClientContact { @@ -885,6 +970,100 @@ func (x *ListClientContactsResponse) GetContacts() []*ClientContact { return nil } +type StreamClientContactsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId []byte `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` +} + +func (x *StreamClientContactsRequest) Reset() { + *x = StreamClientContactsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamClientContactsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamClientContactsRequest) ProtoMessage() {} + +func (x *StreamClientContactsRequest) ProtoReflect() protoreflect.Message { + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamClientContactsRequest.ProtoReflect.Descriptor instead. +func (*StreamClientContactsRequest) Descriptor() ([]byte, []int) { + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{18} +} + +func (x *StreamClientContactsRequest) GetClientId() []byte { + if x != nil { + return x.ClientId + } + return nil +} + +type StreamClientContactsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Contact *ClientContact `protobuf:"bytes,1,opt,name=contact,proto3" json:"contact,omitempty"` +} + +func (x *StreamClientContactsResponse) Reset() { + *x = StreamClientContactsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamClientContactsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamClientContactsResponse) ProtoMessage() {} + +func (x *StreamClientContactsResponse) ProtoReflect() protoreflect.Message { + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamClientContactsResponse.ProtoReflect.Descriptor instead. +func (*StreamClientContactsResponse) Descriptor() ([]byte, []int) { + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{19} +} + +func (x *StreamClientContactsResponse) GetContact() *ClientContact { + if x != nil { + return x.Contact + } + return nil +} + type ClientContact struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -899,7 +1078,7 @@ type ClientContact struct { func (x *ClientContact) Reset() { *x = ClientContact{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[16] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -912,7 +1091,7 @@ func (x *ClientContact) String() string { func (*ClientContact) ProtoMessage() {} func (x *ClientContact) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[16] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -925,7 +1104,7 @@ func (x *ClientContact) ProtoReflect() protoreflect.Message { // Deprecated: Use ClientContact.ProtoReflect.Descriptor instead. func (*ClientContact) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{16} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{20} } func (x *ClientContact) GetSentNonce() uint64 { @@ -967,7 +1146,7 @@ type BlacklistClientRequest struct { func (x *BlacklistClientRequest) Reset() { *x = BlacklistClientRequest{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[17] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -980,7 +1159,7 @@ func (x *BlacklistClientRequest) String() string { func (*BlacklistClientRequest) ProtoMessage() {} func (x *BlacklistClientRequest) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[17] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -993,7 +1172,7 @@ func (x *BlacklistClientRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BlacklistClientRequest.ProtoReflect.Descriptor instead. func (*BlacklistClientRequest) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{17} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{21} } func (x *BlacklistClientRequest) GetClientId() []byte { @@ -1016,7 +1195,7 @@ type FetchClientResourceUsageRecordsRequest struct { func (x *FetchClientResourceUsageRecordsRequest) Reset() { *x = FetchClientResourceUsageRecordsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[18] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1029,7 +1208,7 @@ func (x *FetchClientResourceUsageRecordsRequest) String() string { func (*FetchClientResourceUsageRecordsRequest) ProtoMessage() {} func (x *FetchClientResourceUsageRecordsRequest) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[18] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1042,7 +1221,7 @@ func (x *FetchClientResourceUsageRecordsRequest) ProtoReflect() protoreflect.Mes // Deprecated: Use FetchClientResourceUsageRecordsRequest.ProtoReflect.Descriptor instead. func (*FetchClientResourceUsageRecordsRequest) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{18} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{22} } func (x *FetchClientResourceUsageRecordsRequest) GetClientId() []byte { @@ -1077,7 +1256,7 @@ type FetchClientResourceUsageRecordsResponse struct { func (x *FetchClientResourceUsageRecordsResponse) Reset() { *x = FetchClientResourceUsageRecordsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[19] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1090,7 +1269,7 @@ func (x *FetchClientResourceUsageRecordsResponse) String() string { func (*FetchClientResourceUsageRecordsResponse) ProtoMessage() {} func (x *FetchClientResourceUsageRecordsResponse) ProtoReflect() protoreflect.Message { - mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[19] + mi := &file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1103,7 +1282,7 @@ func (x *FetchClientResourceUsageRecordsResponse) ProtoReflect() protoreflect.Me // Deprecated: Use FetchClientResourceUsageRecordsResponse.ProtoReflect.Descriptor instead. func (*FetchClientResourceUsageRecordsResponse) Descriptor() ([]byte, []int) { - return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{19} + return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP(), []int{23} } func (x *FetchClientResourceUsageRecordsResponse) GetRecords() []*ClientResourceUsageRecord { @@ -1159,207 +1338,237 @@ var file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDesc = []b 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x22, - 0xe2, 0x02, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, - 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x12, 0x46, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x63, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x18, 0x0a, 0x16, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x36, 0x0a, 0x17, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x22, 0xe2, 0x02, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x06, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x06, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x73, 0x12, 0x46, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x63, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x6c, 0x61, 0x73, + 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x14, + 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6c, 0x61, 0x73, 0x74, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x39, + 0x0a, 0x19, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x12, 0x39, 0x0a, 0x0a, 0x6c, 0x61, 0x73, + 0x74, 0x5f, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x6c, 0x61, - 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x6f, - 0x6e, 0x74, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x39, 0x0a, 0x19, - 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x16, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x12, 0x39, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, - 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, + 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x73, + 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x62, 0x6c, 0x61, 0x63, 0x6b, + 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x22, 0x38, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, + 0x22, 0x3d, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, + 0x85, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, + 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x61, + 0x6e, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, + 0x61, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x22, 0x4d, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, + 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x3e, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0x36, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8e, + 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x66, + 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, + 0x66, 0x0a, 0x10, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x38, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x22, 0x5a, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, + 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3c, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x22, 0x3a, 0x0a, + 0x1b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x5a, 0x0a, 0x1c, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x52, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x63, 0x74, 0x22, 0xba, 0x01, 0x0a, 0x0d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x74, 0x5f, + 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x52, 0x09, 0x73, 0x65, 0x6e, + 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x64, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0d, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x29, 0x0a, + 0x10, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x6c, 0x6f, - 0x63, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x65, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x6c, 0x69, - 0x73, 0x74, 0x65, 0x64, 0x22, 0x38, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x22, 0x3d, - 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, - 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0x85, 0x01, - 0x0a, 0x19, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, - 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x61, 0x6e, 0x74, - 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x61, 0x6e, - 0x74, 0x44, 0x61, 0x74, 0x61, 0x22, 0x4d, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, - 0x61, 0x6b, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x22, 0x3e, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x49, 0x64, 0x73, 0x22, 0x36, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8e, 0x01, 0x0a, - 0x18, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x66, 0x0a, - 0x10, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x38, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, - 0x5a, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, - 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, - 0x74, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x22, 0xba, 0x01, 0x0a, 0x0d, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x1d, 0x0a, - 0x0a, 0x73, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x06, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, - 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x06, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x4e, 0x6f, - 0x6e, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, - 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x38, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x35, 0x0a, 0x16, 0x42, 0x6c, 0x61, 0x63, - 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, - 0xcb, 0x01, 0x0a, 0x26, 0x46, 0x65, 0x74, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x43, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3f, 0x0a, 0x0d, - 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x0c, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x71, 0x0a, - 0x27, 0x46, 0x65, 0x74, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, - 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x66, 0x6c, 0x65, 0x65, - 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, - 0x32, 0xc6, 0x0a, 0x0a, 0x05, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x58, 0x0a, 0x0f, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x29, 0x2e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x00, 0x12, 0x79, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x73, 0x12, 0x2e, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, - 0x63, 0x61, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x66, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x22, 0x35, 0x0a, 0x16, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xcb, 0x01, 0x0a, 0x26, 0x46, 0x65, + 0x74, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x12, 0x43, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3f, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x71, 0x0a, 0x27, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x32, 0xb1, 0x0c, 0x0a, 0x05, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x58, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x72, + 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x29, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, + 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x79, + 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, 0x72, 0x6f, 0x61, + 0x64, 0x63, 0x61, 0x73, 0x74, 0x73, 0x12, 0x2e, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, + 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, + 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x0b, 0x4c, 0x69, 0x73, + 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x0f, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x12, 0x29, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x42, 0x72, 0x6f, 0x61, 0x64, - 0x63, 0x61, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x5e, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x25, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, - 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x73, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x2c, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, - 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x6d, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, - 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, - 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x13, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, - 0x6b, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, - 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2f, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x12, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x73, 0x12, 0x2c, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2d, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, + 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, + 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x73, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x12, 0x2c, 0x2e, + 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7b, 0x0a, 0x14, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x73, 0x12, 0x2e, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, + 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, + 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x6d, 0x0a, 0x10, 0x47, 0x65, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x2e, + 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x65, + 0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x13, 0x2e, 0x66, 0x6c, 0x65, 0x65, + 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, + 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x15, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x12, 0x2f, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, + 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, + 0x12, 0x73, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, + 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, + 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7f, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x30, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x7f, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x2e, 0x66, 0x6c, 0x65, - 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x4c, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x23, - 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, - 0x41, 0x0a, 0x09, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x18, 0x2e, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, - 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0f, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, - 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, 0x6c, 0x61, 0x63, 0x6b, 0x6c, - 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x9a, 0x01, 0x0a, - 0x1f, 0x46, 0x65, 0x74, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, - 0x12, 0x39, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x31, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x46, + 0x69, 0x6c, 0x65, 0x12, 0x23, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x69, 0x6c, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, + 0x65, 0x12, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x66, 0x6c, + 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0f, 0x42, 0x6c, 0x61, 0x63, 0x6b, + 0x6c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x2e, 0x66, 0x6c, 0x65, + 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x42, + 0x6c, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, + 0x61, 0x6b, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x00, 0x12, 0x9a, 0x01, 0x0a, 0x1f, 0x46, 0x65, 0x74, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x39, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, + 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x3a, 0x2e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x66, 0x6c, - 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, - 0x46, 0x65, 0x74, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x66, - 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2f, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, - 0x70, 0x65, 0x61, 0x6b, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, - 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x4c, + 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2f, 0x66, + 0x6c, 0x65, 0x65, 0x74, 0x73, 0x70, 0x65, 0x61, 0x6b, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x66, 0x6c, 0x65, 0x65, 0x74, + 0x73, 0x70, 0x65, 0x61, 0x6b, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1374,82 +1583,91 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescGZIP( return file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDescData } -var file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 24) var file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_goTypes = []interface{}{ (*CreateBroadcastRequest)(nil), // 0: fleetspeak.server.CreateBroadcastRequest (*ListActiveBroadcastsRequest)(nil), // 1: fleetspeak.server.ListActiveBroadcastsRequest (*ListActiveBroadcastsResponse)(nil), // 2: fleetspeak.server.ListActiveBroadcastsResponse (*ListClientsRequest)(nil), // 3: fleetspeak.server.ListClientsRequest (*ListClientsResponse)(nil), // 4: fleetspeak.server.ListClientsResponse - (*Client)(nil), // 5: fleetspeak.server.Client - (*GetMessageStatusRequest)(nil), // 6: fleetspeak.server.GetMessageStatusRequest - (*DeletePendingMessagesRequest)(nil), // 7: fleetspeak.server.DeletePendingMessagesRequest - (*GetPendingMessagesRequest)(nil), // 8: fleetspeak.server.GetPendingMessagesRequest - (*GetPendingMessagesResponse)(nil), // 9: fleetspeak.server.GetPendingMessagesResponse - (*GetPendingMessageCountRequest)(nil), // 10: fleetspeak.server.GetPendingMessageCountRequest - (*GetPendingMessageCountResponse)(nil), // 11: fleetspeak.server.GetPendingMessageCountResponse - (*GetMessageStatusResponse)(nil), // 12: fleetspeak.server.GetMessageStatusResponse - (*StoreFileRequest)(nil), // 13: fleetspeak.server.StoreFileRequest - (*ListClientContactsRequest)(nil), // 14: fleetspeak.server.ListClientContactsRequest - (*ListClientContactsResponse)(nil), // 15: fleetspeak.server.ListClientContactsResponse - (*ClientContact)(nil), // 16: fleetspeak.server.ClientContact - (*BlacklistClientRequest)(nil), // 17: fleetspeak.server.BlacklistClientRequest - (*FetchClientResourceUsageRecordsRequest)(nil), // 18: fleetspeak.server.FetchClientResourceUsageRecordsRequest - (*FetchClientResourceUsageRecordsResponse)(nil), // 19: fleetspeak.server.FetchClientResourceUsageRecordsResponse - (*Broadcast)(nil), // 20: fleetspeak.server.Broadcast - (*fleetspeak.Label)(nil), // 21: fleetspeak.Label - (*timestamp.Timestamp)(nil), // 22: google.protobuf.Timestamp - (*fleetspeak.Message)(nil), // 23: fleetspeak.Message - (*fleetspeak.MessageResult)(nil), // 24: fleetspeak.MessageResult - (*ClientResourceUsageRecord)(nil), // 25: fleetspeak.server.ClientResourceUsageRecord - (*fleetspeak.EmptyMessage)(nil), // 26: fleetspeak.EmptyMessage + (*StreamClientIdsRequest)(nil), // 5: fleetspeak.server.StreamClientIdsRequest + (*StreamClientIdsResponse)(nil), // 6: fleetspeak.server.StreamClientIdsResponse + (*Client)(nil), // 7: fleetspeak.server.Client + (*GetMessageStatusRequest)(nil), // 8: fleetspeak.server.GetMessageStatusRequest + (*DeletePendingMessagesRequest)(nil), // 9: fleetspeak.server.DeletePendingMessagesRequest + (*GetPendingMessagesRequest)(nil), // 10: fleetspeak.server.GetPendingMessagesRequest + (*GetPendingMessagesResponse)(nil), // 11: fleetspeak.server.GetPendingMessagesResponse + (*GetPendingMessageCountRequest)(nil), // 12: fleetspeak.server.GetPendingMessageCountRequest + (*GetPendingMessageCountResponse)(nil), // 13: fleetspeak.server.GetPendingMessageCountResponse + (*GetMessageStatusResponse)(nil), // 14: fleetspeak.server.GetMessageStatusResponse + (*StoreFileRequest)(nil), // 15: fleetspeak.server.StoreFileRequest + (*ListClientContactsRequest)(nil), // 16: fleetspeak.server.ListClientContactsRequest + (*ListClientContactsResponse)(nil), // 17: fleetspeak.server.ListClientContactsResponse + (*StreamClientContactsRequest)(nil), // 18: fleetspeak.server.StreamClientContactsRequest + (*StreamClientContactsResponse)(nil), // 19: fleetspeak.server.StreamClientContactsResponse + (*ClientContact)(nil), // 20: fleetspeak.server.ClientContact + (*BlacklistClientRequest)(nil), // 21: fleetspeak.server.BlacklistClientRequest + (*FetchClientResourceUsageRecordsRequest)(nil), // 22: fleetspeak.server.FetchClientResourceUsageRecordsRequest + (*FetchClientResourceUsageRecordsResponse)(nil), // 23: fleetspeak.server.FetchClientResourceUsageRecordsResponse + (*Broadcast)(nil), // 24: fleetspeak.server.Broadcast + (*fleetspeak.Label)(nil), // 25: fleetspeak.Label + (*timestamp.Timestamp)(nil), // 26: google.protobuf.Timestamp + (*fleetspeak.Message)(nil), // 27: fleetspeak.Message + (*fleetspeak.MessageResult)(nil), // 28: fleetspeak.MessageResult + (*ClientResourceUsageRecord)(nil), // 29: fleetspeak.server.ClientResourceUsageRecord + (*fleetspeak.EmptyMessage)(nil), // 30: fleetspeak.EmptyMessage } var file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_depIdxs = []int32{ - 20, // 0: fleetspeak.server.CreateBroadcastRequest.broadcast:type_name -> fleetspeak.server.Broadcast - 20, // 1: fleetspeak.server.ListActiveBroadcastsResponse.broadcasts:type_name -> fleetspeak.server.Broadcast - 5, // 2: fleetspeak.server.ListClientsResponse.clients:type_name -> fleetspeak.server.Client - 21, // 3: fleetspeak.server.Client.labels:type_name -> fleetspeak.Label - 22, // 4: fleetspeak.server.Client.last_contact_time:type_name -> google.protobuf.Timestamp - 22, // 5: fleetspeak.server.Client.last_clock:type_name -> google.protobuf.Timestamp - 23, // 6: fleetspeak.server.GetPendingMessagesResponse.messages:type_name -> fleetspeak.Message - 22, // 7: fleetspeak.server.GetMessageStatusResponse.creation_time:type_name -> google.protobuf.Timestamp - 24, // 8: fleetspeak.server.GetMessageStatusResponse.result:type_name -> fleetspeak.MessageResult - 16, // 9: fleetspeak.server.ListClientContactsResponse.contacts:type_name -> fleetspeak.server.ClientContact - 22, // 10: fleetspeak.server.ClientContact.timestamp:type_name -> google.protobuf.Timestamp - 22, // 11: fleetspeak.server.FetchClientResourceUsageRecordsRequest.start_timestamp:type_name -> google.protobuf.Timestamp - 22, // 12: fleetspeak.server.FetchClientResourceUsageRecordsRequest.end_timestamp:type_name -> google.protobuf.Timestamp - 25, // 13: fleetspeak.server.FetchClientResourceUsageRecordsResponse.records:type_name -> fleetspeak.server.ClientResourceUsageRecord - 0, // 14: fleetspeak.server.Admin.CreateBroadcast:input_type -> fleetspeak.server.CreateBroadcastRequest - 1, // 15: fleetspeak.server.Admin.ListActiveBroadcasts:input_type -> fleetspeak.server.ListActiveBroadcastsRequest - 3, // 16: fleetspeak.server.Admin.ListClients:input_type -> fleetspeak.server.ListClientsRequest - 14, // 17: fleetspeak.server.Admin.ListClientContacts:input_type -> fleetspeak.server.ListClientContactsRequest - 6, // 18: fleetspeak.server.Admin.GetMessageStatus:input_type -> fleetspeak.server.GetMessageStatusRequest - 23, // 19: fleetspeak.server.Admin.InsertMessage:input_type -> fleetspeak.Message - 7, // 20: fleetspeak.server.Admin.DeletePendingMessages:input_type -> fleetspeak.server.DeletePendingMessagesRequest - 8, // 21: fleetspeak.server.Admin.GetPendingMessages:input_type -> fleetspeak.server.GetPendingMessagesRequest - 10, // 22: fleetspeak.server.Admin.GetPendingMessageCount:input_type -> fleetspeak.server.GetPendingMessageCountRequest - 13, // 23: fleetspeak.server.Admin.StoreFile:input_type -> fleetspeak.server.StoreFileRequest - 26, // 24: fleetspeak.server.Admin.KeepAlive:input_type -> fleetspeak.EmptyMessage - 17, // 25: fleetspeak.server.Admin.BlacklistClient:input_type -> fleetspeak.server.BlacklistClientRequest - 18, // 26: fleetspeak.server.Admin.FetchClientResourceUsageRecords:input_type -> fleetspeak.server.FetchClientResourceUsageRecordsRequest - 26, // 27: fleetspeak.server.Admin.CreateBroadcast:output_type -> fleetspeak.EmptyMessage - 2, // 28: fleetspeak.server.Admin.ListActiveBroadcasts:output_type -> fleetspeak.server.ListActiveBroadcastsResponse - 4, // 29: fleetspeak.server.Admin.ListClients:output_type -> fleetspeak.server.ListClientsResponse - 15, // 30: fleetspeak.server.Admin.ListClientContacts:output_type -> fleetspeak.server.ListClientContactsResponse - 12, // 31: fleetspeak.server.Admin.GetMessageStatus:output_type -> fleetspeak.server.GetMessageStatusResponse - 26, // 32: fleetspeak.server.Admin.InsertMessage:output_type -> fleetspeak.EmptyMessage - 26, // 33: fleetspeak.server.Admin.DeletePendingMessages:output_type -> fleetspeak.EmptyMessage - 9, // 34: fleetspeak.server.Admin.GetPendingMessages:output_type -> fleetspeak.server.GetPendingMessagesResponse - 11, // 35: fleetspeak.server.Admin.GetPendingMessageCount:output_type -> fleetspeak.server.GetPendingMessageCountResponse - 26, // 36: fleetspeak.server.Admin.StoreFile:output_type -> fleetspeak.EmptyMessage - 26, // 37: fleetspeak.server.Admin.KeepAlive:output_type -> fleetspeak.EmptyMessage - 26, // 38: fleetspeak.server.Admin.BlacklistClient:output_type -> fleetspeak.EmptyMessage - 19, // 39: fleetspeak.server.Admin.FetchClientResourceUsageRecords:output_type -> fleetspeak.server.FetchClientResourceUsageRecordsResponse - 27, // [27:40] is the sub-list for method output_type - 14, // [14:27] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 24, // 0: fleetspeak.server.CreateBroadcastRequest.broadcast:type_name -> fleetspeak.server.Broadcast + 24, // 1: fleetspeak.server.ListActiveBroadcastsResponse.broadcasts:type_name -> fleetspeak.server.Broadcast + 7, // 2: fleetspeak.server.ListClientsResponse.clients:type_name -> fleetspeak.server.Client + 25, // 3: fleetspeak.server.Client.labels:type_name -> fleetspeak.Label + 26, // 4: fleetspeak.server.Client.last_contact_time:type_name -> google.protobuf.Timestamp + 26, // 5: fleetspeak.server.Client.last_clock:type_name -> google.protobuf.Timestamp + 27, // 6: fleetspeak.server.GetPendingMessagesResponse.messages:type_name -> fleetspeak.Message + 26, // 7: fleetspeak.server.GetMessageStatusResponse.creation_time:type_name -> google.protobuf.Timestamp + 28, // 8: fleetspeak.server.GetMessageStatusResponse.result:type_name -> fleetspeak.MessageResult + 20, // 9: fleetspeak.server.ListClientContactsResponse.contacts:type_name -> fleetspeak.server.ClientContact + 20, // 10: fleetspeak.server.StreamClientContactsResponse.contact:type_name -> fleetspeak.server.ClientContact + 26, // 11: fleetspeak.server.ClientContact.timestamp:type_name -> google.protobuf.Timestamp + 26, // 12: fleetspeak.server.FetchClientResourceUsageRecordsRequest.start_timestamp:type_name -> google.protobuf.Timestamp + 26, // 13: fleetspeak.server.FetchClientResourceUsageRecordsRequest.end_timestamp:type_name -> google.protobuf.Timestamp + 29, // 14: fleetspeak.server.FetchClientResourceUsageRecordsResponse.records:type_name -> fleetspeak.server.ClientResourceUsageRecord + 0, // 15: fleetspeak.server.Admin.CreateBroadcast:input_type -> fleetspeak.server.CreateBroadcastRequest + 1, // 16: fleetspeak.server.Admin.ListActiveBroadcasts:input_type -> fleetspeak.server.ListActiveBroadcastsRequest + 3, // 17: fleetspeak.server.Admin.ListClients:input_type -> fleetspeak.server.ListClientsRequest + 5, // 18: fleetspeak.server.Admin.StreamClientIds:input_type -> fleetspeak.server.StreamClientIdsRequest + 16, // 19: fleetspeak.server.Admin.ListClientContacts:input_type -> fleetspeak.server.ListClientContactsRequest + 18, // 20: fleetspeak.server.Admin.StreamClientContacts:input_type -> fleetspeak.server.StreamClientContactsRequest + 8, // 21: fleetspeak.server.Admin.GetMessageStatus:input_type -> fleetspeak.server.GetMessageStatusRequest + 27, // 22: fleetspeak.server.Admin.InsertMessage:input_type -> fleetspeak.Message + 9, // 23: fleetspeak.server.Admin.DeletePendingMessages:input_type -> fleetspeak.server.DeletePendingMessagesRequest + 10, // 24: fleetspeak.server.Admin.GetPendingMessages:input_type -> fleetspeak.server.GetPendingMessagesRequest + 12, // 25: fleetspeak.server.Admin.GetPendingMessageCount:input_type -> fleetspeak.server.GetPendingMessageCountRequest + 15, // 26: fleetspeak.server.Admin.StoreFile:input_type -> fleetspeak.server.StoreFileRequest + 30, // 27: fleetspeak.server.Admin.KeepAlive:input_type -> fleetspeak.EmptyMessage + 21, // 28: fleetspeak.server.Admin.BlacklistClient:input_type -> fleetspeak.server.BlacklistClientRequest + 22, // 29: fleetspeak.server.Admin.FetchClientResourceUsageRecords:input_type -> fleetspeak.server.FetchClientResourceUsageRecordsRequest + 30, // 30: fleetspeak.server.Admin.CreateBroadcast:output_type -> fleetspeak.EmptyMessage + 2, // 31: fleetspeak.server.Admin.ListActiveBroadcasts:output_type -> fleetspeak.server.ListActiveBroadcastsResponse + 4, // 32: fleetspeak.server.Admin.ListClients:output_type -> fleetspeak.server.ListClientsResponse + 6, // 33: fleetspeak.server.Admin.StreamClientIds:output_type -> fleetspeak.server.StreamClientIdsResponse + 17, // 34: fleetspeak.server.Admin.ListClientContacts:output_type -> fleetspeak.server.ListClientContactsResponse + 19, // 35: fleetspeak.server.Admin.StreamClientContacts:output_type -> fleetspeak.server.StreamClientContactsResponse + 14, // 36: fleetspeak.server.Admin.GetMessageStatus:output_type -> fleetspeak.server.GetMessageStatusResponse + 30, // 37: fleetspeak.server.Admin.InsertMessage:output_type -> fleetspeak.EmptyMessage + 30, // 38: fleetspeak.server.Admin.DeletePendingMessages:output_type -> fleetspeak.EmptyMessage + 11, // 39: fleetspeak.server.Admin.GetPendingMessages:output_type -> fleetspeak.server.GetPendingMessagesResponse + 13, // 40: fleetspeak.server.Admin.GetPendingMessageCount:output_type -> fleetspeak.server.GetPendingMessageCountResponse + 30, // 41: fleetspeak.server.Admin.StoreFile:output_type -> fleetspeak.EmptyMessage + 30, // 42: fleetspeak.server.Admin.KeepAlive:output_type -> fleetspeak.EmptyMessage + 30, // 43: fleetspeak.server.Admin.BlacklistClient:output_type -> fleetspeak.EmptyMessage + 23, // 44: fleetspeak.server.Admin.FetchClientResourceUsageRecords:output_type -> fleetspeak.server.FetchClientResourceUsageRecordsResponse + 30, // [30:45] is the sub-list for method output_type + 15, // [15:30] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() } @@ -1521,7 +1739,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Client); i { + switch v := v.(*StreamClientIdsRequest); i { case 0: return &v.state case 1: @@ -1533,7 +1751,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMessageStatusRequest); i { + switch v := v.(*StreamClientIdsResponse); i { case 0: return &v.state case 1: @@ -1545,7 +1763,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeletePendingMessagesRequest); i { + switch v := v.(*Client); i { case 0: return &v.state case 1: @@ -1557,7 +1775,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPendingMessagesRequest); i { + switch v := v.(*GetMessageStatusRequest); i { case 0: return &v.state case 1: @@ -1569,7 +1787,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPendingMessagesResponse); i { + switch v := v.(*DeletePendingMessagesRequest); i { case 0: return &v.state case 1: @@ -1581,7 +1799,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPendingMessageCountRequest); i { + switch v := v.(*GetPendingMessagesRequest); i { case 0: return &v.state case 1: @@ -1593,7 +1811,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPendingMessageCountResponse); i { + switch v := v.(*GetPendingMessagesResponse); i { case 0: return &v.state case 1: @@ -1605,7 +1823,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMessageStatusResponse); i { + switch v := v.(*GetPendingMessageCountRequest); i { case 0: return &v.state case 1: @@ -1617,7 +1835,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StoreFileRequest); i { + switch v := v.(*GetPendingMessageCountResponse); i { case 0: return &v.state case 1: @@ -1629,7 +1847,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListClientContactsRequest); i { + switch v := v.(*GetMessageStatusResponse); i { case 0: return &v.state case 1: @@ -1641,7 +1859,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListClientContactsResponse); i { + switch v := v.(*StoreFileRequest); i { case 0: return &v.state case 1: @@ -1653,7 +1871,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClientContact); i { + switch v := v.(*ListClientContactsRequest); i { case 0: return &v.state case 1: @@ -1665,7 +1883,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BlacklistClientRequest); i { + switch v := v.(*ListClientContactsResponse); i { case 0: return &v.state case 1: @@ -1677,7 +1895,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FetchClientResourceUsageRecordsRequest); i { + switch v := v.(*StreamClientContactsRequest); i { case 0: return &v.state case 1: @@ -1689,6 +1907,54 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { } } file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamClientContactsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClientContact); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlacklistClientRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FetchClientResourceUsageRecordsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FetchClientResourceUsageRecordsResponse); i { case 0: return &v.state @@ -1707,7 +1973,7 @@ func file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_fleetspeak_src_server_proto_fleetspeak_server_admin_proto_rawDesc, NumEnums: 0, - NumMessages: 20, + NumMessages: 24, NumExtensions: 0, NumServices: 1, }, @@ -1740,8 +2006,12 @@ type AdminClient interface { ListActiveBroadcasts(ctx context.Context, in *ListActiveBroadcastsRequest, opts ...grpc.CallOption) (*ListActiveBroadcastsResponse, error) // ListClients lists the currently active FS clients. ListClients(ctx context.Context, in *ListClientsRequest, opts ...grpc.CallOption) (*ListClientsResponse, error) + // StreamClientIds lists the currently active FS clients as a stream. + StreamClientIds(ctx context.Context, in *StreamClientIdsRequest, opts ...grpc.CallOption) (Admin_StreamClientIdsClient, error) // ListClientContacts lists the contact history for a client. ListClientContacts(ctx context.Context, in *ListClientContactsRequest, opts ...grpc.CallOption) (*ListClientContactsResponse, error) + // StreamClientContacts lists the contact history for a client as a stream. + StreamClientContacts(ctx context.Context, in *StreamClientContactsRequest, opts ...grpc.CallOption) (Admin_StreamClientContactsClient, error) // GetMessageStatus retrieves the current status of a message. GetMessageStatus(ctx context.Context, in *GetMessageStatusRequest, opts ...grpc.CallOption) (*GetMessageStatusResponse, error) // InsertMessage inserts a message into the Fleetspeak system to be processed @@ -1802,6 +2072,38 @@ func (c *adminClient) ListClients(ctx context.Context, in *ListClientsRequest, o return out, nil } +func (c *adminClient) StreamClientIds(ctx context.Context, in *StreamClientIdsRequest, opts ...grpc.CallOption) (Admin_StreamClientIdsClient, error) { + stream, err := c.cc.NewStream(ctx, &_Admin_serviceDesc.Streams[0], "/fleetspeak.server.Admin/StreamClientIds", opts...) + if err != nil { + return nil, err + } + x := &adminStreamClientIdsClient{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 Admin_StreamClientIdsClient interface { + Recv() (*StreamClientIdsResponse, error) + grpc.ClientStream +} + +type adminStreamClientIdsClient struct { + grpc.ClientStream +} + +func (x *adminStreamClientIdsClient) Recv() (*StreamClientIdsResponse, error) { + m := new(StreamClientIdsResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + func (c *adminClient) ListClientContacts(ctx context.Context, in *ListClientContactsRequest, opts ...grpc.CallOption) (*ListClientContactsResponse, error) { out := new(ListClientContactsResponse) err := c.cc.Invoke(ctx, "/fleetspeak.server.Admin/ListClientContacts", in, out, opts...) @@ -1811,6 +2113,38 @@ func (c *adminClient) ListClientContacts(ctx context.Context, in *ListClientCont return out, nil } +func (c *adminClient) StreamClientContacts(ctx context.Context, in *StreamClientContactsRequest, opts ...grpc.CallOption) (Admin_StreamClientContactsClient, error) { + stream, err := c.cc.NewStream(ctx, &_Admin_serviceDesc.Streams[1], "/fleetspeak.server.Admin/StreamClientContacts", opts...) + if err != nil { + return nil, err + } + x := &adminStreamClientContactsClient{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 Admin_StreamClientContactsClient interface { + Recv() (*StreamClientContactsResponse, error) + grpc.ClientStream +} + +type adminStreamClientContactsClient struct { + grpc.ClientStream +} + +func (x *adminStreamClientContactsClient) Recv() (*StreamClientContactsResponse, error) { + m := new(StreamClientContactsResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + func (c *adminClient) GetMessageStatus(ctx context.Context, in *GetMessageStatusRequest, opts ...grpc.CallOption) (*GetMessageStatusResponse, error) { out := new(GetMessageStatusResponse) err := c.cc.Invoke(ctx, "/fleetspeak.server.Admin/GetMessageStatus", in, out, opts...) @@ -1901,8 +2235,12 @@ type AdminServer interface { ListActiveBroadcasts(context.Context, *ListActiveBroadcastsRequest) (*ListActiveBroadcastsResponse, error) // ListClients lists the currently active FS clients. ListClients(context.Context, *ListClientsRequest) (*ListClientsResponse, error) + // StreamClientIds lists the currently active FS clients as a stream. + StreamClientIds(*StreamClientIdsRequest, Admin_StreamClientIdsServer) error // ListClientContacts lists the contact history for a client. ListClientContacts(context.Context, *ListClientContactsRequest) (*ListClientContactsResponse, error) + // StreamClientContacts lists the contact history for a client as a stream. + StreamClientContacts(*StreamClientContactsRequest, Admin_StreamClientContactsServer) error // GetMessageStatus retrieves the current status of a message. GetMessageStatus(context.Context, *GetMessageStatusRequest) (*GetMessageStatusResponse, error) // InsertMessage inserts a message into the Fleetspeak system to be processed @@ -1941,9 +2279,15 @@ func (*UnimplementedAdminServer) ListActiveBroadcasts(context.Context, *ListActi func (*UnimplementedAdminServer) ListClients(context.Context, *ListClientsRequest) (*ListClientsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListClients not implemented") } +func (*UnimplementedAdminServer) StreamClientIds(*StreamClientIdsRequest, Admin_StreamClientIdsServer) error { + return status.Errorf(codes.Unimplemented, "method StreamClientIds not implemented") +} func (*UnimplementedAdminServer) ListClientContacts(context.Context, *ListClientContactsRequest) (*ListClientContactsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListClientContacts not implemented") } +func (*UnimplementedAdminServer) StreamClientContacts(*StreamClientContactsRequest, Admin_StreamClientContactsServer) error { + return status.Errorf(codes.Unimplemented, "method StreamClientContacts not implemented") +} func (*UnimplementedAdminServer) GetMessageStatus(context.Context, *GetMessageStatusRequest) (*GetMessageStatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMessageStatus not implemented") } @@ -2030,6 +2374,27 @@ func _Admin_ListClients_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Admin_StreamClientIds_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(StreamClientIdsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(AdminServer).StreamClientIds(m, &adminStreamClientIdsServer{stream}) +} + +type Admin_StreamClientIdsServer interface { + Send(*StreamClientIdsResponse) error + grpc.ServerStream +} + +type adminStreamClientIdsServer struct { + grpc.ServerStream +} + +func (x *adminStreamClientIdsServer) Send(m *StreamClientIdsResponse) error { + return x.ServerStream.SendMsg(m) +} + func _Admin_ListClientContacts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListClientContactsRequest) if err := dec(in); err != nil { @@ -2048,6 +2413,27 @@ func _Admin_ListClientContacts_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Admin_StreamClientContacts_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(StreamClientContactsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(AdminServer).StreamClientContacts(m, &adminStreamClientContactsServer{stream}) +} + +type Admin_StreamClientContactsServer interface { + Send(*StreamClientContactsResponse) error + grpc.ServerStream +} + +type adminStreamClientContactsServer struct { + grpc.ServerStream +} + +func (x *adminStreamClientContactsServer) Send(m *StreamClientContactsResponse) error { + return x.ServerStream.SendMsg(m) +} + func _Admin_GetMessageStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetMessageStatusRequest) if err := dec(in); err != nil { @@ -2267,6 +2653,17 @@ var _Admin_serviceDesc = grpc.ServiceDesc{ Handler: _Admin_FetchClientResourceUsageRecords_Handler, }, }, - Streams: []grpc.StreamDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "StreamClientIds", + Handler: _Admin_StreamClientIds_Handler, + ServerStreams: true, + }, + { + StreamName: "StreamClientContacts", + Handler: _Admin_StreamClientContacts_Handler, + ServerStreams: true, + }, + }, Metadata: "fleetspeak/src/server/proto/fleetspeak_server/admin.proto", } diff --git a/fleetspeak/src/server/proto/fleetspeak_server/admin.proto b/fleetspeak/src/server/proto/fleetspeak_server/admin.proto index 84b62e13..84934263 100644 --- a/fleetspeak/src/server/proto/fleetspeak_server/admin.proto +++ b/fleetspeak/src/server/proto/fleetspeak_server/admin.proto @@ -33,6 +33,13 @@ message ListClientsResponse { repeated Client clients = 1; } +message StreamClientIdsRequest { +} + +message StreamClientIdsResponse { + bytes client_id = 1; +} + message Client { // Next unused tag: 8 @@ -91,6 +98,14 @@ message ListClientContactsResponse { repeated ClientContact contacts = 1; } +message StreamClientContactsRequest { + bytes client_id = 1; +} + +message StreamClientContactsResponse { + ClientContact contact = 1; +} + message ClientContact { fixed64 sent_nonce = 1; fixed64 received_nonce = 2; @@ -126,10 +141,18 @@ service Admin { rpc ListClients (ListClientsRequest) returns (ListClientsResponse) { } + // StreamClientIds lists the currently active FS clients as a stream. + rpc StreamClientIds (StreamClientIdsRequest) returns (stream StreamClientIdsResponse) { + } + // ListClientContacts lists the contact history for a client. rpc ListClientContacts (ListClientContactsRequest) returns (ListClientContactsResponse) { } + // StreamClientContacts lists the contact history for a client as a stream. + rpc StreamClientContacts (StreamClientContactsRequest) returns (stream StreamClientContactsResponse) { + } + // GetMessageStatus retrieves the current status of a message. rpc GetMessageStatus (GetMessageStatusRequest) returns (GetMessageStatusResponse) { } diff --git a/fleetspeak/src/server/servertests/admin_test.go b/fleetspeak/src/server/servertests/admin_test.go index cbf55f59..0fab7271 100644 --- a/fleetspeak/src/server/servertests/admin_test.go +++ b/fleetspeak/src/server/servertests/admin_test.go @@ -17,10 +17,13 @@ package servertests_test import ( "bytes" "context" + "reflect" "sort" "strings" "testing" + "google.golang.org/grpc" + "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" @@ -125,6 +128,20 @@ func TestMessageStatusAPI(t *testing.T) { } } +type mockStreamClientIdsServer struct { + grpc.ServerStream + responses []*spb.StreamClientIdsResponse +} + +func (m *mockStreamClientIdsServer) Send(response *spb.StreamClientIdsResponse) error { + m.responses = append(m.responses, response) + return nil +} + +func (m *mockStreamClientIdsServer) Context() context.Context { + return context.Background() +} + func TestListClientsAPI(t *testing.T) { ctx := context.Background() @@ -166,38 +183,60 @@ func TestListClientsAPI(t *testing.T) { t.Errorf("AddClient returned an error: %v", err) } - lcRes, err := as.ListClients(ctx, &spb.ListClientsRequest{}) - if err != nil { - t.Errorf("ListClients returned an error: %v", err) - } + t.Run("ListClients", func(t *testing.T) { + lcRes, err := as.ListClients(ctx, &spb.ListClientsRequest{}) + if err != nil { + t.Errorf("ListClients returned an error: %v", err) + } - lcWant := &spb.ListClientsResponse{ - Clients: []*spb.Client{ - { - ClientId: id0, + lcWant := &spb.ListClientsResponse{ + Clients: []*spb.Client{ + { + ClientId: id0, + }, + { + ClientId: id1, + Labels: lab1, + }, }, - { - ClientId: id1, - Labels: lab1, - }, - }, - } + } - // The result's order is arbitrary, so let's sort it. - sort.Slice(lcRes.Clients, func(i, j int) bool { - return bytes.Compare(lcRes.Clients[i].ClientId, lcRes.Clients[j].ClientId) < 0 - }) + // The result's order is arbitrary, so let's sort it. + sort.Slice(lcRes.Clients, func(i, j int) bool { + return bytes.Compare(lcRes.Clients[i].ClientId, lcRes.Clients[j].ClientId) < 0 + }) - for _, c := range lcRes.Clients { - if c.LastContactTime == nil { - t.Errorf("ListClients error: LastSeenTimestamp is nil") + for _, c := range lcRes.Clients { + if c.LastContactTime == nil { + t.Errorf("ListClients error: LastSeenTimestamp is nil") + } + c.LastContactTime = nil } - c.LastContactTime = nil - } - if !proto.Equal(lcRes, lcWant) { - t.Errorf("ListClients error: want [%v], got [%v]", lcWant, lcRes) - } + if !proto.Equal(lcRes, lcWant) { + t.Errorf("ListClients error: want [%v], got [%v]", lcWant, lcRes) + } + }) + + t.Run("StreamClientIds", func(t *testing.T) { + var m mockStreamClientIdsServer + req := &spb.StreamClientIdsRequest{} + err := as.StreamClientIds(req, &m) + if err != nil { + t.Errorf("StreamClientIds returned an error: %v", err) + } + var ids [][]byte + for _, response := range m.responses { + ids = append(ids, response.ClientId) + } + sort.Slice(ids, func(i, j int) bool { + return bytes.Compare(ids[i], ids[j]) < 0 + }) + expected := [][]byte{id0, id1} + if !reflect.DeepEqual(ids, expected) { + t.Errorf("StreamClientIds error: want [%v], got [%v].", expected, ids) + } + }) } func TestInsertMessageAPI(t *testing.T) { @@ -472,3 +511,77 @@ func TestPendingMessages(t *testing.T) { } }) } + +type mockStreamClientContactsServer struct { + grpc.ServerStream + responses []*spb.StreamClientContactsResponse +} + +func (m *mockStreamClientContactsServer) Send(response *spb.StreamClientContactsResponse) error { + m.responses = append(m.responses, response) + return nil +} + +func (m *mockStreamClientContactsServer) Context() context.Context { + return context.Background() +} + +func TestClientContacts(t *testing.T) { + ctx := context.Background() + + ts := testserver.Make(t, "server", "TestPendingMessages", nil) + defer ts.S.Stop() + + as := admin.NewServer(ts.DS, nil) + + id := []byte{0, 0, 0, 0, 0, 0, 0, 0} + cid, err := common.BytesToClientID(id) + if err != nil { + t.Fatalf("Failed to convert ID: %v.", err) + } + + err = ts.DS.AddClient(ctx, cid, &db.ClientData{}) + if err != nil { + t.Fatalf("Failed to add client: %v.", err) + } + + for _, data := range []db.ContactData{ + { + ClientID: cid, + Addr: "a1", + }, + { + ClientID: cid, + Addr: "a2", + }, + } { + _, err = ts.DS.RecordClientContact(ctx, data) + if err != nil { + t.Fatalf("Failed to record client contact: %v.", err) + } + } + + t.Run("StreamClientContacts", func(t *testing.T) { + req := &spb.StreamClientContactsRequest{ + ClientId: id, + } + var m mockStreamClientContactsServer + err := as.StreamClientContacts(req, &m) + if err != nil { + t.Fatalf("StreamClientContacts failed: %v.", err) + } + + var addrs []string + for _, response := range m.responses { + addrs = append(addrs, response.Contact.ObservedAddress) + } + sort.Strings(addrs) + + expected := []string{"a1", "a2"} + + if !reflect.DeepEqual(addrs, expected) { + t.Errorf("StreamClientContacts error: want [%v], got [%v].", expected, addrs) + } + }) + +} diff --git a/fleetspeak/src/server/sqlite/clientstore.go b/fleetspeak/src/server/sqlite/clientstore.go index c218efe8..46265639 100644 --- a/fleetspeak/src/server/sqlite/clientstore.go +++ b/fleetspeak/src/server/sqlite/clientstore.go @@ -153,6 +153,34 @@ func (d *Datastore) ListClients(ctx context.Context, ids []common.ClientID) ([]* return ret, err } +func (d *Datastore) StreamClientIds(ctx context.Context, callback func(common.ClientID) error) error { + d.l.Lock() + defer d.l.Unlock() + return d.runInTx(func(tx *sql.Tx) error { + rs, err := tx.QueryContext(ctx, "SELECT client_id FROM clients") + if err != nil { + return err + } + defer rs.Close() + for rs.Next() { + var sid string + err := rs.Scan(&sid) + if err != nil { + return err + } + id, err := common.StringToClientID(sid) + if err != nil { + return err + } + err = callback(id) + if err != nil { + return err + } + } + return nil + }) +} + func (d *Datastore) GetClientData(ctx context.Context, id common.ClientID) (*db.ClientData, error) { d.l.Lock() defer d.l.Unlock() @@ -262,11 +290,10 @@ func (d *Datastore) RecordClientContact(ctx context.Context, data db.ContactData return res, err } -func (d *Datastore) ListClientContacts(ctx context.Context, id common.ClientID) ([]*spb.ClientContact, error) { +func (d *Datastore) StreamClientContacts(ctx context.Context, id common.ClientID, callback func(*spb.ClientContact) error) error { d.l.Lock() defer d.l.Unlock() - var res []*spb.ClientContact if err := d.runInTx(func(tx *sql.Tx) error { rows, err := tx.QueryContext( ctx, @@ -304,14 +331,26 @@ func (d *Datastore) ListClientContacts(ctx context.Context, id common.ClientID) } c.Timestamp = ts - res = append(res, c) + err = callback(c) + if err != nil { + return err + } } return nil }); err != nil { - return nil, err + return err } - return res, nil + return nil +} + +func (d *Datastore) ListClientContacts(ctx context.Context, id common.ClientID) ([]*spb.ClientContact, error) { + var res []*spb.ClientContact + callback := func(c *spb.ClientContact) error { + res = append(res, c) + return nil + } + return res, d.StreamClientContacts(ctx, id, callback) } func (d *Datastore) LinkMessagesToContact(ctx context.Context, contact db.ContactID, ids []common.MessageID) error { diff --git a/fleetspeak/src/server/stats.go b/fleetspeak/src/server/stats.go index 48787de5..1ed05328 100644 --- a/fleetspeak/src/server/stats.go +++ b/fleetspeak/src/server/stats.go @@ -130,6 +130,13 @@ func (d MonitoredDatastore) ListClients(ctx context.Context, ids []common.Client return res, err } +func (d MonitoredDatastore) StreamClientIds(ctx context.Context, callback func(common.ClientID) error) error { + s := ftime.Now() + err := d.D.StreamClientIds(ctx, callback) + d.C.DatastoreOperation(s, ftime.Now(), "StreamClientIds", err) + return err +} + func (d MonitoredDatastore) GetClientData(ctx context.Context, id common.ClientID) (*db.ClientData, error) { s := ftime.Now() res, err := d.D.GetClientData(ctx, id) @@ -183,6 +190,13 @@ func (d MonitoredDatastore) ListClientContacts(ctx context.Context, id common.Cl return res, err } +func (d MonitoredDatastore) StreamClientContacts(ctx context.Context, id common.ClientID, callback func(*spb.ClientContact) error) error { + s := ftime.Now() + err := d.D.StreamClientContacts(ctx, id, callback) + d.C.DatastoreOperation(s, ftime.Now(), "StreamClientContacts", err) + return err +} + func (d MonitoredDatastore) RecordResourceUsageData(ctx context.Context, id common.ClientID, rud *mpb.ResourceUsageData) error { s := ftime.Now() err := d.D.RecordResourceUsageData(ctx, id, rud)