mirror of
https://github.com/openai/codex.git
synced 2026-11-13 22:47:20 +00:00
feat(app-server): add remote control pairing status RPC (#26450)
## What
Exposes the pairing status transport as experimental app-server v2 RPC
`remoteControl/pairing/status`.
- Adds request/response protocol types for exactly one lookup key:
`pairingCode` or `manualPairingCode`, returning `{ claimed }`.
- Registers the RPC with `global_shared_read("remote-control-pairing")`.
- Wires the method through `MessageProcessor` and
`RemoteControlRequestProcessor`.
- Validates missing/conflicting pairing-code params as invalid requests.
- Documents the RPC in `app-server/README.md`.
- Adds processor, protocol export, and JSON-RPC integration coverage for
both code paths.
## Why
This is the app-server surface the desktop app can poll while the
QR/manual pairing modal is active.
Depends on https://github.com/openai/codex/pull/26449
Related backend change: https://github.com/openai/openai/pull/990244
## Verification
- `cargo test --manifest-path app-server-protocol/Cargo.toml
remote_control`
- `cargo test --manifest-path app-server/Cargo.toml remote_control`
- `cargo fmt --all --check`
- `git diff --check`
This commit is contained in:
1 parent
841f057f2d
commit
0177231ca0
8 files changed
+193
No files matched your search
@@ -11,6 +11,8 @@ use codex_app_server_protocol::RemoteControlDisableResponse;
|
||||
use codex_app_server_protocol::RemoteControlEnableResponse;
|
||||
use codex_app_server_protocol::RemoteControlPairingStartParams;
|
||||
use codex_app_server_protocol::RemoteControlPairingStartResponse;
|
||||
use codex_app_server_protocol::RemoteControlPairingStatusParams;
|
||||
use codex_app_server_protocol::RemoteControlPairingStatusResponse;
|
||||
use codex_app_server_protocol::RemoteControlStatusReadResponse;
|
||||
use std::io;
|
||||
|
||||
@@ -60,6 +62,17 @@ impl RemoteControlRequestProcessor {
|
||||
.map_err(map_pairing_start_error)
|
||||
}
|
||||
|
||||
pub(crate) async fn pairing_status(
|
||||
&self,
|
||||
params: RemoteControlPairingStatusParams,
|
||||
) -> Result<RemoteControlPairingStatusResponse, JSONRPCErrorError> {
|
||||
validate_pairing_status_params(¶ms)?;
|
||||
self.handle()?
|
||||
.pairing_status(params)
|
||||
.await
|
||||
.map_err(map_pairing_start_error)
|
||||
}
|
||||
|
||||
pub(crate) async fn clients_list(
|
||||
&self,
|
||||
params: RemoteControlClientsListParams,
|
||||
@@ -99,6 +112,20 @@ fn map_pairing_start_error(err: io::Error) -> JSONRPCErrorError {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_pairing_status_params(
|
||||
params: &RemoteControlPairingStatusParams,
|
||||
) -> Result<(), JSONRPCErrorError> {
|
||||
match (¶ms.pairing_code, ¶ms.manual_pairing_code) {
|
||||
(Some(_), None) | (None, Some(_)) => Ok(()),
|
||||
(Some(_), Some(_)) => Err(invalid_request(
|
||||
"remoteControl/pairing/status accepts either pairingCode or manualPairingCode, not both",
|
||||
)),
|
||||
(None, None) => Err(invalid_request(
|
||||
"remoteControl/pairing/status requires pairingCode or manualPairingCode",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_client_management_error(err: io::Error) -> JSONRPCErrorError {
|
||||
match err.kind() {
|
||||
io::ErrorKind::InvalidInput
|
||||
|
||||
+53
@@ -23,6 +23,59 @@ async fn pairing_start_returns_internal_error_when_remote_control_is_unavailable
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn pairing_status_returns_internal_error_when_remote_control_is_unavailable() {
|
||||
let err = RemoteControlRequestProcessor::new(/*remote_control_handle*/ None)
|
||||
.pairing_status(RemoteControlPairingStatusParams {
|
||||
pairing_code: Some("pairing-code".to_string()),
|
||||
manual_pairing_code: None,
|
||||
})
|
||||
.await
|
||||
.expect_err("missing remote control should fail pairing status");
|
||||
|
||||
assert_eq!(
|
||||
err,
|
||||
JSONRPCErrorError {
|
||||
code: INTERNAL_ERROR_CODE,
|
||||
data: None,
|
||||
message: "remote control is unavailable for this app-server".to_string(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pairing_status_rejects_missing_pairing_codes() {
|
||||
assert_eq!(
|
||||
validate_pairing_status_params(&RemoteControlPairingStatusParams {
|
||||
pairing_code: None,
|
||||
manual_pairing_code: None,
|
||||
}),
|
||||
Err(JSONRPCErrorError {
|
||||
code: INVALID_REQUEST_ERROR_CODE,
|
||||
data: None,
|
||||
message: "remoteControl/pairing/status requires pairingCode or manualPairingCode"
|
||||
.to_string(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pairing_status_rejects_conflicting_pairing_codes() {
|
||||
assert_eq!(
|
||||
validate_pairing_status_params(&RemoteControlPairingStatusParams {
|
||||
pairing_code: Some("pairing-code".to_string()),
|
||||
manual_pairing_code: Some("ABCD-EFGH".to_string()),
|
||||
}),
|
||||
Err(JSONRPCErrorError {
|
||||
code: INVALID_REQUEST_ERROR_CODE,
|
||||
data: None,
|
||||
message:
|
||||
"remoteControl/pairing/status accepts either pairingCode or manualPairingCode, not both"
|
||||
.to_string(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pairing_start_maps_invalid_input_to_invalid_request() {
|
||||
assert_eq!(
|
||||
|
||||
Reference in new issue
Block a user