1use std::{collections::HashMap, fmt::Debug, marker::PhantomData};
2
3use futures_util::Stream;
4use serde::{Deserialize, Serialize, Serializer};
5use zbus::zvariant::{ObjectPath, OwnedObjectPath, OwnedValue, Type};
6
7use crate::{desktop::HandleToken, proxy::Proxy, Error};
8
9#[derive(Type)]
22#[doc(alias = "org.freedesktop.portal.Session")]
23#[zvariant(signature = "o")]
24pub struct Session<'a, T>(Proxy<'a>, PhantomData<T>)
25where
26 T: SessionPortal;
27
28impl<'a, T> Session<'a, T>
29where
30 T: SessionPortal,
31{
32 pub(crate) async fn new<P>(path: P) -> Result<Session<'a, T>, Error>
36 where
37 P: TryInto<ObjectPath<'a>>,
38 P::Error: Into<zbus::Error>,
39 {
40 let proxy = Proxy::new_desktop_with_path("org.freedesktop.portal.Session", path).await?;
41 Ok(Self(proxy, PhantomData))
42 }
43
44 pub(crate) async fn from_unique_name(
45 handle_token: &HandleToken,
46 ) -> Result<Session<'a, T>, crate::Error> {
47 let path =
48 Proxy::unique_name("/org/freedesktop/portal/desktop/session", handle_token).await?;
49 #[cfg(feature = "tracing")]
50 tracing::info!("Creating a org.freedesktop.portal.Session {}", path);
51 Self::new(path).await
52 }
53
54 #[doc(alias = "Closed")]
60 pub async fn receive_closed(&self) -> Result<impl Stream<Item = ()>, Error> {
61 self.0.signal("Closed").await
62 }
63
64 #[doc(alias = "Close")]
71 pub async fn close(&self) -> Result<(), Error> {
72 self.0.call("Close", &()).await
73 }
74
75 pub(crate) fn path(&self) -> &ObjectPath<'_> {
76 self.0.path()
77 }
78}
79
80impl<T> Serialize for Session<'_, T>
81where
82 T: SessionPortal,
83{
84 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85 where
86 S: Serializer,
87 {
88 ObjectPath::serialize(self.path(), serializer)
89 }
90}
91
92impl<T> Debug for Session<'_, T>
93where
94 T: SessionPortal,
95{
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.debug_tuple("Session")
98 .field(&self.path().as_str())
99 .finish()
100 }
101}
102
103pub trait SessionPortal: crate::Sealed {}
105
106#[derive(Type, Debug)]
108#[zvariant(signature = "dict")]
109pub(crate) struct CreateSessionResponse {
110 pub(crate) session_handle: OwnedObjectPath,
111}
112
113impl<'de> Deserialize<'de> for CreateSessionResponse {
124 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
125 where
126 D: serde::Deserializer<'de>,
127 {
128 let map: HashMap<String, OwnedValue> = HashMap::deserialize(deserializer)?;
129 let session_handle = map.get("session_handle").ok_or_else(|| {
130 serde::de::Error::custom(
131 "CreateSessionResponse failed to deserialize. Couldn't find a session_handle",
132 )
133 })?;
134
135 let path = if let Ok(object_path_str) = session_handle.downcast_ref::<&str>() {
136 ObjectPath::try_from(object_path_str).unwrap()
137 } else if let Ok(object_path) = session_handle.downcast_ref::<ObjectPath<'_>>() {
138 object_path
139 } else {
140 return Err(serde::de::Error::custom(
141 "Wrong session_handle type. Expected `s` or `o`.",
142 ));
143 };
144
145 Ok(Self {
146 session_handle: path.into(),
147 })
148 }
149}