wasmer_cli/commands/package/common/
wait.rs1use futures::StreamExt;
2use wasmer_backend_api::{WasmerClient, types::PackageVersionState};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
6pub enum PublishWait {
7 None,
8 Container,
9 NativeExecutables,
10 Bindings,
11 All,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct WaitPackageState {
16 pub container: bool,
17 pub native_executables: bool,
18 pub bindings: bool,
19}
20
21impl WaitPackageState {
22 pub fn is_any(self) -> bool {
23 self.container || self.native_executables || self.bindings
24 }
25
26 pub fn new_none() -> Self {
27 Self {
28 container: false,
29 native_executables: false,
30 bindings: false,
31 }
32 }
33
34 pub fn new_all() -> Self {
35 Self {
36 container: true,
37 native_executables: true,
38 bindings: true,
39 }
40 }
41
42 pub fn new_container() -> Self {
43 Self {
44 container: true,
45 native_executables: false,
46 bindings: false,
47 }
48 }
49
50 pub fn new_exe() -> Self {
51 Self {
52 container: true,
53 native_executables: true,
54 bindings: false,
55 }
56 }
57
58 pub fn new_bindings() -> Self {
59 Self {
60 container: true,
61 native_executables: false,
62 bindings: true,
63 }
64 }
65}
66
67impl From<PublishWait> for WaitPackageState {
68 fn from(value: PublishWait) -> Self {
69 match value {
70 PublishWait::None => Self::new_none(),
71 PublishWait::Container => Self::new_container(),
72 PublishWait::NativeExecutables => Self::new_exe(),
73 PublishWait::Bindings => Self::new_bindings(),
74 PublishWait::All => Self::new_all(),
75 }
76 }
77}
78
79pub async fn wait_package(
80 client: &WasmerClient,
81 to_wait: PublishWait,
82 package_version_id: wasmer_backend_api::types::Id,
83 timeout: humantime::Duration,
84) -> anyhow::Result<()> {
85 if let PublishWait::None = to_wait {
86 return Ok(());
87 }
88
89 let package_version_id = package_version_id.into_inner();
90
91 let mut stream =
92 wasmer_backend_api::subscription::package_version_ready(client, &package_version_id)
93 .await?;
94
95 let mut state: WaitPackageState = to_wait.into();
96
97 let deadline: std::time::Instant =
98 std::time::Instant::now() + std::time::Duration::from_secs(timeout.as_secs());
99
100 loop {
101 if !state.is_any() {
102 break;
103 }
104
105 if std::time::Instant::now() > deadline {
106 return Err(anyhow::anyhow!(
107 "Timed out waiting for package version to become ready"
108 ));
109 }
110
111 let data = match tokio::time::timeout_at(deadline.into(), stream.next()).await {
112 Err(_) => {
113 return Err(anyhow::anyhow!(
114 "Timed out waiting for package version to become ready"
115 ));
116 }
117 Ok(None) => {
118 break;
119 }
120 Ok(Some(data)) => data,
121 };
122
123 if let Some(data) = data.unwrap().data {
124 match data.package_version_ready.state {
125 PackageVersionState::WebcGenerated => state.container = false,
126 PackageVersionState::BindingsGenerated => state.bindings = false,
127 PackageVersionState::NativeExesGenerated => state.native_executables = false,
128 }
129 }
130 }
131
132 Ok(())
133}