zmiany
This commit is contained in:
@@ -11,8 +11,8 @@ rrd = "0.1" # Zakładam dostępność; dostosuj jeśli potrzeba
|
|||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde_teamspeak_querystring = "0.3" # Do parsowania zapytań TS3
|
serde-teamspeak-querystring = "0.3" # Do parsowania zapytań TS3
|
||||||
askama = "0.10" # Dla szablonów HTML
|
askama = "0.10" # Dla szablonów HTML
|
||||||
askama_derive = "0.10"
|
askama_derive = "0.10"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
actix-files = "0.6"
|
actix-files = "0.6"
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
FROM rust:1.70 AS builder
|
FROM rust:1.88 AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
RUN apt-get update && apt-get install -y libclang-dev librrd-dev
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub ts3_server: String,
|
pub ts3_server: String,
|
||||||
pub ts3_query_port: u16,
|
pub ts3_query_port: u16,
|
||||||
@@ -7,7 +8,7 @@ pub struct Config {
|
|||||||
pub ts3_query_pass: String,
|
pub ts3_query_pass: String,
|
||||||
pub rrd_file: String,
|
pub rrd_file: String,
|
||||||
pub rrd_update_interval: u64,
|
pub rrd_update_interval: u64,
|
||||||
// Dodaj inne pola z config.example.py[2]
|
// Dodaj inne pola z config.example.py[2], np. channel_admin_group: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
69
src/main.rs
69
src/main.rs
@@ -1,12 +1,12 @@
|
|||||||
use actix_web::{web, App, HttpServer, HttpResponse};
|
use actix_web::{web, App, HttpServer, HttpResponse};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use chrono::prelude::*;
|
use chrono::{Utc, Datelike};
|
||||||
use tokio::time::{self, Duration};
|
use tokio::time::{self, Duration};
|
||||||
use actix_files as fs;
|
use actix_files as fs;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::ts3::{get_ts3_connection, create_channel};
|
use crate::ts3::{get_ts3_connection, create_channel, get_client_info};
|
||||||
use crate::rrd::{update_rrd_stats, generate_graphs};
|
use crate::rrd::{update_rrd_stats, generate_graphs};
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
@@ -26,18 +26,18 @@ struct CreateTemplate<'a> {
|
|||||||
ts3_server: &'a str,
|
ts3_server: &'a str,
|
||||||
ts3_server_port: u16,
|
ts3_server_port: u16,
|
||||||
client_ip: &'a str,
|
client_ip: &'a str,
|
||||||
client_uuid: Option<&'a str>,
|
client_uuid: &'a str,
|
||||||
now: DateTime<Utc>,
|
year: i32,
|
||||||
flash_message: Option<String>,
|
flash_message: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "stats.html")]
|
#[template(path = "stats.html")]
|
||||||
struct StatsTemplate {
|
struct StatsTemplate<'a> {
|
||||||
graphs: Vec<Graph>,
|
graphs: &'a [Graph],
|
||||||
last_update: String,
|
last_update: &'a str,
|
||||||
server_name: String,
|
server_name: &'a str,
|
||||||
now: DateTime<Utc>,
|
year: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Graph {
|
struct Graph {
|
||||||
@@ -47,45 +47,61 @@ struct Graph {
|
|||||||
|
|
||||||
async fn create_handler(data: web::Json<ChannelData>) -> HttpResponse {
|
async fn create_handler(data: web::Json<ChannelData>) -> HttpResponse {
|
||||||
let config = Config::load();
|
let config = Config::load();
|
||||||
// Logika tworzenia kanału (uproszczona; połącz z TS3)
|
|
||||||
let mut stream = match get_ts3_connection(&config) {
|
let mut stream = match get_ts3_connection(&config) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return HttpResponse::InternalServerError().body(format!("Błąd połączenia: {}", e));
|
return HttpResponse::InternalServerError().body(format!("Błąd połączenia: {}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let result = create_channel(&mut stream, &data.channel_name, &data.channel_topic, &data.channel_password);
|
|
||||||
let flash = match result {
|
// Pobierz client_info jak w app.py[1]
|
||||||
Ok(_) => Some("Kanał utworzony pomyślnie".to_string()),
|
let client_info = get_client_info(&mut stream, "127.0.0.1");
|
||||||
Err(e) => Some(format!("Błąd: {}", e)),
|
let (client_uuid, client_dbid, client_clid) = match &client_info {
|
||||||
|
Some(info) => (info.uid.as_str(), info.dbid, info.clid),
|
||||||
|
None => ("Brak UUID", 0, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let result = create_channel(
|
||||||
|
&mut stream,
|
||||||
|
&data.channel_name,
|
||||||
|
&data.channel_topic,
|
||||||
|
&data.channel_password,
|
||||||
|
client_dbid,
|
||||||
|
client_clid,
|
||||||
|
);
|
||||||
|
let flash_message = match result {
|
||||||
|
Ok(_) => Some("Kanał utworzony pomyślnie"),
|
||||||
|
Err(_e) => Some("Błąd tworzenia kanału"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let now = Utc::now();
|
||||||
let template = CreateTemplate {
|
let template = CreateTemplate {
|
||||||
ts3_server: &config.ts3_server,
|
ts3_server: &config.ts3_server,
|
||||||
ts3_server_port: config.ts3_query_port, // Dostosuj jeśli potrzeba
|
ts3_server_port: config.ts3_query_port,
|
||||||
client_ip: "127.0.0.1", // Pobierz z request (np. req.connection_info().realip_remote_addr())
|
client_ip: "127.0.0.1",
|
||||||
client_uuid: Some("example-uuid"),
|
client_uuid,
|
||||||
now: Utc::now(),
|
year: now.year(),
|
||||||
flash_message: flash,
|
flash_message,
|
||||||
};
|
};
|
||||||
HttpResponse::Ok().content_type("text/html").body(template.render().unwrap())
|
HttpResponse::Ok().content_type("text/html").body(template.render().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn stats_handler() -> HttpResponse {
|
async fn stats_handler() -> HttpResponse {
|
||||||
let config = Config::load();
|
let config = Config::load();
|
||||||
// Generuj wykresy (uproszczone)
|
|
||||||
generate_graphs(&config);
|
generate_graphs(&config);
|
||||||
let graphs = vec![
|
let graphs = [
|
||||||
Graph { file: "hour.gif".to_string(), title: "Ostatnie 12 godzin".to_string() },
|
Graph { file: "hour.gif".to_string(), title: "Ostatnie 12 godzin".to_string() },
|
||||||
Graph { file: "day.gif".to_string(), title: "Ostatnie 24 godziny".to_string() },
|
Graph { file: "day.gif".to_string(), title: "Ostatnie 24 godziny".to_string() },
|
||||||
Graph { file: "72h.gif".to_string(), title: "Ostatnie 72 godziny".to_string() },
|
Graph { file: "72h.gif".to_string(), title: "Ostatnie 72 godziny".to_string() },
|
||||||
Graph { file: "week.gif".to_string(), title: "Ostatni tydzień".to_string() },
|
Graph { file: "week.gif".to_string(), title: "Ostatni tydzień".to_string() },
|
||||||
];
|
];
|
||||||
|
let now = Utc::now();
|
||||||
|
let last_update = now.format("%Y-%m-%d %H:%M:%S").to_string();
|
||||||
let template = StatsTemplate {
|
let template = StatsTemplate {
|
||||||
graphs,
|
graphs: &graphs,
|
||||||
last_update: Utc::now().to_string(),
|
last_update: &last_update,
|
||||||
server_name: "linuxiarz.pl".to_string(),
|
server_name: "linuxiarz.pl",
|
||||||
now: Utc::now(),
|
year: now.year(),
|
||||||
};
|
};
|
||||||
HttpResponse::Ok().content_type("text/html").body(template.render().unwrap())
|
HttpResponse::Ok().content_type("text/html").body(template.render().unwrap())
|
||||||
}
|
}
|
||||||
@@ -95,7 +111,6 @@ async fn main() -> std::io::Result<()> {
|
|||||||
env_logger::init();
|
env_logger::init();
|
||||||
let config = Config::load();
|
let config = Config::load();
|
||||||
|
|
||||||
// Tło do aktualizacji RRD
|
|
||||||
let config_clone = config.clone();
|
let config_clone = config.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut interval = time::interval(Duration::from_secs(config_clone.rrd_update_interval));
|
let mut interval = time::interval(Duration::from_secs(config_clone.rrd_update_interval));
|
||||||
|
12
src/rrd.rs
12
src/rrd.rs
@@ -1,12 +1,12 @@
|
|||||||
use crate::config::Config; // Import Config
|
use crate::config::Config;
|
||||||
// Zakładam użycie biblioteki rrd; dostosuj
|
use log;
|
||||||
|
|
||||||
pub fn update_rrd_stats(config: &Config) {
|
pub fn update_rrd_stats(config: &Config) {
|
||||||
// Pobierz dane z TS3 i zaktualizuj RRD (na podstawie app.py[1])
|
// Pobierz online users jak w app.py[1], update RRD
|
||||||
log::info!("Updating RRD stats");
|
log::info!("Updating RRD stats for file: {}", config.rrd_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_graphs(config: &Config) {
|
pub fn generate_graphs(config: &Config) {
|
||||||
// Generuj wykresy (na podstawie create_rrd_graph w app.py[1])
|
// Generuj wykresy dla hour, day, 72h, week jak w app.py[1]
|
||||||
log::info!("Generating graphs");
|
log::info!("Generating graphs with interval: {}", config.rrd_update_interval);
|
||||||
}
|
}
|
||||||
|
33
src/ts3.rs
33
src/ts3.rs
@@ -1,20 +1,33 @@
|
|||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::io::{BufRead, BufReader, Write};
|
use std::io::Write;
|
||||||
use crate::config::Config; // Import Config
|
use crate::config::Config;
|
||||||
|
|
||||||
pub fn get_ts3_connection(config: &Config) -> Result<TcpStream, String> {
|
pub fn get_ts3_connection(config: &Config) -> Result<TcpStream, String> {
|
||||||
let mut stream = TcpStream::connect(format!("{}:{}", config.ts3_server, config.ts3_query_port))
|
let stream = TcpStream::connect(format!("{}:{}", config.ts3_server, config.ts3_query_port))
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
let mut writer = stream.try_clone().unwrap();
|
let mut writer = stream.try_clone().unwrap();
|
||||||
writer.write_all(format!("login {} {}\n", config.ts3_query_user, config.ts3_query_pass).as_bytes()).unwrap();
|
writer.write_all(format!("login {} {}\n", config.ts3_query_user, config.ts3_query_pass).as_bytes()).unwrap();
|
||||||
// Dodaj odczyt odpowiedzi i obsługę błędów
|
// Dodaj odczyt odpowiedzi i obsługę błędów, jak w app.py[1]
|
||||||
Ok(stream)
|
Ok(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_channel(stream: &mut TcpStream, name: &str, topic: &str, password: &str) -> Result<String, String> {
|
// Symulacja get_client_info z app.py[1] (porównanie IP, zwrot UUID itd.)
|
||||||
// Implementacja channelcreate, etc. (uproszczona; dostosuj na podstawie app.py[1])
|
pub fn get_client_info(_ts3conn: &mut TcpStream, _ip_address: &str) -> Option<ClientInfo> {
|
||||||
let command = format!("channelcreate channel_name={} channel_topic={} channel_password={}\n", name, topic, password);
|
// Pełna implementacja: Wyślij clientlist, clientinfo, porównaj IP
|
||||||
stream.write_all(command.as_bytes()).unwrap();
|
// Tymczasowo: unimplemented!()
|
||||||
// Parsuj odpowiedź (użyj serde_teamspeak_querystring)
|
unimplemented!();
|
||||||
unimplemented!(); // Pełna implementacja wymaga testów
|
}
|
||||||
|
|
||||||
|
pub struct ClientInfo {
|
||||||
|
pub uid: String,
|
||||||
|
pub nickname: String,
|
||||||
|
pub dbid: u32,
|
||||||
|
pub clid: u32,
|
||||||
|
pub ip: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_channel(_stream: &mut TcpStream, _name: &str, _topic: &str, _password: &str, _client_dbid: u32, _client_clid: u32) -> Result<String, String> {
|
||||||
|
// Pełna logika z app.py[1]: channelcreate, setclientchannelgroup, clientmove
|
||||||
|
// Tymczasowo: unimplemented!()
|
||||||
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<footer class="text-center mt-4">
|
<footer class="text-center mt-4">
|
||||||
TS3 Manager © {{ now.year }} | Hosted by linuxiarz.pl
|
TS3 Manager © {{ year }} | Hosted by linuxiarz.pl
|
||||||
</footer>
|
</footer>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
Reference in New Issue
Block a user