use anyhow::Result;
use solana_sdk::instruction::Instruction;
pub trait InstructionMiddleware: Send + Sync {
fn name(&self) -> &'static str;
fn process_protocol_instructions(
&self,
protocol_instructions: Vec<Instruction>,
protocol_name: &str,
is_buy: bool,
) -> Result<Vec<Instruction>>;
fn process_full_instructions(
&self,
full_instructions: Vec<Instruction>,
protocol_name: &str,
is_buy: bool,
) -> Result<Vec<Instruction>>;
fn clone_box(&self) -> Box<dyn InstructionMiddleware>;
}
pub struct MiddlewareManager {
middlewares: Vec<Box<dyn InstructionMiddleware>>,
}
impl Clone for MiddlewareManager {
fn clone(&self) -> Self {
Self {
middlewares: self.middlewares.iter().map(|middleware| middleware.clone_box()).collect(),
}
}
}
impl MiddlewareManager {
pub fn new() -> Self {
Self { middlewares: Vec::new() }
}
pub fn add_middleware(mut self, middleware: Box<dyn InstructionMiddleware>) -> Self {
self.middlewares.push(middleware);
self
}
pub fn apply_middlewares_process_full_instructions(
&self,
mut full_instructions: Vec<Instruction>,
protocol_name: &str,
is_buy: bool,
) -> Result<Vec<Instruction>> {
for middleware in &self.middlewares {
full_instructions =
middleware.process_full_instructions(full_instructions, protocol_name, is_buy)?;
if full_instructions.is_empty() {
break;
}
}
Ok(full_instructions)
}
pub fn apply_middlewares_process_protocol_instructions(
&self,
mut protocol_instructions: Vec<Instruction>,
protocol_name: &str,
is_buy: bool,
) -> Result<Vec<Instruction>> {
for middleware in &self.middlewares {
protocol_instructions = middleware.process_protocol_instructions(
protocol_instructions,
protocol_name,
is_buy,
)?;
if protocol_instructions.is_empty() {
break;
}
}
Ok(protocol_instructions)
}
pub fn with_common_middlewares() -> Self {
Self::new().add_middleware(Box::new(crate::trading::middleware::builtin::LoggingMiddleware))
}
}