feat(communities): add magnetlink to RequestToJoinResponse

This is done so that when member join a community by being accepted by
the community owner, they also receive the most up-to-date magnetlink
along with it.
This commit is contained in:
Pascal Precht 2022-12-09 15:26:12 +01:00 committed by r4bbit
parent d03691c2f2
commit dd8be1d8b0
5 changed files with 197 additions and 138 deletions

View File

@ -706,7 +706,7 @@ func (m *Messenger) Start() (*MessengerResponse, error) {
return nil, err
}
if m.config.torrentConfig != nil && m.config.torrentConfig.Enabled && m.communitiesManager.TorrentClientStarted() {
if m.torrentClientReady() {
adminCommunities, err := m.communitiesManager.Created()
if err == nil && len(adminCommunities) > 0 {
available := m.SubscribeMailserverAvailable()

View File

@ -719,6 +719,15 @@ func (m *Messenger) AcceptRequestToJoinCommunity(request *requests.AcceptRequest
Grant: grant,
}
if m.torrentClientReady() && m.communitiesManager.TorrentFileExists(community.IDString()) {
magnetlink, err := m.communitiesManager.GetHistoryArchiveMagnetlink(community.ID())
if err != nil {
m.logger.Warn("couldn't get magnet link for community", zap.Error(err))
return nil, err
}
requestToJoinResponseProto.MagnetUri = magnetlink
}
payload, err := proto.Marshal(requestToJoinResponseProto)
if err != nil {
return nil, err
@ -1076,7 +1085,7 @@ func (m *Messenger) EditCommunity(request *requests.EditCommunity) (*MessengerRe
id := community.ID()
if m.config.torrentConfig != nil && m.config.torrentConfig.Enabled && m.communitiesManager.TorrentClientStarted() {
if m.torrentClientReady() {
if !communitySettings.HistoryArchiveSupportEnabled {
m.communitiesManager.StopHistoryArchiveTasksInterval(id)
} else if !m.communitiesManager.IsSeedingHistoryArchiveTorrent(id) {
@ -1139,7 +1148,7 @@ func (m *Messenger) ImportCommunity(ctx context.Context, key *ecdsa.PrivateKey)
return nil, err
}
if m.config.torrentConfig != nil && m.config.torrentConfig.Enabled && m.communitiesManager.TorrentClientStarted() {
if m.torrentClientReady() {
var communities []*communities.Community
communities = append(communities, community)
go m.InitHistoryArchiveTasks(communities)
@ -2984,10 +2993,7 @@ func (m *Messenger) RequestImportDiscordCommunity(request *requests.ImportDiscor
}
}
if m.config.torrentConfig != nil &&
m.config.torrentConfig.Enabled &&
communitySettings.HistoryArchiveSupportEnabled &&
m.communitiesManager.TorrentClientStarted() {
if m.torrentClientReady() && communitySettings.HistoryArchiveSupportEnabled {
err = m.communitiesManager.SeedHistoryArchiveTorrent(discordCommunity.ID())
if err != nil {
@ -3101,6 +3107,15 @@ func (m *Messenger) pinMessagesToWakuMessages(pinMessages []*common.PinMessage,
return wakuMessages, nil
}
func (m *Messenger) torrentClientReady() bool {
// Simply checking for `torrentConfig.Enabled` isn't enough
// as there's a possiblity that the torrent client couldn't
// be instantiated (for example in case of port conflicts)
return m.config.torrentConfig != nil &&
m.config.torrentConfig.Enabled &&
m.communitiesManager.TorrentClientStarted()
}
func (m *Messenger) chatMessagesToWakuMessages(chatMessages []*common.Message, c *communities.Community) ([]*types.Message, error) {
wakuMessages := make([]*types.Message, 0)
for _, msg := range chatMessages {

View File

@ -906,7 +906,7 @@ func (m *Messenger) HandleHistoryArchiveMagnetlinkMessage(state *ReceivedMessage
return err
}
if m.config.torrentConfig != nil && m.config.torrentConfig.Enabled && settings != nil && settings.HistoryArchiveSupportEnabled {
if m.torrentClientReady() && settings != nil && settings.HistoryArchiveSupportEnabled {
signedByOwnedCommunity, err := m.communitiesManager.IsAdminCommunity(communityPubKey)
if err != nil {
return err
@ -950,106 +950,7 @@ func (m *Messenger) HandleHistoryArchiveMagnetlinkMessage(state *ReceivedMessage
// this wait groups tracks all ongoing tasks across communities
m.downloadHistoryArchiveTasksWaitGroup.Add(1)
defer m.downloadHistoryArchiveTasksWaitGroup.Done()
downloadTaskInfo, err := m.communitiesManager.DownloadHistoryArchivesByMagnetlink(id, magnetlink, task.Cancel)
if err != nil {
logMsg := "failed to download history archive data"
if err == communities.ErrTorrentTimedout {
m.communitiesManager.LogStdout("torrent has timed out, trying once more...")
downloadTaskInfo, err = m.communitiesManager.DownloadHistoryArchivesByMagnetlink(id, magnetlink, task.Cancel)
if err != nil {
m.communitiesManager.LogStdout(logMsg, zap.Error(err))
return
}
} else {
m.communitiesManager.LogStdout(logMsg, zap.Error(err))
return
}
}
if downloadTaskInfo.Cancelled {
if downloadTaskInfo.TotalDownloadedArchivesCount > 0 {
m.communitiesManager.LogStdout(fmt.Sprintf("downloaded %d of %d archives so far", downloadTaskInfo.TotalDownloadedArchivesCount, downloadTaskInfo.TotalArchivesCount))
}
return
}
importTicker := time.NewTicker(100 * time.Millisecond)
defer importTicker.Stop()
importMessageArchivesLoop:
for {
select {
case <-task.Cancel:
m.communitiesManager.LogStdout("interrupted importing history archive messages")
return
case <-importTicker.C:
archiveIDsToImport, err := m.communitiesManager.GetMessageArchiveIDsToImport(id)
if err != nil {
m.communitiesManager.LogStdout("couldn't get message archive IDs to import", zap.Error(err))
return
}
if len(archiveIDsToImport) == 0 {
m.communitiesManager.LogStdout("no message archives to import")
break importMessageArchivesLoop
}
m.communitiesManager.LogStdout(fmt.Sprintf("importing message archive, %d left", len(archiveIDsToImport)))
// only process one archive at a time, so in case of cancel we don't
// wait for all archives to be processed first
downloadedArchiveID := archiveIDsToImport[0]
messagesToHandle, err := m.communitiesManager.ExtractMessagesFromHistoryArchives(id, []string{downloadedArchiveID})
if err != nil {
m.communitiesManager.LogStdout("failed to extract history archive messages", zap.Error(err))
continue
}
importedMessages := make(map[transport.Filter][]*types.Message, 0)
otherMessages := make(map[transport.Filter][]*types.Message, 0)
for filter, messages := range messagesToHandle {
for _, message := range messages {
if message.ThirdPartyID != "" {
importedMessages[filter] = append(importedMessages[filter], message)
} else {
otherMessages[filter] = append(otherMessages[filter], message)
}
}
}
m.config.messengerSignalsHandler.ImportingHistoryArchiveMessages(types.EncodeHex(id))
err = m.handleImportedMessages(importedMessages)
if err != nil {
m.communitiesManager.LogStdout("failed to handle imported messages", zap.Error(err))
continue
}
response, err := m.handleRetrievedMessages(otherMessages, false)
if err != nil {
m.communitiesManager.LogStdout("failed to write history archive messages to database", zap.Error(err))
continue
}
err = m.communitiesManager.SetMessageArchiveIDImported(id, downloadedArchiveID, true)
if err != nil {
m.communitiesManager.LogStdout("failed to mark history message archive as imported", zap.Error(err))
continue
}
if !response.IsEmpty() {
notifications := response.Notifications()
response.ClearNotifications()
signal.SendNewMessages(response)
localnotifications.PushMessages(notifications)
}
}
}
m.config.messengerSignalsHandler.DownloadingHistoryArchivesFinished(types.EncodeHex(id))
m.downloadAndImportHistoryArchives(id, magnetlink, task.Cancel)
}(currentTask)
return m.communitiesManager.UpdateMagnetlinkMessageClock(id, clock)
@ -1058,6 +959,107 @@ func (m *Messenger) HandleHistoryArchiveMagnetlinkMessage(state *ReceivedMessage
return nil
}
func (m *Messenger) downloadAndImportHistoryArchives(id types.HexBytes, magnetlink string, cancel chan struct{}) {
downloadTaskInfo, err := m.communitiesManager.DownloadHistoryArchivesByMagnetlink(id, magnetlink, cancel)
if err != nil {
logMsg := "failed to download history archive data"
if err == communities.ErrTorrentTimedout {
m.communitiesManager.LogStdout("torrent has timed out, trying once more...")
downloadTaskInfo, err = m.communitiesManager.DownloadHistoryArchivesByMagnetlink(id, magnetlink, cancel)
if err != nil {
m.communitiesManager.LogStdout(logMsg, zap.Error(err))
return
}
} else {
m.communitiesManager.LogStdout(logMsg, zap.Error(err))
return
}
}
if downloadTaskInfo.Cancelled {
m.communitiesManager.LogStdout(fmt.Sprintf("downloaded %d of %d archives so far", downloadTaskInfo.TotalDownloadedArchivesCount, downloadTaskInfo.TotalArchivesCount))
return
}
importTicker := time.NewTicker(100 * time.Millisecond)
defer importTicker.Stop()
importMessageArchivesLoop:
for {
select {
case <-cancel:
m.communitiesManager.LogStdout("interrupted importing history archive messages")
return
case <-importTicker.C:
archiveIDsToImport, err := m.communitiesManager.GetMessageArchiveIDsToImport(id)
if err != nil {
m.communitiesManager.LogStdout("couldn't get message archive IDs to import", zap.Error(err))
return
}
if len(archiveIDsToImport) == 0 {
m.communitiesManager.LogStdout("no message archives to import")
break importMessageArchivesLoop
}
m.communitiesManager.LogStdout(fmt.Sprintf("importing message archive, %d left", len(archiveIDsToImport)))
// only process one archive at a time, so in case of cancel we don't
// wait for all archives to be processed first
downloadedArchiveID := archiveIDsToImport[0]
messagesToHandle, err := m.communitiesManager.ExtractMessagesFromHistoryArchives(id, []string{downloadedArchiveID})
if err != nil {
m.communitiesManager.LogStdout("failed to extract history archive messages", zap.Error(err))
continue
}
importedMessages := make(map[transport.Filter][]*types.Message, 0)
otherMessages := make(map[transport.Filter][]*types.Message, 0)
for filter, messages := range messagesToHandle {
for _, message := range messages {
if message.ThirdPartyID != "" {
importedMessages[filter] = append(importedMessages[filter], message)
} else {
otherMessages[filter] = append(otherMessages[filter], message)
}
}
}
m.config.messengerSignalsHandler.ImportingHistoryArchiveMessages(types.EncodeHex(id))
err = m.handleImportedMessages(importedMessages)
if err != nil {
m.communitiesManager.LogStdout("failed to handle imported messages", zap.Error(err))
continue
}
response, err := m.handleRetrievedMessages(otherMessages, false)
if err != nil {
m.communitiesManager.LogStdout("failed to write history archive messages to database", zap.Error(err))
continue
}
err = m.communitiesManager.SetMessageArchiveIDImported(id, downloadedArchiveID, true)
if err != nil {
m.communitiesManager.LogStdout("failed to mark history message archive as imported", zap.Error(err))
continue
}
if !response.IsEmpty() {
notifications := response.Notifications()
response.ClearNotifications()
signal.SendNewMessages(response)
localnotifications.PushMessages(notifications)
}
}
}
m.config.messengerSignalsHandler.DownloadingHistoryArchivesFinished(types.EncodeHex(id))
}
func (m *Messenger) HandleCommunityCancelRequestToJoin(state *ReceivedMessageState, signer *ecdsa.PublicKey, cancelRequestToJoinProto protobuf.CommunityCancelRequestToJoin) error {
if cancelRequestToJoinProto.CommunityId == nil {
return errors.New("invalid community id")
@ -1172,8 +1174,41 @@ func (m *Messenger) HandleCommunityRequestToJoinResponse(state *ReceivedMessageS
return err
}
if len(response.Communities()) > 0 {
state.Response.AddCommunity(response.Communities()[0])
state.Response.AddCommunitySettings(response.CommunitiesSettings()[0])
communitySettings := response.CommunitiesSettings()[0]
community := response.Communities()[0]
state.Response.AddCommunity(community)
state.Response.AddCommunitySettings(communitySettings)
magnetlink := requestToJoinResponseProto.MagnetUri
if m.torrentClientReady() && communitySettings != nil && communitySettings.HistoryArchiveSupportEnabled && magnetlink != "" {
currentTask := m.communitiesManager.GetHistoryArchiveDownloadTask(community.IDString())
go func(currentTask *communities.HistoryArchiveDownloadTask) {
// Cancel ongoing download/import task
if currentTask != nil {
close(currentTask.Cancel)
currentTask.Waiter.Wait()
}
task := &communities.HistoryArchiveDownloadTask{
Cancel: make(chan struct{}),
Waiter: *new(sync.WaitGroup),
}
m.communitiesManager.AddHistoryArchiveDownloadTask(community.IDString(), task)
task.Waiter.Add(1)
defer task.Waiter.Done()
m.downloadHistoryArchiveTasksWaitGroup.Add(1)
defer m.downloadHistoryArchiveTasksWaitGroup.Done()
m.downloadAndImportHistoryArchives(community.ID(), magnetlink, task.Cancel)
}(currentTask)
clock := requestToJoinResponseProto.Community.ArchiveMagnetlinkClock
return m.communitiesManager.UpdateMagnetlinkMessageClock(community.ID(), clock)
}
}
}

View File

@ -751,6 +751,7 @@ type CommunityRequestToJoinResponse struct {
Accepted bool `protobuf:"varint,3,opt,name=accepted,proto3" json:"accepted,omitempty"`
Grant []byte `protobuf:"bytes,4,opt,name=grant,proto3" json:"grant,omitempty"`
CommunityId []byte `protobuf:"bytes,5,opt,name=community_id,json=communityId,proto3" json:"community_id,omitempty"`
MagnetUri string `protobuf:"bytes,6,opt,name=magnet_uri,json=magnetUri,proto3" json:"magnet_uri,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -816,6 +817,13 @@ func (m *CommunityRequestToJoinResponse) GetCommunityId() []byte {
return nil
}
func (m *CommunityRequestToJoinResponse) GetMagnetUri() string {
if m != nil {
return m.MagnetUri
}
return ""
}
type CommunityRequestToLeave struct {
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
CommunityId []byte `protobuf:"bytes,2,opt,name=community_id,json=communityId,proto3" json:"community_id,omitempty"`
@ -1258,12 +1266,12 @@ func init() {
}
var fileDescriptor_f937943d74c1cd8b = []byte{
// 1396 bytes of a gzipped FileDescriptorProto
// 1404 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x57, 0xcd, 0x6f, 0x1b, 0x45,
0x14, 0xef, 0xfa, 0x23, 0xb6, 0x9f, 0xed, 0xd4, 0x99, 0x36, 0xc9, 0x36, 0xfd, 0x88, 0xbb, 0x80,
0x94, 0x0a, 0xe1, 0xaa, 0xa9, 0x90, 0x2a, 0xbe, 0x5a, 0x37, 0xb5, 0x8a, 0x69, 0x62, 0xb7, 0x13,
0x87, 0xd2, 0x1e, 0x58, 0x4d, 0x76, 0x27, 0xce, 0x28, 0xeb, 0x59, 0xb3, 0x33, 0x8e, 0x30, 0x07,
0xfe, 0x0e, 0xc4, 0x95, 0x0b, 0x27, 0xfe, 0x05, 0x0e, 0x9c, 0xb8, 0x70, 0xe7, 0xc6, 0x9f, 0x82,
0xfe, 0x0e, 0xc4, 0x95, 0x0b, 0x27, 0xfe, 0x05, 0x0e, 0xdc, 0xb9, 0x73, 0xe3, 0xc8, 0x9f, 0x81,
0x66, 0xf6, 0xc3, 0xeb, 0xaf, 0xb4, 0x52, 0x85, 0xc4, 0xc9, 0xf3, 0xde, 0xbe, 0xf7, 0x7b, 0xdf,
0xf3, 0xc6, 0xb0, 0xe6, 0xf8, 0x83, 0xc1, 0x88, 0x33, 0xc9, 0xa8, 0x68, 0x0c, 0x03, 0x5f, 0xfa,
0xa8, 0xa8, 0x7f, 0x8e, 0x47, 0x27, 0x5b, 0x57, 0x9c, 0x53, 0x22, 0x6d, 0xe6, 0x52, 0x2e, 0x99,
@ -1278,7 +1286,7 @@ var fileDescriptor_f937943d74c1cd8b = []byte{
0xa1, 0x0a, 0x14, 0xd5, 0xc9, 0x6e, 0xee, 0xef, 0xd7, 0x0c, 0xb4, 0x0e, 0x6b, 0x9a, 0x3a, 0x68,
0x76, 0x9a, 0x4f, 0x5b, 0xf6, 0xd1, 0x61, 0x0b, 0x1f, 0xd6, 0x32, 0xe8, 0x1a, 0xac, 0x87, 0xec,
0xee, 0x93, 0x16, 0x6e, 0xf6, 0x5a, 0xf6, 0x5e, 0xb7, 0xd3, 0x6b, 0x75, 0x7a, 0xb5, 0xac, 0xf5,
0x8f, 0x01, 0x57, 0x13, 0xdb, 0xcf, 0x69, 0x30, 0x60, 0x42, 0x30, 0x9f, 0x0b, 0x74, 0x0d, 0x8a,
0xb7, 0x01, 0x57, 0x13, 0xdb, 0xcf, 0x69, 0x30, 0x60, 0x42, 0x30, 0x9f, 0x0b, 0x74, 0x0d, 0x8a,
0x94, 0x0b, 0xdb, 0xe7, 0xde, 0x58, 0x67, 0xaa, 0x88, 0x0b, 0x94, 0x8b, 0x2e, 0xf7, 0xc6, 0xc8,
0x84, 0xc2, 0x30, 0x60, 0xe7, 0x44, 0x52, 0x9d, 0xa3, 0x22, 0x8e, 0x49, 0xf4, 0x39, 0xac, 0x10,
0xc7, 0xa1, 0x42, 0xe8, 0x0c, 0xad, 0xee, 0x7e, 0xb0, 0x20, 0xc0, 0x94, 0x91, 0x46, 0x53, 0x0b,
@ -1309,7 +1317,7 @@ var fileDescriptor_f937943d74c1cd8b = []byte{
0x4d, 0xe3, 0x5e, 0x5f, 0x84, 0x1b, 0x82, 0x8c, 0x53, 0xd8, 0xd6, 0xb7, 0xb0, 0xb1, 0xb8, 0x54,
0xe8, 0x09, 0x6c, 0x0f, 0x19, 0x8f, 0x93, 0x6e, 0x13, 0xcf, 0xb3, 0xa3, 0xd9, 0xb2, 0x29, 0x27,
0xc7, 0x1e, 0x75, 0xa3, 0x7b, 0xe9, 0xfa, 0x90, 0xf1, 0xa8, 0x0c, 0x4d, 0xcf, 0x4b, 0x72, 0xaa,
0x45, 0xac, 0xbf, 0x33, 0x50, 0x9d, 0x0a, 0x0c, 0x7d, 0x31, 0x99, 0x6f, 0x43, 0xf7, 0xf0, 0xfb,
0x45, 0xac, 0xbf, 0x32, 0x50, 0x9d, 0x0a, 0x0c, 0x7d, 0x31, 0x99, 0x6f, 0x43, 0xf7, 0xf0, 0xfb,
0x4b, 0x52, 0xf0, 0x76, 0x83, 0x9d, 0x79, 0xb7, 0xc1, 0xce, 0xbe, 0xe5, 0x60, 0x6f, 0x43, 0x39,
0x1a, 0x1d, 0xbd, 0xbb, 0x72, 0x3a, 0xf1, 0xf1, 0x34, 0xa9, 0xd5, 0xb5, 0x05, 0xc5, 0xa1, 0x2f,
0x98, 0x9a, 0x3a, 0x7d, 0x5b, 0xe4, 0x71, 0x42, 0xff, 0x47, 0xad, 0x66, 0xb9, 0xb0, 0x36, 0x57,
@ -1321,30 +1329,30 @@ var fileDescriptor_f937943d74c1cd8b = []byte{
0xba, 0x17, 0xd3, 0xef, 0x46, 0x54, 0xc8, 0x9e, 0xff, 0x95, 0xcf, 0x96, 0xed, 0x96, 0x68, 0xa9,
0xa6, 0xe2, 0x57, 0x4b, 0xb5, 0xa3, 0x52, 0xb0, 0xd4, 0x87, 0xd9, 0x67, 0x4b, 0x6e, 0xfe, 0xd9,
0x72, 0x1b, 0x2a, 0x2e, 0x13, 0x43, 0x8f, 0x8c, 0x43, 0xe8, 0xbc, 0x06, 0x28, 0x47, 0x3c, 0x05,
0x6f, 0xfd, 0x66, 0xc0, 0x8d, 0x54, 0xb1, 0xb8, 0x43, 0xbd, 0xff, 0xb7, 0xc3, 0x7f, 0x1a, 0x70,
0x6f, 0xfd, 0x66, 0xc0, 0x8d, 0x54, 0xb1, 0xb8, 0x43, 0xbd, 0xff, 0xb7, 0xc3, 0xff, 0x18, 0x70,
0x6b, 0x71, 0x6e, 0x31, 0x15, 0x43, 0x9f, 0x0b, 0xba, 0xc4, 0xe5, 0xcf, 0xa0, 0x94, 0x98, 0xba,
0x60, 0x3a, 0x53, 0x5d, 0x81, 0x27, 0x0a, 0xaa, 0x13, 0xd5, 0x63, 0x44, 0x5f, 0xe3, 0x59, 0x7d,
0xbd, 0x24, 0xf4, 0xa4, 0x79, 0x72, 0xe9, 0xe6, 0x99, 0x0d, 0x37, 0x3f, 0x17, 0xae, 0x85, 0x61,
0x73, 0x3e, 0x94, 0x7d, 0x4a, 0xce, 0x97, 0xc5, 0x30, 0x8b, 0x99, 0x99, 0xc7, 0xfc, 0x06, 0x6e,
0xa7, 0x46, 0x33, 0xbc, 0xfd, 0x66, 0xb7, 0xe5, 0x12, 0xf4, 0x9b, 0x00, 0xe1, 0xc2, 0xb5, 0x47,
0x01, 0x8b, 0xca, 0x5a, 0x0a, 0x39, 0x47, 0x01, 0xb3, 0x7e, 0x37, 0xa0, 0xfc, 0x92, 0x9c, 0x8d,
0xe2, 0xd5, 0x56, 0x83, 0xac, 0x60, 0xfd, 0x68, 0xac, 0xd4, 0x51, 0x2d, 0x3b, 0xc9, 0x06, 0x54,
0x48, 0x32, 0x18, 0x6a, 0xfd, 0x1c, 0x9e, 0x30, 0x94, 0x51, 0xe9, 0x0f, 0x99, 0xa3, 0xf3, 0x57,
0xc1, 0x21, 0xa1, 0x1f, 0x8d, 0x64, 0xec, 0xf9, 0x24, 0x6e, 0x88, 0x98, 0x0c, 0xbf, 0xb8, 0x2e,
0xe3, 0xfd, 0x28, 0x77, 0x31, 0xa9, 0xae, 0x8a, 0x53, 0x22, 0x4e, 0xcd, 0x15, 0xcd, 0xd6, 0x67,
0x64, 0x41, 0x45, 0x9e, 0xb2, 0xc0, 0x7d, 0x4e, 0x02, 0x95, 0x07, 0xb3, 0x10, 0x2e, 0xe3, 0x34,
0xcf, 0xfa, 0x11, 0xb6, 0x52, 0x01, 0xc4, 0x69, 0xa1, 0x92, 0xb8, 0x44, 0x12, 0x65, 0xef, 0x9c,
0x06, 0x22, 0xbe, 0x2a, 0xaa, 0x38, 0x26, 0x95, 0xbd, 0x93, 0xc0, 0x1f, 0x44, 0x21, 0xe9, 0x33,
0x5a, 0x85, 0x8c, 0xf4, 0x75, 0x28, 0x39, 0x9c, 0x91, 0xbe, 0xb2, 0xef, 0xf8, 0x5c, 0x52, 0x2e,
0x7b, 0x3a, 0xc8, 0x5c, 0x3d, 0xbb, 0x53, 0xc1, 0x53, 0x3c, 0xf5, 0xf4, 0x47, 0xf3, 0x0e, 0x5c,
0x60, 0xf8, 0x11, 0x14, 0x07, 0x91, 0x7b, 0x51, 0xcb, 0xa6, 0x96, 0xd2, 0xf2, 0x50, 0x70, 0xa2,
0x85, 0xee, 0x29, 0x04, 0x2d, 0xa3, 0xde, 0x9a, 0x6a, 0xad, 0xad, 0x2f, 0x44, 0xc0, 0x89, 0x98,
0xf5, 0x87, 0x01, 0xdb, 0xf3, 0xd8, 0x6d, 0xee, 0xd2, 0xef, 0xdf, 0x22, 0x57, 0xef, 0xee, 0xf2,
0x06, 0xac, 0xf8, 0x27, 0x27, 0x82, 0xca, 0x28, 0xbb, 0x11, 0xa5, 0xaa, 0x20, 0xd8, 0x0f, 0x34,
0xfa, 0x37, 0xa5, 0xcf, 0xb3, 0x3d, 0x92, 0x4b, 0x7a, 0xc4, 0xfa, 0xcb, 0x80, 0xcd, 0x25, 0x51,
0xa0, 0x67, 0x50, 0x8c, 0x5e, 0x90, 0xf1, 0xae, 0xbf, 0x7b, 0x91, 0x8f, 0x5a, 0xa9, 0x11, 0x11,
0xd1, 0xda, 0x4f, 0x00, 0xb6, 0x4e, 0xa0, 0x3a, 0xf5, 0x69, 0xc1, 0x16, 0x7d, 0x38, 0xbd, 0x45,
0xef, 0xbc, 0xd1, 0x58, 0x92, 0x95, 0xc9, 0x56, 0x7d, 0x5c, 0x7d, 0x5d, 0x6e, 0xdc, 0xfd, 0x34,
0xd6, 0x3c, 0x5e, 0xd1, 0xa7, 0xfb, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x01, 0x61, 0xde, 0x61,
0xf9, 0x0e, 0x00, 0x00,
0xbd, 0x24, 0xf4, 0xa4, 0x79, 0x72, 0xe9, 0xe6, 0x99, 0x0d, 0x37, 0x3f, 0x1f, 0xee, 0x4d, 0x80,
0x70, 0xc3, 0xd9, 0xa3, 0x80, 0x99, 0x2b, 0x3a, 0xd8, 0x52, 0xc8, 0x39, 0x0a, 0x98, 0x85, 0x61,
0x73, 0x3e, 0xd2, 0x7d, 0x4a, 0xce, 0x97, 0x85, 0x38, 0x6b, 0x32, 0x33, 0x67, 0xd2, 0xfa, 0x06,
0x6e, 0xa7, 0x26, 0x37, 0xbc, 0x1c, 0x67, 0x97, 0xe9, 0x12, 0xf4, 0x69, 0x6f, 0x33, 0xb3, 0xde,
0xfe, 0x6e, 0x40, 0xf9, 0x25, 0x39, 0x1b, 0xc5, 0x9b, 0xaf, 0x06, 0x59, 0xc1, 0xfa, 0xd1, 0xd4,
0xa9, 0xa3, 0xda, 0x85, 0x92, 0x0d, 0xa8, 0x90, 0x64, 0x30, 0xd4, 0xfa, 0x39, 0x3c, 0x61, 0x28,
0xa3, 0xd2, 0x1f, 0x32, 0x47, 0xa7, 0xb7, 0x82, 0x43, 0x42, 0xbf, 0x29, 0xc9, 0xd8, 0xf3, 0x49,
0xdc, 0x2f, 0x31, 0x19, 0x7e, 0x71, 0x5d, 0xc6, 0xfb, 0x51, 0x6a, 0x63, 0x52, 0xdd, 0x24, 0xa7,
0x44, 0x9c, 0xea, 0x84, 0x56, 0xb0, 0x3e, 0x23, 0x0b, 0x2a, 0xf2, 0x94, 0x05, 0xee, 0x73, 0x12,
0xa8, 0x3c, 0x98, 0x85, 0x70, 0x57, 0xa7, 0x79, 0xd6, 0x8f, 0xb0, 0x95, 0x0a, 0x20, 0x4e, 0x0b,
0x95, 0xc4, 0x25, 0x92, 0x28, 0x7b, 0xe7, 0x34, 0x10, 0xf1, 0x4d, 0x52, 0xc5, 0x31, 0xa9, 0xec,
0x9d, 0x04, 0xfe, 0x20, 0x0a, 0x49, 0x9f, 0xd1, 0x2a, 0x64, 0xa4, 0xaf, 0x43, 0xc9, 0xe1, 0x8c,
0xf4, 0x95, 0x7d, 0xc7, 0xe7, 0x92, 0x72, 0xd9, 0xd3, 0x41, 0xe6, 0xea, 0xd9, 0x9d, 0x0a, 0x9e,
0xe2, 0xa9, 0x7f, 0x06, 0x68, 0xde, 0x81, 0x0b, 0x0c, 0x3f, 0x82, 0xe2, 0x20, 0x72, 0x2f, 0xea,
0xe8, 0xd4, 0xce, 0x5a, 0x1e, 0x0a, 0x4e, 0xb4, 0xd0, 0x3d, 0x85, 0xa0, 0x65, 0xd4, 0x53, 0x54,
0x6d, 0xbd, 0xf5, 0x85, 0x08, 0x38, 0x11, 0xb3, 0xfe, 0x30, 0x60, 0x7b, 0x1e, 0xbb, 0xcd, 0x5d,
0xfa, 0xfd, 0x5b, 0xe4, 0xea, 0xdd, 0x5d, 0xde, 0x80, 0x15, 0xff, 0xe4, 0x44, 0x50, 0x19, 0x65,
0x37, 0xa2, 0x54, 0x15, 0x04, 0xfb, 0x81, 0x46, 0x7f, 0xb6, 0xf4, 0x79, 0xb6, 0x47, 0x72, 0x49,
0x8f, 0x58, 0x7f, 0x1a, 0xb0, 0xb9, 0x24, 0x0a, 0xf4, 0x0c, 0x8a, 0xd1, 0x03, 0x33, 0x7e, 0x0a,
0xdc, 0xbd, 0xc8, 0x47, 0xad, 0xd4, 0x88, 0x88, 0xe8, 0x55, 0x90, 0x00, 0x6c, 0x9d, 0x40, 0x75,
0xea, 0xd3, 0x82, 0x25, 0xfb, 0x70, 0x7a, 0xc9, 0xde, 0x79, 0xa3, 0xb1, 0x24, 0x2b, 0x93, 0xa5,
0xfb, 0xb8, 0xfa, 0xba, 0xdc, 0xb8, 0xfb, 0x69, 0xac, 0x79, 0xbc, 0xa2, 0x4f, 0xf7, 0xff, 0x0d,
0x00, 0x00, 0xff, 0xff, 0x03, 0x37, 0x5b, 0x30, 0x18, 0x0f, 0x00, 0x00,
}

View File

@ -99,6 +99,7 @@ message CommunityRequestToJoinResponse {
bool accepted = 3;
bytes grant = 4;
bytes community_id = 5;
string magnet_uri = 6;
}
message CommunityRequestToLeave {