Skip to content

Commit 3d679a1

Browse files
committed
Add metadata key preference to configuration
1 parent b2c6a52 commit 3d679a1

File tree

5 files changed

+206
-52
lines changed

5 files changed

+206
-52
lines changed

data/src/capabilities.rs

Lines changed: 86 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,69 @@ pub struct MultilineLimits {
7777
pub max_lines: Option<usize>,
7878
}
7979

80+
#[derive(Debug, Clone, thiserror::Error)]
81+
pub enum CapParseError {
82+
#[error(transparent)]
83+
ParseInt(#[from] std::num::ParseIntError),
84+
#[error("Missing key `{0}` in dictionary: {1}")]
85+
MissingKey(String, String),
86+
}
87+
88+
impl FromStr for MultilineLimits {
89+
type Err = CapParseError;
90+
91+
fn from_str(s: &str) -> Result<Self, Self::Err> {
92+
let dictionary = s
93+
.split(',')
94+
.flat_map(|s| s.split_once('='))
95+
.collect::<HashMap<_, _>>();
96+
97+
Ok(MultilineLimits {
98+
max_bytes: dictionary
99+
.get("max-bytes")
100+
.ok_or_else(|| {
101+
CapParseError::MissingKey(
102+
"max-bytes".to_owned(),
103+
s.to_owned(),
104+
)
105+
})?
106+
.parse::<usize>()?,
107+
max_lines: dictionary
108+
.get("max-lines")
109+
.map(|s| s.parse::<usize>())
110+
.transpose()?,
111+
})
112+
}
113+
}
114+
115+
#[derive(Debug, Clone, Copy)]
116+
pub struct MetadataLimits {
117+
pub max_subs: usize,
118+
}
119+
120+
impl FromStr for MetadataLimits {
121+
type Err = CapParseError;
122+
123+
fn from_str(s: &str) -> Result<Self, Self::Err> {
124+
let dictionary = s
125+
.split(',')
126+
.flat_map(|s| s.split_once('='))
127+
.collect::<HashMap<_, _>>();
128+
129+
Ok(MetadataLimits {
130+
max_subs: dictionary
131+
.get("max-subs")
132+
.ok_or_else(|| {
133+
CapParseError::MissingKey(
134+
"max-subs".to_owned(),
135+
s.to_owned(),
136+
)
137+
})?
138+
.parse::<usize>()?,
139+
})
140+
}
141+
}
142+
80143
impl MultilineLimits {
81144
pub fn concat_bytes(
82145
&self,
@@ -199,10 +262,9 @@ pub enum MultilineBatchKind {
199262

200263
#[derive(Debug, Default)]
201264
pub struct Capabilities {
202-
listed: HashSet<String>,
265+
listed: HashMap<String, String>,
203266
pending: HashMap<String, String>,
204267
acknowledged: HashSet<Capability>,
205-
multiline: Option<MultilineLimits>,
206268
}
207269

208270
impl Capabilities {
@@ -346,27 +408,11 @@ impl Capabilities {
346408
requested.push("sasl");
347409
}
348410

349-
if let Some(multiline) = self.pending.get("draft/multiline") {
350-
let dictionary = multiline.split(',').collect::<Vec<_>>();
351-
352-
if let Some(max_bytes) = dictionary.iter().find_map(|key_value| {
353-
key_value
354-
.strip_prefix("max-bytes=")
355-
.and_then(|value| value.parse::<usize>().ok())
356-
}) {
357-
self.multiline = Some(MultilineLimits {
358-
max_bytes,
359-
max_lines: dictionary.iter().find_map(|key_value| {
360-
key_value
361-
.strip_prefix("max-lines=")
362-
.and_then(|value| value.parse::<usize>().ok())
363-
}),
364-
});
365-
366-
if !self.acknowledged(Capability::Multiline) {
367-
requested.push("draft/multiline");
368-
}
369-
}
411+
if let Some(multiline) = self.pending.get("draft/multiline")
412+
&& !self.acknowledged(Capability::Multiline)
413+
&& MultilineLimits::from_str(multiline).is_ok()
414+
{
415+
requested.push("draft/multiline");
370416
}
371417

372418
if self.pending.contains_key("draft/metadata-2")
@@ -375,8 +421,8 @@ impl Capabilities {
375421
requested.push("draft/metadata-2");
376422
}
377423

378-
for (cap, _) in self.pending.drain() {
379-
self.listed.insert(cap);
424+
for (cap, val) in self.pending.drain() {
425+
self.listed.insert(cap, val);
380426
}
381427

382428
requested
@@ -403,11 +449,21 @@ impl Capabilities {
403449
}
404450

405451
pub fn multiline_limits(&self) -> Option<MultilineLimits> {
406-
if self.acknowledged(Capability::Multiline) {
407-
self.multiline
408-
} else {
409-
None
410-
}
452+
self.acknowledged(Capability::Multiline)
453+
.then(|| {
454+
MultilineLimits::from_str(self.listed.get("draft/multiline")?)
455+
.ok()
456+
})
457+
.flatten()
458+
}
459+
460+
pub fn metadata_limits(&self) -> Option<MetadataLimits> {
461+
self.acknowledged(Capability::Metadata)
462+
.then(|| {
463+
MetadataLimits::from_str(self.listed.get("draft/metadata-2")?)
464+
.ok()
465+
})
466+
.flatten()
411467
}
412468

413469
pub fn contains_multiline_limits(&self) -> bool {

data/src/client.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2876,13 +2876,30 @@ impl Client {
28762876

28772877
// request metadata
28782878
if self.capabilities.acknowledged(Capability::Metadata) {
2879-
// TODO(pounce) have list of currently implemented keys somewhere
2880-
self.handle.try_send(command!(
2881-
"METADATA",
2882-
"*",
2883-
"SUB",
2884-
"display-name",
2885-
))?;
2879+
let mut requested = config
2880+
.metadata
2881+
.preferred_key_strs()
2882+
.map(ToString::to_string)
2883+
.collect::<Vec<String>>();
2884+
2885+
if let Some(limits) =
2886+
self.capabilities.metadata_limits()
2887+
{
2888+
requested.truncate(limits.max_subs);
2889+
}
2890+
2891+
log::debug!(
2892+
"[{}] Requesting subs: {requested:?}",
2893+
self.server
2894+
);
2895+
2896+
if !requested.is_empty() {
2897+
let mut args =
2898+
vec!["*".to_string(), "SUB".to_string()];
2899+
args.extend(requested);
2900+
2901+
self.handle.try_send(command("METADATA", args))?;
2902+
}
28862903
}
28872904

28882905
let channels = self

data/src/config.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub use self::window::Window;
3333
use crate::appearance::theme::Styles;
3434
use crate::appearance::{self, Appearance};
3535
use crate::audio::{self};
36+
use crate::config::metadata::Metadata;
3637
use crate::serde::{
3738
deserialize_f32_positive_float_maybe, deserialize_u8_positive_integer_maybe,
3839
};
@@ -49,6 +50,7 @@ pub mod highlights;
4950
pub mod inclusivities;
5051
pub mod keys;
5152
pub mod logs;
53+
pub mod metadata;
5254
pub mod notification;
5355
pub mod pane;
5456
pub mod platform_specific;
@@ -85,6 +87,7 @@ pub struct Config {
8587
pub logs: Logs,
8688
pub platform_specific: PlatformSpecific,
8789
pub check_for_update_on_launch: bool,
90+
pub metadata: Metadata,
8891
}
8992

9093
impl Default for Config {
@@ -112,6 +115,7 @@ impl Default for Config {
112115
logs: Logs::default(),
113116
platform_specific: PlatformSpecific::default(),
114117
check_for_update_on_launch: true,
118+
metadata: Metadata::default(),
115119
}
116120
}
117121
}
@@ -372,6 +376,7 @@ impl Config {
372376
pub logs: Logs,
373377
pub platform_specific: PlatformSpecific,
374378
pub check_for_update_on_launch: bool,
379+
pub metadata: Metadata,
375380
}
376381

377382
impl Default for Configuration {
@@ -399,6 +404,7 @@ impl Config {
399404
logs: Logs::default(),
400405
platform_specific: PlatformSpecific::default(),
401406
check_for_update_on_launch: true,
407+
metadata: Metadata::default(),
402408
}
403409
}
404410
}
@@ -437,6 +443,7 @@ impl Config {
437443
logs,
438444
platform_specific,
439445
check_for_update_on_launch,
446+
metadata,
440447
} = serde_ignored::deserialize(config, |ignored| {
441448
log::warn!("[config.toml] Ignoring unknown setting: {ignored}");
442449
})
@@ -476,6 +483,7 @@ impl Config {
476483
logs,
477484
platform_specific,
478485
check_for_update_on_launch,
486+
metadata,
479487
})
480488
}
481489

data/src/config/metadata.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use serde::Deserialize;
2+
3+
use crate::metadata;
4+
use crate::metadata::Key::{self, *};
5+
6+
#[derive(Debug, Clone, Deserialize)]
7+
pub struct Metadata {
8+
/// List of keys to subscribe to, in order of preference
9+
pub preferred_keys: Vec<metadata::Key>,
10+
}
11+
12+
impl Default for Metadata {
13+
fn default() -> Self {
14+
Self {
15+
preferred_keys: vec![
16+
DisplayName,
17+
Avatar,
18+
Pronouns,
19+
Homepage,
20+
Color,
21+
Status,
22+
],
23+
}
24+
}
25+
}
26+
27+
impl Metadata {
28+
pub fn preferred_key_strs(&self) -> impl Iterator<Item = &'static str> {
29+
self.preferred_keys.iter().copied().map(Key::to_str)
30+
}
31+
}

0 commit comments

Comments
 (0)