Download codex-rs/exec-server/src/server/handler.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 17.1 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/exec-server/src/server/handler.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/exec-server/src/server/handler.rs
-
curl -L -o handler.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/exec-server/src/server/handler.rs
17.1 kB
| use std::sync::Arc; | |
| use std::sync::Mutex as StdMutex; | |
| use std::sync::atomic::AtomicBool; | |
| use std::sync::atomic::Ordering; | |
| use codex_exec_server_protocol::JSONRPCErrorError; | |
| use codex_exec_server_protocol::RequestId; | |
| use codex_http_client::HttpClientFactory; | |
| use opentelemetry::trace::SpanContext; | |
| use serde_json::to_value; | |
| use std::collections::HashSet; | |
| use tokio::sync::Mutex; | |
| use tokio_util::sync::CancellationToken; | |
| use tokio_util::task::TaskTracker; | |
| use crate::ExecServerRuntimePaths; | |
| use crate::client::http_client::PendingRouteAwareHttpBodyStream; | |
| use crate::client::http_client::RouteAwareHttpClient; | |
| use crate::client::http_client::RouteAwareHttpRequestRunner; | |
| use crate::environment_config::ReadEnvironmentConfigError; | |
| use crate::environment_config::read_environment_config; | |
| use crate::protocol::CapabilityRootsDiscoverParams; | |
| use crate::protocol::CapabilityRootsDiscoverResponse; | |
| use crate::protocol::EnvironmentConfigReadParams; | |
| use crate::protocol::EnvironmentConfigReadResponse; | |
| use crate::protocol::EnvironmentInfo; | |
| use crate::protocol::EnvironmentStatus; | |
| use crate::protocol::EnvironmentStatusKind; | |
| use crate::protocol::ExecParams; | |
| use crate::protocol::ExecResponse; | |
| use crate::protocol::FsCanonicalizeParams; | |
| use crate::protocol::FsCanonicalizeResponse; | |
| use crate::protocol::FsCloseParams; | |
| use crate::protocol::FsCloseResponse; | |
| use crate::protocol::FsCopyParams; | |
| use crate::protocol::FsCopyResponse; | |
| use crate::protocol::FsCreateDirectoryParams; | |
| use crate::protocol::FsCreateDirectoryResponse; | |
| use crate::protocol::FsGetMetadataParams; | |
| use crate::protocol::FsGetMetadataResponse; | |
| use crate::protocol::FsOpenParams; | |
| use crate::protocol::FsOpenResponse; | |
| use crate::protocol::FsReadBlockParams; | |
| use crate::protocol::FsReadBlockResponse; | |
| use crate::protocol::FsReadDirectoryParams; | |
| use crate::protocol::FsReadDirectoryResponse; | |
| use crate::protocol::FsReadFileParams; | |
| use crate::protocol::FsReadFileResponse; | |
| use crate::protocol::FsRemoveParams; | |
| use crate::protocol::FsRemoveResponse; | |
| use crate::protocol::FsWalkParams; | |
| use crate::protocol::FsWalkResponse; | |
| use crate::protocol::FsWriteFileParams; | |
| use crate::protocol::FsWriteFileResponse; | |
| use crate::protocol::HttpRequestParams; | |
| use crate::protocol::InitializeParams; | |
| use crate::protocol::InitializeResponse; | |
| use crate::protocol::ReadParams; | |
| use crate::protocol::ReadResponse; | |
| use crate::protocol::SignalParams; | |
| use crate::protocol::SignalResponse; | |
| use crate::protocol::TerminateParams; | |
| use crate::protocol::TerminateResponse; | |
| use crate::protocol::WriteParams; | |
| use crate::protocol::WriteResponse; | |
| use crate::rpc::RpcNotificationSender; | |
| use crate::rpc::internal_error; | |
| use crate::rpc::invalid_params; | |
| use crate::rpc::invalid_request; | |
| use crate::server::build_identity::local_environment_info; | |
| use crate::server::file_system_handler::FileSystemHandler; | |
| use crate::server::session_registry::SessionHandle; | |
| use crate::server::session_registry::SessionRegistry; | |
| use crate::telemetry::ExecutorRegistration; | |
| pub(crate) struct ExecServerHandler { | |
| pub(super) executor_registration: Option<Arc<ExecutorRegistration>>, | |
| session_registry: Arc<SessionRegistry>, | |
| notifications: RpcNotificationSender, | |
| session: StdMutex<Option<SessionHandle>>, | |
| active_body_stream_ids: Mutex<HashSet<String>>, | |
| background_task_shutdown: CancellationToken, | |
| background_tasks: TaskTracker, | |
| file_system: FileSystemHandler, | |
| runtime_paths: ExecServerRuntimePaths, | |
| http_client: RouteAwareHttpClient, | |
| initialize_requested: AtomicBool, | |
| initialized: AtomicBool, | |
| } | |
| impl ExecServerHandler { | |
| pub(crate) fn new( | |
| session_registry: Arc<SessionRegistry>, | |
| notifications: RpcNotificationSender, | |
| runtime_paths: ExecServerRuntimePaths, | |
| http_client_factory: HttpClientFactory, | |
| ) -> Self { | |
| Self { | |
| executor_registration: None, | |
| session_registry, | |
| notifications, | |
| session: StdMutex::new(None), | |
| active_body_stream_ids: Mutex::new(HashSet::new()), | |
| background_task_shutdown: CancellationToken::new(), | |
| background_tasks: TaskTracker::new(), | |
| file_system: FileSystemHandler::new(runtime_paths.clone()), | |
| runtime_paths, | |
| http_client: RouteAwareHttpClient::new(http_client_factory), | |
| initialize_requested: AtomicBool::new(false), | |
| initialized: AtomicBool::new(false), | |
| } | |
| } | |
| pub(crate) async fn shutdown(&self) { | |
| self.background_task_shutdown.cancel(); | |
| self.background_tasks.close(); | |
| self.background_tasks.wait().await; | |
| self.file_system.shutdown().await; | |
| if let Some(session) = self.session() { | |
| session.detach().await; | |
| } | |
| } | |
| pub(crate) fn is_session_attached(&self) -> bool { | |
| self.session() | |
| .is_none_or(|session| session.is_session_attached()) | |
| } | |
| pub(crate) async fn initialize( | |
| &self, | |
| params: InitializeParams, | |
| ) -> Result<InitializeResponse, JSONRPCErrorError> { | |
| if self.initialize_requested.swap(true, Ordering::SeqCst) { | |
| return Err(invalid_request( | |
| "initialize may only be sent once per connection".to_string(), | |
| )); | |
| } | |
| let session = match self | |
| .session_registry | |
| .attach( | |
| params.resume_session_id.clone(), | |
| self.notifications.clone(), | |
| self.runtime_paths.clone(), | |
| ) | |
| .await | |
| { | |
| Ok(session) => session, | |
| Err(error) => { | |
| self.initialize_requested.store(false, Ordering::SeqCst); | |
| return Err(error); | |
| } | |
| }; | |
| let session_id = session.session_id().to_string(); | |
| tracing::debug!( | |
| session_id, | |
| connection_id = %session.connection_id(), | |
| "exec-server session attached" | |
| ); | |
| *self | |
| .session | |
| .lock() | |
| .unwrap_or_else(std::sync::PoisonError::into_inner) = Some(session); | |
| Ok(InitializeResponse { | |
| session_id, | |
| environment_info: Some(local_environment_info()), | |
| }) | |
| } | |
| pub(crate) fn initialized(&self) -> Result<(), String> { | |
| if !self.initialize_requested.load(Ordering::SeqCst) { | |
| return Err("received `initialized` notification before `initialize`".into()); | |
| } | |
| self.require_session_attached() | |
| .map_err(|error| error.message)?; | |
| self.initialized.store(true, Ordering::SeqCst); | |
| Ok(()) | |
| } | |
| pub(crate) async fn exec( | |
| &self, | |
| params: ExecParams, | |
| launch_context: Option<SpanContext>, | |
| ) -> Result<ExecResponse, JSONRPCErrorError> { | |
| let session = self.require_initialized_for("exec")?; | |
| session | |
| .process() | |
| .exec( | |
| params, | |
| crate::process_telemetry::ProcessTelemetry { | |
| launch_context, | |
| executor_registration: self.executor_registration.clone(), | |
| ..Default::default() | |
| }, | |
| ) | |
| .await | |
| } | |
| pub(crate) fn environment_info(&self) -> Result<EnvironmentInfo, JSONRPCErrorError> { | |
| self.require_initialized_for("environment info")?; | |
| Ok(local_environment_info()) | |
| } | |
| pub(crate) async fn environment_config_read( | |
| &self, | |
| params: EnvironmentConfigReadParams, | |
| ) -> Result<EnvironmentConfigReadResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("environment config")?; | |
| read_environment_config(crate::LOCAL_FS.as_ref(), params) | |
| .await | |
| .map_err(|error| match error { | |
| ReadEnvironmentConfigError::InvalidParams(message) => invalid_params(message), | |
| ReadEnvironmentConfigError::Internal(message) => internal_error(message), | |
| }) | |
| } | |
| pub(crate) fn environment_status(&self) -> Result<EnvironmentStatus, JSONRPCErrorError> { | |
| self.require_initialized_for("environment status")?; | |
| Ok(EnvironmentStatus { | |
| status: EnvironmentStatusKind::Ready, | |
| }) | |
| } | |
| pub(crate) async fn exec_read( | |
| &self, | |
| params: ReadParams, | |
| ) -> Result<ReadResponse, JSONRPCErrorError> { | |
| let session = self.require_initialized_for("exec")?; | |
| let response = session.process().exec_read(params).await?; | |
| self.require_session_attached()?; | |
| Ok(response) | |
| } | |
| pub(crate) async fn exec_write( | |
| &self, | |
| params: WriteParams, | |
| ) -> Result<WriteResponse, JSONRPCErrorError> { | |
| let session = self.require_initialized_for("exec")?; | |
| session.process().exec_write(params).await | |
| } | |
| pub(crate) async fn signal( | |
| &self, | |
| params: SignalParams, | |
| ) -> Result<SignalResponse, JSONRPCErrorError> { | |
| let session = self.require_initialized_for("exec")?; | |
| session.process().signal(params).await | |
| } | |
| pub(crate) async fn terminate( | |
| &self, | |
| params: TerminateParams, | |
| ) -> Result<TerminateResponse, JSONRPCErrorError> { | |
| let session = self.require_initialized_for("exec")?; | |
| session.process().terminate(params).await | |
| } | |
| pub(crate) async fn http_request( | |
| self: &Arc<Self>, | |
| request_id: RequestId, | |
| params: HttpRequestParams, | |
| ) -> Result<(), JSONRPCErrorError> { | |
| self.require_initialized_for("http")?; | |
| let stream_response = params.stream_response; | |
| let http_request_id = params.request_id.clone(); | |
| if stream_response { | |
| self.reserve_http_body_stream(&http_request_id).await?; | |
| } | |
| let response = self | |
| .http_client | |
| .runner(params.redirect_policy) | |
| .run(params) | |
| .await; | |
| if response.is_err() && stream_response { | |
| self.release_http_body_stream(&http_request_id).await; | |
| } | |
| let (response, mut pending_stream) = response?; | |
| let result = match to_value(response) { | |
| Ok(result) => result, | |
| Err(err) => { | |
| if let Some(pending_stream) = pending_stream.take() { | |
| self.release_http_body_stream(&pending_stream.request_id) | |
| .await; | |
| } | |
| return Err(internal_error(err.to_string())); | |
| } | |
| }; | |
| if let Err(error) = self.notifications.response(request_id, result).await { | |
| if let Some(pending_stream) = pending_stream.take() { | |
| self.release_http_body_stream(&pending_stream.request_id) | |
| .await; | |
| } | |
| return Err(error); | |
| } | |
| if let Some(pending_stream) = pending_stream { | |
| self.start_http_body_stream(pending_stream).await; | |
| } | |
| Ok(()) | |
| } | |
| pub(crate) async fn fs_read_file( | |
| &self, | |
| params: FsReadFileParams, | |
| ) -> Result<FsReadFileResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.read_file(params).await | |
| } | |
| pub(crate) async fn discover_capability_roots( | |
| &self, | |
| params: CapabilityRootsDiscoverParams, | |
| ) -> Result<CapabilityRootsDiscoverResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("capability discovery")?; | |
| self.file_system.discover_capability_roots(params).await | |
| } | |
| pub(crate) async fn fs_open( | |
| &self, | |
| params: FsOpenParams, | |
| ) -> Result<FsOpenResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.open(params).await | |
| } | |
| pub(crate) async fn fs_read_block( | |
| &self, | |
| params: FsReadBlockParams, | |
| ) -> Result<FsReadBlockResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.read_block(params).await | |
| } | |
| pub(crate) async fn fs_close( | |
| &self, | |
| params: FsCloseParams, | |
| ) -> Result<FsCloseResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.close(params).await | |
| } | |
| pub(crate) async fn fs_write_file( | |
| &self, | |
| params: FsWriteFileParams, | |
| ) -> Result<FsWriteFileResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.write_file(params).await | |
| } | |
| pub(crate) async fn fs_create_directory( | |
| &self, | |
| params: FsCreateDirectoryParams, | |
| ) -> Result<FsCreateDirectoryResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.create_directory(params).await | |
| } | |
| pub(crate) async fn fs_get_metadata( | |
| &self, | |
| params: FsGetMetadataParams, | |
| ) -> Result<FsGetMetadataResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.get_metadata(params).await | |
| } | |
| pub(crate) async fn fs_canonicalize( | |
| &self, | |
| params: FsCanonicalizeParams, | |
| ) -> Result<FsCanonicalizeResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.canonicalize(params).await | |
| } | |
| pub(crate) async fn fs_read_directory( | |
| &self, | |
| params: FsReadDirectoryParams, | |
| ) -> Result<FsReadDirectoryResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.read_directory(params).await | |
| } | |
| pub(crate) async fn fs_walk( | |
| &self, | |
| params: FsWalkParams, | |
| ) -> Result<FsWalkResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.walk(params).await | |
| } | |
| pub(crate) async fn fs_remove( | |
| &self, | |
| params: FsRemoveParams, | |
| ) -> Result<FsRemoveResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.remove(params).await | |
| } | |
| pub(crate) async fn fs_copy( | |
| &self, | |
| params: FsCopyParams, | |
| ) -> Result<FsCopyResponse, JSONRPCErrorError> { | |
| self.require_initialized_for("filesystem")?; | |
| self.file_system.copy(params).await | |
| } | |
| fn require_initialized_for( | |
| &self, | |
| method_family: &str, | |
| ) -> Result<SessionHandle, JSONRPCErrorError> { | |
| if !self.initialize_requested.load(Ordering::SeqCst) { | |
| return Err(invalid_request(format!( | |
| "client must call initialize before using {method_family} methods" | |
| ))); | |
| } | |
| let session = self.require_session_attached()?; | |
| if !self.initialized.load(Ordering::SeqCst) { | |
| return Err(invalid_request(format!( | |
| "client must send initialized before using {method_family} methods" | |
| ))); | |
| } | |
| Ok(session) | |
| } | |
| fn require_session_attached(&self) -> Result<SessionHandle, JSONRPCErrorError> { | |
| let Some(session) = self.session() else { | |
| return Err(invalid_request( | |
| "client must call initialize before using methods".to_string(), | |
| )); | |
| }; | |
| if session.is_session_attached() { | |
| return Ok(session); | |
| } | |
| Err(invalid_request( | |
| "session has been resumed by another connection".to_string(), | |
| )) | |
| } | |
| fn session(&self) -> Option<SessionHandle> { | |
| self.session | |
| .lock() | |
| .unwrap_or_else(std::sync::PoisonError::into_inner) | |
| .clone() | |
| } | |
| async fn start_http_body_stream( | |
| self: &Arc<Self>, | |
| pending_stream: PendingRouteAwareHttpBodyStream, | |
| ) { | |
| let request_id = pending_stream.request_id.clone(); | |
| if self.background_task_shutdown.is_cancelled() { | |
| self.release_http_body_stream(&request_id).await; | |
| return; | |
| } | |
| let finished_request_id = request_id.clone(); | |
| let handler = Arc::clone(self); | |
| let notifications = self.notifications.clone(); | |
| let shutdown = self.background_task_shutdown.clone(); | |
| self.background_tasks.spawn(async move { | |
| tokio::select! { | |
| _ = shutdown.cancelled() => {} | |
| _ = RouteAwareHttpRequestRunner::stream_body(pending_stream, notifications) => {} | |
| } | |
| handler.release_http_body_stream(&finished_request_id).await; | |
| }); | |
| } | |
| async fn release_http_body_stream(&self, request_id: &str) { | |
| let mut active_body_stream_ids = self.active_body_stream_ids.lock().await; | |
| active_body_stream_ids.remove(request_id); | |
| } | |
| async fn reserve_http_body_stream(&self, request_id: &str) -> Result<(), JSONRPCErrorError> { | |
| let mut active_body_stream_ids = self.active_body_stream_ids.lock().await; | |
| if active_body_stream_ids.contains(request_id) { | |
| return Err(invalid_params(format!( | |
| "http/request streamResponse requestId `{request_id}` is already active" | |
| ))); | |
| } | |
| active_body_stream_ids.insert(request_id.to_string()); | |
| Ok(()) | |
| } | |
| } | |
| mod tests; | |