feat: more robust logic and handle discord reconnects
This commit is contained in:
parent
43dab27968
commit
30034b9f60
2 changed files with 78 additions and 38 deletions
|
@ -1,34 +1,32 @@
|
|||
/*
|
||||
* This file WAS ONCE is part of discord-presence. Extension for Zed that
|
||||
* adds support for Discord Rich Presence using LSP. It is heavily modified
|
||||
* to be used here.
|
||||
*
|
||||
* Copyright (c) 2025 Steinhübl, Virt
|
||||
*/
|
||||
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use discord_rich_presence::{
|
||||
DiscordIpc, DiscordIpcClient,
|
||||
activity::{Activity, Assets, Button, Timestamps},
|
||||
};
|
||||
use log::{debug, error, info};
|
||||
use log::{debug, info};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Discord {
|
||||
client: DiscordIpcClient,
|
||||
connected: bool,
|
||||
}
|
||||
|
||||
impl Discord {
|
||||
pub fn new(id: &str) -> Result<Self> {
|
||||
Ok(Self { client: DiscordIpcClient::new(id) })
|
||||
Ok(Self { client: DiscordIpcClient::new(id), connected: false })
|
||||
}
|
||||
|
||||
pub fn is_connected(&self) -> bool {
|
||||
self.connected
|
||||
}
|
||||
|
||||
pub fn connect(&mut self) -> Result<()> {
|
||||
debug!("connecting to discord");
|
||||
|
||||
self.client.connect().context("failed to connect to discord ipc")?;
|
||||
self.connected = true;
|
||||
|
||||
info!("successfully connected to discord");
|
||||
Ok(())
|
||||
|
@ -37,7 +35,10 @@ impl Discord {
|
|||
pub fn disconnect(&mut self) -> Result<()> {
|
||||
debug!("disconnecting from discord");
|
||||
|
||||
self.client.close().context("failed to disconnect from discord")
|
||||
self.client.close().context("failed to disconnect from discord")?;
|
||||
self.connected = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) -> Result<()> {
|
||||
|
|
91
src/main.rs
91
src/main.rs
|
@ -1,6 +1,5 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
thread::sleep,
|
||||
time::{Duration, Instant, SystemTime},
|
||||
};
|
||||
|
||||
|
@ -8,7 +7,7 @@ use anyhow::Result;
|
|||
use discord::Discord;
|
||||
use hyprland::{Address, Hyprland};
|
||||
use language::get_language;
|
||||
use log::{debug, info};
|
||||
use log::{debug, error, info, warn};
|
||||
|
||||
pub mod discord;
|
||||
pub mod hyprland;
|
||||
|
@ -19,7 +18,7 @@ const ICONS_URL: &str =
|
|||
"https://raw.githubusercontent.com/xhyrom/zed-discord-presence/main/assets/icons";
|
||||
const ZED_CLASS: &str = "dev.zed.Zed";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
struct ZedInstance {
|
||||
workspace: String,
|
||||
file: Option<String>,
|
||||
|
@ -29,6 +28,14 @@ struct ZedInstance {
|
|||
focused: SystemTime,
|
||||
}
|
||||
|
||||
impl PartialEq for ZedInstance {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.workspace.eq(&other.workspace)
|
||||
&& self.file.eq(&other.file)
|
||||
&& self.started.eq(&other.started)
|
||||
}
|
||||
}
|
||||
|
||||
impl ZedInstance {
|
||||
pub fn new(title: &str) -> Self {
|
||||
let mut s = Self {
|
||||
|
@ -79,19 +86,18 @@ fn main() -> Result<()> {
|
|||
);
|
||||
}
|
||||
|
||||
info!("connecting to discord ipc");
|
||||
discord.connect()?;
|
||||
info!("connecting to hyprland ipc");
|
||||
hyprland.connect(Duration::from_secs(60))?;
|
||||
|
||||
let mut first = true;
|
||||
let mut updated = Instant::now() - idle;
|
||||
let mut shown: Option<ZedInstance> = None;
|
||||
|
||||
loop {
|
||||
let events = hyprland.read_events()?;
|
||||
debug!("received new hyprland events");
|
||||
|
||||
// only check on timeout if not active
|
||||
let mut changed = first || events.is_none() && !instances.contains_key(&active);
|
||||
first = false;
|
||||
// update anyways if last update has been before idle timeout
|
||||
let mut changed = Instant::now().duration_since(updated) < idle;
|
||||
|
||||
if let Some(events) = events {
|
||||
for event in events {
|
||||
|
@ -131,27 +137,55 @@ fn main() -> Result<()> {
|
|||
}
|
||||
|
||||
if changed {
|
||||
if let Some(instance) = instances.get(&active).or_else(|| {
|
||||
debug!("checking for instance change");
|
||||
|
||||
let instance = instances.get(&active).or_else(|| {
|
||||
instances.values().max_by(|a, b| a.focused.cmp(&b.focused)).filter(|instance| {
|
||||
SystemTime::now().duration_since(instance.focused).expect("compare times wtf")
|
||||
< idle
|
||||
})
|
||||
}) {
|
||||
info!(
|
||||
"setting discord activity to {} in workspace {}",
|
||||
instance.file.as_ref().map(|s| s.as_str()).unwrap_or("<none>"),
|
||||
instance.workspace
|
||||
);
|
||||
});
|
||||
|
||||
set_activity(
|
||||
&mut discord,
|
||||
instance.file.as_ref().map(|s| s.as_str()).unwrap_or("nothing"),
|
||||
&instance.workspace,
|
||||
instance.started,
|
||||
)?
|
||||
} else {
|
||||
info!("removing discord activity");
|
||||
discord.clear()?;
|
||||
if instance != shown.as_ref() {
|
||||
debug!("updating discord status as change was detected");
|
||||
shown = instance.cloned();
|
||||
updated = Instant::now();
|
||||
|
||||
if !discord.is_connected() {
|
||||
info!("(re-)connecting to discord ipc");
|
||||
|
||||
if let Err(e) = discord.connect() {
|
||||
warn!("failed to connect to discord, waiting for next update: {e:#}");
|
||||
shown = None;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let result = if let Some(ref instance) = shown {
|
||||
info!(
|
||||
"setting discord activity to {} in workspace {}",
|
||||
instance.file.as_ref().map(|s| s.as_str()).unwrap_or("<none>"),
|
||||
instance.workspace
|
||||
);
|
||||
set_activity(
|
||||
&mut discord,
|
||||
instance.file.as_ref().map(|s| s.as_str()).unwrap_or("nothing"),
|
||||
&instance.workspace,
|
||||
instance.started,
|
||||
)
|
||||
} else {
|
||||
info!("removing discord activity");
|
||||
discord.clear()
|
||||
};
|
||||
|
||||
if let Err(e) = result {
|
||||
warn!("failed to set discord activity: {e:#}");
|
||||
|
||||
debug!("disconnecting from discord");
|
||||
discord.disconnect().map_err(|e| error!("failed to disconnect: {e:#}")).ok();
|
||||
|
||||
shown = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +198,12 @@ pub fn set_activity(
|
|||
started: SystemTime,
|
||||
) -> Result<()> {
|
||||
let language = get_language(file);
|
||||
let language_upper: String = language.chars().take(1).chain(language.chars().skip(1)).collect();
|
||||
let language_upper: String = language
|
||||
.chars()
|
||||
.take(1)
|
||||
.map(|a| a.to_ascii_uppercase())
|
||||
.chain(language.chars().skip(1))
|
||||
.collect();
|
||||
|
||||
discord.set(
|
||||
Some(format!("Editing {file}")),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue