2019-12-12 00:56:30 +01:00
< ? php
2020-01-17 18:19:25 +01:00
/*
* This file is part of RaspiSMS .
*
* ( c ) Pierre - Lin Bonnemaison < plebwebsas @ gmail . com >
*
* This source file is subject to the GPL - 3.0 license that is bundled
* with this source code in the file LICENSE .
*/
2019-12-12 00:56:30 +01:00
namespace daemons ;
2020-01-17 18:19:25 +01:00
use Monolog\Handler\StreamHandler ;
use Monolog\Logger ;
2019-12-12 00:56:30 +01:00
/**
2020-01-17 18:19:25 +01:00
* Phone daemon class .
2019-12-12 00:56:30 +01:00
*/
class Phone extends AbstractDaemon
{
2020-03-04 05:10:45 +01:00
private $max_inactivity = 5 * 60 ;
2019-12-12 00:56:30 +01:00
private $msg_queue ;
2020-01-07 01:31:34 +01:00
private $msg_queue_id ;
private $webhook_queue ;
2019-12-17 07:47:11 +01:00
private $last_message_at ;
2020-01-07 01:31:34 +01:00
private $phone ;
private $adapter ;
private $bdd ;
2019-12-12 00:56:30 +01:00
2020-01-07 01:31:34 +01:00
/**
2020-01-17 18:19:25 +01:00
* Constructor .
*
2020-01-07 01:31:34 +01:00
* @ param array $phone : A phone table entry
*/
public function __construct ( array $phone )
2019-12-12 00:56:30 +01:00
{
2020-01-07 01:31:34 +01:00
$this -> phone = $phone ;
2020-03-04 01:40:47 +01:00
$this -> msg_queue_id = ( int ) ( QUEUE_ID_PHONE_PREFIX . $this -> phone [ 'id' ]);
2020-01-17 18:19:25 +01:00
2020-03-04 01:40:47 +01:00
$name = 'RaspiSMS Daemon Phone ' . $this -> phone [ 'id' ];
2019-12-12 00:56:30 +01:00
$logger = new Logger ( $name );
2020-03-04 04:18:26 +01:00
$logger -> pushHandler ( new StreamHandler ( PWD_LOGS . '/daemons.log' , Logger :: DEBUG ));
2019-12-17 07:47:11 +01:00
$pid_dir = PWD_PID ;
2020-01-08 18:20:17 +01:00
$no_parent = false ; //Phone should be rattach to manager, so manager can stop him easily
2019-12-17 07:47:11 +01:00
$additional_signals = [];
2020-01-08 18:20:17 +01:00
$uniq = true ; //Each phone should be uniq
2019-12-12 00:56:30 +01:00
2020-01-08 18:20:17 +01:00
//Construct the daemon
parent :: __construct ( $name , $logger , $pid_dir , $no_parent , $additional_signals , $uniq );
2020-01-17 18:19:25 +01:00
2019-12-12 00:56:30 +01:00
parent :: start ();
}
public function run ()
{
2020-03-04 03:28:34 +01:00
usleep ( 0.5 * 1000000 ); //Micro sleep for perfs
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
$this -> bdd = \descartes\Model :: _connect ( DATABASE_HOST , DATABASE_NAME , DATABASE_USER , DATABASE_PASSWORD , 'UTF8' );
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
//Send smss in queue
$this -> send_smss ();
2019-12-17 07:47:11 +01:00
2020-01-07 01:31:34 +01:00
//Read received smss
$this -> read_smss ();
2020-03-04 03:28:34 +01:00
//Stop after 5 minutes of inactivity to avoid useless daemon
if (( microtime ( true ) - $this -> last_message_at ) > $this -> max_inactivity )
{
posix_kill ( getmypid (), SIGTERM ); //Send exit signal to the current process
return false ;
}
2020-01-04 19:30:06 +01:00
}
2020-01-17 18:19:25 +01:00
public function on_start ()
{
//Set last message at to construct time
$this -> last_message_at = microtime ( true );
$this -> msg_queue = msg_get_queue ( $this -> msg_queue_id );
$this -> webhook_queue = msg_get_queue ( QUEUE_ID_WEBHOOK );
//Instanciate adapter
$adapter_class = $this -> phone [ 'adapter' ];
$this -> adapter = new $adapter_class ( $this -> phone [ 'number' ], $this -> phone [ 'adapter_datas' ]);
2020-01-17 18:47:08 +01:00
$this -> logger -> info ( 'Starting Phone daemon with pid ' . getmypid ());
2020-01-17 18:19:25 +01:00
}
public function on_stop ()
{
//Delete queue on daemon close
2020-01-17 18:47:08 +01:00
$this -> logger -> info ( 'Closing queue : ' . $this -> msg_queue_id );
2020-01-17 18:19:25 +01:00
msg_remove_queue ( $this -> msg_queue );
2020-01-17 18:47:08 +01:00
$this -> logger -> info ( 'Stopping Phone daemon with pid ' . getmypid ());
2020-01-17 18:19:25 +01:00
}
public function handle_other_signals ( $signal )
{
2020-01-17 18:47:08 +01:00
$this -> logger -> info ( 'Signal not handled by ' . $this -> name . ' Daemon : ' . $signal );
2020-01-17 18:19:25 +01:00
}
2020-01-04 19:30:06 +01:00
/**
2020-01-17 18:19:25 +01:00
* Send sms .
2020-01-04 19:30:06 +01:00
*/
2020-01-17 18:19:25 +01:00
private function send_smss ()
2020-01-04 19:30:06 +01:00
{
2020-01-07 01:31:34 +01:00
$find_message = true ;
while ( $find_message )
2019-12-12 00:56:30 +01:00
{
2020-01-17 18:19:25 +01:00
//Call message
2020-01-07 17:55:16 +01:00
$msgtype = null ;
$maxsize = 409600 ;
$message = null ;
$error_code = null ;
2020-01-17 18:19:25 +01:00
$success = msg_receive ( $this -> msg_queue , QUEUE_TYPE_SEND_MSG , $msgtype , $maxsize , $message , true , MSG_IPC_NOWAIT , $error_code ); //MSG_IPC_NOWAIT == dont wait if no message found
2020-01-07 17:55:16 +01:00
2020-01-17 18:19:25 +01:00
if ( ! $success && MSG_ENOMSG !== $error_code )
2020-01-07 17:55:16 +01:00
{
2020-01-17 18:47:08 +01:00
$this -> logger -> critical ( 'Error reading MSG SEND Queue, error code : ' . $error_code );
2020-01-17 18:19:25 +01:00
2020-01-07 17:55:16 +01:00
return false ;
}
2020-01-07 01:31:34 +01:00
if ( ! $message )
{
$find_message = false ;
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
continue ;
}
2020-01-17 18:19:25 +01:00
2020-01-08 02:14:38 +01:00
$internal_sended = new \controllers\internals\Sended ( $this -> bdd );
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
//Update last message time
$this -> last_message_at = microtime ( true );
$now = new \DateTime ();
$at = $now -> format ( 'Y-m-d H:i:s' );
$message [ 'at' ] = $at ;
2020-01-17 18:19:25 +01:00
2020-03-04 01:40:47 +01:00
$message [ 'origin' ] = $this -> phone [ 'number' ];
2020-01-17 18:47:08 +01:00
$this -> logger -> info ( 'Try send message : ' . json_encode ( $message ));
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
$sended_sms_uid = $this -> adapter -> send ( $message [ 'destination' ], $message [ 'text' ], $message [ 'flash' ]);
if ( ! $sended_sms_uid )
{
2020-01-17 18:47:08 +01:00
$this -> logger -> error ( 'Failed send message : ' . json_encode ( $message ));
2020-03-05 23:07:07 +01:00
$internal_sended -> create ( $this -> phone [ 'id_user' ], $at , $message [ 'text' ], $message [ 'origin' ], $message [ 'destination' ], $sended_sms_uid , $this -> phone [ 'adapter' ], $message [ 'flash' ], 'failed' );
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
continue ;
}
//Run webhook
$internal_setting = new \controllers\internals\Setting ( $this -> bdd );
$user_settings = $internal_setting -> gets_for_user ( $this -> phone [ 'id_user' ]);
2020-01-07 17:55:16 +01:00
$this -> process_for_webhook ( $message , 'send_sms' , $user_settings );
2020-01-07 01:31:34 +01:00
2020-01-17 18:47:08 +01:00
$this -> logger -> info ( 'Successfully send message : ' . json_encode ( $message ));
2020-01-07 01:31:34 +01:00
2020-03-05 23:07:07 +01:00
$internal_sended -> create ( $this -> phone [ 'id_user' ], $at , $message [ 'text' ], $message [ 'origin' ], $message [ 'destination' ], $sended_sms_uid , $this -> phone [ 'adapter' ], $message [ 'flash' ]);
2019-12-12 00:56:30 +01:00
}
2020-01-07 01:31:34 +01:00
}
/**
2020-03-04 01:40:47 +01:00
* Read smss for a phone .
2020-01-07 01:31:34 +01:00
*/
2020-01-17 18:19:25 +01:00
private function read_smss ()
2020-01-07 01:31:34 +01:00
{
$internal_received = new \controllers\internals\Received ( $this -> bdd );
$internal_setting = new \controllers\internals\Setting ( $this -> bdd );
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
$smss = $this -> adapter -> read ();
if ( ! $smss )
{
return true ;
}
//Get users settings
$user_settings = $internal_setting -> gets_for_user ( $this -> phone [ 'id_user' ]);
//Process smss
foreach ( $smss as $sms )
{
2020-01-17 18:47:08 +01:00
$this -> logger -> info ( 'Receive message : ' . json_encode ( $sms ));
2020-01-07 01:31:34 +01:00
$command_result = $this -> process_for_command ( $sms );
2020-01-08 16:17:12 +01:00
$this -> logger -> info ( 'after command' );
2020-01-07 01:31:34 +01:00
$sms [ 'text' ] = $command_result [ 'text' ];
$is_command = $command_result [ 'is_command' ];
2020-01-06 13:51:02 +01:00
2020-01-07 01:31:34 +01:00
$this -> process_for_webhook ( $sms , 'receive_sms' , $user_settings );
2020-01-06 13:51:02 +01:00
2020-01-08 14:14:40 +01:00
$this -> process_for_transfer ( $sms , $user_settings );
2020-03-05 23:07:07 +01:00
$internal_received -> create ( $this -> phone [ 'id_user' ], $sms [ 'at' ], $sms [ 'text' ], $sms [ 'origin' ], $sms [ 'destination' ], 'unread' , $is_command );
2020-01-07 01:31:34 +01:00
}
}
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
/**
2020-01-17 18:19:25 +01:00
* Process a sms to find if its a command and so execute it .
*
2020-01-07 01:31:34 +01:00
* @ param array $sms : The sms
2020-01-17 18:19:25 +01:00
*
2020-01-07 01:31:34 +01:00
* @ return array : [ 'text' => new sms text , 'is_command' => bool ]
*/
2020-01-17 18:19:25 +01:00
private function process_for_command ( array $sms )
2020-01-07 01:31:34 +01:00
{
2020-01-07 17:55:16 +01:00
$internal_command = new \controllers\internals\Command ( $this -> bdd );
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
$is_command = false ;
$command = $internal_command -> check_for_command ( $this -> phone [ 'id_user' ], $sms [ 'text' ]);
if ( $command )
{
$is_command = true ;
2020-01-07 17:55:16 +01:00
$sms [ 'text' ] = $command [ 'updated_text' ];
2020-01-07 01:31:34 +01:00
exec ( $command [ 'command' ]);
}
2020-01-07 17:55:16 +01:00
return [ 'text' => $sms [ 'text' ], 'is_command' => $is_command ];
2020-01-07 01:31:34 +01:00
}
2019-12-20 18:31:19 +01:00
2020-01-07 01:31:34 +01:00
/**
2020-01-17 18:19:25 +01:00
* Process a sms to transmit a webhook query to webhook daemon if needed .
*
* @ param array $sms : The sms
* @ param string $webhook_type : Type of webhook to trigger
* @ param array $user_settings : Use settings
2020-01-07 01:31:34 +01:00
*/
2020-01-17 18:19:25 +01:00
private function process_for_webhook ( array $sms , string $webhook_type , array $user_settings )
2020-01-07 01:31:34 +01:00
{
if ( ! $user_settings [ 'webhook' ])
{
return false ;
}
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
$internal_webhook = new \controllers\internals\Webhook ( $this -> bdd );
2020-01-17 18:19:25 +01:00
2020-01-07 01:31:34 +01:00
$webhooks = $internal_webhook -> gets_for_type_and_user ( $this -> phone [ 'id_user' ], $webhook_type );
foreach ( $webhooks as $webhook )
{
$message = [
'url' => $webhook [ 'url' ],
'datas' => [
'webhook_type' => $webhook [ 'type' ],
'at' => $sms [ 'at' ],
'text' => $sms [ 'text' ],
'origin' => $sms [ 'origin' ],
'destination' => $sms [ 'destination' ],
],
];
2020-01-07 17:55:16 +01:00
$error_code = null ;
2020-01-17 18:19:25 +01:00
$success = msg_send ( $this -> webhook_queue , QUEUE_TYPE_WEBHOOK , $message , true , true , $error_code );
2020-01-07 17:55:16 +01:00
if ( ! $success )
{
2020-01-17 18:47:08 +01:00
$this -> logger -> critical ( 'Failed send webhook message in queue, error code : ' . $error_code );
2020-01-07 17:55:16 +01:00
}
2020-01-07 01:31:34 +01:00
}
2019-12-12 00:56:30 +01:00
}
2020-01-17 18:19:25 +01:00
2020-01-08 14:14:40 +01:00
/**
2020-01-17 18:19:25 +01:00
* Process a sms to transfer it by mail .
*
* @ param array $sms : The sms
2020-01-08 14:14:40 +01:00
* @ param array $user_settings : Use settings
*/
2020-01-17 18:19:25 +01:00
private function process_for_transfer ( array $sms , array $user_settings )
2020-01-08 14:14:40 +01:00
{
if ( ! $user_settings [ 'transfer' ])
{
return false ;
}
$internal_user = new \controllers\internals\User ( $this -> bdd );
$user = $internal_user -> get ( $this -> phone [ 'id_user' ]);
if ( ! $user )
{
return false ;
}
2020-01-07 01:31:34 +01:00
2020-01-17 18:47:08 +01:00
$this -> logger -> info ( 'Transfer sms to ' . $user [ 'email' ] . ' : ' . json_encode ( $sms ));
2019-12-12 00:56:30 +01:00
2020-01-17 18:19:25 +01:00
\controllers\internals\Tool :: send_email ( $user [ 'email' ], EMAIL_TRANSFER_SMS , [ 'sms' => $sms ]);
2019-12-12 00:56:30 +01:00
}
}