aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test.yml23
-rw-r--r--Dockerfile27
-rw-r--r--README.md10
-rw-r--r--docker-compose.yml1
-rw-r--r--src/auth.rs7
-rw-r--r--src/main.rs17
-rw-r--r--src/routes/device.rs4
-rw-r--r--src/routes/start.rs3
8 files changed, 69 insertions, 23 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c1bfdf7..90a5fea 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -12,7 +12,6 @@ env:
12 RUSTC_WRAPPER: "sccache" 12 RUSTC_WRAPPER: "sccache"
13 SQLX_OFFLINE: "true" 13 SQLX_OFFLINE: "true"
14 CARGO_TERM_COLOR: always 14 CARGO_TERM_COLOR: always
15 CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
16 15
17jobs: 16jobs:
18 build: 17 build:
@@ -21,23 +20,25 @@ jobs:
21 - name: Run sccache-cache 20 - name: Run sccache-cache
22 uses: mozilla-actions/[email protected] 21 uses: mozilla-actions/[email protected]
23 22
24 - uses: actions/checkout@v3 23 - uses: actions/checkout@v4
25 - uses: actions-rs/toolchain@v1 24 - uses: actions-rs/toolchain@v1
26 with: 25 with:
27 toolchain: stable 26 toolchain: stable
28 target: armv7-unknown-linux-gnueabihf
29 components: rustfmt, clippy 27 components: rustfmt, clippy
30 override: true 28 override: true
31 29
32 - name: Install arm linker 30 - name: Run cargo check
33 run: sudo apt update && sudo apt install gcc-arm-linux-gnueabihf -y 31 uses: actions-rs/cargo@v1
32 with:
33 command: check
34 34
35 - name: Cargo build 35 - name: Run Clippy
36 uses: actions-rs/cargo@v1 36 uses: actions-rs/cargo@v1
37 with: 37 with:
38 command: build 38 command: clippy
39 args: --release --target armv7-unknown-linux-gnueabihf
40 39
40 - name: Set up QEMU
41 uses: docker/setup-qemu-action@v3
41 - name: Set up Docker Buildx 42 - name: Set up Docker Buildx
42 uses: docker/setup-buildx-action@v2 43 uses: docker/setup-buildx-action@v2
43 - name: Login to DockerHub 44 - name: Login to DockerHub
@@ -50,8 +51,10 @@ jobs:
50 id: docker_build 51 id: docker_build
51 uses: docker/build-push-action@v3 52 uses: docker/build-push-action@v3
52 with: 53 with:
53 file: Dockerfile
54 push: true 54 push: true
55 platforms: linux/amd64,linux/arm64
56 cache-from: type=gha
57 cache-to: type=gha,mode=max
55 tags: | 58 tags: |
56 ghcr.io/fxqnlr/webol:dev-latest 59 ghcr.io/fxqnlr/webol:dev-latest
57 ghcr.io/fxqnlr/webol:dev-${{ github.run_number }} \ No newline at end of file 60 ghcr.io/fxqnlr/webol:dev-${{ github.run_number }}
diff --git a/Dockerfile b/Dockerfile
index 0a7db3f..d4473e9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,26 @@
1FROM --platform=arm64 debian:12-slim 1FROM debian:bookworm AS deb_extractor
2RUN cd /tmp && \
3 apt-get update && apt-get download \
4 libc6 && \
5 mkdir /dpkg && \
6 for deb in *.deb; do dpkg --extract $deb /dpkg || exit 10; done
2 7
3WORKDIR /usr/local/webol 8FROM lukemathwalker/cargo-chef:latest-rust-1.73.0 as chef
4COPY ./target/armv7-unknown-linux-gnueabihf/release/webol /usr/local/bin/webol 9WORKDIR app
10
11FROM chef AS planner
12COPY . .
13RUN cargo chef prepare --recipe-path recipe.json
14
15FROM chef as builder
16COPY --from=planner /app/recipe.json recipe.json
17RUN cargo chef cook --release --recipe-path recipe.json
18COPY . .
19RUN cargo build --release
20
21FROM gcr.io/distroless/cc
22COPY --from=builder /app/target/release/webol /
23COPY --from=deb_extractor /dpkg /
5 24
6EXPOSE 7229 25EXPOSE 7229
7CMD ["webol"] 26ENTRYPOINT ["./webol"] \ No newline at end of file
diff --git a/README.md b/README.md
index f062819..fdc7ad2 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,9 @@
1# webol \ No newline at end of file 1# webol
2
3DATABASE_URL: `String`
4
5WEBOL_APIKEY: `String`
6
7WEBOL_SERVERADDR: `Option<String>`
8
9WEBOL_BINDADDR: `Option<String>`
diff --git a/docker-compose.yml b/docker-compose.yml
index 1980356..9d73e9b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,6 +3,7 @@ version: '3.1'
3services: 3services:
4 db: 4 db:
5 image: postgres 5 image: postgres
6 container_name: webol_dev_postgres
6 restart: no 7 restart: no
7 environment: 8 environment:
8 POSTGRES_PASSWORD: postgres 9 POSTGRES_PASSWORD: postgres
diff --git a/src/auth.rs b/src/auth.rs
index b7693a0..81e798f 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -1,21 +1,26 @@
1use std::error::Error; 1use std::error::Error;
2use axum::headers::HeaderValue; 2use axum::headers::HeaderValue;
3use axum::http::StatusCode; 3use axum::http::StatusCode;
4use tracing::error; 4use tracing::{debug, error, trace};
5use crate::auth::AuthError::{MissingSecret, ServerError, WrongSecret}; 5use crate::auth::AuthError::{MissingSecret, ServerError, WrongSecret};
6use crate::config::SETTINGS; 6use crate::config::SETTINGS;
7 7
8pub fn auth(secret: Option<&HeaderValue>) -> Result<bool, AuthError> { 8pub fn auth(secret: Option<&HeaderValue>) -> Result<bool, AuthError> {
9 debug!("auth request with secret {:?}", secret);
9 if let Some(value) = secret { 10 if let Some(value) = secret {
11 trace!("value exists");
10 let key = SETTINGS 12 let key = SETTINGS
11 .get_string("apikey") 13 .get_string("apikey")
12 .map_err(|err| ServerError(Box::new(err)))?; 14 .map_err(|err| ServerError(Box::new(err)))?;
13 if value.to_str().map_err(|err| ServerError(Box::new(err)))? == key.as_str() { 15 if value.to_str().map_err(|err| ServerError(Box::new(err)))? == key.as_str() {
16 debug!("successful auth");
14 Ok(true) 17 Ok(true)
15 } else { 18 } else {
19 debug!("unsuccessful auth (wrong secret)");
16 Err(WrongSecret) 20 Err(WrongSecret)
17 } 21 }
18 } else { 22 } else {
23 debug!("unsuccessful auth (no secret)");
19 Err(MissingSecret) 24 Err(MissingSecret)
20 } 25 }
21} 26}
diff --git a/src/main.rs b/src/main.rs
index bb37dc2..b7306ea 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,6 +7,7 @@ use sqlx::postgres::PgPoolOptions;
7use time::util::local_offset; 7use time::util::local_offset;
8use tracing::{debug, info, level_filters::LevelFilter}; 8use tracing::{debug, info, level_filters::LevelFilter};
9use tracing_subscriber::{EnvFilter, fmt::{self, time::LocalTime}, prelude::*}; 9use tracing_subscriber::{EnvFilter, fmt::{self, time::LocalTime}, prelude::*};
10use crate::config::SETTINGS;
10use crate::routes::device::{get_device, post_device, put_device}; 11use crate::routes::device::{get_device, post_device, put_device};
11use crate::routes::start::start; 12use crate::routes::start::start;
12 13
@@ -37,13 +38,12 @@ async fn main() {
37 38
38 let version = env!("CARGO_PKG_VERSION"); 39 let version = env!("CARGO_PKG_VERSION");
39 40
40 info!("starting webol v{}", version); 41 info!("start webol v{}", version);
41 42
42 let db = init_db_pool().await; 43 let db = init_db_pool().await;
43 44
44 let shared_state = Arc::new(AppState { db }); 45 let shared_state = Arc::new(AppState { db });
45 46
46 // build our application with a single route
47 let app = Router::new() 47 let app = Router::new()
48 .route("/start", post(start)) 48 .route("/start", post(start))
49 .route("/device", get(get_device)) 49 .route("/device", get(get_device))
@@ -51,8 +51,9 @@ async fn main() {
51 .route("/device", post(post_device)) 51 .route("/device", post(post_device))
52 .with_state(shared_state); 52 .with_state(shared_state);
53 53
54 // run it with hyper on localhost:3000 54 let addr = SETTINGS.get_string("serveraddr").unwrap_or("0.0.0.0:7229".to_string());
55 axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) 55 info!("start server on {}", addr);
56 axum::Server::bind(&addr.parse().unwrap())
56 .serve(app.into_make_service()) 57 .serve(app.into_make_service())
57 .await 58 .await
58 .unwrap(); 59 .unwrap();
@@ -63,9 +64,13 @@ pub struct AppState {
63} 64}
64 65
65async fn init_db_pool() -> PgPool { 66async fn init_db_pool() -> PgPool {
67 #[cfg(not(debug_assertions))]
68 let db_url = SETTINGS.get_string("database.url").unwrap();
69
70 #[cfg(debug_assertions)]
66 let db_url = env::var("DATABASE_URL").unwrap(); 71 let db_url = env::var("DATABASE_URL").unwrap();
67 72
68 debug!("attempting to connect dbPool to '{}'", db_url); 73 debug!("attempt to connect dbPool to '{}'", db_url);
69 74
70 let pool = PgPoolOptions::new() 75 let pool = PgPoolOptions::new()
71 .max_connections(5) 76 .max_connections(5)
@@ -76,4 +81,4 @@ async fn init_db_pool() -> PgPool {
76 info!("dbPool successfully connected to '{}'", db_url); 81 info!("dbPool successfully connected to '{}'", db_url);
77 82
78 pool 83 pool
79} \ No newline at end of file 84}
diff --git a/src/routes/device.rs b/src/routes/device.rs
index d5d7144..025c7d0 100644
--- a/src/routes/device.rs
+++ b/src/routes/device.rs
@@ -4,11 +4,13 @@ use axum::headers::HeaderMap;
4use axum::Json; 4use axum::Json;
5use serde::{Deserialize, Serialize}; 5use serde::{Deserialize, Serialize};
6use serde_json::{json, Value}; 6use serde_json::{json, Value};
7use tracing::info;
7use crate::auth::auth; 8use crate::auth::auth;
8use crate::db::Device; 9use crate::db::Device;
9use crate::error::WebolError; 10use crate::error::WebolError;
10 11
11pub async fn get_device(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<GetDevicePayload>) -> Result<Json<Value>, WebolError> { 12pub async fn get_device(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<GetDevicePayload>) -> Result<Json<Value>, WebolError> {
13 info!("GET request");
12 let secret = headers.get("authorization"); 14 let secret = headers.get("authorization");
13 if auth(secret).map_err(WebolError::Auth)? { 15 if auth(secret).map_err(WebolError::Auth)? {
14 let device = sqlx::query_as!( 16 let device = sqlx::query_as!(
@@ -33,6 +35,7 @@ pub struct GetDevicePayload {
33} 35}
34 36
35pub async fn put_device(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<PutDevicePayload>) -> Result<Json<Value>, WebolError> { 37pub async fn put_device(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<PutDevicePayload>) -> Result<Json<Value>, WebolError> {
38 info!("PUT request");
36 let secret = headers.get("authorization"); 39 let secret = headers.get("authorization");
37 if auth(secret).map_err(WebolError::Auth)? { 40 if auth(secret).map_err(WebolError::Auth)? {
38 sqlx::query!( 41 sqlx::query!(
@@ -64,6 +67,7 @@ pub struct PutDeviceResponse {
64} 67}
65 68
66pub async fn post_device(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<PostDevicePayload>) -> Result<Json<Value>, WebolError> { 69pub async fn post_device(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<PostDevicePayload>) -> Result<Json<Value>, WebolError> {
70 info!("POST request");
67 let secret = headers.get("authorization"); 71 let secret = headers.get("authorization");
68 if auth(secret).map_err(WebolError::Auth)? { 72 if auth(secret).map_err(WebolError::Auth)? {
69 let device = sqlx::query_as!( 73 let device = sqlx::query_as!(
diff --git a/src/routes/start.rs b/src/routes/start.rs
index d16ea4e..163d58c 100644
--- a/src/routes/start.rs
+++ b/src/routes/start.rs
@@ -12,6 +12,7 @@ use crate::db::Device;
12use crate::error::WebolError; 12use crate::error::WebolError;
13 13
14pub async fn start(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<StartPayload>) -> Result<Json<Value>, WebolError> { 14pub async fn start(State(state): State<Arc<crate::AppState>>, headers: HeaderMap, Json(payload): Json<StartPayload>) -> Result<Json<Value>, WebolError> {
15 info!("POST request");
15 let secret = headers.get("authorization"); 16 let secret = headers.get("authorization");
16 if auth(secret).map_err(WebolError::Auth)? { 17 if auth(secret).map_err(WebolError::Auth)? {
17 let device = sqlx::query_as!( 18 let device = sqlx::query_as!(
@@ -28,7 +29,7 @@ pub async fn start(State(state): State<Arc<crate::AppState>>, headers: HeaderMap
28 29
29 let bind_addr = SETTINGS 30 let bind_addr = SETTINGS
30 .get_string("bindaddr") 31 .get_string("bindaddr")
31 .map_err(|err| WebolError::Server(Box::new(err)))?; 32 .unwrap_or("0.0.0.0:1111".to_string());
32 33
33 let _ = send_packet( 34 let _ = send_packet(
34 &bind_addr.parse().map_err(|err| WebolError::Server(Box::new(err)))?, 35 &bind_addr.parse().map_err(|err| WebolError::Server(Box::new(err)))?,