Our Personal Data Server from scratch! tranquil.farm
oauth atproto pds rust postgresql objectstorage fun

fix: signal cli in containers

authored by lewis.moe and committed by tangled.org 18cdb612 2c8568b2

+45 -11
+13 -2
Dockerfile
··· 20 20 fi && \ 21 21 cp target/release/tranquil-pds /tmp/tranquil-pds 22 22 23 - FROM alpine:3.23 24 - RUN apk add --no-cache msmtp ca-certificates && ln -sf /usr/bin/msmtp /usr/sbin/sendmail 23 + FROM alpine:3.23 AS signal-cli 24 + RUN apk add --no-cache curl tar 25 + ARG SIGNAL_CLI_VERSION=0.13.24 26 + RUN curl -fsSL "https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/signal-cli-${SIGNAL_CLI_VERSION}-Linux-native.tar.gz" \ 27 + | tar xz -C /usr/local/bin 28 + 29 + FROM debian:trixie-slim 30 + RUN apt-get update && apt-get install -y --no-install-recommends msmtp ca-certificates \ 31 + && rm -rf /var/lib/apt/lists/* \ 32 + && ln -sf /usr/bin/msmtp /usr/sbin/sendmail 33 + COPY --from=signal-cli /usr/local/bin/signal-cli /usr/local/bin/signal-cli 34 + VOLUME /var/lib/signal-cli 25 35 COPY --from=builder /tmp/tranquil-pds /usr/local/bin/tranquil-pds 26 36 COPY --from=frontend /app/dist /var/lib/tranquil-pds/frontend 27 37 COPY migrations /app/migrations 28 38 WORKDIR /app 39 + ENV SIGNAL_CLI_CONFIG=/var/lib/signal-cli 29 40 ENV SERVER_HOST=0.0.0.0 30 41 ENV SERVER_PORT=3000 31 42 EXPOSE 3000
+32 -9
crates/tranquil-comms/src/sender.rs
··· 22 22 23 23 #[derive(Debug, thiserror::Error)] 24 24 pub enum SendError { 25 - #[error("Failed to spawn sendmail process: {0}")] 26 - ProcessSpawn(#[from] std::io::Error), 27 - #[error("Sendmail exited with non-zero status: {0}")] 28 - SendmailFailed(String), 25 + #[error("Failed to spawn {command}: {source}")] 26 + ProcessSpawn { 27 + command: String, 28 + source: std::io::Error, 29 + }, 30 + #[error("{command} exited with non-zero status: {detail}")] 31 + ProcessFailed { command: String, detail: String }, 29 32 #[error("Channel not configured: {0:?}")] 30 33 NotConfigured(CommsChannel), 31 34 #[error("External service error: {0}")] ··· 160 163 .stdin(Stdio::piped()) 161 164 .stdout(Stdio::piped()) 162 165 .stderr(Stdio::piped()) 163 - .spawn()?; 166 + .spawn() 167 + .map_err(|e| SendError::ProcessSpawn { 168 + command: self.sendmail_path.clone(), 169 + source: e, 170 + })?; 164 171 if let Some(mut stdin) = child.stdin.take() { 165 - stdin.write_all(email_content.as_bytes()).await?; 172 + stdin.write_all(email_content.as_bytes()).await.map_err(|e| { 173 + SendError::ProcessSpawn { 174 + command: self.sendmail_path.clone(), 175 + source: e, 176 + } 177 + })?; 166 178 } 167 - let output = child.wait_with_output().await?; 179 + let output = child.wait_with_output().await.map_err(|e| { 180 + SendError::ProcessSpawn { 181 + command: self.sendmail_path.clone(), 182 + source: e, 183 + } 184 + })?; 168 185 if !output.status.success() { 169 186 let stderr = String::from_utf8_lossy(&output.stderr); 170 - return Err(SendError::SendmailFailed(stderr.to_string())); 187 + return Err(SendError::ProcessFailed { 188 + command: self.sendmail_path.clone(), 189 + detail: stderr.to_string(), 190 + }); 171 191 } 172 192 Ok(()) 173 193 } ··· 656 676 retry_delay(attempt).await; 657 677 continue; 658 678 } 659 - return Err(SendError::ProcessSpawn(e)); 679 + return Err(SendError::ProcessSpawn { 680 + command: self.signal_cli_path.clone(), 681 + source: e, 682 + }); 660 683 } 661 684 Err(_) => { 662 685 if attempt < MAX_RETRIES - 1 {