@@ -18,15 +18,17 @@ use conf::Conf;
1818use cookie:: time:: { Duration , OffsetDateTime } ;
1919use futures:: { StreamExt , TryStreamExt } ;
2020use lettre:: {
21- AsyncSmtpTransport , AsyncTransport , Message , Tokio1Executor , message:: header:: ContentType , transport:: smtp:: authentication:: { Credentials , Mechanism :: Login }
21+ AsyncSmtpTransport , AsyncTransport , Message , Tokio1Executor , message:: header:: ContentType , transport:: smtp:: authentication:: { Credentials }
2222} ;
2323use serde_json:: json;
24+ use tokio:: sync:: { broadcast:: Sender } ;
25+ use tokio_stream:: wrappers:: errors:: BroadcastStreamRecvError ;
2426use tower:: builder:: ServiceBuilder ;
25- use tower_http:: { compression :: CompressionLayer , cors:: { Any , CorsLayer } , services:: ServeDir , trace:: TraceLayer } ;
27+ use tower_http:: { cors:: { Any , CorsLayer } , services:: ServeDir , trace:: TraceLayer } ;
2628use web_push:: { ContentEncoding , HyperWebPushClient , SubscriptionInfo , VapidSignatureBuilder , WebPushClient , WebPushMessageBuilder } ;
27- use std:: { env, fs:: { self , File } , net:: { SocketAddr , TcpListener } } ;
29+ use std:: { env, fs:: { self , File } , net:: { SocketAddr , TcpListener } , ops :: Deref , sync :: Arc } ;
2830use std:: collections:: HashMap ;
29- use tokio_postgres:: { IsolationLevel , types:: { ToSql , Type } } ;
31+ use tokio_postgres:: { AsyncMessage , Client , IsolationLevel , types:: { ToSql , Type } } ;
3032use deadpool_postgres:: { Pool , Transaction } ;
3133use tracing_subscriber:: { layer:: SubscriberExt , util:: SubscriberInitExt } ;
3234use biscuit_auth:: { KeyPair , PrivateKey , Biscuit , builder:: * } ;
@@ -77,6 +79,8 @@ struct AppState {
7779 read_pool : Pool ,
7880 write_pool : Pool ,
7981 config : HttpgConfig ,
82+ tx : Sender < AsyncMessage > ,
83+ client : Arc < Client > ,
8084}
8185
8286#[ tokio:: main]
@@ -93,11 +97,39 @@ async fn main() -> Result<(), HttpgError> {
9397
9498 let read_pool = httpg_config. pg . read_pool ( ) ?;
9599 let write_pool = httpg_config. pg . write_pool ( ) ?;
100+
101+ let ( client, mut conn) = httpg_config. pg . connect ( ) . await ?;
102+
103+ let ( tx, _rx) = tokio:: sync:: broadcast:: channel :: < AsyncMessage > ( 16 ) ;
104+
105+ let mut stream = futures:: stream:: poll_fn ( move |cx| conn. poll_message ( cx) ) ;
106+
107+ let wrapped_tx = tx. clone ( ) ;
108+ tokio:: spawn ( async move {
109+ while let Some ( Ok ( m) ) = stream. next ( ) . await {
110+ wrapped_tx. send ( m) . unwrap ( ) ;
111+ // Event::default().data(n.payload())
112+ // )).map_err(|e| HttpgError::anyhow(e.to_string()))?;
113+ // match m {
114+ // tokio_postgres::AsyncMessage::Notice(n) => tracing::info!("{n:#?}"),
115+ // tokio_postgres::AsyncMessage::Notification(n) => {
116+ // tx.send(Ok(
117+ // Event::default().data(n.payload())
118+ // )).map_err(|e| HttpgError::anyhow(e.to_string()))?;
119+ // },
120+ // _ => {HttpgError::anyhow("unsupported AsyncMessage");},
121+ // }
122+ }
123+
124+ Ok :: < _ , HttpgError > ( ( ) )
125+ } ) ;
96126
97127 let state = AppState {
98128 read_pool,
99129 write_pool,
100130 config : httpg_config. to_owned ( ) ,
131+ tx,
132+ client : Arc :: new ( client) ,
101133 } ;
102134
103135 let app = Router :: new ( )
@@ -309,8 +341,7 @@ async fn pre<'a>(tx: &mut Transaction<'a>, biscuit: &Option<extract::biscuit::Bi
309341 serde_json:: to_string( & query) ?,
310342 Type :: TEXT
311343 )
312- ] )
313- . await ?;
344+ ] ) . await ?;
314345
315346 if let Some ( extract:: biscuit:: Biscuit ( b) ) = biscuit {
316347 futures:: future:: join_all ( b. iter ( ) . map ( async |sql| {
@@ -534,34 +565,32 @@ async fn stream_query(
534565
535566#[ debug_handler]
536567async fn sse_query (
537- State ( AppState { config, ..} ) : State < AppState > ,
538- biscuit : Option < extract:: biscuit:: Biscuit > ,
568+ State ( AppState { tx, client, ..} ) : State < AppState > ,
539569 Path ( channel) : Path < String > ,
540- query : extract:: query:: Query ,
541570) -> Result < impl IntoResponse , HttpgError > {
542571
543- let ( client, mut conn) = config. pg . connect ( ) . await ?;
544-
545- let ( tx, rx) = tokio:: sync:: mpsc:: unbounded_channel :: < Result < Event , HttpgError > > ( ) ;
546-
547- let mut stream = futures:: stream:: poll_fn ( move |cx| conn. poll_message ( cx) ) ;
548- tokio:: spawn ( async move {
549- client. simple_query_raw ( & format ! ( "listen {channel}" ) ) . await . unwrap ( ) ;
550- while let Some ( Ok ( m) ) = stream. next ( ) . await {
551- match m {
552- tokio_postgres:: AsyncMessage :: Notice ( n) => tracing:: info!( "{n:#?}" ) ,
553- tokio_postgres:: AsyncMessage :: Notification ( n) => {
554- tx. send ( Ok (
555- Event :: default ( ) . data ( n. payload ( ) )
556- ) ) . unwrap ( ) ;
557- } ,
558- _ => todo ! ( )
559- }
560- }
561- } ) ;
572+ client. simple_query_raw ( & format ! ( "listen {channel}" ) ) . await ?;
562573
563574 Ok ( Sse :: new (
564- tokio_stream:: wrappers:: UnboundedReceiverStream :: new ( rx)
575+ tokio_stream:: wrappers:: BroadcastStream :: new ( tx. subscribe ( ) )
576+ . try_filter_map ( move |m| {
577+ let channel = channel. clone ( ) ;
578+ async move {
579+ match m {
580+ tokio_postgres:: AsyncMessage :: Notice ( n) => {
581+ tracing:: info!( "{n:#?}" ) ;
582+ Ok ( None )
583+ } ,
584+ tokio_postgres:: AsyncMessage :: Notification ( n) => {
585+ match n. channel ( ) {
586+ c if c == channel => Ok ( Some ( Event :: default ( ) . data ( n. payload ( ) ) ) ) ,
587+ _ => Ok ( None )
588+ }
589+ } ,
590+ _ => Err ( BroadcastStreamRecvError :: Lagged ( 1 ) ) ,
591+ }
592+ }
593+ } )
565594 ) )
566595 // .keep_alive(
567596 // axum::response::sse::KeepAlive::new()
0 commit comments