Files
api/services/nginx/app/classes/bird.php
T
Jeppe Bundgaard 5a59562e35 Add Bird API integration with voice call and flash call support
- Implement Bird API client (`bird.php`) for handling HTTP requests to Bird services.
- Add routes for voice and flash call management (`birdVoiceFlashCallsRoute.php`, `birdNumbersRoute.php`).
- Introduce test cases for voice calls, flash calls, and numbers (`VoiceCallsApiTest.php`, `NumbersAndFlashCallsApiTest.php`).
- Include configuration management classes and APIs for enabling the Bird module and managing API keys (`bird_c.php`).
- Provide OpenAPI specifications for flash call endpoints (`bird-flash-calls.md`).
2026-02-19 12:19:36 +01:00

183 lines
5.5 KiB
PHP

<?php
namespace classes;
require_once WD . '/modules/bird/bird_c.php';
use bird\bird_c;
use Exception;
class bird
{
/**
* Configuration of the Bird module
* @var bird_c|object
*/
public $config;
public function __construct()
{
$this->config = new bird_c();
}
/**
* Ensure module is enabled
* @throws Exception
*/
function requireModuleEnabled(): void
{
if (!$this->config->enabled->isTrue()) {
throw new Exception('The bird module is not enabled');
}
}
/**
* Ensure API key is present
* @throws Exception
*/
function requireValidApiKey(): void
{
$k = $this->config->api_key->getVariableValue();
if ($k === null || $k === '') {
throw new Exception('Invalid API key defined in the config (bird_api_key_c)');
}
}
/**
* Ensure base URL is defined
* @throws Exception
*/
function requireValidServerURL(): void
{
$u = $this->config->server_url->getVariableValue();
if ($u === null || $u === '') {
throw new Exception('Invalid server URL defined in the config (bird_server_url_c)');
}
}
/**
* Send a request to Bird API
* @param string $endpoint e.g. "/v1/devices"
* @param array $data request body
* @param string $method HTTP method (currently only POST supported)
* @return object|array|null
* @throws Exception
*/
function sendRequest(string $endpoint, array $data = [], string $method = 'POST'): object|array|null
{
$this->requireModuleEnabled();
$this->requireValidApiKey();
$this->requireValidServerURL();
return match (strtoupper($method)) {
'POST' => $this->sendPostRequest($endpoint, $data),
'GET' => $this->sendGetRequest($endpoint, $data),
default => throw new Exception('Invalid request method'),
};
}
/**
* Send POST request
* @param string $endpoint
* @param array $data
* @return array|object|null
* @throws Exception
*/
function sendPostRequest(string $endpoint, array $data): array|object|null
{
$this->requireModuleEnabled();
$this->requireValidApiKey();
$this->requireValidServerURL();
$url = rtrim($this->config->server_url->getVariableValue(), '/') . $endpoint;
$headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->config->api_key->getVariableValue(),
];
$body = json_encode($data);
$result = $this->doHttpRequest('POST', $url, $headers, $body);
$status = (int)($result['status_code'] ?? 0);
$response = $result['body'] ?? '';
if ($status >= 400) {
throw new Exception('Bird API request failed with status ' . $status);
}
if ($response === '' || $response === false || $response === null) {
return null;
}
$decoded = json_decode($response);
return $decoded ?? $response;
}
/**
* Low-level HTTP transport (curl). Tests can override this to stub network.
* @param string $method
* @param string $url
* @param array $headers
* @param string $body
* @return array{status_code:int, body:string|false}
* @throws Exception
*/
protected function doHttpRequest(string $method, string $url, array $headers, string $body = ''): array
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$upper = strtoupper($method);
if ($upper === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
} else {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $upper);
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
$err = curl_error($ch);
curl_close($ch);
throw new Exception('cURL error: ' . $err);
}
curl_close($ch);
return [
'status_code' => (int)$code,
'body' => $resp,
];
}
/**
* Send GET request
* @param string $endpoint
* @param array $query
* @return array|object|null
* @throws Exception
*/
function sendGetRequest(string $endpoint, array $query = []): array|object|null
{
$this->requireModuleEnabled();
$this->requireValidApiKey();
$this->requireValidServerURL();
$base = rtrim($this->config->server_url->getVariableValue(), '/');
$url = $base . $endpoint;
if (!empty($query)) {
$qs = http_build_query($query);
$url .= (str_contains($url, '?') ? '&' : '?') . $qs;
}
$headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->config->api_key->getVariableValue(),
];
$result = $this->doHttpRequest('GET', $url, $headers);
$status = (int)($result['status_code'] ?? 0);
$response = $result['body'] ?? '';
if ($status >= 400) {
throw new Exception('Bird API request failed with status ' . $status);
}
if ($response === '' || $response === false || $response === null) {
return null;
}
$decoded = json_decode($response);
return $decoded ?? $response;
}
}