Skip to content

Commit

Permalink
Implemented more stats & expansion macros.
Browse files Browse the repository at this point in the history
  • Loading branch information
mkrueger committed Jan 28, 2025
1 parent 63d412a commit b2b60ae
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 37 deletions.
2 changes: 1 addition & 1 deletion crates/icy_board/src/menu_runner/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl PcbBoardCommand {
self.state.reset_color(TerminalTarget::Both).await?;
self.state.clear_screen(TerminalTarget::Both).await?;
self.state.get_term_caps()?;
self.state.session.login_date = chrono::Local::now();
self.state.session.login_date = chrono::Utc::now();

// intial_welcome
let board_name = self.state.get_board().await.config.board.name.clone();
Expand Down
4 changes: 2 additions & 2 deletions crates/icy_board_engine/src/icy_board/doors/chain_txt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fs;

use chrono::{Local, Timelike, Utc};
use chrono::{Timelike, Utc};
use icy_engine::TextPane;

use crate::{
Expand Down Expand Up @@ -53,7 +53,7 @@ pub async fn create_chain_txt(state: &IcyBoardState, path: &std::path::Path) ->
contents.push_str(&format!("{}\r\n", board.config.board.name));
contents.push_str(&format!("{}\r\n", board.config.sysop.name));
contents.push_str(&format!("{}\r\n", state.session.login_date.time().num_seconds_from_midnight()));
contents.push_str(&format!("{}\r\n", (Local::now() - state.session.login_date).num_seconds()));
contents.push_str(&format!("{}\r\n", (Utc::now() - state.session.login_date).num_seconds()));
contents.push_str(&format!("{}\r\n", state.session.current_user.as_ref().unwrap().stats.total_upld_bytes / 1024));
contents.push_str(&format!("{}\r\n", state.session.current_user.as_ref().unwrap().stats.num_uploads));
contents.push_str(&format!("{}\r\n", state.session.current_user.as_ref().unwrap().stats.today_dnld_bytes / 1024));
Expand Down
6 changes: 3 additions & 3 deletions crates/icy_board_engine/src/icy_board/doors/pcboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
tables::export_cp437_string,
Res,
};
use chrono::{Local, Timelike};
use chrono::{Timelike, Utc};
pub async fn create_pcboard(state: &IcyBoardState, path: &std::path::Path) -> Res<()> {
create_pcboard_sys(state, path)?;
create_user_sys(state, path).await?;
Expand Down Expand Up @@ -39,7 +39,7 @@ fn create_pcboard_sys(state: &IcyBoardState, path: &std::path::Path) -> Res<()>
contents.extend(export_cp437_string(&state.session.get_first_name(), 15, b' ')); // User's First Name (padded to 15 characters)
contents.extend(export_cp437_string(&"SECRET", 12, b' ')); // User's Password (padded to 12 characters)
contents.extend(u16::to_le_bytes((state.session.login_date.time().num_seconds_from_midnight() / 60) as u16)); // Time User Logged On (in minutes since midnight)
contents.extend(u16::to_le_bytes((Local::now() - state.session.login_date).num_minutes() as u16)); // Time used so far today (negative number of minutes)
contents.extend(u16::to_le_bytes((Utc::now() - state.session.login_date).num_minutes() as u16)); // Time used so far today (negative number of minutes)
contents.extend(state.session.login_date.format("%H:%M").to_string().as_bytes()); // Time User Logged On (in "HH:MM" format)
contents.extend(u16::to_le_bytes(32767)); // Time Allowed On (from PWRD file)
contents.extend(u16::to_le_bytes(32767)); // Allowed K-Bytes for Download
Expand Down Expand Up @@ -158,7 +158,7 @@ async fn create_user_sys(state: &IcyBoardState, path: &std::path::Path) -> Res<(
contents.extend(export_cp437_string(&user.user_comment, 31, 0));
contents.extend(export_cp437_string(&user.sysop_comment, 31, 0));
contents.extend(u32::to_le_bytes(user.stats.today_dnld_bytes as u32));
contents.extend(u32::to_le_bytes((Local::now() - state.session.login_date).num_minutes() as u32));
contents.extend(u32::to_le_bytes((Utc::now() - state.session.login_date).num_minutes() as u32));
contents.extend(u16::to_le_bytes(0)); // Julian date for Registration Expiration Date
contents.extend(u32::to_le_bytes(0)); // Expired Security Level
contents.extend(u16::to_le_bytes(0)); // LastConference
Expand Down
110 changes: 92 additions & 18 deletions crates/icy_board_engine/src/icy_board/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::{

use crate::{executable::Executable, icy_board::user_base::UserBase, Res};
use async_recursion::async_recursion;
use chrono::{DateTime, Datelike, Local, Timelike, Utc};
use chrono::{DateTime, Datelike, Local, Utc};
use codepages::tables::UNICODE_TO_CP437;
use dizbase::file_base::FileBase;
use icy_engine::{ansi, OutputFormat, SaveOptions, ScreenPreperation};
Expand Down Expand Up @@ -70,6 +70,9 @@ pub struct DisplayOptions {
pub show_on_screen: bool,

pub in_file_list: Option<PathBuf>,

// Enable CTRL-X / CTRL-K checking for display_files
pub allow_break: bool,
}

impl DisplayOptions {
Expand All @@ -94,6 +97,7 @@ impl Default for DisplayOptions {
display_text: true,
show_on_screen: true,
in_file_list: None,
allow_break: true,
}
}
}
Expand Down Expand Up @@ -126,7 +130,7 @@ pub struct Session {
pub is_local: bool,
pub paged_sysop: bool,

pub login_date: DateTime<Local>,
pub login_date: DateTime<Utc>,

pub current_user: Option<User>,
pub cur_user_id: i32,
Expand Down Expand Up @@ -187,6 +191,13 @@ pub struct Session {
// The maximum number of files in flagged_files
pub batch_limit: usize,
pub flagged_files: Vec<PathBuf>,

/// The current message number read (used for @CURMSGNUM@ macro)
pub current_messagenumber: u32,
pub high_msg_num: u32,
pub low_msg_num: u32,
pub last_msg_read: u32,
pub highest_msg_read: u32,
}

impl Session {
Expand All @@ -195,7 +206,7 @@ impl Session {
disp_options: DisplayOptions::default(),
current_conference_number: 0,
current_conference: Conference::default(),
login_date: Local::now(),
login_date: Utc::now(),
current_user: None,
cur_user_id: -1,
cur_security: 0,
Expand Down Expand Up @@ -238,6 +249,11 @@ impl Session {

// Seems to be hardcoded in PCBoard
batch_limit: 30,
current_messagenumber: 0,
high_msg_num: 0,
low_msg_num: 0,
last_msg_read: 0,
highest_msg_read: 0,
}
}

Expand Down Expand Up @@ -761,7 +777,6 @@ impl IcyBoardState {
return Err(IcyBoardError::UserNumberInvalid(user_number).into());
}
let mut user = self.get_board().await.users[user_number].clone();
user.stats.last_on = Utc::now();
user.stats.num_times_on += 1;
let last_conference: u16 = user.last_conference;
self.get_board().await.statistics.add_caller(user.get_name().clone());
Expand Down Expand Up @@ -801,6 +816,16 @@ impl IcyBoardState {
self.update_language().await;
}

if let Some(user) = &mut self.session.current_user {
let login_date = self.session.login_date.to_utc();
if user.stats.last_on.date_naive() != login_date.date_naive() {
user.stats.minutes_today = 0;
}
user.stats.minutes_today += (Utc::now() - login_date).num_minutes() as u16;

user.stats.last_on = login_date;
}

if let Some(user) = &self.session.current_user {
let mut board = self.get_board().await;
for u in 0..board.users.len() {
Expand Down Expand Up @@ -1317,8 +1342,11 @@ impl IcyBoardState {
"CONFNUM" => result = self.session.current_conference_number.to_string(),

// TODO
"CREDLEFT" | "CREDNOW" | "CREDSTART" | "CREDUSED" | "CURMSGNUM" => {}
"CREDLEFT" | "CREDNOW" | "CREDSTART" | "CREDUSED" => {}

"CURMSGNUM" => {
result = self.session.current_messagenumber.to_string();
}
"DATAPHONE" => {
if let Some(user) = &self.session.current_user {
result = user.bus_data_phone.to_string();
Expand Down Expand Up @@ -1379,12 +1407,28 @@ impl IcyBoardState {
result = user.home_voice_phone.to_string();
}
}
"HIGHMSGNUM" => {}
"HIGHMSGNUM" => result = self.session.high_msg_num.to_string(),
"INAME" => {}
"INCONF" => result = self.session.current_conference.name.to_string(),
"LOGDATE" => {} // Logon Date
"LOGTIME" => {} // Logon Time
"KBLEFT" | "KBLIMIT" | "LASTCALLERNODE" | "LASTCALLERSYSTEM" | "LASTDATEON" | "LASTTIMEON" | "LMR" | "LOWMSGNUM" | "MAXBYTES" | "MAXFILES" => {}
"LOGDATE" => result = self.format_date(self.session.login_date),
"LOGTIME" => result = self.format_time(self.session.login_date),
"LASTDATEON" => {
if let Some(user) = &self.session.current_user {
result = self.format_date(user.stats.last_on);
}
}
"LASTTIMEON" => {
if let Some(user) = &self.session.current_user {
result = self.format_time(user.stats.last_on);
}
}
"LOWMSGNUM" => {
result = self.session.low_msg_num.to_string();
}
"LMR" => {
result = self.session.last_msg_read.to_string();
}
"KBLEFT" | "KBLIMIT" | "LASTCALLERNODE" | "LASTCALLERSYSTEM" | "MAXBYTES" | "MAXFILES" => {}
"MINLEFT" => result = "1000".to_string(),
"MORE" => {
let _ = self.more_promt().await;
Expand Down Expand Up @@ -1463,7 +1507,27 @@ impl IcyBoardState {
self.session.non_stop_off();
return None;
}
"PROLTR" | "PRODESC" | "PWXDATE" | "PWXDAYS" | "QOFF" | "QON" | "RATIOBYTES" | "RATIOFILES" => {}
"PROLTR" => {
if let Some(user) = &self.session.current_user {
result = user.protocol.to_string();
}
}
"PRODESC" => {
if let Some(user) = &self.session.current_user {
if let Some(prot) = self.board.lock().await.protocols.find_protocol(&user.protocol) {
result = prot.description.to_string();
}
}
}
"QOFF" => {
self.session.disp_options.allow_break = false;
return None;
}
"QON" => {
self.session.disp_options.allow_break = true;
return None;
}
"PWXDATE" | "PWXDAYS" | "RATIOBYTES" | "RATIOFILES" => {}
"RCPS" => result = self.transfer_statistics.uploaded_cps.to_string(),
"RBYTES" => result = self.transfer_statistics.uploaded_bytes.to_string(),
"RFILES" => result = self.transfer_statistics.uploaded_files.to_string(),
Expand All @@ -1486,22 +1550,26 @@ impl IcyBoardState {
"SYSOPIN" => result = self.get_board().await.config.sysop.sysop_start.to_string(),
"SYSOPOUT" => result = self.get_board().await.config.sysop.sysop_stop.to_string(),
"SYSTIME" => {
let now = Local::now();
let t = now.time();
result = format!("{:02}:{:02}", t.hour(), t.minute());
result = self.format_time(Utc::now());
}
"TIMELIMIT" => result = self.session.time_limit.to_string(),
"TIMELEFT" => {
let now = Local::now();
let now = Utc::now();
let time_on = now - self.session.login_date;
if self.session.time_limit == 0 {
result = "UNLIMITED".to_string();
} else {
result = (self.session.time_limit as i64 - time_on.num_minutes()).to_string();
}
}
"TIMEUSED" => {}
"TOTALTIME" => {}
"TIMEUSED" => result = (Utc::now() - self.session.login_date).num_minutes().to_string(),
"TOTALTIME" => {
let mut current = (Utc::now() - self.session.login_date).num_minutes();
if let Some(user) = &self.session.current_user {
current += user.stats.minutes_today as i64;
}
result = current.to_string();
}
"UPBYTES" => {
if let Some(user) = &self.session.current_user {
result = user.stats.total_upld_bytes.to_string();
Expand All @@ -1527,8 +1595,14 @@ impl IcyBoardState {
result = "0".to_string();
}
}
"WAIT" => {}
"WHO" => {}
"WAIT" => {
let _ = self.press_enter().await;
return None;
}
"WHO" => {
let _ = self.who_display_nodes().await;
return None;
}
"XOFF" => {
self.session.disp_options.grapics_mode = GraphicsMode::Ansi;
return None;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl IcyBoardState {
self.reset_color(TerminalTarget::Both).await?;
self.clear_screen(TerminalTarget::Both).await?;
self.get_term_caps()?;
self.session.login_date = chrono::Local::now();
self.session.login_date = chrono::Utc::now();

// intial_welcome
let board_name = self.get_board().await.config.board.name.clone();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl MessageViewer {
}

impl IcyBoardState {
pub async fn read_msgs_from_base(&mut self, message_base: JamMessageBase) -> Res<()> {
pub async fn read_msgs_from_base(&mut self, mut message_base: JamMessageBase) -> Res<()> {
let viewer = MessageViewer::load(&self.display_text)?;

while !self.session.disp_options.abort_printout {
Expand All @@ -212,7 +212,7 @@ impl IcyBoardState {
}

if let Ok(number) = text.parse::<u32>() {
self.read_message_number(&message_base, &viewer, number, None).await?;
self.read_message_number(&mut message_base, &viewer, number, None).await?;
}
}
self.press_enter().await?;
Expand All @@ -222,14 +222,30 @@ impl IcyBoardState {

pub async fn read_message_number(
&mut self,
message_base: &JamMessageBase,
message_base: &mut JamMessageBase,
viewer: &MessageViewer,
mut number: u32,
matches: Option<Vec<(usize, usize)>>,
) -> Res<()> {
if number == 0 {
return Ok(());
}
self.session.current_messagenumber = number;
self.session.high_msg_num = message_base.base_messagenumber();
self.session.high_msg_num = message_base.base_messagenumber() + message_base.active_messages();

unsafe {
let crc = JamMessageBase::get_crc(&bstr::BString::new(self.session.user_name.as_mut_vec().clone()));
let mut opt = message_base
.find_last_read(crc, self.session.cur_user_id as u32)?
.unwrap_or(message_base.create_last_read(crc, self.session.cur_user_id as u32)?);
self.session.last_msg_read = opt.last_read_msg;
self.session.highest_msg_read = opt.high_read_msg;

opt.last_read_msg = number;
opt.high_read_msg = opt.high_read_msg.max(number);
message_base.write_last_read(opt)?;
}
loop {
match message_base.read_header(number) {
Ok(header) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ impl IcyBoardState {
self.display_text(IceText::BatchSend, display_flags::LFBEFORE).await?;

self.board.lock().await.statistics.add_download(&state);
self.board.lock().await.save_statistics();
self.board.lock().await.save_statistics()?;
}
Err(e) => {
log::error!("Error while initiating file transfer with {:?} : {}", protocol, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl IcyBoardState {
let message_base_file = &self.session.current_conference.areas[area].filename;
let msgbase_file_resolved = self.get_board().await.resolve_file(message_base_file);
match JamMessageBase::open(&msgbase_file_resolved) {
Ok(message_base) => {
Ok(mut message_base) => {
let msg_search_from = if let Some(token) = self.session.tokens.pop_front() {
token
} else {
Expand Down Expand Up @@ -73,7 +73,7 @@ impl IcyBoardState {
let txt = message_base.read_msg_text(&msg)?;
let matches = get_matches(&txt, &search_text);
if !matches.is_empty() {
self.read_message_number(&message_base, &viewer, start, Some(matches)).await?;
self.read_message_number(&mut message_base, &viewer, start, Some(matches)).await?;
}
}
start += 1;
Expand Down
5 changes: 5 additions & 0 deletions crates/icy_board_engine/src/icy_board/user_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ pub struct UserStats {
#[serde(default)]
#[serde(skip_serializing_if = "is_null_64")]
pub total_doors_executed: u64,

#[serde(default)]
#[serde(skip_serializing_if = "is_null_16")]
pub minutes_today: u16,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
Expand Down Expand Up @@ -594,6 +598,7 @@ impl User {
today_num_downloads: 0,
today_num_uploads: 0,
total_doors_executed: 0,
minutes_today: 0,
},
}
}
Expand Down
9 changes: 9 additions & 0 deletions crates/icy_board_engine/src/icy_board/xfer_protocols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ impl SupportedProtocols {
fs::write(output, res)?;
Ok(())
}

pub fn find_protocol(&self, char_code: &str) -> Option<&Protocol> {
for p in &self.protocols {
if p.char_code == char_code {
return Some(p);
}
}
None
}
}

impl Deref for SupportedProtocols {
Expand Down
Loading

0 comments on commit b2b60ae

Please sign in to comment.