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, 30"
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 #[prost(message, tag = "30")]
134 UnsubscribeMetrics(super::UnsubscribeMetrics),
135 }
136}
137
138#[derive(Clone, PartialEq, ProstMessage)]
139pub struct ListJobs {}
140
141#[derive(Clone, PartialEq, ProstMessage)]
146pub struct StartJob {
147 #[prost(string, tag = "1")]
148 pub factory_name: String,
149 #[prost(string, tag = "2")]
150 pub instance_name: String,
151 #[prost(map = "string, string", tag = "3")]
152 pub params: HashMap<String, String>,
153 #[prost(message, optional, tag = "4")]
154 pub cluster: Option<ClusterJobStart>,
155}
156
157#[derive(Clone, PartialEq, ProstMessage)]
158pub struct DrainJob {
159 #[prost(string, tag = "1")]
160 pub name: String,
161 #[prost(bool, tag = "2")]
162 pub cluster: bool,
163}
164
165#[derive(Clone, PartialEq, ProstMessage)]
166pub struct StopJob {
167 #[prost(string, tag = "1")]
168 pub name: String,
169 #[prost(bool, tag = "2")]
170 pub cluster: bool,
171}
172
173#[derive(Clone, PartialEq, ProstMessage)]
174pub struct RestartJob {
175 #[prost(string, tag = "1")]
176 pub name: String,
177 #[prost(bool, tag = "2")]
178 pub cluster: bool,
179}
180
181#[derive(Clone, PartialEq, ProstMessage)]
182pub struct JobStatusRequest {
183 #[prost(string, tag = "1")]
184 pub name: String,
185 #[prost(bool, tag = "2")]
186 pub cluster: bool,
187}
188
189#[derive(Clone, PartialEq, ProstMessage)]
190pub struct SubscribeEvents {
191 #[prost(uint64, tag = "1")]
192 pub buffer: u64,
193}
194
195#[derive(Clone, PartialEq, ProstMessage)]
196pub struct SubscribeMetrics {
197 #[prost(uint64, tag = "1")]
198 pub interval_ms: u64,
199 #[prost(string, repeated, tag = "2")]
202 pub job_names: Vec<String>,
203 #[prost(bool, tag = "3")]
206 pub local_only: bool,
207}
208
209#[derive(Clone, PartialEq, ProstMessage)]
210pub struct UnsubscribeMetrics {
211 #[prost(uint64, tag = "1")]
212 pub subscription_id: u64,
213}
214
215#[derive(Clone, PartialEq, ProstMessage)]
216pub struct GetConfig {
217 #[prost(string, tag = "1")]
218 pub key: String,
219}
220
221#[derive(Clone, PartialEq, ProstMessage)]
222pub struct PutConfig {
223 #[prost(string, tag = "1")]
224 pub key: String,
225 #[prost(string, tag = "2")]
226 pub value: String,
227}
228
229#[derive(Clone, PartialEq, ProstMessage)]
235pub struct ListClusterJobs {
236 #[prost(uint64, tag = "1")]
239 pub timeout_ms: u64,
240}
241
242#[derive(Clone, PartialEq, ProstMessage)]
244pub struct ClusterNodeInfo {
245 #[prost(uint64, tag = "1")]
248 pub timeout_ms: u64,
249}
250
251#[derive(Clone, PartialEq, ProstMessage)]
253pub struct SubmitClusterJob {
254 #[prost(string, tag = "1")]
255 pub factory_name: String,
256 #[prost(string, tag = "2")]
257 pub instance_name: String,
258 #[prost(map = "string, string", tag = "3")]
259 pub params: HashMap<String, String>,
260 #[prost(message, optional, tag = "4")]
261 pub placement: Option<PlacementSpec>,
262 #[prost(uint64, tag = "5")]
265 pub timeout_ms: u64,
266}
267
268#[derive(Clone, PartialEq, ProstMessage)]
271pub struct RememberClusterAssignment {
272 #[prost(string, tag = "1")]
273 pub instance_name: String,
274 #[prost(message, optional, tag = "2")]
275 pub assignment: Option<ClusterJobStart>,
276}
277
278#[derive(Clone, PartialEq, ProstMessage)]
280pub struct ShardAllocationRequest {
281 #[prost(string, tag = "1")]
282 pub type_name: String,
283 #[prost(string, tag = "2")]
284 pub shard_id: String,
285 #[prost(uint64, tag = "3")]
288 pub timeout_ms: u64,
289}
290
291#[derive(Clone, PartialEq, ProstMessage)]
293pub struct ShardAllocation {
294 #[prost(string, tag = "1")]
295 pub type_name: String,
296 #[prost(string, tag = "2")]
297 pub shard_id: String,
298 #[prost(string, tag = "3")]
299 pub node_id: String,
300 #[prost(uint64, tag = "4")]
301 pub generation: u64,
302}
303
304#[derive(Clone, PartialEq, ProstMessage)]
306pub struct ShardAllocationEntry {
307 #[prost(string, tag = "1")]
308 pub type_name: String,
309 #[prost(string, tag = "2")]
310 pub shard_id: String,
311 #[prost(string, tag = "3")]
312 pub node_id: String,
313 #[prost(uint64, tag = "4")]
314 pub generation: u64,
315}
316
317#[derive(Clone, PartialEq, ProstMessage)]
320pub struct ShardAllocationTable {
321 #[prost(message, repeated, tag = "1")]
322 pub entries: Vec<ShardAllocationEntry>,
323}
324
325#[derive(Clone, PartialEq, ProstMessage)]
327pub struct RememberShardAllocations {
328 #[prost(message, optional, tag = "1")]
329 pub table: Option<ShardAllocationTable>,
330}
331
332#[derive(Clone, PartialEq, ProstMessage)]
334pub struct GetShardAllocations {
335 #[prost(string, tag = "1")]
336 pub type_name: String,
337}
338
339#[derive(Clone, PartialEq, ProstMessage)]
341pub struct ShardEnvelopeWire {
342 #[prost(string, tag = "1")]
343 pub entity_id: String,
344 #[prost(string, tag = "2")]
345 pub shard_id: String,
346 #[prost(bytes = "vec", tag = "3")]
347 pub payload: Vec<u8>,
348}
349
350#[derive(Clone, PartialEq, ProstMessage)]
352pub struct ForwardShardEnvelopes {
353 #[prost(string, tag = "1")]
354 pub type_name: String,
355 #[prost(message, repeated, tag = "2")]
356 pub envelopes: Vec<ShardEnvelopeWire>,
357}
358
359#[derive(Clone, PartialEq, ProstMessage)]
361pub struct ShardEnvelopeAck {
362 #[prost(string, tag = "1")]
363 pub entity_id: String,
364 #[prost(string, tag = "2")]
365 pub shard_id: String,
366 #[prost(bool, tag = "3")]
367 pub ok: bool,
368 #[prost(string, tag = "4")]
369 pub message: String,
370}
371
372#[derive(Clone, PartialEq, ProstMessage)]
374pub struct ShardEnvelopeBatchResult {
375 #[prost(message, repeated, tag = "1")]
376 pub acks: Vec<ShardEnvelopeAck>,
377}
378
379#[derive(Clone, PartialEq, ProstMessage)]
381pub struct CompleteShardingAsk {
382 #[prost(uint64, tag = "1")]
383 pub request_id: u64,
384 #[prost(bool, tag = "2")]
385 pub ok: bool,
386 #[prost(bytes = "vec", tag = "3")]
387 pub payload: Vec<u8>,
388 #[prost(string, tag = "4")]
389 pub message: String,
390}
391
392#[derive(Clone, PartialEq, ProstMessage)]
394pub struct OpenShardPipe {}
395
396#[derive(Clone, PartialEq, ProstMessage)]
402pub struct ShardPipeFrame {
403 #[prost(message, repeated, tag = "1")]
404 pub forwards: Vec<ForwardShardEnvelopes>,
405 #[prost(message, repeated, tag = "2")]
406 pub replies: Vec<CompleteShardingAsk>,
407}
408
409#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, prost::Enumeration)]
410#[repr(i32)]
411pub enum PlacementStrategy {
412 LeastJobs = 0,
413 Pinned = 1,
414}
415
416#[derive(Clone, PartialEq, ProstMessage)]
417pub struct PlacementSpec {
418 #[prost(string, tag = "1")]
419 pub role_constraint: String,
420 #[prost(enumeration = "PlacementStrategy", tag = "2")]
421 pub strategy: i32,
422 #[prost(string, tag = "3")]
423 pub pinned_node_id: String,
424}
425
426#[derive(Clone, PartialEq, ProstMessage)]
427pub struct ClusterPlacementHistory {
428 #[prost(uint64, tag = "1")]
429 pub generation: u64,
430 #[prost(string, tag = "2")]
431 pub from_node_id: String,
432 #[prost(string, tag = "3")]
433 pub to_node_id: String,
434 #[prost(string, tag = "4")]
435 pub reason: String,
436 #[prost(uint64, tag = "5")]
437 pub timestamp_ms: u64,
438}
439
440#[derive(Clone, PartialEq, ProstMessage)]
442pub struct ClusterJobStart {
443 #[prost(string, tag = "1")]
444 pub factory_name: String,
445 #[prost(map = "string, string", tag = "2")]
446 pub params: HashMap<String, String>,
447 #[prost(message, optional, tag = "3")]
448 pub placement: Option<PlacementSpec>,
449 #[prost(string, tag = "4")]
450 pub coordinator_node_id: String,
451 #[prost(string, tag = "5")]
452 pub assigned_node_id: String,
453 #[prost(uint64, tag = "6")]
454 pub placement_generation: u64,
455 #[prost(message, repeated, tag = "7")]
456 pub history: Vec<ClusterPlacementHistory>,
457}
458
459#[derive(Clone, PartialEq, ProstMessage)]
460pub struct Response {
461 #[prost(uint64, tag = "1")]
462 pub request_id: u64,
463 #[prost(enumeration = "ResponseStatus", tag = "2")]
464 pub status: i32,
465 #[prost(string, tag = "3")]
466 pub message: String,
467 #[prost(bytes = "vec", tag = "4")]
468 pub payload: Vec<u8>,
469}
470
471impl Response {
472 #[must_use]
473 pub fn ok(request_id: u64, payload: Vec<u8>) -> Self {
474 Self {
475 request_id,
476 status: ResponseStatus::Ok as i32,
477 message: String::new(),
478 payload,
479 }
480 }
481
482 #[must_use]
483 pub fn error(request_id: u64, status: ResponseStatus, message: impl Into<String>) -> Self {
484 Self {
485 request_id,
486 status: status as i32,
487 message: message.into(),
488 payload: Vec::new(),
489 }
490 }
491
492 #[must_use]
493 pub fn response_status(&self) -> ResponseStatus {
494 ResponseStatus::try_from(self.status).unwrap_or(ResponseStatus::Failed)
495 }
496}
497
498#[derive(Clone, PartialEq, ProstMessage)]
499pub struct JobList {
500 #[prost(message, repeated, tag = "1")]
501 pub jobs: Vec<JobStatus>,
502}
503
504#[derive(Clone, PartialEq, ProstMessage)]
506pub struct ClusterJobList {
507 #[prost(message, repeated, tag = "1")]
508 pub nodes: Vec<ClusterJobNode>,
509 #[prost(message, repeated, tag = "2")]
510 pub errors: Vec<ClusterNodeError>,
511 #[prost(bool, tag = "3")]
512 pub partial: bool,
513}
514
515#[derive(Clone, PartialEq, ProstMessage)]
517pub struct ClusterJobNode {
518 #[prost(string, tag = "1")]
519 pub node_id: String,
520 #[prost(string, tag = "2")]
521 pub address: String,
522 #[prost(bool, tag = "3")]
523 pub local: bool,
524 #[prost(message, repeated, tag = "4")]
525 pub jobs: Vec<JobStatus>,
526}
527
528#[derive(Clone, PartialEq, ProstMessage)]
530pub struct ClusterNodeList {
531 #[prost(message, repeated, tag = "1")]
532 pub nodes: Vec<ClusterNodeStatus>,
533 #[prost(message, repeated, tag = "2")]
534 pub errors: Vec<ClusterNodeError>,
535 #[prost(bool, tag = "3")]
536 pub partial: bool,
537}
538
539#[derive(Clone, PartialEq, ProstMessage)]
541pub struct ClusterNodeStatus {
542 #[prost(string, tag = "1")]
543 pub node_id: String,
544 #[prost(string, tag = "2")]
545 pub member_state: String,
546 #[prost(string, tag = "3")]
547 pub address: String,
548 #[prost(string, tag = "4")]
549 pub agent_addr: String,
550 #[prost(string, repeated, tag = "5")]
551 pub roles: Vec<String>,
552 #[prost(bool, tag = "6")]
553 pub unreachable: bool,
554 #[prost(bool, tag = "7")]
555 pub local: bool,
556 #[prost(string, tag = "8")]
557 pub session_state: String,
558}
559
560#[derive(Clone, PartialEq, ProstMessage)]
562pub struct ClusterNodeError {
563 #[prost(string, tag = "1")]
564 pub node_id: String,
565 #[prost(string, tag = "2")]
566 pub message: String,
567}
568
569#[derive(Clone, PartialEq, ProstMessage)]
570pub struct ConfigValue {
571 #[prost(string, tag = "1")]
572 pub key: String,
573 #[prost(string, tag = "2")]
574 pub value: String,
575 #[prost(bool, tag = "3")]
576 pub existed: bool,
577}
578
579#[derive(Clone, PartialEq, ProstMessage)]
580pub struct JobStatus {
581 #[prost(string, tag = "1")]
582 pub name: String,
583 #[prost(uint64, tag = "2")]
584 pub job_id: u64,
585 #[prost(string, tag = "3")]
586 pub state: String,
587 #[prost(string, tag = "4")]
588 pub desired_state: String,
589 #[prost(uint64, tag = "5")]
590 pub generation: u64,
591 #[prost(uint64, tag = "6")]
592 pub starts_total: u64,
593 #[prost(uint64, tag = "7")]
594 pub restarts_total: u64,
595 #[prost(uint64, optional, tag = "8")]
596 pub last_start_at_ms: Option<u64>,
597 #[prost(uint64, optional, tag = "9")]
598 pub last_exit_at_ms: Option<u64>,
599 #[prost(string, tag = "10")]
600 pub last_exit_reason: String,
601 #[prost(uint64, optional, tag = "11")]
602 pub backoff_remaining_ms: Option<u64>,
603 #[prost(uint64, optional, tag = "12")]
604 pub drain_remaining_ms: Option<u64>,
605 #[prost(bool, tag = "13")]
606 pub drain_supported: bool,
607 #[prost(uint64, optional, tag = "14")]
608 pub active_streams: Option<u64>,
609 #[prost(bool, tag = "15")]
610 pub cluster_job: bool,
611 #[prost(string, tag = "16")]
612 pub factory_name: String,
613 #[prost(message, optional, tag = "17")]
614 pub placement: Option<PlacementSpec>,
615 #[prost(string, tag = "18")]
616 pub coordinator_node_id: String,
617 #[prost(string, tag = "19")]
618 pub placement_node_id: String,
619 #[prost(uint64, tag = "20")]
620 pub placement_generation: u64,
621 #[prost(message, repeated, tag = "21")]
622 pub placement_history: Vec<ClusterPlacementHistory>,
623 #[prost(map = "string, string", tag = "22")]
624 pub params: HashMap<String, String>,
625}
626
627#[derive(Clone, PartialEq, ProstMessage)]
628pub struct EventFrame {
629 #[prost(uint64, tag = "1")]
630 pub subscription_id: u64,
631 #[prost(message, optional, tag = "2")]
632 pub event: Option<Event>,
633}
634
635#[derive(Clone, PartialEq, ProstMessage)]
636pub struct Event {
637 #[prost(uint64, tag = "1")]
638 pub sequence: u64,
639 #[prost(uint64, tag = "2")]
640 pub timestamp_ms: u64,
641 #[prost(string, tag = "3")]
642 pub name: String,
643 #[prost(uint64, tag = "4")]
644 pub job_id: u64,
645 #[prost(uint64, tag = "5")]
646 pub generation: u64,
647 #[prost(string, tag = "6")]
648 pub kind: String,
649 #[prost(string, tag = "7")]
650 pub detail: String,
651}
652
653#[derive(Clone, PartialEq, ProstMessage)]
654pub struct MetricFrame {
655 #[prost(uint64, tag = "1")]
656 pub subscription_id: u64,
657 #[prost(message, optional, tag = "2")]
658 pub sample: Option<MetricSample>,
659}
660
661#[derive(Clone, PartialEq, ProstMessage)]
662pub struct MetricSample {
663 #[prost(uint64, tag = "1")]
664 pub timestamp_ms: u64,
665 #[prost(message, repeated, tag = "2")]
666 pub streams: Vec<StreamMetric>,
667}
668
669#[derive(Clone, PartialEq, ProstMessage)]
670pub struct StreamMetric {
671 #[prost(uint64, tag = "1")]
672 pub id: u64,
673 #[prost(string, tag = "2")]
674 pub name: String,
675 #[prost(uint64, tag = "3")]
676 pub elements_through: u64,
677 #[prost(uint64, tag = "4")]
678 pub restarts: u64,
679 #[prost(string, tag = "5")]
680 pub state: String,
681 #[prost(uint64, tag = "6")]
682 pub started_at_ms: u64,
683 #[prost(uint64, tag = "7")]
684 pub state_changed_at_ms: u64,
685 #[prost(uint64, optional, tag = "8")]
686 pub finished_at_ms: Option<u64>,
687 #[prost(uint64, tag = "9")]
688 pub uptime_ms: u64,
689}
690
691#[derive(Clone, PartialEq, ProstMessage)]
692pub struct DcpFrame {
693 #[prost(oneof = "dcp_frame::Frame", tags = "1, 2, 3, 4, 5, 6")]
694 pub frame: Option<dcp_frame::Frame>,
695}
696
697impl DcpFrame {
698 #[must_use]
699 pub fn hello(hello: Hello) -> Self {
700 Self {
701 frame: Some(dcp_frame::Frame::Hello(hello)),
702 }
703 }
704
705 #[must_use]
706 pub fn request(request: Request) -> Self {
707 Self {
708 frame: Some(dcp_frame::Frame::Request(request)),
709 }
710 }
711
712 #[must_use]
713 pub fn response(response: Response) -> Self {
714 Self {
715 frame: Some(dcp_frame::Frame::Response(response)),
716 }
717 }
718
719 #[must_use]
720 pub fn event(subscription_id: u64, event: Event) -> Self {
721 Self {
722 frame: Some(dcp_frame::Frame::Event(EventFrame {
723 subscription_id,
724 event: Some(event),
725 })),
726 }
727 }
728
729 #[must_use]
730 pub fn metric(subscription_id: u64, sample: MetricSample) -> Self {
731 Self {
732 frame: Some(dcp_frame::Frame::Metric(MetricFrame {
733 subscription_id,
734 sample: Some(sample),
735 })),
736 }
737 }
738
739 #[must_use]
740 pub fn shard_pipe(pipe: ShardPipeFrame) -> Self {
741 Self {
742 frame: Some(dcp_frame::Frame::ShardPipe(pipe)),
743 }
744 }
745}
746
747pub mod dcp_frame {
748 #[allow(clippy::large_enum_variant)]
749 #[derive(Clone, PartialEq, prost::Oneof)]
750 pub enum Frame {
751 #[prost(message, tag = "1")]
752 Hello(super::Hello),
753 #[prost(message, tag = "2")]
754 Request(super::Request),
755 #[prost(message, tag = "3")]
756 Response(super::Response),
757 #[prost(message, tag = "4")]
758 Event(super::EventFrame),
759 #[prost(message, tag = "5")]
760 Metric(super::MetricFrame),
761 #[prost(message, tag = "6")]
762 ShardPipe(super::ShardPipeFrame),
763 }
764}