@@ -32,7 +32,10 @@ use rust_ipfs::{Ipfs, PeerId};
32
32
use serde:: { Deserialize , Serialize } ;
33
33
use uuid:: Uuid ;
34
34
35
+ use super :: community:: CommunityInviteDocument ;
36
+ use super :: topics:: ConversationTopic ;
35
37
use super :: { document:: root:: RootDocumentMap , ds_key:: DataStoreKey , PeerIdExt } ;
38
+ use crate :: store:: CommunityJoinEvents ;
36
39
use crate :: store:: {
37
40
conversation:: ConversationDocument ,
38
41
discovery:: Discovery ,
@@ -92,6 +95,7 @@ impl MessageStore {
92
95
ipfs : ipfs. clone ( ) ,
93
96
conversation_task : HashMap :: new ( ) ,
94
97
community_task : HashMap :: new ( ) ,
98
+ community_invites : vec ! [ ] ,
95
99
identity : identity. clone ( ) ,
96
100
root,
97
101
discovery,
@@ -903,8 +907,12 @@ impl MessageStore {
903
907
inner. list_communities_joined ( ) . await
904
908
}
905
909
pub async fn list_communities_invited_to ( & self ) -> Result < Vec < ( Uuid , CommunityInvite ) > , Error > {
906
- let inner = & mut * self . inner . write ( ) . await ;
907
- inner. list_communities_invited_to ( ) . await
910
+ let inner = & * self . inner . read ( ) . await ;
911
+ Ok ( inner
912
+ . community_invites
913
+ . iter ( )
914
+ . map ( |( community_id, i) | ( * community_id, CommunityInvite :: from ( i. clone ( ) ) ) )
915
+ . collect ( ) )
908
916
}
909
917
pub async fn leave_community ( & mut self , community_id : Uuid ) -> Result < ( ) , Error > {
910
918
let inner = & * self . inner . read ( ) . await ;
@@ -1024,20 +1032,38 @@ impl MessageStore {
1024
1032
invite_id : Uuid ,
1025
1033
) -> Result < ( ) , Error > {
1026
1034
let inner = & * self . inner . read ( ) . await ;
1027
- let community_meta = inner
1028
- . community_task
1029
- . get ( & community_id)
1030
- . ok_or ( Error :: InvalidCommunity ) ?;
1031
- let ( tx, rx) = oneshot:: channel ( ) ;
1032
- let _ = community_meta
1033
- . command_tx
1034
- . clone ( )
1035
- . send ( CommunityTaskCommand :: DeleteCommunityInvite {
1036
- invite_id,
1037
- response : tx,
1038
- } )
1039
- . await ;
1040
- rx. await . map_err ( anyhow:: Error :: from) ?
1035
+ match inner. community_task . get ( & community_id) {
1036
+ None => {
1037
+ let keypair = inner. root . keypair ( ) ;
1038
+
1039
+ let event = CommunityJoinEvents :: DeleteInvite { invite_id } ;
1040
+ let payload = PayloadBuilder :: new ( keypair, event)
1041
+ . from_ipfs ( & inner. ipfs )
1042
+ . await ?;
1043
+ let bytes = payload. to_bytes ( ) ?;
1044
+
1045
+ if let Err ( e) = inner
1046
+ . ipfs
1047
+ . pubsub_publish ( community_id. join_topic ( ) , bytes)
1048
+ . await
1049
+ {
1050
+ tracing:: error!( id=%community_id, "Unable to send event: {e}" ) ;
1051
+ }
1052
+ }
1053
+ Some ( community_meta) => {
1054
+ let ( tx, rx) = oneshot:: channel ( ) ;
1055
+ let _ = community_meta
1056
+ . command_tx
1057
+ . clone ( )
1058
+ . send ( CommunityTaskCommand :: DeleteCommunityInvite {
1059
+ invite_id,
1060
+ response : tx,
1061
+ } )
1062
+ . await ;
1063
+ return rx. await . map_err ( anyhow:: Error :: from) ?;
1064
+ }
1065
+ }
1066
+ Ok ( ( ) )
1041
1067
}
1042
1068
pub async fn get_community_invite (
1043
1069
& mut self ,
@@ -1060,26 +1086,24 @@ impl MessageStore {
1060
1086
. await ;
1061
1087
rx. await . map_err ( anyhow:: Error :: from) ?
1062
1088
}
1063
- pub async fn accept_community_invite (
1064
- & mut self ,
1065
- community_id : Uuid ,
1066
- invite_id : Uuid ,
1067
- ) -> Result < ( ) , Error > {
1089
+ pub async fn request_join_community ( & mut self , community_id : Uuid ) -> Result < ( ) , Error > {
1068
1090
let inner = & * self . inner . read ( ) . await ;
1069
- let community_meta = inner
1070
- . community_task
1071
- . get ( & community_id)
1072
- . ok_or ( Error :: InvalidCommunity ) ?;
1073
- let ( tx, rx) = oneshot:: channel ( ) ;
1074
- let _ = community_meta
1075
- . command_tx
1076
- . clone ( )
1077
- . send ( CommunityTaskCommand :: AcceptCommunityInvite {
1078
- invite_id,
1079
- response : tx,
1080
- } )
1081
- . await ;
1082
- rx. await . map_err ( anyhow:: Error :: from) ?
1091
+ let keypair = inner. root . keypair ( ) ;
1092
+
1093
+ let event = CommunityJoinEvents :: Join ;
1094
+ let payload = PayloadBuilder :: new ( keypair, event)
1095
+ . from_ipfs ( & inner. ipfs )
1096
+ . await ?;
1097
+ let bytes = payload. to_bytes ( ) ?;
1098
+
1099
+ if let Err ( e) = inner
1100
+ . ipfs
1101
+ . pubsub_publish ( community_id. join_topic ( ) , bytes)
1102
+ . await
1103
+ {
1104
+ tracing:: error!( id=%community_id, "Unable to send event: {e}" ) ;
1105
+ }
1106
+ Ok ( ( ) )
1083
1107
}
1084
1108
pub async fn edit_community_invite (
1085
1109
& mut self ,
@@ -2105,6 +2129,7 @@ struct ConversationInner {
2105
2129
ipfs : Ipfs ,
2106
2130
conversation_task : HashMap < Uuid , ConversationInnerMeta > ,
2107
2131
community_task : HashMap < Uuid , CommunityInnerMeta > ,
2132
+ community_invites : Vec < ( Uuid , CommunityInviteDocument ) > ,
2108
2133
root : RootDocumentMap ,
2109
2134
file : FileStore ,
2110
2135
event : EventSubscription < RayGunEventKind > ,
@@ -3016,8 +3041,7 @@ impl ConversationInner {
3016
3041
pub async fn get_community ( & mut self , community_id : Uuid ) -> Result < Community , Error > {
3017
3042
let doc = self . get_community_document ( community_id) . await ?;
3018
3043
let own_did = & self . identity . did_key ( ) ;
3019
- if own_did != & doc. owner && !doc. has_valid_invite ( own_did) && !doc. members . contains ( own_did)
3020
- {
3044
+ if !doc. participants ( ) . contains ( own_did) {
3021
3045
return Err ( Error :: Unauthorized ) ;
3022
3046
}
3023
3047
Ok ( doc. into ( ) )
@@ -3038,24 +3062,6 @@ impl ConversationInner {
3038
3062
} )
3039
3063
. collect ( ) )
3040
3064
}
3041
- pub async fn list_communities_invited_to ( & self ) -> Result < Vec < ( Uuid , CommunityInvite ) > , Error > {
3042
- let own_did = & self . identity . did_key ( ) ;
3043
- Ok ( self
3044
- . list_community ( )
3045
- . await
3046
- . iter ( )
3047
- . filter_map ( |c| {
3048
- for ( _, invite) in & c. invites {
3049
- if let Some ( target) = & invite. target_user {
3050
- if target == own_did {
3051
- return Some ( ( c. id , CommunityInvite :: from ( invite. clone ( ) ) ) ) ;
3052
- }
3053
- }
3054
- }
3055
- None
3056
- } )
3057
- . collect ( ) )
3058
- }
3059
3065
}
3060
3066
3061
3067
async fn process_conversation (
@@ -3196,30 +3202,18 @@ async fn process_conversation(
3196
3202
ConversationEvents :: NewCommunityInvite {
3197
3203
community_id,
3198
3204
invite,
3199
- community_document,
3200
3205
} => {
3201
- let did = this. identity . did_key ( ) ;
3202
-
3203
- if this. contains_community ( community_id) . await {
3204
- return Err ( anyhow:: anyhow!( "Already apart of {community_id}" ) . into ( ) ) ;
3205
- }
3206
-
3207
- let recipients = community_document. participants ( ) . clone ( ) ;
3208
-
3209
- for recipient in & recipients {
3210
- if !this. discovery . contains ( recipient) . await {
3211
- let _ = this. discovery . insert ( recipient) . await ;
3206
+ let mut updated = false ;
3207
+ for i in this. community_invites . len ( ) ..0 {
3208
+ let ( community, invitation) = this. community_invites [ i] . clone ( ) ;
3209
+ if community == community_id && invitation. id == invite. id {
3210
+ this. community_invites [ i] = ( community_id, invite. clone ( ) ) ;
3211
+ updated = true ;
3212
+ break ;
3212
3213
}
3213
3214
}
3214
-
3215
- this. set_community_document ( community_document) . await ?;
3216
-
3217
- this. create_community_task ( community_id) . await ?;
3218
-
3219
- for recipient in recipients. iter ( ) . filter ( |d| did. ne ( d) ) {
3220
- if let Err ( e) = this. request_community_key ( community_id, recipient) . await {
3221
- tracing:: warn!( %community_id, error = %e, %recipient, "Failed to send exchange request" ) ;
3222
- }
3215
+ if !updated {
3216
+ this. community_invites . push ( ( community_id, invite. clone ( ) ) ) ;
3223
3217
}
3224
3218
3225
3219
this. event
@@ -3229,6 +3223,83 @@ async fn process_conversation(
3229
3223
} )
3230
3224
. await ;
3231
3225
}
3226
+ ConversationEvents :: DeleteCommunityInvite {
3227
+ community_id,
3228
+ invite,
3229
+ } => {
3230
+ for i in this. community_invites . len ( ) ..0 {
3231
+ let ( community, invitation) = this. community_invites [ i] . clone ( ) ;
3232
+ if community == community_id && invitation. id == invite. id {
3233
+ this. community_invites . swap_remove ( i) ;
3234
+ this. event
3235
+ . emit ( RayGunEventKind :: CommunityUninvited {
3236
+ community_id,
3237
+ invite_id : invite. id ,
3238
+ } )
3239
+ . await ;
3240
+ break ;
3241
+ }
3242
+ }
3243
+ }
3244
+ ConversationEvents :: JoinCommunity {
3245
+ community_id,
3246
+ community_document : result,
3247
+ } => match result {
3248
+ None => {
3249
+ this. event
3250
+ . emit ( RayGunEventKind :: CommunityJoinRejected { community_id } )
3251
+ . await ;
3252
+ return Ok ( ( ) ) ;
3253
+ }
3254
+ Some ( community_document) => {
3255
+ for i in this. community_invites . len ( ) ..0 {
3256
+ let ( community, _) = this. community_invites [ i] ;
3257
+ if community == community_id {
3258
+ this. community_invites . swap_remove ( i) ;
3259
+ }
3260
+ }
3261
+
3262
+ let did = this. identity . did_key ( ) ;
3263
+
3264
+ if this. contains_community ( community_id) . await {
3265
+ return Ok ( ( ) ) ;
3266
+ }
3267
+
3268
+ let recipients = community_document. participants ( ) . clone ( ) ;
3269
+
3270
+ for recipient in & recipients {
3271
+ if !this. discovery . contains ( recipient) . await {
3272
+ let _ = this. discovery . insert ( recipient) . await ;
3273
+ }
3274
+ }
3275
+
3276
+ this. set_community_document ( community_document) . await ?;
3277
+
3278
+ this. create_community_task ( community_id) . await ?;
3279
+
3280
+ for recipient in recipients. iter ( ) . filter ( |d| did. ne ( d) ) {
3281
+ if let Err ( e) = this. request_community_key ( community_id, recipient) . await {
3282
+ tracing:: warn!( %community_id, error = %e, %recipient, "Failed to send exchange request" ) ;
3283
+ }
3284
+ }
3285
+
3286
+ let community_meta = this
3287
+ . community_task
3288
+ . get ( & community_id)
3289
+ . ok_or ( Error :: InvalidCommunity ) ?;
3290
+ let ( tx, rx) = oneshot:: channel ( ) ;
3291
+ let _ = community_meta
3292
+ . command_tx
3293
+ . clone ( )
3294
+ . send ( CommunityTaskCommand :: SendJoinedCommunityEvent { response : tx } )
3295
+ . await ;
3296
+ let _ = rx. await . map_err ( anyhow:: Error :: from) ?;
3297
+
3298
+ this. event
3299
+ . emit ( RayGunEventKind :: CommunityJoined { community_id } )
3300
+ . await ;
3301
+ }
3302
+ } ,
3232
3303
ConversationEvents :: DeleteCommunity { community_id } => {
3233
3304
tracing:: trace!( "Delete community event received for {community_id}" ) ;
3234
3305
if !this. contains_community ( community_id) . await {
0 commit comments