Skip to content

Commit

Permalink
feat(services): add services page
Browse files Browse the repository at this point in the history
  • Loading branch information
ravenclaw900 committed Oct 3, 2021
1 parent 2f47a66 commit db128e6
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 7 deletions.
34 changes: 34 additions & 0 deletions src/backend/src/sockets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,37 @@ async fn management_handler(
}
}

async fn service_handler(
socket_send: &mut SplitSink<warp::ws::WebSocket, warp::ws::Message>,
quit: &Arc<AtomicBool>,
data_recv: &mut Receiver<types::Request>,
) {
loop {
let _send = socket_send
.send(Message::text(
serde_json::to_string(&types::ServiceList {
services: systemdata::services(),
})
.unwrap(),
))
.await;
if quit.load(Relaxed) {
quit.store(false, Relaxed);
break;
}
match data_recv.try_recv() {
Err(_) => {}
Ok(data) => {
Command::new("systemctl")
.args([data.cmd, (&*data.args[0]).to_string()])
.spawn()
.unwrap();
}
}
thread::sleep(time::Duration::from_secs(2));
}
}

pub async fn socket_handler(socket: warp::ws::WebSocket) {
let (mut socket_send, mut socket_recv) = socket.split();
let (data_send, mut data_recv) = broadcast::channel(1);
Expand Down Expand Up @@ -181,6 +212,9 @@ pub async fn socket_handler(socket: warp::ws::WebSocket) {
"/management" => {
management_handler(&mut socket_send, &quit_clone, &mut data_recv).await;
}
"/service" => {
service_handler(&mut socket_send, &quit_clone, &mut data_recv).await;
}
_ => {}
}
}
Expand Down
63 changes: 57 additions & 6 deletions src/backend/src/systemdata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,11 @@ pub fn processes() -> Vec<types::ProcessData> {

pub fn dpsoftware() -> Vec<types::DPSoftwareData> {
let out = Command::new("/boot/dietpi/dietpi-software")
.args(["list"])
.arg("list")
.output()
.unwrap()
.stdout;
let out_list = from_utf8(out.as_slice())
.unwrap()
.split('\n')
.collect::<Vec<&str>>();
let out_list = from_utf8(&out).unwrap().split('\n').collect::<Vec<&str>>();
let mut software_list = Vec::new();
software_list.reserve(match out_list.len().checked_sub(9) {
Some(num) => num,
Expand Down Expand Up @@ -216,7 +213,7 @@ pub fn host() -> types::HostData {
let dp_version: Vec<&str> = dp_file.split(&['=', '\n'][..]).collect();
let installed_pkgs = from_utf8(
&Command::new("dpkg")
.args(["--get-selections"])
.arg("--get-selections")
.output()
.unwrap()
.stdout,
Expand All @@ -239,3 +236,57 @@ pub fn host() -> types::HostData {
upgrades: upgradable_pkgs,
}
}

pub fn services() -> Vec<types::ServiceData> {
let services = &Command::new("/boot/dietpi/dietpi-services")
.arg("status")
.output()
.unwrap()
.stdout;
let services_str = from_utf8(services).unwrap();
let mut services_list = Vec::new();
for element in services_str
.replace("[FAILED] DietPi-Services | \u{25cf} ", "dpdashboardtemp")
.replace("[ INFO ] DietPi-Services | ", "dpdashboardtemp")
.replace("[ OK ] DietPi-Services | ", "dpdashboardtemp")
.split("dpdashboardtemp")
.skip(1)
{
let mut name = String::new();
let mut log = String::new();
let mut status = String::new();
let mut start = String::new();
if element.contains(".service") {
for (index, el1) in element.split('\n').enumerate() {
status = "failed".to_string();
match index {
0 => name = el1.split_once(".service").unwrap().0.to_string(),
9.. => log.push_str(format!("{}<br>", el1).as_str()),
_ => (),
}
}
} else {
let (el1, el2) = element.split_once(':').unwrap();
name = el1.trim().to_string();
match el2.split_once(" since ") {
Some(statusdate) => {
match statusdate.0.trim() {
"active (running)" => status = "running".to_string(),
"active (exited)" => status = "exited".to_string(),
"inactive (dead)" => status = "dead".to_string(),
_ => status = "unknown".to_string(),
}
start = statusdate.1.trim().to_string();
}
None => status = "dead".to_string(),
}
}
services_list.push(types::ServiceData {
name,
log,
status,
start,
});
}
services_list
}
15 changes: 14 additions & 1 deletion src/backend/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub struct DPSoftwareList {
pub response: String,
}

#[derive(serde::Serialize, Debug)]
#[derive(serde::Serialize)]
pub struct HostData {
pub hostname: String,
pub uptime: u64,
Expand All @@ -70,3 +70,16 @@ pub struct HostData {
pub packages: usize,
pub upgrades: u32,
}

#[derive(serde::Serialize, Debug)]
pub struct ServiceData {
pub name: String,
pub log: String,
pub status: String,
pub start: String,
}

#[derive(serde::Serialize)]
pub struct ServiceList {
pub services: Vec<ServiceData>,
}
17 changes: 17 additions & 0 deletions src/frontend/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
faTerminal,
faUser,
faBars,
faList,
} from "@fortawesome/free-solid-svg-icons";
import Management from "./pages/Management.svelte";
import FileBrowser from "./pages/FileBrowser.svelte";
import Service from "./pages/Service.svelte";
interface socketData {
software?: software[];
response?: string;
processes?: processes[];
services: services[];
}
interface software {
Expand All @@ -42,6 +45,13 @@
status: string;
}
interface services {
name: string;
status: string;
log: string;
start: string;
}
let url = "";
let socket;
Expand Down Expand Up @@ -100,6 +110,10 @@
>Processes</NavbarLink
></span
>
<span on:click={pollServer}
><NavbarLink icon={faList} to="service">Services</NavbarLink
></span
>
<span on:click={pollServer}
><NavbarLink icon={faDatabase} to="software"
>Software</NavbarLink
Expand Down Expand Up @@ -148,6 +162,9 @@
<Route path="browser"
><FileBrowser {socket} {socketData} /></Route
>
<Route path="service"
><Service {socket} {socketData} /></Route
>
<Route path=""><h3>Page not found</h3></Route>
{:else}
<h3 class="dark:text-white">Connecting to API...</h3>
Expand Down
98 changes: 98 additions & 0 deletions src/frontend/src/pages/Service.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts">
import {
faSquare,
faPlay,
faRedoAlt,
} from "@fortawesome/free-solid-svg-icons";
import Fa from "svelte-fa";
export let socket;
export let socketData: serviceData;
interface serviceData {
services?: services[];
}
interface services {
name: string;
status: string;
log: string;
start: string;
}
function sendAction(action, name) {
socket.send(JSON.stringify({ cmd: action, args: [name] }));
}
</script>

<main>
{#if socketData.services != undefined}
<table
class="border border-gray-300 dark:border-gray-700 w-full table-fixed break-words"
>
<tr class="bg-dplime">
<th>Name</th>
<th>Status</th>
<th>Log</th>
<th>Start Time</th>
<th>Actions</th>
</tr>
{#each socketData.services as service}
<tr
class="mt-32 even:bg-white odd:bg-gray-200 dark:even:bg-black dark:odd:bg-gray-800 dark:text-white dark:border-gray-600 border-t-2 border-gray-300 border-opacity-50"
>
<td class="p-2">{service.name}</td>
<td class="p-2">{service.status}</td>
<td class="p-2">
{#if service.log != ""}
<details>
<summary> Show log </summary>
{@html service.log}
</details>
{/if}</td
>
<td class="p-2">{service.start}</td>
<td class="p-2 space-x-2">
{#if service.status == "dead" || service.status == "failed"}
<span
on:click={() =>
sendAction("start", service.name)}
title="Start"
><Fa
icon={faPlay}
class="hover:bg-gray-500 hover:bg-opacity-50 active:bg-opacity-75 rounded-sm"
style="padding: 0.125rem"
size="lg"
/></span
>
{:else}
<span
on:click={() =>
sendAction("stop", service.name)}
title="Stop"
><Fa
icon={faSquare}
class="hover:bg-gray-500 hover:bg-opacity-50 active:bg-opacity-75 p-0.5 rounded-sm"
style="padding: 0.125rem"
size="lg"
/></span
><span
on:click={() =>
sendAction("restart", service.name)}
title="Restart"
><Fa
icon={faRedoAlt}
class="hover:bg-gray-500 hover:bg-opacity-50 active:bg-opacity-75 p-0.5 rounded-sm"
style="padding: 0.125rem"
size="lg"
/></span
>
{/if}</td
>
</tr>
{/each}
</table>
{:else}
<h3 class="dark:text-white">Getting data...</h3>
{/if}
</main>

0 comments on commit db128e6

Please sign in to comment.