Incorporate beachhead files from the previous mono-repo

This commit is contained in:
Joshua Coles 2024-03-01 20:04:00 +00:00
parent 50709621fd
commit 8b2f0102c4
8 changed files with 4199 additions and 5 deletions

36
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Build and Publish Docker Container
on:
push:
branches:
- main
jobs:
build:
runs-on: macos-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker
uses: docker/login-action@v1
with:
registry: git.joshuacoles.me
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker image -- toggl-portal
uses: docker/build-push-action@675965c0e16f1a0f94ecafff969d8c966f92c17b
with:
context: .
push: true
tags: git.joshuacoles.me/personal/beachhead-services/toggl-portal:arm
build-args: |
APP_NAME=toggl-portal
PACKAGE_NAME=toggl-portal

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
/.idea
/ignore

4009
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,10 @@ name = "toggl-portal"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "toggl-portal"
path = "src/main.rs"
[dependencies]
tokio = { version = "1.0", features = ["full"] }
axum = { version = "0.6.20", features = ["multipart"] }
@ -13,7 +17,6 @@ tower-http = { version = "0.4.3", features = ["trace", "cors", "compression-gzip
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json"] }
anyhow = { version = "^1.0", features = ["backtrace"] }
beachhead = { path = "../" }
hyper = "0.14.27"
reqwest = { version = "0.11.20", features = ["rustls", "json"] }
base64 = "0.21.4"

88
Dockerfile Normal file
View File

@ -0,0 +1,88 @@
# syntax=docker/dockerfile:1
################################################################################
# Create a stage for building the application.
ARG RUST_VERSION=1.71.1
ARG APP_NAME=timing-beachhead
ARG PACKAGE_NAME=beachhead
FROM rust:${RUST_VERSION}-slim-bullseye AS build
ARG APP_NAME
ARG PACKAGE_NAME
WORKDIR /app
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
pkg-config \
libssl-dev \
&& \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Build the application.
# Leverage a cache mount to /usr/local/cargo/registry/
# for downloaded dependencies and a cache mount to /app/target/ for
# compiled dependencies which will speed up subsequent builds.
# Leverage a bind mount to the src directory to avoid having to copy the
# source code into the container. Once built, copy the executable to an
# output directory before the cache mounted /app/target is unmounted.
RUN --mount=type=bind,source=src,target=src \
--mount=type=bind,source=obsidian-portal,target=obsidian-portal \
--mount=type=bind,source=toggl-portal,target=toggl-portal \
--mount=type=bind,source=lectures-portal,target=lectures-portal \
--mount=type=bind,source=Cargo.toml,target=Cargo.toml \
--mount=type=bind,source=Cargo.lock,target=Cargo.lock \
--mount=type=cache,target=/app/target/ \
--mount=type=cache,target=/usr/local/cargo/registry/ \
<<EOF
set -e
cargo build --locked --release --package $PACKAGE_NAME
cp ./target/release/$APP_NAME /bin/server
EOF
################################################################################
# Create a new stage for running the application that contains the minimal
# runtime dependencies for the application. This often uses a different base
# image from the build stage where the necessary files are copied from the build
# stage.
#
# The example below uses the debian bullseye image as the foundation for running the app.
# By specifying the "bullseye-slim" tag, it will also use whatever happens to be the
# most recent version of that tag when you build your Dockerfile. If
# reproducability is important, consider using a digest
# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
FROM debian:bullseye-slim AS final
# Install curl for health check, clean up apt
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Disabled to allow read access to the database file.
## Create a non-privileged user that the app will run under.
## See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
#ARG UID=10001
#RUN adduser \
# --disabled-password \
# --gecos "" \
# --home "/nonexistent" \
# --shell "/sbin/nologin" \
# --no-create-home \
# --uid "${UID}" \
# appuser
#USER appuser
# Copy the executable from the "build" stage.
COPY --from=build /bin/server /bin/
# Expose the port that the application listens on.
ENV ADDRESS=0.0.0.0:3000
EXPOSE 3000
HEALTHCHECK \
CMD curl -f http://localhost:3000/health || exit 1
# What the container should run when it is started.
CMD ["/bin/server"]

View File

@ -12,7 +12,7 @@ use axum::routing::{get, post};
use axum::{Extension, Json, Router};
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use beachhead::{shutdown_signal, Result};
use utils::{shutdown_signal, Result};
use chrono::{NaiveDate, NaiveTime};
use clap::Parser;
use migration::{Migrator, MigratorTrait};
@ -30,6 +30,7 @@ mod db;
mod entity;
mod poll;
mod types;
mod utils;
#[derive(Debug, Clone, Parser)]
struct Config {
@ -202,7 +203,7 @@ fn from_csv_row(row: csv::StringRecord) -> ActiveModel {
async fn import_csv(
Extension(db): Extension<DatabaseConnection>,
mut multipart: Multipart,
) -> beachhead::Result<impl IntoResponse> {
) -> Result<impl IntoResponse> {
return Ok((StatusCode::NOT_IMPLEMENTED, "Not implemented"));
// while let Some(field) = multipart.next_field().await? {

View File

@ -3,7 +3,7 @@ use crate::entity::{client, project, time_entry};
use crate::types::{Project, ProjectClient, TogglQuery};
use sea_orm::{DatabaseConnection, EntityTrait, QuerySelect};
use tracing::instrument;
use crate::day_exclusivity_condition;
use crate::{day_exclusivity_condition, utils};
#[tracing::instrument(skip(client, db))]
pub async fn poll_job(client: TogglClient, db: DatabaseConnection, poll_period: u64) {
@ -33,7 +33,7 @@ pub async fn poll_job(client: TogglClient, db: DatabaseConnection, poll_period:
pub async fn perform_poll(
client: &TogglClient,
db: &DatabaseConnection,
) -> beachhead::Result<usize> {
) -> utils::Result<usize> {
let now = chrono::Utc::now();
let today_string = now
.date_naive()

54
src/utils.rs Normal file
View File

@ -0,0 +1,54 @@
use axum::http::StatusCode;
use axum::response::IntoResponse;
use tokio::signal;
#[derive(Debug)]
pub struct AppError(anyhow::Error);
// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
// `Result<_, AppError>`. That way you don't need to do that manually.
impl<E> From<E> for AppError
where
E: Into<anyhow::Error>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}
impl IntoResponse for AppError {
fn into_response(self) -> axum::response::Response {
tracing::error!("{:?}", self);
(
StatusCode::INTERNAL_SERVER_ERROR,
"An internal error occurred",
)
.into_response()
}
}
pub type Result<T, E = AppError> = std::result::Result<T, E>;
pub async fn shutdown_signal() {
let ctrl_c = async {
signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {},
_ = terminate => {},
}
}