esrlabs / chipmunk

log analysis tool
Apache License 2.0
557 stars 39 forks source link

Plugin mechanism for compiled rust code #1984

Open marcmo opened 7 months ago

marcmo commented 7 months ago

we need to be able to link precompiled static libraries.

First example will be the MDF library

DmitryAstafyev commented 7 months ago

Tech Overview

Scripting Sockets Pipes Memory Wasm Dynamic lib (FFI) Static lib
Runtime loading
-1 - no; 1 - yes
1 1 1 1 1
Requires interpreter
or compiler
-1 - requires; 0 - doesn't
-1 0 0 0 0
Performance
estimation
(theoretically)
1 - poor; 5 - best
2 3 3 3 5
Windows
headache
0 - not expected
-1 - probably
0 -1 0 0 0
Possibility avoid cloning
1 - no cloning;
0 - partly;
-1- cloning
-1 -1 -1 1 1
Required rust unsafe
0 - yes;
1 - no;
1 1 1 1 0
Score 2 3 4 x 6 7 x
Disqualification R.0 R.1

R.0. - This feature heavily depends on the system’s kernel, so it may hurt the “Cross-Compatibility” requirement. [1] R.1. - Requires compilation with basic application; no run-time loading

Plugins targets

  1. Source
  2. Parser

Requirements for plugins system

Plugin output files

note: store in the home folder ~/.chipmunk/plugins

Loading

Opened questions

Overview of ByteSource and Parser traits

Motivation to use (try to use) crate [abi_stable](https://github.com/rodrimati1992/abi_stable_crates) is better support of types. But in general would be good to understand, which types we would like to use and if is there a way to stay on the level of primitives.

ByteSource trait

pub trait ByteSource: Send + Sync {
    fn consume(&mut self, offset: usize);
    fn current_slice(&self) -> &[u8];                    <== Key method
    fn len(&self) -> usize;
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
    async fn reload(&mut self, filter: Option<&SourceFilter>) -> Result<Option<ReloadInfo>, Error>;
    async fn cancel(&mut self) -> Result<(), Error> {
        Ok(())
    }
    async fn income(&mut self, _msg: sde::SdeRequest) -> Result<sde::SdeResponse, Error> {
        Err(Error::NotSupported)
    }
}

The key-method is current_slice, which delivers a byte's slice for future processing by a parser. Actually ByteSource plugin can operate with primitive types only.

Conclusion: plugin can operate just with primitive types

Parser trait


#[derive(Debug)]
pub enum ParseYield<T> {
    Message(T),
    Attachment(Attachment),
    MessageAndAttachment((T, Attachment)),
}

pub trait Parser<T> {
    fn parse<'a>(
        &mut self,
        input: &'a [u8],
        timestamp: Option<u64>,
    ) -> Result<(&'a [u8], Option<ParseYield<T>>), Error>;
}

#[derive(Debug, Clone, Serialize)]
pub struct Attachment {
    pub name: String,
    pub size: usize,
    pub created_date: Option<String>,
    pub modified_date: Option<String>,
    /// The indexes of the message within the original trace (0-based).
    pub messages: Vec<usize>,
    pub data: Vec<u8>,
}

Conclusion: plugin can operate just with primitive types in case of implementation our own simple protocol based on header and payload

References/links:

DmitryAstafyev commented 7 months ago

As for the first step we could implement BinaryByteSource (sources/src/binary/raw.rs) as a plugin. For the first prototype:

Goals: