start of service stuff implementation

This commit is contained in:
OMGeeky
2024-10-10 19:19:34 +02:00
parent 51c8548e5c
commit 0516ffa9bb
5 changed files with 221 additions and 5 deletions

View File

@@ -5,7 +5,10 @@ edition = "2021"
[dependencies]
rocket = "0.5.1"
rocket_dyn_templates = { version = "0.2.0", features = ["tera"] }
twba-common.workspace = true
lazy_static = "1.5.0"
derive_more = { version = "1.0.0", features = ["full"] }
serde = { version = "1.0.203", features = ["derive"] }

View File

@@ -1,9 +1,11 @@
use crate::services::init_services;
use derive_more::{FromStr, FromStrError};
#[macro_use]
extern crate rocket;
use rocket::request::FromParam;
use rocket::tokio::time::{sleep, Duration};
use rocket_dyn_templates::Template;
use std::sync::OnceLock;
use twba_common::init_tracing;
use twba_common::prelude::twba_local_db;
@@ -14,10 +16,7 @@ use twba_common::prelude::Conf;
static CLIENT: OnceLock<DatabaseConnection> = OnceLock::new();
static CONF: OnceLock<Conf> = OnceLock::new();
#[get("/service/<service>/info")]
fn service_info(service: AvailableServices) -> String {
format!("Here is some info about the service: name: {service}")
}
mod services;
#[get("/delay/<seconds>")]
async fn delay(seconds: u64) -> String {
@@ -50,8 +49,20 @@ async fn get_new_client<'a>() -> Result<DatabaseConnection, MainError> {
async fn main() -> Result<(), MainError> {
let _guard = init_tracing("twba_uploader");
info!("Hello world!");
let services = init_services();
let _rocket = rocket::build()
.mount("/", routes![index, delay, service_info])
.manage(services)
.mount("/", routes![index, delay,])
.mount(
"/services/",
routes![
services::service,
services::service_info,
services::update_progress,
services::increment_progress,
],
)
.attach(Template::fairing())
.launch()
.await?;

103
src/services.rs Normal file
View File

@@ -0,0 +1,103 @@
use crate::AvailableServices;
use rocket::fs::{relative, FileServer};
use rocket::State;
use rocket_dyn_templates::{context, Template};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::SystemTime;
use std::time::UNIX_EPOCH;
#[derive(serde::Serialize)]
pub struct Service {
name: String,
id: String,
tasks: Vec<Task>,
}
#[derive(serde::Serialize)]
pub struct Task {
name: String,
id: String,
progress: Arc<AtomicUsize>, // Progress in percentage
}
#[get("/<service>/info")]
pub(super) fn service_info(service: AvailableServices) -> String {
format!("Here is some info about the service: name: {service}")
}
pub(super) fn init_services() -> Vec<Service> {
let task1_progress = Arc::new(AtomicUsize::new(60));
let task2_progress = Arc::new(AtomicUsize::new(100));
let task3_progress = Arc::new(AtomicUsize::new(20));
let task4_progress = Arc::new(AtomicUsize::new(80));
vec![
Service {
name: "Service A".to_string(),
id: "s1".to_string(),
tasks: vec![
Task {
name: "Task 1".to_string(),
id: "t1".to_string(),
progress: task1_progress,
},
Task {
name: "Task 2".to_string(),
id: "t2".to_string(),
progress: task2_progress,
},
],
},
Service {
name: "Service B".to_string(),
id: "s2".to_string(),
tasks: vec![
Task {
name: "Task 3".to_string(),
id: "t3".to_string(),
progress: task3_progress,
},
Task {
name: "Task 4".to_string(),
id: "t4".to_string(),
progress: task4_progress,
},
],
},
]
}
#[get("/")]
pub(super) fn service(services: &State<Vec<Service>>) -> Template {
let x = services.inner();
let last_update = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
Template::render(
"services-overview",
context! { services: x , last_update: last_update },
)
}
#[post("/<service>/increment-progress/<task>")]
pub fn increment_progress(
service: String,
task: String,
services: &State<Vec<Service>>,
) -> Result<(), String> {
if let Some(service) = services.inner().iter().find(|x| x.id == service) {
if let Some(task) = service.tasks.iter().find(|x| x.id == task) {
task.progress.fetch_add(1, Ordering::AcqRel);
Ok(())
} else {
Err("task with index not found".to_string())
}
} else {
Err("service with index not found".to_string())
}
}
#[get("/update_progress")]
pub fn update_progress(services: &State<Vec<Service>>) -> Template {
Template::render("services", context! { services: services.inner() })
}

View File

@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Services and Tasks</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div class="container">
<h1>Services and Tasks</h1>
<div class="row" id="services-container">
</div>
<div id="last-update-element" data-timestamp="0">hi</div>
<button id="update-button">Update Progress</button>
</div>
<script>
function update_task_progress(service_id, task_id) {
console.log('updating task: ' + service_id + ' ' + task_id);
// $.post('/update_progress', {
$.ajax({
type: "POST",
url: "/services/" + service_id + "/increment-progress/" + task_id,
success: function (data) {
console.log('success updating', data);
updateProgress();
},
error: function (error) {
console.error("Error updating progress:", error);
// Handle the error appropriately (e.g., display an error message)
}
});
}
function updateProgress() {
$.get("/services/update_progress", function (data) {
$("#services-container").html(data);
updateLastUpdateTime();
});
}
function updateLastUpdateTime() {
let lastUpdateElement = $("#last-update-element");
lastUpdateElement.text("Last updated " + new Date().toLocaleString('de-DE'));
console.log('updating progress: ' + lastUpdateElement.text());
}
let updateInterval;
function startUpdateInterval(interval) {
clearInterval(updateInterval); // Clear any existing interval
updateInterval = setInterval(updateProgress, interval);
}
$(document).ready(function () {
const normalUpdateInterval = 5000;
const slowUpdateInterval = 30000;
$("#update-button").click(updateProgress);
updateProgress();
// Initial update and fast interval
updateProgress();
startUpdateInterval(normalUpdateInterval);
// Detect visibility changes
document.addEventListener("visibilitychange", function () {
if (document.visibilityState === "visible") {
// Fast updates when tab is visible
startUpdateInterval(normalUpdateInterval);
} else {
// Slow updates when tab is hidden
startUpdateInterval(slowUpdateInterval);
}
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,16 @@
{% for service in services %}
<div class="col-md-6">
<h2>{{ service.name }}</h2>
<ul class="list-group">
{% for task in service.tasks %}
<li class="list-group-item">
{{ task.name }}
<div class="progress">
<div class="progress-bar" role="progressbar" style="width:{{ task.progress }}%;" aria-valuenow="{{ task.progress }}" aria-valuemin="0" aria-valuemax="100">{{ task.progress }}%</div>
</div>
<button id="increment-button" onclick="update_task_progress( '{{service.id}}','{{task.id}}' )">+</button>
</li>
{% endfor %}
</ul>
</div>
{% endfor %}