1use std::collections::HashMap;
2
3use prost::Message as ProstMessage;
4
5pub const DCP_PROTOCOL_VERSION: &str = "0.10.0";
11
12pub const DCP_PROTOCOL_MAJOR: u32 = 0;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, prost::Enumeration)]
17#[repr(i32)]
18pub enum ClientKind {
19 Unspecified = 0,
20 Cli = 1,
21 Tui = 2,
22 Daemon = 3,
23 ClusterNode = 4,
24}
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, prost::Enumeration)]
28#[repr(i32)]
29pub enum ResponseStatus {
30 Ok = 0,
31 BadRequest = 1,
32 Unauthorized = 2,
33 NotFound = 3,
34 Conflict = 4,
35 Failed = 5,
36 ProtocolMismatch = 6,
37 DeadlineExceeded = 7,
38}
39
40#[derive(Clone, PartialEq, ProstMessage)]
43pub struct Auth {
44 #[prost(string, tag = "1")]
45 pub bearer_token: String,
46}
47
48#[derive(Clone, PartialEq, ProstMessage)]
50pub struct Hello {
51 #[prost(string, tag = "1")]
52 pub protocol_version: String,
53 #[prost(string, tag = "2")]
54 pub node_id: String,
55 #[prost(enumeration = "ClientKind", tag = "3")]
56 pub client_kind: i32,
57 #[prost(message, optional, tag = "4")]
58 pub auth: Option<Auth>,
59 #[prost(string, repeated, tag = "5")]
60 pub capabilities: Vec<String>,
61}
62
63impl Hello {
64 #[must_use]
65 pub fn new(node_id: impl Into<String>, client_kind: ClientKind) -> Self {
66 Self {
67 protocol_version: DCP_PROTOCOL_VERSION.to_owned(),
68 node_id: node_id.into(),
69 client_kind: client_kind as i32,
70 auth: None,
71 capabilities: Vec::new(),
72 }
73 }
74}
75
76#[derive(Clone, PartialEq, ProstMessage)]
78pub struct Request {
79 #[prost(uint64, tag = "1")]
80 pub request_id: u64,
81 #[prost(uint64, tag = "2")]
82 pub deadline_ms: u64,
83 #[prost(
84 oneof = "request::Command",
85 tags = "10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29"
86 )]
87 pub command: Option<request::Command>,
88}
89
90pub mod request {
91 #[derive(Clone, PartialEq, prost::Oneof)]
92 pub enum Command {
93 #[prost(message, tag = "10")]
94 ListJobs(super::ListJobs),
95 #[prost(message, tag = "11")]
96 StartJob(super::StartJob),
97 #[prost(message, tag = "12")]
98 DrainJob(super::DrainJob),
99 #[prost(message, tag = "13")]
100 StopJob(super::StopJob),
101 #[prost(message, tag = "14")]
102 RestartJob(super::RestartJob),
103 #[prost(message, tag = "15")]
104 JobStatus(super::JobStatusRequest),
105 #[prost(message, tag = "16")]
106 SubscribeEvents(super::SubscribeEvents),
107 #[prost(message, tag = "17")]
108 SubscribeMetrics(super::SubscribeMetrics),
109 #[prost(message, tag = "18")]
110 GetConfig(super::GetConfig),
111 #[prost(message, tag = "19")]
112 PutConfig(super::PutConfig),
113 #[prost(message, tag = "20")]
114 ListClusterJobs(super::ListClusterJobs),
115 #[prost(message, tag = "21")]
116 ClusterNodeInfo(super::ClusterNodeInfo),
117 #[prost(message, tag = "22")]
118 SubmitClusterJob(super::SubmitClusterJob),
119 #[prost(message, tag = "23")]
120 RememberClusterAssignment(super::RememberClusterAssignment),
121 #[prost(message, tag = "24")]
122 AllocateShard(super::ShardAllocationRequest),
123 #[prost(message, tag = "25")]
124 RememberShardAllocations(super::RememberShardAllocations),
125 #[prost(message, tag = "26")]
126 GetShardAllocations(super::GetShardAllocations),
127 #[prost(message, tag = "27")]
128 ForwardShardEnvelopes(super::ForwardShardEnvelopes),
129 #[prost(message, tag = "28")]
130 CompleteShardingAsk(super::CompleteShardingAsk),
131 #[prost(message, tag = "29")]
132 OpenShardPipe(super::OpenShardPipe),
133 }
134}
135
136#[derive(Clone, PartialEq, ProstMessage)]
137pub struct ListJobs {}
138
139#[derive(Clone, PartialEq, ProstMessage)]
144pub struct StartJob {
145 #[prost(string, tag = "1")]
146 pub factory_name: String,
147 #[prost(string, tag = "2")]
148 pub instance_name: String,
149 #[prost(map = "string, string", tag = "3")]
150 pub params: HashMap<String, String>,
151 #[prost(message, optional, tag = "4")]
152 pub cluster: Option<ClusterJobStart>,
153}
154
155#[derive(Clone, PartialEq, ProstMessage)]
156pub struct DrainJob {
157 #[prost(string, tag = "1")]
158 pub name: String,
159 #[prost(bool, tag = "2")]
160 pub cluster: bool,
161}
162
163#[derive(Clone, PartialEq, ProstMessage)]
164pub struct StopJob {
165 #[prost(string, tag = "1")]
166 pub name: String,
167 #[prost(bool, tag = "2")]
168 pub cluster: bool,
169}
170
171#[derive(Clone, PartialEq, ProstMessage)]
172pub struct RestartJob {
173 #[prost(string, tag = "1")]
174 pub name: String,
175 #[prost(bool, tag = "2")]
176 pub cluster: bool,
177}
178
179#[derive(Clone, PartialEq, ProstMessage)]
180pub struct JobStatusRequest {
181 #[prost(string, tag = "1")]
182 pub name: String,
183 #[prost(bool, tag = "2")]
184 pub cluster: bool,
185}
186
187#[derive(Clone, PartialEq, ProstMessage)]
188pub struct SubscribeEvents {
189 #[prost(uint64, tag = "1")]
190 pub buffer: u64,
191}
192
193#[derive(Clone, PartialEq, ProstMessage)]
194pub struct SubscribeMetrics {
195 #[prost(uint64, tag = "1")]
196 pub interval_ms: u64,
197}
198
199#[derive(Clone, PartialEq, ProstMessage)]
200pub struct GetConfig {
201 #[prost(string, tag = "1")]
202 pub key: String,
203}
204
205#[derive(Clone, PartialEq, ProstMessage)]
206pub struct PutConfig {
207 #[prost(string, tag = "1")]
208 pub key: String,
209 #[prost(string, tag = "2")]
210 pub value: String,
211}
212
213#[derive(Clone, PartialEq, ProstMessage)]
219pub struct ListClusterJobs {
220 #[prost(uint64, tag = "1")]
223 pub timeout_ms: u64,
224}
225
226#[derive(Clone, PartialEq, ProstMessage)]
228pub struct ClusterNodeInfo {
229 #[prost(uint64, tag = "1")]
232 pub timeout_ms: u64,
233}
234
235#[derive(Clone, PartialEq, ProstMessage)]
237pub struct SubmitClusterJob {
238 #[prost(string, tag = "1")]
239 pub factory_name: String,
240 #[prost(string, tag = "2")]
241 pub instance_name: String,
242 #[prost(map = "string, string", tag = "3")]
243 pub params: HashMap<String, String>,
244 #[prost(message, optional, tag = "4")]
245 pub placement: Option<PlacementSpec>,
246 #[prost(uint64, tag = "5")]
249 pub timeout_ms: u64,
250}
251
252#[derive(Clone, PartialEq, ProstMessage)]
254pub struct RememberClusterAssignment {
255 #[prost(string, tag = "1")]
256 pub instance_name: String,
257 #[prost(message, optional, tag = "2")]
258 pub assignment: Option<ClusterJobStart>,
259}
260
261#[derive(Clone, PartialEq, ProstMessage)]
263pub struct ShardAllocationRequest {
264 #[prost(string, tag = "1")]
265 pub type_name: String,
266 #[prost(string, tag = "2")]
267 pub shard_id: String,
268 #[prost(uint64, tag = "3")]
271 pub timeout_ms: u64,
272}
273
274#[derive(Clone, PartialEq, ProstMessage)]
276pub struct ShardAllocation {
277 #[prost(string, tag = "1")]
278 pub type_name: String,
279 #[prost(string, tag = "2")]
280 pub shard_id: String,
281 #[prost(string, tag = "3")]
282 pub node_id: String,
283 #[prost(uint64, tag = "4")]
284 pub generation: u64,
285}
286
287#[derive(Clone, PartialEq, ProstMessage)]
289pub struct ShardAllocationEntry {
290 #[prost(string, tag = "1")]
291 pub type_name: String,
292 #[prost(string, tag = "2")]
293 pub shard_id: String,
294 #[prost(string, tag = "3")]
295 pub node_id: String,
296 #[prost(uint64, tag = "4")]
297 pub generation: u64,
298}
299
300#[derive(Clone, PartialEq, ProstMessage)]
303pub struct ShardAllocationTable {
304 #[prost(message, repeated, tag = "1")]
305 pub entries: Vec<ShardAllocationEntry>,
306}
307
308#[derive(Clone, PartialEq, ProstMessage)]
310pub struct RememberShardAllocations {
311 #[prost(message, optional, tag = "1")]
312 pub table: Option<ShardAllocationTable>,
313}
314
315#[derive(Clone, PartialEq, ProstMessage)]
317pub struct GetShardAllocations {
318 #[prost(string, tag = "1")]
319 pub type_name: String,
320}
321
322#[derive(Clone, PartialEq, ProstMessage)]
324pub struct ShardEnvelopeWire {
325 #[prost(string, tag = "1")]
326 pub entity_id: String,
327 #[prost(string, tag = "2")]
328 pub shard_id: String,
329 #[prost(bytes = "vec", tag = "3")]
330 pub payload: Vec<u8>,
331}
332
333#[derive(Clone, PartialEq, ProstMessage)]
335pub struct ForwardShardEnvelopes {
336 #[prost(string, tag = "1")]
337 pub type_name: String,
338 #[prost(message, repeated, tag = "2")]
339 pub envelopes: Vec<ShardEnvelopeWire>,
340}
341
342#[derive(Clone, PartialEq, ProstMessage)]
344pub struct ShardEnvelopeAck {
345 #[prost(string, tag = "1")]
346 pub entity_id: String,
347 #[prost(string, tag = "2")]
348 pub shard_id: String,
349 #[prost(bool, tag = "3")]
350 pub ok: bool,
351 #[prost(string, tag = "4")]
352 pub message: String,
353}
354
355#[derive(Clone, PartialEq, ProstMessage)]
357pub struct ShardEnvelopeBatchResult {
358 #[prost(message, repeated, tag = "1")]
359 pub acks: Vec<ShardEnvelopeAck>,
360}
361
362#[derive(Clone, PartialEq, ProstMessage)]
364pub struct CompleteShardingAsk {
365 #[prost(uint64, tag = "1")]
366 pub request_id: u64,
367 #[prost(bool, tag = "2")]
368 pub ok: bool,
369 #[prost(bytes = "vec", tag = "3")]
370 pub payload: Vec<u8>,
371 #[prost(string, tag = "4")]
372 pub message: String,
373}
374
375#[derive(Clone, PartialEq, ProstMessage)]
377pub struct OpenShardPipe {}
378
379#[derive(Clone, PartialEq, ProstMessage)]
385pub struct ShardPipeFrame {
386 #[prost(message, repeated, tag = "1")]
387 pub forwards: Vec<ForwardShardEnvelopes>,
388 #[prost(message, repeated, tag = "2")]
389 pub replies: Vec<CompleteShardingAsk>,
390}
391
392#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, prost::Enumeration)]
393#[repr(i32)]
394pub enum PlacementStrategy {
395 LeastJobs = 0,
396 Pinned = 1,
397}
398
399#[derive(Clone, PartialEq, ProstMessage)]
400pub struct PlacementSpec {
401 #[prost(string, tag = "1")]
402 pub role_constraint: String,
403 #[prost(enumeration = "PlacementStrategy", tag = "2")]
404 pub strategy: i32,
405 #[prost(string, tag = "3")]
406 pub pinned_node_id: String,
407}
408
409#[derive(Clone, PartialEq, ProstMessage)]
410pub struct ClusterPlacementHistory {
411 #[prost(uint64, tag = "1")]
412 pub generation: u64,
413 #[prost(string, tag = "2")]
414 pub from_node_id: String,
415 #[prost(string, tag = "3")]
416 pub to_node_id: String,
417 #[prost(string, tag = "4")]
418 pub reason: String,
419 #[prost(uint64, tag = "5")]
420 pub timestamp_ms: u64,
421}
422
423#[derive(Clone, PartialEq, ProstMessage)]
425pub struct ClusterJobStart {
426 #[prost(string, tag = "1")]
427 pub factory_name: String,
428 #[prost(map = "string, string", tag = "2")]
429 pub params: HashMap<String, String>,
430 #[prost(message, optional, tag = "3")]
431 pub placement: Option<PlacementSpec>,
432 #[prost(string, tag = "4")]
433 pub coordinator_node_id: String,
434 #[prost(string, tag = "5")]
435 pub assigned_node_id: String,
436 #[prost(uint64, tag = "6")]
437 pub placement_generation: u64,
438 #[prost(message, repeated, tag = "7")]
439 pub history: Vec<ClusterPlacementHistory>,
440}
441
442#[derive(Clone, PartialEq, ProstMessage)]
443pub struct Response {
444 #[prost(uint64, tag = "1")]
445 pub request_id: u64,
446 #[prost(enumeration = "ResponseStatus", tag = "2")]
447 pub status: i32,
448 #[prost(string, tag = "3")]
449 pub message: String,
450 #[prost(bytes = "vec", tag = "4")]
451 pub payload: Vec<u8>,
452}
453
454impl Response {
455 #[must_use]
456 pub fn ok(request_id: u64, payload: Vec<u8>) -> Self {
457 Self {
458 request_id,
459 status: ResponseStatus::Ok as i32,
460 message: String::new(),
461 payload,
462 }
463 }
464
465 #[must_use]
466 pub fn error(request_id: u64, status: ResponseStatus, message: impl Into<String>) -> Self {
467 Self {
468 request_id,
469 status: status as i32,
470 message: message.into(),
471 payload: Vec::new(),
472 }
473 }
474
475 #[must_use]
476 pub fn response_status(&self) -> ResponseStatus {
477 ResponseStatus::try_from(self.status).unwrap_or(ResponseStatus::Failed)
478 }
479}
480
481#[derive(Clone, PartialEq, ProstMessage)]
482pub struct JobList {
483 #[prost(message, repeated, tag = "1")]
484 pub jobs: Vec<JobStatus>,
485}
486
487#[derive(Clone, PartialEq, ProstMessage)]
489pub struct ClusterJobList {
490 #[prost(message, repeated, tag = "1")]
491 pub nodes: Vec<ClusterJobNode>,
492 #[prost(message, repeated, tag = "2")]
493 pub errors: Vec<ClusterNodeError>,
494 #[prost(bool, tag = "3")]
495 pub partial: bool,
496}
497
498#[derive(Clone, PartialEq, ProstMessage)]
500pub struct ClusterJobNode {
501 #[prost(string, tag = "1")]
502 pub node_id: String,
503 #[prost(string, tag = "2")]
504 pub address: String,
505 #[prost(bool, tag = "3")]
506 pub local: bool,
507 #[prost(message, repeated, tag = "4")]
508 pub jobs: Vec<JobStatus>,
509}
510
511#[derive(Clone, PartialEq, ProstMessage)]
513pub struct ClusterNodeList {
514 #[prost(message, repeated, tag = "1")]
515 pub nodes: Vec<ClusterNodeStatus>,
516 #[prost(message, repeated, tag = "2")]
517 pub errors: Vec<ClusterNodeError>,
518 #[prost(bool, tag = "3")]
519 pub partial: bool,
520}
521
522#[derive(Clone, PartialEq, ProstMessage)]
524pub struct ClusterNodeStatus {
525 #[prost(string, tag = "1")]
526 pub node_id: String,
527 #[prost(string, tag = "2")]
528 pub member_state: String,
529 #[prost(string, tag = "3")]
530 pub address: String,
531 #[prost(string, tag = "4")]
532 pub agent_addr: String,
533 #[prost(string, repeated, tag = "5")]
534 pub roles: Vec<String>,
535 #[prost(bool, tag = "6")]
536 pub unreachable: bool,
537 #[prost(bool, tag = "7")]
538 pub local: bool,
539 #[prost(string, tag = "8")]
540 pub session_state: String,
541}
542
543#[derive(Clone, PartialEq, ProstMessage)]
545pub struct ClusterNodeError {
546 #[prost(string, tag = "1")]
547 pub node_id: String,
548 #[prost(string, tag = "2")]
549 pub message: String,
550}
551
552#[derive(Clone, PartialEq, ProstMessage)]
553pub struct ConfigValue {
554 #[prost(string, tag = "1")]
555 pub key: String,
556 #[prost(string, tag = "2")]
557 pub value: String,
558 #[prost(bool, tag = "3")]
559 pub existed: bool,
560}
561
562#[derive(Clone, PartialEq, ProstMessage)]
563pub struct JobStatus {
564 #[prost(string, tag = "1")]
565 pub name: String,
566 #[prost(uint64, tag = "2")]
567 pub job_id: u64,
568 #[prost(string, tag = "3")]
569 pub state: String,
570 #[prost(string, tag = "4")]
571 pub desired_state: String,
572 #[prost(uint64, tag = "5")]
573 pub generation: u64,
574 #[prost(uint64, tag = "6")]
575 pub starts_total: u64,
576 #[prost(uint64, tag = "7")]
577 pub restarts_total: u64,
578 #[prost(uint64, optional, tag = "8")]
579 pub last_start_at_ms: Option<u64>,
580 #[prost(uint64, optional, tag = "9")]
581 pub last_exit_at_ms: Option<u64>,
582 #[prost(string, tag = "10")]
583 pub last_exit_reason: String,
584 #[prost(uint64, optional, tag = "11")]
585 pub backoff_remaining_ms: Option<u64>,
586 #[prost(uint64, optional, tag = "12")]
587 pub drain_remaining_ms: Option<u64>,
588 #[prost(bool, tag = "13")]
589 pub drain_supported: bool,
590 #[prost(uint64, optional, tag = "14")]
591 pub active_streams: Option<u64>,
592 #[prost(bool, tag = "15")]
593 pub cluster_job: bool,
594 #[prost(string, tag = "16")]
595 pub factory_name: String,
596 #[prost(message, optional, tag = "17")]
597 pub placement: Option<PlacementSpec>,
598 #[prost(string, tag = "18")]
599 pub coordinator_node_id: String,
600 #[prost(string, tag = "19")]
601 pub placement_node_id: String,
602 #[prost(uint64, tag = "20")]
603 pub placement_generation: u64,
604 #[prost(message, repeated, tag = "21")]
605 pub placement_history: Vec<ClusterPlacementHistory>,
606 #[prost(map = "string, string", tag = "22")]
607 pub params: HashMap<String, String>,
608}
609
610#[derive(Clone, PartialEq, ProstMessage)]
611pub struct EventFrame {
612 #[prost(uint64, tag = "1")]
613 pub subscription_id: u64,
614 #[prost(message, optional, tag = "2")]
615 pub event: Option<Event>,
616}
617
618#[derive(Clone, PartialEq, ProstMessage)]
619pub struct Event {
620 #[prost(uint64, tag = "1")]
621 pub sequence: u64,
622 #[prost(uint64, tag = "2")]
623 pub timestamp_ms: u64,
624 #[prost(string, tag = "3")]
625 pub name: String,
626 #[prost(uint64, tag = "4")]
627 pub job_id: u64,
628 #[prost(uint64, tag = "5")]
629 pub generation: u64,
630 #[prost(string, tag = "6")]
631 pub kind: String,
632 #[prost(string, tag = "7")]
633 pub detail: String,
634}
635
636#[derive(Clone, PartialEq, ProstMessage)]
637pub struct MetricFrame {
638 #[prost(uint64, tag = "1")]
639 pub subscription_id: u64,
640 #[prost(message, optional, tag = "2")]
641 pub sample: Option<MetricSample>,
642}
643
644#[derive(Clone, PartialEq, ProstMessage)]
645pub struct MetricSample {
646 #[prost(uint64, tag = "1")]
647 pub timestamp_ms: u64,
648 #[prost(message, repeated, tag = "2")]
649 pub streams: Vec<StreamMetric>,
650}
651
652#[derive(Clone, PartialEq, ProstMessage)]
653pub struct StreamMetric {
654 #[prost(uint64, tag = "1")]
655 pub id: u64,
656 #[prost(string, tag = "2")]
657 pub name: String,
658 #[prost(uint64, tag = "3")]
659 pub elements_through: u64,
660 #[prost(uint64, tag = "4")]
661 pub restarts: u64,
662 #[prost(string, tag = "5")]
663 pub state: String,
664 #[prost(uint64, tag = "6")]
665 pub started_at_ms: u64,
666 #[prost(uint64, tag = "7")]
667 pub state_changed_at_ms: u64,
668 #[prost(uint64, optional, tag = "8")]
669 pub finished_at_ms: Option<u64>,
670 #[prost(uint64, tag = "9")]
671 pub uptime_ms: u64,
672}
673
674#[derive(Clone, PartialEq, ProstMessage)]
675pub struct DcpFrame {
676 #[prost(oneof = "dcp_frame::Frame", tags = "1, 2, 3, 4, 5, 6")]
677 pub frame: Option<dcp_frame::Frame>,
678}
679
680impl DcpFrame {
681 #[must_use]
682 pub fn hello(hello: Hello) -> Self {
683 Self {
684 frame: Some(dcp_frame::Frame::Hello(hello)),
685 }
686 }
687
688 #[must_use]
689 pub fn request(request: Request) -> Self {
690 Self {
691 frame: Some(dcp_frame::Frame::Request(request)),
692 }
693 }
694
695 #[must_use]
696 pub fn response(response: Response) -> Self {
697 Self {
698 frame: Some(dcp_frame::Frame::Response(response)),
699 }
700 }
701
702 #[must_use]
703 pub fn event(subscription_id: u64, event: Event) -> Self {
704 Self {
705 frame: Some(dcp_frame::Frame::Event(EventFrame {
706 subscription_id,
707 event: Some(event),
708 })),
709 }
710 }
711
712 #[must_use]
713 pub fn metric(subscription_id: u64, sample: MetricSample) -> Self {
714 Self {
715 frame: Some(dcp_frame::Frame::Metric(MetricFrame {
716 subscription_id,
717 sample: Some(sample),
718 })),
719 }
720 }
721
722 #[must_use]
723 pub fn shard_pipe(pipe: ShardPipeFrame) -> Self {
724 Self {
725 frame: Some(dcp_frame::Frame::ShardPipe(pipe)),
726 }
727 }
728}
729
730pub mod dcp_frame {
731 #[allow(clippy::large_enum_variant)]
732 #[derive(Clone, PartialEq, prost::Oneof)]
733 pub enum Frame {
734 #[prost(message, tag = "1")]
735 Hello(super::Hello),
736 #[prost(message, tag = "2")]
737 Request(super::Request),
738 #[prost(message, tag = "3")]
739 Response(super::Response),
740 #[prost(message, tag = "4")]
741 Event(super::EventFrame),
742 #[prost(message, tag = "5")]
743 Metric(super::MetricFrame),
744 #[prost(message, tag = "6")]
745 ShardPipe(super::ShardPipeFrame),
746 }
747}