Prepare dockerized build for Railway

This commit is contained in:
2023-06-16 20:14:59 -05:00
parent e8cffce4d1
commit ea22c91cac
6 changed files with 140 additions and 9 deletions

17
Cargo.lock generated
View File

@@ -137,6 +137,21 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5" checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5"
[[package]]
name = "dotenvy"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]]
name = "envy"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "fdeflate" name = "fdeflate"
version = "0.3.0" version = "0.3.0"
@@ -897,6 +912,8 @@ name = "time-banner"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"axum", "axum",
"dotenvy",
"envy",
"futures", "futures",
"png", "png",
"resvg", "resvg",

View File

@@ -15,3 +15,5 @@ tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
futures = "0.3.28" futures = "0.3.28"
png = "0.17.9" png = "0.17.9"
dotenvy = "0.15.7"
envy = "0.4.2"

43
Dockerfile Normal file
View File

@@ -0,0 +1,43 @@
# Build Stage
FROM rust:1.68.0 as builder
RUN USER=root cargo new --bin time-banner
WORKDIR ./time-banner
ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
COPY ./Cargo.toml ./Cargo.toml
# Build empty app with downloaded dependencies to produce a stable image layer for next build
RUN cargo build --release
# Build web app with own code
RUN rm src/*.rs
ADD . ./
RUN rm ./target/release/deps/time-banner*
RUN cargo build --release
FROM debian:buster-slim
ARG APP=/usr/src/app
RUN apt-get update \
&& apt-get install -y ca-certificates tzdata \
&& rm -rf /var/lib/apt/lists/*
ENV TZ=Etc/UTC \
APP_USER=appuser
RUN groupadd $APP_USER \
&& useradd -g $APP_USER $APP_USER \
&& mkdir -p ${APP}
COPY --from=builder /time-banner/target/release/time-banner ${APP}/time-banner
RUN chown -R $APP_USER:$APP_USER ${APP}
USER $APP_USER
WORKDIR ${APP}
EXPOSE 3000
ENV PORT 3000
CMD ["./time-banner"]

57
src/config.rs Normal file
View File

@@ -0,0 +1,57 @@
use serde::Deserialize;
use tracing::Level;
#[derive(Deserialize, Debug)]
pub enum Environment {
Production,
Development,
}
#[derive(Deserialize, Debug)]
pub struct Configuration {
#[serde(default = "default_env")]
pub env: Environment,
#[serde(default = "default_port")]
pub port: u16,
}
fn default_port() -> u16 {
3000
}
fn default_env() -> Environment {
Environment::Development
}
impl Configuration {
pub fn socket_addr(&self) -> [u8; 4] {
match self.env {
Environment::Production => {
let socket = [0, 0, 0, 0];
tracing::info!(
"Starting Production on {:?}:{}",
socket.as_slice(),
self.port
);
socket
}
Environment::Development => {
let socket = [127, 0, 0, 1];
tracing::info!(
"Starting Development on {:?}:{}",
socket.as_slice(),
self.port
);
socket
}
}
}
pub fn log_level(&self) -> Level {
match self.env {
Environment::Production => Level::INFO,
Environment::Development => Level::DEBUG,
}
}
}

View File

@@ -1,3 +1,5 @@
mod config;
use std::net::SocketAddr; use std::net::SocketAddr;
use axum::{http::StatusCode, Json, response::IntoResponse, Router, routing::{get, post}}; use axum::{http::StatusCode, Json, response::IntoResponse, Router, routing::{get, post}};
@@ -5,21 +7,33 @@ use axum::body::{Bytes, Full};
use axum::extract::ConnectInfo; use axum::extract::ConnectInfo;
use axum::http::header; use axum::http::header;
use axum::response::Response; use axum::response::Response;
use dotenvy::dotenv;
use config::Configuration;
mod svg; mod svg;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
// initialize tracing // Parse dotenv files and expose them as environment variables
tracing_subscriber::fmt::init(); dotenv().ok();
let app = Router::new() // envy uses our Configuration struct to parse environment variables
.route("/", get(root)); let config = envy::from_env::<Configuration>().expect("Please provide PORT env var");
// initialize tracing
tracing_subscriber::fmt()
// With the log_level from our config
.with_max_level(config.log_level())
.init();
// build our application with a route
let app = Router::new().route("/", get(root_handler));
// run our app with hyper // run our app with hyper
// `axum::Server` is a re-export of `hyper::Server` // `axum::Server` is a re-export of `hyper::Server`
let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); let addr = SocketAddr::from((config.socket_addr(), config.port));
tracing::debug!("listening on {}", addr);
axum::Server::bind(&addr) axum::Server::bind(&addr)
.serve(app.into_make_service_with_connect_info::<SocketAddr>()) .serve(app.into_make_service_with_connect_info::<SocketAddr>())
.await .await
@@ -27,7 +41,7 @@ async fn main() {
} }
// basic handler that responds with a static string // basic handler that responds with a static string
async fn root(connect_info: ConnectInfo<SocketAddr>) -> impl IntoResponse { async fn root_handler(connect_info: ConnectInfo<SocketAddr>) -> impl IntoResponse {
let raw_image = svg::get(); let raw_image = svg::get();
if raw_image.is_err() { if raw_image.is_err() {

View File

@@ -29,8 +29,6 @@ pub fn get() -> Result<Vec<u8>, RenderError> {
fontdb.load_system_fonts(); fontdb.load_system_fonts();
let svg_data = std::fs::read("test.svg").unwrap(); let svg_data = std::fs::read("test.svg").unwrap();
// print bytes as string
println!("{:?}", String::from_utf8(svg_data.clone()).unwrap());
let mut tree_result = usvg::Tree::from_data(&svg_data, &opt); let mut tree_result = usvg::Tree::from_data(&svg_data, &opt);
if tree_result.is_err() { return Err(RenderError { message: Some("Failed to parse".to_string()) }); } if tree_result.is_err() { return Err(RenderError { message: Some("Failed to parse".to_string()) }); }