1use itertools::Itertools;
2
3use crate::*;
4
5use std::collections::{HashMap, HashSet};
6use std::convert::TryFrom;
7use std::str::FromStr;
8use bucky_error::{BuckyError, BuckyErrorCode, BuckyResult};
9use crate::protos::standard_objects;
10
11pub enum GroupMemberScope {
12 Admin,
13 Member,
14 All,
15}
16
17#[derive(Clone, Debug, RawEncode, RawDecode)]
18pub enum GroupDescContent {
19 SimpleGroup(SimpleGroupDescContent),
20 Org(OrgDescContent),
21}
22
23impl GroupDescContent {
24 pub fn founder_id(&self) -> &Option<ObjectId> {
25 match self {
26 GroupDescContent::SimpleGroup(desc) => &desc.founder_id,
27 GroupDescContent::Org(desc) => &desc.founder_id,
28 }
29 }
30}
31
32#[derive(Clone, Debug, RawEncode, RawDecode)]
33pub enum GroupBodyContent {
34 SimpleGroup(SimpleGroupBodyContent),
35 Org(OrgBodyContent),
36}
37
38impl DescContent for GroupDescContent {
39 fn obj_type() -> u16 {
40 ObjectTypeCode::Group.into()
41 }
42
43 type OwnerType = SubDescNone;
44 type AreaType = Option<Area>;
45 type AuthorType = SubDescNone;
46 type PublicKeyType = SubDescNone;
47}
48
49impl BodyContent for GroupBodyContent {
50 fn format(&self) -> u8 {
51 OBJECT_CONTENT_CODEC_FORMAT_RAW
52 }
53}
54
55impl GroupBodyContent {
56 pub fn name(&self) -> &Option<String> {
57 &self.common().name
58 }
59
60 pub fn icon(&self) -> &Option<String> {
61 &self.common().icon
62 }
63
64 pub fn description(&self) -> &Option<String> {
65 &self.common().description
66 }
67
68 pub fn members(&self) -> &HashMap<ObjectId, GroupMember> {
69 &self.common().members
70 }
71
72 pub fn members_mut(&mut self) -> &mut HashMap<ObjectId, GroupMember> {
73 &mut self.common_mut().members
74 }
75
76 pub fn ood_list(&self) -> &Vec<DeviceId> {
77 &self.common().ood_list
78 }
79
80 pub fn ood_list_mut(&mut self) -> &mut Vec<DeviceId> {
81 &mut self.common_mut().ood_list
82 }
83
84 pub fn version(&self) -> u64 {
85 self.common().version
86 }
87
88 pub fn prev_shell_id(&self) -> &Option<ObjectId> {
89 &self.common().prev_shell_id
90 }
91
92 fn common(&self) -> &CommonGroupBodyContent {
93 match self {
94 GroupBodyContent::Org(body) => &body.common,
95 GroupBodyContent::SimpleGroup(body) => &body.common,
96 }
97 }
98
99 fn common_mut(&mut self) -> &mut CommonGroupBodyContent {
100 match self {
101 GroupBodyContent::Org(body) => &mut body.common,
102 GroupBodyContent::SimpleGroup(body) => &mut body.common,
103 }
104 }
105}
106
107pub type GroupType = NamedObjType<GroupDescContent, GroupBodyContent>;
108pub type GroupBuilder = NamedObjectBuilder<GroupDescContent, GroupBodyContent>;
109
110pub type GroupDesc = NamedObjectDesc<GroupDescContent>;
111pub type GroupId = NamedObjectId<GroupType>;
112pub type Group = NamedObjectBase<GroupType>;
113
114impl GroupDesc {
115 pub fn group_id(&self) -> GroupId {
116 GroupId::try_from(self.calculate_id()).unwrap()
117 }
118}
119
120impl Group {
121 pub fn new_simple_group(
122 founder_id: Option<ObjectId>,
123 admins: Vec<GroupMember>,
124 area: Area,
125 ) -> GroupBuilder {
126 let desc_content = SimpleGroupDescContent {
127 unique_id: UniqueId::create_with_random(),
128 admins: HashMap::from_iter(admins.into_iter().map(|m| (m.id, m))),
129 founder_id,
130 };
131
132 let body_content = SimpleGroupBodyContent::default();
133
134 GroupBuilder::new(
135 GroupDescContent::SimpleGroup(desc_content),
136 GroupBodyContent::SimpleGroup(body_content),
137 )
138 .area(area)
139 }
140
141 pub fn new_org(founder_id: Option<ObjectId>, area: Area) -> GroupBuilder {
142 let desc_content = OrgDescContent {
143 founder_id,
144 unique_id: UniqueId::create_with_random(),
145 };
146
147 let body_content = OrgBodyContent::default();
148
149 GroupBuilder::new(
150 GroupDescContent::Org(desc_content),
151 GroupBodyContent::Org(body_content),
152 )
153 .area(area)
154 }
155
156 pub fn founder_id(&self) -> &Option<ObjectId> {
157 match self.desc().content() {
158 GroupDescContent::SimpleGroup(s) => &s.founder_id,
159 GroupDescContent::Org(o) => &o.founder_id,
160 }
161 }
162
163 pub fn name(&self) -> &Option<String> {
164 &self.common().name
165 }
166
167 pub fn set_name(&mut self, name: Option<String>) {
168 self.common_mut().name = name;
169 }
170
171 pub fn icon(&self) -> &Option<String> {
172 &self.common().icon
173 }
174
175 pub fn set_icon(&mut self, icon: Option<String>) {
176 self.common_mut().icon = icon;
177 }
178
179 pub fn description(&self) -> &Option<String> {
180 &self.common().description
181 }
182
183 pub fn set_description(&mut self, description: Option<String>) {
184 self.common_mut().description = description;
185 }
186
187 pub fn admins(&self) -> &HashMap<ObjectId, GroupMember> {
188 if self.is_org() {
189 &self.check_org_body_content().admins
190 } else {
191 &self.check_simple_group_desc_content().admins
192 }
193 }
194
195 pub fn members(&self) -> &HashMap<ObjectId, GroupMember> {
196 &self.common().members
197 }
198
199 pub fn set_members(&mut self, members: Vec<GroupMember>) {
200 self.common_mut().members = HashMap::from_iter(members.into_iter().map(|m| (m.id, m)));
201 }
202
203 pub fn ood_list(&self) -> &Vec<DeviceId> {
204 &self.common().ood_list
205 }
206
207 pub fn set_ood_list(&mut self, oods: Vec<DeviceId>) {
208 self.common_mut().ood_list = HashSet::<DeviceId>::from_iter(oods.into_iter())
209 .into_iter()
210 .sorted()
211 .collect();
212 }
213
214 pub fn contain_ood(&self, ood_id: &ObjectId) -> bool {
215 match DeviceId::try_from(ood_id) {
216 Ok(device_id) => self.ood_list().contains(&device_id),
217 Err(_) => false,
218 }
219 }
220
221 pub fn is_same_ood_list(&self, other: &Group) -> bool {
222 let my_oods = self.ood_list();
223 let other_oods = other.ood_list();
224
225 if my_oods.len() != other_oods.len() {
226 return false;
227 }
228
229 for id in my_oods {
230 if !other_oods.contains(id) {
231 return false;
232 }
233 }
234
235 true
236 }
237
238 pub fn version(&self) -> u64 {
239 self.common().version
240 }
241
242 pub fn set_version(&mut self, version: u64) {
243 self.common_mut().version = version;
244 }
245
246 pub fn prev_shell_id(&self) -> &Option<ObjectId> {
247 &self.common().prev_shell_id
248 }
249
250 pub fn set_prev_shell_id(&mut self, prev_shell_id: Option<ObjectId>) {
251 self.common_mut().prev_shell_id = prev_shell_id;
252 }
253
254 pub fn is_simple_group(&self) -> bool {
255 match self.desc().content() {
256 GroupDescContent::SimpleGroup(_) => true,
257 _ => false,
258 }
259 }
260
261 pub fn is_org(&self) -> bool {
262 match self.desc().content() {
263 GroupDescContent::Org(_) => true,
264 _ => false,
265 }
266 }
267
268 pub fn check_simple_group_desc_content(&self) -> &SimpleGroupDescContent {
269 match self.desc().content() {
270 GroupDescContent::SimpleGroup(desc) => desc,
271 _ => panic!("group type not match, expect: simple"),
272 }
273 }
274
275 pub fn check_org_desc_content(&self) -> &OrgDescContent {
276 match self.desc().content() {
277 GroupDescContent::Org(desc) => desc,
278 _ => panic!("group type not match, expect: org"),
279 }
280 }
281
282 pub fn check_simple_group_body_content(&self) -> &SimpleGroupBodyContent {
283 match self.body().as_ref().unwrap().content() {
284 GroupBodyContent::SimpleGroup(body) => body,
285 _ => panic!("group type not match, expect: simple"),
286 }
287 }
288
289 pub fn check_org_body_content(&self) -> &OrgBodyContent {
290 match self.body().as_ref().unwrap().content() {
291 GroupBodyContent::Org(body) => body,
292 _ => panic!("group type not match, expect: org"),
293 }
294 }
295
296 pub fn check_simple_group_body_content_mut(&mut self) -> &mut SimpleGroupBodyContent {
297 match self.body_mut().as_mut().unwrap().content_mut() {
298 GroupBodyContent::SimpleGroup(body) => body,
299 _ => panic!("group type not match, expect: simple"),
300 }
301 }
302
303 pub fn check_org_body_content_mut(&mut self) -> &mut OrgBodyContent {
304 match self.body_mut().as_mut().unwrap().content_mut() {
305 GroupBodyContent::Org(body) => body,
306 _ => panic!("group type not match, expect: org"),
307 }
308 }
309
310 pub fn select_members_with_distance(
311 &self,
312 target: &ObjectId,
313 scope: GroupMemberScope,
314 ) -> Vec<&ObjectId> {
315 let mut members = match scope {
316 GroupMemberScope::Admin => self.admins().keys().collect::<Vec<_>>(),
317 GroupMemberScope::Member => self.members().keys().collect::<Vec<_>>(),
318 GroupMemberScope::All => [
319 self.admins().keys().collect::<Vec<_>>(),
320 self.members().keys().collect::<Vec<_>>(),
321 ]
322 .concat(),
323 };
324
325 members.sort_unstable_by(|l, r| {
326 let dl = l.distance_of(target);
327 let dr = r.distance_of(target);
328 dl.cmp(&dr)
329 });
330 members
331 }
332
333 pub fn ood_list_with_distance(&self, target: &ObjectId) -> Vec<&ObjectId> {
334 let oods = self
335 .ood_list()
336 .iter()
337 .map(|id| id.object_id())
338 .sorted_unstable_by(|l, r| {
339 let dl = l.distance_of(target);
340 let dr = r.distance_of(target);
341 dl.cmp(&dr)
342 })
343 .collect::<Vec<_>>();
344 oods
345 }
346
347 fn common(&self) -> &CommonGroupBodyContent {
348 self.body().as_ref().unwrap().content().common()
349 }
350
351 fn common_mut(&mut self) -> &mut CommonGroupBodyContent {
352 self.body_mut().as_mut().unwrap().content_mut().common_mut()
353 }
354}
355
356#[derive(Clone, Debug)]
357pub struct GroupMember {
358 pub id: ObjectId,
359 pub title: String,
360}
361
362impl GroupMember {
363 pub fn new(id: ObjectId, title: String) -> Self {
364 GroupMember { id, title }
365 }
366 pub fn from_member_id(id: ObjectId) -> GroupMember {
367 GroupMember {
368 id,
369 title: "".to_string(),
370 }
371 }
372}
373
374impl TryFrom<protos::GroupMember> for GroupMember {
375 type Error = BuckyError;
376
377 fn try_from(value: protos::GroupMember) -> BuckyResult<Self> {
378 let ret = Self {
379 id: ProtobufCodecHelper::decode_buf(value.id)?,
380 title: value.title,
381 };
382
383 Ok(ret)
384 }
385}
386
387impl TryFrom<&GroupMember> for protos::GroupMember {
388 type Error = BuckyError;
389
390 fn try_from(value: &GroupMember) -> BuckyResult<Self> {
391 let mut ret = Self::new();
392
393 ret.id = value.id.to_vec()?;
394 ret.title = value.title.clone();
395
396 Ok(ret)
397 }
398}
399
400impl FromStr for GroupMember {
401 type Err = BuckyError;
402
403 fn from_str(s: &str) -> Result<Self, Self::Err> {
404 let mut fields = s.split(":");
405
406 let id = if let Some(id) = fields.next() {
407 PeopleId::from_str(id)?
408 } else {
409 return Err(BuckyError::new(
410 BuckyErrorCode::InvalidFormat,
411 "need peopleid of member.",
412 ));
413 };
414
415 let title = fields.next().unwrap_or("");
416
417 Ok(Self {
418 id: id.object_id().clone(),
419 title: title.to_string(),
420 })
421 }
422}
423
424impl ToString for &GroupMember {
425 fn to_string(&self) -> String {
426 format!("{}:{}", self.id, self.title)
427 }
428}
429
430#[derive(Clone, Debug, Default)]
431struct CommonGroupBodyContent {
432 name: Option<String>,
433 icon: Option<String>,
434 description: Option<String>,
435
436 members: HashMap<ObjectId, GroupMember>,
437
438 ood_list: Vec<DeviceId>,
439
440 version: u64,
441 prev_shell_id: Option<ObjectId>,
442}
443
444impl CommonGroupBodyContent {
445 fn new(
446 name: Option<String>,
447 icon: Option<String>,
448 description: Option<String>,
449 members: Vec<GroupMember>,
450 ood_list: Vec<DeviceId>,
451 ) -> Self {
452 Self {
453 name,
454 icon,
455 description,
456 members: HashMap::from_iter(members.into_iter().map(|m| (m.id, m))),
457 ood_list: HashSet::<DeviceId>::from_iter(ood_list.into_iter())
458 .into_iter()
459 .sorted()
460 .collect::<Vec<_>>(),
461 version: 0,
462 prev_shell_id: None,
463 }
464 }
465}
466
467impl TryFrom<protos::CommonGroupBodyContent> for CommonGroupBodyContent {
468 type Error = BuckyError;
469
470 fn try_from(mut value: protos::CommonGroupBodyContent) -> BuckyResult<Self> {
471 let mut ood_list = ProtobufCodecHelper::decode_buf_list(value.take_ood_list())?;
472 ood_list.sort();
473
474 let ret = Self {
475 name: if value.has_name() {
476 Some(value.take_name())
477 } else {
478 None
479 },
480 icon: if value.has_icon() {
481 Some(value.take_icon())
482 } else {
483 None
484 },
485 description: if value.has_description() {
486 Some(value.take_description())
487 } else {
488 None
489 },
490 members:
491 HashMap::from_iter(
492 ProtobufCodecHelper::decode_value_list::<
493 GroupMember,
494 standard_objects::GroupMember,
495 >(value.take_members())?
496 .into_iter()
497 .map(|m| (m.id, m)),
498 ),
499 ood_list,
500 version: value.version,
501 prev_shell_id: if value.has_prev_shell_id() {
502 Some(ProtobufCodecHelper::decode_buf(value.take_prev_shell_id())?)
503 } else {
504 None
505 },
506 };
507
508 Ok(ret)
509 }
510}
511
512impl TryFrom<&CommonGroupBodyContent> for protos::CommonGroupBodyContent {
513 type Error = BuckyError;
514
515 fn try_from(value: &CommonGroupBodyContent) -> BuckyResult<Self> {
516 let mut ret = Self::new();
517
518 if let Some(name) = value.name.as_ref() {
519 ret.set_name(name.clone());
520 }
521 if let Some(icon) = value.icon.as_ref() {
522 ret.set_icon(icon.clone());
523 }
524 if let Some(description) = value.description.as_ref() {
525 ret.set_description(description.clone());
526 }
527
528 let members = value
529 .members
530 .values()
531 .sorted_by(|l, r| l.id.cmp(&r.id))
532 .map(|m| m.clone())
533 .collect::<Vec<_>>();
534 ret.set_members(ProtobufCodecHelper::encode_nested_list(&members)?);
535
536 let oods = value
537 .ood_list
538 .iter()
539 .sorted()
540 .map(|id| id.clone())
541 .collect::<Vec<_>>();
542 ret.set_ood_list(ProtobufCodecHelper::encode_buf_list(oods.as_slice())?);
543
544 ret.version = value.version;
545 if let Some(prev_shell_id) = &value.prev_shell_id {
546 ret.set_prev_shell_id(prev_shell_id.to_vec()?);
547 }
548
549 Ok(ret)
550 }
551}
552
553#[derive(Clone, Debug)]
554pub struct SimpleGroupDescContent {
555 unique_id: UniqueId,
556 founder_id: Option<ObjectId>,
557 admins: HashMap<ObjectId, GroupMember>,
558}
559
560impl SimpleGroupDescContent {
561 pub fn admins(&self) -> &HashMap<ObjectId, GroupMember> {
562 &self.admins
563 }
564}
565
566impl TryFrom<protos::SimpleGroupDescContent> for SimpleGroupDescContent {
567 type Error = BuckyError;
568
569 fn try_from(mut value: protos::SimpleGroupDescContent) -> BuckyResult<Self> {
570 let ret = Self {
571 founder_id: if value.has_founder_id() {
572 ProtobufCodecHelper::decode_buf(value.take_founder_id())?
573 } else {
574 None
575 },
576 unique_id: ProtobufCodecHelper::decode_buf(value.unique_id)?,
577 admins:
578 HashMap::from_iter(
579 ProtobufCodecHelper::decode_value_list::<
580 GroupMember,
581 standard_objects::GroupMember,
582 >(value.admins)?
583 .into_iter()
584 .map(|m| (m.id, m)),
585 ),
586 };
587
588 Ok(ret)
589 }
590}
591
592impl TryFrom<&SimpleGroupDescContent> for protos::SimpleGroupDescContent {
593 type Error = BuckyError;
594
595 fn try_from(value: &SimpleGroupDescContent) -> BuckyResult<Self> {
596 let mut ret = Self::new();
597
598 ret.unique_id = value.unique_id.to_vec()?;
599 if let Some(founder_id) = value.founder_id.as_ref() {
600 ret.set_founder_id(founder_id.to_vec()?);
601 }
602
603 let admins = value
604 .admins
605 .values()
606 .sorted_by(|l, r| l.id.cmp(&r.id))
607 .map(|m| m.clone())
608 .collect::<Vec<_>>();
609 ret.set_admins(ProtobufCodecHelper::encode_nested_list(&admins)?);
610
611 Ok(ret)
612 }
613}
614
615#[derive(Clone, Debug, Default)]
616pub struct SimpleGroupBodyContent {
617 common: CommonGroupBodyContent,
618}
619
620impl SimpleGroupBodyContent {
621 fn new(
622 name: Option<String>,
623 icon: Option<String>,
624 description: Option<String>,
625 members: Vec<GroupMember>,
626 ood_list: Vec<DeviceId>,
627 ) -> Self {
628 Self {
629 common: CommonGroupBodyContent::new(name, icon, description, members, ood_list),
630 }
631 }
632}
633
634impl TryFrom<protos::SimpleGroupBodyContent> for SimpleGroupBodyContent {
635 type Error = BuckyError;
636
637 fn try_from(mut value: protos::SimpleGroupBodyContent) -> BuckyResult<Self> {
638 let ret = Self {
639 common: ProtobufCodecHelper::decode_value(value.take_common())?,
640 };
641
642 Ok(ret)
643 }
644}
645
646impl TryFrom<&SimpleGroupBodyContent> for protos::SimpleGroupBodyContent {
647 type Error = BuckyError;
648
649 fn try_from(value: &SimpleGroupBodyContent) -> BuckyResult<Self> {
650 let mut ret = Self::new();
651
652 ret.set_common(ProtobufCodecHelper::encode_nested_item(&value.common)?);
653
654 Ok(ret)
655 }
656}
657
658#[derive(Clone, Debug)]
659pub struct OrgDescContent {
660 unique_id: UniqueId,
661 founder_id: Option<ObjectId>,
662}
663
664impl TryFrom<protos::OrgDescContent> for OrgDescContent {
665 type Error = BuckyError;
666
667 fn try_from(mut value: protos::OrgDescContent) -> BuckyResult<Self> {
668 let ret = Self {
669 founder_id: if value.has_founder_id() {
670 Some(ProtobufCodecHelper::decode_buf(value.take_founder_id())?)
671 } else {
672 None
673 },
674 unique_id: ProtobufCodecHelper::decode_buf(value.unique_id)?,
675 };
676
677 Ok(ret)
678 }
679}
680
681impl TryFrom<&OrgDescContent> for protos::OrgDescContent {
682 type Error = BuckyError;
683
684 fn try_from(value: &OrgDescContent) -> BuckyResult<Self> {
685 let mut ret = Self::new();
686
687 ret.unique_id = value.unique_id.to_vec()?;
688 if let Some(founder_id) = value.founder_id.as_ref() {
689 ret.set_founder_id(founder_id.to_vec()?);
690 }
691
692 Ok(ret)
693 }
694}
695
696#[derive(Clone, Debug, Default)]
697pub struct OrgBodyContent {
698 admins: HashMap<ObjectId, GroupMember>,
699 common: CommonGroupBodyContent,
700}
701
702impl OrgBodyContent {
703 fn new(
704 name: Option<String>,
705 icon: Option<String>,
706 description: Option<String>,
707 admins: Vec<GroupMember>,
708 members: Vec<GroupMember>,
709 ood_list: Vec<DeviceId>,
710 ) -> Self {
711 Self {
712 common: CommonGroupBodyContent::new(name, icon, description, members, ood_list),
713 admins: HashMap::from_iter(admins.into_iter().map(|m| (m.id, m))),
714 }
715 }
716
717 pub fn admins(&self) -> &HashMap<ObjectId, GroupMember> {
718 &self.admins
719 }
720
721 pub fn set_admins(&mut self, admins: Vec<GroupMember>) {
722 self.admins = HashMap::from_iter(admins.into_iter().map(|m| (m.id, m)));
723 }
724}
725
726impl TryFrom<protos::OrgBodyContent> for OrgBodyContent {
727 type Error = BuckyError;
728
729 fn try_from(mut value: protos::OrgBodyContent) -> BuckyResult<Self> {
730 let ret = Self {
731 admins:
732 HashMap::from_iter(
733 ProtobufCodecHelper::decode_value_list::<
734 GroupMember,
735 standard_objects::GroupMember,
736 >(value.take_admins())?
737 .into_iter()
738 .map(|m| (m.id, m)),
739 ),
740 common: ProtobufCodecHelper::decode_value(value.take_common())?,
741 };
742
743 Ok(ret)
744 }
745}
746
747impl TryFrom<&OrgBodyContent> for protos::OrgBodyContent {
748 type Error = BuckyError;
749
750 fn try_from(value: &OrgBodyContent) -> BuckyResult<Self> {
751 let mut ret = Self::new();
752
753 let admins = value
754 .admins
755 .values()
756 .sorted_by(|l, r| l.id.cmp(&r.id))
757 .map(|m| m.clone())
758 .collect::<Vec<_>>();
759
760 ret.set_admins(ProtobufCodecHelper::encode_nested_list(&admins)?);
761 ret.set_common(ProtobufCodecHelper::encode_nested_item(&value.common)?);
762
763 Ok(ret)
764 }
765}
766
767crate::inner_impl_default_protobuf_raw_codec!(SimpleGroupDescContent);
768crate::inner_impl_default_protobuf_raw_codec!(SimpleGroupBodyContent);
769
770crate::inner_impl_default_protobuf_raw_codec!(OrgDescContent);
771crate::inner_impl_default_protobuf_raw_codec!(OrgBodyContent);
772
773#[cfg(test)]
774mod test {
775 use crate::*;
776
777 #[test]
778 fn simple_group() {
779 }
805}