1use anyhow::{bail, Context as _, Result};
4use maelstrom_base::proto;
5use maelstrom_github::{GitHubReadQueue, GitHubWriteQueue};
6use maelstrom_linux::{self as linux, Fd};
7use serde::{de::DeserializeOwned, Serialize};
8use slog::{debug, Logger};
9use std::time::Duration;
10use std::{
11 fmt::Debug,
12 io::{Read, Write},
13 os::fd::AsRawFd,
14};
15use tokio::{
16 io::{AsyncRead, AsyncReadExt as _, AsyncWrite, AsyncWriteExt as _},
17 sync::mpsc::{UnboundedReceiver, UnboundedSender},
18 time::Instant,
19};
20
21fn encode_message_to_vec(msg: &impl Serialize) -> Result<Vec<u8>> {
22 let msg_len = proto::serialized_size(msg)? as u32;
23 let mut buf = Vec::<u8>::with_capacity(msg_len as usize + 4);
24 Write::write_all(&mut buf, &msg_len.to_be_bytes())?;
25 proto::serialize_into(&mut buf, msg)?;
26 Ok(buf)
27}
28
29pub fn write_message_to_socket(
33 stream: &mut impl Write,
34 msg: &(impl Debug + Serialize),
35 log: &Logger,
36) -> Result<()> {
37 debug!(log, "sending message"; "message" => #?msg);
38 (|| Ok(stream.write_all(&encode_message_to_vec(msg)?)?))()
39 .inspect_err(|err| debug!(log, "error sending message"; "error" => %err))
40}
41
42pub async fn write_message_to_async_socket(
46 stream: &mut (impl AsyncWrite + Unpin),
47 msg: &(impl Debug + Serialize),
48 log: &Logger,
49) -> Result<()> {
50 debug!(log, "sending message"; "message" => #?msg);
51 async { Ok(stream.write_all(&encode_message_to_vec(msg)?).await?) }
52 .await
53 .inspect_err(|err| debug!(log, "error sending message"; "error" => %err))
54}
55
56pub fn read_message_from_socket<MessageT>(stream: &mut impl Read, log: &Logger) -> Result<MessageT>
60where
61 MessageT: Debug + DeserializeOwned,
62{
63 (|| {
64 let mut msg_len: [u8; 4] = [0; 4];
65 stream.read_exact(&mut msg_len)?;
66 let mut buf = vec![0; u32::from_be_bytes(msg_len) as usize];
67 stream.read_exact(&mut buf)?;
68 Result::Ok(proto::deserialize(&buf)?)
69 })()
70 .inspect(|msg| debug!(log, "received message"; "message" => #?msg))
71 .inspect_err(|err| debug!(log, "error receiving message"; "error" => %err))
72}
73
74pub async fn read_message_from_async_socket<MessageT>(
77 stream: &mut (impl AsyncRead + Unpin),
78 log: &Logger,
79) -> Result<MessageT>
80where
81 MessageT: Debug + DeserializeOwned,
82{
83 async {
84 let mut msg_len: [u8; 4] = [0; 4];
85 stream.read_exact(&mut msg_len).await?;
86 let mut buf = vec![0; u32::from_be_bytes(msg_len) as usize];
87 stream.read_exact(&mut buf).await?;
88 Result::Ok(proto::deserialize(&buf)?)
89 }
90 .await
91 .inspect(|msg| debug!(log, "received message"; "message" => #?msg))
92 .inspect_err(|err| debug!(log, "error receiving message"; "error" => %err))
93}
94
95pub async fn async_socket_writer<MessageT>(
99 mut channel: UnboundedReceiver<MessageT>,
100 mut socket: (impl AsyncWrite + Unpin),
101 log: Logger,
102 context: &'static str,
103) -> Result<()>
104where
105 MessageT: Debug + Serialize,
106{
107 while let Some(msg) = channel.recv().await {
108 write_message_to_async_socket(&mut socket, &msg, &log)
109 .await
110 .context(context)?;
111 }
112 Ok(())
113}
114
115pub async fn async_socket_reader<MessageT, TransformedT>(
119 mut socket: (impl AsyncRead + Unpin),
120 channel: UnboundedSender<TransformedT>,
121 transform: impl Fn(MessageT) -> TransformedT,
122 log: Logger,
123 context: &'static str,
124) -> Result<()>
125where
126 MessageT: Debug + DeserializeOwned,
127{
128 loop {
129 let msg = read_message_from_async_socket(&mut socket, &log)
130 .await
131 .context(context)?;
132 if channel.send(transform(msg)).is_err() {
133 return Ok(());
134 }
135 }
136}
137
138pub trait AsRawFdExt: Sized {
139 fn set_socket_options(self) -> Result<Self>;
140}
141
142impl<T: AsRawFd> AsRawFdExt for T {
143 fn set_socket_options(self) -> Result<Self> {
144 let fd = Fd::from_raw(self.as_raw_fd());
145 linux::setsockopt_tcp_nodelay(&fd, true)?;
146 linux::setsockopt_so_keepalive(&fd, true)?;
147 linux::setsockopt_tcp_keepcnt(&fd, 3)?;
148 linux::setsockopt_tcp_keepidle(&fd, 300)?;
149 linux::setsockopt_tcp_keepintvl(&fd, 300)?;
150 Ok(self)
151 }
152}
153
154pub async fn read_message_from_github_queue<MessageT>(
155 queue: &mut GitHubReadQueue,
156 log: &Logger,
157) -> Result<MessageT>
158where
159 MessageT: Debug + DeserializeOwned,
160{
161 async {
162 let Some(buf) = queue.read_msg().await? else {
163 bail!("unexpected eof from github queue");
164 };
165 Result::Ok(proto::deserialize(&buf)?)
166 }
167 .await
168 .inspect(|msg| debug!(log, "received message"; "message" => #?msg))
169 .inspect_err(|err| debug!(log, "error receiving message"; "error" => %err))
170}
171
172pub async fn github_queue_reader<MessageT, TransformedT>(
173 queue: &mut GitHubReadQueue,
174 channel: UnboundedSender<TransformedT>,
175 transform: impl Fn(MessageT) -> TransformedT,
176 log: Logger,
177 context: &'static str,
178) -> Result<()>
179where
180 MessageT: Debug + DeserializeOwned,
181{
182 loop {
183 let msg = read_message_from_github_queue(queue, &log)
184 .await
185 .context(context)?;
186 if channel.send(transform(msg)).is_err() {
187 return Ok(());
188 }
189 }
190}
191
192pub async fn write_message_to_github_queue(
193 queue: &mut GitHubWriteQueue,
194 msg: &(impl Debug + Serialize),
195 log: &Logger,
196) -> Result<()> {
197 debug!(log, "sending message"; "message" => #?msg);
198 queue
199 .write_msg(&proto::serialize(msg).unwrap())
200 .await
201 .inspect_err(|err| debug!(log, "error sending message"; "error" => %err))?;
202 Ok(())
203}
204
205pub async fn write_many_messages_to_github_queue<MessageT>(
206 queue: &mut GitHubWriteQueue,
207 msgs: &[MessageT],
208 log: &Logger,
209) -> Result<()>
210where
211 MessageT: Debug + Serialize,
212{
213 queue
214 .write_many_msgs(&Vec::from_iter(
215 msgs.iter().map(|msg| proto::serialize(msg).unwrap()),
216 ))
217 .await
218 .inspect_err(|err| debug!(log, "error sending message"; "error" => %err))?;
219 Ok(())
220}
221
222pub async fn github_queue_writer<MessageT>(
223 mut channel: UnboundedReceiver<MessageT>,
224 queue: &mut GitHubWriteQueue,
225 log: Logger,
226 context: &'static str,
227) -> Result<()>
228where
229 MessageT: Debug + Serialize,
230{
231 let mut to_send = vec![];
232 let mut next = Instant::now() + Duration::from_millis(10);
233 loop {
234 match tokio::time::timeout_at(next, channel.recv()).await {
235 Err(_) => {
236 if !to_send.is_empty() {
237 write_many_messages_to_github_queue(queue, &to_send, &log)
238 .await
239 .context("writing messages to github queue")
240 .context(context)?;
241 to_send.clear();
242 }
243 next = Instant::now() + Duration::from_millis(10);
244 }
245 Ok(Some(msg)) => {
246 to_send.push(msg);
247 }
248 Ok(None) => break,
249 }
250 }
251 queue
252 .shut_down()
253 .await
254 .context("shutting down github queue")
255 .context(context)?;
256
257 Ok(())
258}