1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use alloc::collections::BTreeMap;
use alloc::fmt::{Display, Error as FmtError, Formatter};

use ibc_relayer_types::core::ics24_host::identifier::ChainId;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use tracing::info;

use crate::{
    object::{Object, ObjectType},
    worker::{WorkerData, WorkerHandle, WorkerId},
};

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct WorkerDesc {
    pub id: WorkerId,
    pub object: Object,
    pub data: Option<WorkerData>,
}

impl WorkerDesc {
    pub fn new(id: WorkerId, object: Object, data: Option<WorkerData>) -> Self {
        Self { id, object, data }
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct SupervisorState {
    pub chains: Vec<ChainId>,
    pub workers: BTreeMap<ObjectType, Vec<WorkerDesc>>,
}

impl SupervisorState {
    pub fn new<'a>(
        mut chains: Vec<ChainId>,
        workers: impl Iterator<Item = &'a WorkerHandle>,
    ) -> Self {
        chains.sort();

        let workers = workers
            .map(|h| WorkerDesc::new(h.id(), h.object().clone(), h.data().cloned()))
            .into_group_map_by(|desc| desc.object.object_type())
            .into_iter()
            .update(|(_, os)| os.sort_by_key(|desc| desc.object.short_name()))
            .collect::<BTreeMap<_, _>>();

        Self { chains, workers }
    }

    pub fn print_info(&self) {
        self.to_string()
            .split('\n')
            .for_each(|line| info!("{}", line));
    }
}

impl Display for SupervisorState {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        writeln!(f)?;
        writeln!(f, "* Chains: {}", self.chains.iter().join(", "))?;
        for (tpe, objects) in &self.workers {
            writeln!(f, "* {tpe:?} workers:")?;
            for desc in objects {
                writeln!(f, "  - {} (id: {})", desc.object.short_name(), desc.id)?;
                if let Some(WorkerData::Client {
                    misbehaviour,
                    refresh,
                }) = desc.data
                {
                    writeln!(f, "    | misbehaviour: {misbehaviour}, refresh: {refresh}")?;
                }
            }
        }

        Ok(())
    }
}