1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use time::{serde::rfc3339, OffsetDateTime};
#[serde_with::serde_as]
#[derive(
Debug, Clone, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize,
)]
#[serde(rename_all = "camelCase")]
/// A Neos session.
pub struct SessionInfo {
/// The name of the session
pub name: String,
#[serde_as(deserialize_as = "serde_with::DefaultOnNull")]
#[serde(default)]
/// The description of the session
///
/// Defaulted to empty string if the API returns none for the session.
pub description: String,
#[serde(rename = "correspondingWorldId")]
/// The ID of the session's world
pub world: Option<crate::model::RecordId>,
/// The tags of the session
pub tags: Vec<String>,
#[serde(rename = "sessionId")]
/// The ID of the session (`S-{uuid}` for example)
pub id: crate::id::Session,
#[serde(rename = "normalizedSessionId")]
/// Normalized (capitalization) version of the session's id (`s-{uuid}` for
/// example)
pub normalized_id: String,
#[serde(rename = "hostUserId")]
/// The ID of the session's host (`U-{uuid}` for example)
pub host_id: Option<crate::id::User>,
/// The ID of the session's host's machine (`{uuid}`)
pub host_machine_id: String,
/// The username of the session's host
pub host_username: String,
/// A hash to check if the session is compatible (version, plugins, etc)
pub compatibility_hash: String,
/// The version of Neos that session is hosting
pub neos_version: String,
#[serde(rename = "headlessHost")]
/// If the host is a headless (server) instance or not.
pub is_headless_host: bool,
#[serde(rename = "sessionURLs")]
/// Links to the session, in custom protocols such as `lnl-nat:///` and
/// `neos-steam://`
pub urls: Vec<String>,
#[serde(rename = "sessionUsers")]
/// A list of the session's users very basic details.
#[cfg_attr(
not(feature = "debug"),
serde_as(as = "serde_with::VecSkipError<_>")
)]
pub users: Vec<crate::model::SessionUser>,
/// A link to the thumbnail of the session.
///
/// Can be `https://` or `neosdb://` for example
pub thumbnail: Option<crate::AssetUrl>,
/// The amount of users that have joined the session
pub joined_users: u8,
/// The amount of users that are focused on the session
pub active_users: u8,
/// Total of `joined_users`..?
pub total_joined_users: u8,
/// Total of `active_users`...?
pub total_active_users: u8,
/// The max limit of users in the session
pub max_users: u8,
#[serde(rename = "mobileFriendly")]
/// If the session is suitable for mobile clients
pub is_mobile_friendly: bool,
#[serde(with = "rfc3339")]
/// When the session began
pub session_begin_time: OffsetDateTime,
#[serde(rename = "lastUpdate")]
#[serde(with = "rfc3339")]
/// When the session was last updated
pub last_update_time: OffsetDateTime,
#[serde(default)]
#[serde(with = "crate::util::opt_rfc3339")]
/// Since when has the host been away most likely
pub away_since: Option<OffsetDateTime>,
/// Who can access the session
pub access_level: crate::model::SessionAccessLevel,
/// If the session has ended
#[serde_as(deserialize_as = "serde_with::DefaultOnNull")]
#[serde(default = "has_ended_default")]
pub has_ended: bool,
/// If the session is valid
#[serde_as(deserialize_as = "serde_with::DefaultOnNull")]
#[serde(default)]
pub is_valid: bool,
#[serde_as(deserialize_as = "serde_with::DefaultOnNull")]
#[serde(default)]
/// Sessions that this session is a child of
///
/// Defaulted to empty vector if the API returns none for the session.
pub parent_session_ids: Vec<crate::id::Session>,
#[serde_as(deserialize_as = "serde_with::DefaultOnNull")]
#[serde(default)]
/// Sessions that are the child of this session
///
/// Defaulted to empty vector if the API returns none for the session.
pub nested_session_ids: Vec<crate::id::Session>,
}
// If the field is missing, it probably has ended...
const fn has_ended_default() -> bool { true }
#[must_use]
/// Tries to strip XML tags out of a string.
///
/// Not using an actual XML parser though, just a simple `<` and `>` character
/// search.
fn bad_xml_strip(str: &str) -> String {
let start_indexes = str.match_indices('<');
let end_indexes = str.match_indices('>');
let mut stripped_name = str.to_owned();
start_indexes.rev().zip(end_indexes.rev()).for_each(
|((start, _), (end, _))| {
if start < end {
stripped_name.replace_range(start..=end, "");
}
},
);
stripped_name
}
impl SessionInfo {
#[must_use]
/// Tries to remove the XML notation-like parts from a session's name.
///
/// Note that this is imperfect and not using an actual XML parser to remain
/// lightweight.
pub fn stripped_name(&self) -> String { bad_xml_strip(&self.name) }
}