scufflecloud_video_api/services/
stream.rs

1use db_types::models::{Stream, StreamId};
2use db_types::schema::streams;
3use diesel::{ExpressionMethods, SelectableHelper};
4use diesel_async::RunQueryDsl;
5use ext_traits::{OptionExt, RequestExt, ResultExt};
6use petname::Generator;
7use tonic_types::ErrorDetails;
8
9use crate::services::VideoApiSvc;
10
11#[tonic::async_trait]
12impl<G: video_api_traits::Global> pb::scufflecloud::video::api::v1::stream_service_server::StreamService for VideoApiSvc<G> {
13    async fn create(
14        &self,
15        req: tonic::Request<pb::scufflecloud::video::api::v1::StreamCreateRequest>,
16    ) -> Result<tonic::Response<pb::scufflecloud::video::api::v1::StreamCreateResponse>, tonic::Status> {
17        let global = req.global::<G>()?;
18
19        let payload = req.into_inner();
20        let project_id = payload
21            .project_id
22            .parse()
23            .into_tonic_err_with_field_violation("project_id", "invalid ID")?;
24
25        // TODO: check permissions and if project exists
26
27        let name = payload
28            .name
29            .or_else(|| petname::Petnames::large().generate_one(3, "-"))
30            .into_tonic_internal_err("failed to generate random stream name")?;
31
32        let stream = Stream {
33            id: StreamId::new(),
34            project_id,
35            name,
36        };
37
38        let mut conn = global
39            .db()
40            .await
41            .into_tonic_internal_err("failed to get database connection")?;
42
43        diesel::insert_into(streams::dsl::streams)
44            .values(&stream)
45            .execute(&mut conn)
46            .await
47            .into_tonic_internal_err("failed to insert stream into database")?;
48
49        Ok(tonic::Response::new(pb::scufflecloud::video::api::v1::StreamCreateResponse {
50            stream: Some(stream.into()),
51        }))
52    }
53
54    async fn get(
55        &self,
56        req: tonic::Request<pb::scufflecloud::video::api::v1::StreamGetRequest>,
57    ) -> Result<tonic::Response<pb::scufflecloud::video::api::v1::StreamGetResponse>, tonic::Status> {
58        let global = req.global::<G>()?;
59        let payload = req.into_inner();
60        let stream_id = payload.id.parse().into_tonic_err_with_field_violation("id", "invalid ID")?;
61
62        // TODO: check permissions
63
64        let stream = global
65            .stream_loader()
66            .load(stream_id)
67            .await
68            .ok()
69            .into_tonic_internal_err("failed to load stream")?
70            .into_tonic_err(tonic::Code::NotFound, "stream not found", ErrorDetails::new())?;
71
72        Ok(tonic::Response::new(pb::scufflecloud::video::api::v1::StreamGetResponse {
73            stream: Some(stream.into()),
74        }))
75    }
76
77    async fn update(
78        &self,
79        _req: tonic::Request<pb::scufflecloud::video::api::v1::StreamUpdateRequest>,
80    ) -> Result<tonic::Response<pb::scufflecloud::video::api::v1::StreamUpdateResponse>, tonic::Status> {
81        Err(tonic::Status::unimplemented("not implemented yet"))
82    }
83
84    async fn delete(
85        &self,
86        req: tonic::Request<pb::scufflecloud::video::api::v1::StreamDeleteRequest>,
87    ) -> Result<tonic::Response<pb::scufflecloud::video::api::v1::StreamDeleteResponse>, tonic::Status> {
88        let global = req.global::<G>()?;
89
90        let payload = req.into_inner();
91        let stream_id: StreamId = payload.id.parse().into_tonic_err_with_field_violation("id", "invalid ID")?;
92
93        // TODO: check permissions
94
95        let mut conn = global
96            .db()
97            .await
98            .into_tonic_internal_err("failed to get database connection")?;
99
100        let stream = diesel::delete(streams::dsl::streams)
101            .filter(streams::dsl::id.eq(stream_id))
102            .returning(Stream::as_returning())
103            .get_result::<Stream>(&mut conn)
104            .await
105            .into_tonic_internal_err("failed to insert stream into database")?;
106
107        Ok(tonic::Response::new(pb::scufflecloud::video::api::v1::StreamDeleteResponse {
108            stream: Some(stream.into()),
109        }))
110    }
111
112    async fn list(
113        &self,
114        _req: tonic::Request<pb::scufflecloud::video::api::v1::StreamListRequest>,
115    ) -> Result<tonic::Response<pb::scufflecloud::video::api::v1::StreamListResponse>, tonic::Status> {
116        Err(tonic::Status::unimplemented("not implemented yet"))
117    }
118}