File size: 4,810 Bytes
3374e90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/// Event kinds for the BEX async callback system.
///
/// Each kind corresponds to a specific result type from the plugin API.
/// The C++ backend uses these to dispatch events to the appropriate UI handler.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BexEventKind {
    InstallResult,
    UninstallResult,
    HomeResult,
    CategoryResult,
    SearchResult,
    InfoResult,
    ServersResult,
    StreamResult,
    SubtitleSearchResult,
    SubtitleDownloadResult,
    ArticleResult,
    Log,
    Progress,
    Error,
    Cancelled,
}

impl BexEventKind {
    /// Convert to the integer tag used in the C ABI callback.
    /// Must stay in sync with the C++ side enum.
    pub fn to_tag(self) -> u8 {
        match self {
            Self::InstallResult => 0,
            Self::UninstallResult => 1,
            Self::HomeResult => 2,
            Self::CategoryResult => 3,
            Self::SearchResult => 4,
            Self::InfoResult => 5,
            Self::ServersResult => 6,
            Self::StreamResult => 7,
            Self::SubtitleSearchResult => 8,
            Self::SubtitleDownloadResult => 9,
            Self::ArticleResult => 10,
            Self::Log => 11,
            Self::Progress => 12,
            Self::Error => 13,
            Self::Cancelled => 14,
        }
    }
}

/// Payload format indicator.
///
/// Tells the C++ consumer how to interpret the payload bytes.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BexPayloadFormat {
    /// No payload (e.g., for Log/Progress events that carry data in fields).
    None,
    /// FlatBuffer binary — zero-copy deserialization on C++ side.
    FlatBuffer,
    /// JSON string — used for debug/CLI mode.
    JsonDebug,
    /// Opaque binary blob.
    Binary,
}

/// Internal event representation.
///
/// Produced by the runtime for each completed request. The C++ backend
/// drains these via `bex_drain_events()` and dispatches them to the UI.
#[derive(Debug, Clone)]
pub struct BexEvent {
    /// Monotonically increasing request ID (matches the ID returned by submit_*)
    pub request_id: u64,
    /// Monotonically increasing sequence number for ordering
    pub seq: u64,
    /// What kind of result this event carries
    pub kind: BexEventKind,
    /// Whether the operation succeeded
    pub ok: bool,
    /// Which plugin produced this event
    pub plugin_id: String,
    /// How to interpret the payload bytes
    pub payload_format: BexPayloadFormat,
    /// The actual result payload (FlatBuffer, JSON, or binary)
    pub payload: Vec<u8>,
    /// Machine-readable error code (empty if ok)
    pub error_code: String,
    /// Human-readable error message (empty if ok)
    pub error_message: String,
}

impl BexEvent {
    /// Create a success event with a FlatBuffer payload.
    pub fn success(
        request_id: u64,
        seq: u64,
        kind: BexEventKind,
        plugin_id: String,
        payload: Vec<u8>,
    ) -> Self {
        Self {
            request_id,
            seq,
            kind,
            ok: true,
            plugin_id,
            payload_format: BexPayloadFormat::FlatBuffer,
            payload,
            error_code: String::new(),
            error_message: String::new(),
        }
    }

    /// Create a success event with a JSON payload (for debug/CLI).
    pub fn success_json(
        request_id: u64,
        seq: u64,
        kind: BexEventKind,
        plugin_id: String,
        json: String,
    ) -> Self {
        Self {
            request_id,
            seq,
            kind,
            ok: true,
            plugin_id,
            payload_format: BexPayloadFormat::JsonDebug,
            payload: json.into_bytes(),
            error_code: String::new(),
            error_message: String::new(),
        }
    }

    /// Create an error event.
    pub fn error(
        request_id: u64,
        seq: u64,
        kind: BexEventKind,
        plugin_id: String,
        error_code: &str,
        error_message: &str,
    ) -> Self {
        Self {
            request_id,
            seq,
            kind,
            ok: false,
            plugin_id,
            payload_format: BexPayloadFormat::None,
            payload: Vec::new(),
            error_code: error_code.to_string(),
            error_message: error_message.to_string(),
        }
    }

    /// Create a cancellation event.
    pub fn cancelled(request_id: u64, seq: u64, plugin_id: String) -> Self {
        Self {
            request_id,
            seq,
            kind: BexEventKind::Cancelled,
            ok: false,
            plugin_id,
            payload_format: BexPayloadFormat::None,
            payload: Vec::new(),
            error_code: "CANCELLED".to_string(),
            error_message: "Request was cancelled".to_string(),
        }
    }
}