@@ -7,8 +7,9 @@ use std::{
77
88use anyhow:: anyhow;
99use client:: {
10- blobs:: { BlobInfo , BlobStatus , IncompleteBlobInfo , WrapOption } ,
10+ blobs:: { self , BlobInfo , BlobStatus , IncompleteBlobInfo , WrapOption } ,
1111 tags:: TagInfo ,
12+ MemConnector ,
1213} ;
1314use futures_buffered:: BufferedStreamExt ;
1415use futures_lite:: StreamExt ;
@@ -32,7 +33,13 @@ use proto::{
3233 } ,
3334 Request , RpcError , RpcResult , RpcService ,
3435} ;
35- use quic_rpc:: server:: { ChannelTypes , RpcChannel , RpcServerError } ;
36+ use quic_rpc:: {
37+ server:: { ChannelTypes , RpcChannel , RpcServerError } ,
38+ RpcClient , RpcServer ,
39+ } ;
40+ use tokio:: task:: JoinSet ;
41+ use tokio_util:: task:: AbortOnDropHandle ;
42+ use tracing:: { error, warn} ;
3643
3744use crate :: {
3845 export:: ExportProgress ,
@@ -56,6 +63,16 @@ const RPC_BLOB_GET_CHUNK_SIZE: usize = 1024 * 64;
5663const RPC_BLOB_GET_CHANNEL_CAP : usize = 2 ;
5764
5865impl < D : crate :: store:: Store > Blobs < D > {
66+ /// Get a client for the blobs protocol
67+ pub fn client ( self : Arc < Self > ) -> blobs:: Client < MemConnector > {
68+ let client = self
69+ . rpc_handler
70+ . get_or_init ( || RpcHandler :: new ( & self ) )
71+ . client
72+ . clone ( ) ;
73+ blobs:: Client :: new ( client)
74+ }
75+
5976 /// Handle an RPC request
6077 pub async fn handle_rpc_request < C > (
6178 self : Arc < Self > ,
@@ -871,3 +888,60 @@ impl<D: crate::store::Store> Blobs<D> {
871888 Ok ( CreateCollectionResponse { hash, tag } )
872889 }
873890}
891+
892+ #[ derive( Debug ) ]
893+ pub ( crate ) struct RpcHandler {
894+ /// Client to hand out
895+ client : RpcClient < crate :: rpc:: proto:: RpcService , MemConnector > ,
896+ /// Handler task
897+ _handler : AbortOnDropHandle < ( ) > ,
898+ }
899+
900+ impl RpcHandler {
901+ fn new < D : crate :: store:: Store > ( blobs : & Arc < Blobs < D > > ) -> Self {
902+ let blobs = blobs. clone ( ) ;
903+ let ( listener, connector) = quic_rpc:: transport:: flume:: channel ( 1 ) ;
904+ let listener = RpcServer :: new ( listener) ;
905+ let client = RpcClient :: new ( connector) ;
906+ let task = tokio:: spawn ( async move {
907+ let mut tasks = JoinSet :: new ( ) ;
908+ loop {
909+ tokio:: select! {
910+ Some ( res) = tasks. join_next( ) , if !tasks. is_empty( ) => {
911+ if let Err ( e) = res {
912+ if e. is_panic( ) {
913+ error!( "Panic handling RPC request: {e}" ) ;
914+ }
915+ }
916+ }
917+ req = listener. accept( ) => {
918+ let req = match req {
919+ Ok ( req) => req,
920+ Err ( e) => {
921+ warn!( "Error accepting RPC request: {e}" ) ;
922+ continue ;
923+ }
924+ } ;
925+ let blobs = blobs. clone( ) ;
926+ tasks. spawn( async move {
927+ let ( req, client) = match req. read_first( ) . await {
928+ Ok ( ( req, client) ) => ( req, client) ,
929+ Err ( e) => {
930+ warn!( "Error reading first message: {e}" ) ;
931+ return ;
932+ }
933+ } ;
934+ if let Err ( cause) = blobs. handle_rpc_request( req, client) . await {
935+ warn!( "Error handling RPC request: {:?}" , cause) ;
936+ }
937+ } ) ;
938+ }
939+ }
940+ }
941+ } ) ;
942+ Self {
943+ client,
944+ _handler : AbortOnDropHandle :: new ( task) ,
945+ }
946+ }
947+ }
0 commit comments