clrghouz/app/Models/Address.php
2021-07-18 22:11:34 +10:00

236 lines
5.2 KiB
PHP

<?php
namespace App\Models;
use Carbon\Carbon;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Classes\FTN\Packet;
use App\Http\Controllers\DomainController;
use App\Traits\ScopeActive;
class Address extends Model
{
use ScopeActive,SoftDeletes;
/* SCOPES */
public function scopeFTNOrder($query)
{
return $query
->orderBy('region_id')
->orderBy('host_id')
->orderBy('node_id')
->orderBy('point_id');
}
/* RELATIONS */
/**
* Find children dependant on this record
*/
public function children()
{
switch (strtolower($this->role)) {
case 'region':
return $this->hasMany(self::class,'region_id','region_id')
->where('zone_id',$this->zone_id)
->where(function($q) {
return $q->where('host_id',0)
->orWhere('role',DomainController::NODE_NC);
})
->where('id','<>',$this->id);
case 'host':
return $this->hasMany(self::class,'host_id','host_id')
->where('zone_id',$this->zone_id)
->where('region_id',$this->region_id)
->whereNull('hub_id')
->where('id','<>',$this->id);
case 'hub':
return $this->hasMany(self::class,'hub_id','id');
case 'node':
// Nodes dont have children, but must return a relationship instance
return $this->hasOne(self::class,NULL,'void');
default:
throw new Exception('Unknown role: '.$this->role);
}
}
public function system()
{
return $this->belongsTo(System::class);
}
public function zone()
{
return $this->belongsTo(Zone::class);
}
/* ATTRIBUTES */
/**
* Render the node name in full 5D
*
* @return string
*/
public function getFTNAttribute(): string
{
return sprintf('%s@%s',$this->getFTN4DAttribute(),$this->zone->domain->name);
}
public function getFTN3DAttribute(): string
{
return sprintf('%d:%d/%d',$this->zone->zone_id,$this->host_id ?: $this->region_id,$this->node_id);
}
public function getFTN4DAttribute(): string
{
return sprintf('%s.%d',$this->getFTN3DAttribute(),$this->point_id);
}
public function getRoleAttribute($value)
{
switch ($value) {
case DomainController::NODE_ZC;
return 'Zone';
case DomainController::NODE_RC;
return 'Region';
case DomainController::NODE_NC;
return 'Host';
case DomainController::NODE_HC;
return 'Hub';
case DomainController::NODE_PVT;
return 'PVT';
case DomainController::NODE_DOWN;
return 'DOWN';
case NULL:
return 'Node';
default:
return '?';
}
}
/* METHODS */
/**
* Find a record in the DB for a node string, eg: 10:1/1.0
*
* @param string $ftn
* @return Address|null
* @throws Exception
*/
public static function findFTN(string $ftn): ?self
{
$ftn = self::parseFTN($ftn);
$o = (new self)->active()
->select('addresses.*')
->where('zones.zone_id',$ftn['z'])
->where('host_id',$ftn['n'])
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->where('zones.active',TRUE)
->where('domains.active',TRUE)
->where('addresses.active',TRUE)
->where('node_id',$ftn['f'])
->where('point_id',$ftn['p'])
->when($ftn['d'],function($query,$domain) {
$query->where('domains.name',$domain);
})
->when((! $ftn['d']),function($query) {
$query->where('domains.default',TRUE);
})
->single();
return ($o && $o->system->active) ? $o : NULL;
}
/**
* Get netmail for this node (including it's children)
*
* @return Packet|null
*/
public function getNetmail(): ?Packet
{
if (($x=Netmail::whereIn('tftn_id',$this->children->pluck('id')->push($this->id))
->where(function($q) {
return $q->whereNull('sent')
->orWhere('sent',FALSE);
}))
->count())
{
$o = new Packet($this);
foreach ($x->get() as $oo) {
$o->addNetmail($oo->packet());
$oo->packet = $o->name;
$oo->sent = TRUE;
$oo->sent_at = Carbon::now();
$oo->save();
}
return $o;
}
return NULL;
}
/**
* Parse a string and split it out as an FTN array
*
* @param string $ftn
* @return array
* @throws Exception
*/
public static function parseFTN(string $ftn): array
{
// http://ftsc.org/docs/frl-1028.002
if (! preg_match('#^([0-9]+):([0-9]+)/([0-9]+)(.([0-9]+))?(@([a-z0-9\-_~]{0,8}))?$#',strtolower($ftn),$matches))
throw new Exception('Invalid FTN: '.$ftn);
// Check our numbers are correct.
foreach ([1,2,3] as $i) {
if ((! is_numeric($matches[$i])) || ($matches[$i] > DomainController::NUMBER_MAX))
throw new Exception('Invalid FTN: '.$ftn);
}
if (isset($matches[5]) AND ((! is_numeric($matches[$i])) || ($matches[5] > DomainController::NUMBER_MAX)))
throw new Exception('Invalid FTN: '.$ftn);
return [
'z'=>(int)$matches[1],
'n'=>(int)$matches[2],
'f'=>(int)$matches[3],
'p'=>isset($matches[5]) && $matches[5] ? (int)$matches[5] : 0,
'd'=>$matches[7] ?? NULL
];
}
/**
* Retrieve the address session details/passwords
*
* @param string $type
* @return string|null
*/
public function session(string $type): ?string
{
static $session = NULL;
if (is_null($session)) {
$session = (new SystemZone)
->where('zone_id',$this->zone_id)
->where('system_id',$this->system_id)
->single();
}
return $session ? $session->{$type} : NULL;
}
}