Added system polling
This commit is contained in:
parent
c23b5ebfc2
commit
4e44e2e266
@ -28,7 +28,9 @@ abstract class Protocol
|
|||||||
|
|
||||||
// Our sessions Types
|
// Our sessions Types
|
||||||
public const SESSION_AUTO = 0;
|
public const SESSION_AUTO = 0;
|
||||||
|
/** @deprecate Use mailers:class */
|
||||||
public const SESSION_EMSI = 1;
|
public const SESSION_EMSI = 1;
|
||||||
|
/** @deprecate Use mailers:class */
|
||||||
public const SESSION_BINKP = 2;
|
public const SESSION_BINKP = 2;
|
||||||
public const SESSION_ZMODEM = 3;
|
public const SESSION_ZMODEM = 3;
|
||||||
|
|
||||||
@ -447,6 +449,7 @@ abstract class Protocol
|
|||||||
$slo->sessiontype = $type;
|
$slo->sessiontype = $type;
|
||||||
$slo->sessiontime = $this->node->session_time;
|
$slo->sessiontime = $this->node->session_time;
|
||||||
$slo->result = ($rc & self::S_MASK);
|
$slo->result = ($rc & self::S_MASK);
|
||||||
|
$slo->originate = $this->originate;
|
||||||
|
|
||||||
$so->logs()->save($slo);
|
$so->logs()->save($slo);
|
||||||
}
|
}
|
||||||
|
@ -1420,8 +1420,6 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface
|
|||||||
$trys++;
|
$trys++;
|
||||||
}
|
}
|
||||||
|
|
||||||
dump(['ls_rxHdr'=>hex_dump(join('',$this->ls_rxHdr))]);
|
|
||||||
|
|
||||||
switch (($rc=$this->ls_zrecvhdr($this->ls_rxHdr,$this->ls_HeaderTimeout))) {
|
switch (($rc=$this->ls_zrecvhdr($this->ls_rxHdr,$this->ls_HeaderTimeout))) {
|
||||||
/* Send ZRINIT again */
|
/* Send ZRINIT again */
|
||||||
case self::ZRQINIT:
|
case self::ZRQINIT:
|
||||||
|
@ -34,14 +34,14 @@ class CommBinkpSend extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
Log::info('CBS:- Call BINKP send');
|
|
||||||
|
|
||||||
$mo = Mailer::where('name',self::ID)->singleOrFail();
|
|
||||||
|
|
||||||
$ao = Address::findFTN($this->argument('ftn'));
|
$ao = Address::findFTN($this->argument('ftn'));
|
||||||
if (! $ao)
|
if (! $ao)
|
||||||
throw new ModelNotFoundException('Unknown node: '.$this->argument('ftn'));
|
throw new ModelNotFoundException('Unknown node: '.$this->argument('ftn'));
|
||||||
|
|
||||||
Job::dispatchSync($ao,$mo);
|
Log::info(sprintf('CBS:- Call BINKP send for %s',$ao->ftn));
|
||||||
|
|
||||||
|
$mo = Mailer::where('name',self::ID)->singleOrFail();
|
||||||
|
|
||||||
|
Job::dispatch($ao,$mo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,14 +34,14 @@ class CommEMSISend extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
Log::info('CES:- Call EMSI send');
|
|
||||||
|
|
||||||
$mo = Mailer::where('name',self::ID)->singleOrFail();
|
|
||||||
|
|
||||||
$ao = Address::findFTN($this->argument('ftn'));
|
$ao = Address::findFTN($this->argument('ftn'));
|
||||||
if (! $ao)
|
if (! $ao)
|
||||||
throw new ModelNotFoundException('Unknown node: '.$this->argument('ftn'));
|
throw new ModelNotFoundException('Unknown node: '.$this->argument('ftn'));
|
||||||
|
|
||||||
Job::dispatchSync($ao,$mo);
|
Log::info(sprintf('CES:- Call EMSI send for %s',$ao->ftn));
|
||||||
|
|
||||||
|
$mo = Mailer::where('name',self::ID)->singleOrFail();
|
||||||
|
|
||||||
|
Job::dispatch($ao,$mo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
app/Console/Commands/JobList.php
Normal file
50
app/Console/Commands/JobList.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
use App\Models\Job;
|
||||||
|
|
||||||
|
class JobList extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'job:list';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Detail list of items in the queue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$lastq = NULL;
|
||||||
|
|
||||||
|
foreach (Job::orderBy('queue')->orderBy('created_at')->cursor() as $o) {
|
||||||
|
if ($o->queue !== $lastq) {
|
||||||
|
$this->alert(sprintf('Queue: %s',$o->queue));
|
||||||
|
$lastq = $o->queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info(sprintf('%s-%d: %s[%s] - %d tries (Created: %s,Timeout: %s,Next: %s)',
|
||||||
|
$o->uuid,
|
||||||
|
$o->id,
|
||||||
|
$o->display_name,
|
||||||
|
$o->command->subject,
|
||||||
|
$o->attempts,
|
||||||
|
$o->created_at,
|
||||||
|
$o->retry_until ?: '-',
|
||||||
|
$o->reserved_at ?: '-',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
app/Console/Commands/MailSend.php
Normal file
52
app/Console/Commands/MailSend.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Jobs\MailSend as Job;
|
||||||
|
|
||||||
|
class MailSend extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'mail:send'
|
||||||
|
.' {--T|type=normal : Send crash, normal or both mail}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Trigger a poll to each node with mail queued';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
switch ($this->option('type')) {
|
||||||
|
case 'crash':
|
||||||
|
Log::info('CML:- Triggering polls to send CRASH mail');
|
||||||
|
Job::dispatchSync(TRUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'normal':
|
||||||
|
Log::info('CML:- Triggering polls to send NORMAL mail');
|
||||||
|
Job::dispatchSync(FALSE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'all':
|
||||||
|
Log::info('CML:- Triggering polls to send ALL mail');
|
||||||
|
Job::dispatchSync(NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$this->error('Specify -T crash, normal or all');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
|
use App\Jobs\MailSend;
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
@ -24,8 +25,8 @@ class Kernel extends ConsoleKernel
|
|||||||
*/
|
*/
|
||||||
protected function schedule(Schedule $schedule)
|
protected function schedule(Schedule $schedule)
|
||||||
{
|
{
|
||||||
// $schedule->command('inspire')
|
$schedule->job(new MailSend(TRUE))->everyFiveMinutes()->withoutOverlapping();
|
||||||
// ->hourly();
|
$schedule->job(new MailSend(FALSE))->twiceDaily(1,13);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +12,7 @@ use Illuminate\Support\Facades\Notification;
|
|||||||
use Illuminate\Support\ViewErrorBag;
|
use Illuminate\Support\ViewErrorBag;
|
||||||
|
|
||||||
use App\Http\Requests\SystemRegister;
|
use App\Http\Requests\SystemRegister;
|
||||||
|
use App\Jobs\AddressPoll;
|
||||||
use App\Models\{Address,Echoarea,Filearea,Setup,System,SystemZone,Zone};
|
use App\Models\{Address,Echoarea,Filearea,Setup,System,SystemZone,Zone};
|
||||||
use App\Notifications\Netmails\AddressLink;
|
use App\Notifications\Netmails\AddressLink;
|
||||||
use App\Rules\{FidoInteger,TwoByteInteger};
|
use App\Rules\{FidoInteger,TwoByteInteger};
|
||||||
@ -279,6 +280,13 @@ class SystemController extends Controller
|
|||||||
foreach (['name','location','sysop','hold','phone','address','port','active','method','notes','zt_id','pkt_type'] as $key)
|
foreach (['name','location','sysop','hold','phone','address','port','active','method','notes','zt_id','pkt_type'] as $key)
|
||||||
$o->{$key} = $request->post($key);
|
$o->{$key} = $request->post($key);
|
||||||
|
|
||||||
|
switch ($request->post('pollmode')) {
|
||||||
|
case 1: $o->pollmode = FALSE; break;
|
||||||
|
case 2: $o->pollmode = TRUE; break;
|
||||||
|
default: $o->pollmode = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$o->autohold = FALSE;
|
||||||
$o->save();
|
$o->save();
|
||||||
|
|
||||||
$mailers = collect($request->post('mailer_details'))
|
$mailers = collect($request->post('mailer_details'))
|
||||||
@ -653,8 +661,10 @@ class SystemController extends Controller
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($ca->count() && $la=$ca->pop())
|
if ($ca->count() && $la=$ca->pop()) {
|
||||||
Notification::route('netmail',$la)->notify(new AddressLink(Auth::user()));
|
Notification::route('netmail',$la)->notify(new AddressLink(Auth::user()));
|
||||||
|
AddressPoll::dispatch($la)->delay(15);
|
||||||
|
}
|
||||||
|
|
||||||
return view('user.system.register_send')
|
return view('user.system.register_send')
|
||||||
->with('la',$la)
|
->with('la',$la)
|
||||||
|
@ -27,6 +27,14 @@ class SystemRegister extends FormRequest
|
|||||||
return Gate::allows($this->so->users->count() ? 'update' : 'register',$this->so);
|
return Gate::allows($this->so->users->count() ? 'update' : 'register',$this->so);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function messages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'hold' => 'Must be Yes or No',
|
||||||
|
'pollmode' => 'Must be Hold, Normal or Crash',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
@ -64,6 +72,7 @@ class SystemRegister extends FormRequest
|
|||||||
$this->so->exists ? [
|
$this->so->exists ? [
|
||||||
'active' => 'required|boolean',
|
'active' => 'required|boolean',
|
||||||
'hold' => 'required|boolean',
|
'hold' => 'required|boolean',
|
||||||
|
'pollmode' => 'required|integer|min:0|max:2',
|
||||||
] : [],
|
] : [],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -3,24 +3,37 @@
|
|||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\ManuallyFailedException;
|
||||||
|
use Illuminate\Queue\MaxAttemptsExceededException;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
|
||||||
use App\Classes\Protocol;
|
use App\Classes\Protocol;
|
||||||
use App\Classes\Protocol\{Binkp,EMSI};
|
use App\Classes\Protocol\{Binkp,EMSI};
|
||||||
use App\Classes\Sock\SocketClient;
|
use App\Classes\Sock\SocketClient;
|
||||||
use App\Classes\Sock\SocketException;
|
use App\Classes\Sock\SocketException;
|
||||||
use App\Models\{Address,Mailer,Setup};
|
use App\Models\{Address,Mailer,Setup};
|
||||||
|
use App\Notifications\Netmails\PollingFailed;
|
||||||
|
|
||||||
class AddressPoll implements ShouldQueue
|
class AddressPoll implements ShouldQueue, ShouldBeUnique
|
||||||
{
|
{
|
||||||
private const LOGKEY = 'JAP';
|
private const LOGKEY = 'JAP';
|
||||||
|
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $tries = 5;
|
||||||
|
|
||||||
|
public $maxExceptions = 1;
|
||||||
|
|
||||||
|
public $failOnTimeout = TRUE;
|
||||||
|
|
||||||
|
public const QUEUE = 'poll';
|
||||||
|
|
||||||
private Address $ao;
|
private Address $ao;
|
||||||
private ?Mailer $mo;
|
private ?Mailer $mo;
|
||||||
|
|
||||||
@ -28,6 +41,50 @@ class AddressPoll implements ShouldQueue
|
|||||||
{
|
{
|
||||||
$this->ao = $ao;
|
$this->ao = $ao;
|
||||||
$this->mo = $mo;
|
$this->mo = $mo;
|
||||||
|
|
||||||
|
$this->onQueue(self::QUEUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($key): mixed
|
||||||
|
{
|
||||||
|
switch ($key) {
|
||||||
|
case 'address':
|
||||||
|
return $this->ao;
|
||||||
|
|
||||||
|
case 'subject':
|
||||||
|
return $this->ao->ftn;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Because pluck doesnt return __get() defined vars
|
||||||
|
*
|
||||||
|
* @param $key
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function __isset($key): bool
|
||||||
|
{
|
||||||
|
$keys = ['address'];
|
||||||
|
|
||||||
|
return in_array($key,$keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to wait between tries
|
||||||
|
*
|
||||||
|
* @return int[] in seconds
|
||||||
|
*/
|
||||||
|
public function backoff(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
60*5, // 5 mins
|
||||||
|
60*60, // 1 hr
|
||||||
|
60*60*6, // 6 hrs
|
||||||
|
60*60*12 // 12 hrs
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,24 +92,19 @@ class AddressPoll implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if (! $this->ao->system->mailer_preferred->count() || ($this->mo && (! $this->ao->system->mailer_preferred->find($this->mo))))
|
if (! $this->ao->system->mailer_preferred->count() || ($this->mo && (! $this->ao->system->mailer_preferred->find($this->mo)))) {
|
||||||
throw new \Exception(sprintf('Unable to poll [%s] missing mailer details',$this->ao->ftn));
|
$this->fail('Missing mailer details');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info(sprintf('%s:- Polling [%s] - attempt [%d]',self::LOGKEY,$this->ao->ftn,$this->attempts()));
|
||||||
|
|
||||||
foreach ($this->ao->system->mailer_preferred as $o) {
|
foreach ($this->ao->system->mailer_preferred as $o) {
|
||||||
// If we chose a protocol, skip to find the mailer details for it
|
// If we chose a protocol, skip to find the mailer details for it
|
||||||
if ($this->mo && ($o->id !== $this->mo->id))
|
if ($this->mo && ($o->id !== $this->mo->id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Log::info(sprintf('%s:- Starting a [%s] session to [%s:%d]',self::LOGKEY,$o->name,$this->ao->system->address,$o->pivot->port));
|
|
||||||
|
|
||||||
try {
|
|
||||||
$client = SocketClient::create($this->ao->system->address,$o->pivot->port);
|
|
||||||
|
|
||||||
} catch (SocketException $e) {
|
|
||||||
Log::error(sprintf('%s:! Unable to connect to [%s]: %s',self::LOGKEY,$this->ao->ftn,$e->getMessage()));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($o->name) {
|
switch ($o->name) {
|
||||||
case 'BINKP':
|
case 'BINKP':
|
||||||
$s = new Binkp(Setup::findOrFail(config('app.id')));
|
$s = new Binkp(Setup::findOrFail(config('app.id')));
|
||||||
@ -67,16 +119,59 @@ class AddressPoll implements ShouldQueue
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new \Exception(sprintf('Node [%s] has a mailer type that is unhandled',$this->ao->ftn));
|
$this->fail('Mailer type unhandled');
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log::info(sprintf('%s:- Trying a [%s] session to [%s:%d] (%s)',
|
||||||
|
self::LOGKEY,$o->name,$this->ao->system->address,$o->pivot->port,$this->ao->ftn));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$client = SocketClient::create($this->ao->system->address,$o->pivot->port);
|
||||||
|
|
||||||
if (($s->session($session,$client,$this->ao) & Protocol::S_MASK) === Protocol::S_OK) {
|
if (($s->session($session,$client,$this->ao) & Protocol::S_MASK) === Protocol::S_OK) {
|
||||||
Log::info(sprintf('%s:= Connection ended successfully with [%s]',self::LOGKEY,$client->address_remote));
|
Log::info(sprintf('%s:= Connection ended successfully with [%s] (%s)',self::LOGKEY,$client->address_remote,$this->ao->ftn));
|
||||||
break;
|
return;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log::alert(sprintf('%s:! Connection failed to [%s]',self::LOGKEY,$client->address_remote));
|
Log::alert(sprintf('%s:! Connection failed to [%s] (%s)',self::LOGKEY,$client->address_remote,$this->ao->ftn));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SocketException $e) {
|
||||||
|
Log::error(sprintf('%s:! Unable to connect to [%s]: %s',self::LOGKEY,$this->ao->ftn,$e->getMessage()));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$delay = (int)($this->backoff()[$this->attempts()-1] ?? last($this->backoff()));
|
||||||
|
Log::info(sprintf('%s:= Retrying poll in %d seconds',self::LOGKEY,$delay));
|
||||||
|
$this->release($delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function failed(\Throwable $exception): void
|
||||||
|
{
|
||||||
|
switch (get_class($exception)) {
|
||||||
|
case ManuallyFailedException::class:
|
||||||
|
Log::error(sprintf('%s:! Address Poll failed for [%s] (%s)',self::LOGKEY,$this->ao->ftn,$exception->getMessage()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MaxAttemptsExceededException::class:
|
||||||
|
Log::error(sprintf('%s:! Address Poll was tried too many times for [%s]',self::LOGKEY,$this->ao->ftn));
|
||||||
|
Notification::route('netmail',$this->ao)->notify(new PollingFailed);
|
||||||
|
|
||||||
|
$this->ao->system->autohold = TRUE;
|
||||||
|
$this->ao->system->save();
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log::error(sprintf('%s:! Address Poll to [%s] with an unknown exception [%s]',self::LOGKEY,$this->ao->ftn,$exception->getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uniqueId(): string
|
||||||
|
{
|
||||||
|
return $this->ao->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
179
app/Jobs/MailSend.php
Normal file
179
app/Jobs/MailSend.php
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Repat\LaravelJobs\Job;
|
||||||
|
|
||||||
|
use App\Classes\FTN\Message;
|
||||||
|
use App\Models\Address;
|
||||||
|
|
||||||
|
class MailSend implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
private const LOGKEY = 'JCM';
|
||||||
|
|
||||||
|
private ?bool $crash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $crash Send crash mail only
|
||||||
|
*/
|
||||||
|
public function __construct(bool $crash=NULL)
|
||||||
|
{
|
||||||
|
$this->crash = $crash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*/
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
// Netmail waiting by node (only netmail is routed)
|
||||||
|
$netmails = Address::select(['addresses.id','addresses.zone_id','region_id','host_id','node_id','point_id','role','addresses.system_id',DB::raw('count(netmails.id) AS nm')])
|
||||||
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||||
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
|
->join('netmails',['netmails.tftn_id'=>'addresses.id'])
|
||||||
|
->join('systems',['systems.id'=>'addresses.system_id'])
|
||||||
|
->where('addresses.active',TRUE)
|
||||||
|
->where('zones.active',TRUE)
|
||||||
|
->where('domains.active',TRUE)
|
||||||
|
->where(function($query) {
|
||||||
|
return $query->whereNull('autohold')
|
||||||
|
->orWhere('autohold',FALSE);
|
||||||
|
})
|
||||||
|
->where(function($query) {
|
||||||
|
return $query->whereRaw(sprintf('(flags & %d) > 0',Message::FLAG_INTRANSIT))
|
||||||
|
->orWhereRaw(sprintf('(flags & %d) > 0',Message::FLAG_LOCAL));
|
||||||
|
})
|
||||||
|
->whereRaw(sprintf('(flags & %d) = 0',Message::FLAG_SENT))
|
||||||
|
->when(! is_null($this->crash),function($query) {
|
||||||
|
return $query->when(
|
||||||
|
$this->crash,
|
||||||
|
function($query) {
|
||||||
|
return $query->where('pollmode',$this->crash);
|
||||||
|
},
|
||||||
|
function($query) {
|
||||||
|
return $query->whereNotNull('pollmode');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->groupBy('addresses.id')
|
||||||
|
->havingRaw('count(*) > 0')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Echomail waiting by node
|
||||||
|
$echomails = Address::select(['addresses.id','addresses.zone_id','region_id','host_id','node_id','point_id','role','addresses.system_id',DB::raw('count(*) AS em')])
|
||||||
|
->distinct()
|
||||||
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||||
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
|
->join('echomail_seenby',['echomail_seenby.address_id'=>'addresses.id'])
|
||||||
|
->join('systems',['systems.id'=>'addresses.system_id'])
|
||||||
|
->where('addresses.active',TRUE)
|
||||||
|
->where('zones.active',TRUE)
|
||||||
|
->where('domains.active',TRUE)
|
||||||
|
->where(function($query) {
|
||||||
|
return $query->whereNull('autohold')
|
||||||
|
->orWhere('autohold',FALSE);
|
||||||
|
})
|
||||||
|
->whereNotNull('export_at')
|
||||||
|
->whereNull('sent_at')
|
||||||
|
->when(! is_null($this->crash),function($query) {
|
||||||
|
return $query->when(
|
||||||
|
$this->crash,
|
||||||
|
function($query) {
|
||||||
|
return $query->where('pollmode',$this->crash);
|
||||||
|
},
|
||||||
|
function($query) {
|
||||||
|
return $query->whereNotNull('pollmode');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->groupBy(['addresses.id'])
|
||||||
|
->havingRaw('count(*) > 0')
|
||||||
|
->FTNOrder()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Files waiting by node
|
||||||
|
$files = Address::select(['addresses.id','addresses.zone_id','region_id','host_id','node_id','point_id','role','addresses.system_id',DB::raw('count(*) AS fs')])
|
||||||
|
->distinct()
|
||||||
|
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||||
|
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||||
|
->join('file_seenby',['file_seenby.address_id'=>'addresses.id'])
|
||||||
|
->join('systems',['systems.id'=>'addresses.system_id'])
|
||||||
|
->where('addresses.active',TRUE)
|
||||||
|
->where('zones.active',TRUE)
|
||||||
|
->where('domains.active',TRUE)
|
||||||
|
->where(function($query) {
|
||||||
|
return $query->whereNull('autohold')
|
||||||
|
->orWhere('autohold',FALSE);
|
||||||
|
})
|
||||||
|
->whereNotNull('export_at')
|
||||||
|
->whereNull('sent_at')
|
||||||
|
->when(! is_null($this->crash),function($query) {
|
||||||
|
return $query->when(
|
||||||
|
$this->crash,
|
||||||
|
function($query) {
|
||||||
|
return $query->where('pollmode',$this->crash);
|
||||||
|
},
|
||||||
|
function($query) {
|
||||||
|
return $query->whereNotNull('pollmode');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->groupBy(['addresses.id'])
|
||||||
|
->havingRaw('count(*) > 0')
|
||||||
|
->FTNOrder()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Merge our netmails
|
||||||
|
foreach ($echomails as $ao) {
|
||||||
|
if (($x=$netmails->search(function($item) use ($ao) { return $item->id === $ao->id; })) !== FALSE) {
|
||||||
|
$netmails->get($x)->em = $ao->em;
|
||||||
|
} else {
|
||||||
|
$netmails->push($ao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge our files
|
||||||
|
foreach ($files as $ao) {
|
||||||
|
if (($x=$netmails->search(function($item) use ($ao) { return $item->id === $ao->id; })) !== FALSE) {
|
||||||
|
$netmails->get($x)->fs = $ao->fs;
|
||||||
|
} else {
|
||||||
|
$netmails->push($ao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove direct links
|
||||||
|
$netmails = $netmails->filter(function($item) { return $item->parent(); });
|
||||||
|
|
||||||
|
foreach ($netmails->groupBy(function($item) { return $item->parent()->ftn; }) as $oo) {
|
||||||
|
$ao = $oo->first();
|
||||||
|
|
||||||
|
Log::info(sprintf('%s:- Polling [%s] - we have mail for [%d] links. (%d Netmail,%d Echomail,%d Files)',
|
||||||
|
self::LOGKEY,
|
||||||
|
$ao->ftn,
|
||||||
|
$oo->count(),
|
||||||
|
$oo->sum('nm'),
|
||||||
|
$oo->sum('em'),
|
||||||
|
$oo->sum('fs'),
|
||||||
|
));
|
||||||
|
|
||||||
|
// @todo Only send crash mail - send normal mail with a schedule or hold mail
|
||||||
|
|
||||||
|
if (Job::where('queue',$this->queue)->get()->pluck('command.address.id')->search($ao->id) !== FALSE) {
|
||||||
|
Log::alert(sprintf('%s:= Not scheduling poll to [%s], there is already one in the queue',self::LOGKEY,$ao->ftn));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressPoll::dispatch($ao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
@ -283,7 +282,7 @@ class Address extends Model
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new \Exception('Unknown role: '.serialize($this->role));
|
throw new \Exception(sprintf('Unknown role: %s (%d)',serialize($this->role),$this->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $parent?->parent();
|
return $parent?->parent();
|
||||||
|
69
app/Models/Job.php
Normal file
69
app/Models/Job.php
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
|
||||||
|
class Job extends Model
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'payload' => 'array',
|
||||||
|
'reserved_at' => 'datetime',
|
||||||
|
'available_at' => 'datetime',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(array $attributes = [])
|
||||||
|
{
|
||||||
|
parent::__construct($attributes);
|
||||||
|
$this->table = Config::get('queue.connections.' . (Config::get('queue.default', 'database')) . '.table', 'jobs');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayNameAttribute()
|
||||||
|
{
|
||||||
|
return $this->payload['displayName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMaxTriesAttribute()
|
||||||
|
{
|
||||||
|
return $this->payload['maxTries'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDelayAttribute()
|
||||||
|
{
|
||||||
|
return $this->payload['delay'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUUIDAttribute()
|
||||||
|
{
|
||||||
|
return $this->payload['uuid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTimeoutAttribute()
|
||||||
|
{
|
||||||
|
return $this->payload['timeout'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRetryUntilAttribute()
|
||||||
|
{
|
||||||
|
return !is_null($this->payload['retryUntil']) ? new \Carbon\Carbon($this->payload['retryUntil']) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTimeoutAtAttribute()
|
||||||
|
{
|
||||||
|
return !is_null($this->payload['timeout_at']) ? new \Carbon\Carbon($this->payload['timeout_at']) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommandNameAttribute()
|
||||||
|
{
|
||||||
|
return $this->payload['data']['commandName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommandAttribute()
|
||||||
|
{
|
||||||
|
return unserialize($this->payload['data']['command']);
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
use App\Jobs\AddressPoll;
|
||||||
|
|
||||||
class System extends Model
|
class System extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
@ -214,4 +216,13 @@ class System extends Model
|
|||||||
return ($item->role & $type) && ($myzones->search($item->zone_id) !== FALSE);
|
return ($item->role & $type) && ($myzones->search($item->zone_id) !== FALSE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function poll(): ?Job
|
||||||
|
{
|
||||||
|
return Job::where('queue',AddressPoll::QUEUE)
|
||||||
|
->get()
|
||||||
|
->where(function($item) {
|
||||||
|
return $this->akas->pluck('id')->search($item->command->address->id) !== FALSE; })
|
||||||
|
->last();
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,7 +5,6 @@ namespace App\Notifications\Channels;
|
|||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
use App\Jobs\AddressPoll as Job;
|
|
||||||
use App\Models\Netmail;
|
use App\Models\Netmail;
|
||||||
use App\Models\Setup;
|
use App\Models\Setup;
|
||||||
|
|
||||||
@ -43,7 +42,6 @@ class NetmailChannel
|
|||||||
$so = Setup::findOrFail(config('app.id'))->system;
|
$so = Setup::findOrFail(config('app.id'))->system;
|
||||||
$o = $notification->toNetmail($so,$notifiable);
|
$o = $notification->toNetmail($so,$notifiable);
|
||||||
|
|
||||||
Job::dispatch($ao);
|
|
||||||
Log::info(sprintf('%s:= Sent netmail [%s] to [%s]',self::LOGKEY,$o->msgid,$ao->ftn));
|
Log::info(sprintf('%s:= Sent netmail [%s] to [%s]',self::LOGKEY,$o->msgid,$ao->ftn));
|
||||||
}
|
}
|
||||||
}
|
}
|
58
app/Notifications/Netmails/PollingFailed.php
Normal file
58
app/Notifications/Netmails/PollingFailed.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Netmails;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Classes\FTN\Message;
|
||||||
|
use App\Notifications\Netmails;
|
||||||
|
use App\Models\{Netmail,System};
|
||||||
|
use App\Traits\{MessagePath,PageTemplate};
|
||||||
|
|
||||||
|
class PollingFailed extends Netmails
|
||||||
|
{
|
||||||
|
use MessagePath,PageTemplate;
|
||||||
|
|
||||||
|
private const LOGKEY = 'NPF';
|
||||||
|
|
||||||
|
private Carbon $attempt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*
|
||||||
|
* @param System $so
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return Netmail
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function toNetmail(System $so,object $notifiable): Netmail
|
||||||
|
{
|
||||||
|
$o = $this->setupNetmail($so,$notifiable);
|
||||||
|
$ao = $notifiable->routeNotificationFor(static::via);
|
||||||
|
|
||||||
|
Log::info(sprintf('%s:+ Creating auto hold netmail to [%s]',self::LOGKEY,$ao->ftn));
|
||||||
|
|
||||||
|
$o->subject = 'Failed polling - your system is on AUTO HOLD';
|
||||||
|
|
||||||
|
// Message
|
||||||
|
$msg = $this->page(FALSE,'hold');
|
||||||
|
|
||||||
|
$msg->addText("Hi, I've been trying to poll your system without success.\r\r");
|
||||||
|
|
||||||
|
$msg->addText("Your system was automatically placed on hold, which means I no longer attempted to poll you.\r\r");
|
||||||
|
|
||||||
|
$msg->addText(
|
||||||
|
'Since you collected this message, I automatically removed the auto hold status, but if future attempts to poll you fail '.
|
||||||
|
"you'll be automatically placed back on auto hold until you poll me. You'll also get this annoying message each time :(\r\r");
|
||||||
|
|
||||||
|
$msg->addText("To fix this, update your details that I use in the web interface, or change your system to HOLD while you are there.\r\r");
|
||||||
|
|
||||||
|
$o->msg = $msg->render();
|
||||||
|
$o->tagline = 'Painful? We can make that painless :)';
|
||||||
|
|
||||||
|
$o->save();
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
}
|
36
database/migrations/2023_07_25_223929_system_poll.php
Normal file
36
database/migrations/2023_07_25_223929_system_poll.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('system_logs',function (Blueprint $table) {
|
||||||
|
$table->boolean('originate')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('systems',function (Blueprint $table) {
|
||||||
|
$table->boolean('pollmode')->nullable();
|
||||||
|
$table->boolean('autohold')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('systems',function (Blueprint $table) {
|
||||||
|
$table->dropColumn(['pollmode','autohold']);
|
||||||
|
});
|
||||||
|
Schema::table('system_logs',function (Blueprint $table) {
|
||||||
|
$table->dropColumn(['originate']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -272,8 +272,8 @@
|
|||||||
<table class="table monotable">
|
<table class="table monotable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Zone</th>
|
<th>AKA</th>
|
||||||
<th>System</th>
|
<th>Uplink</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
@ -286,7 +286,7 @@
|
|||||||
@if ($x=$oo->parent())
|
@if ($x=$oo->parent())
|
||||||
{{ $x->ftn4d }}
|
{{ $x->ftn4d }}
|
||||||
@else
|
@else
|
||||||
No destination for mail.
|
None
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -305,8 +305,8 @@
|
|||||||
<table class="table monotable">
|
<table class="table monotable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Zone</th>
|
<th>AKA</th>
|
||||||
<th>System</th>
|
<th>Downlink</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<!-- $o = System::class -->
|
||||||
@php
|
@php
|
||||||
use App\Models\Setup;
|
use App\Models\Setup;
|
||||||
@endphp
|
@endphp
|
||||||
@ -21,8 +22,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ZeroTier ID -->
|
||||||
|
<div class="col-3">
|
||||||
|
<label for="zt_id" class="form-label">ZeroTier ID</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-shield-lock-fill"></i></span>
|
||||||
|
<input type="text" class="form-control @error('zt_id') is-invalid @enderror" id="zt_id" placeholder="ZeroTier" name="zt_id" value="{{ old('zt_id',$o->zt_id) }}" @cannot($action,$o)readonly @endcannot>
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('zt_id')
|
||||||
|
{{ $message }}
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Active -->
|
<!-- Active -->
|
||||||
<div class="col-2">
|
<div class="offset-2 col-2">
|
||||||
@can('update',$o)
|
@can('update',$o)
|
||||||
<label for="active" class="form-label">Active</label>
|
<label for="active" class="form-label">Active</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@ -36,36 +51,6 @@
|
|||||||
</div>
|
</div>
|
||||||
@endcan
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hold -->
|
|
||||||
<div class="col-2">
|
|
||||||
@can('update',$o)
|
|
||||||
<label for="hold" class="form-label">Hold Mail</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="btn-group" role="group">
|
|
||||||
<input type="radio" class="btn-check" name="hold" id="hold_yes" value="1" required @if(old('hold',$o->hold))checked @endif>
|
|
||||||
<label class="btn btn-outline-success" for="hold_yes">Yes</label>
|
|
||||||
|
|
||||||
<input type="radio" class="btn-check btn-danger" name="hold" id="hold_no" value="0" required @if(! old('hold',$o->hold))checked @endif>
|
|
||||||
<label class="btn btn-outline-danger" for="hold_no">No</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endcan
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ZeroTier ID -->
|
|
||||||
<div class="offset-1 col-3">
|
|
||||||
<label for="zt_id" class="form-label">ZeroTier ID</label>
|
|
||||||
<div class="input-group has-validation">
|
|
||||||
<span class="input-group-text"><i class="bi bi-shield-lock-fill"></i></span>
|
|
||||||
<input type="text" class="form-control @error('zt_id') is-invalid @enderror" id="zt_id" placeholder="ZeroTier" name="zt_id" value="{{ old('zt_id',$o->zt_id) }}" @cannot($action,$o)readonly @endcannot>
|
|
||||||
<span class="invalid-feedback" role="alert">
|
|
||||||
@error('zt_id')
|
|
||||||
{{ $message }}
|
|
||||||
@enderror
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -86,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Location -->
|
<!-- Location -->
|
||||||
<div class="col-8">
|
<div class="col-4">
|
||||||
<label for="location" class="form-label">Location</label>
|
<label for="location" class="form-label">Location</label>
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
<span class="input-group-text"><i class="bi bi-globe"></i></span>
|
<span class="input-group-text"><i class="bi bi-globe"></i></span>
|
||||||
@ -100,10 +85,41 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Hold -->
|
||||||
|
<div class="offset-1 col-2">
|
||||||
|
@can('update',$o)
|
||||||
|
<label for="hold" class="form-label">Hold Mail <i class="bi bi-info-circle" title="Dont give the node any mail regardless of poll mode"></i></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<input type="radio" class="btn-check" name="hold" id="hold_yes" value="1" required @if(old('hold',$o->hold))checked @endif>
|
||||||
|
<label class="btn btn-outline-warning" for="hold_yes">Yes</label>
|
||||||
|
|
||||||
|
<input type="radio" class="btn-check btn-danger" name="hold" id="hold_no" value="0" required @if(! old('hold',$o->hold))checked @endif>
|
||||||
|
<label class="btn btn-outline-success" for="hold_no">No</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-4">
|
<!-- Address -->
|
||||||
|
<div class="col-5">
|
||||||
|
<label for="address" class="form-label">Internet Address</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-globe"></i></span>
|
||||||
|
<input type="text" class="w-75 form-control @error('address') is-invalid @enderror" id="address" placeholder="FQDN" name="address" value="{{ old('address',$o->address) }}" @cannot($action,$o)readonly @endcannot>
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('address')
|
||||||
|
{{ $message }}
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Phone -->
|
||||||
|
<div class="col-3">
|
||||||
<label for="phone" class="form-label">Phone</label>
|
<label for="phone" class="form-label">Phone</label>
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
<span class="input-group-text"><i class="bi bi-telephone-fill"></i></span>
|
<span class="input-group-text"><i class="bi bi-telephone-fill"></i></span>
|
||||||
@ -116,18 +132,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Address -->
|
<!-- Poll Mode -->
|
||||||
<div class="col-8">
|
<div class="offset-1 col-3">
|
||||||
<label for="address" class="form-label">Internet Address</label>
|
@can('update',$o)
|
||||||
|
<label for="pollmode" class="form-label">Poll Mode <i class="bi bi-info-circle" title="Poll node when mail available, poll on a schedule or hold mail for collection"></i></label>
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
<span class="input-group-text"><i class="bi bi-globe"></i></span>
|
<div class="btn-group @error('pollmode') is-invalid @enderror" role="group">
|
||||||
<input type="text" class="w-75 form-control @error('address') is-invalid @enderror" id="address" placeholder="FQDN" name="address" value="{{ old('address',$o->address) }}" @cannot($action,$o)readonly @endcannot>
|
<input type="radio" class="btn-check" name="pollmode" id="poll_crash" value="2" @if((int)old('pollmode',($o->pollmode === TRUE) ? 2 : 0) === 2)checked @endif>
|
||||||
|
<label class="btn btn-outline-success" for="poll_crash">Crash</label>
|
||||||
|
|
||||||
|
<input type="radio" class="btn-check btn-danger" name="pollmode" id="poll_normal" value="1" @if((int)old('pollmode',($o->pollmode === FALSE) ? 1 : 0) === 1)checked @endif>
|
||||||
|
<label class="btn btn-outline-secondary" for="poll_normal">Normal</label>
|
||||||
|
|
||||||
|
<input type="radio" class="btn-check btn-danger" name="pollmode" id="poll_hold" value="0" @if((int)old('pollmode',is_null($o->pollmode) ? 0 : 1) === 0)checked @endif>
|
||||||
|
<label class="btn btn-outline-warning" for="poll_hold">Hold</label>
|
||||||
|
</div>
|
||||||
<span class="invalid-feedback" role="alert">
|
<span class="invalid-feedback" role="alert">
|
||||||
@error('address')
|
@error('pollmode')
|
||||||
{{ $message }}
|
{{ $message }}
|
||||||
@enderror
|
@enderror
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -136,6 +162,7 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h4 class="pt-4 mb-0 pb-2">Mailer Details</h4>
|
<h4 class="pt-4 mb-0 pb-2">Mailer Details</h4>
|
||||||
|
|
||||||
|
<!-- Mailer Ports -->
|
||||||
<div class="pt-0 row">
|
<div class="pt-0 row">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
@foreach (\App\Models\Mailer::all() as $mo)
|
@foreach (\App\Models\Mailer::all() as $mo)
|
||||||
@ -160,6 +187,7 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Mail Packet -->
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<label for="pkt_type" class="form-label">Mail Packet</label>
|
<label for="pkt_type" class="form-label">Mail Packet</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@ -177,6 +205,55 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (! is_null($o->pollmode))
|
||||||
|
<div class="offset-3 col-4">
|
||||||
|
<table class="table monotable m-0 p-0 small noborder">
|
||||||
|
<tbody style="border-style:dotted;">
|
||||||
|
@if($job = $o->poll())
|
||||||
|
<tr>
|
||||||
|
<td class="cap text-end">@if($job->attempts)Last Attempt @else Scheduled @endif:</td>
|
||||||
|
<td>{{ $job->created_at }} </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="cap text-end">Attempts :</td>
|
||||||
|
<td>{{ $job->attempts ?: 0 }}</td>
|
||||||
|
</tr>
|
||||||
|
@if ($job->attempts)
|
||||||
|
<tr>
|
||||||
|
<td class="cap text-end">Next Attempt :</td>
|
||||||
|
<td>{{ $job->available_at->diffForHumans(now(),$job->available_at->isFuture() ? \Carbon\CarbonInterface::DIFF_ABSOLUTE : \Carbon\CarbonInterface::DIFF_RELATIVE_TO_NOW) }}</td>
|
||||||
|
</tr>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@else
|
||||||
|
<tr>
|
||||||
|
<td class="cap text-end">Last Poll :</td>
|
||||||
|
<td>{{ ($x=$o->logs->where('originate',TRUE)->last())?->created_at ?: 'Never' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="cap text-end">Method :</td>
|
||||||
|
<td>{{ $x?->sessiontype ?: '-' }}</td>
|
||||||
|
</tr>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="cap text-end">Status :</td>
|
||||||
|
<td>
|
||||||
|
@if ($job) Queued
|
||||||
|
@elseif ($o->autohold)Auto Hold
|
||||||
|
@else
|
||||||
|
@switch($o->pollmode)
|
||||||
|
@case(TRUE) Crash @break;
|
||||||
|
@case(FALSE) Normal @break;
|
||||||
|
@default Hold
|
||||||
|
@endswitch
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user