You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/client_macros.md
+12-12Lines changed: 12 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,8 +5,8 @@ The `#[client_task_enum]` and `#[client_task]` procedural macro simplifies the i
5
5
`#[client_task]` attribute allows users to define a struct representing an RPC task and specify its common fields, request, response, and optional blob data using `#[field(...)]` attributes.
6
6
It will not generate ClientTask trait because the ClientTaskAction is optional for task variants.
7
7
8
-
`#[client_task_enum]` attribute allow user to wrap an enum and delegate the ClienTask trait requirements to it's variants.
9
-
It will generate ClientTask trait and the ClientTaskAction according to #[action()] specified for enum variants.
8
+
`#[client_task_enum]` attribute allows users to wrap an enum and delegate the ClientTask trait requirements to its variants.
9
+
It will generate the ClientTask trait and the ClientTaskAction according to the #[action()] specified for enum variants.
10
10
11
11
### `#[action]` on enum variants
12
12
@@ -30,7 +30,7 @@ pub enum FileTask {
30
30
Close(FileCloseTask),
31
31
}
32
32
33
-
// This task does not need to specify an action, as it's handled by the enum variant.
33
+
// This task does not need to specify an action, as it is handled by the enum variant.
34
34
#[client_task]
35
35
pubstructFileOpenTask {
36
36
#[field(common)]
@@ -73,12 +73,12 @@ The macro processes specific fields within the task struct based on the `#[field
73
73
***Requirements:** This field is mandatory. The macro generates `Deref` and `DerefMut` implementations for the task struct, delegating to this `common` field. This allows direct access to the common fields of the task struct.
74
74
75
75
*`#[field(action)]`
76
-
* Purpose: implement ClientTaskAction trait to return RpcAction according to the field
77
-
* Requirements: there's no `action=` specified within the client_task attribute. the field is a numeric or string type, or an enum type that repr by number.
76
+
* Purpose: Implement the ClientTaskAction trait to return an RpcAction according to the field.
77
+
* Requirements: There is no `action=` specified within the `client_task` attribute. The field is a numeric or string type, or an enum type that is represented by a number.
78
78
79
-
* attribute parameter action in `#[client_task(action=...)]`
80
-
* Purpose: implement ClientTaskAction trait with a static value
81
-
* Requirements: there's no `#[field(action)]` specified within the struct. `action()` parameter must be only one, can be numeric, or string, or an enum repr by number.
79
+
* attribute parameter `action` in `#[client_task(action=...)]`
80
+
* Purpose: Implement the ClientTaskAction trait with a static value.
81
+
* Requirements: There is no `#[field(action)]` specified within the struct. The`action()` parameter must be only one, and can be numeric, a string, or an enum represented by a number.
82
82
83
83
*`#[field(req)]`:
84
84
***Purpose:** Designates the field containing the request payload for the RPC call.
@@ -112,11 +112,11 @@ The `#[client_task]` macro automatically generates the following trait implement
112
112
113
113
*`ClientTaskEncode`:
114
114
*`encode_req<C: occams_rpc::codec::Codec>(&self, codec: &C) -> Result<Vec<u8>, ()>`: Encodes the content of the `#[field(req)]` field using the provided codec.
115
-
*`get_req_blob(&self) -> Option<&[u8]>`: If `#[field(req_blob)]` is present, returns `Some` reference to the blob data; otherwise, it returns `None`.
115
+
*`get_req_blob(&self) -> Option<&[u8]>`: If `#[field(req_blob)]` is present, returns a `Some` reference to the blob data; otherwise, it returns `None`.
116
116
117
117
*`ClientTaskDecode`:
118
118
*`decode_resp<C: occams_rpc::codec::Codec>(&mut self, codec: &C, buffer: &[u8]) -> Result<(), ()>`: Decodes the response buffer using the provided codec and stores the result in the `#[field(resp)]` field.
119
-
*`get_resp_blob_mut(&mut self) -> Option<&mut impl occams_rpc::io::AllocateBuf>`: If `#[field(resp_blob)]` is present, returns `Some` mutable reference to the response blob `Option<T>`; otherwise, it returns `None`.
119
+
*`get_resp_blob_mut(&mut self) -> Option<&mut impl occams_rpc::io::AllocateBuf>`: If `#[field(resp_blob)]` is present, returns a `Some` mutable reference to the response blob `Option<T>`; otherwise, it returns `None`.
120
120
121
121
*`ClientTaskDone`:
122
122
* This trait is implemented when `#[field(res)]` and `#[field(noti)]` are present.
@@ -131,7 +131,7 @@ The `#[client_task]` macro automatically generates the following trait implement
131
131
}
132
132
```
133
133
134
-
*when `#[client_task(debug)]` isspecified, youwillgetamorespecifiedDebuggeneratedaccordingto `req` and `resp` field
134
+
*when `#[client_task(debug)]` isspecified, youwillgetamorespecificDebuggeneratedaccordingtothe`req` and `resp` fields
Copy file name to clipboardExpand all lines: docs/design_v2.md
+25-29Lines changed: 25 additions & 29 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,15 +2,15 @@
2
2
3
3
## Design goal
4
4
5
-
A modular, plugable RPC that supports various async runtimes.
5
+
A modular, pluggable RPC that supports various async runtimes.
6
6
7
7
* interface types:
8
8
- stream: Interface for stream processing.
9
9
- api: Interface for remote function call.
10
10
* transport types:
11
11
- TCP transport: optimized for high throughput internal network.
12
12
- RDMA transport: optimized for low latency internal network.
13
-
-Quic transport: optimized for high throughput public network.
13
+
-QUIC transport: optimized for high throughput public network.
14
14
* codec:
15
15
- Msgpack
16
16
- bincode
@@ -22,13 +22,13 @@ A modular, plugable RPC that supports various async runtimes.
22
22
23
23
### Stream protocol
24
24
25
-
str/stream/proto.rs: Defines general proto
25
+
src/stream/proto.rs: Defines general proto
26
26
27
-
`RpcAction`: numeric action is for fewer type variants, while string action is for the implmentation of API interface.
27
+
`RpcAction`: A numeric action is for fewer type variants, while a string action is for the implementation of the API interface.
28
28
29
-
Request format: each request package has a fixed-length header (ReqHead), then followed by structured encoded "msg", then optionally followed by a "blob" (which allocated as owned buffer).
29
+
Request format: Each request package has a fixed-length header (ReqHead), followed by a structured encoded "msg", and then optionally followed by a "blob" (which is allocated as an owned buffer).
30
30
31
-
Response format: each reponse package has a fixed-length header (RespHead), then followed by structured encoded "msg", then optionally followed by a "blob" (which allocated as owned buffer)
31
+
Response format: Each response package has a fixed-length header (RespHead), followed by a structured encoded "msg", and then optionally followed by a "blob" (which is allocated as an owned buffer)
32
32
33
33
### Stream Client
34
34
@@ -37,63 +37,59 @@ Response format: each reponse package has a fixed-length header (RespHead), then
37
37
38
38
src/stream/server.rs:
39
39
40
-
`ServerFactory` is the interafce for user can assign or customize with various plugin (transport, codec, ...)
40
+
`ServerFactory` is the interface for a user to assign or customize with various plugins (transport, codec, etc.).
41
41
42
42
src/stream/server_impl.rs:
43
43
44
-
`RpcServer` is the server implementation, listen and accept connections through transport. The new connection is process by ServerHandle::run interface. We typically use the `ServerHandleTaskStream`implmentation, which utilizes a coroutine to read and a coroutine to write, so that the throughput can at max use 2 cpu cores with one connection.
44
+
`RpcServer` is the server implementation, which listens for and accepts connections through the transport. The new connection is processed by the ServerHandle::run interface. We typically use the `ServerHandleTaskStream`implementation, which utilizes a coroutine to read and a coroutine to write, so that the throughput can use at most 2 CPU cores with one connection.
45
45
46
-
We intended to support service-level graceful restart and graceful shutdown.
46
+
We intend to support service-level graceful restart and graceful shutdown.
47
47
48
-
As a packet received by server, should have gone through the steps:
48
+
A packet received by the server should have gone through the following steps:
An enum task should impl ServerTaskDecode::decode_req(action ... ), regconize sub task type by RpcAction.
54
+
An enum task should implement ServerTaskDecode::decode_req(action ... ), and recognize the sub-task type by RpcAction.
55
55
56
-
For numeric, more used in the stream interface, suitable to use a generated match to call the sub types decode_req.
56
+
For numeric actions, which are more used in the stream interface, it is suitable to use a generated match to call the sub-type's decode_req.
57
57
58
58
The macro can be:
59
59
60
60
```
61
61
62
62
#[server_task_enum]
63
63
pub enum MyServerTask {
64
-
[action=xxx]
64
+
#[action=xxx]
65
65
Type1(SubType1)
66
-
[action=xxx]
66
+
#[action=xxx]
67
67
Type2(SubType2)
68
68
}
69
69
```
70
70
71
-
(action may be num or "string")
71
+
(action may be a number or a string)
72
72
73
-
For SubType1, need to generate MyServerTask::FromSubType1. If user process using SubType, and call subtype::set_result(), should transform into() the supertype to call RpcRespNoti.done().
73
+
For SubType1, we need to generate MyServerTask::From<SubType1>. If a user processes using SubType and calls subtype::set_result(), it should be transformed via into() into the supertype to call RpcRespNoti.done().
74
74
75
-
If user use the ServerTaskVariant/ServerTaskVariantFull generic as subtype, which already implemented ServerTaskEncode/Encode,
76
-
they cannot impl they own method due to the "Orphan Rule" limitation of Rust,
77
-
they should impl wrapper types with new-type pattern. (It's not certain for me Deref, should test)
75
+
If a user uses the ServerTaskVariant/ServerTaskVariantFull generic as a subtype, which has already implemented ServerTaskEncode/Encode, they cannot implement their own methods due to the "Orphan Rule" limitation of Rust. They should implement wrapper types with the new-type pattern. (I'm not certain about Deref, I should test it).
78
76
79
77
So the macro is on MyServerTask:
80
78
81
-
* Need to assign action for the variants for ServerTaskDecode::decode_req, provides get_action(&self) for user
79
+
* Need to assign an action for the variants for ServerTaskDecode::decode_req, which provides get_action(&self) for the user
82
80
83
-
* Need to impl From variants
81
+
* Need to implement From for variants
84
82
85
-
For string, might used in the API interface, can be first match in a HashMap to decide which class to handle, an decode accoding to string (class::method) to a specified Req type.
83
+
For a string, which might be used in the API interface, it can be first matched in a HashMap to decide which class to handle, and decoded according to the string (class::method) to a specified Req type.
86
84
87
85
88
86
#### Dispatch
89
87
90
-
The dispatcher is repsponsible for decode the task and dispatch to backend processing. (There may be struct like worker pool in other threads/coroutines to handle)
88
+
The dispatcher is responsible for decoding the task and dispatching it to the backend for processing. (There may be a struct like a worker pool in other threads/coroutines to handle this).
91
89
92
-
Codec is intend to support encryption, so there should be shared state, need to initialized as Arc<Codec> share between
93
-
conn reader and writer. Therefore, The dispatcher should be a Arc being shared between reader and writer.
90
+
The codec is intended to support encryption, so there should be a shared state, which needs to be initialized as an Arc<Codec> and shared between the connection reader and writer. Therefore, the dispatcher should be an Arc shared between the reader and writer.
94
91
95
-
Because the connection of reader and writer is parallel, we should define ReqDispatch trait and RespReceiver trait separately. The ReqDispatch relies on RespReceiver because it should know about the task type of done channel.
92
+
Because the reader and writer for a connection are parallel, we should define the ReqDispatch and RespReceiver traits separately. The ReqDispatch trait relies on RespReceiver because it needs to know about the task type of the done channel.
96
93
97
-
We set RespReceiver in ServerFactory as an associate type. but we leave the ReqDispatch to be infered From
98
-
` fn new_dispatcher(&self) -> impl ReqDispatch<Self::RespReceiver>``, because like TaskReqDispatch, usually comes with
99
-
closure capturing the connext about how to dispatch the task. There may be a Fn or a struct defined by user.
94
+
We set RespReceiver in ServerFactory as an associated type, but we leave ReqDispatch to be inferred from
95
+
` fn new_dispatcher(&self) -> impl ReqDispatch<Self::RespReceiver>``, because, like TaskReqDispatch, it usually comes with a closure capturing the context about how to dispatch the task. This may be a Fn or a struct defined by the user.
0 commit comments