adlt/plugins/
plugin.rs

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
78
79
80
81
82
83
84
85
86
87
use std::{
    any::Any,
    fmt,
    sync::{Arc, RwLock},
};

use crate::dlt::DltMessage;

pub trait Plugin {
    fn name(&self) -> &str;
    fn enabled(&self) -> bool;

    fn state(&self) -> Arc<RwLock<PluginState>>;

    /// process a single msg
    /// this can modify the msg (and is expected for most plugins)
    ///
    /// a plugin can modify e.g.
    /// - msg.timestamp_dms
    /// - msg.reception_time_us
    /// - payload: msg.set_payload_text(...)
    ///
    /// returns false if the msg should be droppped (i.e. not forwarded) and true in all other cases
    fn process_msg(&mut self, msg: &mut DltMessage) -> bool;
}

impl fmt::Debug for dyn Plugin + Send {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Plugin")
            .field("name", &self.name())
            .field("enabled", &self.enabled())
            .finish()
    }
}

type ApplyCommandFn = fn(
    internal_data: &Option<Box<dyn Any + Send + Sync>>,
    cmd: &str,
    params: Option<&serde_json::Map<String, serde_json::Value>>,
    cmdCtx: Option<&serde_json::Map<String, serde_json::Value>>,
) -> bool;

/// status/state from a plugin. Can be updated and be shared across threads
///
/// The state consists of a json object (value) with at least the members:
/// - name: <name of the plugin>
/// optional:
/// - treeItems: Array of objects with
///  - label:String
///  - children -> json objects with similar structure
///  optional members:
///  - tooltip:String
///  - description:String
///  - iconPath:String (see https://code.visualstudio.com/api/references/icons-in-labels#icon-listing)
///  to ease presentation in a treeview (https://code.visualstudio.com/api/references/vscode-api#TreeItem)
///
/// Two other members are used to interact with a plugin:
/// - apply_command : optional fn that will be called e.g. from remote plugin_cmd. Current use-case: FileTransferPlugin "save"
/// - internal_data: optional data that the apply_command function can access.
pub struct PluginState {
    pub generation: u32, // 0 initial, 1 = 1st,...
    pub value: serde_json::Value,
    pub apply_command: Option<ApplyCommandFn>,
    pub internal_data: Option<Box<dyn Any + Send + Sync>>,
}

impl fmt::Debug for PluginState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("PluginState")
            .field("generation", &self.generation)
            .field("value", &self.value)
            .field("apply_command", &self.apply_command.is_some())
            .field("internal_data", &self.internal_data.is_some())
            .finish()
    }
}

impl Default for PluginState {
    fn default() -> Self {
        PluginState {
            generation: 0,
            value: serde_json::Value::Null,
            apply_command: None,
            internal_data: None,
        }
    }
}