Implemented file sending during BINKP and EMSI sessions

This commit is contained in:
2023-06-22 17:36:22 +10:00
parent 58341db0fb
commit b1b86ca04a
14 changed files with 308 additions and 82 deletions

View File

@@ -4,8 +4,11 @@ namespace App\Classes\File;
use Exception;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\UnreadableFileEncountered;
use App\Models\File;
/**
* A file we are sending or receiving
*
@@ -35,6 +38,7 @@ class Item
protected int $file_mtime = 0;
protected int $file_type = 0;
protected int $action = 0;
protected File $filemodel;
public bool $sent = FALSE;
public bool $received = FALSE;
@@ -51,19 +55,27 @@ class Item
switch ($action) {
case self::I_SEND:
if (! is_string($file))
throw new Exception('Invalid object creation - file should be a string');
if ($file instanceof File) {
$this->filemodel = $file;
// @todo We should catch any exceptions if the default storage is s3 (it is) and we cannot find the file, or the s3 call fails
$this->file_size = Storage::size($file->full_storage_path);
$this->file_mtime = Storage::lastModified($file->full_storage_path);
if (! file_exists($file))
throw new FileNotFoundException('Item doesnt exist: '.$file);
} else {
if (! is_string($file))
throw new Exception('Invalid object creation - file should be a string');
if (! is_readable($file))
throw new UnreadableFileEncountered('Item cannot be read: '.$file);
if (! file_exists($file))
throw new FileNotFoundException('Item doesnt exist: '.$file);
$this->file_name = $file;
$x = stat($file);
$this->file_size = $x['size'];
$this->file_mtime = $x['mtime'];
if (! is_readable($file))
throw new UnreadableFileEncountered('Item cannot be read: '.$file);
$this->file_name = $file;
$x = stat($file);
$this->file_size = $x['size'];
$this->file_mtime = $x['mtime'];
}
break;
@@ -104,7 +116,7 @@ class Item
return $this->file_name;
case 'sendas':
return basename($this->file_name);
return $this->file_name ? basename($this->file_name) : $this->filemodel->file;
default:
throw new Exception('Unknown key: '.$key);

View File

@@ -6,6 +6,7 @@ use Exception;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\UnreadableFileEncountered;
use App\Models\Address;
@@ -52,12 +53,12 @@ final class Send extends Item
case 'file_count':
return $this->list
->filter(function($item) { return $item->isType(self::IS_FILE); })
->filter(function($item) { return $item->isType(self::IS_FILE|self::IS_TIC); })
->count();
case 'file_size':
return $this->list
->filter(function($item) { return $item->isType(self::IS_FILE); })
->filter(function($item) { return $item->isType(self::IS_FILE|self::IS_TIC); })
->sum(function($item) { return $item->file_size; });
case 'filepos':
@@ -162,7 +163,8 @@ final class Send extends Item
Log::debug(sprintf('%s: - Closing [%s], sent in [%d]',self::LOGKEY,$this->sending->file_name,$end));
}
if (! $this->sending instanceof Mail)
// @todo This should be done better isType == file?
if ((! $this->sending instanceof Mail) && (! $this->sending->isType(self::IS_TIC)))
fclose($this->f);
$this->sending = NULL;
@@ -177,7 +179,44 @@ final class Send extends Item
*/
public function feof(): bool
{
return ($this->sending instanceof Mail) ? ($this->file_pos == $this->size) : feof($this->f);
return (($this->sending instanceof Mail) || ($this->sending->isType(self::IS_TIC)))
? ($this->file_pos == $this->size)
: feof($this->f);
}
/**
* Add our mail to the send queue
*
* @param Address $ao
* @return bool
* @throws Exception
* @todo We need to make this into a transaction, incase the transfer fails.
*/
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->getFiles())->count()) {
Log::debug(sprintf('%s:- [%d] Files(s) added for sending to [%s]',self::LOGKEY,$x->count(),$ao->ftn));
// Add Files
foreach ($x as $xx) {
$this->list->push(new Item($xx,self::I_SEND));
$this->list->push(new Tic($ao,$xx,self::I_SEND));
}
$file = TRUE;
}
return $file;
}
/**
@@ -212,14 +251,27 @@ final class Send extends Item
$this->file_pos = 0;
$this->start = time();
$this->f = fopen($this->sending->file_name,'rb');
if (! $this->f) {
Log::error(sprintf('%s:! Unable to open file [%s] for reading',self::LOGKEY,$this->sending->file_name));
return FALSE;
// If sending->file is a string, then we dont need to actually open anything
if ($this->sending->isType(self::IS_TIC)) {
$this->f = TRUE;
return TRUE;
}
Log::info(sprintf('%s:= open - File [%s] opened with size [%d]',self::LOGKEY,$this->sending->file_name,$this->sending->file_size));
return TRUE;
// If sending file is a File::class, then our file is s3
if (! $this->sending->file_name && $this->sending->filemodel) {
$this->f = Storage::readStream($this->sending->filemodel->full_storage_path);
return TRUE;
} else {
$this->f = fopen($this->sending->file_name,'rb');
if (! $this->f) {
Log::error(sprintf('%s:! Unable to open file [%s] for reading',self::LOGKEY,$this->sending->file_name));
return FALSE;
}
Log::info(sprintf('%s:= open - File [%s] opened with size [%d]',self::LOGKEY,$this->sending->file_name,$this->sending->file_size));
return TRUE;
}
}
/**
@@ -236,7 +288,7 @@ final class Send extends Item
// If the node is marked as hold - dont send any mail.
if ($ao->system->hold) {
Log::info(sprintf('%s: - System [%d] mail is marked as hold - not checking for mail.',self::LOGKEY,$ao->system_id));
Log::info(sprintf('%s: - System [%d] is marked as hold - not checking for mail.',self::LOGKEY,$ao->system_id));
return FALSE;
}
@@ -276,6 +328,11 @@ final class Send extends Item
// We are sending mail
if ($this->sending instanceof Mail) {
$data = $this->sending->read($this->file_pos,$length);
// We are sending a tic file
} else if ($this->sending->isType(self::IS_TIC)) {
$data = $this->sending->read($this->file_pos,$length);
} else {
$data = fread($this->f,$length);
}
@@ -303,7 +360,7 @@ final class Send extends Item
if (! $this->f)
throw new Exception('No file open for seek');
if ($this->sending instanceof Mail) {
if (($this->sending instanceof Mail) || $this->sending->isType(self::IS_TIC)) {
$pos = ($pos < $this->size) ? $pos : $this->size;
$rc = TRUE;

38
app/Classes/File/Tic.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
namespace App\Classes\File;
use App\Classes\FTN\Tic as FTNTic;
use App\Models\{Address,File};
class Tic extends Item
{
/**
* @throws \Exception
*/
public function __construct(Address $ao,File $fo,int $action)
{
$this->action |= $action;
$tic = new FTNTic;
switch ($action) {
case self::I_SEND:
$this->file = $tic->generate($ao,$fo);
$this->file_type = self::IS_TIC;
$this->file_name = sprintf('%s.tic',sprintf('%08x',$fo->id));
$this->file_size = strlen($this->file);
$this->file_mtime = $fo->created_at->timestamp;
break;
default:
throw new \Exception('Unknown action: '.$action);
}
}
public function read(int $start,int $length): string
{
return substr($this->file,$start,$length);
}
}