clrghouz/app/Classes/File/Send.php

336 lines
7.5 KiB
PHP

<?php
namespace App\Classes\File;
use Exception;
use Illuminate\Support\Facades\Log;
use League\Flysystem\UnreadableFileEncountered;
use App\Classes\File\Send\Dynamic;
use App\Classes\Node;
use App\Models\Address;
/**
* Object representing the files we are sending
*
* @property-read resource fd
* @property-read int files_size The size of the files waiting to be sent
* @property-read int mail_size The size of the mail waiting to be sent
* @property-read int togo_count The total number of items that havent been sent yet
* @property-read int total_size The size of the items waiting to be sent
* @property-read int total_sent
* @property-read int total_sent_bytes
*/
class Send extends Base
{
private const LOGKEY = 'IS-';
public const T_NONE = 0;
/** @var int This file contains a file from the DB */
public const T_FILE = (1<<0);
/** @var int This file contains a bundle of Netmail */
public const T_NETMAIL = (1<<1);
/** @var int This file contains a bundle of Echomail */
public const T_ECHOMAIL = (1<<2);
private string $comp_data;
public function __construct()
{
// Initialise our variables
if (get_class($this) === self::class) {
$this->list = collect();
$this->f = NULL;
}
}
public function __get($key)
{
switch ($key) {
case 'completed':
return $this->list
->filter(function($item) { return $item->complete === TRUE; });
case 'fd':
return ! is_null($this->index);
case 'files_count':
return $this->list
->filter(function($item) { return $item->isType(self::IS_FILE|self::IS_TIC); })
->count();
case 'files_size':
return $this->list
->filter(function($item) { return $item->isType(self::IS_FILE|self::IS_TIC); })
->sum(function($item) { return $item->size; });
case 'mail_count':
return $this->list
->filter(function($item) { return $item->isType(self::IS_ARC|self::IS_PKT); })
->count();
case 'mail_size':
return $this->list
->filter(function($item) { return $item->isType(self::IS_ARC|self::IS_PKT); })
->sum(function($item) { return $item->size; });
case 'name':
case 'nameas':
case 'mtime':
case 'size':
case 'type':
return $this->sending->{$key};
case 'pos':
return $this->{$key};
case 'sending':
return $this->list->get($this->index);
case 'togo_count':
return $this->list
->filter(function($item) { return $item->complete === FALSE; })
->count();
case 'total_sent':
return $this->completed
->count();
case 'total_sent_bytes':
return $this->completed
->sum(function($item) { return $item->size; });
case 'total_size':
return $this->list
->sum(function($item) { return $item->size; });
default:
throw new Exception('Unknown key: '.$key);
}
}
/**
* Close the file descriptor of the file we are sending
*
* @param bool $successful
* @param Node $node
* @throws Exception
*/
public function close(bool $successful,Node $node): void
{
if (! $this->fd)
throw new Exception('No file to close');
if ($successful) {
$end = time()-$this->start;
Log::info(sprintf('%s:- Closing [%s], sent in [%d] with [%s] items',self::LOGKEY,$this->sending->nameas,$end,$this->sending->dbids->count()));
}
$this->sending->close($successful,$node);
$this->index = NULL;
}
public function dynamic(Address $ao): bool
{
$file = FALSE;
// If the node is marked as hold - dont send any files.
if ($ao->system->hold) {
Log::info(sprintf('%s:- System [%d] is marked as hold - not checking for files.',self::LOGKEY,$ao->system_id));
return FALSE;
}
// Files
if (($x=$ao->dynamicWaiting())->count()) {
Log::debug(sprintf('%s:- [%d] Dynamic Files(s) added for sending to [%s]',self::LOGKEY,$x->count(),$ao->ftn));
// Add Files
foreach ($x as $do)
$this->list->push(new Dynamic($do,$ao,self::T_FILE));
$file = TRUE;
}
return $file;
}
/*
private function compress(string $comp_mode): void
{
switch ($comp_mode) {
case 'BZ2':
$this->comp_data = bzcompress($buf);
break;
case 'GZ':
$this->comp_data = gzcompress($buf);
break;
}
}
*/
/**
* Check if we are at the end of the file
*
* @return bool
*/
public function feof(): bool
{
return $this->sending->feof();
}
/**
* Add our mail to the send queue
*
* @param Address $ao
* @return bool
* @throws Exception
*/
public function files(Address $ao): bool
{
$file = FALSE;
// If the node is marked as hold - dont send any files.
if ($ao->system->hold) {
Log::info(sprintf('%s:- System [%d] is marked as hold - not checking for files.',self::LOGKEY,$ao->system_id));
return FALSE;
}
// Files
if (($x=$ao->filesWaiting())->count()) {
Log::debug(sprintf('%s:- [%d] Files(s) added for sending to [%s]',self::LOGKEY,$x->count(),$ao->ftn));
// Add Files
foreach ($x as $fo) {
$this->list->push(new File($fo,self::T_FILE));
$this->list->push(new Tic($fo,$ao,self::T_NONE));
}
$file = TRUE;
}
return $file;
}
/**
* Open a file for sending
*
* @param string $compress
* @return bool
* @throws Exception
*/
public function open(string $compress=''): bool
{
Log::debug(sprintf('%s:+ Opening file to send',self::LOGKEY));
if ((($this->index=$this->list->search(function($item) { return $item->complete === FALSE; })) !== FALSE)
&& $this->sending->open())
{
Log::info(sprintf('%s:- Sending item [%d] (%s)',self::LOGKEY,$this->index,$this->sending->nameas));
$this->pos = 0;
$this->start = time();
/*
if ($compress)
$this->comp_data = $this->compdata($compress);
*/
return TRUE;
} else {
throw new Exception('No files to open');
}
}
/**
* Add our mail to the send queue
*
* @param Address $ao
* @param bool $update
* @return bool
* @throws Exception
*/
public function mail(Address $ao,bool $update=TRUE): bool
{
$mail = FALSE;
// If the node is marked as hold - dont send any mail.
if ($ao->system->hold) {
Log::info(sprintf('%s:- System [%d] is marked as hold - not checking for mail.',self::LOGKEY,$ao->system_id));
return FALSE;
}
// Netmail
if ($x=$ao->getNetmail($update)) {
Log::debug(sprintf('%s:- Netmail(s) added for sending to [%s]',self::LOGKEY,$ao->ftn));
$this->list->push(new Mail($x,self::T_NETMAIL));
$mail = TRUE;
}
// Echomail
if ($x=$ao->getEchomail($update)) {
Log::debug(sprintf('%s:- Echomail(s) added for sending to [%s]',self::LOGKEY,$ao->ftn));
$this->list->push(new Mail($x,self::T_ECHOMAIL));
$mail = TRUE;
}
return $mail;
}
/**
* Read bytes of the sending file
*
* @param int $length
* @return string|null
* @throws UnreadableFileEncountered
* @throws Exception
*/
public function read(int $length): ?string
{
if (! $this->fd)
throw new Exception('No file open for read');
$data = $this->sending->read($length);
if ($data === FALSE)
throw new UnreadableFileEncountered('Error reading file: '.$this->sending->name);
$this->pos += strlen($data);
Log::debug(sprintf('%s:- Read [%d] bytes, file pos now [%d]',self::LOGKEY,strlen($data),$this->pos));
return $data;
}
/**
* Seek to a specific position of our file
*
* @param int $pos
* @return bool
* @throws Exception
*/
public function seek(int $pos): bool
{
if (! $this->fd)
throw new Exception('No file open for seek');
if ($this->sending->seek($pos)) {
$this->pos = $pos;
Log::debug(sprintf('%s:= Seeked to [%d]',self::LOGKEY,$this->pos));
return TRUE;
} else {
Log::error(sprintf('%s:! Failed to seek to [%d]',self::LOGKEY,$pos));
return FALSE;
}
}
}