2019-04-27 13:57:39 +00:00
< ? php
namespace App\Models ;
2021-09-06 13:39:32 +00:00
use Carbon\Carbon ;
2022-01-01 05:59:35 +00:00
use Illuminate\Database\Eloquent\Model ;
use Illuminate\Database\Eloquent\SoftDeletes ;
2022-01-22 12:08:46 +00:00
use Illuminate\Support\Collection ;
2021-08-29 14:44:20 +00:00
use Illuminate\Support\Facades\DB ;
2021-09-06 13:39:32 +00:00
use Illuminate\Support\Facades\Log ;
2019-04-27 13:57:39 +00:00
2022-10-30 12:42:30 +00:00
use App\Casts\ { CollectionOrNull , CompressedString };
2021-07-30 14:35:52 +00:00
use App\Classes\FTN\Message ;
use App\Interfaces\Packet ;
2024-05-11 13:18:08 +00:00
use App\Traits\ { EncodeUTF8 , MsgID , ParseAddresses };
2021-07-30 14:35:52 +00:00
2021-09-06 13:39:32 +00:00
final class Echomail extends Model implements Packet
2019-04-27 13:57:39 +00:00
{
2024-05-11 13:18:08 +00:00
use SoftDeletes , EncodeUTF8 , MsgID , ParseAddresses ;
2021-08-11 13:45:30 +00:00
2021-09-06 13:39:32 +00:00
private const LOGKEY = 'ME-' ;
2022-10-30 12:42:30 +00:00
private Collection $set_seenby ;
private Collection $set_path ;
2023-08-05 11:32:45 +00:00
private Carbon $set_recvtime ;
2023-07-15 12:10:05 +00:00
private string $set_pkt ;
2023-11-22 02:14:21 +00:00
private string $set_sender ;
2022-01-04 22:25:36 +00:00
private bool $no_export = FALSE ;
2022-01-01 05:59:35 +00:00
protected $casts = [
2023-06-26 00:32:38 +00:00
'datetime' => 'datetime:Y-m-d H:i:s' ,
2022-10-30 12:42:30 +00:00
'kludges' => CollectionOrNull :: class ,
'msg' => CompressedString :: class ,
'msg_src' => CompressedString :: class ,
2023-06-26 00:32:38 +00:00
'rogue_seenby' => CollectionOrNull :: class ,
'rogue_path' => CollectionOrNull :: class ,
2022-01-01 05:59:35 +00:00
];
2021-09-14 13:14:13 +00:00
2021-08-11 13:45:30 +00:00
private const cast_utf8 = [
2021-12-01 11:45:51 +00:00
'to' ,
'from' ,
2021-08-26 12:32:32 +00:00
'subject' ,
'msg' ,
2022-02-19 05:33:14 +00:00
'msg_src' ,
2021-09-12 13:06:17 +00:00
'origin' ,
'tearline' ,
'tagline' ,
2021-08-11 13:45:30 +00:00
];
2019-04-27 13:57:39 +00:00
2022-11-01 11:24:36 +00:00
public function __set ( $key , $value )
2022-01-01 05:59:35 +00:00
{
switch ( $key ) {
2022-01-04 22:25:36 +00:00
case 'no_export' :
2022-01-01 05:59:35 +00:00
case 'set_path' :
2023-07-15 12:10:05 +00:00
case 'set_pkt' :
2023-11-22 02:14:21 +00:00
case 'set_sender' :
2023-08-05 11:32:45 +00:00
case 'set_recvtime' :
2022-01-01 05:59:35 +00:00
case 'set_seenby' :
$this -> { $key } = $value ;
break ;
default :
parent :: __set ( $key , $value );
}
}
2021-09-06 13:39:32 +00:00
public static function boot ()
{
parent :: boot ();
2021-11-29 10:12:44 +00:00
// @todo if the message is updated with new SEEN-BY's from another route, we'll delete the pending export for systems (if there is one)
2021-09-06 13:39:32 +00:00
static :: created ( function ( $model ) {
2023-09-20 10:29:23 +00:00
$rogue = collect ();
2023-11-22 02:14:21 +00:00
$seenby = collect ();
2023-11-17 01:18:55 +00:00
$path = collect ();
2021-09-06 13:39:32 +00:00
2023-09-20 10:29:23 +00:00
// Parse PATH
if ( $model -> set_path -> count ())
$path = self :: parseAddresses ( 'path' , $model -> set_path , $model -> fftn -> zone , $rogue );
2021-09-06 13:39:32 +00:00
2023-11-22 02:14:21 +00:00
// Make sure our sender is first in the path
if ( ! $path -> contains ( $model -> fftn_id )) {
Log :: alert ( sprintf ( '%s:? Echomail adding sender to start of PATH [%s].' , self :: LOGKEY , $model -> fftn_id ));
$path -> prepend ( $model -> fftn_id );
}
// Make sure our pktsrc is last in the path
if ( isset ( $model -> set_sender ) && ( ! $path -> contains ( $model -> set_sender ))) {
Log :: alert ( sprintf ( '%s:? Echomail adding pktsrc to end of PATH [%s].' , self :: LOGKEY , $model -> set_sender ));
$path -> push ( $model -> set_sender );
}
2022-01-01 05:59:35 +00:00
// Save the Path
$ppoid = NULL ;
2023-09-20 10:29:23 +00:00
foreach ( $path as $aoid ) {
2022-01-01 05:59:35 +00:00
$po = DB :: select ( 'INSERT INTO echomail_path (echomail_id,address_id,parent_id) VALUES (?,?,?) RETURNING id' ,[
$model -> id ,
$aoid ,
$ppoid ,
2021-09-06 13:39:32 +00:00
]);
2022-01-01 05:59:35 +00:00
$ppoid = $po [ 0 ] -> id ;
2021-09-06 13:39:32 +00:00
}
2023-09-20 10:29:23 +00:00
$rogue = collect ();
2023-12-01 07:14:51 +00:00
// @todo move the parseAddress processing into Message::class, and our address to the seenby (and thus no need to add it when we export)
2023-09-20 10:29:23 +00:00
// Parse SEEN-BY
if ( $model -> set_seenby -> count ())
$seenby = self :: parseAddresses ( 'seenby' , $model -> set_seenby , $model -> fftn -> zone , $rogue );
2023-11-22 02:35:37 +00:00
// Make sure our sender is in the seenby
2023-11-22 02:14:21 +00:00
if ( ! $seenby -> contains ( $model -> fftn_id )) {
Log :: alert ( sprintf ( '%s:? Echomail adding sender to SEENBY [%s].' , self :: LOGKEY , $model -> fftn_id ));
$seenby -> push ( $model -> fftn_id );
}
2023-11-22 02:35:37 +00:00
// Make sure our pktsrc is in the seenby
2023-11-22 02:14:21 +00:00
if ( isset ( $model -> set_sender ) && ( ! $seenby -> contains ( $model -> set_sender ))) {
Log :: alert ( sprintf ( '%s:? Echomail adding pktsrc to SEENBY [%s].' , self :: LOGKEY , $model -> set_sender ));
$seenby -> push ( $model -> set_sender );
}
2023-09-20 10:29:23 +00:00
if ( count ( $rogue )) {
$model -> rogue_seenby = $rogue ;
$model -> save ();
}
if ( $seenby )
$model -> seenby () -> sync ( $seenby );
2023-07-15 12:10:05 +00:00
// Our last node in the path is our sender
2023-08-05 11:32:45 +00:00
if ( isset ( $model -> set_pkt ) && isset ( $model -> set_recvtime )) {
2023-11-17 01:18:55 +00:00
if ( $path -> count ()) {
DB :: update ( 'UPDATE echomail_path set recv_pkt=?,recv_at=? where address_id=? and echomail_id=?' ,[
$model -> set_pkt ,
$model -> set_recvtime ,
$path -> last (),
$model -> id ,
]);
} else {
Log :: critical ( sprintf ( '%s:! Wasnt able to set packet details for [%d] to [%s] to [%s], no path information' , self :: LOGKEY , $model -> id , $model -> set_pkt , $model -> set_recvtime ));
}
2023-07-15 12:10:05 +00:00
}
2022-01-01 05:59:35 +00:00
// See if we need to export this message.
2023-07-29 03:17:36 +00:00
if ( $model -> echoarea -> sec_read ) {
$exportto = ( $x = $model
-> echoarea
-> addresses
2024-04-14 11:16:33 +00:00
-> filter ( function ( $item ) use ( $model ) { return $model -> echoarea -> can_read ( $item -> security ); }))
2023-07-29 03:17:36 +00:00
-> pluck ( 'id' )
2023-09-20 10:29:23 +00:00
-> diff ( $seenby );
2023-07-29 03:17:36 +00:00
if ( $exportto -> count ()) {
if ( $model -> no_export ) {
2023-09-08 11:11:53 +00:00
Log :: alert ( sprintf ( '%s:- NOT processing exporting of message by configuration [%s] to [%s]' , self :: LOGKEY , $model -> id , $exportto -> join ( ',' )));
2023-07-29 03:17:36 +00:00
return ;
}
2023-09-08 11:11:53 +00:00
Log :: info ( sprintf ( '%s:- Exporting message [%s] to [%s]' , self :: LOGKEY , $model -> id , $exportto -> join ( ',' )));
2023-07-29 03:17:36 +00:00
// Save the seenby for the exported systems
$model -> seenby () -> syncWithPivotValues ( $exportto ,[ 'export_at' => Carbon :: now ()], FALSE );
2022-01-04 22:25:36 +00:00
}
2022-01-01 05:59:35 +00:00
}
2021-09-06 13:39:32 +00:00
});
}
2021-07-30 14:35:52 +00:00
/* RELATIONS */
2019-04-27 13:57:39 +00:00
2021-09-06 13:39:32 +00:00
public function echoarea ()
{
return $this -> belongsTo ( Echoarea :: class );
}
2021-07-30 14:35:52 +00:00
public function fftn ()
2019-04-27 13:57:39 +00:00
{
2022-01-01 05:59:35 +00:00
return $this -> belongsTo ( Address :: class )
2021-07-30 14:35:52 +00:00
-> withTrashed ();
2019-04-27 13:57:39 +00:00
}
2022-01-01 05:59:35 +00:00
public function seenby ()
2021-08-29 01:48:27 +00:00
{
2022-01-01 05:59:35 +00:00
return $this -> belongsToMany ( Address :: class , 'echomail_seenby' )
2023-12-01 07:14:51 +00:00
-> withPivot ([ 'export_at' , 'sent_at' , 'sent_pkt' ])
2023-09-19 07:28:25 +00:00
-> FTN2DOrder ();
2021-08-29 01:48:27 +00:00
}
2022-01-01 05:59:35 +00:00
public function path ()
2021-08-29 01:48:27 +00:00
{
2022-01-22 12:08:46 +00:00
return $this -> belongsToMany ( Address :: class , 'echomail_path' )
2023-11-22 02:35:37 +00:00
-> withPivot ([ 'id' , 'parent_id' , 'recv_pkt' , 'recv_at' ]);
2021-08-29 01:48:27 +00:00
}
2021-07-30 14:35:52 +00:00
/* METHODS */
2022-11-04 12:14:47 +00:00
public function init () : void
{
$this -> set_path = collect ();
$this -> set_seenby = collect ();
}
2021-08-11 13:45:30 +00:00
public function jsonSerialize () : array
{
return $this -> encode ();
}
2021-07-30 14:35:52 +00:00
/**
* Return this model as a packet
*/
public function packet ( Address $ao ) : Message
2019-04-27 13:57:39 +00:00
{
2023-09-08 11:11:53 +00:00
Log :: info ( sprintf ( '%s:+ Bundling [%s]' , self :: LOGKEY , $this -> id ));
2021-09-06 13:39:32 +00:00
2024-04-21 11:40:55 +00:00
$sysaddress = our_address ( $this -> fftn );
2023-10-09 10:54:46 +00:00
if ( ! $sysaddress )
throw new \Exception ( sprintf ( '%s:! We dont have an address in this network? (%s)' , self :: LOGKEY , $this -> fftn -> zone -> domain -> name ));
2021-07-30 14:35:52 +00:00
// @todo Dont bundle mail to nodes that have been disabled, or addresses that have been deleted
$o = new Message ;
$o -> header = [
2023-10-09 10:54:46 +00:00
'onode' => $sysaddress -> node_id ,
2021-07-30 14:35:52 +00:00
'dnode' => $ao -> node_id ,
2023-10-09 10:54:46 +00:00
'onet' => $sysaddress -> host_id ,
2021-07-30 14:35:52 +00:00
'dnet' => $ao -> host_id ,
2023-07-15 12:10:05 +00:00
'flags' => 0 ,
2021-07-30 14:35:52 +00:00
'cost' => 0 ,
'date' => $this -> datetime -> format ( 'd M y H:i:s' ),
];
$o -> tzutc = $this -> datetime -> utcOffset ( $this -> tzoffset ) -> getOffsetString ( '' );
$o -> user_to = $this -> to ;
$o -> user_from = $this -> from ;
$o -> subject = $this -> subject ;
2021-09-06 13:39:32 +00:00
$o -> echoarea = $this -> echoarea -> name ;
2021-07-30 14:35:52 +00:00
$o -> flags = $this -> flags ;
2021-09-14 13:14:13 +00:00
if ( $this -> kludges )
2022-01-15 02:06:15 +00:00
$o -> kludge = collect ( $this -> kludges );
2021-09-14 13:14:13 +00:00
2022-01-01 05:59:35 +00:00
$o -> kludge -> put ( 'dbid' , $this -> id );
2021-07-30 14:35:52 +00:00
$o -> msgid = $this -> msgid ;
2022-01-01 05:59:35 +00:00
if ( $this -> replyid )
$o -> replyid = $this -> replyid ;
2021-07-30 14:35:52 +00:00
$o -> message = $this -> msg ;
if ( $this -> tagline )
$o -> tagline = $this -> tagline ;
if ( $this -> tearline )
$o -> tearline = $this -> tearline ;
if ( $this -> origin )
$o -> origin = $this -> origin ;
2023-07-15 12:10:05 +00:00
$o -> seenby = $this -> seenby -> push ( $sysaddress ) -> unique () -> pluck ( 'ftn2d' );
// Add our address to the path and seenby
$o -> path = $this -> pathorder () -> merge ( $sysaddress -> ftn2d );
2021-07-30 14:35:52 +00:00
2021-09-06 13:39:32 +00:00
$o -> packed = TRUE ;
2021-07-30 14:35:52 +00:00
return $o ;
2019-04-27 13:57:39 +00:00
}
2022-01-22 12:08:46 +00:00
public function pathorder ( string $display = 'ftn2d' , int $start = NULL ) : Collection
{
$result = collect ();
if ( $x = $this -> path -> firstWhere ( 'pivot.parent_id' , $start )) {
$result -> push ( $x -> $display );
$result -> push ( $this -> pathorder ( $display , $x -> pivot -> id ));
2023-06-27 07:39:11 +00:00
}
2022-01-22 12:08:46 +00:00
return $result -> flatten () -> filter ();
}
2019-04-27 13:57:39 +00:00
}