use super::{Component, ComponentState};
use crate::node::{
components::ComponentRequest,
formats::{ExternalEvent, ShutdownReason},
node_settings::Settings,
};
use anyhow::Result;
use crossbeam::channel::{self, Receiver, Sender};
use ffi_support::rust_string_to_c;
use std::{convert::TryFrom, os::raw::c_char};
#[derive(Debug)]
pub struct FfiMessage {
code: i32,
message: String,
}
mod ffi_codes {
pub const NODE_STOPPED_BY_NODE: i32 = 10;
pub const NODE_STOPPED_BY_NODE_UI: i32 = 11;
pub const NODE_STOPPED_BY_HOST: i32 = 12;
pub const ERR_PORT_COLLISION: i32 = 13;
}
impl TryFrom<i32> for ShutdownReason {
type Error = anyhow::Error;
fn try_from(value: i32) -> Result<Self, Self::Error> {
use ffi_codes::*;
match value {
NODE_STOPPED_BY_NODE_UI => Ok(ShutdownReason::TriggeredByUser),
NODE_STOPPED_BY_HOST => Ok(ShutdownReason::TriggeredByHost),
x => anyhow::bail!("Unsupported error code! {}", x),
}
}
}
impl From<ShutdownReason> for FfiMessage {
fn from(s: ShutdownReason) -> FfiMessage {
let (code, message) = match s {
ShutdownReason::TriggeredByUser => (ffi_codes::NODE_STOPPED_BY_NODE_UI, "".to_string()),
ShutdownReason::TriggeredByHost => (ffi_codes::NODE_STOPPED_BY_HOST, "".to_string()),
ShutdownReason::Internal(err) => match err {
crate::node::NodeError::ServicesStartup { err, .. } | crate::node::NodeError::InternalError(err) => {
(ffi_codes::NODE_STOPPED_BY_NODE, format!("{:#}", err))
}
crate::node::NodeError::PortCollision { component, addr } => (
ffi_codes::ERR_PORT_COLLISION,
format!(
"Could not bind to port {}. Please specify a different {} port",
addr, component
),
),
},
};
FfiMessage::new(code, message)
}
}
impl FfiMessage {
pub fn new(code: i32, message: String) -> Self {
Self { code, message }
}
}
impl From<FfiMessage> for (i32, *mut c_char) {
fn from(m: FfiMessage) -> (i32, *mut c_char) {
(m.code, rust_string_to_c(m.message))
}
}
#[allow(dead_code)]
pub(crate) struct Android {
rx: Receiver<ComponentRequest<()>>,
android_tx: Sender<FfiMessage>,
sender: Sender<ExternalEvent>,
}
impl Android {
pub fn new(
sender: Sender<ExternalEvent>,
rx: Receiver<ComponentRequest<()>>,
android_tx: Sender<FfiMessage>,
) -> Self {
Self { rx, android_tx, sender }
}
}
impl Component<(), ()> for Android {
fn get_rx(&self) -> &channel::Receiver<ComponentRequest<()>> {
&self.rx
}
fn get_type() -> &'static str {
"android"
}
fn handle_request(&mut self, _: ()) -> Result<()> {
Ok(())
}
fn extract_settings(&self, _: Settings) -> Result<()> {
Ok(())
}
fn start(&mut self, _: Sender<anyhow::Result<()>>) -> Result<()> {
Ok(())
}
fn stop(&mut self) -> Result<()> {
Ok(())
}
fn loop_on_rx(self) -> Result<()> {
let mut supervisor = None;
while let Ok(msg) = self.rx.recv() {
match msg {
ComponentRequest::Shutdown(r) => {
self.android_tx.send(r.into())?;
break;
}
ComponentRequest::RegisterSupervisor(snd) => {
snd.send((Self::get_type().into(), ComponentState::Started))?;
supervisor.replace(snd);
}
_ => {}
}
}
if let Some(tx) = supervisor {
tx.send((Self::get_type().into(), ComponentState::Stopped))?;
}
Ok(())
}
}