diff --git a/adapters/BenchmarkAdapter.php b/adapters/BenchmarkAdapter.php new file mode 100644 index 0000000..3cec1b8 --- /dev/null +++ b/adapters/BenchmarkAdapter.php @@ -0,0 +1,217 @@ + + * + * This source file is subject to the GPL-3.0 license that is bundled + * with this source code in the file LICENSE. + */ + +namespace adapters; + + /** + * Interface for phones adapters + * Phone's adapters allow RaspiSMS to use a platform to communicate with a phone number. + * Its an adapter between internal and external code, as an API, command line software, physical modem, etc. + * + * All Phone Adapters must implement this interface + */ + class BenchmarkAdapter implements AdapterInterface + { + /** + * Datas used to configure interaction with the implemented service. (e.g : Api credentials, ports numbers, etc.). + */ + private $datas; + + /** + * API URL + */ + private $api_url = 'https://jsonplaceholder.typicode.com/posts'; + + /** + * Adapter constructor, called when instanciated by RaspiSMS. + * + * @param json string $datas : JSON string of the datas to configure interaction with the implemented service + */ + public function __construct(string $datas) + { + $this->datas = $datas; + } + + /** + * Classname of the adapter. + */ + public static function meta_classname(): string + { + return __CLASS__; + } + + /** + * Uniq name of the adapter + * It should be the classname of the adapter un snakecase. + */ + public static function meta_uid(): string + { + return 'benchmark_adapter'; + } + + /** + * Name of the adapter. + * It should probably be the name of the service it adapt (e.g : Gammu SMSD, OVH SMS, SIM800L, etc.). + */ + public static function meta_name(): string + { + return 'Benchmark'; + } + + /** + * Description of the adapter. + * A short description of the service the adapter implements. + */ + public static function meta_description(): string + { + return 'A benchmark adaptater that use https://jsonplaceholder.typicode.com to test speed of SMS sending.'; + } + + /** + * List of entries we want in datas for the adapter. + * + * @return array : Eachline line is a field as an array with keys : name, title, description, required + */ + public static function meta_datas_fields(): array + { + return []; + } + + /** + * Does the implemented service support reading smss. + */ + public static function meta_support_read(): bool + { + return false; + } + + /** + * Does the implemented service support flash smss. + */ + public static function meta_support_flash(): bool + { + return true; + } + + /** + * Does the implemented service support status change. + */ + public static function meta_support_status_change(): bool + { + return false; + } + + /** + * Does the implemented service support reception callback. + */ + public static function meta_support_reception(): bool + { + return false; + } + + /** + * Method called to send a SMS to a number. + * + * @param string $destination : Phone number to send the sms to + * @param string $text : Text of the SMS to send + * @param bool $flash : Is the SMS a Flash SMS + * + * @return array : [ + * bool 'error' => false if no error, true else + * ?string 'error_message' => null if no error, else error message + * int 'uid' => Uid of the sms created on success + * ] + */ + public function send(string $destination, string $text, bool $flash = false) + { + $response = [ + 'error' => false, + 'error_message' => null, + 'uid' => null, + ]; + + try + { + $datas = [ + 'sms_text' => $text, + 'sms_destination' => $destination, + 'sms_flash' => $flash, + ]; + + $endpoint = $this->api_url; + + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $endpoint); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($datas)); + $curl_response = curl_exec($curl); + curl_close($curl); + + if (false === $curl_response) + { + $response['error'] = true; + $response['error_message'] = 'HTTP query failed.'; + + return $response; + } + + var_dump($curl_response); + + $response_decode = json_decode($curl_response, true); + if (null === $response_decode) + { + $response['error'] = true; + $response['error_message'] = 'Invalid JSON for response.'; + + return $response; + } + + $response['uid'] = uniqid(); + + return $response; + } + catch (\Throwable $t) + { + $response['error'] = true; + $response['error_message'] = $t->getMessage(); + + return $response; + } + } + + public function read(): array + { + return []; + } + + public static function status_change_callback() + { + return null; + } + + public static function reception_callback(): array + { + return []; + } + + /** + * Method called to verify if the adapter is working correctly + * should be use for exemple to verify that credentials and number are both valid. + * + * @return bool : False on error, true else + */ + public function test(): bool + { + return true; + } + } diff --git a/composer.json b/composer.json index 13f7b51..e8c2754 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "ovh/ovh": "^2.0", "twilio/sdk": "^6.1", "symfony/yaml": "^5.0", - "phpmailer/phpmailer": "^6.1" + "phpmailer/phpmailer": "^6.1", + "symfony/process": "^5.1" }, "require-dev": { } diff --git a/controllers/internals/Console.php b/controllers/internals/Console.php index 30033a8..748ace7 100644 --- a/controllers/internals/Console.php +++ b/controllers/internals/Console.php @@ -67,6 +67,42 @@ namespace controllers\internals; new \daemons\Phone($phone); } + /** + * Send a SMS using a phone + * + * @param $id_phone : Phone id + */ + public function send_sms($id_phone, $message) + { + $bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, 'UTF8'); + $internal_sended = new \controllers\internals\Sended($bdd); + $internal_phone = new \controllers\internals\Phone($bdd); + + $id_phone = (int) $id_phone; + + $phone = $internal_phone->get($id_phone); + if (!$phone) + { + exit(1); + } + + $message = json_decode($message, true); + + $adapter_class = $phone['adapter']; + $adapter = new $adapter_class($phone['adapter_datas']); + $response = $internal_sended->send($adapter, $phone['id_user'], $phone['id'], $message['text'], $message['destination'], $message['flash']); + + var_dump($adapter); + + if ($response['error']) + { + echo $response['error_message'] . "gfuck"; + exit(1); + } + + exit(0); + } + /** * Create a user or update an existing user. * diff --git a/daemons/Phone.php b/daemons/Phone.php index cee8be2..9a8501b 100644 --- a/daemons/Phone.php +++ b/daemons/Phone.php @@ -13,6 +13,8 @@ namespace daemons; use Monolog\Handler\StreamHandler; use Monolog\Logger; +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Process; /** * Phone daemon class. @@ -106,7 +108,7 @@ class Phone extends AbstractDaemon */ private function send_smss() { - $internal_sended = new \controllers\internals\Sended($this->bdd); + $tasks = []; $find_message = true; while ($find_message) @@ -138,16 +140,37 @@ class Phone extends AbstractDaemon //Do message sending $this->logger->info('Try send message : ' . json_encode($message)); + $this->logger->info('with : ' . join(' ', [PWD . '/console.php', 'controllers/internals/Console.php', 'send_sms', '--id_phone=' . escapeshellarg($this->phone['id']), '--message=' . escapeshellarg(json_encode($message))])); - $response = $internal_sended->send($this->adapter, $this->phone['id_user'], $this->phone['id'], $message['text'], $message['destination'], $message['flash']); - if ($response['error']) + $process = new Process([PWD . '/console.php', 'controllers/internals/Console.php', 'send_sms', '--id_phone=' . $this->phone['id'], '--message=' . json_encode($message)]); + $tasks[] = ['message' => $message, 'process' => $process]; + } + + foreach ($tasks as $task) + { + $task['process']->run(); + } + + $done = false; + while (! $done) + { + usleep(0.001 * 1000000); //Micro sleep for perfs + + $done = true; + foreach ($tasks as $task) { - $this->logger->error('Failed send message : ' . json_encode($message) . ' with error : ' . $response['error_message']); + if ($task['process']->isRunning()) { + $done = false; + continue; + } - continue; + if (!$task['process']->isSuccessful()) { + $this->logger->error('Failed send message : ' . json_encode($task['message']) . ' with : ' . $task['process']->getErrorOutput() . $task['process']->getOutput()); + continue; + } + + $this->logger->info('Successfully send message : ' . json_encode($task['message'])); } - - $this->logger->info('Successfully send message : ' . json_encode($message)); } } diff --git a/descartes/autoload.php b/descartes/autoload.php index 87f9c59..b6fd0fe 100644 --- a/descartes/autoload.php +++ b/descartes/autoload.php @@ -15,7 +15,7 @@ $class = str_replace('\\', '/', $class); #Gestion des namespaces if (file_exists(PWD . '/' . $class . '.php')) - { + { require_once(PWD . '/' . $class . '.php'); }