support multi channel
This commit is contained in:
parent
01a464dce5
commit
a7d0a43fdd
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1027,7 +1027,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ffplayout-api"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"actix-multipart",
|
||||
"actix-web",
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 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
|
||||
www-data ALL = NOPASSWD: /usr/bin/systemctl start ffplayout, /usr/bin/systemctl stop ffplayout, /usr/bin/systemctl restart ffplayout, /usr/bin/systemctl status ffplayout, /usr/bin/systemctl is-active ffplayout, /usr/bin/systemctl enable ffplayout, /usr/bin/systemctl disable ffplayout
|
||||
|
||||
www-data ALL = NOPASSWD: /bin/systemctl start ffplayout@*, /bin/systemctl stop ffplayout@*, /bin/systemctl reload ffplayout@*, /bin/systemctl restart ffplayout@*, /bin/systemctl status ffplayout@*, /bin/systemctl is-active ffplayout@*, /bin/systemctl enable ffplayout@*, /bin/systemctl disable ffplayout@*
|
||||
www-data ALL = NOPASSWD: /usr/bin/systemctl start ffplayout@*, /usr/bin/systemctl stop ffplayout@*, /usr/bin/systemctl restart ffplayout@*, /usr/bin/systemctl status ffplayout@*, /usr/bin/systemctl is-active ffplayout@*, /usr/bin/systemctl enable ffplayout@*, /usr/bin/systemctl disable ffplayout@*
|
||||
|
31
docs/api.md
31
docs/api.md
@ -55,10 +55,10 @@ curl -X POST 'http://localhost:8000/api/user/' -H 'Content-Type: application/jso
|
||||
|
||||
#### ffpapi Settings
|
||||
|
||||
**Get Settings**
|
||||
**Get Settings from Channel**
|
||||
|
||||
```BASH
|
||||
curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKEN>"
|
||||
curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
@ -75,22 +75,37 @@ curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKE
|
||||
}
|
||||
```
|
||||
|
||||
**Get all Settings**
|
||||
**Get settings from all Channels**
|
||||
|
||||
```BASH
|
||||
curl -X GET http://127.0.0.1:8000/api/settings -H "Authorization: Bearer <TOKEN>"
|
||||
curl -X GET http://127.0.0.1:8000/api/channels -H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
**Update Settings**
|
||||
**Update Channel**
|
||||
|
||||
```BASH
|
||||
curl -X PATCH http://127.0.0.1:8000/api/settings/1 -H "Content-Type: application/json" \
|
||||
curl -X PATCH http://127.0.0.1:8000/api/channel/1 -H "Content-Type: application/json" \
|
||||
-d '{ "id": 1, "channel_name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \
|
||||
"config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png",
|
||||
"role_id": 1, "channel_id": 1 }' \
|
||||
"config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png", "timezone": "Europe/Berlin"}' \
|
||||
-H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
**Create new Channel**
|
||||
|
||||
```BASH
|
||||
curl -X POST http://127.0.0.1:8000/api/channel/ -H "Content-Type: application/json" \
|
||||
-d '{ "channel_name": "Channel 2", "preview_url": "http://localhost/live/channel2.m3u8", \
|
||||
"config_path": "/etc/ffplayout/channel2.yml", "extra_extensions": "jpg,jpeg,png",
|
||||
"timezone": "Europe/Berlin", "service": "ffplayout@channel2.service" }' \
|
||||
-H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
**Delete Channel**
|
||||
|
||||
```BASH
|
||||
curl -X DELETE http://127.0.0.1:8000/api/channel/2 -H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
#### ffplayout Config
|
||||
|
||||
**Get Config**
|
||||
|
@ -4,7 +4,7 @@ description = "Rest API for ffplayout"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Jonathan Baecker jonbae77@gmail.com"]
|
||||
readme = "README.md"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
@ -15,11 +15,11 @@ use utils::{
|
||||
auth, db_path, init_config,
|
||||
models::LoginUser,
|
||||
routes::{
|
||||
add_dir, add_preset, add_user, control_playout, del_playlist, delete_preset, file_browser,
|
||||
gen_playlist, get_all_settings, get_log, get_playlist, get_playout_config, get_presets,
|
||||
get_settings, get_user, login, media_current, media_last, media_next, move_rename,
|
||||
patch_settings, process_control, remove, save_file, save_playlist, send_text_message,
|
||||
update_playout_config, update_preset, update_user,
|
||||
add_channel, add_dir, add_preset, add_user, control_playout, del_playlist, delete_preset,
|
||||
file_browser, gen_playlist, get_all_channels, get_channel, get_log, get_playlist,
|
||||
get_playout_config, get_presets, get_user, login, media_current, media_last, media_next,
|
||||
move_rename, patch_channel, process_control, remove, remove_channel, save_file,
|
||||
save_playlist, send_text_message, update_playout_config, update_preset, update_user,
|
||||
},
|
||||
run_args, Role,
|
||||
};
|
||||
@ -84,9 +84,11 @@ async fn main() -> std::io::Result<()> {
|
||||
.service(get_presets)
|
||||
.service(update_preset)
|
||||
.service(delete_preset)
|
||||
.service(get_settings)
|
||||
.service(get_all_settings)
|
||||
.service(patch_settings)
|
||||
.service(get_channel)
|
||||
.service(get_all_channels)
|
||||
.service(patch_channel)
|
||||
.service(add_channel)
|
||||
.service(remove_channel)
|
||||
.service(update_user)
|
||||
.service(send_text_message)
|
||||
.service(control_playout)
|
||||
|
56
ffplayout-api/src/utils/channels.rs
Normal file
56
ffplayout-api/src/utils/channels.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use std::fs;
|
||||
|
||||
use simplelog::*;
|
||||
|
||||
use crate::utils::{
|
||||
control::control_service,
|
||||
errors::ServiceError,
|
||||
handles::{db_add_channel, db_delete_channel, db_get_channel},
|
||||
models::Channel,
|
||||
};
|
||||
|
||||
pub async fn create_channel(target_channel: Channel) -> Result<Channel, ServiceError> {
|
||||
if !target_channel.service.starts_with("ffplayout@") {
|
||||
return Err(ServiceError::BadRequest("Bad service name!".to_string()));
|
||||
}
|
||||
|
||||
if !target_channel.config_path.starts_with("/etc/ffplayout") {
|
||||
return Err(ServiceError::BadRequest("Bad config path!".to_string()));
|
||||
}
|
||||
|
||||
if let Ok(source_channel) = db_get_channel(&1).await {
|
||||
if fs::copy(&source_channel.config_path, &target_channel.config_path).is_ok() {
|
||||
match db_add_channel(target_channel).await {
|
||||
Ok(c) => {
|
||||
if let Err(e) = control_service(c.id, "enable").await {
|
||||
return Err(e);
|
||||
}
|
||||
return Ok(c);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(ServiceError::Conflict(e.to_string()));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
pub async fn delete_channel(id: i64) -> Result<(), ServiceError> {
|
||||
if let Ok(channel) = db_get_channel(&id).await {
|
||||
if control_service(channel.id, "stop").await.is_ok()
|
||||
&& control_service(channel.id, "disable").await.is_ok()
|
||||
{
|
||||
if let Err(e) = fs::remove_file(channel.config_path) {
|
||||
error!("{e}");
|
||||
};
|
||||
match db_delete_channel(&id).await {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(e) => return Err(ServiceError::Conflict(e.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
@ -7,7 +7,7 @@ use reqwest::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use simplelog::*;
|
||||
|
||||
use crate::utils::{errors::ServiceError, handles::db_get_settings, playout_config};
|
||||
use crate::utils::{errors::ServiceError, handles::db_get_channel, playout_config};
|
||||
use ffplayout_lib::vec_strings;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
@ -57,14 +57,32 @@ struct SystemD {
|
||||
|
||||
impl SystemD {
|
||||
async fn new(id: i64) -> Result<Self, ServiceError> {
|
||||
let settings = db_get_settings(&id).await?;
|
||||
let channel = db_get_channel(&id).await?;
|
||||
|
||||
Ok(Self {
|
||||
service: settings.service,
|
||||
cmd: vec_strings!["systemctl"],
|
||||
service: channel.service,
|
||||
cmd: vec_strings!["/usr/bin/systemctl"],
|
||||
})
|
||||
}
|
||||
|
||||
fn enable(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["enable".to_string(), self.service]);
|
||||
|
||||
Command::new("sudo").args(self.cmd).spawn()?;
|
||||
|
||||
Ok("Success".to_string())
|
||||
}
|
||||
|
||||
fn disable(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["disable".to_string(), self.service]);
|
||||
|
||||
Command::new("sudo").args(self.cmd).spawn()?;
|
||||
|
||||
Ok("Success".to_string())
|
||||
}
|
||||
|
||||
fn start(mut self) -> Result<String, ServiceError> {
|
||||
self.cmd
|
||||
.append(&mut vec!["start".to_string(), self.service]);
|
||||
@ -167,6 +185,8 @@ pub async fn control_service(id: i64, command: &str) -> Result<String, ServiceEr
|
||||
let system_d = SystemD::new(id).await?;
|
||||
|
||||
match command {
|
||||
"enable" => system_d.enable(),
|
||||
"disable" => system_d.disable(),
|
||||
"start" => system_d.start(),
|
||||
"stop" => system_d.stop(),
|
||||
"restart" => system_d.restart(),
|
||||
|
@ -9,7 +9,7 @@ use sqlx::{migrate::MigrateDatabase, sqlite::SqliteQueryResult, Pool, Sqlite, Sq
|
||||
|
||||
use crate::utils::{
|
||||
db_path,
|
||||
models::{Settings, TextPreset, User},
|
||||
models::{Channel, TextPreset, User},
|
||||
GlobalSettings,
|
||||
};
|
||||
|
||||
@ -33,7 +33,7 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
name TEXT NOT NULL,
|
||||
UNIQUE(name)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS settings
|
||||
CREATE TABLE IF NOT EXISTS channels
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
channel_name TEXT NOT NULL,
|
||||
@ -42,7 +42,7 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
extra_extensions TEXT NOT NULL,
|
||||
timezone TEXT NOT NULL,
|
||||
service TEXT NOT NULL,
|
||||
UNIQUE(channel_name)
|
||||
UNIQUE(channel_name, service)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS presets
|
||||
(
|
||||
@ -59,7 +59,7 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
boxborderw TEXT NOT NULL,
|
||||
alpha TEXT NOT NULL,
|
||||
channel_id INTEGER NOT NULL DEFAULT 1,
|
||||
FOREIGN KEY (channel_id) REFERENCES settings (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
FOREIGN KEY (channel_id) REFERENCES channels (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
UNIQUE(name)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS user
|
||||
@ -72,7 +72,7 @@ async fn create_schema() -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
role_id INTEGER NOT NULL DEFAULT 2,
|
||||
channel_id INTEGER NOT NULL DEFAULT 1,
|
||||
FOREIGN KEY (role_id) REFERENCES roles (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
FOREIGN KEY (channel_id) REFERENCES settings (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
FOREIGN KEY (channel_id) REFERENCES channels (id) ON UPDATE SET NULL ON DELETE SET NULL,
|
||||
UNIQUE(mail, username)
|
||||
);";
|
||||
let result = sqlx::query(query).execute(&conn).await;
|
||||
@ -111,7 +111,7 @@ pub async fn db_init(domain: Option<String>) -> Result<&'static str, Box<dyn std
|
||||
SELECT RAISE(FAIL, 'Database is already initialized!');
|
||||
END;
|
||||
INSERT INTO global(secret) VALUES($1);
|
||||
INSERT INTO settings(channel_name, preview_url, config_path, extra_extensions, timezone, service)
|
||||
INSERT INTO channels(channel_name, preview_url, config_path, extra_extensions, timezone, service)
|
||||
VALUES('Channel 1', $2, '/etc/ffplayout/ffplayout.yml', 'jpg,jpeg,png', 'UTC', 'ffplayout.service');
|
||||
INSERT INTO roles(name) VALUES('admin'), ('user'), ('guest');
|
||||
INSERT INTO presets(name, text, x, y, fontsize, line_spacing, fontcolor, box, boxcolor, boxborderw, alpha, channel_id)
|
||||
@ -147,37 +147,37 @@ pub async fn db_global() -> Result<GlobalSettings, sqlx::Error> {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_get_settings(id: &i64) -> Result<Settings, sqlx::Error> {
|
||||
pub async fn db_get_channel(id: &i64) -> Result<Channel, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
let query = "SELECT * FROM settings WHERE id = $1";
|
||||
let result: Settings = sqlx::query_as(query).bind(id).fetch_one(&conn).await?;
|
||||
let query = "SELECT * FROM channels WHERE id = $1";
|
||||
let result: Channel = sqlx::query_as(query).bind(id).fetch_one(&conn).await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_get_all_settings() -> Result<Vec<Settings>, sqlx::Error> {
|
||||
pub async fn db_get_all_channels() -> Result<Vec<Channel>, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
let query = "SELECT * FROM settings";
|
||||
let result: Vec<Settings> = sqlx::query_as(query).fetch_all(&conn).await?;
|
||||
let result: Vec<Channel> = sqlx::query_as(query).fetch_all(&conn).await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_update_settings(
|
||||
pub async fn db_update_channel(
|
||||
id: i64,
|
||||
settings: Settings,
|
||||
channel: Channel,
|
||||
) -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
|
||||
let query = "UPDATE settings SET channel_name = $2, preview_url = $3, config_path = $4, extra_extensions = $5 WHERE id = $1";
|
||||
let query = "UPDATE channels SET channel_name = $2, preview_url = $3, config_path = $4, extra_extensions = $5 WHERE id = $1";
|
||||
let result: SqliteQueryResult = sqlx::query(query)
|
||||
.bind(id)
|
||||
.bind(settings.channel_name.clone())
|
||||
.bind(settings.preview_url.clone())
|
||||
.bind(settings.config_path.clone())
|
||||
.bind(settings.extra_extensions.clone())
|
||||
.bind(channel.channel_name.clone())
|
||||
.bind(channel.preview_url.clone())
|
||||
.bind(channel.config_path.clone())
|
||||
.bind(channel.extra_extensions.clone())
|
||||
.execute(&conn)
|
||||
.await?;
|
||||
conn.close().await;
|
||||
@ -185,6 +185,38 @@ pub async fn db_update_settings(
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_add_channel(channel: Channel) -> Result<Channel, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
|
||||
let query = "INSERT INTO channels (channel_name, preview_url, config_path, extra_extensions, timezone, service) VALUES($1, $2, $3, $4, $5, $6)";
|
||||
let result = sqlx::query(query)
|
||||
.bind(channel.channel_name)
|
||||
.bind(channel.preview_url)
|
||||
.bind(channel.config_path)
|
||||
.bind(channel.extra_extensions)
|
||||
.bind(channel.timezone)
|
||||
.bind(channel.service)
|
||||
.execute(&conn)
|
||||
.await?;
|
||||
let new_channel: Channel = sqlx::query_as("SELECT * FROM channels WHERE id = $1")
|
||||
.bind(result.last_insert_rowid())
|
||||
.fetch_one(&conn)
|
||||
.await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(new_channel)
|
||||
}
|
||||
|
||||
pub async fn db_delete_channel(id: &i64) -> Result<SqliteQueryResult, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
|
||||
let query = "DELETE FROM channels WHERE id = $1";
|
||||
let result: SqliteQueryResult = sqlx::query(query).bind(id).execute(&conn).await?;
|
||||
conn.close().await;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn db_role(id: &i64) -> Result<String, sqlx::Error> {
|
||||
let conn = db_connection().await?;
|
||||
let query = "SELECT name FROM roles WHERE id = $1";
|
||||
|
@ -12,6 +12,7 @@ use simplelog::*;
|
||||
|
||||
pub mod args_parse;
|
||||
pub mod auth;
|
||||
pub mod channels;
|
||||
pub mod control;
|
||||
pub mod errors;
|
||||
pub mod files;
|
||||
@ -23,8 +24,8 @@ pub mod routes;
|
||||
use crate::utils::{
|
||||
args_parse::Args,
|
||||
errors::ServiceError,
|
||||
handles::{db_add_user, db_get_settings, db_global, db_init},
|
||||
models::{Settings, User},
|
||||
handles::{db_add_user, db_get_channel, db_global, db_init},
|
||||
models::{Channel, User},
|
||||
};
|
||||
use ffplayout_lib::utils::PlayoutConfig;
|
||||
|
||||
@ -183,10 +184,10 @@ pub fn read_playout_config(path: &str) -> Result<PlayoutConfig, Box<dyn Error>>
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub async fn playout_config(channel_id: &i64) -> Result<(PlayoutConfig, Settings), ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(channel_id).await {
|
||||
if let Ok(config) = read_playout_config(&settings.config_path.clone()) {
|
||||
return Ok((config, settings));
|
||||
pub async fn playout_config(channel_id: &i64) -> Result<(PlayoutConfig, Channel), ServiceError> {
|
||||
if let Ok(channel) = db_get_channel(channel_id).await {
|
||||
if let Ok(config) = read_playout_config(&channel.config_path.clone()) {
|
||||
return Ok((config, channel));
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +197,7 @@ pub async fn playout_config(channel_id: &i64) -> Result<(PlayoutConfig, Settings
|
||||
}
|
||||
|
||||
pub async fn read_log_file(channel_id: &i64, date: &str) -> Result<String, ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(channel_id).await {
|
||||
if let Ok(channel) = db_get_channel(channel_id).await {
|
||||
let mut date_str = "".to_string();
|
||||
|
||||
if !date.is_empty() {
|
||||
@ -204,7 +205,7 @@ pub async fn read_log_file(channel_id: &i64, date: &str) -> Result<String, Servi
|
||||
date_str.push_str(date);
|
||||
}
|
||||
|
||||
if let Ok(config) = read_playout_config(&settings.config_path) {
|
||||
if let Ok(config) = read_playout_config(&channel.config_path) {
|
||||
let mut log_path = Path::new(&config.logging.log_path)
|
||||
.join("ffplayout.log")
|
||||
.display()
|
||||
|
@ -59,7 +59,7 @@ pub struct TextPreset {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, sqlx::FromRow)]
|
||||
pub struct Settings {
|
||||
pub struct Channel {
|
||||
#[serde(skip_deserializing)]
|
||||
pub id: i64,
|
||||
pub channel_name: String,
|
||||
@ -67,8 +67,5 @@ pub struct Settings {
|
||||
pub config_path: String,
|
||||
pub extra_extensions: String,
|
||||
pub timezone: String,
|
||||
#[sqlx(default)]
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub secret: String,
|
||||
pub service: String,
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use simplelog::*;
|
||||
|
||||
use crate::utils::{
|
||||
auth::{create_jwt, Claims},
|
||||
channels::{create_channel, delete_channel},
|
||||
control::{control_service, control_state, media_info, send_message, Process},
|
||||
errors::ServiceError,
|
||||
files::{
|
||||
@ -29,11 +30,11 @@ use crate::utils::{
|
||||
PathObject,
|
||||
},
|
||||
handles::{
|
||||
db_add_preset, db_add_user, db_delete_preset, db_get_all_settings, db_get_presets,
|
||||
db_get_settings, db_get_user, db_login, db_role, db_update_preset, db_update_settings,
|
||||
db_add_preset, db_add_user, db_delete_preset, db_get_all_channels, db_get_channel,
|
||||
db_get_presets, db_get_user, db_login, db_role, db_update_channel, db_update_preset,
|
||||
db_update_user,
|
||||
},
|
||||
models::{LoginUser, Settings, TextPreset, User},
|
||||
models::{Channel, LoginUser, TextPreset, User},
|
||||
playlist::{delete_playlist, generate_playlist, read_playlist, write_playlist},
|
||||
read_log_file, read_playout_config, Role,
|
||||
};
|
||||
@ -219,10 +220,10 @@ async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError>
|
||||
|
||||
/// #### ffpapi Settings
|
||||
///
|
||||
/// **Get Settings**
|
||||
/// **Get Settings from Channel**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X GET http://127.0.0.1:8000/api/settings/1 -H "Authorization: Bearer <TOKEN>"
|
||||
/// curl -X GET http://127.0.0.1:8000/api/channel/1 -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
///
|
||||
/// **Response:**
|
||||
@ -238,53 +239,85 @@ async fn add_user(data: web::Json<User>) -> Result<impl Responder, ServiceError>
|
||||
/// "service": "ffplayout.service"
|
||||
/// }
|
||||
/// ```
|
||||
#[get("/settings/{id}")]
|
||||
#[get("/channel/{id}")]
|
||||
#[has_any_role("Role::Admin", "Role::User", type = "Role")]
|
||||
async fn get_settings(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(&id).await {
|
||||
return Ok(web::Json(settings));
|
||||
async fn get_channel(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(channel) = db_get_channel(&id).await {
|
||||
return Ok(web::Json(channel));
|
||||
}
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
/// **Get all Settings**
|
||||
/// **Get settings from all Channels**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X GET http://127.0.0.1:8000/api/settings -H "Authorization: Bearer <TOKEN>"
|
||||
/// curl -X GET http://127.0.0.1:8000/api/channels -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[get("/settings")]
|
||||
#[get("/channels")]
|
||||
#[has_any_role("Role::Admin", type = "Role")]
|
||||
async fn get_all_settings() -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(settings) = db_get_all_settings().await {
|
||||
return Ok(web::Json(settings));
|
||||
async fn get_all_channels() -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(channel) = db_get_all_channels().await {
|
||||
return Ok(web::Json(channel));
|
||||
}
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
/// **Update Settings**
|
||||
/// **Update Channel**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X PATCH http://127.0.0.1:8000/api/settings/1 -H "Content-Type: application/json" \
|
||||
/// curl -X PATCH http://127.0.0.1:8000/api/channel/1 -H "Content-Type: application/json" \
|
||||
/// -d '{ "id": 1, "channel_name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \
|
||||
/// "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png",
|
||||
/// "role_id": 1, "channel_id": 1 }' \
|
||||
/// "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png", "timezone": "Europe/Berlin"}' \
|
||||
/// -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[patch("/settings/{id}")]
|
||||
#[patch("/channel/{id}")]
|
||||
#[has_any_role("Role::Admin", type = "Role")]
|
||||
async fn patch_settings(
|
||||
async fn patch_channel(
|
||||
id: web::Path<i64>,
|
||||
data: web::Json<Settings>,
|
||||
data: web::Json<Channel>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
if db_update_settings(*id, data.into_inner()).await.is_ok() {
|
||||
if db_update_channel(*id, data.into_inner()).await.is_ok() {
|
||||
return Ok("Update Success");
|
||||
};
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
/// **Create new Channel**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X POST http://127.0.0.1:8000/api/channel/ -H "Content-Type: application/json" \
|
||||
/// -d '{ "channel_name": "Channel 2", "preview_url": "http://localhost/live/channel2.m3u8", \
|
||||
/// "config_path": "/etc/ffplayout/channel2.yml", "extra_extensions": "jpg,jpeg,png",
|
||||
/// "timezone": "Europe/Berlin", "service": "ffplayout@channel2.service" }' \
|
||||
/// -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[post("/channel/")]
|
||||
#[has_any_role("Role::Admin", type = "Role")]
|
||||
async fn add_channel(data: web::Json<Channel>) -> Result<impl Responder, ServiceError> {
|
||||
match create_channel(data.into_inner()).await {
|
||||
Ok(c) => Ok(web::Json(c)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// **Delete Channel**
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X DELETE http://127.0.0.1:8000/api/channel/2 -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[delete("/channel/{id}")]
|
||||
#[has_any_role("Role::Admin", type = "Role")]
|
||||
async fn remove_channel(id: web::Path<i64>) -> Result<impl Responder, ServiceError> {
|
||||
if delete_channel(*id).await.is_ok() {
|
||||
return Ok("Delete Channel Success");
|
||||
}
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
}
|
||||
|
||||
/// #### ffplayout Config
|
||||
///
|
||||
/// **Get Config**
|
||||
@ -300,8 +333,8 @@ async fn get_playout_config(
|
||||
id: web::Path<i64>,
|
||||
_details: AuthDetails<Role>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(&id).await {
|
||||
if let Ok(config) = read_playout_config(&settings.config_path) {
|
||||
if let Ok(channel) = db_get_channel(&id).await {
|
||||
if let Ok(config) = read_playout_config(&channel.config_path) {
|
||||
return Ok(web::Json(config));
|
||||
}
|
||||
};
|
||||
@ -321,11 +354,11 @@ async fn update_playout_config(
|
||||
id: web::Path<i64>,
|
||||
data: web::Json<PlayoutConfig>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(settings) = db_get_settings(&id).await {
|
||||
if let Ok(channel) = db_get_channel(&id).await {
|
||||
if let Ok(f) = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&settings.config_path)
|
||||
.open(&channel.config_path)
|
||||
{
|
||||
serde_yaml::to_writer(f, &data).unwrap();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user