pub struct Request {
pub id: RequestId,
pub category: EventCategory,
pub operation: String,
pub source: ComponentId,
pub target: Option<ComponentId>,
pub channel: ChannelId,
pub payload: Value,
pub timeout_ms: u64,
}Expand description
A synchronous request message between Components.
Represents a query that expects exactly one Response.
§Required Fields
All fields except target are mandatory and have no sensible defaults:
| Field | Why No Default |
|---|---|
id | Must be unique per request (generated by Request::new) |
operation | Defines what action to perform |
source | Identifies the requesting Component |
channel | Execution context for permission/scope |
payload | Operation-specific data |
timeout_ms | Has default, but requires explicit construction |
§Why No Default Implementation
DO NOT implement Default for this type.
Reasons:
-
idmust be unique: Each request needs a freshRequestId. ADefaultimpl would either reuse the same ID (broken) or generate new ones (hidden side effect inDefault). -
sourceis mandatory: There is no “anonymous” request. Every request must have an identifiable source for routing and permission checking. -
channelis mandatory: Requests without a channel cannot be scoped for permission inheritance or signal targeting. -
operationis mandatory: An empty operation string is meaningless and would fail at runtime.
§Serde Deserialization
When deserializing, all fields must be present in the input.
There are no #[serde(default)] attributes intentionally.
Partial requests are rejected at deserialization time.
§Example
use orcs_event::{Request, EventCategory};
use orcs_types::{ComponentId, ChannelId};
use serde_json::json;
let request = Request::new(
EventCategory::Echo,
"read",
ComponentId::builtin("tool"),
ChannelId::new(),
json!({ "path": "/tmp/file.txt" }),
);
assert_eq!(request.operation, "read");
assert!(request.target.is_none());Fields§
§id: RequestIdUnique identifier for this request.
Generated automatically by Request::new.
Used to correlate with the corresponding Response.
category: EventCategoryEvent category for subscription-based routing.
The EventBus routes this request only to Components that subscribe to this category.
operation: StringOperation name (e.g., “chat”, “read”, “approve”).
Determines how the target Component processes the request.
source: ComponentIdSource Component that initiated this request.
Used for:
- Response routing
- Permission checking
- Audit logging
target: Option<ComponentId>Target Component (optional).
Some(id): Direct request to specific ComponentNone: Broadcast to all Components handling this operation
channel: ChannelIdExecution context channel.
Used for:
- Permission scope inheritance
- Signal targeting (cancel, pause, etc.)
- Parallel execution isolation
payload: ValueOperation-specific payload.
Structure depends on the operation type.
timeout_ms: u64Timeout in milliseconds.
Default: DEFAULT_TIMEOUT_MS (30 seconds).
Override with Request::with_timeout.
Implementations§
Source§impl Request
impl Request
Sourcepub fn new(
category: EventCategory,
operation: impl Into<String>,
source: ComponentId,
channel: ChannelId,
payload: Value,
) -> Request
pub fn new( category: EventCategory, operation: impl Into<String>, source: ComponentId, channel: ChannelId, payload: Value, ) -> Request
Creates a new Request with a unique ID and default timeout.
Note: This method does not validate the operation string.
For validated construction, use Request::try_new via the
TryNew trait.
§Arguments
category- Event category for routingoperation- Operation name (e.g., “chat”, “read”)source- The Component initiating this requestchannel- Execution context for scopingpayload- Operation-specific data
§Example
use orcs_event::{Request, EventCategory};
use orcs_types::{ComponentId, ChannelId};
use serde_json::json;
let req = Request::new(
EventCategory::Echo,
"echo",
ComponentId::builtin("test"),
ChannelId::new(),
json!({ "message": "Hello" }),
);Sourcepub fn with_target(self, target: ComponentId) -> Request
pub fn with_target(self, target: ComponentId) -> Request
Sets the target Component for direct routing.
By default, requests are broadcast to all Components that handle the operation. Use this to send directly to one.
§Example
use orcs_event::{Request, EventCategory};
use orcs_types::{ComponentId, ChannelId};
use serde_json::Value;
let req = Request::new(
EventCategory::Hil,
"approve",
ComponentId::builtin("tool"),
ChannelId::new(),
Value::Null,
)
.with_target(ComponentId::builtin("hil"));
assert!(req.target.is_some());Sourcepub fn with_timeout(self, timeout_ms: u64) -> Request
pub fn with_timeout(self, timeout_ms: u64) -> Request
Sets a custom timeout in milliseconds.
Default is DEFAULT_TIMEOUT_MS (30 seconds).
§Example
use orcs_event::{Request, EventCategory};
use orcs_types::{ComponentId, ChannelId};
use serde_json::Value;
// Short timeout for quick operations
let req = Request::new(
EventCategory::Lifecycle,
"ping",
ComponentId::builtin("monitor"),
ChannelId::new(),
Value::Null,
)
.with_timeout(1000); // 1 second
assert_eq!(req.timeout_ms, 1000);Trait Implementations§
Source§impl<'de> Deserialize<'de> for Request
impl<'de> Deserialize<'de> for Request
Source§fn deserialize<__D>(
__deserializer: __D,
) -> Result<Request, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(
__deserializer: __D,
) -> Result<Request, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
Source§impl Serialize for Request
impl Serialize for Request
Source§fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
Source§impl TryNew for Request
impl TryNew for Request
Source§fn try_new(
args: <Request as TryNew>::Args,
) -> Result<Request, <Request as TryNew>::Error>
fn try_new( args: <Request as TryNew>::Args, ) -> Result<Request, <Request as TryNew>::Error>
Attempts to create a new Request with validation.
§Validation
operationmust not be emptyoperationmust not be whitespace-only
§Errors
Returns EventError::InvalidRequest if validation fails.
§Example
use orcs_event::{Request, RequestArgs, EventError, EventCategory};
use orcs_types::{ComponentId, ChannelId, TryNew, ErrorCode};
use serde_json::Value;
// Valid request
let args = RequestArgs {
category: EventCategory::Echo,
operation: "echo".to_string(),
source: ComponentId::builtin("echo"),
channel: ChannelId::new(),
payload: Value::Null,
};
assert!(Request::try_new(args).is_ok());
// Invalid: empty operation
let args = RequestArgs {
category: EventCategory::Echo,
operation: String::new(),
source: ComponentId::builtin("echo"),
channel: ChannelId::new(),
payload: Value::Null,
};
let err = Request::try_new(args).unwrap_err();
assert_eq!(err.code(), "EVENT_INVALID_REQUEST");Source§type Error = EventError
type Error = EventError
Source§type Args = RequestArgs
type Args = RequestArgs
Auto Trait Implementations§
impl Freeze for Request
impl RefUnwindSafe for Request
impl Send for Request
impl Sync for Request
impl Unpin for Request
impl UnsafeUnpin for Request
impl UnwindSafe for Request
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more