1#![allow(unsafe_code)]
9#![allow(clippy::wildcard_imports)]
13#![allow(clippy::must_use_candidate)]
17#![allow(clippy::map_unwrap_or)]
21
22use extism_pdk::*;
23use hm_plugin_protocol::host_abi::*;
24use hm_plugin_protocol::{BuildEvent, StdStream};
25
26#[host_fn]
27extern "ExtismHost" {
28 fn hm_log(level: Json<Level>, msg: String);
29 fn hm_emit_step_log(stream: Json<StdStream>, bytes: Vec<u8>);
30 fn hm_emit_event(event: Json<BuildEvent>);
31
32 fn hm_kv_get(scope: Json<KvScope>, key: String) -> Json<Option<Vec<u8>>>;
33 fn hm_kv_set(scope: Json<KvScope>, key: String, val: Vec<u8>);
34
35 fn hm_archive_read(args: Json<ArchiveReadArgs>) -> Vec<u8>;
36 fn hm_archive_total_size(id: Json<ArchiveId>) -> u64;
37 fn hm_fs_read_config(rel_path: String) -> Json<Option<Vec<u8>>>;
38
39 fn hm_unix_socket_connect(path: String) -> Json<SocketHandle>;
40 fn hm_socket_write(args: Json<SocketWriteArgs>) -> u64;
41 fn hm_socket_read(args: Json<SocketReadArgs>) -> Vec<u8>;
42 fn hm_socket_close(h: Json<SocketHandle>);
43
44 fn hm_keyring_get(args: Json<KeyringArgs>) -> Json<Option<String>>;
45 fn hm_keyring_set(args: Json<KeyringSetArgs>);
46 fn hm_keyring_delete(args: Json<KeyringArgs>);
47
48 fn hm_tty_prompt(args: Json<TtyPromptArgs>) -> String;
49 fn hm_tty_confirm(args: Json<TtyConfirmArgs>) -> bool;
50 fn hm_browser_open(url: String) -> bool;
51 fn hm_spawn_loopback(port: Json<Option<u16>>) -> Json<LoopbackHandle>;
52 fn hm_loopback_recv(args: Json<LoopbackRecvArgs>) -> Json<Option<CallbackData>>;
53
54 fn hm_should_cancel() -> u32;
55
56 fn hm_write_stdout(bytes: Vec<u8>);
57 fn hm_write_stderr(bytes: Vec<u8>);
58}
59
60pub use hm_plugin_protocol::ArchiveId;
61
62pub fn log(level: Level, msg: &str) {
70 let _ = unsafe { hm_log(Json(level), msg.to_string()) };
71}
72
73pub fn emit_step_log(stream: StdStream, bytes: &[u8]) {
74 let _ = unsafe { hm_emit_step_log(Json(stream), bytes.to_vec()) };
75}
76
77pub fn emit_event(event: BuildEvent) {
78 let _ = unsafe { hm_emit_event(Json(event)) };
79}
80
81pub fn kv_get(scope: KvScope, key: &str) -> Option<Vec<u8>> {
82 let Json(v) = unsafe { hm_kv_get(Json(scope), key.into()) }.unwrap_or(Json(None));
83 v
84}
85
86pub fn kv_set(scope: KvScope, key: &str, val: &[u8]) {
87 let _ = unsafe { hm_kv_set(Json(scope), key.into(), val.to_vec()) };
88}
89
90pub fn archive_total_size(id: ArchiveId) -> u64 {
91 unsafe { hm_archive_total_size(Json(id)) }.unwrap_or(0)
92}
93
94pub fn archive_read(id: ArchiveId, offset: u64, max: u64) -> Vec<u8> {
95 unsafe { hm_archive_read(Json(ArchiveReadArgs { id, offset, max })) }.unwrap_or_default()
96}
97
98pub fn fs_read_config(rel_path: &str) -> Option<Vec<u8>> {
99 let Json(v) = unsafe { hm_fs_read_config(rel_path.into()) }.unwrap_or(Json(None));
100 v
101}
102
103pub fn unix_socket_connect(path: &str) -> Option<SocketHandle> {
104 unsafe { hm_unix_socket_connect(path.into()) }
105 .ok()
106 .map(|Json(h)| h)
107}
108
109pub fn socket_write(h: SocketHandle, bytes: &[u8]) -> u64 {
110 unsafe {
111 hm_socket_write(Json(SocketWriteArgs {
112 h,
113 bytes: bytes.to_vec(),
114 }))
115 }
116 .unwrap_or(0)
117}
118
119pub fn socket_read(h: SocketHandle, max: u64) -> Vec<u8> {
120 unsafe { hm_socket_read(Json(SocketReadArgs { h, max })) }.unwrap_or_default()
121}
122
123pub fn socket_close(h: SocketHandle) {
124 let _ = unsafe { hm_socket_close(Json(h)) };
125}
126
127pub fn keyring_get(service: &str, account: &str) -> Option<String> {
128 let Json(v) = unsafe {
129 hm_keyring_get(Json(KeyringArgs {
130 service: service.into(),
131 account: account.into(),
132 }))
133 }
134 .unwrap_or(Json(None));
135 v
136}
137
138pub fn keyring_set(service: &str, account: &str, secret: &str) {
139 let _ = unsafe {
140 hm_keyring_set(Json(KeyringSetArgs {
141 service: service.into(),
142 account: account.into(),
143 secret: secret.into(),
144 }))
145 };
146}
147
148pub fn keyring_delete(service: &str, account: &str) {
149 let _ = unsafe {
150 hm_keyring_delete(Json(KeyringArgs {
151 service: service.into(),
152 account: account.into(),
153 }))
154 };
155}
156
157pub fn tty_prompt(msg: &str, mask: bool) -> String {
158 unsafe {
159 hm_tty_prompt(Json(TtyPromptArgs {
160 msg: msg.into(),
161 mask,
162 }))
163 }
164 .unwrap_or_default()
165}
166
167pub fn tty_confirm(msg: &str, default: bool) -> bool {
168 unsafe {
169 hm_tty_confirm(Json(TtyConfirmArgs {
170 msg: msg.into(),
171 default,
172 }))
173 }
174 .unwrap_or(default)
175}
176
177pub fn browser_open(url: &str) -> bool {
178 unsafe { hm_browser_open(url.into()) }.unwrap_or(false)
179}
180
181pub fn write_stdout(bytes: &[u8]) {
182 let _ = unsafe { hm_write_stdout(bytes.to_vec()) };
183}
184
185pub fn write_stderr(bytes: &[u8]) {
186 let _ = unsafe { hm_write_stderr(bytes.to_vec()) };
187}
188
189pub fn spawn_loopback(port: Option<u16>) -> Option<LoopbackHandle> {
190 unsafe { hm_spawn_loopback(Json(port)) }
191 .ok()
192 .map(|Json(h)| h)
193}
194
195pub fn loopback_recv(h: LoopbackHandle, timeout_ms: u32) -> Option<CallbackData> {
196 let Json(v) =
197 unsafe { hm_loopback_recv(Json(LoopbackRecvArgs { h, timeout_ms })) }.unwrap_or(Json(None));
198 v
199}
200
201pub fn should_cancel() -> bool {
202 unsafe { hm_should_cancel() }
203 .map(|n| n != 0)
204 .unwrap_or(false)
205}