ONO::Cron::Service::Minutely

package ONO::Cron::Service::Minutely;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################

use strict;

use ONO::IO;
use ONO::DB;

use ONO::Cron::Service::ToolBox;

use ONO::Ext::Morzino::ToolBox;
use ONO::Core::HostOS;
use ONO::ToolBox::SendMail;
use ONO::Lib::Video::ToolBox;
use ONO::ToolBox::ONO;

###############################################################################
# ONO
###############################################################################

#: ONO Cron Service minutely tasks.

sub run {

#: Execution logic.

my (
$self,
$db,
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$timestamp,
$switches,
) = @_;

my %vars;

my $DATA = ONO::Cron::Service::ToolBox->print("Service running: Minutely",$switches);

my $lastyear = $year-1;

my %ono = ONO::ToolBox::ONO->get();

############################################################################
# system status monitoring
############################################################################

# system load and memory usage

my ($cpu_load,$mem_load) = (ONO::Core::HostOS->cpu_load_percent,ONO::Core::HostOS->mem_load_percent);

if ($ono{'site'} && $ono{'domain'} && ($cpu_load > 199 || ($cpu_load > 149 && $min%2 == 0) || ($cpu_load > 124 && $min%5 == 0) || $mem_load > 149)) {

my $STATUS = "HIGH";
if ($cpu_load > 149 || $mem_load > 149) {
$STATUS = "CRITICAL";
}
my $vid1 = ONO::IO->count("var/tmp/cronsync/video2thumbqueue",0,"t");
my $vid2 = ONO::IO->count("var/tmp/cronsync/video2mp4queue",0,"t");
my $mp3 = ONO::IO->count("var/tmp/cronsync/audio2mp3queue",0,"t");

my $PROC = `ps aux | sort -nrk 3,3 | head -n 25`;

ONO::ToolBox::SendMail->sendmail(
"$ono{'site'} <noreply\@$ono{'domain'}>",
"mail:tracker",
"[$ono{'site'}] SYSLOAD IS $STATUS [$cpu_load,$mem_load] [$vid1,$vid2,$mp3]",
"TIME: $mday/$mon/$year \@ $hour:$min:$sec\nCPU load: $cpu_load\%\nMEM load: $mem_load\%\nMedia queue: thumbs:$vid1, mp4:$vid2, mp3:$mp3\n\n$PROC\n",
);

}

############################################################################
# get this installation's ONO perl environments
############################################################################

my @envs = ('ono');
my %env;
foreach my $app (ONO::IO->ls("cgi-bin/local/perl")) {
if ($app =~ /[a-z]/ && $app !~ /\./ && $app !~ /^_/) {
@envs = (@envs,$app);
$env{$app}++;
}
}

############################################################################
# useful maintenance jobs
############################################################################

my @jobs = (
'none',
);

if ($env{'school'}) {
@jobs = (
@jobs,
'school_virschool_relationships',
);
}

my $jobnum = @jobs;

# execute up to 5 jobs, as long as cpu_load and mem_load are in good shape

if (($cpu_load < 25 && $mem_load < 50) || ONO::IO->devstation) {

for (my $i = 0; $i < 5; $i++) {

my $jobrand = int(rand($jobnum));
my $job = $jobs[$jobrand];

if ($db && $job && $job ne "none") {

if ((ONO::Core::HostOS->cpu_load_percent < 25 && ONO::Core::HostOS->mem_load_percent < 50) || ONO::IO->devstation) {

# school_virschool_relationships

if ($job eq "school_virschool_relationships") {

if (ONO::DB->table_exists($db,"school_school_virschool_relationships") && ONO::DB->table_exists($db,"school_school_virclass")) {

my $LIMIT = int(ONO::DB->count($db,"school_school_virschool_relationships")/1000)+1;

foreach my $line (ONO::DB->select($db,"school_school_virschool_relationships","","RAND()","LIMIT $LIMIT")) {
my @col = ONO::DB->readcols($line);

foreach my $line2 (ONO::DB->select($db,"school_school_virclass","id = '$col[1]'")) {
my @col2 = ONO::DB->readcols($line2);

# status = $col[4], flags = $col2[17]

if (($col[4] eq "" || $col[4] == 1) && $col2[17] =~ /H/) {
ONO::DB->command($db,"UPDATE school_school_virschool_relationships SET status = '0',
modification_username = 'service', modification_timestamp = '$timestamp' WHERE virclass = '$col[1]'");
}

if ($col[4] < 1 && $col2[17] !~ /H/) {
ONO::DB->command($db,"UPDATE school_school_virschool_relationships SET status = '1',
modification_username = 'service', modification_timestamp = '$timestamp' WHERE virclass = '$col[1]'");
}

}
}
}
}

# all done

}
}
}
}

############################################################################
# gargabe collection
############################################################################

if (($cpu_load < 25 && $mem_load < 50) || ONO::IO->devstation) {

foreach my $env (@envs) {

if ($db && ONO::IO->exists("var/community/$env")) {

# service is running 1440 times a day, so we'll make sure that each user will be checked once a day in average
# there's a limit of 100 users per run, which means that no more than 144,000 users a day will be checked

my ($users,$files) = (0,0);

if (ONO::DB->table_exists($db,"${env}_community_users")) {
$users = int(ONO::DB->count($db,"${env}_community_users")/1440);
}

if ($users < 1) {
$users = 1;
}
if ($users > 100) {
$users = 100;
}

if (ONO::DB->table_exists($db,"${env}_community_users")) {

foreach my $line (ONO::DB->select($db,"${env}_community_users","","RAND()","LIMIT $users")) {
my @col = ONO::DB->readcols($line);

my $path = "var/community/$env/accounts/data/".ONO::IO->deepdir($col[0])."/$col[0]/microblog";
if (ONO::IO->exists($path)) {

foreach my $file (ONO::IO->ls($path)) {
if ($file =~ /^2(.*?)\.txt$/) {

# delete files that are older than 2 years

if ($file !~ /^$year/ && $file !~ /^$lastyear/) {
ONO::IO->rm("$path/$file");
$files++;
}

# delete last year's files if january has passed

if ($file =~ /^$lastyear/ && $mon > 1) {
ONO::IO->rm("$path/$file");
$files++;
}

# delete this year's files if they're older than 1 month

if ($file =~ /^$year(.*)\.txt/) {
if (substr($1,0,2) < $mon-1) {
ONO::IO->rm("$path/$file");
$files++;
}
}

}

}

}

}

}

$DATA .= ONO::Cron::Service::ToolBox->print("- garbage: $files files cleaned up for $users users in $env",$switches);

# virtual classrooms

if ($env eq "school" && ONO::IO->exists("community/portal/data")) {

# service is running 1440 times a day, so we'll make sure that all virclasses will be checked once a day in average
# there's a limit of 10 classes per run, which means that no more than 14,400 classes a day will be checked

my $classes = int(ONO::DB->count($db,"${env}_school_virclass")/1440);
my $files = 0;

if ($classes < 1) {
$classes = 1;
}
if ($classes > 10) {
$classes = 10;
}

foreach my $line (ONO::DB->select($db,"${env}_school_virclass","","RAND()","LIMIT $classes")) {
my @col = ONO::DB->readcols($line);

my $path = ONO::Ext::Morzino::ToolBox->virclass_dir($col[0]);

# activity

# data - feed & microblog

foreach my $opt ('feed','microblog') {

foreach my $file (ONO::IO->ls("$path/data/$opt")) {
if ($file =~ /^2(.*?)\.txt$/) {

# delete files that are older than 2 years

if ($file !~ /^$year/ && $file !~ /^$lastyear/) {
ONO::IO->rm("$path/data/$opt/$file");
$files++;
}

# delete last year's files if march has passed

if ($file =~ /^$lastyear/ && $mon > 3) {
ONO::IO->rm("$path/data/$opt/$file");
$files++;
}

# delete this year's files if they're older than 3 months

if ($file =~ /^$year(.*)\.txt/) {
if (substr($1,0,2) < $mon-3) {
ONO::IO->rm("$path/data/$opt/$file");
$files++;
}
}

}

}

}

# data - work progress

foreach my $dir (ONO::IO->ls("$path/data/work/progress")) {
if ($dir =~ /[0-9]/) {

foreach my $file (ONO::IO->ls("$path/data/work/progress/$dir")) {
if ($file =~ /^2(.*?)\.txt$/) {

# delete files that are older than 2 years

if ($file !~ /^$year/ && $file !~ /^$lastyear/) {
ONO::IO->rm("$path/data/work/progress/$dir/$file");
$files++;
}

# delete last year's files if march has passed

if ($file =~ /^$lastyear/ && $mon > 3) {
ONO::IO->rm("$path/data/work/progress/$dir/$file");
$files++;
}

# delete this year's files if they're older than 3 months

if ($file =~ /^$year(.*)\.txt/) {
if (substr($1,0,2) < $mon-3) {
ONO::IO->rm("$path/data/work/progress/$dir/$file");
$files++;
}
}

}
}
}
}

# media

}
$DATA .= ONO::Cron::Service::ToolBox->print("- garbage: $files files cleaned up for $classes virclasses in $env",$switches);

}

}
}
}

return $DATA;

}

###############################################################################
# end of script
###############################################################################

1;

__END__