use std::marker::PhantomData;
use crate::
{
a_sync::
{
syslog_async_internal::{AsyncMutexGuard, AsyncSyslogInternal}
},
error::SyRes,
formatters::{SyslogFormatter},
syslog_provider::*,
LogFacility,
LogStat,
Priority
};
use crate::a_sync::syslog_async_internal::AsyncMutex;
#[cfg(feature = "build_async_interface")]
use crate::a_sync::syslog_async_internal::AsyncSyslogInternalIO;
#[cfg(feature = "async_embedded")]
use crate::a_sync::{syslog_async_internal::AsyncSyslogInternalIO, DefaultAsyncMutex};
#[cfg(feature = "async_embedded")]
use crate::formatters::DefaultSyslogFormatter;
#[cfg(feature = "async_embedded")]
use crate::a_sync::DefaultIOs;
use super::{syslog_trait::AsyncSyslogApi};
#[cfg(target_family = "unix")]
pub type DefaultLocalSyslogDestination = SyslogLocal;
#[cfg(target_family = "windows")]
pub type DefaultLocalSyslogDestination = WindowsEvent;
#[cfg(feature = "async_embedded")]
#[derive(Debug)]
pub struct AsyncSyslog<D = DefaultLocalSyslogDestination, F = DefaultSyslogFormatter, IO = DefaultIOs, MUX = DefaultAsyncMutex<F, D, IO>>
(MUX, PhantomData<D>, PhantomData<F>, PhantomData<IO>)
where
D: AsyncSyslogDestination,
F: SyslogFormatter + Sync,
MUX: AsyncMutex<F, D, AsyncSyslogInternal<F, D, IO>>,
IO: AsyncSyslogInternalIO;
#[cfg(feature = "build_async_interface")]
#[derive(Debug)]
pub struct AsyncSyslog<D, F, IO, MUX>
(MUX, PhantomData<D>, PhantomData<F>, PhantomData<IO>)
where
D: AsyncSyslogDestination,
F: SyslogFormatter + Sync,
MUX: AsyncMutex<F, D, AsyncSyslogInternal<F, D, IO>>,
IO: AsyncSyslogInternalIO;
#[cfg(feature = "async_embedded")]
impl AsyncSyslog
{
pub async
fn openlog(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap: DefaultLocalSyslogDestination) -> SyRes<Self>
{
let mut syslog =
AsyncSyslogInternal::<DefaultSyslogFormatter, DefaultLocalSyslogDestination, DefaultIOs>::new(ident, logstat, facility, net_tap)?;
if logstat.contains(LogStat::LOG_NDELAY) == true
{
syslog.connectlog().await?;
}
let mux_syslog = DefaultAsyncMutex::a_new(syslog);
return Ok(
Self(
mux_syslog,
PhantomData::<DefaultLocalSyslogDestination>,
PhantomData::<DefaultSyslogFormatter>,
PhantomData::<DefaultIOs>
)
);
}
}
impl<F, D, IO, MUX> AsyncSyslog<D, F, IO, MUX>
where
F: SyslogFormatter + Sync,
D: AsyncSyslogDestination,
MUX: AsyncMutex<F, D, AsyncSyslogInternal<F, D, IO>>,
IO: AsyncSyslogInternalIO
{
pub async
fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap: D) -> SyRes<AsyncSyslog<D, F, IO, MUX>>
{
let mut syslog =
AsyncSyslogInternal::<F, D, IO>::new(ident, logstat, facility, net_tap)?;
if logstat.contains(LogStat::LOG_NDELAY) == true
{
syslog.connectlog().await?;
}
let mux_syslog = MUX::a_new(syslog);
return Ok( Self(mux_syslog, PhantomData::<D>, PhantomData::<F>, PhantomData::<IO>) );
}
#[inline]
pub async
fn setlogmask(&self, logmask: i32) -> i32
{
return
self
.0
.a_lock()
.await
.guard_mut()
.set_logmask(logmask);
}
pub async
fn change_identity(&self, ident: &str)
{
return
self
.0
.a_lock()
.await
.guard_mut()
.change_identity(ident);
}
pub async
fn closelog(&self) -> SyRes<()>
{
return
self
.0
.a_lock()
.await
.guard_mut()
.closelog()
.await;
}
#[inline]
pub async
fn syslog(&self, pri: Priority, fmt: String)
{
self.0.a_lock().await.guard_mut().vsyslog1(pri, fmt.into()).await;
}
#[inline]
pub async
fn vsyslog(&self, pri: Priority, fmt: &'static str)
{
self.0.a_lock().await.guard_mut().vsyslog1(pri, fmt.into()).await;
}
#[inline]
pub async
fn esyslog(&self, pri: Priority, fmt: F)
{
self.0.a_lock().await.guard_mut().vsyslog1(pri, fmt).await;
}
pub async
fn reconnect(&self) -> SyRes<()>
{
return self.0.a_lock().await.guard_mut().reconnect().await;
}
pub async
fn update_tap(&self, new_tap: D) -> SyRes<()>
{
return self.0.a_lock().await.guard_mut().update_tap_data(new_tap).await;
}
}
#[cfg(target_family = "unix")]
#[cfg(test)]
mod async_tests
{
use super::*;
#[cfg(feature = "build_async_smol")]
#[test]
fn test_smol() -> smol::io::Result<()>
{
smol::block_on(
async
{
use std::{sync::Arc, time::{Duration, Instant}};
use smol::Timer;
let log =
AsyncSyslog::openlog(
Some("smol_test1"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogLocal::new()
)
.await;
assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
let log = Arc::new(log.unwrap());
let c1_log = log.clone();
let c2_log = log.clone();
smol::spawn(async move
{
for i in 0..5
{
use std::time::Duration;
use smol::Timer;
let cc_c1_log = c1_log.clone();
Timer::after(Duration::from_nanos(200)).await;
smol::spawn( async move
{
use std::time::Instant;
let m = format!("ASYNC a message from thread 1 #{}[]", i);
let now = Instant::now();
cc_c1_log.syslog(Priority::LOG_DEBUG, m).await;
let elapsed = now.elapsed();
println!("t1: {:?}", elapsed);
}).await;
}
}
)
.await;
smol::spawn(async move
{
for i in 0..5
{
use std::time::Duration;
use smol::Timer;
let cc_c2_log = c2_log.clone();
Timer::after(Duration::from_nanos(201)).await;
smol::spawn( async move
{
use std::time::Instant;
let m = format!("ASYNC きるさお命泉ぶねりよ日子金れっ {}", i);
let now = Instant::now();
cc_c2_log.syslog(Priority::LOG_DEBUG, m.into()).await;
let elapsed = now.elapsed();
println!("t2: {:?}", elapsed);
}).await;
}
}).await;
let m = format!("ASYNC A message from main, きるさお命泉ぶねりよ日子金れっ");
let now = Instant::now();
log.syslog(Priority::LOG_DEBUG, m).await;
let elapsed = now.elapsed();
println!("main: {:?}", elapsed);
log.change_identity("smol_test1new").await;
let m = format!("ASYNC A message from main new ident, きるさお命泉ぶねりよ日子金れっ");
log.syslog(Priority::LOG_DEBUG, m).await;
Timer::after(Duration::from_secs(1)).await;
log.closelog().await.unwrap();
Timer::after(Duration::from_nanos(201)).await;
Ok(())
}
)
}
#[cfg(feature = "build_async_tokio")]
#[tokio::test]
async fn test_multithreading()
{
use tokio::time::Instant;
use std::sync::Arc;
use tokio::time::{sleep, Duration};
let log =
AsyncSyslog::openlog(
Some("asynctest1"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogLocal::new()
).await;
assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
let log = Arc::new(log.unwrap());
let c1_log = log.clone();
let c2_log = log.clone();
tokio::spawn( async move
{
for i in 0..5
{
let cc_c1_log = c1_log.clone();
sleep(Duration::from_nanos(200)).await;
tokio::spawn( async move
{
let m = format!("ASYNC a message from thread 1 #{}[]", i);
let now = Instant::now();
cc_c1_log.syslog(Priority::LOG_DEBUG, m).await;
let elapsed = now.elapsed();
println!("t1: {:?}", elapsed);
});
}
}
);
tokio::spawn(async move
{
for i in 0..5
{
let cc_c2_log = c2_log.clone();
sleep(Duration::from_nanos(201)).await;
tokio::spawn( async move
{
let m = format!("ASYNC きるさお命泉ぶねりよ日子金れっ {}", i);
let now = Instant::now();
cc_c2_log.syslog(Priority::LOG_DEBUG, m).await;
let elapsed = now.elapsed();
println!("t2: {:?}", elapsed);
});
}
});
let m = format!("ASYNC A message from main, きるさお命泉ぶねりよ日子金れっ");
let now = Instant::now();
log.syslog(Priority::LOG_DEBUG, m).await;
let elapsed = now.elapsed();
println!("main: {:?}", elapsed);
sleep(Duration::from_secs(1)).await;
log.change_identity("asynctest1new").await;
let m = format!("ASYNC A message from main new ident, きるさお命泉ぶねりよ日子金れっ");
log.syslog(Priority::LOG_DEBUG, m).await;
log.closelog().await.unwrap();
sleep(Duration::from_nanos(201)).await;
return;
}
}