use async_trait::async_trait;
use parking_lot::RwLock;
use tonic::Status;
use crate::errors::SessionError;
use crate::fire_and_forget::FireAndForgetConfiguration;
use crate::request_response::RequestResponseConfiguration;
use crate::streaming::StreamingConfiguration;
use agp_datapath::messages::encoder::Agent;
use agp_datapath::pubsub::proto::pubsub::v1::{Message, SessionHeaderType};
pub type Id = u32;
pub const SESSION_RANGE: std::ops::Range<u32> = 0..(u32::MAX - 1000);
pub const SESSION_UNSPECIFIED: u32 = u32::MAX;
#[derive(Clone, PartialEq, Debug)]
pub struct SessionMessage {
pub message: Message,
pub info: Info,
}
impl SessionMessage {
pub fn new(message: Message, info: Info) -> Self {
SessionMessage { message, info }
}
}
impl From<(Message, Info)> for SessionMessage {
fn from(tuple: (Message, Info)) -> Self {
SessionMessage {
message: tuple.0,
info: tuple.1,
}
}
}
impl From<Message> for SessionMessage {
fn from(message: Message) -> Self {
let info = Info::from(&message);
SessionMessage { message, info }
}
}
impl From<SessionMessage> for Message {
fn from(session_message: SessionMessage) -> Self {
session_message.message
}
}
pub type AppChannelSender = tokio::sync::mpsc::Sender<Result<SessionMessage, SessionError>>;
pub type AppChannelReceiver = tokio::sync::mpsc::Receiver<Result<SessionMessage, SessionError>>;
pub type GwChannelSender = tokio::sync::mpsc::Sender<Result<Message, Status>>;
pub type GwChannelReceiver = tokio::sync::mpsc::Receiver<Result<Message, Status>>;
#[derive(Clone, PartialEq, Debug)]
pub struct Info {
pub id: Id,
pub message_id: Option<u32>,
pub session_header_type: SessionHeaderType,
pub message_source: Option<Agent>,
pub input_connection: Option<u64>,
}
impl Info {
pub fn new(id: Id) -> Self {
Info {
id,
message_id: None,
session_header_type: SessionHeaderType::Unspecified,
message_source: None,
input_connection: None,
}
}
pub fn set_message_id(&mut self, message_id: u32) {
self.message_id = Some(message_id);
}
pub fn set_session_header_type(&mut self, session_header_type: SessionHeaderType) {
self.session_header_type = session_header_type;
}
pub fn set_message_source(&mut self, message_source: Agent) {
self.message_source = Some(message_source);
}
pub fn set_input_connection(&mut self, input_connection: u64) {
self.input_connection = Some(input_connection);
}
pub fn get_message_id(&self) -> Option<u32> {
self.message_id
}
pub fn get_session_header_type(&self) -> SessionHeaderType {
self.session_header_type
}
pub fn get_message_source(&self) -> Option<Agent> {
self.message_source.clone()
}
pub fn get_input_connection(&self) -> Option<u64> {
self.input_connection
}
}
impl From<&Message> for Info {
fn from(message: &Message) -> Self {
let session_header = message.get_session_header();
let agp_header = message.get_agp_header();
let id = session_header.session_id;
let message_id = session_header.message_id;
let message_source = message.get_source();
let input_connection = agp_header.incoming_conn;
let session_header_type = session_header.header_type;
Info {
id,
message_id: Some(message_id),
session_header_type: SessionHeaderType::try_from(session_header_type)
.unwrap_or(SessionHeaderType::Unspecified),
message_source: Some(message_source),
input_connection,
}
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum State {
Active,
Inactive,
}
#[derive(Clone, PartialEq, Debug)]
pub enum SessionDirection {
#[allow(dead_code)]
Sender,
#[allow(dead_code)]
Receiver,
Bidirectional,
}
#[derive(Clone, PartialEq, Debug)]
pub(crate) enum MessageDirection {
North,
South,
}
#[derive(Clone, PartialEq, Debug)]
pub enum SessionType {
FireAndForget,
RequestResponse,
Streaming,
}
impl std::fmt::Display for SessionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SessionType::FireAndForget => write!(f, "FireAndForget"),
SessionType::RequestResponse => write!(f, "RequestResponse"),
SessionType::Streaming => write!(f, "Streaming"),
}
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum SessionConfig {
FireAndForget(FireAndForgetConfiguration),
RequestResponse(RequestResponseConfiguration),
Streaming(StreamingConfiguration),
}
pub trait SessionConfigTrait {
fn replace(&mut self, session_config: &SessionConfig) -> Result<(), SessionError>;
}
impl std::fmt::Display for SessionConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SessionConfig::FireAndForget(ff) => write!(f, "{}", ff),
SessionConfig::RequestResponse(rr) => write!(f, "{}", rr),
SessionConfig::Streaming(s) => write!(f, "{}", s),
}
}
}
pub(crate) trait CommonSession {
#[allow(dead_code)]
fn id(&self) -> Id;
#[allow(dead_code)]
fn state(&self) -> &State;
fn source(&self) -> &Agent;
fn session_config(&self) -> SessionConfig;
fn set_session_config(&self, session_config: &SessionConfig) -> Result<(), SessionError>;
}
#[async_trait]
pub(crate) trait Session: CommonSession {
async fn on_message(
&self,
message: SessionMessage,
direction: MessageDirection,
) -> Result<(), SessionError>;
}
pub(crate) struct Common {
#[allow(dead_code)]
id: Id,
#[allow(dead_code)]
state: State,
session_config: RwLock<SessionConfig>,
#[allow(dead_code)]
session_direction: SessionDirection,
source: Agent,
tx_gw: GwChannelSender,
tx_app: AppChannelSender,
}
impl CommonSession for Common {
fn id(&self) -> Id {
self.id
}
fn state(&self) -> &State {
&self.state
}
fn source(&self) -> &Agent {
&self.source
}
fn session_config(&self) -> SessionConfig {
self.session_config.read().clone()
}
fn set_session_config(&self, session_config: &SessionConfig) -> Result<(), SessionError> {
let mut conf = self.session_config.write();
match *conf {
SessionConfig::FireAndForget(ref mut config) => {
config.replace(session_config)?;
}
SessionConfig::RequestResponse(ref mut config) => {
config.replace(session_config)?;
}
SessionConfig::Streaming(ref mut config) => {
config.replace(session_config)?;
}
}
Ok(())
}
}
impl Common {
pub(crate) fn new(
id: Id,
session_direction: SessionDirection,
session_type: SessionConfig,
source: Agent,
tx_gw: GwChannelSender,
tx_app: AppChannelSender,
) -> Common {
Common {
id,
state: State::Active,
session_direction,
session_config: RwLock::new(session_type),
source,
tx_gw,
tx_app,
}
}
#[allow(dead_code)]
pub(crate) fn tx_gw(&self) -> GwChannelSender {
self.tx_gw.clone()
}
pub(crate) fn tx_gw_ref(&self) -> &GwChannelSender {
&self.tx_gw
}
#[allow(dead_code)]
pub(crate) fn tx_app(&self) -> AppChannelSender {
self.tx_app.clone()
}
pub(crate) fn tx_app_ref(&self) -> &AppChannelSender {
&self.tx_app
}
}
macro_rules! delegate_common_behavior {
($parent:ident, $($tokens:ident),+) => {
impl CommonSession for $parent {
fn id(&self) -> Id {
self.$($tokens).+.id()
}
fn state(&self) -> &State {
self.$($tokens).+.state()
}
fn session_config(&self) -> SessionConfig {
self.$($tokens).+.session_config()
}
fn set_session_config(&self, session_config: &SessionConfig) -> Result<(), SessionError> {
self.$($tokens).+.set_session_config(session_config)
}
fn source(&self) -> &Agent {
self.$($tokens).+.source()
}
}
};
}