pub struct CodexProxy {
pub router: Arc<BackendRouter>,
pub providers: HashMap<String, Arc<dyn Provider>>,
pub log_body: bool,
pub log_dir: PathBuf,
pub conversation_store: Arc<ConversationStore>,
}Expand description
Codex proxy handler implementing ProxyHttp trait.
Fields§
§router: Arc<BackendRouter>Backend router for multi-backend routing.
providers: HashMap<String, Arc<dyn Provider>>Providers for each backend (shared, stateless).
log_body: boolWhether to log request/response bodies.
log_dir: PathBufDirectory for debug log files.
conversation_store: Arc<ConversationStore>In-memory conversation store for previous_response_id expansion.
Implementations§
Source§impl CodexProxy
impl CodexProxy
Sourcepub fn new(
router: Arc<BackendRouter>,
providers: HashMap<String, Arc<dyn Provider>>,
log_body: bool,
log_dir: PathBuf,
) -> Self
pub fn new( router: Arc<BackendRouter>, providers: HashMap<String, Arc<dyn Provider>>, log_body: bool, log_dir: PathBuf, ) -> Self
Create a new CodexProxy instance.
Sourcepub fn get_provider(&self, name: &str) -> Option<Arc<dyn Provider>>
pub fn get_provider(&self, name: &str) -> Option<Arc<dyn Provider>>
Get a shared handle to the provider for a backend.
Sourcepub fn get_conversation(
&self,
response_id: &str,
) -> Option<ConversationSnapshot>
pub fn get_conversation( &self, response_id: &str, ) -> Option<ConversationSnapshot>
Lookup conversation snapshot by response id.
Sourcepub fn store_conversation(
&self,
response_id: String,
snapshot: ConversationSnapshot,
)
pub fn store_conversation( &self, response_id: String, snapshot: ConversationSnapshot, )
Persist conversation snapshot for follow-up turns.
Trait Implementations§
Source§impl ProxyHttp for CodexProxy
impl ProxyHttp for CodexProxy
Source§fn request_filter<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
ctx: &'life2 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<bool>> + Send + 'async_trait>>
fn request_filter<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, session: &'life1 mut Session, ctx: &'life2 mut Self::CTX, ) -> Pin<Box<dyn Future<Output = PingoraResult<bool>> + Send + 'async_trait>>
Request filter - called for each request to select backend and prepare context.
Source§fn upstream_peer<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
ctx: &'life2 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<Box<HttpPeer>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn upstream_peer<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
ctx: &'life2 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<Box<HttpPeer>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Select upstream peer for proxying.
Source§fn upstream_request_filter<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
upstream_request: &'life2 mut RequestHeader,
ctx: &'life3 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn upstream_request_filter<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
upstream_request: &'life2 mut RequestHeader,
ctx: &'life3 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Filter and modify the upstream request.
Source§fn request_body_filter<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
body: &'life2 mut Option<Bytes>,
end_of_stream: bool,
ctx: &'life3 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<()>> + Send + 'async_trait>>
fn request_body_filter<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, _session: &'life1 mut Session, body: &'life2 mut Option<Bytes>, end_of_stream: bool, ctx: &'life3 mut Self::CTX, ) -> Pin<Box<dyn Future<Output = PingoraResult<()>> + Send + 'async_trait>>
Capture and transform request body (Responses API → Chat API).
For conversion requests, we need to buffer ALL chunks and send the converted body at end_of_stream. This is because HTTP/2 DATA frames arrive incrementally and we can’t convert partial bodies.
Source§fn response_filter<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
upstream_response: &'life2 mut ResponseHeader,
ctx: &'life3 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn response_filter<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
upstream_response: &'life2 mut ResponseHeader,
ctx: &'life3 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Handle upstream response headers.
Source§fn response_body_filter(
&self,
_session: &mut Session,
body: &mut Option<Bytes>,
end_of_body: bool,
ctx: &mut Self::CTX,
) -> PingoraResult<Option<Duration>>
fn response_body_filter( &self, _session: &mut Session, body: &mut Option<Bytes>, end_of_body: bool, ctx: &mut Self::CTX, ) -> PingoraResult<Option<Duration>>
Transform response body (Chat API → Responses API for streaming).
Source§fn connected_to_upstream<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
reused: bool,
peer: &'life2 HttpPeer,
_fd: RawFd,
digest: Option<&'life3 Digest>,
ctx: &'life4 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn connected_to_upstream<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
reused: bool,
peer: &'life2 HttpPeer,
_fd: RawFd,
digest: Option<&'life3 Digest>,
ctx: &'life4 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = PingoraResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Called when connected to upstream.
Source§fn error_while_proxy(
&self,
peer: &HttpPeer,
_session: &mut Session,
e: Box<Error>,
ctx: &mut Self::CTX,
_client_reused: bool,
) -> Box<Error>
fn error_while_proxy( &self, peer: &HttpPeer, _session: &mut Session, e: Box<Error>, ctx: &mut Self::CTX, _client_reused: bool, ) -> Box<Error>
Handle proxy errors.
Source§fn fail_to_proxy<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
session: &'life1 mut Session,
e: &'life2 Error,
ctx: &'life3 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = FailToProxy> + Send + 'async_trait>>
fn fail_to_proxy<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, session: &'life1 mut Session, e: &'life2 Error, ctx: &'life3 mut Self::CTX, ) -> Pin<Box<dyn Future<Output = FailToProxy> + Send + 'async_trait>>
Handle fatal errors when proxy cannot be established.
Source§type CTX = ProxyContext
type CTX = ProxyContext
Source§fn init_downstream_modules(&self, modules: &mut HttpModules)
fn init_downstream_modules(&self, modules: &mut HttpModules)
Source§fn early_request_filter<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
_ctx: &'life2 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = Result<(), Box<Error>>> + Send + 'async_trait>>
fn early_request_filter<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _session: &'life1 mut Session, _ctx: &'life2 mut Self::CTX, ) -> Pin<Box<dyn Future<Output = Result<(), Box<Error>>> + Send + 'async_trait>>
Source§fn allow_spawning_subrequest(
&self,
_session: &Session,
_ctx: &Self::CTX,
) -> bool
fn allow_spawning_subrequest( &self, _session: &Session, _ctx: &Self::CTX, ) -> bool
Source§fn request_cache_filter(
&self,
_session: &mut Session,
_ctx: &mut Self::CTX,
) -> Result<(), Box<Error>>
fn request_cache_filter( &self, _session: &mut Session, _ctx: &mut Self::CTX, ) -> Result<(), Box<Error>>
Source§fn cache_key_callback(
&self,
_session: &Session,
_ctx: &mut Self::CTX,
) -> Result<CacheKey, Box<Error>>
fn cache_key_callback( &self, _session: &Session, _ctx: &mut Self::CTX, ) -> Result<CacheKey, Box<Error>>
Source§fn cache_miss(&self, session: &mut Session, _ctx: &mut Self::CTX)
fn cache_miss(&self, session: &mut Session, _ctx: &mut Self::CTX)
Source§fn cache_hit_filter<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
_meta: &'life2 CacheMeta,
_hit_handler: &'life3 mut Box<dyn HandleHit + Sync + Send>,
_is_fresh: bool,
_ctx: &'life4 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = Result<Option<ForcedFreshness>, Box<Error>>> + Send + 'async_trait>>
fn cache_hit_filter<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, _session: &'life1 mut Session, _meta: &'life2 CacheMeta, _hit_handler: &'life3 mut Box<dyn HandleHit + Sync + Send>, _is_fresh: bool, _ctx: &'life4 mut Self::CTX, ) -> Pin<Box<dyn Future<Output = Result<Option<ForcedFreshness>, Box<Error>>> + Send + 'async_trait>>
Source§fn proxy_upstream_filter<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session: &'life1 mut Session,
_ctx: &'life2 mut Self::CTX,
) -> Pin<Box<dyn Future<Output = Result<bool, Box<Error>>> + Send + 'async_trait>>
fn proxy_upstream_filter<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _session: &'life1 mut Session, _ctx: &'life2 mut Self::CTX, ) -> Pin<Box<dyn Future<Output = Result<bool, Box<Error>>> + Send + 'async_trait>>
Source§fn response_cache_filter(
&self,
_session: &Session,
_resp: &ResponseHeader,
_ctx: &mut Self::CTX,
) -> Result<RespCacheable, Box<Error>>
fn response_cache_filter( &self, _session: &Session, _resp: &ResponseHeader, _ctx: &mut Self::CTX, ) -> Result<RespCacheable, Box<Error>>
Source§fn cache_vary_filter(
&self,
_meta: &CacheMeta,
_ctx: &mut Self::CTX,
_req: &RequestHeader,
) -> Option<[u8; 16]>
fn cache_vary_filter( &self, _meta: &CacheMeta, _ctx: &mut Self::CTX, _req: &RequestHeader, ) -> Option<[u8; 16]>
Source§fn cache_not_modified_filter(
&self,
session: &Session,
resp: &ResponseHeader,
_ctx: &mut Self::CTX,
) -> Result<bool, Box<Error>>
fn cache_not_modified_filter( &self, session: &Session, resp: &ResponseHeader, _ctx: &mut Self::CTX, ) -> Result<bool, Box<Error>>
Source§fn range_header_filter(
&self,
session: &mut Session,
resp: &mut ResponseHeader,
_ctx: &mut Self::CTX,
) -> RangeType
fn range_header_filter( &self, session: &mut Session, resp: &mut ResponseHeader, _ctx: &mut Self::CTX, ) -> RangeType
range_filter::RangeType. Read more