feat: mpris support for audio applet
This commit is contained in:
parent
3f0f632d41
commit
557a43517d
5 changed files with 460 additions and 20 deletions
|
|
@ -12,11 +12,13 @@ libpulse-glib-binding = "2.25.0"
|
|||
tokio = { version = "1.20.1", features=["full"] }
|
||||
libcosmic.workspace = true
|
||||
cosmic-time.workspace = true
|
||||
log = "0.4.14"
|
||||
tracing = "0.1.40"
|
||||
pretty_env_logger = "0.4.0"
|
||||
# Application i18n
|
||||
i18n-embed = { version = "0.13", features = ["fluent-system", "desktop-requester"] }
|
||||
i18n-embed-fl = "0.6"
|
||||
rust-embed = "6.6"
|
||||
rust-embed-utils = "7.5.0"
|
||||
|
||||
serde = "1.0.130"
|
||||
mpris = "2.0.1"
|
||||
url = "2"
|
||||
|
|
|
|||
15
cosmic-applet-audio/src/config.rs
Normal file
15
cosmic-applet-audio/src/config.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
use cosmic::cosmic_config::cosmic_config_derive::CosmicConfigEntry;
|
||||
use cosmic::cosmic_config::{self, Config, ConfigGet, ConfigSet, CosmicConfigEntry};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, CosmicConfigEntry, PartialEq, Eq)]
|
||||
pub struct AudioAppletConfig {
|
||||
pub show_media_controls_in_top_panel: bool,
|
||||
}
|
||||
|
||||
impl AudioAppletConfig {
|
||||
/// Returns the version of the config
|
||||
pub fn version() -> u64 {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,21 @@
|
|||
mod localize;
|
||||
|
||||
use config::AudioAppletConfig;
|
||||
use cosmic::app::Command;
|
||||
use cosmic::applet::cosmic_panel_config::PanelAnchor;
|
||||
use cosmic::applet::menu_button;
|
||||
use cosmic::applet::menu_control_padding;
|
||||
use cosmic::applet::padded_control;
|
||||
use cosmic::cosmic_config::CosmicConfigEntry;
|
||||
use cosmic::iced::widget;
|
||||
use cosmic::iced::Limits;
|
||||
use cosmic::iced_futures::futures::channel::mpsc::Sender;
|
||||
use cosmic::iced_futures::futures::SinkExt;
|
||||
use cosmic::iced_runtime::core::alignment::Horizontal;
|
||||
|
||||
use cosmic::widget::button;
|
||||
use cosmic::widget::Column;
|
||||
use cosmic::widget::Row;
|
||||
use cosmic::widget::{divider, icon};
|
||||
use cosmic::Renderer;
|
||||
|
||||
|
|
@ -21,7 +30,12 @@ use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
|
|||
|
||||
use iced::wayland::popup::{destroy_popup, get_popup};
|
||||
use iced::widget::container;
|
||||
use mpris::PlaybackStatus;
|
||||
use mpris_subscription::MprisRequest;
|
||||
use mpris_subscription::MprisUpdate;
|
||||
|
||||
mod config;
|
||||
mod mpris_subscription;
|
||||
mod pulse;
|
||||
use crate::localize::localize;
|
||||
use crate::pulse::DeviceInfo;
|
||||
|
|
@ -33,7 +47,7 @@ pub fn main() -> cosmic::iced::Result {
|
|||
// Prepare i18n
|
||||
localize();
|
||||
|
||||
cosmic::applet::run::<Audio>(false, ())
|
||||
cosmic::applet::run::<Audio>(true, ())
|
||||
}
|
||||
|
||||
static SHOW_MEDIA_CONTROLS: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
|
||||
|
|
@ -50,9 +64,11 @@ struct Audio {
|
|||
icon_name: String,
|
||||
input_icon_name: String,
|
||||
popup: Option<window::Id>,
|
||||
show_media_controls_in_top_panel: bool,
|
||||
id_ctr: u128,
|
||||
timeline: Timeline,
|
||||
config: AudioAppletConfig,
|
||||
mpris_tx: Option<Sender<MprisRequest>>,
|
||||
player_status: Option<mpris_subscription::PlayerStatus>,
|
||||
}
|
||||
|
||||
impl Audio {
|
||||
|
|
@ -127,6 +143,113 @@ enum Message {
|
|||
CloseRequested(window::Id),
|
||||
ToggleMediaControlsInTopPanel(chain::Toggler, bool),
|
||||
Frame(Instant),
|
||||
ConfigChanged(AudioAppletConfig),
|
||||
Mpris(mpris_subscription::MprisUpdate),
|
||||
MprisRequest(MprisRequest),
|
||||
}
|
||||
|
||||
impl Audio {
|
||||
fn playback_buttons(&self) -> Option<Element<Message>> {
|
||||
if self.player_status.is_some() && self.config.show_media_controls_in_top_panel {
|
||||
let mut elements = Vec::with_capacity(3);
|
||||
if let Some(go_prev) = self.go_previous() {
|
||||
elements.push(go_prev);
|
||||
}
|
||||
if let Some(play_pause) = self.play_pause() {
|
||||
elements.push(play_pause);
|
||||
}
|
||||
if let Some(go_next) = self.go_next() {
|
||||
elements.push(go_next);
|
||||
}
|
||||
|
||||
Some(match self.core.applet.anchor {
|
||||
PanelAnchor::Left | PanelAnchor::Right => Column::with_children(elements)
|
||||
.align_items(Alignment::Center)
|
||||
.into(),
|
||||
PanelAnchor::Top | PanelAnchor::Bottom => Row::with_children(elements)
|
||||
.align_items(Alignment::Center)
|
||||
.into(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn go_previous(&self) -> Option<Element<Message>> {
|
||||
self.player_status.as_ref().and_then(|s| {
|
||||
if s.can_go_previous {
|
||||
Some(
|
||||
button::icon(
|
||||
icon::from_name("media-skip-backward-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
)
|
||||
.extra_small()
|
||||
.on_press(Message::MprisRequest(MprisRequest::Previous))
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn go_next(&self) -> Option<Element<Message>> {
|
||||
self.player_status.as_ref().and_then(|s| {
|
||||
if s.can_go_next {
|
||||
Some(
|
||||
button::icon(
|
||||
icon::from_name("media-skip-forward-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
)
|
||||
.extra_small()
|
||||
.on_press(Message::MprisRequest(MprisRequest::Next))
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn play_pause(&self) -> Option<Element<Message>> {
|
||||
self.player_status.as_ref().and_then(|s| match s.status {
|
||||
PlaybackStatus::Playing => {
|
||||
if s.can_pause {
|
||||
Some(
|
||||
button::icon(
|
||||
icon::from_name("media-playback-pause-symbolic")
|
||||
.size(32)
|
||||
.symbolic(true),
|
||||
)
|
||||
.on_press(Message::MprisRequest(MprisRequest::Pause))
|
||||
.extra_small()
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
PlaybackStatus::Paused | PlaybackStatus::Stopped => {
|
||||
if s.can_play {
|
||||
Some(
|
||||
button::icon(
|
||||
icon::from_name("media-playback-start-symbolic")
|
||||
.size(32)
|
||||
.symbolic(true),
|
||||
)
|
||||
.extra_small()
|
||||
.on_press(Message::MprisRequest(MprisRequest::Play))
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl cosmic::Application for Audio {
|
||||
|
|
@ -227,7 +350,7 @@ impl cosmic::Application for Audio {
|
|||
if let PulseState::Connected(connection) = &mut self.pulse_state {
|
||||
if let Some(device) = &self.current_input {
|
||||
if let Some(name) = &device.name {
|
||||
log::info!("increasing volume of {}", name);
|
||||
tracing::info!("increasing volume of {}", name);
|
||||
connection.send(pulse::Message::SetSourceVolumeByName(
|
||||
name.clone(),
|
||||
device.volume,
|
||||
|
|
@ -308,7 +431,7 @@ impl cosmic::Application for Audio {
|
|||
panic!("Subscriton error handling is bad. This should never happen.")
|
||||
}
|
||||
_ => {
|
||||
log::trace!("Received misc message")
|
||||
tracing::trace!("Received misc message")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -316,13 +439,40 @@ impl cosmic::Application for Audio {
|
|||
},
|
||||
Message::ToggleMediaControlsInTopPanel(chain, enabled) => {
|
||||
self.timeline.set_chain(chain).start();
|
||||
self.show_media_controls_in_top_panel = enabled;
|
||||
self.config.show_media_controls_in_top_panel = enabled;
|
||||
if let Ok(helper) =
|
||||
cosmic::cosmic_config::Config::new(Self::APP_ID, AudioAppletConfig::version())
|
||||
{
|
||||
if let Err(err) = self.config.write_entry(&helper) {
|
||||
tracing::error!(?err, "Error writing config");
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::CloseRequested(id) => {
|
||||
if Some(id) == self.popup {
|
||||
self.popup = None;
|
||||
}
|
||||
}
|
||||
Message::ConfigChanged(c) => {
|
||||
self.config = c;
|
||||
}
|
||||
Message::Mpris(mpris_subscription::MprisUpdate::Setup(tx)) => {
|
||||
self.mpris_tx = Some(tx);
|
||||
}
|
||||
Message::Mpris(mpris_subscription::MprisUpdate::Player(p)) => {
|
||||
self.player_status = Some(p);
|
||||
}
|
||||
Message::Mpris(MprisUpdate::Finished) => {
|
||||
self.player_status = None;
|
||||
self.mpris_tx = None;
|
||||
}
|
||||
Message::MprisRequest(r) => {
|
||||
if let Some(mut tx) = self.mpris_tx.clone() {
|
||||
_ = tokio::spawn(async move {
|
||||
_ = tx.send(r).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Command::none()
|
||||
|
|
@ -334,15 +484,46 @@ impl cosmic::Application for Audio {
|
|||
self.timeline
|
||||
.as_subscription()
|
||||
.map(|(_, now)| Message::Frame(now)),
|
||||
cosmic::cosmic_config::config_subscription(
|
||||
0,
|
||||
Self::APP_ID.into(),
|
||||
AudioAppletConfig::version(),
|
||||
)
|
||||
.map(|(_, res)| match res {
|
||||
Ok(c) => Message::ConfigChanged(c),
|
||||
Err((errs, c)) => {
|
||||
for err in errs {
|
||||
tracing::error!("Error loading config: {}", err);
|
||||
}
|
||||
Message::ConfigChanged(c)
|
||||
}
|
||||
}),
|
||||
mpris_subscription::mpris_subscription(0).map(Message::Mpris),
|
||||
])
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<Message> {
|
||||
self.core
|
||||
let btn = self
|
||||
.core
|
||||
.applet
|
||||
.icon_button(&self.icon_name)
|
||||
.on_press(Message::TogglePopup)
|
||||
.into()
|
||||
.on_press(Message::TogglePopup);
|
||||
if let Some(playback_buttons) = self.playback_buttons() {
|
||||
match self.core.applet.anchor {
|
||||
PanelAnchor::Left | PanelAnchor::Right => {
|
||||
Column::with_children(vec![playback_buttons, btn.into()])
|
||||
.align_items(Alignment::Center)
|
||||
.into()
|
||||
}
|
||||
PanelAnchor::Top | PanelAnchor::Bottom => {
|
||||
Row::with_children(vec![playback_buttons, btn.into()])
|
||||
.align_items(Alignment::Center)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
btn.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
||||
|
|
@ -362,7 +543,7 @@ impl cosmic::Application for Audio {
|
|||
)
|
||||
.0 * 100.0;
|
||||
|
||||
let audio_content = if audio_disabled {
|
||||
let mut audio_content = if audio_disabled {
|
||||
column![padded_control(
|
||||
text(fl!("disconnected"))
|
||||
.width(Length::Fill)
|
||||
|
|
@ -441,6 +622,40 @@ impl cosmic::Application for Audio {
|
|||
]
|
||||
.align_items(Alignment::Start)
|
||||
};
|
||||
|
||||
if let Some(s) = self.player_status.as_ref() {
|
||||
let mut elements = Vec::with_capacity(5);
|
||||
|
||||
if let Some(icon_path) = s.icon.clone() {
|
||||
elements.push(icon(icon::from_path(icon_path)).size(24).into());
|
||||
}
|
||||
|
||||
elements.push(
|
||||
column![
|
||||
text(s.title.clone().unwrap_or_default()).size(14),
|
||||
text(s.artists.clone().unwrap_or_default().join(", ")).size(10),
|
||||
]
|
||||
.into(),
|
||||
);
|
||||
|
||||
if let Some(go_prev) = self.go_previous() {
|
||||
elements.push(go_prev);
|
||||
}
|
||||
if let Some(play_pause) = self.play_pause() {
|
||||
elements.push(play_pause);
|
||||
}
|
||||
if let Some(go_next) = self.go_next() {
|
||||
elements.push(go_next);
|
||||
}
|
||||
|
||||
audio_content = audio_content.push(padded_control(divider::horizontal::default()));
|
||||
audio_content = audio_content.push(
|
||||
Row::with_children(elements)
|
||||
.align_items(Alignment::Center)
|
||||
.spacing(8)
|
||||
.padding(menu_control_padding()),
|
||||
);
|
||||
}
|
||||
let content = column![
|
||||
audio_content,
|
||||
padded_control(divider::horizontal::default()),
|
||||
|
|
@ -450,7 +665,7 @@ impl cosmic::Application for Audio {
|
|||
SHOW_MEDIA_CONTROLS,
|
||||
&self.timeline,
|
||||
Some(fl!("show-media-controls")),
|
||||
self.show_media_controls_in_top_panel,
|
||||
self.config.show_media_controls_in_top_panel,
|
||||
Message::ToggleMediaControlsInTopPanel,
|
||||
)
|
||||
.text_size(14)
|
||||
|
|
|
|||
205
cosmic-applet-audio/src/mpris_subscription.rs
Normal file
205
cosmic-applet-audio/src/mpris_subscription.rs
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
use std::{borrow::Cow, fmt::Debug, hash::Hash, path::PathBuf, time::Duration};
|
||||
|
||||
use cosmic::{
|
||||
iced::{self, subscription},
|
||||
iced_futures::futures::{
|
||||
self,
|
||||
channel::mpsc::{channel, Receiver, Sender},
|
||||
SinkExt, StreamExt,
|
||||
},
|
||||
};
|
||||
use mpris::{PlaybackStatus, PlayerFinder};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PlayerStatus {
|
||||
pub icon: Option<PathBuf>,
|
||||
pub title: Option<Cow<'static, str>>,
|
||||
pub artists: Option<Vec<Cow<'static, str>>>,
|
||||
pub status: PlaybackStatus,
|
||||
pub can_pause: bool,
|
||||
pub can_play: bool,
|
||||
pub can_go_previous: bool,
|
||||
pub can_go_next: bool,
|
||||
}
|
||||
|
||||
pub fn mpris_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||
id: I,
|
||||
) -> iced::Subscription<MprisUpdate> {
|
||||
subscription::channel(id, 50, move |mut output| async move {
|
||||
let mut state = State::Setup;
|
||||
|
||||
loop {
|
||||
state = update(state, &mut output).await;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum State {
|
||||
Setup,
|
||||
Wait(Receiver<MprisUpdate>),
|
||||
Finished,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum MprisUpdate {
|
||||
Setup(Sender<MprisRequest>),
|
||||
Player(PlayerStatus),
|
||||
Finished,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum MprisRequest {
|
||||
Play,
|
||||
Pause,
|
||||
Next,
|
||||
Previous,
|
||||
}
|
||||
|
||||
async fn update(state: State, output: &mut futures::channel::mpsc::Sender<MprisUpdate>) -> State {
|
||||
match state {
|
||||
State::Setup => {
|
||||
let (mut tx, rx) = channel(30);
|
||||
let (thread_tx, mut thread_rx) = channel(30);
|
||||
let _ = std::thread::spawn(move || {
|
||||
let mut ctr = 0;
|
||||
loop {
|
||||
let player = match PlayerFinder::new().and_then(|f| {
|
||||
f.find_active()
|
||||
.map_err(|e| mpris::DBusError::Miscellaneous(e.to_string()))
|
||||
}) {
|
||||
Ok(p) => {
|
||||
ctr = 0;
|
||||
p
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(?e, "Failed to find active media player.");
|
||||
std::thread::sleep(Duration::from_millis(ctr.min(20) * 100));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let can_go_next = player.can_go_next().unwrap_or_default();
|
||||
let can_go_previous = player.can_go_previous().unwrap_or_default();
|
||||
let can_play = player.can_play().unwrap_or_default();
|
||||
let can_pause = player.can_pause().unwrap_or_default();
|
||||
|
||||
let Ok(mut tracker) = player.track_progress(200) else {
|
||||
tracing::error!("Failed to track progress.");
|
||||
std::thread::sleep(Duration::from_secs(2));
|
||||
continue;
|
||||
};
|
||||
let (title, artists, icon) = player
|
||||
.get_metadata()
|
||||
.map(|m| {
|
||||
(
|
||||
m.title().map(|c| Cow::Owned(String::from(c))),
|
||||
m.artists().map(|a| {
|
||||
a.into_iter()
|
||||
.map(|a| Cow::from(String::from(a)))
|
||||
.collect::<Vec<_>>()
|
||||
}),
|
||||
m.art_url()
|
||||
.and_then(|u| url::Url::parse(u).ok())
|
||||
.and_then(|u| {
|
||||
if u.scheme() == "file" {
|
||||
u.to_file_path().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
if let Err(err) = tx.try_send(MprisUpdate::Player(PlayerStatus {
|
||||
icon,
|
||||
title,
|
||||
artists,
|
||||
status: player
|
||||
.get_playback_status()
|
||||
.unwrap_or(PlaybackStatus::Stopped),
|
||||
can_pause,
|
||||
can_play,
|
||||
can_go_previous,
|
||||
can_go_next,
|
||||
})) {
|
||||
tracing::error!(?err, "Failed to send player update.");
|
||||
}
|
||||
loop {
|
||||
if let Ok(req) = thread_rx.try_next() {
|
||||
match req {
|
||||
Some(MprisRequest::Play) => {
|
||||
let _ = player.play();
|
||||
}
|
||||
Some(MprisRequest::Pause) => {
|
||||
let _ = player.pause();
|
||||
}
|
||||
Some(MprisRequest::Next) => {
|
||||
let _ = player.next();
|
||||
}
|
||||
Some(MprisRequest::Previous) => {
|
||||
let _ = player.previous();
|
||||
}
|
||||
None => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
let tick = tracker.tick();
|
||||
if tick.player_quit {
|
||||
tracing::info!("Player quit.");
|
||||
break;
|
||||
}
|
||||
if tick.progress_changed {
|
||||
let metadata = tick.progress.metadata();
|
||||
if let Err(err) = tx.try_send(MprisUpdate::Player(PlayerStatus {
|
||||
icon: metadata
|
||||
.art_url()
|
||||
.and_then(|u| url::Url::parse(u).ok())
|
||||
.and_then(|u| {
|
||||
if u.scheme() == "file" {
|
||||
u.to_file_path().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
title: metadata.title().map(|t| Cow::from(t.to_string())),
|
||||
artists: metadata.artists().map(|a| {
|
||||
a.into_iter().map(|a| Cow::from(a.to_string())).collect()
|
||||
}),
|
||||
status: tick.progress.playback_status(),
|
||||
can_pause: player.can_pause().unwrap_or_default(),
|
||||
can_play: player.can_play().unwrap_or_default(),
|
||||
can_go_previous: player.can_go_previous().unwrap_or_default(),
|
||||
can_go_next: player.can_go_next().unwrap_or_default(),
|
||||
})) {
|
||||
tracing::error!(?err, "Failed to send player update.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(tracker);
|
||||
}
|
||||
});
|
||||
|
||||
let _ = output.send(MprisUpdate::Setup(thread_tx)).await;
|
||||
|
||||
State::Wait(rx)
|
||||
}
|
||||
State::Wait(mut rx) => match rx.next().await {
|
||||
Some(u) => {
|
||||
match u {
|
||||
MprisUpdate::Setup(_) => {}
|
||||
u => {
|
||||
let _ = output.send(u).await;
|
||||
}
|
||||
}
|
||||
State::Wait(rx)
|
||||
}
|
||||
None => {
|
||||
_ = output.send(MprisUpdate::Finished).await;
|
||||
return State::Finished;
|
||||
}
|
||||
},
|
||||
State::Finished => iced::futures::future::pending().await,
|
||||
}
|
||||
}
|
||||
|
|
@ -212,7 +212,7 @@ impl PulseHandle {
|
|||
.await
|
||||
.unwrap(),
|
||||
Err(e) => {
|
||||
log::error!("ERROR! {:?}", e);
|
||||
tracing::error!("ERROR! {:?}", e);
|
||||
PulseHandle::send_disconnected(&mut from_pulse_send).await;
|
||||
}
|
||||
}
|
||||
|
|
@ -262,28 +262,31 @@ impl PulseHandle {
|
|||
server.set_source_volume_by_name(&name, &channel_volumes)
|
||||
}
|
||||
Message::UpdateConnection => {
|
||||
log::info!(
|
||||
tracing::info!(
|
||||
"Updating Connection, server exists: {:?}",
|
||||
server.is_some()
|
||||
);
|
||||
if let Some(mut cur_server) = server.take() {
|
||||
log::trace!("getting server info...");
|
||||
tracing::trace!("getting server info...");
|
||||
if let Err(_) = cur_server.get_server_info() {
|
||||
log::warn!("got error, server must be disconnected...");
|
||||
tracing::warn!("got error, server must be disconnected...");
|
||||
PulseHandle::send_disconnected(&mut from_pulse_send).await;
|
||||
} else {
|
||||
log::trace!("got server info, still connected...");
|
||||
tracing::trace!("got server info, still connected...");
|
||||
server = Some(cur_server);
|
||||
}
|
||||
} else {
|
||||
match PulseServer::connect().and_then(|server| server.init()) {
|
||||
Ok(new_server) => {
|
||||
log::info!("Connected to server");
|
||||
tracing::info!("Connected to server");
|
||||
PulseHandle::send_connected(&mut from_pulse_send).await;
|
||||
server = Some(new_server);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed to connect to server: {:?}", err);
|
||||
tracing::error!(
|
||||
"Failed to connect to server: {:?}",
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -327,7 +330,7 @@ impl PulseHandle {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
log::warn!("message doesn't match")
|
||||
tracing::warn!("message doesn't match")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue