Skip to content

Instantly share code, notes, and snippets.

@eduardonunesp
Created January 11, 2021 18:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save eduardonunesp/a9d783e1d86b85cccccd4cfbc6e8d530 to your computer and use it in GitHub Desktop.
Save eduardonunesp/a9d783e1d86b85cccccd4cfbc6e8d530 to your computer and use it in GitHub Desktop.
pdf-exporter
use std::fs::File;
use std::io::{prelude::*, BufReader, Write};
use std::process::Command;
use actix_multipart::Multipart;
use actix_web::{
get, http::StatusCode, post, web, App, Error, HttpResponse, HttpServer, Responder,
};
use futures::{StreamExt, TryStreamExt};
use tempdir::TempDir;
#[get("/")]
async fn ping() -> impl Responder {
"Pong".with_status(StatusCode::OK)
}
#[post("/")]
async fn upload(mut payload: Multipart) -> Result<HttpResponse, Error> {
let dir = TempDir::new("temp")?;
let mut vec: Vec<u8> = vec![];
while let Ok(Some(mut field)) = payload.try_next().await {
let content_type = field.content_disposition().unwrap();
let filename = content_type.get_filename().unwrap();
let tmp_filepath = dir.path().join(sanitize_filename::sanitize(&filename));
let mut filepath = tmp_filepath.clone();
let mut f = web::block(move || std::fs::File::create(&tmp_filepath)).await?;
// Field in turn is stream of *Bytes* object
while let Some(chunk) = field.next().await {
let data = chunk?;
// filesystem operations are blocking, we have to use threadpool
f = web::block(move || f.write_all(&data).map(|_| f)).await?;
}
println!("{:?}", &filepath);
let mut soffice = Command::new("soffice");
let result = soffice
.arg("--headless")
.arg("--convert-to")
.arg("pdf")
.arg(&filepath)
.arg("--outdir")
.arg(std::path::Path::new(&filepath).parent().unwrap())
.output()?;
println!("{}", String::from_utf8_lossy(&result.stdout));
filepath.set_extension("pdf");
vec = web::block(move || {
let file = File::open(filepath)?;
let mut buf_reader = BufReader::new(file);
let mut tmp_vec: Vec<u8> = vec![];
buf_reader.read_to_end(&mut tmp_vec)?;
std::io::Result::Ok(tmp_vec)
})
.await?;
}
Ok(HttpResponse::Ok()
.content_type("application/pdf")
.body(vec)
.into())
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
let port = std::env::var("PORT").unwrap_or("3000".to_string());
let server_address = format!("0.0.0.0:{}", port);
println!("Serving on port {}", server_address);
HttpServer::new(|| App::new().service(upload).service(ping))
.bind(server_address)?
.run()
.await
}
@eduardonunesp
Copy link
Author

FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y software-properties-common
RUN add-apt-repository ppa:libreoffice/ppa
RUN apt-get update
RUN apt-get install -y --force-yes libreoffice
RUN apt-get clean

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

COPY ./target/release/exporter /usr/src/app

EXPOSE 3000

CMD [ "/usr/src/app/exporter" ]

@eduardonunesp
Copy link
Author

eduardonunesp commented Jul 14, 2021

[package]
name = "exporter"
version = "0.1.0"
authors = ["Eduardo Pereira <eduardonunesp@gmail.com>"]
edition = "2018"

[dependencies]
actix-rt = "1.0.0"
actix-web = "2.0.0"
actix-http = "1.0.1"
actix-service = "1.0.5"
actix-multipart = "0.2.0"
futures = "0.3.1"
sanitize-filename = "0.2"
tempdir = "0.3"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment