@@ -22,18 +22,17 @@ use lettre::{
2222} ;
2323use serde_json:: json;
2424use tokio:: sync:: { broadcast:: Sender } ;
25- use tokio_stream:: wrappers:: errors:: BroadcastStreamRecvError ;
2625use tower:: builder:: ServiceBuilder ;
2726use tower_http:: { cors:: { Any , CorsLayer } , services:: ServeDir , trace:: TraceLayer } ;
2827use web_push:: { ContentEncoding , HyperWebPushClient , SubscriptionInfo , VapidSignatureBuilder , WebPushClient , WebPushMessageBuilder } ;
29- use std:: { env, fs:: { self , File } , net:: { SocketAddr , TcpListener } , ops :: Deref , sync:: Arc } ;
28+ use std:: { env, fs:: { self , File } , net:: { SocketAddr , TcpListener } , sync:: Arc } ;
3029use std:: collections:: HashMap ;
31- use tokio_postgres:: { AsyncMessage , Client , IsolationLevel , types:: { ToSql , Type } } ;
32- use deadpool_postgres:: { Pool , Transaction } ;
30+ use tokio_postgres:: { AsyncMessage , Client , IsolationLevel , Notification , types:: Type } ;
31+ use deadpool_postgres:: Pool ;
3332use tracing_subscriber:: { layer:: SubscriberExt , util:: SubscriberInitExt } ;
3433use biscuit_auth:: { KeyPair , PrivateKey , Biscuit , builder:: * } ;
3534
36- use crate :: { error:: HttpgError , extract :: query :: Query , postgres:: { PostgresConfig , QueryGuard } , response:: CancelStream } ;
35+ use crate :: { error:: HttpgError , postgres:: { PostgresConfig , QueryGuard } , response:: CancelStream } ;
3736
3837#[ derive( Clone , Conf ) ]
3938struct TlsConfig {
@@ -79,7 +78,7 @@ struct AppState {
7978 read_pool : Pool ,
8079 write_pool : Pool ,
8180 config : HttpgConfig ,
82- tx : Sender < AsyncMessage > ,
81+ tx : Sender < Notification > ,
8382 client : Arc < Client > ,
8483}
8584
@@ -99,28 +98,21 @@ async fn main() -> Result<(), HttpgError> {
9998 let write_pool = httpg_config. pg . write_pool ( ) ?;
10099
101100 let ( client, mut conn) = httpg_config. pg . connect ( ) . await ?;
102-
103- let ( tx, _rx) = tokio:: sync:: broadcast:: channel :: < AsyncMessage > ( 16 ) ;
104-
101+ let ( tx, _rx) = tokio:: sync:: broadcast:: channel :: < Notification > ( 16 ) ;
105102 let mut stream = futures:: stream:: poll_fn ( move |cx| conn. poll_message ( cx) ) ;
106-
107103 let wrapped_tx = tx. clone ( ) ;
108104 tokio:: spawn ( async move {
109105 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- // }
106+ match m {
107+ tokio_postgres:: AsyncMessage :: Notice ( n) => {
108+ tracing:: info!( "{n:#?}" ) ;
109+ } ,
110+ tokio_postgres:: AsyncMessage :: Notification ( n) => {
111+ wrapped_tx. send ( n) . map_err ( Box :: new) ?;
112+ }
113+ _ => { }
114+ }
122115 }
123-
124116 Ok :: < _ , HttpgError > ( ( ) )
125117 } ) ;
126118
@@ -138,6 +130,7 @@ async fn main() -> Result<(), HttpgError> {
138130 . route ( "/logout" , get ( logout) . post ( logout) )
139131 . route ( "/{path}/logout" , get ( logout) . post ( logout) )
140132 . route ( "/sse/{channel}" , get ( sse_query) )
133+ . route ( "/{path}/sse/{channel}" , get ( sse_query) )
141134 . route ( "/query" , get ( stream_query) . post ( post_query) )
142135 . route ( "/{path}/query" , get ( stream_query) . post ( post_query) )
143136 . route ( "/{path}/query/{cursor}" , post ( post_query) )
@@ -252,12 +245,13 @@ async fn login(
252245 let root = KeyPair :: from ( & PrivateKey :: from_bytes ( & private_key, Algorithm :: Ed25519 ) ?) ;
253246
254247 let mut conn = write_pool. get ( ) . await ?;
255- let mut tx = conn. build_transaction ( )
248+ let tx = conn. build_transaction ( )
256249 . isolation_level ( IsolationLevel :: Serializable )
257250 . start ( ) . await ?
258251 ;
259252
260- let _guard = pre ( & mut tx, & biscuit, & anon_role, & query) . await ?;
253+ tx. query_typed_raw ( "select set_config('httpg.query', $1, true)" , [ ( serde_json:: to_string ( & query) ?, Type :: TEXT ) ] ) . await ?;
254+ tx. batch_execute ( & pre ( & biscuit, & anon_role) ) . await ?;
261255
262256 let sql_params: Vec < ( _ , Type ) > = query. params . iter ( ) . map ( |param| {
263257 ( param. tosql_sync ( ) , param. to_owned ( ) . into ( ) )
@@ -306,50 +300,15 @@ async fn logout(
306300 ) )
307301}
308302
309- async fn pre < ' a > ( tx : & mut Transaction < ' a > , biscuit : & Option < extract:: biscuit:: Biscuit > , anon_role : & String , query : & ' a Query ) -> Result < QueryGuard , HttpgError > {
303+ fn pre ( biscuit : & Option < extract:: biscuit:: Biscuit > , anon_role : & String ) -> String {
310304
311- let guard = QueryGuard {
312- cancel_token : tx. cancel_token ( ) ,
313- finished : false ,
314- } ;
305+ let mut s = vec ! [
306+ format!( "set local role to {anon_role}" ) ,
307+ ] ;
315308
316- tx. batch_execute ( & format ! ( "set local role to {anon_role}" ) ) . await ?;
317-
318- if let Some ( lang) = & query. accept_language {
319- let mut lang = lang. split ( "," ) . next ( ) . unwrap_or ( "en-US" ) . replace ( "-" , "_" ) ;
320- lang. push_str ( ".UTF8" ) ;
321-
322- let params: [ ( & ( dyn ToSql + Sync ) , Type ) ; 1 ] = [
323- (
324- & lang,
325- Type :: TEXT
326- )
327- ] ;
328-
329- let stx = tx. savepoint ( "lc_time" ) . await ?;
330-
331- let res = stx. query_typed ( "select set_config('lc_time', $1, true)" , & params) . await ;
332-
333- match res {
334- Ok ( _) => stx. commit ( ) . await ?,
335- Err ( _) => stx. rollback ( ) . await ?,
336- }
337- }
338-
339- tx. query_typed_raw ( "select set_config('httpg.query', $1, true)" , vec ! [
340- (
341- serde_json:: to_string( & query) ?,
342- Type :: TEXT
343- )
344- ] ) . await ?;
309+ s. push ( biscuit. to_owned ( ) . map ( |b| b. 0 . join ( ";" ) ) . unwrap_or_default ( ) ) ;
345310
346- if let Some ( extract:: biscuit:: Biscuit ( b) ) = biscuit {
347- futures:: future:: join_all ( b. iter ( ) . map ( async |sql| {
348- tx. batch_execute ( sql) . await
349- } ) ) . await ;
350- }
351-
352- Ok ( guard)
311+ s. join ( ";" )
353312}
354313
355314#[ debug_handler]
@@ -360,12 +319,17 @@ async fn email(
360319) -> Result < impl IntoResponse , HttpgError > {
361320
362321 let mut conn = write_pool. get ( ) . await ?;
363- let mut tx = conn. build_transaction ( )
322+ let tx = conn. build_transaction ( )
364323 . isolation_level ( IsolationLevel :: Serializable )
365324 . start ( ) . await
366325 ?;
367326
368- let _guard = pre ( & mut tx, & biscuit, & anon_role, & query) . await ?;
327+ let _guard = QueryGuard {
328+ cancel_token : tx. cancel_token ( ) ,
329+ finished : false ,
330+ } ;
331+ tx. query_typed_raw ( "select set_config('httpg.query', $1, true)" , [ ( serde_json:: to_string ( & query) ?, Type :: TEXT ) ] ) . await ?;
332+ tx. batch_execute ( & pre ( & biscuit, & anon_role) ) . await ?;
369333
370334 let sql_params: Vec < ( _ , Type ) > = query. params . iter ( ) . map ( |param| {
371335 ( param. tosql_sync ( ) , param. to_owned ( ) . into ( ) )
@@ -451,12 +415,17 @@ async fn web_push(
451415) -> Result < impl IntoResponse , HttpgError > {
452416
453417 let mut conn = read_pool. get ( ) . await ?;
454- let mut tx = conn. build_transaction ( )
418+ let tx = conn. build_transaction ( )
455419 . isolation_level ( IsolationLevel :: RepeatableRead )
456420 . start ( ) . await
457421 ?;
458422
459- let _guard = pre ( & mut tx, & biscuit, & anon_role, & query) . await ?;
423+ let _guard = QueryGuard {
424+ cancel_token : tx. cancel_token ( ) ,
425+ finished : false ,
426+ } ;
427+ tx. query_typed_raw ( "select set_config('httpg.query', $1, true)" , [ ( serde_json:: to_string ( & query) ?, Type :: TEXT ) ] ) . await ?;
428+ tx. batch_execute ( & pre ( & biscuit, & anon_role) ) . await ?;
460429
461430 let sql_params: Vec < ( _ , Type ) > = query. params . iter ( ) . map ( |param| {
462431 ( param. tosql_sync ( ) , param. to_owned ( ) . into ( ) )
@@ -536,13 +505,20 @@ async fn stream_query(
536505 None => read_pool,
537506 } . get ( ) . await ?;
538507
539- let mut tx = conn. build_transaction ( )
508+ let tx = conn. build_transaction ( )
540509 . read_only ( true )
541510 . isolation_level ( IsolationLevel :: RepeatableRead )
542511 . start ( ) . await ?
543512 ;
544513
545- let guard = pre ( & mut tx, & biscuit, & anon_role, & query) . await ?;
514+ let guard = QueryGuard {
515+ cancel_token : tx. cancel_token ( ) ,
516+ finished : false ,
517+ } ;
518+
519+ tx. query_typed_raw ( "select set_config('httpg.query', $1, true)" , [ ( serde_json:: to_string ( & query) ?, Type :: TEXT ) ] ) . await ?;
520+
521+ tx. batch_execute ( & pre ( & biscuit, & anon_role) ) . await ?;
546522
547523 let sql_params: Vec < ( _ , Type ) > = query. params . iter ( ) . map ( |param| {
548524 ( param. tosql_sync ( ) , param. to_owned ( ) . into ( ) )
@@ -573,21 +549,12 @@ async fn sse_query(
573549
574550 Ok ( Sse :: new (
575551 tokio_stream:: wrappers:: BroadcastStream :: new ( tx. subscribe ( ) )
576- . try_filter_map ( move |m | {
552+ . try_filter_map ( move |n | {
577553 let channel = channel. clone ( ) ;
578554 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 ) ) ,
555+ match n. channel ( ) {
556+ c if c == channel => Ok ( Some ( Event :: default ( ) . data ( n. payload ( ) ) ) ) ,
557+ _ => Ok ( None )
591558 }
592559 }
593560 } )
@@ -616,9 +583,14 @@ async fn post_query(
616583 let mut retry: u8 = 0 ;
617584 loop {
618585 let mut conn = write_pool. get ( ) . await ?;
619- let mut tx = conn. build_transaction ( ) . isolation_level ( IsolationLevel :: Serializable ) . start ( ) . await ?;
586+ let tx = conn. build_transaction ( ) . isolation_level ( IsolationLevel :: Serializable ) . start ( ) . await ?;
620587
621- let guard = pre ( & mut tx, & biscuit, anon_role, & query) . await ?;
588+ let guard = QueryGuard {
589+ cancel_token : tx. cancel_token ( ) ,
590+ finished : false ,
591+ } ;
592+ tx. query_typed_raw ( "select set_config('httpg.query', $1, true)" , [ ( serde_json:: to_string ( & query) ?, Type :: TEXT ) ] ) . await ?;
593+ tx. batch_execute ( & pre ( & biscuit, anon_role) ) . await ?;
622594
623595 let result = tx. query_typed ( query. sql . as_ref ( ) . ok_or ( HttpgError :: anyhow ( "no sql passed" ) ) ?, & sql_params) . await ;
624596
@@ -658,19 +630,20 @@ async fn post_query(
658630 continue ;
659631 }
660632
661-
662633 match & query. on_error {
663634 Some ( on_error) => {
664- let errors = json ! ( { "error" : & error} ) ;
665-
666635 let mut conn = read_pool. get ( ) . await ?;
667- let mut tx = conn. build_transaction ( ) . read_only ( true ) . isolation_level ( IsolationLevel :: RepeatableRead ) . start ( ) . await ?;
636+ let tx = conn. build_transaction ( ) . read_only ( true ) . isolation_level ( IsolationLevel :: RepeatableRead ) . start ( ) . await ?;
668637
669- let guard = pre ( & mut tx, & biscuit, anon_role, & query) . await ?;
638+ let guard = QueryGuard {
639+ cancel_token : tx. cancel_token ( ) ,
640+ finished : false ,
641+ } ;
642+ tx. batch_execute ( & pre ( & biscuit, anon_role) ) . await ?;
670643
671644 tx. query_typed_raw (
672645 "select set_config('httpg.errors', $1, true)" ,
673- vec ! [ ( serde_json:: to_string( & errors ) ?, Type :: TEXT ) ]
646+ vec ! [ ( serde_json:: to_string( & json! ( { "error" : & error } ) ) ?, Type :: TEXT ) ]
674647 ) . await ?;
675648
676649 let rows = tx. query_typed_raw ( on_error. as_ref ( ) , sql_params) . await ?;
0 commit comments