From c94d490cb8971a69b1497d094db0e99d1f2e82b3 Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 17:37:19 +0900 Subject: [PATCH 1/9] =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E4=BB=A5?= =?UTF-8?q?=E5=A4=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/explore/error.rs | 2 -- server/src/traq/channel.rs | 5 ++++ server/src/traq/channel/error.rs | 17 +++++++++++ server/src/traq/channel/impl.rs | 50 ++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 server/src/traq/channel/error.rs create mode 100644 server/src/traq/channel/impl.rs diff --git a/server/src/explore/error.rs b/server/src/explore/error.rs index 5463e430..bcc4b001 100644 --- a/server/src/explore/error.rs +++ b/server/src/explore/error.rs @@ -1,5 +1,3 @@ -// todo: 仮置き -/// infallible #[derive(Debug, Clone, thiserror::Error)] pub enum Error { #[error("exploration field stream closed")] diff --git a/server/src/traq/channel.rs b/server/src/traq/channel.rs index e1f43fbe..ca99d49f 100644 --- a/server/src/traq/channel.rs +++ b/server/src/traq/channel.rs @@ -3,6 +3,9 @@ use serde::{Deserialize, Serialize}; use crate::prelude::IntoStatus; +mod r#impl; +pub mod error; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)] #[serde(transparent)] pub struct TraqChannelId(pub uuid::Uuid); @@ -27,6 +30,8 @@ pub trait TraqChannelService: Send + Sync + 'static { ) -> BoxFuture<'a, Result, Self::Error>>; } +pub struct TraqChannelServiceImpl; + #[allow(clippy::type_complexity)] pub trait ProvideTraqChannelService: Send + Sync + 'static { type Context; diff --git a/server/src/traq/channel/error.rs b/server/src/traq/channel/error.rs new file mode 100644 index 00000000..4cd13d79 --- /dev/null +++ b/server/src/traq/channel/error.rs @@ -0,0 +1,17 @@ +#[derive(Debug, Clone, thiserror::Error)] +pub enum Error { + #[error("request send error")] + RequestSendError, + #[error("parse error")] + ParseError, + #[error("status")] + Status(#[from] tonic::Status), +} + +impl From for tonic::Status { + fn from(value: Error) -> Self { + tonic::Status::internal(value.to_string()) + } +} + +pub type Result = std::result::Result; \ No newline at end of file diff --git a/server/src/traq/channel/impl.rs b/server/src/traq/channel/impl.rs new file mode 100644 index 00000000..3eb79fff --- /dev/null +++ b/server/src/traq/channel/impl.rs @@ -0,0 +1,50 @@ +use futures::FutureExt; + +use crate::{prelude::IntoStatus, traq::{ + bot::{BuildRequestAsBotParams, ProvideTraqBotService}, + TraqHost, +}}; + +impl super::TraqChannelService for super::TraqChannelServiceImpl +where + Context: ProvideTraqBotService + AsRef, +{ + type Error = super::error::Error; + + fn get_all_channels<'a>( + &'a self, + ctx: &'a Context, + params: super::GetAllChannelsParams, + ) -> futures::future::BoxFuture<'a, Result, Self::Error>> { + get_all_channels(ctx, params).boxed() + } +} + +async fn get_all_channels<'a, Context>( + ctx: &'a Context, + params: super::GetAllChannelsParams, +) -> Result, super::error::Error> +where + Context: ProvideTraqBotService + AsRef, +{ + // send request + let traq_host: &TraqHost = ctx.as_ref(); + + let params = BuildRequestAsBotParams { + method: http::Method::GET, + uri: &format!("https://{}/api/v3/channels", traq_host), + }; + + let result = ctx + .build_request_as_bot(params) + .await + .map_err(IntoStatus::into_status)? + .send() + .await + .map_err(|_|super::error::Error::RequestSendError)? + .json::>() + .await + .map_err(|_|super::error::Error::ParseError)?; + + Ok(result) +} \ No newline at end of file From 35e21a78fe379ed5931cd6f706e374d22e63f307 Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 18:47:50 +0900 Subject: [PATCH 2/9] =?UTF-8?q?Vec=E3=81=AE?= =?UTF-8?q?=E6=A7=8B=E7=AF=89=E3=81=BE=E3=81=A7=E3=80=82=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E3=81=AE=E6=89=B1=E3=81=84=E5=90=88=E3=81=A3=E3=81=A6?= =?UTF-8?q?=E3=82=8B=E3=81=8B=E3=82=8F=E3=81=8B=E3=82=89=E3=81=9A=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/traq/channel.rs | 2 +- server/src/traq/channel/error.rs | 2 +- server/src/traq/channel/impl.rs | 107 +++++++++++++++++++++++++++---- 3 files changed, 96 insertions(+), 15 deletions(-) diff --git a/server/src/traq/channel.rs b/server/src/traq/channel.rs index ca99d49f..7ae12328 100644 --- a/server/src/traq/channel.rs +++ b/server/src/traq/channel.rs @@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize}; use crate::prelude::IntoStatus; -mod r#impl; pub mod error; +mod r#impl; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)] #[serde(transparent)] diff --git a/server/src/traq/channel/error.rs b/server/src/traq/channel/error.rs index 4cd13d79..74200cb1 100644 --- a/server/src/traq/channel/error.rs +++ b/server/src/traq/channel/error.rs @@ -14,4 +14,4 @@ impl From for tonic::Status { } } -pub type Result = std::result::Result; \ No newline at end of file +pub type Result = std::result::Result; diff --git a/server/src/traq/channel/impl.rs b/server/src/traq/channel/impl.rs index 3eb79fff..fbaffbfc 100644 --- a/server/src/traq/channel/impl.rs +++ b/server/src/traq/channel/impl.rs @@ -1,9 +1,14 @@ +use std::collections::HashMap; + use futures::FutureExt; -use crate::{prelude::IntoStatus, traq::{ - bot::{BuildRequestAsBotParams, ProvideTraqBotService}, - TraqHost, -}}; +use crate::{ + prelude::IntoStatus, + traq::{ + bot::{BuildRequestAsBotParams, ProvideTraqBotService}, + TraqHost, + }, +}; impl super::TraqChannelService for super::TraqChannelServiceImpl where @@ -20,9 +25,9 @@ where } } -async fn get_all_channels<'a, Context>( - ctx: &'a Context, - params: super::GetAllChannelsParams, +async fn get_all_channels( + ctx: &Context, + _params: super::GetAllChannelsParams, ) -> Result, super::error::Error> where Context: ProvideTraqBotService + AsRef, @@ -32,7 +37,7 @@ where let params = BuildRequestAsBotParams { method: http::Method::GET, - uri: &format!("https://{}/api/v3/channels", traq_host), + uri: &format!("https://{}/api/v3/channels?include-dm=false", traq_host), }; let result = ctx @@ -41,10 +46,86 @@ where .map_err(IntoStatus::into_status)? .send() .await - .map_err(|_|super::error::Error::RequestSendError)? - .json::>() + .map_err(|_| super::error::Error::RequestSendError)? + .json::() .await - .map_err(|_|super::error::Error::ParseError)?; + .map_err(|_| super::error::Error::ParseError)?; + + // build full paths + let mut channels = HashMap::new(); + + for channel in result.public { + let node = ChannelNode { + is_root: channel.parent_id.is_none(), + name: channel.name, + children: channel.children, + }; + + channels.insert(channel.id, node); + } + + let root_channels = channels + .values() + .filter(|node| node.is_root) + .cloned() + .collect::>(); - Ok(result) -} \ No newline at end of file + Ok(root_channels + .iter() + .flat_map(|node| node.dfs("", &channels)) + .collect::>()) +} + +#[derive(serde::Deserialize)] +struct TraqChannelRaw { + public: Vec, + dm: Vec, +} + +#[derive(serde::Deserialize)] +struct PublicChannel { + id: super::TraqChannelId, + parent_id: Option, + archived: bool, + force: bool, + topic: String, + name: String, + children: Vec, +} + +#[derive(serde::Deserialize)] +struct DmChannel { + id: super::TraqChannelId, + user_id: crate::traq::user::TraqUserId, +} + +#[derive(Clone)] +struct ChannelNode { + is_root: bool, + name: String, + children: Vec, +} + +impl ChannelNode { + fn dfs( + &self, + path: &str, + channels: &HashMap, + ) -> Vec { + // current channel + let path = format!("{}/{}", path, self.name); + + let mut result = vec![super::TraqChannel { + id: super::TraqChannelId(uuid::Uuid::new_v4()), + path: path.clone(), + }]; + + self.children + .iter() + .flat_map(|child| channels.get(child)) + .flat_map(|child_node| child_node.dfs(&path, channels)) + .for_each(|channel| result.push(channel)); + + result + } +} From c3a50a11c5c6dd680e3cf14a97b11bd39248047c Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 20:55:20 +0900 Subject: [PATCH 3/9] =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=82=92tracing?= =?UTF-8?q?=E3=81=AB=E6=B5=81=E3=81=97=E3=81=9F=E3=80=82From=20for?= =?UTF-8?q?=20tonic::Status=E3=81=AE=E4=B8=AD=E8=BA=AB=E3=82=92=E6=9B=B8?= =?UTF-8?q?=E3=81=84=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/traq/channel/error.rs | 6 +++++- server/src/traq/channel/impl.rs | 16 +++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/server/src/traq/channel/error.rs b/server/src/traq/channel/error.rs index 74200cb1..c5ab59ad 100644 --- a/server/src/traq/channel/error.rs +++ b/server/src/traq/channel/error.rs @@ -10,7 +10,11 @@ pub enum Error { impl From for tonic::Status { fn from(value: Error) -> Self { - tonic::Status::internal(value.to_string()) + match value { + Error::RequestSendError => tonic::Status::internal("request sending error"), + Error::ParseError => tonic::Status::internal("parsing error"), + Error::Status(status) => status, + } } } diff --git a/server/src/traq/channel/impl.rs b/server/src/traq/channel/impl.rs index fbaffbfc..60e6a90c 100644 --- a/server/src/traq/channel/impl.rs +++ b/server/src/traq/channel/impl.rs @@ -46,10 +46,16 @@ where .map_err(IntoStatus::into_status)? .send() .await - .map_err(|_| super::error::Error::RequestSendError)? + .map_err(|e| { + tracing::error!(error = &e as &dyn std::error::Error); + super::error::Error::RequestSendError + })? .json::() .await - .map_err(|_| super::error::Error::ParseError)?; + .map_err(|e| { + tracing::warn!(error = &e as &dyn std::error::Error); + super::error::Error::ParseError + })?; // build full paths let mut channels = HashMap::new(); @@ -76,13 +82,13 @@ where .collect::>()) } -#[derive(serde::Deserialize)] +#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] struct TraqChannelRaw { public: Vec, dm: Vec, } -#[derive(serde::Deserialize)] +#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] struct PublicChannel { id: super::TraqChannelId, parent_id: Option, @@ -93,7 +99,7 @@ struct PublicChannel { children: Vec, } -#[derive(serde::Deserialize)] +#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] struct DmChannel { id: super::TraqChannelId, user_id: crate::traq::user::TraqUserId, From 260f9aeedcabd55ff94ef2dab62314f13faf6a64 Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 21:32:38 +0900 Subject: [PATCH 4/9] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AAclone=E3=82=92?= =?UTF-8?q?=E6=B6=88=E3=81=97=E3=81=9F=E3=80=82channels=E3=82=92=E3=82=A4?= =?UTF-8?q?=E3=83=86=E3=83=AC=E3=83=BC=E3=82=BF=E3=83=BC=E3=81=A7=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E4=BD=9C=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/traq/channel/impl.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/server/src/traq/channel/impl.rs b/server/src/traq/channel/impl.rs index 60e6a90c..672dd9e6 100644 --- a/server/src/traq/channel/impl.rs +++ b/server/src/traq/channel/impl.rs @@ -58,22 +58,24 @@ where })?; // build full paths - let mut channels = HashMap::new(); - - for channel in result.public { - let node = ChannelNode { - is_root: channel.parent_id.is_none(), - name: channel.name, - children: channel.children, - }; - - channels.insert(channel.id, node); - } + let channels = result + .public + .into_iter() + .map(|ch| { + ( + ch.id, + ChannelNode { + is_root: ch.parent_id.is_none(), + name: ch.name, + children: ch.children, + }, + ) + }) + .collect::>(); let root_channels = channels .values() .filter(|node| node.is_root) - .cloned() .collect::>(); Ok(root_channels From 4b36025376f6e93d3339da02b4195696d4c18f37 Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 23:03:52 +0900 Subject: [PATCH 5/9] =?UTF-8?q?=E5=98=98id=E3=82=92=E4=BD=9C=E3=81=A3?= =?UTF-8?q?=E3=81=A6=E3=81=97=E3=81=BE=E3=81=A3=E3=81=A6=E3=81=9F=E3=81=AE?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=E3=80=82=E3=83=81=E3=83=A3=E3=83=B3?= =?UTF-8?q?=E3=83=8D=E3=83=AB=E3=83=91=E3=82=B9=E3=82=92#=E3=81=8B?= =?UTF-8?q?=E3=82=89=E5=A7=8B=E3=82=81=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/traq/channel/impl.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/src/traq/channel/impl.rs b/server/src/traq/channel/impl.rs index 672dd9e6..afc78361 100644 --- a/server/src/traq/channel/impl.rs +++ b/server/src/traq/channel/impl.rs @@ -66,6 +66,7 @@ where ch.id, ChannelNode { is_root: ch.parent_id.is_none(), + id: ch.id, name: ch.name, children: ch.children, }, @@ -80,7 +81,7 @@ where Ok(root_channels .iter() - .flat_map(|node| node.dfs("", &channels)) + .flat_map(|node| node.dfs("#", &channels)) .collect::>()) } @@ -110,6 +111,7 @@ struct DmChannel { #[derive(Clone)] struct ChannelNode { is_root: bool, + id: super::TraqChannelId, name: String, children: Vec, } @@ -124,7 +126,7 @@ impl ChannelNode { let path = format!("{}/{}", path, self.name); let mut result = vec![super::TraqChannel { - id: super::TraqChannelId(uuid::Uuid::new_v4()), + id: self.id, path: path.clone(), }]; From a3dfc03078c68371855ee6f1ddaf1921011a6c16 Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 23:06:05 +0900 Subject: [PATCH 6/9] =?UTF-8?q?TraqChannelServiceImpl=E3=81=ABDebug,=20Clo?= =?UTF-8?q?ne,=20Copy,=20Default=E3=82=92=E5=B0=8E=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/traq/channel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/traq/channel.rs b/server/src/traq/channel.rs index 7ae12328..657bb89d 100644 --- a/server/src/traq/channel.rs +++ b/server/src/traq/channel.rs @@ -30,6 +30,7 @@ pub trait TraqChannelService: Send + Sync + 'static { ) -> BoxFuture<'a, Result, Self::Error>>; } +#[derive(Debug, Clone, Copy, Default)] pub struct TraqChannelServiceImpl; #[allow(clippy::type_complexity)] From 5c9a5ed4daebac03d64a0c2b43761c8df2dc593a Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 23:21:36 +0900 Subject: [PATCH 7/9] =?UTF-8?q?=E3=83=91=E3=82=B9=E3=81=8C"#/"=E5=A7=8B?= =?UTF-8?q?=E3=81=BE=E3=82=8A=E3=81=AB=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=97?= =?UTF-8?q?=E3=81=BE=E3=81=86=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/traq/channel/impl.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/src/traq/channel/impl.rs b/server/src/traq/channel/impl.rs index afc78361..92dfbe10 100644 --- a/server/src/traq/channel/impl.rs +++ b/server/src/traq/channel/impl.rs @@ -81,7 +81,7 @@ where Ok(root_channels .iter() - .flat_map(|node| node.dfs("#", &channels)) + .flat_map(|node| node.dfs("", &channels)) .collect::>()) } @@ -123,7 +123,11 @@ impl ChannelNode { channels: &HashMap, ) -> Vec { // current channel - let path = format!("{}/{}", path, self.name); + let path = if path == "#" { + format!("#{}", self.name) + } else { + format!("{}/{}", path, self.name) + }; let mut result = vec![super::TraqChannel { id: self.id, From c9f04ea1ba9378e87a8c312a587988f40596465d Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 23:32:37 +0900 Subject: [PATCH 8/9] =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E7=9B=B4=E3=81=97=E5=BF=98=E3=82=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/traq/channel/impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/traq/channel/impl.rs b/server/src/traq/channel/impl.rs index 92dfbe10..112c348e 100644 --- a/server/src/traq/channel/impl.rs +++ b/server/src/traq/channel/impl.rs @@ -123,7 +123,7 @@ impl ChannelNode { channels: &HashMap, ) -> Vec { // current channel - let path = if path == "#" { + let path = if path.is_empty() { format!("#{}", self.name) } else { format!("{}/{}", path, self.name) From 0ac29a3eb32e193c4eacf9d47b92b908ce1800fc Mon Sep 17 00:00:00 2001 From: helgev Date: Sat, 25 Jan 2025 23:45:42 +0900 Subject: [PATCH 9/9] =?UTF-8?q?=E3=82=A4=E3=83=86=E3=83=AC=E3=83=BC?= =?UTF-8?q?=E3=82=BF=E3=83=BC=E3=81=AB=E3=81=BE=E3=81=A8=E3=82=81=E3=81=A6?= =?UTF-8?q?=E3=81=8B=E3=82=89extend=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/traq/channel/impl.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/src/traq/channel/impl.rs b/server/src/traq/channel/impl.rs index 112c348e..e236e4d4 100644 --- a/server/src/traq/channel/impl.rs +++ b/server/src/traq/channel/impl.rs @@ -134,11 +134,12 @@ impl ChannelNode { path: path.clone(), }]; - self.children + let it = self + .children .iter() .flat_map(|child| channels.get(child)) - .flat_map(|child_node| child_node.dfs(&path, channels)) - .for_each(|channel| result.push(channel)); + .flat_map(|child_node| child_node.dfs(&path, channels)); + result.extend(it); result }