control systemd service
This commit is contained in:
parent
a8578a10cc
commit
3bd18b3fa6
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1027,7 +1027,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ffplayout-api"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"actix-multipart",
|
||||
"actix-web",
|
||||
|
3
assets/11-ffplayout
Normal file
3
assets/11-ffplayout
Normal file
@ -0,0 +1,3 @@
|
||||
# give user www-data permission to control the ffplayout systemd service
|
||||
|
||||
www-data ALL = NOPASSWD: /bin/systemctl start ffplayout.service, /bin/systemctl stop ffplayout.service, /bin/systemctl reload ffplayout.service, /bin/systemctl restart ffplayout.service, /bin/systemctl status ffplayout.service, /bin/systemctl is-active ffplayout.service
|
@ -138,6 +138,10 @@ Response is in JSON format
|
||||
- **GET** `/api/control/{id}/media/last/`\
|
||||
Response is in JSON format
|
||||
|
||||
- **POST** `/api/control/{id}/process/`\
|
||||
JSON Data: `{"command": "<start/stop/restart/status>"}`
|
||||
Response is in TEXT format
|
||||
|
||||
#### Playlist Operations
|
||||
|
||||
- **GET** `/api/playlist/{id}/2022-06-20`\
|
||||
|
@ -4,7 +4,7 @@ description = "Rest API for ffplayout"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Jonathan Baecker jonbae77@gmail.com"]
|
||||
readme = "README.md"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -17,9 +17,9 @@ use utils::{
|
||||
routes::{
|
||||
add_preset, add_user, del_playlist, file_browser, gen_playlist, get_playlist,
|
||||
get_playout_config, get_presets, get_settings, jump_to_last, jump_to_next, login,
|
||||
media_current, media_last, media_next, move_rename, patch_settings, remove, reset_playout,
|
||||
save_file, save_playlist, send_text_message, update_playout_config, update_preset,
|
||||
update_user,
|
||||
media_current, media_last, media_next, move_rename, patch_settings, process_control,
|
||||
remove, reset_playout, save_file, save_playlist, send_text_message, update_playout_config,
|
||||
update_preset, update_user,
|
||||
},
|
||||
run_args, Role,
|
||||
};
|
||||
@ -92,6 +92,7 @@ async fn main() -> std::io::Result<()> {
|
||||
.service(media_current)
|
||||
.service(media_next)
|
||||
.service(media_last)
|
||||
.service(process_control)
|
||||
.service(get_playlist)
|
||||
.service(save_playlist)
|
||||
.service(gen_playlist)
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, process::Command};
|
||||
|
||||
use reqwest::{
|
||||
header::{HeaderMap, AUTHORIZATION, CONTENT_TYPE},
|
||||
@ -7,7 +7,8 @@ use reqwest::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use simplelog::*;
|
||||
|
||||
use crate::utils::{errors::ServiceError, playout_config};
|
||||
use crate::utils::{errors::ServiceError, handles::db_get_settings, playout_config};
|
||||
use ffplayout_lib::vec_strings;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
struct RpcObj<T> {
|
||||
@ -44,6 +45,62 @@ impl<T> RpcObj<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Process {
|
||||
pub command: String,
|
||||
}
|
||||
|
||||
struct SystemD {
|
||||
service: String,
|
||||
cmd: Vec<String>,
|
||||
}
|
||||
|
||||
impl SystemD {
|
||||
async fn new(id: i64) -> Result<Self, ServiceError> {
|
||||
let settings = db_get_settings(&id).await?;
|
||||
|
||||
Ok(Self {
|
||||
service: settings.service,
|
||||
cmd: vec_strings!["systemctl"],
|
||||
})
|
||||
}
|
||||
|
||||
fn start(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["start".to_string(), self.service]);
|
||||
|
||||
Command::new("sudo").args(self.cmd).spawn()?;
|
||||
|
||||
Ok("Success".to_string())
|
||||
}
|
||||
|
||||
fn stop(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd.append(&mut vec!["stop".to_string(), self.service]);
|
||||
|
||||
Command::new("sudo").args(self.cmd).spawn()?;
|
||||
|
||||
Ok("Success".to_string())
|
||||
}
|
||||
|
||||
fn restart(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["restart".to_string(), self.service]);
|
||||
|
||||
Command::new("sudo").args(self.cmd).spawn()?;
|
||||
|
||||
Ok("Success".to_string())
|
||||
}
|
||||
|
||||
fn status(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["is-active".to_string(), self.service]);
|
||||
|
||||
let output = Command::new("sudo").args(self.cmd).output()?;
|
||||
|
||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn create_header(auth: &str) -> HeaderMap {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(
|
||||
@ -105,3 +162,15 @@ pub async fn media_info(id: i64, command: String) -> Result<Response, ServiceErr
|
||||
|
||||
post_request(id, json_obj).await
|
||||
}
|
||||
|
||||
pub async fn control_service(id: i64, command: &str) -> Result<String, ServiceError> {
|
||||
let system_d = SystemD::new(id).await?;
|
||||
|
||||
match command {
|
||||
"start" => system_d.start(),
|
||||
"stop" => system_d.stop(),
|
||||
"restart" => system_d.restart(),
|
||||
"status" => system_d.status(),
|
||||
_ => Err(ServiceError::BadRequest("Command not found!".to_string())),
|
||||
}
|
||||
}
|
||||
|
@ -59,3 +59,9 @@ impl From<actix_web::error::BlockingError> for ServiceError {
|
||||
ServiceError::BadRequest(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for ServiceError {
|
||||
fn from(err: sqlx::Error) -> ServiceError {
|
||||
ServiceError::BadRequest(err.to_string())
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
preview_url TEXT NOT NULL,
|
||||
config_path TEXT NOT NULL,
|
||||
extra_extensions TEXT NOT NULL,
|
||||
service TEXT NOT NULL,
|
||||
UNIQUE(channel_name)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS user
|
||||
@ -108,9 +109,9 @@ pub async fn db_init() -> Result<&'static str, Box<dyn std::error::Error>> {
|
||||
('Scrolling Text', 'We have a very important announcement to make.', 'ifnot(ld(1),st(1,t));if(lt(t,ld(1)+1),w+4,w-w/12*mod(t-ld(1),12*(w+tw)/w))', '(h-line_h)*0.9',
|
||||
'24', '4', '#ffffff', '1.0', '1', '#000000@0x80', '4');
|
||||
INSERT INTO roles(name) VALUES('admin'), ('user'), ('guest');
|
||||
INSERT INTO settings(channel_name, preview_url, config_path, extra_extensions)
|
||||
INSERT INTO settings(channel_name, preview_url, config_path, extra_extensions, service)
|
||||
VALUES('Channel 1', 'http://localhost/live/preview.m3u8',
|
||||
'/etc/ffplayout/ffplayout.yml', '.jpg,.jpeg,.png');";
|
||||
'/etc/ffplayout/ffplayout.yml', '.jpg,.jpeg,.png', 'ffplayout.service');";
|
||||
sqlx::query(query).bind(secret).execute(&instances).await?;
|
||||
instances.close().await;
|
||||
|
||||
|
@ -66,4 +66,5 @@ pub struct Settings {
|
||||
#[sqlx(default)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub secret: String,
|
||||
pub service: String,
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use simplelog::*;
|
||||
|
||||
use crate::utils::{
|
||||
auth::{create_jwt, Claims},
|
||||
control::{control_state, media_info, send_message},
|
||||
control::{control_service, control_state, media_info, send_message, Process},
|
||||
errors::ServiceError,
|
||||
files::{browser, remove_file_or_folder, rename_file, upload, MoveObject, PathObject},
|
||||
handles::{
|
||||
@ -352,6 +352,18 @@ pub async fn media_last(id: web::Path<i64>) -> Result<impl Responder, ServiceErr
|
||||
}
|
||||
}
|
||||
|
||||
/// curl -X GET http://localhost:8080/api/control/1/process/
|
||||
/// --header 'Content-Type: application/json' --header 'Authorization: <TOKEN>'
|
||||
/// -d '{"command": "start"}'
|
||||
#[post("/control/{id}/process/")]
|
||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||
pub async fn process_control(
|
||||
id: web::Path<i64>,
|
||||
proc: web::Json<Process>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
control_service(*id, &proc.command).await
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// ffplayout playlist operations
|
||||
///
|
||||
|
@ -52,6 +52,7 @@ assets = [
|
||||
"755"
|
||||
],
|
||||
["../assets/ffpapi.service", "/lib/systemd/system/ffpapi.service", "644"],
|
||||
["../assets/11-ffplayout", "/etc/sudoers.d/11-ffplayout", "644"],
|
||||
["../assets/ffplayout.yml", "/etc/ffplayout/ffplayout.yml", "644"],
|
||||
["../assets/logo.png", "/usr/share/ffplayout/logo.png", "644"],
|
||||
["../README.md", "/usr/share/doc/ffplayout/README", "644"],
|
||||
@ -69,6 +70,7 @@ assets = [
|
||||
{ source = "../assets/ffplayout.yml", dest = "/etc/ffplayout/ffplayout.yml", mode = "644", config = true },
|
||||
{ source = "../assets/ffpapi.service", dest = "/lib/systemd/system/ffpapi.service", mode = "644" },
|
||||
{ source = "../assets/ffplayout.service", dest = "/lib/systemd/system/ffplayout.service", mode = "644" },
|
||||
{ source = "../assets/11-ffplayout", dest = "/etc/sudoers.d/11-ffplayout", mode = "644" },
|
||||
{ source = "../README.md", dest = "/usr/share/doc/ffplayout/README", mode = "644", doc = true },
|
||||
{ source = "../LICENSE", dest = "/usr/share/doc/ffplayout/LICENSE", mode = "644" },
|
||||
{ source = "../assets/logo.png", dest = "/usr/share/ffplayout/logo.png", mode = "644" },
|
||||
|
Loading…
Reference in New Issue
Block a user