From 79e2f730ccb1b645dcf975a7932574e7779c5996 Mon Sep 17 00:00:00 2001 From: Lyssieth Date: Tue, 28 Nov 2023 05:39:38 +0200 Subject: [PATCH] fix: fix json serialization --- rave/src/subsonic/mod.rs | 199 ++++++++++++------------ rave/src/subsonic/types/album.rs | 24 +-- rave/src/subsonic/types/artist.rs | 12 +- rave/src/subsonic/types/child.rs | 44 +++--- rave/src/subsonic/types/music_folder.rs | 4 +- 5 files changed, 140 insertions(+), 143 deletions(-) diff --git a/rave/src/subsonic/mod.rs b/rave/src/subsonic/mod.rs index 21a6580..f489fde 100644 --- a/rave/src/subsonic/mod.rs +++ b/rave/src/subsonic/mod.rs @@ -1,4 +1,5 @@ use poem::{http::StatusCode, IntoResponse, Response}; +use serde::ser::SerializeStruct; use serde::{Serialize, Serializer}; use crate::authentication::VersionTriple; @@ -12,130 +13,126 @@ pub use types::artist::Artist; pub use types::child::Child; pub use types::music_folder::MusicFolder; -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone)] pub struct SubsonicResponse { pub status: ResponseStatus, pub version: VersionTriple, - #[serde( - skip_serializing_if = "SubResponseType::is_empty", - serialize_with = "serialize_without_root", - flatten - )] pub value: Box, } -fn serialize_without_root(value: &SubResponseType, s: S) -> Result -where - S: Serializer, -{ - match value { - SubResponseType::MusicFolders { music_folders } => { - #[derive(Serialize)] - struct MF { - id: String, - name: String, - } +impl Serialize for SubsonicResponse { + fn serialize(&self, s: S) -> Result + where + S: Serializer, + { + if self.value.is_empty() { + let mut empty = s.serialize_struct("subsonic-response", 2)?; + empty.serialize_field("status", &self.status)?; + empty.serialize_field("version", &self.version)?; + return empty.end(); + } - impl From for MF { - fn from(value: MusicFolder) -> Self { - Self { - id: value.id, - name: value.name, - } + let mut s = s.serialize_struct("subsonic-response", 3)?; + s.serialize_field("status", &self.status)?; + s.serialize_field("version", &self.version)?; + match self.value.as_ref() { + SubResponseType::MusicFolders { music_folders } => { + s.serialize_field("musicFolders", music_folders)?; + } + SubResponseType::Error(error) => { + s.serialize_field("error", error)?; + } + SubResponseType::License { valid } => { + #[derive(Serialize)] + struct License { + #[serde(rename = "valid")] + valid: bool, } - } - #[derive(Serialize)] - struct MusicFolders { - #[serde(rename = "musicFolders")] - music_folders: Vec, + s.serialize_field("license", &License { valid: *valid })?; } + SubResponseType::AlbumList { albums } => { + #[derive(Serialize)] + struct AlbumList<'a> { + #[serde(rename = "album")] + albums: &'a Vec, + } - MusicFolders { - music_folders: music_folders.iter().map(|v| v.clone().into()).collect(), - } - .serialize(s) - } - SubResponseType::Error(error) => error.serialize(s), - SubResponseType::License { valid } => valid.serialize(s), - SubResponseType::AlbumList { albums } => { - #[derive(Serialize)] - struct AlbumList { - #[serde(rename = "album")] - albums: Vec, + s.serialize_field("albumList", &AlbumList { albums })?; } + SubResponseType::AlbumList2 { albums } => { + #[derive(Serialize)] + struct AlbumList2<'a> { + #[serde(rename = "album")] + albums: &'a Vec, + } - AlbumList { - albums: albums.clone(), - } - .serialize(s) - } - SubResponseType::AlbumList2 { albums } => { - #[derive(Serialize)] - struct AlbumList2 { - #[serde(rename = "album")] - albums: Vec, + s.serialize_field("albumList2", &AlbumList2 { albums })?; } + SubResponseType::Album { album, songs } => { + #[derive(Serialize)] + struct AlbumWithSongs<'a> { + #[serde(flatten)] + album: &'a Album, + #[serde(rename = "song")] + songs: &'a Vec, + } - AlbumList2 { - albums: albums.clone(), - } - .serialize(s) - } - SubResponseType::Album { album, songs } => { - #[derive(Serialize)] - #[serde(rename = "album")] - struct AlbumWithSongs<'a> { - #[serde(flatten)] - album: &'a Album, - #[serde(rename = "song")] - songs: &'a Vec, + s.serialize_field("album", &AlbumWithSongs { album, songs })?; } + SubResponseType::ScanStatus { scanning, count } => { + #[derive(Serialize)] + struct ScanStatus { + scanning: bool, + count: u64, + } - AlbumWithSongs { album, songs }.serialize(s) - } - SubResponseType::ScanStatus { scanning, count } => { - #[derive(Serialize)] - #[serde(rename = "scanStatus")] - struct ScanStatus { - #[serde(rename = "scanning")] - scanning: bool, - #[serde(rename = "count")] - count: u64, + s.serialize_field( + "scanStatus", + &ScanStatus { + scanning: *scanning, + count: *count, + }, + )?; } - - ScanStatus { - scanning: *scanning, - count: *count, - } - .serialize(s) - } - SubResponseType::SearchResult3 { - artists, - albums, - songs, - } => { - #[derive(Serialize)] - #[serde(rename = "searchResult3")] - struct SearchResult3<'a> { - #[serde(rename = "artist")] - artists: &'a Vec, - #[serde(rename = "album")] - albums: &'a Vec, - #[serde(rename = "song")] - songs: &'a Vec, - } - - SearchResult3 { + SubResponseType::SearchResult3 { artists, albums, songs, + } => { + #[derive(Serialize)] + struct SearchResult3<'a> { + #[serde(rename = "artist")] + artists: &'a Vec, + #[serde(rename = "album")] + albums: &'a Vec, + #[serde(rename = "song")] + songs: &'a Vec, + } + + s.serialize_field( + "searchResult3", + &SearchResult3 { + artists, + albums, + songs, + }, + )?; } - .serialize(s) + SubResponseType::Artists { artists } => { + #[derive(Serialize)] + struct Artists<'a> { + #[serde(rename = "artist")] + artists: &'a Vec, + } + + s.serialize_field("artists", &Artists { artists })?; + } + SubResponseType::Artist { artist } => s.serialize_field("artist", artist)?, + SubResponseType::Empty => unreachable!("Empty response should be handled above"), } - SubResponseType::Artists { artists } => artists.serialize(s), - SubResponseType::Artist { artist } => artist.serialize(s), - SubResponseType::Empty => s.serialize_none(), + + s.end() } } diff --git a/rave/src/subsonic/types/album.rs b/rave/src/subsonic/types/album.rs index fd537ca..127f321 100644 --- a/rave/src/subsonic/types/album.rs +++ b/rave/src/subsonic/types/album.rs @@ -4,29 +4,29 @@ use time::format_description::well_known::Iso8601; #[derive(Debug, Clone, Serialize)] pub struct Album { - #[serde(rename = "@id")] + #[serde(rename = "id")] pub id: String, - #[serde(rename = "@name")] + #[serde(rename = "name")] pub name: String, - #[serde(rename = "@artist", skip_serializing_if = "Option::is_none")] + #[serde(rename = "artist", skip_serializing_if = "Option::is_none")] pub artist: Option, - #[serde(rename = "@artistId", skip_serializing_if = "Option::is_none")] + #[serde(rename = "artistId", skip_serializing_if = "Option::is_none")] pub artist_id: Option, - #[serde(rename = "@coverArt", skip_serializing_if = "Option::is_none")] + #[serde(rename = "coverArt", skip_serializing_if = "Option::is_none")] pub cover_art_id: Option, - #[serde(rename = "@songCount")] + #[serde(rename = "songCount")] pub song_count: u64, - #[serde(rename = "@duration")] + #[serde(rename = "duration")] pub duration: u64, - #[serde(rename = "@playCount")] + #[serde(rename = "playCount")] pub play_count: u64, - #[serde(rename = "@created")] + #[serde(rename = "created")] pub created: String, - #[serde(rename = "@starred", skip_serializing_if = "Option::is_none")] + #[serde(rename = "starred", skip_serializing_if = "Option::is_none")] pub starred: Option, - #[serde(rename = "@year", skip_serializing_if = "Option::is_none")] + #[serde(rename = "year", skip_serializing_if = "Option::is_none")] pub year: Option, - #[serde(rename = "@genre", skip_serializing_if = "Option::is_none")] + #[serde(rename = "genre", skip_serializing_if = "Option::is_none")] pub genre: Option, } diff --git a/rave/src/subsonic/types/artist.rs b/rave/src/subsonic/types/artist.rs index e7d8cec..df75ab2 100644 --- a/rave/src/subsonic/types/artist.rs +++ b/rave/src/subsonic/types/artist.rs @@ -4,17 +4,17 @@ use time::format_description::well_known::Iso8601; #[derive(Debug, Clone, Serialize)] pub struct Artist { - #[serde(rename = "@id")] + #[serde(rename = "id")] pub id: String, - #[serde(rename = "@name")] + #[serde(rename = "name")] pub name: String, - #[serde(rename = "@coverArtId")] + #[serde(rename = "coverArtId")] pub cover_art: Option, - #[serde(rename = "@artistImageUrl")] + #[serde(rename = "artistImageUrl")] pub artist_image_url: Option, - #[serde(rename = "@albumCount")] + #[serde(rename = "albumCount")] pub album_count: u64, - #[serde(rename = "@starred")] + #[serde(rename = "starred")] pub starred: Option, } diff --git a/rave/src/subsonic/types/child.rs b/rave/src/subsonic/types/child.rs index c109afa..a7147e1 100644 --- a/rave/src/subsonic/types/child.rs +++ b/rave/src/subsonic/types/child.rs @@ -6,49 +6,49 @@ use crate::subsonic::{Album, Artist}; #[derive(Debug, Clone, Serialize)] pub struct Child { - #[serde(rename = "@id")] + #[serde(rename = "id")] pub id: String, - #[serde(rename = "@isDir")] + #[serde(rename = "isDir")] pub is_dir: bool, - #[serde(rename = "@title")] + #[serde(rename = "title")] pub title: String, - #[serde(rename = "@album", skip_serializing_if = "Option::is_none")] + #[serde(rename = "album", skip_serializing_if = "Option::is_none")] pub album: Option, - #[serde(rename = "@track", skip_serializing_if = "Option::is_none")] + #[serde(rename = "track", skip_serializing_if = "Option::is_none")] pub track: Option, - #[serde(rename = "@year", skip_serializing_if = "Option::is_none")] + #[serde(rename = "year", skip_serializing_if = "Option::is_none")] pub year: Option, - #[serde(rename = "@coverArtId", skip_serializing_if = "Option::is_none")] + #[serde(rename = "coverArtId", skip_serializing_if = "Option::is_none")] pub cover_art_id: Option, - #[serde(rename = "@size")] + #[serde(rename = "size")] pub size: u64, - #[serde(rename = "@contentType")] + #[serde(rename = "contentType")] pub content_type: String, - #[serde(rename = "@suffix")] + #[serde(rename = "suffix")] pub suffix: String, - #[serde(rename = "@starred", skip_serializing_if = "Option::is_none")] + #[serde(rename = "starred", skip_serializing_if = "Option::is_none")] pub starred: Option, - #[serde(rename = "@duration")] + #[serde(rename = "duration")] pub duration: u64, - #[serde(rename = "@bitRate", skip_serializing_if = "Option::is_none")] + #[serde(rename = "bitRate", skip_serializing_if = "Option::is_none")] pub bit_rate: Option, - #[serde(rename = "@path")] + #[serde(rename = "path")] pub path: String, - #[serde(rename = "@playCount")] + #[serde(rename = "playCount")] pub play_count: u64, - #[serde(rename = "@discNumber")] + #[serde(rename = "discNumber")] pub disc_number: u32, - #[serde(rename = "@created")] + #[serde(rename = "created")] pub created: String, - #[serde(rename = "@albumId", skip_serializing_if = "Option::is_none")] + #[serde(rename = "albumId", skip_serializing_if = "Option::is_none")] pub album_id: Option, - #[serde(rename = "@artistId", skip_serializing_if = "Option::is_none")] + #[serde(rename = "artistId", skip_serializing_if = "Option::is_none")] pub artist_id: Option, - #[serde(rename = "@artist")] + #[serde(rename = "artist")] pub artist: String, - #[serde(rename = "@type")] + #[serde(rename = "type")] pub child_type: String, - #[serde(rename = "@isVideo")] + #[serde(rename = "isVideo")] pub is_video: bool, } diff --git a/rave/src/subsonic/types/music_folder.rs b/rave/src/subsonic/types/music_folder.rs index d74c171..53b5e2f 100644 --- a/rave/src/subsonic/types/music_folder.rs +++ b/rave/src/subsonic/types/music_folder.rs @@ -3,9 +3,9 @@ use serde::Serialize; #[derive(Debug, Clone, Serialize)] pub struct MusicFolder { - #[serde(rename = "@id")] + #[serde(rename = "id")] pub id: String, - #[serde(rename = "@name")] + #[serde(rename = "name")] pub name: String, }