Compare commits
8 Commits
5312bee9bc
...
8d1dc800a5
Author | SHA1 | Date | |
---|---|---|---|
8d1dc800a5 | |||
05a496c05c | |||
38cfcc8c3e | |||
ca7ca7e60a | |||
3e62e3d8e1 | |||
7a7d7b369e | |||
bc3407e9d4 | |||
6f2c970b1f |
@ -5,6 +5,8 @@ APP_DEBUG=true
|
|||||||
APP_URL=http://clrghouz
|
APP_URL=http://clrghouz
|
||||||
APP_TIMEZONE=Australia/Melbourne
|
APP_TIMEZONE=Australia/Melbourne
|
||||||
|
|
||||||
|
CACHE_STORE=array
|
||||||
|
|
||||||
LOG_CHANNEL=stderr
|
LOG_CHANNEL=stderr
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
@ -13,7 +15,7 @@ DB_HOST=postgres-test
|
|||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_DATABASE=test
|
DB_DATABASE=test
|
||||||
DB_USERNAME=test
|
DB_USERNAME=test
|
||||||
DB_PASSWORD=test
|
DB_PASSWORD=password
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
BROADCAST_DRIVER=log
|
||||||
CACHE_DRIVER=file
|
CACHE_DRIVER=file
|
||||||
|
@ -78,7 +78,7 @@ class Area extends Base
|
|||||||
->whereNotNull('export_at')
|
->whereNotNull('export_at')
|
||||||
->whereNull('sent_at')
|
->whereNull('sent_at')
|
||||||
->orderBy('echomails.datetime')
|
->orderBy('echomails.datetime')
|
||||||
->skip($this->mo->fftn->system->pkt_msgs)
|
->skip($this->mo->fftn->system->pkt_msgs) // Might already being sent in this session
|
||||||
->delete();
|
->delete();
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- FTN [%s] UNSUBSCRIBED from [%s] clearing [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$x));
|
Log::debug(sprintf('%s:- FTN [%s] UNSUBSCRIBED from [%s] clearing [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$x));
|
||||||
|
@ -7,7 +7,7 @@ use Illuminate\Support\Facades\Log;
|
|||||||
|
|
||||||
use App\Classes\FTN\Process\Netmail\Robot;
|
use App\Classes\FTN\Process\Netmail\Robot;
|
||||||
use App\Models\{Echomail,Netmail};
|
use App\Models\{Echomail,Netmail};
|
||||||
use App\Notifications\Netmails\Areafix\CommandsProcessed;
|
use App\Notifications\Netmails\Filefix\CommandsProcessed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process messages to Ping
|
* Process messages to Ping
|
||||||
|
144
app/Classes/FTN/Process/Netmail/Robot/Filefix/Area.php
Normal file
144
app/Classes/FTN/Process/Netmail/Robot/Filefix/Area.php
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Classes\FTN\Process\Netmail\Robot\Filefix;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Classes\FTN\Process\Netmail\Robot\Areafix\Base;
|
||||||
|
use App\Jobs\FilefixRescan;
|
||||||
|
|
||||||
|
// Filearea Processing Command
|
||||||
|
class Area extends Base
|
||||||
|
{
|
||||||
|
private const LOGKEY = 'FFA';
|
||||||
|
|
||||||
|
private const command = '%AREA';
|
||||||
|
|
||||||
|
public static function help(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
self::command.' [-|+]<FILEAREA> [R|D=<DAYS>]',
|
||||||
|
' Use the area command to subscribe (+) or unsubscribe (-) to a FILEAREA',
|
||||||
|
' Arguments:',
|
||||||
|
' - FILEAREA (required) name of area to subscribe or unsubscribe',
|
||||||
|
' - D=DAYS (optional) number of days to resend files from this area that you',
|
||||||
|
' havent already received (useful if you are resubscribing to an area and',
|
||||||
|
' have received files in the past)',
|
||||||
|
' - R=DAYS (optional) number of days to resend files from this area (even if',
|
||||||
|
' it was sent to you previously)',
|
||||||
|
' Notes:',
|
||||||
|
' * "+" is optional, and is implied if "-" is not used',
|
||||||
|
' * "R" and "D" options only apply to subscribing',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process(): string
|
||||||
|
{
|
||||||
|
$command = self::command.' '.join(' ',$this->arguments);
|
||||||
|
|
||||||
|
// If command starts with '-', its to unsubscribe
|
||||||
|
if (str_starts_with($this->arguments[0],'-')) {
|
||||||
|
$sub = FALSE;
|
||||||
|
$area = substr($this->arguments[0],1);
|
||||||
|
|
||||||
|
} elseif (str_starts_with($this->arguments[0],'+')) {
|
||||||
|
$sub = TRUE;
|
||||||
|
$area = substr($this->arguments[0],1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$sub = TRUE;
|
||||||
|
$area = $this->arguments[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::debug(sprintf('%s:- Processing [%s] for [%s]',self::LOGKEY,$sub ? 'ADD' : 'REMOVE',$area));
|
||||||
|
|
||||||
|
// Drop the area from the arguments, the rest are options
|
||||||
|
array_shift($this->arguments);
|
||||||
|
|
||||||
|
// Area exists
|
||||||
|
if ($fa=$this->mo->fftn->domain->fileareas->where('name',$area)->pop()) {
|
||||||
|
// If already subscribed
|
||||||
|
if ($nea=$this->mo->fftn->fileareas->where('name',$area)->pop()) {
|
||||||
|
// requesting to subscribe "You already are since..., arguments ignored
|
||||||
|
if ($sub) {
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] ALREADY subscribed to [%s] since [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$nea->pivot->subscribed->format('Y-m-d H:i')));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- ALREADY subscribed since %s',$command,$nea->pivot->subscribed->format('Y-m-d H:i'));
|
||||||
|
|
||||||
|
// requesting to unsubscribe
|
||||||
|
} else {
|
||||||
|
$this->mo->fftn->fileareas()->detach($fa->id);
|
||||||
|
|
||||||
|
// Remove sub, clear queue
|
||||||
|
$x = DB::table('file_seenby')
|
||||||
|
->where('address_id',$this->mo->fftn->id)
|
||||||
|
->join('files',['files.id'=>'file_seenby.file_id'])
|
||||||
|
->where('filearea_id',$nea->id)
|
||||||
|
->whereNotNull('export_at')
|
||||||
|
->whereNull('sent_at')
|
||||||
|
->orderBy('files.datetime')
|
||||||
|
->skip(1) // Might already being sent in this session
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] UNSUBSCRIBED from [%s] clearing [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$x));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- UNSUBSCRIBED, CLEARED [%d] FILES from queue',$command,$x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not subscribed
|
||||||
|
} else {
|
||||||
|
// requesting to subscribe, subsubsribe and rescan if arguments
|
||||||
|
if ($sub) {
|
||||||
|
$this->mo->fftn->fileareas()->attach([$fa->id=>['subscribed'=>Carbon::now()]]);
|
||||||
|
|
||||||
|
// If we have arguments, they are to rescan
|
||||||
|
if (count($this->arguments) === 1) {
|
||||||
|
$m = [];
|
||||||
|
if (preg_match('/^([DR])=([0-9]+)$/',$this->arguments[0],$m)) {
|
||||||
|
switch ($m[1]) {
|
||||||
|
// Scan
|
||||||
|
case 'D':
|
||||||
|
FilefixRescan::dispatch($this->mo->fftn,$fa,$m[2])
|
||||||
|
->onQueue('mail');
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- SUBSCRIBED, RESCAN [%d] DAYS queued',$command,$m[2]);
|
||||||
|
|
||||||
|
// Scan
|
||||||
|
case 'R':
|
||||||
|
FilefixRescan::dispatch($this->mo->fftn,$fa,$m[2],TRUE)
|
||||||
|
->onQueue('mail');
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- SUBSCRIBED, FORCE RESCAN [%d] DAYS queued',$command,$m[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- SUBSCRIBED, INVALID OPTIONS',$command);
|
||||||
|
|
||||||
|
} elseif (count($this->arguments) > 1) {
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] subscribed to [%s], extra commands [%s] ignored',self::LOGKEY,$this->mo->fftn->ftn,$area,join('|',$this->arguments)));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- SUBSCRIBED, OPTIONS IGNORED',$command);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] subscribed to [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- SUBSCRIBED',$command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not subscribed, "you arent subscribed, arguments ignored"
|
||||||
|
} else {
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] is NOT subscribed to [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- NOT subscribed, NO ACTION taken',$command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] area UNKNOWN [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- AREA UNKNOWN, NO ACTION TAKEN',$command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ use Illuminate\Support\Facades\Notification;
|
|||||||
use App\Classes\FTN\Process\Netmail\Robot\Areafix\Base;
|
use App\Classes\FTN\Process\Netmail\Robot\Areafix\Base;
|
||||||
use App\Notifications\Netmails\Filefix\AreaList as AreaListNotification;
|
use App\Notifications\Netmails\Filefix\AreaList as AreaListNotification;
|
||||||
|
|
||||||
// LIST - List echoareas in a domain
|
// LIST - List fileareas in a domain
|
||||||
class AreaList extends Base
|
class AreaList extends Base
|
||||||
{
|
{
|
||||||
private const LOGKEY = 'AFS';
|
private const LOGKEY = 'AFS';
|
||||||
|
67
app/Classes/FTN/Process/Netmail/Robot/Filefix/Filelist.php
Normal file
67
app/Classes/FTN/Process/Netmail/Robot/Filefix/Filelist.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Classes\FTN\Process\Netmail\Robot\Filefix;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
|
||||||
|
use App\Classes\FTN\Process\Netmail\Robot\Areafix\Base;
|
||||||
|
use App\Notifications\Netmails\Filefix\Filelist as FilelistNotification;
|
||||||
|
|
||||||
|
// FILELIST - List files in an area
|
||||||
|
class Filelist extends Base
|
||||||
|
{
|
||||||
|
private const LOGKEY = 'AFR';
|
||||||
|
private const command = '%FILELIST';
|
||||||
|
|
||||||
|
public static function help(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
self::command.' [-|+]<FILEAREA> [<DAYS>]',
|
||||||
|
' Use the filelist command to list files from an filearea.',
|
||||||
|
' This is will resend files again, even if you have received them in the',
|
||||||
|
' past.',
|
||||||
|
' Arguments:',
|
||||||
|
' - FILEAREA (required) name of area',
|
||||||
|
' - DAYS (optional) number of days to resend mail from this area that you',
|
||||||
|
' If DAYS is omitted, the default is 30. The maximum is 365.',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process(): string
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:- Filefix [%s] for [%s] for [%s]',self::LOGKEY,self::command,$this->mo->fftn->ftn,join('|',$this->arguments)));
|
||||||
|
|
||||||
|
$command = self::command.' '.join(' ',$this->arguments);
|
||||||
|
|
||||||
|
if (! is_numeric($this->arguments[1]))
|
||||||
|
return sprintf('%-25s <-- INVALID, DAYS [%s] NOT NUMERIC',$command,$this->arguments[1]);
|
||||||
|
|
||||||
|
if ($this->arguments[1] > 365)
|
||||||
|
$this->arguments[1] = 365;
|
||||||
|
|
||||||
|
// Area exists
|
||||||
|
if ($fa=$this->mo->fftn->domain->fileareas->where('name',$this->arguments[0])->pop()) {
|
||||||
|
// If already subscribed
|
||||||
|
if ($this->mo->fftn->fileareas->pluck('name')->contains($this->arguments[0])) {
|
||||||
|
Notification::route('netmail',$this->mo->fftn)
|
||||||
|
->notify(new FileListNotification($this->mo,$fa,$this->arguments[1]));
|
||||||
|
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] FILELIST [%s] DAYS [%d]',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0],$this->arguments[1]));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- FILELIST [%d] DAYS',$command,$this->arguments[1]);
|
||||||
|
|
||||||
|
// If not subscribed
|
||||||
|
} else {
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] is NOT subscribed to [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0]));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- NOT subscribed, NO ACTION taken',$command);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log::debug(sprintf('%s:- FTN [%s] area UNKNOWN [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$this->arguments[0]));
|
||||||
|
|
||||||
|
return sprintf('%-25s <-- AREA UNKNOWN, NO ACTION TAKEN',$command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,24 +22,28 @@ class File extends FileBase implements \Iterator
|
|||||||
{
|
{
|
||||||
parent::__construct($path,$checkPath);
|
parent::__construct($path,$checkPath);
|
||||||
|
|
||||||
switch($x=$this->guessExtension()) {
|
if ($this->getExtension() === 'pkt')
|
||||||
case 'zip':
|
$this->canHandle = TRUE;
|
||||||
$this->canHandle = TRUE;
|
|
||||||
$this->isArchive = TRUE;
|
|
||||||
$this->z = new \ZipArchive;
|
|
||||||
$this->z->open($this->getRealPath());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NULL:
|
else
|
||||||
case 'bin':
|
switch ($x=$this->guessExtension()) {
|
||||||
if ($this->isPacket() || ($path instanceof UploadedFile && (strcasecmp($path->getClientOriginalExtension(),'pkt') === 0))) {
|
case 'zip':
|
||||||
$this->canHandle = TRUE;
|
$this->canHandle = TRUE;
|
||||||
|
$this->isArchive = TRUE;
|
||||||
|
$this->z = new \ZipArchive;
|
||||||
|
$this->z->open($this->getRealPath());
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
case NULL:
|
||||||
Log::alert(sprintf('%s:? Unknown file received: %s (%s) [%s]',self::LOGKEY,$x,$this->getExtension(),$path instanceof UploadedFile ? $path->getClientOriginalExtension() : '-'));
|
case 'bin':
|
||||||
}
|
if ($this->isPacket() || ($path instanceof UploadedFile && (strcasecmp($path->getClientOriginalExtension(),'pkt') === 0))) {
|
||||||
|
$this->canHandle = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log::alert(sprintf('%s:? Unknown file received: %s (%s) [%s]',self::LOGKEY,$x,$this->getExtension(),$path instanceof UploadedFile ? $path->getClientOriginalExtension() : '-'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ITERATOR */
|
/* ITERATOR */
|
||||||
|
@ -203,7 +203,7 @@ class Send extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
if (($x=$ao->filesWaiting())->count()) {
|
if (($x=$ao->getFiles())->count()) {
|
||||||
Log::info(sprintf('%s:- [%d] Files(s) added for sending to [%s]',self::LOGKEY,$x->count(),$ao->ftn));
|
Log::info(sprintf('%s:- [%d] Files(s) added for sending to [%s]',self::LOGKEY,$x->count(),$ao->ftn));
|
||||||
|
|
||||||
// Add Files
|
// Add Files
|
||||||
|
@ -11,6 +11,7 @@ final class SocketException extends \Exception {
|
|||||||
public const CANT_CONNECT = 5;
|
public const CANT_CONNECT = 5;
|
||||||
public const SOCKET_ERROR = 6;
|
public const SOCKET_ERROR = 6;
|
||||||
public const SOCKET_EAGAIN = 11;
|
public const SOCKET_EAGAIN = 11;
|
||||||
|
public const SOCKET_TIMEOUT = 15;
|
||||||
public const SOCKET_READ = 22;
|
public const SOCKET_READ = 22;
|
||||||
public const CONNECTION_RESET = 104;
|
public const CONNECTION_RESET = 104;
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ final class SocketException extends \Exception {
|
|||||||
self::CANT_CONNECT => 'Can\'t connect: "%s"',
|
self::CANT_CONNECT => 'Can\'t connect: "%s"',
|
||||||
self::SOCKET_ERROR => 'Socket Error: "%s"',
|
self::SOCKET_ERROR => 'Socket Error: "%s"',
|
||||||
self::SOCKET_EAGAIN => 'Socket Resource Temporarily Unavailable - Try again',
|
self::SOCKET_EAGAIN => 'Socket Resource Temporarily Unavailable - Try again',
|
||||||
|
self::SOCKET_TIMEOUT => 'Timeout reached "%d"',
|
||||||
self::SOCKET_READ => 'Unable to read from socket',
|
self::SOCKET_READ => 'Unable to read from socket',
|
||||||
self::CONNECTION_RESET => 'Connection reset by peer',
|
self::CONNECTION_RESET => 'Connection reset by peer',
|
||||||
];
|
];
|
||||||
|
@ -48,7 +48,8 @@ final class SocketClient {
|
|||||||
/** @var string Data in the RX buffer */
|
/** @var string Data in the RX buffer */
|
||||||
private string $rx_buf = '';
|
private string $rx_buf = '';
|
||||||
|
|
||||||
public function __construct (\Socket $connection,bool $originate=FALSE) {
|
public function __construct (\Socket $connection,bool $originate=FALSE)
|
||||||
|
{
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
|
|
||||||
if ($this->type === SOCK_STREAM) {
|
if ($this->type === SOCK_STREAM) {
|
||||||
@ -62,7 +63,7 @@ final class SocketClient {
|
|||||||
if (($x=$this->read(5,6)) === 'PROXY ')
|
if (($x=$this->read(5,6)) === 'PROXY ')
|
||||||
$vers = 1;
|
$vers = 1;
|
||||||
|
|
||||||
elseif (($x === "\x0d\x0a\x0d\x0a\x00\x0d") && ($this->read('5,6') === "\x0aQUIT\x0a"))
|
elseif (($x === "\x0d\x0a\x0d\x0a\x00\x0d") && ($this->read(5,6) === "\x0aQUIT\x0a"))
|
||||||
$vers = 2;
|
$vers = 2;
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -191,38 +192,26 @@ final class SocketClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get($key) {
|
public function __get(string $key): mixed
|
||||||
switch ($key) {
|
{
|
||||||
case 'address_remote':
|
return match ($key) {
|
||||||
case 'port_remote':
|
'address_remote', 'port_remote' => $this->{$key},
|
||||||
return $this->{$key};
|
'cps', 'speed' => Arr::get($this->session,$key),
|
||||||
|
'rx_free' => self::RX_BUF_SIZE-$this->rx_left,
|
||||||
case 'cps':
|
'rx_left' => strlen($this->rx_buf),
|
||||||
case 'speed':
|
'tx_free' => self::TX_BUF_SIZE-strlen($this->tx_buf),
|
||||||
return Arr::get($this->session,$key);
|
'type' => socket_get_option($this->connection,SOL_SOCKET,SO_TYPE),
|
||||||
|
default => throw new \Exception(sprintf('%s:! Unknown key [%s]:',self::LOGKEY, $key)),
|
||||||
case 'rx_free':
|
};
|
||||||
return self::RX_BUF_SIZE-$this->rx_left;
|
|
||||||
|
|
||||||
case 'rx_left':
|
|
||||||
return strlen($this->rx_buf);
|
|
||||||
|
|
||||||
case 'tx_free':
|
|
||||||
return self::TX_BUF_SIZE-strlen($this->tx_buf);
|
|
||||||
|
|
||||||
case 'type':
|
|
||||||
return socket_get_option($this->connection,SOL_SOCKET,SO_TYPE);
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new \Exception(sprintf('%s:! Unknown key [%s]:',self::LOGKEY,$key));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __set($key,$value) {
|
public function __set(string $key,mixed $value): void
|
||||||
|
{
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
case 'cps':
|
case 'cps':
|
||||||
case 'speed':
|
case 'speed':
|
||||||
return $this->session[$key] = $value;
|
$this->session[$key] = $value;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new \Exception(sprintf('%s:! Unknown key [%s]:',self::LOGKEY,$key));
|
throw new \Exception(sprintf('%s:! Unknown key [%s]:',self::LOGKEY,$key));
|
||||||
@ -350,7 +339,7 @@ final class SocketClient {
|
|||||||
while (strlen($this->tx_buf)) {
|
while (strlen($this->tx_buf)) {
|
||||||
$tv = $this->timer_rest($tm);
|
$tv = $this->timer_rest($tm);
|
||||||
|
|
||||||
if (($rc=$this->canSend($tv)) > 0) {
|
if ($rc=$this->canSend($tv)) {
|
||||||
if (self::DEBUG)
|
if (self::DEBUG)
|
||||||
Log::debug(sprintf('%s:- Chars to send [%d]',self::LOGKEY,strlen($this->tx_buf)));
|
Log::debug(sprintf('%s:- Chars to send [%d]',self::LOGKEY,strlen($this->tx_buf)));
|
||||||
|
|
||||||
@ -378,14 +367,14 @@ final class SocketClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @return int
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function canSend(int $timeout): int
|
public function canSend(int $timeout): bool
|
||||||
{
|
{
|
||||||
$write = [$this->connection];
|
$write = [$this->connection];
|
||||||
|
|
||||||
return $this->socketSelect(NULL,$write,NULL,$timeout);
|
return $this->socketSelect(NULL,$write,NULL,$timeout) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -412,14 +401,14 @@ final class SocketClient {
|
|||||||
* We have data in the buffer or on the socket
|
* We have data in the buffer or on the socket
|
||||||
*
|
*
|
||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @return int
|
* @return bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function hasData(int $timeout): int
|
public function hasData(int $timeout): bool
|
||||||
{
|
{
|
||||||
$read = [$this->connection];
|
$read = [$this->connection];
|
||||||
|
|
||||||
return $this->rx_left ?: $this->socketSelect($read,NULL,NULL,$timeout);
|
return ($this->rx_left ?: $this->socketSelect($read,NULL,NULL,$timeout)) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -427,10 +416,11 @@ final class SocketClient {
|
|||||||
*
|
*
|
||||||
* @param int $timeout How long to wait for data
|
* @param int $timeout How long to wait for data
|
||||||
* @param int $len The amount of data we want
|
* @param int $len The amount of data we want
|
||||||
|
* @param int $flags
|
||||||
* @return string|null
|
* @return string|null
|
||||||
* @throws SocketException
|
* @throws SocketException
|
||||||
*/
|
*/
|
||||||
public function read(int $timeout,int $len=1024): ?string
|
public function read(int $timeout,int $len=1024,int $flags=MSG_DONTWAIT): ?string
|
||||||
{
|
{
|
||||||
// We have data in our buffer
|
// We have data in our buffer
|
||||||
if ($this->rx_left >= $len) {
|
if ($this->rx_left >= $len) {
|
||||||
@ -443,19 +433,19 @@ final class SocketClient {
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($timeout AND ($this->hasData($timeout) === 0))
|
if ($timeout && (! $this->hasData($timeout)))
|
||||||
return NULL;
|
throw new SocketException(SocketException::SOCKET_TIMEOUT,$timeout);
|
||||||
|
|
||||||
$buf = '';
|
$buf = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch ($this->type) {
|
switch ($this->type) {
|
||||||
case SOCK_STREAM:
|
case SOCK_STREAM:
|
||||||
$recv = socket_recv($this->connection,$buf,self::RX_SIZE,MSG_DONTWAIT);
|
$recv = socket_recv($this->connection,$buf,self::RX_SIZE,$flags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOCK_DGRAM:
|
case SOCK_DGRAM:
|
||||||
$recv = socket_recvfrom($this->connection,$buf,self::RX_SIZE,MSG_DONTWAIT,$this->address_remote,$this->port_remote);
|
$recv = socket_recvfrom($this->connection,$buf,self::RX_SIZE,$flags,$this->address_remote,$this->port_remote);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -515,12 +505,11 @@ final class SocketClient {
|
|||||||
*/
|
*/
|
||||||
public function read_ch(int $timeout): int
|
public function read_ch(int $timeout): int
|
||||||
{
|
{
|
||||||
if ($this->hasData($timeout) > 0) {
|
if ($this->hasData($timeout))
|
||||||
$ch = $this->read($timeout,1);
|
$ch = $this->read($timeout,1);
|
||||||
|
|
||||||
} else {
|
else
|
||||||
return self::TIMEOUT;
|
throw new SocketException(SocketException::SOCKET_TIMEOUT,$timeout);
|
||||||
}
|
|
||||||
|
|
||||||
return ord($ch);
|
return ord($ch);
|
||||||
}
|
}
|
||||||
@ -549,12 +538,12 @@ final class SocketClient {
|
|||||||
*
|
*
|
||||||
* @param string $message
|
* @param string $message
|
||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @return int|false
|
* @return int|bool
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function send(string $message,int $timeout): int|false
|
public function send(string $message,int $timeout): int|bool
|
||||||
{
|
{
|
||||||
if ($timeout AND (! $rc=$this->canSend($timeout)))
|
if ($timeout && (! $rc=$this->canSend($timeout)))
|
||||||
return $rc;
|
return $rc;
|
||||||
|
|
||||||
if (self::DEBUG)
|
if (self::DEBUG)
|
||||||
@ -634,4 +623,4 @@ final class SocketClient {
|
|||||||
|
|
||||||
return $this->socketSelect($read,$write,NULL,$timeout);
|
return $this->socketSelect($read,$write,NULL,$timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -51,6 +51,9 @@ class Rescan extends Command
|
|||||||
|
|
||||||
$eo = Echoarea::where('name',$this->argument('area'))->sole();
|
$eo = Echoarea::where('name',$this->argument('area'))->sole();
|
||||||
|
|
||||||
|
if ($eo->domain_id !== $ao->zone->domain_id)
|
||||||
|
throw new \Exception(sprintf('Echo area [%s] is not in domain [%s] for FTN [%s]',$eo->name,$ao->zone->domain->name,$ao->ftn));
|
||||||
|
|
||||||
if ($this->option('queue'))
|
if ($this->option('queue'))
|
||||||
AreafixRescan::dispatch($ao,$eo,$this->argument('days'))->onQueue($this->option('queuename'));
|
AreafixRescan::dispatch($ao,$eo,$this->argument('days'))->onQueue($this->option('queuename'));
|
||||||
else
|
else
|
||||||
|
@ -24,7 +24,7 @@ class AddressCheck extends Command
|
|||||||
|
|
||||||
$this->info(sprintf('Address: %s (%s)',$o->ftn,$o->role_name));
|
$this->info(sprintf('Address: %s (%s)',$o->ftn,$o->role_name));
|
||||||
$this->info(sprintf("Children: \n- %s",$o->children()->pluck('ftn4d')->join("\n- ")));
|
$this->info(sprintf("Children: \n- %s",$o->children()->pluck('ftn4d')->join("\n- ")));
|
||||||
$this->info(sprintf("Downstream: \n- %s",$o->downstream()->pluck('ftn4d')->join("\n- ")));
|
$this->info(sprintf("Downlinks: \n- %s",$o->downlinks()->pluck('ftn4d')->join("\n- ")));
|
||||||
$this->info(sprintf('Uplink: %s (Parent: %s)',$o->uplink()?->ftn,$o->parent()?->ftn));
|
$this->info(sprintf('Uplink: %s (Parent: %s)',$o->uplink()?->ftn,$o->parent()?->ftn));
|
||||||
$this->info(sprintf('Our Address: %s',our_address($o)?->ftn));
|
$this->info(sprintf('Our Address: %s',our_address($o)?->ftn));
|
||||||
$this->info(sprintf('- Domain Addresses: %s',our_address($o->zone->domain)->pluck('ftn4d')->join(',')));
|
$this->info(sprintf('- Domain Addresses: %s',our_address($o->zone->domain)->pluck('ftn4d')->join(',')));
|
||||||
|
@ -25,21 +25,22 @@ class ZoneCheck extends Command
|
|||||||
$this->warn('Zone: '.$zo->zone_id);
|
$this->warn('Zone: '.$zo->zone_id);
|
||||||
$this->info(sprintf('- Our address(es): %s',our_address($do)->pluck('ftn4d')->join(',')));
|
$this->info(sprintf('- Our address(es): %s',our_address($do)->pluck('ftn4d')->join(',')));
|
||||||
|
|
||||||
$this->table(['id','ftn','role','parent','children','downlinks','uplink','send from','region_id','system','notes'],$zo->addresses()->FTNorder()->active()->with(['system'])->dontCache()->get()->transform(function($item) {
|
$this->table(['id','ftn','role','parent','children','downlinks','uplink','send from','region_id','system','notes'],
|
||||||
return [
|
$zo->addresses()->FTN()->active()->with(['system','nodes_hub'])->get()->transform(function($item) {
|
||||||
'id'=>$item->id,
|
return [
|
||||||
'ftn'=>$item->ftn4d,
|
'id'=>$item->id,
|
||||||
'role'=>$item->role_name,
|
'ftn'=>$item->ftn4d,
|
||||||
'parent'=>$item->parent()?->ftn4d,
|
'role'=>$item->role_name,
|
||||||
'children'=>$item->children()->count(),
|
'parent'=>$item->parent()?->ftn4d,
|
||||||
'downlinks'=>$item->downlinks()->count(),
|
'children'=>$item->children()->count(),
|
||||||
'uplink'=>($x=$item->uplink())?->ftn4d,
|
'downlinks'=>$item->downlinks()->count(),
|
||||||
'send from'=>$x ? our_address($item->uplink())?->ftn4d : '',
|
'uplink'=>($x=$item->uplink())?->ftn4d,
|
||||||
'region_id'=>$item->region_id,
|
'send from'=>$x ? our_address($item->uplink())?->ftn4d : '',
|
||||||
'system'=>$item->system->name,
|
'region_id'=>$item->region_id,
|
||||||
'notes'=>$item->isRoleOverride() ? 'Role Override' : '',
|
'system'=>$item->system->name,
|
||||||
];
|
'notes'=>$item->isRoleOverride() ? 'Role Override' : '',
|
||||||
}));
|
];
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands\Filefix;
|
namespace App\Console\Commands\Filefix;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
use App\Models\{Address,Filearea,File};
|
use App\Jobs\FilefixRescan;
|
||||||
|
use App\Models\{Address,Filearea};
|
||||||
|
|
||||||
class Rescan extends Command
|
class Rescan extends Command
|
||||||
{
|
{
|
||||||
@ -14,7 +14,13 @@ class Rescan extends Command
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'filefix:rescan {ftn} {area} {file?}';
|
protected $signature = 'filefix:rescan'
|
||||||
|
.' {ftn : FTN Address}'
|
||||||
|
.' {area : Echoarea Tag}'
|
||||||
|
.' {days? : Limit to files received days ago}'
|
||||||
|
.' {--j|queue : Queue the Job}'
|
||||||
|
.' {--Q|queuename=default : Queue on queue}'
|
||||||
|
.' {--R|export : Re-export previously sent files}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
@ -31,6 +37,9 @@ class Rescan extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
|
if (($this->argument('days')) && (! is_numeric($this->argument('days'))))
|
||||||
|
throw new \Exception('Days must be numeric: '.$this->argument('days'));
|
||||||
|
|
||||||
$ao = Address::findFtn($this->argument('ftn'));
|
$ao = Address::findFtn($this->argument('ftn'));
|
||||||
|
|
||||||
if (! $ao)
|
if (! $ao)
|
||||||
@ -41,49 +50,14 @@ class Rescan extends Command
|
|||||||
throw new \Exception('Areaname is required');
|
throw new \Exception('Areaname is required');
|
||||||
|
|
||||||
$fao = Filearea::where('name',$this->argument('area'))->sole();
|
$fao = Filearea::where('name',$this->argument('area'))->sole();
|
||||||
|
|
||||||
if ($fao->domain_id !== $ao->zone->domain_id)
|
if ($fao->domain_id !== $ao->zone->domain_id)
|
||||||
throw new \Exception(sprintf('File area [%s] is not in domain [%s] for FTN [%s]',$fao->name,$ao->zone->domain->name,$ao->ftn));
|
throw new \Exception(sprintf('File area [%s] is not in domain [%s] for FTN [%s]',$fao->name,$ao->zone->domain->name,$ao->ftn));
|
||||||
|
|
||||||
// Check that the user is subscribed
|
if ($this->option('queue'))
|
||||||
if (! $ao->fileareas->contains($fao->id))
|
FilefixRescan::dispatch($ao,$fao,$this->argument('days'))->onQueue($this->option('queuename'));
|
||||||
throw new \Exception(sprintf('FTN [%s] is not subscribed to [%s]',$ao->ftn,$fao->name));
|
else
|
||||||
|
FilefixRescan::dispatchSync($ao,$fao,$this->argument('days'));
|
||||||
// Check that an FTN can read the area
|
|
||||||
if (! $fao->can_read($ao->security))
|
|
||||||
throw new \Exception(sprintf('FTN [%s] doesnt have permission to receive [%s]',$ao->ftn,$fao->name));
|
|
||||||
|
|
||||||
foreach (File::select('id')
|
|
||||||
->where('filearea_id',$fao->id)
|
|
||||||
->when($this->argument('file'),function($query) {
|
|
||||||
return $query->where('name','=',$this->argument('file'));
|
|
||||||
})
|
|
||||||
->orderBy('datetime')
|
|
||||||
->cursor() as $fo) {
|
|
||||||
|
|
||||||
// File hasnt been exported before
|
|
||||||
if (! $fo->seenby->count()) {
|
|
||||||
$fo->seenby()->attach($ao->id,['export_at'=>Carbon::now()]);
|
|
||||||
$this->info(sprintf('Exported [%d] to [%s]',$fo->id,$ao->ftn3d));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$export = $fo->seenby->where('id',$ao->id)->pop();
|
|
||||||
|
|
||||||
// File is pending export
|
|
||||||
if ($export && $export->pivot->export_at && is_null($export->pivot->sent_at) && is_null($export->pivot->sent_pkt)) {
|
|
||||||
$this->warn(sprintf('Not exporting [%d] already queued for [%s]',$fo->id,$ao->ftn3d));
|
|
||||||
|
|
||||||
// File has been exported
|
|
||||||
} elseif ($export) {
|
|
||||||
$fo->seenby()->updateExistingPivot($ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
|
||||||
$this->info(sprintf('Re-exported [%d] to [%s]',$fo->id,$ao->ftn3d));
|
|
||||||
|
|
||||||
// File has not been exported
|
|
||||||
} else {
|
|
||||||
$fo->seenby()->attach($ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
|
||||||
$this->info(sprintf('Exported [%d] to [%s]',$fo->id,$ao->ftn3d));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
|
168
app/Jobs/FilefixRescan.php
Normal file
168
app/Jobs/FilefixRescan.php
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\Middleware\Skip;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
|
||||||
|
use App\Models\{Address,Filearea,File};
|
||||||
|
use App\Notifications\Netmails\Filefix\Scan;
|
||||||
|
|
||||||
|
class FilefixRescan implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
private const LOGKEY = 'JAR';
|
||||||
|
|
||||||
|
private Address $ao; // System address
|
||||||
|
private Filearea $fao; // Domain we are processing
|
||||||
|
private int $days;
|
||||||
|
private bool $rescan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct(Address $ao,Filearea $fao,int $days=30,bool $rescan=FALSE)
|
||||||
|
{
|
||||||
|
$this->ao = $ao->withoutRelations();
|
||||||
|
$this->fao = $fao->withoutRelations();
|
||||||
|
$this->days = $days;
|
||||||
|
$this->rescan = $rescan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get(string $key): mixed
|
||||||
|
{
|
||||||
|
switch ($key) {
|
||||||
|
case 'jobname':
|
||||||
|
return sprintf('%s %s (%d)',$this->ao->ftn,$this->fao->name,$this->days);
|
||||||
|
|
||||||
|
default:
|
||||||
|
$this->fail('Unkown key:'.$key);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function middleware(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Skip::when(function(): bool {
|
||||||
|
if ($this->fao->domain_id !== $this->ao->zone->domain_id) {
|
||||||
|
Log::error(sprintf('%s:! File area [%s] is not in domain [%s] for FTN [%s]',self::LOGKEY,$this->fao->name,$this->ao->zone->domain->name,$this->ao->ftn));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
// Check that the user is subscribed
|
||||||
|
} elseif (! $this->ao->fileareas->contains($this->fao->id)) {
|
||||||
|
Log::error(sprintf('%s:! FTN [%s] is not subscribed to [%s]',self::LOGKEY,$this->ao->ftn,$this->fao->name));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
// Check that an FTN can read the area
|
||||||
|
} elseif (! $this->fao->can_read($this->ao->security)) {
|
||||||
|
Log::error(sprintf('%s:! FTN [%s] doesnt have permission to receive [%s]',self::LOGKEY,$this->ao->ftn,$this->fao->name));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
$c = 0;
|
||||||
|
$s = 0;
|
||||||
|
|
||||||
|
$earliest = NULL;
|
||||||
|
$latest = NULL;
|
||||||
|
|
||||||
|
foreach (File::select(['id','datetime'])
|
||||||
|
->where('filearea_id',$this->fao->id)
|
||||||
|
->where('datetime','>=',
|
||||||
|
Carbon::now()
|
||||||
|
->subDays($this->days)
|
||||||
|
->startOfDay()
|
||||||
|
)
|
||||||
|
->orderBy('datetime')
|
||||||
|
->cursor() as $fo) {
|
||||||
|
|
||||||
|
// File hasnt been exported before
|
||||||
|
if (! $fo->seenby->count()) {
|
||||||
|
$fo->seenby()->attach($this->ao->id,['export_at'=>Carbon::now()]);
|
||||||
|
$c++;
|
||||||
|
|
||||||
|
if (($fo->datetime < $earliest) || (! $earliest))
|
||||||
|
$earliest = $fo->datetime;
|
||||||
|
|
||||||
|
if (($latest < $fo->datetime) || (! $latest))
|
||||||
|
$latest = $fo->datetime;
|
||||||
|
|
||||||
|
Log::debug(sprintf('Exported [%d] FILE (%s) dated (%s) to [%s]',$fo->id,$fo->name,$fo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$export = $fo->seenby->where('id',$this->ao->id)->pop();
|
||||||
|
|
||||||
|
if ($export) {
|
||||||
|
// File is pending export
|
||||||
|
if ($export->pivot->export_at && is_null($export->pivot->sent_at) && is_null($export->pivot->sent_pkt)) {
|
||||||
|
$s++;
|
||||||
|
Log::debug(sprintf('Not exporting [%d] FILE (%s) dated (%s) already queued for [%s]',$fo->id,$fo->name,$fo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));
|
||||||
|
|
||||||
|
// File has been exported
|
||||||
|
} elseif ($this->rescan) {
|
||||||
|
$fo->seenby()->updateExistingPivot($this->ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
||||||
|
$c++;
|
||||||
|
|
||||||
|
if (($fo->datetime < $earliest) || (! $earliest))
|
||||||
|
$earliest = $fo->datetime;
|
||||||
|
|
||||||
|
if (($latest < $fo->datetime) || (! $latest))
|
||||||
|
$latest = $fo->datetime;
|
||||||
|
|
||||||
|
Log::debug(sprintf('Re-exported [%d] FILE (%s) dated (%s) to [%s]',$fo->id,$fo->name,$fo->datetime,$this->ao->ftn3d));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$s++;
|
||||||
|
Log::debug(sprintf('Not resending previously sent message [%d], FILE (%s) - sent on [%s]',
|
||||||
|
$fo->id,
|
||||||
|
$fo->name,
|
||||||
|
$export->pivot->sent_at ?: '-',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// File has not been exported
|
||||||
|
} else {
|
||||||
|
$fo->seenby()->attach($this->ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
||||||
|
$c++;
|
||||||
|
|
||||||
|
if (($fo->datetime < $earliest) || (! $earliest))
|
||||||
|
$earliest = $fo->datetime;
|
||||||
|
|
||||||
|
if (($latest < $fo->datetime) || (! $latest))
|
||||||
|
$latest = $fo->datetime;
|
||||||
|
|
||||||
|
Log::debug(sprintf('Exported [%d] to [%s]',$fo->id,$this->ao->ftn3d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Notification::route('netmail',$this->ao)
|
||||||
|
->notify(new Scan(collect([
|
||||||
|
'area'=>$this->fao->name,
|
||||||
|
'queued'=>$c,
|
||||||
|
'skipped'=>$s,
|
||||||
|
'earliest'=>$earliest,
|
||||||
|
'latest'=>$latest,
|
||||||
|
])));
|
||||||
|
|
||||||
|
Log::info(sprintf('%s:= Queued [%d], Skipped [%d] files for [%s] in [%s]',self::LOGKEY,$c,$s,$this->ao->ftn,$this->fao->name));
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@ use Illuminate\Support\Facades\Log;
|
|||||||
|
|
||||||
use App\Classes\FTN\{Message,Packet};
|
use App\Classes\FTN\{Message,Packet};
|
||||||
use App\Exceptions\InvalidFTNException;
|
use App\Exceptions\InvalidFTNException;
|
||||||
use App\Traits\{QueryCacheableConfig,ScopeActive};
|
use App\Traits\ScopeActive;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents an FTN AKA.
|
* This represents an FTN AKA.
|
||||||
@ -48,7 +48,7 @@ use App\Traits\{QueryCacheableConfig,ScopeActive};
|
|||||||
|
|
||||||
class Address extends Model
|
class Address extends Model
|
||||||
{
|
{
|
||||||
use QueryCacheableConfig,ScopeActive,SoftDeletes;
|
use ScopeActive,SoftDeletes;
|
||||||
|
|
||||||
private const LOGKEY = 'MA-';
|
private const LOGKEY = 'MA-';
|
||||||
|
|
||||||
@ -359,8 +359,8 @@ class Address extends Model
|
|||||||
// We can only work out region/zone if we have a domain - this is for 2D parsing
|
// We can only work out region/zone if we have a domain - this is for 2D parsing
|
||||||
if ($matches[5] ?? NULL) {
|
if ($matches[5] ?? NULL) {
|
||||||
$o = new self;
|
$o = new self;
|
||||||
$o->host_id = $matches[2];
|
$o->host_id = (int)$matches[2];
|
||||||
$o->node_id = $matches[3];
|
$o->node_id = (int)$matches[3];
|
||||||
$o->point_id = empty($matches[4]) ? 0 : (int)$matches[4];
|
$o->point_id = empty($matches[4]) ? 0 : (int)$matches[4];
|
||||||
|
|
||||||
if ($matches[1] !== "0") {
|
if ($matches[1] !== "0") {
|
||||||
@ -469,8 +469,7 @@ class Address extends Model
|
|||||||
->whereNotNull('export_at')
|
->whereNotNull('export_at')
|
||||||
->whereNull('sent_at')
|
->whereNull('sent_at')
|
||||||
->whereNull('echomails.deleted_at')
|
->whereNull('echomails.deleted_at')
|
||||||
->groupBy('addresses.id')
|
->groupBy('addresses.id');
|
||||||
->dontCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeUncollectedEchomailTotal($query)
|
public function scopeUncollectedEchomailTotal($query)
|
||||||
@ -504,8 +503,7 @@ class Address extends Model
|
|||||||
->whereNotNull('export_at')
|
->whereNotNull('export_at')
|
||||||
->whereNull('sent_at')
|
->whereNull('sent_at')
|
||||||
->whereNull('files.deleted_at')
|
->whereNull('files.deleted_at')
|
||||||
->groupBy('addresses.id')
|
->groupBy('addresses.id');
|
||||||
->dontCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeUncollectedFilesTotal($query)
|
public function scopeUncollectedFilesTotal($query)
|
||||||
@ -537,8 +535,7 @@ class Address extends Model
|
|||||||
->whereNull('sent_pkt')
|
->whereNull('sent_pkt')
|
||||||
->whereNull('sent_at')
|
->whereNull('sent_at')
|
||||||
->whereNull('netmails.deleted_at')
|
->whereNull('netmails.deleted_at')
|
||||||
->groupBy('addresses.id')
|
->groupBy('addresses.id');
|
||||||
->dontCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -639,7 +636,7 @@ class Address extends Model
|
|||||||
public function nodes_hub(): HasMany
|
public function nodes_hub(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Address::class,'hub_id','id')
|
return $this->hasMany(Address::class,'hub_id','id')
|
||||||
->select(['id','addresses.zone_id','host_id','node_id','point_id','system_id'])
|
->select(['id','addresses.zone_id','region_id','host_id','node_id','point_id','system_id'])
|
||||||
->active()
|
->active()
|
||||||
->FTNorder()
|
->FTNorder()
|
||||||
->with([
|
->with([
|
||||||
@ -810,7 +807,7 @@ class Address extends Model
|
|||||||
|
|
||||||
public function getIsHostedAttribute(): bool
|
public function getIsHostedAttribute(): bool
|
||||||
{
|
{
|
||||||
return strlen($this->getPassSessionAttribute()) > 0;
|
return strlen($this->getPassSessionAttribute() ?: '') > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getIsHoldAttribute(): bool
|
public function getIsHoldAttribute(): bool
|
||||||
@ -943,60 +940,96 @@ class Address extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the immediate children dependent on this record
|
* This is the children of this record, as per normal FTN routing ZC -> RC -> NC -> HUB -> Node -> Point
|
||||||
|
*
|
||||||
|
* This a ZC would return all records for the Zone,
|
||||||
|
* An RC would only return records in the region, etc
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
|
* @see self::parent()
|
||||||
*/
|
*/
|
||||||
public function children(): Collection
|
public function children(): Collection
|
||||||
{
|
{
|
||||||
// If we are a point, our parent is the boss
|
// If we are a point, our parent is the boss
|
||||||
switch ($this->role_id) {
|
switch ($this->role_id) {
|
||||||
case self::NODE_NN: // Normal Nodes -> Points
|
case self::NODE_NN: // Normal Nodes
|
||||||
return $this->nodes_point;
|
$o = self::active()
|
||||||
|
->where('zone_id',$this->zone_id)
|
||||||
|
->where('region_id',$this->region_id)
|
||||||
|
->where('host_id',$this->host_id)
|
||||||
|
->where('node_id',$this->node_id);
|
||||||
|
|
||||||
case self::NODE_HC: // Hubs -> Normal Nodes
|
break;
|
||||||
return $this->nodes_hub;
|
|
||||||
|
|
||||||
case self::NODE_NC: // Nets -> Normal Nodes, excluding Hub's Nodes
|
case self::NODE_HC: // Hubs
|
||||||
return $this->nodes_net->diff($this
|
$o = self::active()
|
||||||
->nodes_net
|
->where('zone_id',$this->zone_id)
|
||||||
->filter(function($item) { return $item->role_id === Address::NODE_HC; })
|
->where('region_id',$this->region_id)
|
||||||
->transform(function($item) { return $item->children(); })
|
->where('host_id',$this->host_id)
|
||||||
->flatten());
|
->where('hub_id',$this->id)
|
||||||
|
->where('id','<>',$this->id)
|
||||||
|
->get();
|
||||||
|
|
||||||
case self::NODE_RC: // Regions, excluding NC's Nodes
|
// Need to add in points of this hub's nodes
|
||||||
return $this->nodes_region->diff($this
|
return $o->merge(
|
||||||
->nodes_region
|
self::active()
|
||||||
->filter(function($item) { return $item->role_id === Address::NODE_NC; })
|
->where('zone_id',$this->zone_id)
|
||||||
->transform(function($item) { return $item->nodes_net; })
|
->where('region_id',$this->region_id)
|
||||||
->flatten());
|
->where('host_id',$this->host_id)
|
||||||
|
->whereIn('node_id',$o->pluck('node_id'))
|
||||||
|
->where('point_id','<>',0)
|
||||||
|
->get()
|
||||||
|
);
|
||||||
|
|
||||||
case self::NODE_ZC: // Zones, excluding RC's Nodes
|
case self::NODE_NC: // Nets
|
||||||
return $this->nodes_zone->diff($this
|
$o = self::active()
|
||||||
->nodes_zone
|
->where('zone_id',$this->zone_id)
|
||||||
->filter(function($item) { return $item->role_id === Address::NODE_RC; })
|
->where('region_id',$this->region_id)
|
||||||
->transform(function($item) { return $item->nodes_region; })
|
->where('host_id',$this->host_id);
|
||||||
->flatten());
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case self::NODE_RC: // Regions
|
||||||
|
$o = self::active()
|
||||||
|
->where('zone_id',$this->zone_id)
|
||||||
|
->where('region_id',$this->region_id);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case self::NODE_ZC: // Zone
|
||||||
|
$o = self::active()
|
||||||
|
->where('zone_id',$this->zone_id);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return new Collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Collection;
|
return $o
|
||||||
|
->where('id','<>',$this->id)
|
||||||
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find who we should forward mail onto, taking into account session details that we have
|
* Contrast to children(), this takes into account authentication details, and we route mail to this
|
||||||
|
* address (because we have session details) and it's children.
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
|
* @see self::children()
|
||||||
|
* @see self::uplink()
|
||||||
*/
|
*/
|
||||||
public function downlinks(): Collection
|
public function downlinks(): Collection
|
||||||
{
|
{
|
||||||
// We have no session data for this address, by definition it has no children
|
// We have no session data for this address, (and its not our address), by definition it has no children
|
||||||
if (! $this->is_hosted && (! our_address()->pluck('id')->contains($this->id)))
|
if (! $this->is_hosted && (! our_address()->pluck('id')->contains($this->id)))
|
||||||
return new Collection;
|
return new Collection;
|
||||||
|
|
||||||
// If this system is not marked to default route for this address
|
// If this system is not marked to default route for this address
|
||||||
if (! $this->is_default_route) {
|
if (! $this->is_default_route) {
|
||||||
$children = $this->children();
|
$children = $this->children()
|
||||||
|
->push($this);
|
||||||
|
|
||||||
// We route everything for this domain
|
// We route everything for this domain
|
||||||
} else {
|
} else {
|
||||||
@ -1016,28 +1049,17 @@ class Address extends Model
|
|||||||
|
|
||||||
// Exclude links and their children.
|
// Exclude links and their children.
|
||||||
$exclude = collect();
|
$exclude = collect();
|
||||||
foreach (our_nodes($this->zone->domain)->merge(our_address($this->zone->domain)) as $o) {
|
foreach (our_nodes($this->zone->domain)->diff([$this]) as $o) {
|
||||||
|
// We only exclude downlink children
|
||||||
|
if ($o->role_id < $this->role_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
// If this address is in our list, remove it and it's children
|
// If this address is in our list, remove it and it's children
|
||||||
if ($children->contains($o)) {
|
$exclude = $exclude->merge($o->children());
|
||||||
$exclude = $exclude->merge($o->children());
|
$exclude->push($o);
|
||||||
$exclude->push($o);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $children->filter(function($item) use ($exclude) { return ! $exclude->pluck('id')->contains($item->id);});
|
return $children->diff($exclude);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of all our nodes and their children
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Support\Collection
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function downstream(): \Illuminate\Support\Collection
|
|
||||||
{
|
|
||||||
return $this->downlinks()->transform(function($item) {
|
|
||||||
return $item->nodes()->push($item);
|
|
||||||
})->flatten();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1073,11 +1095,10 @@ class Address extends Model
|
|||||||
'origin:id,value',
|
'origin:id,value',
|
||||||
'echoarea:id,name,domain_id',
|
'echoarea:id,name,domain_id',
|
||||||
'echoarea.domain:id,name',
|
'echoarea.domain:id,name',
|
||||||
'fftn:id,zone_id,host_id,node_id,point_id',
|
'fftn:id,zone_id,region_id,host_id,node_id,point_id',
|
||||||
'fftn.zone:id,domain_id,zone_id',
|
'fftn.zone:id,domain_id,zone_id',
|
||||||
'fftn.zone.domain:id,name',
|
'fftn.zone.domain:id,name',
|
||||||
])
|
]);
|
||||||
->dontCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1097,7 +1118,7 @@ class Address extends Model
|
|||||||
->with([
|
->with([
|
||||||
'filearea:id,name,domain_id',
|
'filearea:id,name,domain_id',
|
||||||
'filearea.domain:id,name',
|
'filearea.domain:id,name',
|
||||||
'fftn:id,zone_id,host_id,node_id,point_id',
|
'fftn:id,zone_id,region_id,host_id,node_id,point_id',
|
||||||
'fftn.zone:id,domain_id,zone_id',
|
'fftn.zone:id,domain_id,zone_id',
|
||||||
'fftn.zone.domain:id,name',
|
'fftn.zone.domain:id,name',
|
||||||
])
|
])
|
||||||
@ -1137,7 +1158,7 @@ class Address extends Model
|
|||||||
$role = self::NODE_ZC;
|
$role = self::NODE_ZC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null($role))
|
if (isset($this->region_id) && is_null($role))
|
||||||
Log::alert(sprintf('%s:! Address ROLE [%d] could not be determined for [%s]',self::LOGKEY,($this->role & Address::NODE_ALL),$this->ftn));
|
Log::alert(sprintf('%s:! Address ROLE [%d] could not be determined for [%s]',self::LOGKEY,($this->role & Address::NODE_ALL),$this->ftn));
|
||||||
|
|
||||||
return $role;
|
return $role;
|
||||||
@ -1166,6 +1187,21 @@ class Address extends Model
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFiles(): Collection
|
||||||
|
{
|
||||||
|
if ($count=($num=$this->filesWaiting())->count()) {
|
||||||
|
Log::info(sprintf('%s:= Got [%d] files for [%s] for sending',self::LOGKEY,$count,$this->ftn));
|
||||||
|
|
||||||
|
// Limit to max messages
|
||||||
|
if ($count > $this->system->batch_files)
|
||||||
|
Log::notice(sprintf('%s:= Only sending [%d] files for [%s]',self::LOGKEY,$this->system->batch_files,$this->ftn));
|
||||||
|
|
||||||
|
return $num->take($this->system->batch_files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Collection;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get netmail for this node (including it's children)
|
* Get netmail for this node (including it's children)
|
||||||
*
|
*
|
||||||
@ -1231,8 +1267,8 @@ class Address extends Model
|
|||||||
// Addresses that our downstream of this address, except anybody that has session details with us
|
// Addresses that our downstream of this address, except anybody that has session details with us
|
||||||
$ours = our_nodes($this->zone->domain)->pluck('id');
|
$ours = our_nodes($this->zone->domain)->pluck('id');
|
||||||
|
|
||||||
$addresses = $this->downstream()
|
$addresses = $this->downlinks()
|
||||||
->filter(fn($item)=>! $ours->contains($item->id))
|
->filter(fn($item)=>(! $ours->contains($item->id)))
|
||||||
->merge($this->system->match($this->zone,Address::NODE_ALL));
|
->merge($this->system->match($this->zone,Address::NODE_ALL));
|
||||||
|
|
||||||
$netmails = $this
|
$netmails = $this
|
||||||
@ -1291,18 +1327,20 @@ class Address extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the immediate parent for this node.
|
* Find the immediate parent for this address, as per normal FTN routing ZC <- RC <- NC <- HUB <- Node <- Point
|
||||||
*
|
*
|
||||||
* @return Address|null
|
* @return Address|null
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
|
* @see self::children()
|
||||||
*/
|
*/
|
||||||
public function parent(): ?Address
|
public function parent(): ?Address
|
||||||
{
|
{
|
||||||
// If we are a point, our parent is the boss
|
// If we are a point, our parent is the boss
|
||||||
switch ($this->role_id) {
|
switch ($this->role_id) {
|
||||||
case self::NODE_POINT: // BOSS Node
|
case self::NODE_POINT: // BOSS Node
|
||||||
return Address::active()
|
return self::active()
|
||||||
->where('zone_id',$this->zone_id)
|
->where('zone_id',$this->zone_id)
|
||||||
|
->where('region_id',$this->region_id)
|
||||||
->where('host_id',$this->host_id)
|
->where('host_id',$this->host_id)
|
||||||
->where('node_id',$this->node_id)
|
->where('node_id',$this->node_id)
|
||||||
->where('point_id',0)
|
->where('point_id',0)
|
||||||
@ -1314,16 +1352,17 @@ class Address extends Model
|
|||||||
|
|
||||||
// Else fall through
|
// Else fall through
|
||||||
|
|
||||||
case self::NODE_HC: // RC
|
case self::NODE_HC: // NC
|
||||||
return Address::active()
|
return self::active()
|
||||||
->where('zone_id',$this->zone_id)
|
->where('zone_id',$this->zone_id)
|
||||||
|
->where('region_id',$this->region_id)
|
||||||
->where('host_id',$this->host_id)
|
->where('host_id',$this->host_id)
|
||||||
->where('node_id',0)
|
->where('node_id',0)
|
||||||
->where('point_id',0)
|
->where('point_id',0)
|
||||||
->single();
|
->single();
|
||||||
|
|
||||||
case self::NODE_NC: // RC
|
case self::NODE_NC: // RC
|
||||||
return Address::active()
|
return self::active()
|
||||||
->where('zone_id',$this->zone_id)
|
->where('zone_id',$this->zone_id)
|
||||||
->where('region_id',$this->region_id)
|
->where('region_id',$this->region_id)
|
||||||
->where('host_id',$this->region_id)
|
->where('host_id',$this->region_id)
|
||||||
@ -1332,7 +1371,7 @@ class Address extends Model
|
|||||||
->single();
|
->single();
|
||||||
|
|
||||||
case self::NODE_RC: // ZC
|
case self::NODE_RC: // ZC
|
||||||
return Address::active()
|
return self::active()
|
||||||
->where('zone_id',$this->zone_id)
|
->where('zone_id',$this->zone_id)
|
||||||
->where('region_id',0)
|
->where('region_id',0)
|
||||||
->where('node_id',0)
|
->where('node_id',0)
|
||||||
@ -1356,10 +1395,13 @@ class Address extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the appropriate parent for this address, taking into account who we have session information with
|
* Contrast to parent(), this takes into account authentication details, and we route mail to this
|
||||||
|
* address (because we have session details) with that uplink.
|
||||||
*
|
*
|
||||||
* @return Address|$this|null
|
* @return Address|$this|null
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
|
* @see self::parent()
|
||||||
|
* @see self::downlinks()
|
||||||
*/
|
*/
|
||||||
public function uplink(): ?Address
|
public function uplink(): ?Address
|
||||||
{
|
{
|
||||||
@ -1371,15 +1413,17 @@ class Address extends Model
|
|||||||
if ($this->is_hosted)
|
if ($this->is_hosted)
|
||||||
return $this;
|
return $this;
|
||||||
|
|
||||||
|
// Traverse up our parents until we have one with session details
|
||||||
if ($x=$this->parent()?->uplink()) {
|
if ($x=$this->parent()?->uplink()) {
|
||||||
return $x;
|
return $x;
|
||||||
|
|
||||||
|
// See if we have a node registered as the default route for this zone
|
||||||
} else {
|
} else {
|
||||||
$sz = SystemZone::whereIn('zone_id',$this->domain->zones->pluck('id'))
|
$sz = SystemZone::whereIn('zone_id',$this->domain->zones->pluck('id'))
|
||||||
->where('default',TRUE)
|
->where('default',TRUE)
|
||||||
->single();
|
->single();
|
||||||
|
|
||||||
return $sz?->system->addresses->sortBy('security')->last();
|
return $sz?->system->akas->sortBy('security')->last();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -289,7 +289,7 @@ final class Echomail extends Model implements Packet
|
|||||||
public function seenby()
|
public function seenby()
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Address::class,'echomail_seenby')
|
return $this->belongsToMany(Address::class,'echomail_seenby')
|
||||||
->select(['id','zone_id','host_id','node_id'])
|
->select(['addresses.id','zone_id','host_id','node_id'])
|
||||||
->withPivot(['export_at','sent_at','sent_pkt'])
|
->withPivot(['export_at','sent_at','sent_pkt'])
|
||||||
->dontCache()
|
->dontCache()
|
||||||
->FTN2DOrder();
|
->FTN2DOrder();
|
||||||
|
@ -32,6 +32,7 @@ class Setup extends Model
|
|||||||
public const O_DNS = 1<<3; /* List for DNS */
|
public const O_DNS = 1<<3; /* List for DNS */
|
||||||
public const O_HIDEAKA = 1<<4; /* Hide AKAs to different Zones */
|
public const O_HIDEAKA = 1<<4; /* Hide AKAs to different Zones */
|
||||||
|
|
||||||
|
public const MAX_BATCH_FILES = 5;
|
||||||
public const MAX_MSGS_PKT = 50;
|
public const MAX_MSGS_PKT = 50;
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
@ -68,6 +69,9 @@ class Setup extends Model
|
|||||||
case 'emsi_options':
|
case 'emsi_options':
|
||||||
return Arr::get($this->servers,str_replace('_','.',$key));
|
return Arr::get($this->servers,str_replace('_','.',$key));
|
||||||
|
|
||||||
|
case 'batch_files':
|
||||||
|
return Arr::get($this->options,$key,self::MAX_BATCH_FILES);
|
||||||
|
|
||||||
case 'msgs_pkt':
|
case 'msgs_pkt':
|
||||||
return Arr::get($this->options,$key,self::MAX_MSGS_PKT);
|
return Arr::get($this->options,$key,self::MAX_MSGS_PKT);
|
||||||
|
|
||||||
|
@ -184,21 +184,26 @@ class System extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBatchFilesAttribute(?int $val): int
|
||||||
|
{
|
||||||
|
return $val ?: Setup::findOrFail(config('app.id'))->batch_files;
|
||||||
|
}
|
||||||
|
|
||||||
public function getIsOwnedAttribute(): bool
|
public function getIsOwnedAttribute(): bool
|
||||||
{
|
{
|
||||||
return $this->users->count();
|
return $this->users->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPktMsgsAttribute(?int $val): int
|
|
||||||
{
|
|
||||||
return $val ?: Setup::findOrFail(config('app.id'))->msgs_pkt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLastSeenAttribute(): ?Carbon
|
public function getLastSeenAttribute(): ?Carbon
|
||||||
{
|
{
|
||||||
return $this->logs_recent->first()?->created_at;
|
return $this->logs_recent->first()?->created_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPktMsgsAttribute(?int $val): int
|
||||||
|
{
|
||||||
|
return $val ?: Setup::findOrFail(config('app.id'))->msgs_pkt;
|
||||||
|
}
|
||||||
|
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
|
|
||||||
public function addresses_common(): Collection
|
public function addresses_common(): Collection
|
||||||
|
@ -16,7 +16,7 @@ class CommandsProcessed extends Netmails
|
|||||||
private const LOGKEY = 'ACU';
|
private const LOGKEY = 'ACU';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reply to a areafix, commands unknown.
|
* Reply to a areafix commands.
|
||||||
*
|
*
|
||||||
* @param Netmail $mo
|
* @param Netmail $mo
|
||||||
* @param Collection $commands
|
* @param Collection $commands
|
||||||
|
@ -16,7 +16,7 @@ class Scan extends Netmails
|
|||||||
private const LOGKEY = 'ACS';
|
private const LOGKEY = 'ACS';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reply to a areafix, commands unknown.
|
* Notification on a (re)scan request.
|
||||||
*
|
*
|
||||||
* @param Collection $result
|
* @param Collection $result
|
||||||
*/
|
*/
|
||||||
|
67
app/Notifications/Netmails/Filefix/CommandsProcessed.php
Normal file
67
app/Notifications/Netmails/Filefix/CommandsProcessed.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Netmails\Filefix;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Notifications\Netmails;
|
||||||
|
use App\Models\Netmail;
|
||||||
|
use App\Traits\{MessagePath,PageTemplate};
|
||||||
|
|
||||||
|
class CommandsProcessed extends Netmails
|
||||||
|
{
|
||||||
|
use MessagePath,PageTemplate;
|
||||||
|
|
||||||
|
private const LOGKEY = 'ACU';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reply to a files commands.
|
||||||
|
*
|
||||||
|
* @param Netmail $mo
|
||||||
|
* @param Collection $commands
|
||||||
|
*/
|
||||||
|
public function __construct(private Netmail $mo,private Collection $commands)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return Netmail
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function toNetmail(object $notifiable): Netmail
|
||||||
|
{
|
||||||
|
$o = $this->setupNetmail($notifiable);
|
||||||
|
$ao = $notifiable->routeNotificationFor(static::via);
|
||||||
|
|
||||||
|
Log::info(sprintf('%s:+ Responding to filefix for a node [%s] COMMANDS PROCESSED',self::LOGKEY,$ao->ftn));
|
||||||
|
|
||||||
|
$o->to = $this->mo->from;
|
||||||
|
$o->replyid = $this->mo->msgid;
|
||||||
|
$o->subject = 'Filefix - Result';
|
||||||
|
|
||||||
|
// Message
|
||||||
|
$msg = $this->page(FALSE,'Filefix');
|
||||||
|
|
||||||
|
$msg->addText("Your filefix request has been received, here is the result:\r\r");
|
||||||
|
|
||||||
|
foreach ($this->commands as $command) {
|
||||||
|
$msg->addText("$command\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg->addText("\r");
|
||||||
|
|
||||||
|
$msg->addText($this->message_path($this->mo));
|
||||||
|
|
||||||
|
$o->msg = $msg->render();
|
||||||
|
$o->set_tagline = 'Why did the robot cross the road? The chicken programmed it.';
|
||||||
|
|
||||||
|
$o->save();
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
}
|
103
app/Notifications/Netmails/Filefix/Filelist.php
Normal file
103
app/Notifications/Netmails/Filefix/Filelist.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Netmails\Filefix;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Notifications\Netmails;
|
||||||
|
use App\Models\{Filearea,Netmail};
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use App\Traits\{MessagePath,PageTemplate};
|
||||||
|
|
||||||
|
class Filelist extends Netmails
|
||||||
|
{
|
||||||
|
use MessagePath,PageTemplate;
|
||||||
|
|
||||||
|
private const LOGKEY = 'FCL';
|
||||||
|
|
||||||
|
private Filearea $fa;
|
||||||
|
private int $days;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reply to a filefix FILELIST commands.
|
||||||
|
*
|
||||||
|
* @param Filearea $fa
|
||||||
|
* @param int $days
|
||||||
|
*/
|
||||||
|
public function __construct(Netmail $mo,Filearea $fa,int $days=30)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->mo = $mo->withoutRelations();
|
||||||
|
$this->fa = $fa->withoutRelations();
|
||||||
|
$this->days = $days;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return Netmail
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function toNetmail(object $notifiable): Netmail
|
||||||
|
{
|
||||||
|
$o = $this->setupNetmail($notifiable);
|
||||||
|
$ao = $notifiable->routeNotificationFor(static::via);
|
||||||
|
|
||||||
|
Log::info(sprintf('%s:+ Responding to filefix [%s] FILE LIST processed',self::LOGKEY,$ao->ftn));
|
||||||
|
|
||||||
|
$o->to = $this->mo->from;
|
||||||
|
$o->replyid = $this->mo->msgid;
|
||||||
|
$o->subject = 'Filefix - File List';
|
||||||
|
|
||||||
|
// Message
|
||||||
|
$msg = $this->page(FALSE,'Filefix');
|
||||||
|
|
||||||
|
$msg->addText(sprintf("Filearea [%s] has the following files in the last %d days:\r\r",$this->fa->name,$this->days));
|
||||||
|
|
||||||
|
$files = $this->fa
|
||||||
|
->files()
|
||||||
|
->orderBy('datetime')
|
||||||
|
->where('datetime','>',Carbon::now()->subDays($this->days)->startOfDay());
|
||||||
|
|
||||||
|
if ($files->count()) {
|
||||||
|
$msg->addText(sprintf(":-%s-:-%s-:-%s-:\r",
|
||||||
|
str_repeat('-',15),
|
||||||
|
str_repeat('-',44),
|
||||||
|
str_repeat('-',8),
|
||||||
|
));
|
||||||
|
$msg->addText(sprintf(": %-15s : %-44s : %8s :\r",'FILE','DESCRIPTION','SIZE(mb)'));
|
||||||
|
$msg->addText(sprintf(":-%s-:-%s-:-%s-:\r",
|
||||||
|
str_repeat('-',15),
|
||||||
|
str_repeat('-',44),
|
||||||
|
str_repeat('-',8),
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach ($files->get() as $fo) {
|
||||||
|
$msg->addText(sprintf(": %-15s : %-44s : %8s :\r",
|
||||||
|
$fo->name,
|
||||||
|
Str::limit($fo->desc,44-3),
|
||||||
|
number_format($fo->size/1024/1024,3),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg->addText(sprintf(":-%s-:-%s-:-%s-:\r",
|
||||||
|
str_repeat('-',15),
|
||||||
|
str_repeat('-',44),
|
||||||
|
str_repeat('-',8),
|
||||||
|
));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$msg->addText(sprintf('No files in [%s]',$this->fa->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
$o->msg = $msg->render();
|
||||||
|
$o->set_tagline = 'Why did the robot cross the road? The chicken programmed it.';
|
||||||
|
|
||||||
|
$o->save();
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
}
|
68
app/Notifications/Netmails/Filefix/Scan.php
Normal file
68
app/Notifications/Netmails/Filefix/Scan.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Netmails\Filefix;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Notifications\Netmails;
|
||||||
|
use App\Models\Netmail;
|
||||||
|
use App\Traits\{MessagePath,PageTemplate};
|
||||||
|
|
||||||
|
class Scan extends Netmails
|
||||||
|
{
|
||||||
|
use MessagePath,PageTemplate;
|
||||||
|
|
||||||
|
private const LOGKEY = 'FCS';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification on a (re)scan request.
|
||||||
|
*
|
||||||
|
* @param Collection $result
|
||||||
|
*/
|
||||||
|
public function __construct(private Collection $result)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return Netmail
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function toNetmail(object $notifiable): Netmail
|
||||||
|
{
|
||||||
|
$o = $this->setupNetmail($notifiable);
|
||||||
|
$ao = $notifiable->routeNotificationFor(static::via);
|
||||||
|
|
||||||
|
Log::info(sprintf('%s:+ Responding to filefix for a node [%s] SCAN processed',self::LOGKEY,$ao->ftn));
|
||||||
|
|
||||||
|
$o->subject = 'Filefix - Scan Results';
|
||||||
|
|
||||||
|
// Message
|
||||||
|
$msg = $this->page(FALSE,'Filefix');
|
||||||
|
|
||||||
|
$msg->addText("A filefix (re)Scan has completed:\r\r");
|
||||||
|
|
||||||
|
$msg->addText(sprintf("Area: %s, Queued: %d, Skipped: %d\r\r",
|
||||||
|
$this->result->get('area'),
|
||||||
|
$this->result->get('queued'),
|
||||||
|
$this->result->get('skipped'),
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($x=$this->result->get('earliest'))
|
||||||
|
$msg->addText(sprintf("The earliest file being sent: %s.\r",$x));
|
||||||
|
|
||||||
|
if (($x=$this->result->get('latest')) && ($this->result->get('earliest') !== $x))
|
||||||
|
$msg->addText(sprintf("The latest file being sent: %s.\r",$x));
|
||||||
|
|
||||||
|
$o->msg = $msg->render();
|
||||||
|
$o->set_tagline = 'Why did the chicken cross the road? The robot programmed it.';
|
||||||
|
|
||||||
|
$o->save();
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
}
|
@ -2,42 +2,39 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our testing heirarchy.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
use App\Models\{Address, Domain, Setup, System, Zone};
|
use App\Models\{Address,Domain,Setup,System,Zone};
|
||||||
|
|
||||||
class TestNodeHierarchy extends Seeder
|
class TestNodeHierarchy extends Seeder
|
||||||
{
|
{
|
||||||
public const DEBUG=FALSE;
|
public const DEBUG = TRUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the database seeds.
|
* Run the database seeds.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
* @throws \Exception
|
||||||
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
DB::table('domains')
|
foreach (['a','b','c','d','e','f'] as $domain) {
|
||||||
->insert([
|
DB::table('domains')
|
||||||
'name'=>'a',
|
->insert([
|
||||||
'active'=>TRUE,
|
'name'=>$domain,
|
||||||
'public'=>TRUE,
|
'active'=>TRUE,
|
||||||
'created_at'=>Carbon::now(),
|
'public'=>TRUE,
|
||||||
'updated_at'=>Carbon::now(),
|
'created_at'=>Carbon::now(),
|
||||||
]);
|
'updated_at'=>Carbon::now(),
|
||||||
|
]);
|
||||||
|
|
||||||
DB::table('domains')
|
|
||||||
->insert([
|
|
||||||
'name'=>'b',
|
|
||||||
'active'=>TRUE,
|
|
||||||
'public'=>TRUE,
|
|
||||||
'created_at'=>Carbon::now(),
|
|
||||||
'updated_at'=>Carbon::now(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
foreach (['a','b'] as $domain) {
|
|
||||||
$do = Domain::where('name',$domain)->sole();
|
$do = Domain::where('name',$domain)->sole();
|
||||||
$this->hierarchy($do,100);
|
$this->hierarchy($do,100);
|
||||||
$this->hierarchy($do,101);
|
$this->hierarchy($do,101);
|
||||||
@ -45,9 +42,38 @@ class TestNodeHierarchy extends Seeder
|
|||||||
|
|
||||||
// Configure my addresses
|
// Configure my addresses
|
||||||
$so = Setup::findOrFail(config('app.id'));
|
$so = Setup::findOrFail(config('app.id'));
|
||||||
|
|
||||||
|
// ZC 100:0/0@a
|
||||||
$ao = Address::findFTN('100:0/0@a');
|
$ao = Address::findFTN('100:0/0@a');
|
||||||
$so->system_id = $ao->system_id;
|
$ao->system_id = $so->system_id;
|
||||||
$so->save();
|
$ao->save();
|
||||||
|
|
||||||
|
// RC 100:1/0@b
|
||||||
|
$ao = Address::findFTN('100:1/0@b');
|
||||||
|
$ao->system_id = $so->system_id;
|
||||||
|
$ao->save();
|
||||||
|
|
||||||
|
// NC 100:20/0@c
|
||||||
|
$ao = Address::findFTN('100:20/0@c');
|
||||||
|
$ao->system_id = $so->system_id;
|
||||||
|
$ao->save();
|
||||||
|
|
||||||
|
// HUB 100:30/100@d
|
||||||
|
$ao = Address::findFTN('100:30/100@d');
|
||||||
|
$ao->system_id = $so->system_id;
|
||||||
|
$ao->save();
|
||||||
|
|
||||||
|
// NODE 100:40/101@e
|
||||||
|
$ao = Address::findFTN('100:40/101@e');
|
||||||
|
$ao->system_id = $so->system_id;
|
||||||
|
$ao->save();
|
||||||
|
|
||||||
|
// POINT 100:50/101.3277@f
|
||||||
|
$ao = Address::createFTN('100:50/101.3277@f',$so->system);
|
||||||
|
|
||||||
|
$so->system->name = 'Clearing Houz TEST';
|
||||||
|
$so->system->address = 'localhost';
|
||||||
|
$so->system->save();
|
||||||
|
|
||||||
// Add file area
|
// Add file area
|
||||||
DB::table('fileareas')
|
DB::table('fileareas')
|
||||||
@ -66,9 +92,7 @@ class TestNodeHierarchy extends Seeder
|
|||||||
|
|
||||||
private function hierarchy(Domain $domain,int $zoneid)
|
private function hierarchy(Domain $domain,int $zoneid)
|
||||||
{
|
{
|
||||||
$hosts = [1,2,3,4,5];
|
$levels = [1,2,3,4,5];
|
||||||
$hubs = [10,20,30,40,50];
|
|
||||||
$nodes = [100,200,300,400,500];
|
|
||||||
$hubnodes = [-2,-1,+1,+2,+3];
|
$hubnodes = [-2,-1,+1,+2,+3];
|
||||||
|
|
||||||
$so = $this->system(sprintf('ZC %s-%s',$domain->name,$zoneid));
|
$so = $this->system(sprintf('ZC %s-%s',$domain->name,$zoneid));
|
||||||
@ -85,185 +109,196 @@ class TestNodeHierarchy extends Seeder
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$zo = Zone::where('zone_id',$zoneid)->where('domain_id',$domain->id)->sole();
|
$zo = Zone::where('zone_id',$zoneid)->where('domain_id',$domain->id)->sole();
|
||||||
if (self::DEBUG)
|
|
||||||
dump(['zo'=>$zo->zone_id,'rid'=>0,'hid'=>0,'nid'=>0]);
|
|
||||||
|
|
||||||
// ZC
|
if (self::DEBUG)
|
||||||
|
printf("- ZC %d:%d/%d.%d@%s\n",$zo->zone_id,0,0,0,$domain->name);
|
||||||
|
|
||||||
|
$region_id = 0;
|
||||||
|
// ZC Address
|
||||||
DB::table('addresses')
|
DB::table('addresses')
|
||||||
->insert([
|
->insert([
|
||||||
'zone_id'=>$zo->id,
|
'zone_id'=>$zo->id,
|
||||||
'active'=>TRUE,
|
'active'=>TRUE,
|
||||||
'validated'=>TRUE,
|
'region_id'=>$region_id,
|
||||||
'region_id'=>0,
|
'host_id'=>$region_id,
|
||||||
'host_id'=>0,
|
|
||||||
'node_id'=>0,
|
'node_id'=>0,
|
||||||
'point_id'=>0,
|
'point_id'=>0,
|
||||||
'system_id'=>$so->id,
|
'system_id'=>$so->id,
|
||||||
'role'=>Address::NODE_ZC,
|
|
||||||
'created_at'=>Carbon::now(),
|
'created_at'=>Carbon::now(),
|
||||||
'updated_at'=>Carbon::now(),
|
'updated_at'=>Carbon::now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// ZC Nodes
|
// ZC Nodes
|
||||||
foreach ($nodes as $nid) {
|
foreach ($hubnodes as $hnid) {
|
||||||
if (self::DEBUG)
|
$host_id = $region_id*100+$hnid+3;
|
||||||
dump(['rid'=>$zo->zone_id,'hid'=>$zo->zone_id,'nid'=>$nid]);
|
|
||||||
|
|
||||||
$so = $this->system(sprintf('ZC Node 0/%d',$nid));
|
if (self::DEBUG)
|
||||||
|
printf(" - NODE %d:%d/%d.%d@%s\n",$zo->zone_id,$region_id,$host_id,0,$domain->name);
|
||||||
|
|
||||||
|
$so = $this->system(sprintf('ZC Node 0/%d',$host_id));
|
||||||
DB::table('addresses')
|
DB::table('addresses')
|
||||||
->insert([
|
->insert([
|
||||||
'zone_id'=>$zo->id,
|
'zone_id'=>$zo->id,
|
||||||
'active'=>TRUE,
|
'active'=>TRUE,
|
||||||
'validated'=>TRUE,
|
'region_id'=>$region_id,
|
||||||
'region_id'=>0,
|
'host_id'=>$region_id,
|
||||||
'host_id'=>0,
|
'node_id'=>$host_id,
|
||||||
'node_id'=>$nid,
|
|
||||||
'point_id'=>0,
|
'point_id'=>0,
|
||||||
'system_id'=>$so->id,
|
'system_id'=>$so->id,
|
||||||
'role'=>Address::NODE_NN,
|
|
||||||
'created_at'=>Carbon::now(),
|
'created_at'=>Carbon::now(),
|
||||||
'updated_at'=>Carbon::now(),
|
'updated_at'=>Carbon::now(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self::DEBUG)
|
// RC
|
||||||
dump(['end'=>'nodes top']);
|
foreach ($levels as $region_id) {
|
||||||
|
|
||||||
// Regions
|
|
||||||
foreach ($hosts as $rid) {
|
|
||||||
$hostid = $rid;
|
|
||||||
if (self::DEBUG)
|
if (self::DEBUG)
|
||||||
dump(['rid'=>$rid,'hid'=>$hostid,'nid'=>0]);
|
printf(" - RC %d:%d/%d.%d@%s\n",$zo->zone_id,$region_id,0,0,$domain->name);
|
||||||
|
|
||||||
$so = $this->system(sprintf('Region %03d:%03d/%03d.0@%s',$zoneid,$rid,0,$domain->name));
|
$so = $this->system(sprintf('RC %03d:%03d/%03d.0@%s',$zoneid,$region_id,0,$domain->name));
|
||||||
DB::table('addresses')
|
DB::table('addresses')
|
||||||
->insert([
|
->insert([
|
||||||
'zone_id'=>$zo->id,
|
'zone_id'=>$zo->id,
|
||||||
'active'=>TRUE,
|
'active'=>TRUE,
|
||||||
'validated'=>TRUE,
|
'region_id'=>$region_id,
|
||||||
'region_id'=>$rid,
|
'host_id'=>$region_id,
|
||||||
'host_id'=>$rid,
|
|
||||||
'node_id'=>0,
|
'node_id'=>0,
|
||||||
'point_id'=>0,
|
'point_id'=>0,
|
||||||
'system_id'=>$so->id,
|
'system_id'=>$so->id,
|
||||||
'role'=>Address::NODE_RC,
|
|
||||||
'created_at'=>Carbon::now(),
|
'created_at'=>Carbon::now(),
|
||||||
'updated_at'=>Carbon::now(),
|
'updated_at'=>Carbon::now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// RC Nodes
|
// RC Nodes
|
||||||
foreach ($nodes as $nid) {
|
foreach ($hubnodes as $hnid) {
|
||||||
if (self::DEBUG)
|
$host_id = $hnid+3;
|
||||||
dump(['rid'=>$rid,'hid'=>$hostid,'nid'=>$nid]);
|
|
||||||
|
|
||||||
$so = $this->system(sprintf('RC Node %d/%d',$rid,$nid));
|
if (self::DEBUG)
|
||||||
|
printf(" - NODE %d:%d/%d.%d@%s\n",$zo->zone_id,$region_id,$host_id,0,$domain->name);
|
||||||
|
|
||||||
|
$so = $this->system(sprintf('RC Node %d/%d',$region_id,$host_id));
|
||||||
DB::table('addresses')
|
DB::table('addresses')
|
||||||
->insert([
|
->insert([
|
||||||
'zone_id'=>$zo->id,
|
'zone_id'=>$zo->id,
|
||||||
'active'=>TRUE,
|
'active'=>TRUE,
|
||||||
'validated'=>TRUE,
|
'region_id'=>$region_id,
|
||||||
'region_id'=>$rid,
|
'host_id'=>$region_id,
|
||||||
'host_id'=>$rid,
|
'node_id'=>$host_id,
|
||||||
'node_id'=>$nid,
|
|
||||||
'point_id'=>0,
|
'point_id'=>0,
|
||||||
'system_id'=>$so->id,
|
'system_id'=>$so->id,
|
||||||
'role'=>Address::NODE_NN,
|
|
||||||
'created_at'=>Carbon::now(),
|
'created_at'=>Carbon::now(),
|
||||||
'updated_at'=>Carbon::now(),
|
'updated_at'=>Carbon::now(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if (self::DEBUG)
|
|
||||||
dump(['end'=>'NODES regions']);
|
|
||||||
|
|
||||||
// Hosts
|
// NC
|
||||||
foreach ($hosts as $rrid) {
|
foreach ($levels as $ncid) {
|
||||||
$hostid = $rid*10+$rrid-1;
|
$net_id = $region_id*10+$ncid-1;
|
||||||
if (self::DEBUG)
|
if (self::DEBUG)
|
||||||
dump(['rid'=>$rid,'hid'=>$hostid,'nid'=>0]);
|
printf(" - NC %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,0,0,$domain->name);
|
||||||
|
|
||||||
$so = $this->system(sprintf('Host %d:%d/0 (R%d)',$zoneid,$hostid,$rid));
|
|
||||||
|
|
||||||
|
$so = $this->system(sprintf('NC %d:%d/0 (R%d)',$zo->zone_id,$net_id,$region_id));
|
||||||
DB::table('addresses')
|
DB::table('addresses')
|
||||||
->insert([
|
->insert([
|
||||||
'zone_id'=>$zo->id,
|
'zone_id'=>$zo->id,
|
||||||
'active'=>TRUE,
|
'active'=>TRUE,
|
||||||
'validated'=>TRUE,
|
'region_id'=>$region_id,
|
||||||
'region_id'=>$rid,
|
'host_id'=>$net_id,
|
||||||
'host_id'=>$hostid,
|
|
||||||
'node_id'=>0,
|
'node_id'=>0,
|
||||||
'point_id'=>0,
|
'point_id'=>0,
|
||||||
'system_id'=>$so->id,
|
'system_id'=>$so->id,
|
||||||
'role'=>Address::NODE_NC,
|
|
||||||
'created_at'=>Carbon::now(),
|
'created_at'=>Carbon::now(),
|
||||||
'updated_at'=>Carbon::now(),
|
'updated_at'=>Carbon::now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Nodes
|
// NC Nodes
|
||||||
foreach ($nodes as $nid) {
|
foreach ($hubnodes as $hnid) {
|
||||||
if (self::DEBUG)
|
$host_id = $hnid+3;
|
||||||
dump(['rid'=>$rid,'hid'=>$hostid,'nid'=>$nid]);
|
|
||||||
|
|
||||||
$so = $this->system(sprintf('Host Node %d/%d (R%d)',$hostid,$nid,$rid));
|
if (self::DEBUG)
|
||||||
|
printf(" - NODE %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,$host_id,0,$domain->name);
|
||||||
|
|
||||||
|
$so = $this->system(sprintf('NC Node %d/%d (R%d)',$net_id,$host_id,$region_id));
|
||||||
DB::table('addresses')
|
DB::table('addresses')
|
||||||
->insert([
|
->insert([
|
||||||
'zone_id'=>$zo->id,
|
'zone_id'=>$zo->id,
|
||||||
'active'=>TRUE,
|
'active'=>TRUE,
|
||||||
'validated'=>TRUE,
|
'region_id'=>$region_id,
|
||||||
'region_id'=>$rid,
|
'host_id'=>$net_id,
|
||||||
'host_id'=>$hostid,
|
'node_id'=>$host_id,
|
||||||
'node_id'=>$nid,
|
|
||||||
'point_id'=>0,
|
'point_id'=>0,
|
||||||
'system_id'=>$so->id,
|
'system_id'=>$so->id,
|
||||||
'role'=>Address::NODE_NN,
|
|
||||||
'created_at'=>Carbon::now(),
|
'created_at'=>Carbon::now(),
|
||||||
'updated_at'=>Carbon::now(),
|
'updated_at'=>Carbon::now(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hubs
|
// Hubs
|
||||||
foreach ($hubs as $bid) {
|
foreach ($levels as $hbid) {
|
||||||
$so = $this->system(sprintf('HUB %d/%d (R%d)',$hostid,$bid,$rid));
|
$host_id = $hbid*100;
|
||||||
|
|
||||||
|
if (self::DEBUG)
|
||||||
|
printf(" - HUB %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,$host_id,0,$domain->name);
|
||||||
|
|
||||||
|
$so = $this->system(sprintf('HUB %d/%d (R%d)',$net_id,$host_id,$region_id));
|
||||||
$hub = new Address;
|
$hub = new Address;
|
||||||
$hub->zone_id = $zo->id;
|
$hub->zone_id = $zo->id;
|
||||||
$hub->active = TRUE;
|
$hub->active = TRUE;
|
||||||
$hub->region_id = $rid;
|
$hub->region_id = $region_id;
|
||||||
$hub->host_id = $hostid;
|
$hub->host_id = $net_id;
|
||||||
$hub->node_id = $bid;
|
$hub->node_id = $host_id;
|
||||||
$hub->point_id = 0;
|
$hub->point_id = 0;
|
||||||
$hub->system_id = $so->id;
|
$hub->system_id = $so->id;
|
||||||
$hub->role = Address::NODE_HC;
|
|
||||||
$hub->created_at = Carbon::now();
|
$hub->created_at = Carbon::now();
|
||||||
$hub->updated_at = Carbon::now();
|
$hub->updated_at = Carbon::now();
|
||||||
$hub->save();
|
$hub->save();
|
||||||
|
|
||||||
// Nodes
|
// HUB Nodes
|
||||||
foreach ($hubnodes as $nid) {
|
foreach ($hubnodes as $nid) {
|
||||||
$nodeid = $bid+$nid;
|
$host_id = $hub->node_id+$nid;
|
||||||
$so = $this->system(sprintf('Hub Node %d/%d (R%d/H%d)',$hostid,$nodeid,$rid,$hub->node_id));
|
|
||||||
|
if (self::DEBUG)
|
||||||
|
printf(" - NODE %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,$host_id,0,$domain->name);
|
||||||
|
|
||||||
|
$so = $this->system(sprintf('Hub Node %d/%d (R%d/H%d)',$net_id,$host_id,$region_id,$hub->node_id));
|
||||||
DB::table('addresses')
|
DB::table('addresses')
|
||||||
->insert([
|
->insert([
|
||||||
'zone_id'=>$zo->id,
|
'zone_id'=>$zo->id,
|
||||||
'active'=>TRUE,
|
'active'=>TRUE,
|
||||||
'validated'=>TRUE,
|
'region_id'=>$region_id,
|
||||||
'region_id'=>$rid,
|
'host_id'=>$net_id,
|
||||||
'host_id'=>$hostid,
|
'node_id'=>$host_id,
|
||||||
'node_id'=>$nodeid,
|
|
||||||
'point_id'=>0,
|
'point_id'=>0,
|
||||||
'system_id'=>$so->id,
|
'system_id'=>$so->id,
|
||||||
'hub_id'=>$hub->id,
|
'hub_id'=>$hub->id,
|
||||||
'role'=>Address::NODE_NN,
|
|
||||||
'created_at'=>Carbon::now(),
|
'created_at'=>Carbon::now(),
|
||||||
'updated_at'=>Carbon::now(),
|
'updated_at'=>Carbon::now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
foreach ($hubnodes as $nid) {
|
||||||
|
$point_id = $nid+3;
|
||||||
|
|
||||||
|
if (self::DEBUG)
|
||||||
|
printf(" - POINT %d:%d/%d.%d@%s\n",$zo->zone_id,$net_id,$host_id,$point_id,$domain->name);
|
||||||
|
|
||||||
|
$so = $this->system(sprintf('Node Point %d/%d.%d (R%d/H%d)',$net_id,$host_id,$point_id,$region_id,$hub->node_id));
|
||||||
|
DB::table('addresses')
|
||||||
|
->insert([
|
||||||
|
'zone_id'=>$zo->id,
|
||||||
|
'active'=>TRUE,
|
||||||
|
'region_id'=>$region_id,
|
||||||
|
'host_id'=>$net_id,
|
||||||
|
'node_id'=>$host_id,
|
||||||
|
'point_id'=>$point_id,
|
||||||
|
'system_id'=>$so->id,
|
||||||
|
'created_at'=>Carbon::now(),
|
||||||
|
'updated_at'=>Carbon::now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self::DEBUG)
|
|
||||||
dump(['end'=>'NODES normal']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self::DEBUG)
|
|
||||||
dump(['end'=>'heirarchy']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function system(string $name): System
|
private function system(string $name): System
|
||||||
@ -275,8 +310,9 @@ class TestNodeHierarchy extends Seeder
|
|||||||
$o->active = TRUE;
|
$o->active = TRUE;
|
||||||
$o->created_at = Carbon::now();
|
$o->created_at = Carbon::now();
|
||||||
$o->updated_at = Carbon::now();
|
$o->updated_at = Carbon::now();
|
||||||
|
$o->address = 'myhostname';
|
||||||
$o->save();
|
$o->save();
|
||||||
|
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -109,7 +109,7 @@ class PacketTest extends TestCase
|
|||||||
$f = $this->mail_file('mail/018A-1702393055-78754407.pkt');
|
$f = $this->mail_file('mail/018A-1702393055-78754407.pkt');
|
||||||
|
|
||||||
foreach ($f as $packet) {
|
foreach ($f as $packet) {
|
||||||
$pkt = Packet::process($packet,$x=$f->itemName(),$f->itemSize(),$this->do);
|
$pkt = Packet::process($packet,$x=$f->itemName(),$f->itemSize());
|
||||||
|
|
||||||
$this->assertInstanceOf(Packet\FSC39::class,$pkt);
|
$this->assertInstanceOf(Packet\FSC39::class,$pkt);
|
||||||
$this->assertEquals('ABCDEFGH',$pkt->password);
|
$this->assertEquals('ABCDEFGH',$pkt->password);
|
||||||
@ -136,7 +136,7 @@ class PacketTest extends TestCase
|
|||||||
$f = $this->mail_file('mail/018A-1701955391-71c7a400.pkt');
|
$f = $this->mail_file('mail/018A-1701955391-71c7a400.pkt');
|
||||||
|
|
||||||
foreach ($f as $packet) {
|
foreach ($f as $packet) {
|
||||||
$pkt = Packet::process($packet,$x=$f->itemName(),$f->itemSize(),$this->do);
|
$pkt = Packet::process($packet,$x=$f->itemName(),$f->itemSize());
|
||||||
|
|
||||||
$this->assertInstanceOf(Packet\FSC39::class,$pkt);
|
$this->assertInstanceOf(Packet\FSC39::class,$pkt);
|
||||||
$this->assertEquals('ABCDEFGH',$pkt->password);
|
$this->assertEquals('ABCDEFGH',$pkt->password);
|
||||||
@ -163,7 +163,7 @@ class PacketTest extends TestCase
|
|||||||
$f = $this->mail_file('mail/0B39-1701919239-65713a06.pkt');
|
$f = $this->mail_file('mail/0B39-1701919239-65713a06.pkt');
|
||||||
|
|
||||||
foreach ($f as $packet) {
|
foreach ($f as $packet) {
|
||||||
$pkt = Packet::process($packet,$x=$f->itemName(),$f->itemSize(),$this->do);
|
$pkt = Packet::process($packet,$x=$f->itemName(),$f->itemSize());
|
||||||
|
|
||||||
$this->assertInstanceOf(Packet\FSC48::class,$pkt);
|
$this->assertInstanceOf(Packet\FSC48::class,$pkt);
|
||||||
$this->assertEquals('ABCDEFG#',$pkt->password);
|
$this->assertEquals('ABCDEFG#',$pkt->password);
|
||||||
@ -246,7 +246,7 @@ class PacketTest extends TestCase
|
|||||||
// This packet has an incorrect zone in the Origin
|
// This packet has an incorrect zone in the Origin
|
||||||
$f = $this->mail_file('mail/test_msgid_origin.pkt');
|
$f = $this->mail_file('mail/test_msgid_origin.pkt');
|
||||||
foreach ($f as $packet) {
|
foreach ($f as $packet) {
|
||||||
$pkt = Packet::process($packet,$f->itemName(),$f->itemSize(),$this->do);
|
$pkt = Packet::process($packet,$f->itemName(),$f->itemSize());
|
||||||
|
|
||||||
$this->assertInstanceOf(Packet\FSC39::class,$pkt);
|
$this->assertInstanceOf(Packet\FSC39::class,$pkt);
|
||||||
$this->assertEquals(1,$pkt->count());
|
$this->assertEquals(1,$pkt->count());
|
||||||
@ -278,7 +278,7 @@ class PacketTest extends TestCase
|
|||||||
// This packet has a SOH<char>SOH sequence
|
// This packet has a SOH<char>SOH sequence
|
||||||
$f = $this->mail_file('mail/test_binary_content-2.pkt');
|
$f = $this->mail_file('mail/test_binary_content-2.pkt');
|
||||||
foreach ($f as $packet) {
|
foreach ($f as $packet) {
|
||||||
$pkt = Packet::process($packet,$f->itemName(),$f->itemSize(),$this->do);
|
$pkt = Packet::process($packet,$f->itemName(),$f->itemSize());
|
||||||
|
|
||||||
$this->assertEquals(1,$pkt->count());
|
$this->assertEquals(1,$pkt->count());
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ namespace Tests\Feature;
|
|||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
use App\Models\{Address,Domain,Setup,System};
|
use App\Models\{Address,Domain,Setup,System};
|
||||||
@ -53,12 +54,17 @@ class RoutingTest extends TestCase
|
|||||||
{
|
{
|
||||||
use DatabaseTransactions;
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public const ZONE_ADDRS = 4061;
|
||||||
|
public const REGION_ADDRS = 811;
|
||||||
|
public const NET_ADDRS = 161;
|
||||||
|
public const HUB_ADDRS = 31;
|
||||||
|
public const NODE_ADDRS = 6;
|
||||||
|
|
||||||
private function zone(): Collection
|
private function zone(): Collection
|
||||||
{
|
{
|
||||||
//$this->seed(TestNodeHierarchy::class);
|
|
||||||
|
|
||||||
$do = Domain::where('name','a')->sole();
|
$do = Domain::where('name','a')->sole();
|
||||||
$zo = $do->zones->where('zone_id',100)->pop();
|
$zo = $do->zones->where('zone_id',100)->pop();
|
||||||
|
|
||||||
return $zo->addresses;
|
return $zo->addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,19 +76,31 @@ class RoutingTest extends TestCase
|
|||||||
|
|
||||||
private function session_rc(): void
|
private function session_rc(): void
|
||||||
{
|
{
|
||||||
$ao = Address::findFTN('100:1/0@a');
|
$ao = Address::findFTN('101:1/0@a');
|
||||||
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function session_nc(): void
|
private function session_nc(): void
|
||||||
{
|
{
|
||||||
$ao = Address::findFTN('100:10/0@a');
|
$ao = Address::findFTN('101:10/0@a');
|
||||||
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function session_hub(): void
|
private function session_hub(): void
|
||||||
{
|
{
|
||||||
$ao = Address::findFTN('100:10/20@a');
|
$ao = Address::findFTN('101:10/100@a');
|
||||||
|
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function session_node(): void
|
||||||
|
{
|
||||||
|
$ao = Address::findFTN('101:10/101@a');
|
||||||
|
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function session_point(): void
|
||||||
|
{
|
||||||
|
$ao = Address::findFTN('101:10/101.1@a');
|
||||||
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,14 +108,14 @@ class RoutingTest extends TestCase
|
|||||||
public function test_my_addresses()
|
public function test_my_addresses()
|
||||||
{
|
{
|
||||||
$ftns = our_address();
|
$ftns = our_address();
|
||||||
$this->assertEquals(1,$ftns->count());
|
$this->assertEquals(6,$ftns->count());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of active addresses in a Zone
|
// Get a list of active addresses in a Zone
|
||||||
public function test_zc_addresses()
|
public function test_zone_addresses()
|
||||||
{
|
{
|
||||||
$nodes = $this->zone();
|
$nodes = $this->zone();
|
||||||
$this->assertEquals(936,$nodes->count());
|
$this->assertEquals(self::ZONE_ADDRS,$nodes->count());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a ZC with no session details, and make sure it has no parent nor children
|
// Get a ZC with no session details, and make sure it has no parent nor children
|
||||||
@ -107,230 +125,302 @@ class RoutingTest extends TestCase
|
|||||||
$ao = Address::findFTN('101:0/0@a');
|
$ao = Address::findFTN('101:0/0@a');
|
||||||
|
|
||||||
$this->assertEquals($ao->role_id,Address::NODE_ZC);
|
$this->assertEquals($ao->role_id,Address::NODE_ZC);
|
||||||
$this->assertCount(0,$ao->downstream());
|
$this->assertCount(0,$ao->downlinks());
|
||||||
$this->assertNull($ao->uplink());
|
$this->assertNull($ao->uplink());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a ZC, make sure we are routing to all it's children
|
// If we have a ZC, make sure we are routing to all it's children
|
||||||
public function test_zc_session_children()
|
public function test_zc_session_children()
|
||||||
{
|
{
|
||||||
$this->session_zc();
|
|
||||||
|
|
||||||
$ao = Address::findFTN('101:0/0@a');
|
$ao = Address::findFTN('101:0/0@a');
|
||||||
$this->assertCount(935,$ao->downstream());
|
|
||||||
}
|
|
||||||
|
|
||||||
// An RC's parent should be the ZC, when we have session details with parent
|
// This is a ZC
|
||||||
public function test_zc_rc_node_parent()
|
$this->assertEquals($ao->role_name,'ZC');
|
||||||
{
|
$this->assertEquals(Address::NODE_ZC,$ao->role_id);
|
||||||
|
|
||||||
|
// Children
|
||||||
|
$this->assertCount(self::ZONE_ADDRS-1,$ao->children());
|
||||||
|
$this->assertCount(0,$ao->downlinks());
|
||||||
|
|
||||||
$this->session_zc();
|
$this->session_zc();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
$ao = Address::findFTN('101:1/0@a');
|
// Children
|
||||||
$this->assertEquals($ao->role_id,Address::NODE_RC);
|
$this->assertCount(self::ZONE_ADDRS,$ao->downlinks());
|
||||||
$this->assertEquals('101:0/0.0@a',$ao->uplink()->ftn);
|
}
|
||||||
|
|
||||||
|
// ZC uplink should be null, and the parent should be itself
|
||||||
|
public function test_zc_parent()
|
||||||
|
{
|
||||||
|
$ao = Address::findFTN('101:0/0@a');
|
||||||
|
|
||||||
|
// This uplink should also be null
|
||||||
|
$this->assertNull($ao->uplink()?->ftn);
|
||||||
|
|
||||||
|
$this->session_zc();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
|
// This parent should also be null
|
||||||
|
$this->assertNull($ao->parent()?->ftn);
|
||||||
|
|
||||||
|
// This uplink should be itself
|
||||||
|
$this->assertEquals($ao->ftn,$ao->uplink()?->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of active addresses in a Region
|
|
||||||
public function test_rc_session_children()
|
public function test_rc_session_children()
|
||||||
{
|
{
|
||||||
$this->session_rc();
|
$ao = Address::findFTN('101:1/0@a');
|
||||||
|
|
||||||
$ao = Address::findFTN('100:1/0@a');
|
// This is a RC
|
||||||
$this->assertCount(185,$ao->downstream());
|
$this->assertEquals($ao->role_name,'RC');
|
||||||
|
$this->assertEquals(Address::NODE_RC,$ao->role_id);
|
||||||
|
|
||||||
|
// Children
|
||||||
|
$this->assertCount(self::REGION_ADDRS-1,$ao->children());
|
||||||
|
$this->assertCount(0,$ao->downlinks());
|
||||||
|
|
||||||
|
$this->session_rc();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
|
// This is a ZC
|
||||||
|
$this->assertCount(self::REGION_ADDRS,$ao->downlinks());
|
||||||
}
|
}
|
||||||
|
|
||||||
// An RCs node still collects mail from the RC
|
|
||||||
public function test_rc_node_rc()
|
|
||||||
{
|
|
||||||
$this->session_rc();
|
|
||||||
|
|
||||||
// An RCs node should still be the RC
|
|
||||||
$ao = Address::findFTN('100:1/100@a');
|
|
||||||
$this->assertEquals($ao->role_id,Address::NODE_NN);
|
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->uplink()->ftn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// An NC collects mail for its children
|
|
||||||
public function test_rc_nc_node_rc()
|
|
||||||
{
|
|
||||||
$this->session_rc();
|
|
||||||
|
|
||||||
// A NCs parent should still be the RC
|
|
||||||
$ao = Address::findFTN('100:10/0@a');
|
|
||||||
$this->assertEquals($ao->role_id,Address::NODE_NC);
|
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->uplink()->ftn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Hub still collects mail from NC
|
|
||||||
public function test_rc_hub_node_nc()
|
|
||||||
{
|
|
||||||
$this->session_rc();
|
|
||||||
|
|
||||||
// A Hubs parent should still be the NC
|
|
||||||
$ao = Address::findFTN('100:10/20.0@a');
|
|
||||||
$this->assertEquals($ao->role_id,Address::NODE_HC);
|
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->uplink()->ftn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Hub's node still collects mail from Hub
|
|
||||||
public function test_rc_hub_node_hub()
|
|
||||||
{
|
|
||||||
$this->session_rc();
|
|
||||||
|
|
||||||
// A Hubs node should still be the Hub
|
|
||||||
$ao = Address::findFTN('100:10/22.0@a');
|
|
||||||
$this->assertEquals($ao->role_id,Address::NODE_NN);
|
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->uplink()->ftn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// An RCs parent is us even if we have session details for another RC
|
|
||||||
public function test_rc_parent()
|
public function test_rc_parent()
|
||||||
{
|
{
|
||||||
$this->session_rc();
|
$ao = Address::findFTN('101:1/0@a');
|
||||||
|
$o = Address::findFTN('101:0/0@a');
|
||||||
|
|
||||||
$ao = Address::findFTN('100:2/0@a');
|
// This uplink should also be null
|
||||||
$this->assertNull($ao->uplink()?->ftn);
|
$this->assertNull($ao->uplink()?->ftn);
|
||||||
}
|
|
||||||
|
|
||||||
// If we also have session details for an NC, then there are less RC nodes
|
|
||||||
public function test_rc_nc_session_children()
|
|
||||||
{
|
|
||||||
$this->session_rc();
|
$this->session_rc();
|
||||||
$this->session_nc();
|
$ao->refresh();
|
||||||
|
|
||||||
$ao = Address::findFTN('100:1/0@a');
|
// This parent should also be null
|
||||||
$this->assertCount(185-36,$ao->downstream());
|
$this->assertEquals($o->ftn,$ao->parent()?->ftn);
|
||||||
|
|
||||||
|
// This uplink should be itself
|
||||||
|
$this->assertEquals($ao->ftn,$ao->uplink()?->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we also have session details for an Hub, then there are less RC nodes
|
public function test_zc_rc_nodes()
|
||||||
public function test_rc_hub_session_children()
|
|
||||||
{
|
{
|
||||||
|
$this->session_zc();
|
||||||
$this->session_rc();
|
$this->session_rc();
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/20@a');
|
$ao = Address::findFTN('101:0/0@a');
|
||||||
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
$this->assertCount(self::ZONE_ADDRS-self::REGION_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
$ao = Address::findFTN('100:1/0@a');
|
$ao = Address::findFTN('101:1/0@a');
|
||||||
$this->assertCount(185,$ao->downstream());
|
$this->assertCount(self::REGION_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/22@a');
|
|
||||||
$this->assertEquals('100:10/20.0@a',$ao->uplink()->ftn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we also have session details for an Hub, then there are less RC nodes
|
|
||||||
public function test_rc_hub_session_child()
|
|
||||||
{
|
|
||||||
$this->session_hub();
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/22@a');
|
|
||||||
$this->assertEquals('100:10/20.0@a',$ao->uplink()->ftn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// When we have an RC with session details, we route to all its children
|
|
||||||
public function test_nc_session_children()
|
public function test_nc_session_children()
|
||||||
{
|
{
|
||||||
$this->session_nc();
|
$ao = Address::findFTN('101:10/0@a');
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/0@a');
|
// This is a NC
|
||||||
$this->assertCount(35,$ao->downstream());
|
$this->assertEquals($ao->role_name,'NC');
|
||||||
|
$this->assertEquals(Address::NODE_NC,$ao->role_id);
|
||||||
|
|
||||||
|
// Children
|
||||||
|
$this->assertCount(self::NET_ADDRS-1,$ao->children());
|
||||||
|
$this->assertCount(0,$ao->downlinks());
|
||||||
|
|
||||||
|
$this->session_nc();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
|
// This is a NC
|
||||||
|
$this->assertCount(self::NET_ADDRS,$ao->downlinks());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_complex_rc_nc_hc()
|
public function test_nc_parent()
|
||||||
{
|
{
|
||||||
$this->session_rc();
|
$ao = Address::findFTN('101:10/0@a');
|
||||||
$this->session_nc();
|
$o = Address::findFTN('101:1/0@a');
|
||||||
$this->session_hub();
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:1/100.0@a');
|
// This uplink should also be null
|
||||||
$this->assertCount(0,$ao->downstream());
|
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->uplink()->ftn);
|
|
||||||
|
|
||||||
// RC
|
|
||||||
$ao = Address::findFTN('100:1/0.0@a');
|
|
||||||
$this->assertCount(186-1-30-6,$ao->downstream());
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:11/0.0@a');
|
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->uplink()->ftn);
|
|
||||||
|
|
||||||
// NC
|
|
||||||
$ao = Address::findFTN('100:10/0.0@a');
|
|
||||||
$this->assertCount(36-1-6,$ao->downstream());
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/10.0@a');
|
|
||||||
$this->assertEquals('100:10/0.0@a',$ao->uplink()->ftn);
|
|
||||||
|
|
||||||
// HC
|
|
||||||
$ao = Address::findFTN('100:10/20.0@a');
|
|
||||||
$this->assertCount(6-1,$ao->downstream());
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/22.0@a');
|
|
||||||
$this->assertEquals('100:10/20.0@a',$ao->uplink()->ftn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function test_complex_rc_nc_hc_us()
|
|
||||||
{
|
|
||||||
Cache::forget('so');
|
|
||||||
$setup = Setup::findOrFail(config('app.id'));
|
|
||||||
$ao = Address::findFTN('100:10/0.0@a');
|
|
||||||
$setup->system_id = $ao->system_id;
|
|
||||||
$setup->save();
|
|
||||||
$this->assertEquals('100:10/0.0@a',our_address($ao)?->ftn);
|
|
||||||
|
|
||||||
$this->session_rc();
|
|
||||||
//$this->session_nc();
|
|
||||||
$this->session_hub();
|
|
||||||
$ao = Address::findFTN('100:11/0.0');
|
|
||||||
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:1/100.0@a');
|
|
||||||
$this->assertCount(0,$ao->downstream());
|
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->uplink()?->ftn);
|
|
||||||
|
|
||||||
// RC
|
|
||||||
$ao = Address::findFTN('100:1/0.0@a');
|
|
||||||
$this->assertCount(186-36-36-1,$ao->downstream());
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:11/0.0@a');
|
|
||||||
$this->assertEquals('100:11/0.0@a',$ao->uplink()->ftn);
|
|
||||||
|
|
||||||
// NC
|
|
||||||
$ao = Address::findFTN('100:10/0.0@a');
|
|
||||||
$this->assertCount(36-6-1,$ao->downstream());
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/10.0@a');
|
|
||||||
$this->assertNull($ao->uplink()?->ftn);
|
$this->assertNull($ao->uplink()?->ftn);
|
||||||
|
|
||||||
// HC
|
$this->session_nc();
|
||||||
$ao = Address::findFTN('100:10/20.0@a');
|
$ao->refresh();
|
||||||
$this->assertCount(6-1,$ao->downstream());
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/22.0@a');
|
// This parent should also be null
|
||||||
$this->assertEquals('100:10/20.0@a',$ao->uplink()->ftn);
|
$this->assertEquals($o->ftn,$ao->parent()?->ftn);
|
||||||
Cache::forget('so');
|
|
||||||
|
// This uplink should be itself
|
||||||
|
$this->assertEquals($ao->ftn,$ao->uplink()?->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A points parent is the node, if we have traffic for a point and we have session details for the node
|
public function test_zc_rc_nc_nodes()
|
||||||
public function test_point_session_node()
|
|
||||||
{
|
{
|
||||||
//$this->session_hub();
|
$this->session_zc();
|
||||||
|
$this->session_rc();
|
||||||
|
$this->session_nc();
|
||||||
|
|
||||||
$so = new System;
|
$ao = Address::findFTN('101:0/0@a');
|
||||||
$so->name = 'Point System';
|
$this->assertCount(self::ZONE_ADDRS-self::REGION_ADDRS,$ao->downlinks());
|
||||||
$so->sysop = 'Point Sysop';
|
|
||||||
$so->location = 'Melbourne, AU';
|
|
||||||
$so->active = TRUE;
|
|
||||||
$so->save();
|
|
||||||
|
|
||||||
// Create a child
|
$ao = Address::findFTN('101:1/0@a');
|
||||||
$ao = Address::createFTN('100:10/21.2@a',$so);
|
$this->assertCount(self::REGION_ADDRS-self::NET_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/21.0@a');
|
$ao = Address::findFTN('101:10/0@a');
|
||||||
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
$this->assertCount(self::NET_ADDRS,$ao->downlinks());
|
||||||
|
}
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/21.2@a');
|
public function test_hub_session_children()
|
||||||
$this->assertEquals('100:10/21.0@a',$ao->uplink()?->ftn);
|
{
|
||||||
|
$ao = Address::findFTN('101:10/100@a');
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/21@a');
|
// This is a HUB
|
||||||
$this->assertCount(1,$ao->downstream());
|
$this->assertEquals($ao->role_name,'HUB');
|
||||||
|
$this->assertEquals(Address::NODE_HC,$ao->role_id);
|
||||||
|
|
||||||
|
// Children
|
||||||
|
$this->assertCount(self::HUB_ADDRS-1,$ao->children());
|
||||||
|
$this->assertCount(0,$ao->downlinks());
|
||||||
|
|
||||||
|
$this->session_hub();
|
||||||
|
$ao->refresh()->unsetRelations();
|
||||||
|
|
||||||
|
// This is a NC
|
||||||
|
$this->assertCount(self::HUB_ADDRS,$ao->downlinks());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_hub_parent()
|
||||||
|
{
|
||||||
|
$ao = Address::findFTN('101:10/100@a');
|
||||||
|
$o = Address::findFTN('101:10/0@a');
|
||||||
|
|
||||||
|
// This uplink should also be null
|
||||||
|
$this->assertNull($ao->uplink()?->ftn);
|
||||||
|
|
||||||
|
$this->session_hub();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
|
// This parent should also be null
|
||||||
|
$this->assertEquals($o->ftn,$ao->parent()?->ftn);
|
||||||
|
|
||||||
|
// This uplink should be itself
|
||||||
|
$this->assertEquals($ao->ftn,$ao->uplink()?->ftn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_zc_rc_nc_hub_nodes()
|
||||||
|
{
|
||||||
|
$this->session_zc();
|
||||||
|
$this->session_rc();
|
||||||
|
$this->session_nc();
|
||||||
|
$this->session_hub();
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:0/0@a');
|
||||||
|
$this->assertCount(self::ZONE_ADDRS-self::REGION_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:1/0@a');
|
||||||
|
$this->assertCount(self::REGION_ADDRS-self::NET_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:10/0@a');
|
||||||
|
$this->assertCount(self::NET_ADDRS-self::HUB_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:10/100@a');
|
||||||
|
$this->assertCount(self::HUB_ADDRS,$ao->downlinks());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_node_session_children()
|
||||||
|
{
|
||||||
|
$ao = Address::findFTN('101:10/101@a');
|
||||||
|
|
||||||
|
// This is a NC
|
||||||
|
$this->assertEquals($ao->role_name,'NODE');
|
||||||
|
$this->assertEquals(Address::NODE_NN,$ao->role_id);
|
||||||
|
|
||||||
|
// Children
|
||||||
|
$this->assertCount(self::NODE_ADDRS-1,$ao->children());
|
||||||
|
$this->assertCount(0,$ao->downlinks());
|
||||||
|
|
||||||
|
$this->session_node();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
|
// This is a NC
|
||||||
|
$this->assertCount(self::NODE_ADDRS,$ao->downlinks());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_node_parent()
|
||||||
|
{
|
||||||
|
$ao = Address::findFTN('101:10/101@a');
|
||||||
|
$o = Address::findFTN('101:10/100@a');
|
||||||
|
|
||||||
|
// This uplink should also be null
|
||||||
|
$this->assertNull($ao->uplink()?->ftn);
|
||||||
|
|
||||||
|
$this->session_node();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
|
// This parent should also be null
|
||||||
|
$this->assertEquals($o->ftn,$ao->parent()?->ftn);
|
||||||
|
|
||||||
|
// This uplink should be itself
|
||||||
|
$this->assertEquals($ao->ftn,$ao->uplink()?->ftn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_zc_rc_nc_hub_node_nodes()
|
||||||
|
{
|
||||||
|
$this->session_zc();
|
||||||
|
$this->session_rc();
|
||||||
|
$this->session_nc();
|
||||||
|
$this->session_hub();
|
||||||
|
$this->session_node();
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:0/0@a');
|
||||||
|
$this->assertCount(self::ZONE_ADDRS-self::REGION_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:1/0@a');
|
||||||
|
$this->assertCount(self::REGION_ADDRS-self::NET_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:10/0@a');
|
||||||
|
$this->assertCount(self::NET_ADDRS-self::HUB_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:10/100@a');
|
||||||
|
$this->assertCount(self::HUB_ADDRS-self::NODE_ADDRS,$ao->downlinks());
|
||||||
|
|
||||||
|
$ao = Address::findFTN('101:10/101@a');
|
||||||
|
$this->assertCount(self::NODE_ADDRS,$ao->downlinks());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_point_session_children()
|
||||||
|
{
|
||||||
|
$ao = Address::findFTN('101:10/101.1@a');
|
||||||
|
|
||||||
|
// This is a NC
|
||||||
|
$this->assertEquals($ao->role_name,'POINT');
|
||||||
|
$this->assertEquals(Address::NODE_POINT,$ao->role_id);
|
||||||
|
|
||||||
|
// Children
|
||||||
|
$this->assertCount(0,$ao->children());
|
||||||
|
$this->assertCount(0,$ao->downlinks());
|
||||||
|
|
||||||
|
$this->session_point();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
|
// This is a NC
|
||||||
|
$this->assertCount(1,$ao->downlinks());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_point_parent()
|
||||||
|
{
|
||||||
|
$ao = Address::findFTN('101:10/101.1@a');
|
||||||
|
$o = Address::findFTN('101:10/101@a');
|
||||||
|
|
||||||
|
// This uplink should also be null
|
||||||
|
$this->assertNull($ao->uplink()?->ftn);
|
||||||
|
|
||||||
|
$this->session_point();
|
||||||
|
$ao->refresh();
|
||||||
|
|
||||||
|
// This parent should also be null
|
||||||
|
$this->assertEquals($o->ftn,$ao->parent()?->ftn);
|
||||||
|
|
||||||
|
// This uplink should be itself
|
||||||
|
$this->assertEquals($ao->ftn,$ao->uplink()?->ftn);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -131,7 +131,7 @@ class TicProcessingTest extends TestCase
|
|||||||
$file->refresh();
|
$file->refresh();
|
||||||
$this->assertEquals('100:1/0',$file->fftn->ftn3d);
|
$this->assertEquals('100:1/0',$file->fftn->ftn3d);
|
||||||
$this->assertEquals('100:10/11',$file->origin->ftn3d);
|
$this->assertEquals('100:10/11',$file->origin->ftn3d);
|
||||||
$this->assertCount(12,$file->seenby);
|
$this->assertCount(7,$file->seenby);
|
||||||
$this->assertCount(4,$file->path);
|
$this->assertCount(4,$file->path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user