mirror of
https://github.com/ConnectedHumber/Air-Quality-Web
synced 2024-12-22 10:25:01 +00:00
Add performance counter system.
This commit is contained in:
parent
b92621aab6
commit
0006c2a921
15 changed files with 229 additions and 92 deletions
12
api.php
12
api.php
|
@ -12,16 +12,23 @@ $autoloader->addPrefix("AirQuality", "logic");
|
||||||
$autoloader->addPrefix("SBRL", "lib/SBRL");
|
$autoloader->addPrefix("SBRL", "lib/SBRL");
|
||||||
$autoloader->register();
|
$autoloader->register();
|
||||||
|
|
||||||
|
// 1.5: Performance counter
|
||||||
|
$perfcounter = new \SBRL\PerformanceCounter();
|
||||||
|
$perfcounter->start("total");
|
||||||
|
|
||||||
// 2: Settings
|
// 2: Settings
|
||||||
|
$perfcounter->start("settings");
|
||||||
$settings = new \SBRL\TomlConfig(
|
$settings = new \SBRL\TomlConfig(
|
||||||
"data/settings.toml",
|
"data/settings.toml",
|
||||||
"settings.default.toml"
|
"settings.default.toml"
|
||||||
);
|
);
|
||||||
|
$perfcounter->end("settings");
|
||||||
|
|
||||||
|
|
||||||
// 3: Dependency injection
|
// 3: Dependency injection
|
||||||
|
|
||||||
|
$perfcounter->start("di");
|
||||||
|
|
||||||
$di_builder = new DI\ContainerBuilder();
|
$di_builder = new DI\ContainerBuilder();
|
||||||
$di_builder->addDefinitions("di_config.php");
|
$di_builder->addDefinitions("di_config.php");
|
||||||
if($settings->get("env.mode") == "production") {
|
if($settings->get("env.mode") == "production") {
|
||||||
|
@ -37,6 +44,7 @@ if($settings->get("env.mode") == "production") {
|
||||||
|
|
||||||
$di_container = $di_builder->build();
|
$di_container = $di_builder->build();
|
||||||
|
|
||||||
|
$perfcounter->end("di");
|
||||||
|
|
||||||
// 4: Database
|
// 4: Database
|
||||||
|
|
||||||
|
@ -68,6 +76,8 @@ if(!class_exists($handler_name)) {
|
||||||
exit("Error: No action with the name '$action' could be found.");
|
exit("Error: No action with the name '$action' could be found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUTURE: A PSR-7 request/response system would be rather nice here.
|
|
||||||
$handler = $di_container->get($handler_name);
|
$handler = $di_container->get($handler_name);
|
||||||
|
|
||||||
|
$perfcounter->start("handle");
|
||||||
|
// FUTURE: A PSR-7 request/response system would be rather nice here.
|
||||||
$handler->handle();
|
$handler->handle();
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
use SBRL\TomlConfig;
|
use SBRL\TomlConfig;
|
||||||
|
|
||||||
use AirQuality\Database;
|
// use AirQuality\Database;
|
||||||
|
|
||||||
use AirQuality\Repositories\IDeviceRepository;
|
use AirQuality\Repositories\IDeviceRepository;
|
||||||
use AirQuality\Repositories\MariaDBDeviceRepository;
|
use AirQuality\Repositories\MariaDBDeviceRepository;
|
||||||
|
@ -12,15 +12,23 @@ use AirQuality\Repositories\MariaDBMeasurementDataRepository;
|
||||||
use AirQuality\Repositories\IMeasurementTypeRepository;
|
use AirQuality\Repositories\IMeasurementTypeRepository;
|
||||||
use AirQuality\Repositories\MariaDBMeasurementTypeRepository;
|
use AirQuality\Repositories\MariaDBMeasurementTypeRepository;
|
||||||
|
|
||||||
|
use SBRL\PerformanceCounter;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"settings.file_default" => "data/settings.toml",
|
"settings.file_default" => "data/settings.toml",
|
||||||
"settings.file_custom" => "settings.default.toml",
|
"settings.file_custom" => "settings.default.toml",
|
||||||
|
|
||||||
|
// These are created during initalisation, but we want them available via dependency injection too
|
||||||
TomlConfig::class => function(ContainerInterface $c) {
|
TomlConfig::class => function(ContainerInterface $c) {
|
||||||
global $settings;
|
global $settings;
|
||||||
return $settings;
|
return $settings;
|
||||||
},
|
},
|
||||||
|
PerformanceCounter::class => function(ContainerInterface $c) {
|
||||||
|
global $perfcounter;
|
||||||
|
return $perfcounter;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Interfaces that need mapping to their implementations
|
||||||
IDeviceRepository::class => DI\autowire(MariaDBDeviceRepository::class),
|
IDeviceRepository::class => DI\autowire(MariaDBDeviceRepository::class),
|
||||||
IMeasurementDataRepository::class => DI\autowire(MariaDBMeasurementDataRepository::class),
|
IMeasurementDataRepository::class => DI\autowire(MariaDBMeasurementDataRepository::class),
|
||||||
IMeasurementTypeRepository::class => DI\autowire(MariaDBMeasurementTypeRepository::class)
|
IMeasurementTypeRepository::class => DI\autowire(MariaDBMeasurementTypeRepository::class)
|
||||||
|
|
83
lib/SBRL/PerformanceCounter.php
Normal file
83
lib/SBRL/PerformanceCounter.php
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SBRL;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records performance information.
|
||||||
|
*/
|
||||||
|
class PerformanceCounter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* An associative array of performance information.
|
||||||
|
* It should take the form key => [float] | float.
|
||||||
|
* HACK: If the float is the only item in an array, then it hasn't been ended yet.
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of performance counters to hide when rendering.
|
||||||
|
* Useful to keep some counters around for later, but keep them hidden so as to not clutter everything up.
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $hidden = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new performance counter instea
|
||||||
|
*/
|
||||||
|
function __construct() {
|
||||||
|
// code...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts recording the time taken for a given key.
|
||||||
|
* Calling end($key) is optional
|
||||||
|
* @param string $key The key to start recording the time taken for.
|
||||||
|
*/
|
||||||
|
public function start(string $key) {
|
||||||
|
$this->data[$key] = [microtime(true)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends recording the time taken for a given key.
|
||||||
|
* @param string $key The key to end counting for.
|
||||||
|
* @return float The time taken, in milliseconds
|
||||||
|
*/
|
||||||
|
public function end(string $key) {
|
||||||
|
if(empty($this->data[$key]))
|
||||||
|
throw new Exception("Error: We can't end counting for $key because we haven't started yet");
|
||||||
|
|
||||||
|
$this->data[$key] = (microtime(true) - $this->data[$key][0]) * 1000;
|
||||||
|
return $this->data[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the performance information as a short string.
|
||||||
|
* Suitable for sending in a HTTP header, for example.
|
||||||
|
* @return string The rendered performance information.
|
||||||
|
*/
|
||||||
|
public function render() {
|
||||||
|
$result = "";
|
||||||
|
$parts = [];
|
||||||
|
foreach($this->data as $key => $value) {
|
||||||
|
if(in_array($key, $this->hidden))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(is_array($value))
|
||||||
|
$value = $this->end($key);
|
||||||
|
|
||||||
|
$render = round($value, 2) . "ms $key";
|
||||||
|
if($key == "total") {
|
||||||
|
$result .= "$render | ";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$parts[] = $render;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result .= implode(", ", $parts);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,36 +4,40 @@ namespace AirQuality\Actions;
|
||||||
|
|
||||||
use \SBRL\TomlConfig;
|
use \SBRL\TomlConfig;
|
||||||
|
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class Changelog implements IAction {
|
class Changelog implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var \ParsedownExtra */
|
/** @var \ParsedownExtra */
|
||||||
private $parsedown_ext;
|
private $parsedown_ext;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TomlConfig $in_settings,
|
TomlConfig $in_settings,
|
||||||
\ParsedownExtra $in_parsedown_ext) {
|
\ParsedownExtra $in_parsedown_ext,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
$this->parsedown_ext = $in_parsedown_ext;
|
$this->parsedown_ext = $in_parsedown_ext;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
|
|
||||||
// 1: Parse markdown
|
// 1: Parse markdown
|
||||||
|
$this->perfcounter->start("parse");
|
||||||
$result = $this->parsedown_ext->text(file_get_contents(ROOT_DIR."Changelog.md"));
|
$result = $this->parsedown_ext->text(file_get_contents(ROOT_DIR."Changelog.md"));
|
||||||
|
$this->perfcounter->end("parse");
|
||||||
|
|
||||||
|
|
||||||
// 2: Send response
|
// 2: Send response
|
||||||
header("content-length: " . strlen($result));
|
header("content-length: " . strlen($result));
|
||||||
header("content-type: text/html");
|
header("content-type: text/html");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, null));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($result);
|
echo($result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,13 @@ use \AirQuality\Repositories\IMeasurementTypeRepository;
|
||||||
use \AirQuality\ApiResponseSender;
|
use \AirQuality\ApiResponseSender;
|
||||||
|
|
||||||
use \AirQuality\Validator;
|
use \AirQuality\Validator;
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class DeviceData implements IAction {
|
class DeviceData implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var IMeasurementDataRepository */
|
/** @var IMeasurementDataRepository */
|
||||||
private $measurement_repo;
|
private $measurement_repo;
|
||||||
|
@ -30,11 +32,13 @@ class DeviceData implements IAction {
|
||||||
TomlConfig $in_settings,
|
TomlConfig $in_settings,
|
||||||
IMeasurementDataRepository $in_measurement_repo,
|
IMeasurementDataRepository $in_measurement_repo,
|
||||||
IMeasurementTypeRepository $in_type_repo,
|
IMeasurementTypeRepository $in_type_repo,
|
||||||
ApiResponseSender $in_sender) {
|
ApiResponseSender $in_sender,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
$this->measurement_repo = $in_measurement_repo;
|
$this->measurement_repo = $in_measurement_repo;
|
||||||
$this->type_repo = $in_type_repo;
|
$this->type_repo = $in_type_repo;
|
||||||
$this->sender = $in_sender;
|
$this->sender = $in_sender;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
|
|
||||||
$this->validator = new Validator($_GET);
|
$this->validator = new Validator($_GET);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +46,6 @@ class DeviceData implements IAction {
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
// 1: Validate params
|
// 1: Validate params
|
||||||
$this->validator->is_numberish("device-id");
|
$this->validator->is_numberish("device-id");
|
||||||
|
@ -61,7 +64,7 @@ class DeviceData implements IAction {
|
||||||
if(new \DateTime($_GET["start"]) > new \DateTime($_GET["end"])) {
|
if(new \DateTime($_GET["start"]) > new \DateTime($_GET["end"])) {
|
||||||
$this->sender->send_error_plain(
|
$this->sender->send_error_plain(
|
||||||
400, "Error: The start date must be earlier than the end date.", [
|
400, "Error: The start date must be earlier than the end date.", [
|
||||||
[ "x-time-taken", PerfFormatter::format_perf_data($start_time, $start_handle, null) ]
|
[ "x-time-taken", $this->perfcounter->render() ]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -70,18 +73,19 @@ class DeviceData implements IAction {
|
||||||
if(!empty($_GET["average-seconds"]) && intval($_GET["average-seconds"]) == 0) {
|
if(!empty($_GET["average-seconds"]) && intval($_GET["average-seconds"]) == 0) {
|
||||||
$this->sender->send_error_plain(
|
$this->sender->send_error_plain(
|
||||||
400, "Error: That average-seconds value is invalid (an integer greater than 0 required).", [
|
400, "Error: That average-seconds value is invalid (an integer greater than 0 required).", [
|
||||||
[ "x-time-taken", PerfFormatter::format_perf_data($start_time, $start_handle, null) ]
|
[ "x-time-taken", $this->perfcounter->render() ]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->perfcounter->start("sql");
|
||||||
$reading_type_id = $this->type_repo->get_id($_GET["reading-type"]);
|
$reading_type_id = $this->type_repo->get_id($_GET["reading-type"]);
|
||||||
|
|
||||||
if($reading_type_id == null) {
|
if($reading_type_id == null) {
|
||||||
$this->sender->send_error_plain(
|
$this->sender->send_error_plain(
|
||||||
400, "Error: That reading type is invalid.", [
|
400, "Error: That reading type is invalid.", [
|
||||||
[ "x-time-taken", PerfFormatter::format_perf_data($start_time, $start_handle, null) ]
|
[ "x-time-taken", $this->perfcounter->render() ]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -95,19 +99,20 @@ class DeviceData implements IAction {
|
||||||
new \DateTime($_GET["end"]),
|
new \DateTime($_GET["end"]),
|
||||||
!empty($_GET["average-seconds"]) ? intval($_GET["average-seconds"]) : 1
|
!empty($_GET["average-seconds"]) ? intval($_GET["average-seconds"]) : 1
|
||||||
);
|
);
|
||||||
|
$this->perfcounter->end("sql");
|
||||||
|
|
||||||
// 2.5: Validate data from database
|
// 2.5: Validate data from database
|
||||||
if(empty($data)) {
|
if(empty($data)) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
header("content-type: text/plain");
|
header("content-type: text/plain");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, null));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo("Error: No data has been recorded from the device id for that measurement type in the selected time scale or it doesn't exist.");
|
echo("Error: No data has been recorded from the device id for that measurement type in the selected time scale or it doesn't exist.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 3: Serialise data
|
// 3: Serialise data
|
||||||
$start_encode = microtime(true);
|
$this->perfcounter->start("encode");
|
||||||
$response_type = "application/octet-stream";
|
$response_type = "application/octet-stream";
|
||||||
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
||||||
$response = null;
|
$response = null;
|
||||||
|
@ -123,13 +128,14 @@ class DeviceData implements IAction {
|
||||||
$response = ResponseEncoder::encode_csv($data);
|
$response = ResponseEncoder::encode_csv($data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
$this->perfcounter->end("encode");
|
||||||
|
|
||||||
|
|
||||||
// 4: Send response
|
// 4: Send response
|
||||||
header("content-length: " . strlen($response));
|
header("content-length: " . strlen($response));
|
||||||
header("content-type: $response_type");
|
header("content-type: $response_type");
|
||||||
header("content-disposition: inline; filename=$response_suggested_filename");
|
header("content-disposition: inline; filename=$response_suggested_filename");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, $start_encode));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($response);
|
echo($response);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,14 @@ use \AirQuality\Repositories\IMeasurementDataRepository;
|
||||||
use \AirQuality\ApiResponseSender;
|
use \AirQuality\ApiResponseSender;
|
||||||
|
|
||||||
use \AirQuality\Validator;
|
use \AirQuality\Validator;
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class DeviceDataBounds implements IAction {
|
class DeviceDataBounds implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var IMeasurementDataRepository */
|
/** @var IMeasurementDataRepository */
|
||||||
private $measurement_repo;
|
private $measurement_repo;
|
||||||
|
|
||||||
|
@ -24,10 +27,12 @@ class DeviceDataBounds implements IAction {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TomlConfig $in_settings,
|
TomlConfig $in_settings,
|
||||||
IMeasurementDataRepository $in_measurement_repo,
|
IMeasurementDataRepository $in_measurement_repo,
|
||||||
ApiResponseSender $in_sender) {
|
ApiResponseSender $in_sender,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
$this->measurement_repo = $in_measurement_repo;
|
$this->measurement_repo = $in_measurement_repo;
|
||||||
$this->sender = $in_sender;
|
$this->sender = $in_sender;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
|
|
||||||
$this->validator = new Validator($_GET);
|
$this->validator = new Validator($_GET);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +40,6 @@ class DeviceDataBounds implements IAction {
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
// 1: Validate params
|
// 1: Validate params
|
||||||
$this->validator->is_numberish("device-id");
|
$this->validator->is_numberish("device-id");
|
||||||
|
@ -43,29 +47,32 @@ class DeviceDataBounds implements IAction {
|
||||||
|
|
||||||
|
|
||||||
// 2: Pull data from database
|
// 2: Pull data from database
|
||||||
|
$this->perfcounter->start("sql");
|
||||||
$data = $this->measurement_repo->get_device_reading_bounds(
|
$data = $this->measurement_repo->get_device_reading_bounds(
|
||||||
intval($_GET["device-id"])
|
intval($_GET["device-id"])
|
||||||
);
|
);
|
||||||
|
$this->perfcounter->end("sql");
|
||||||
|
|
||||||
// 2.5: Validate data from database
|
// 2.5: Validate data from database
|
||||||
if(empty($data)) {
|
if(empty($data)) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
header("content-type: text/plain");
|
header("content-type: text/plain");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, null));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo("Error: No data has been recorded from the device id or it doesn't exist.");
|
echo("Error: No data has been recorded from the device id or it doesn't exist.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 3: Serialise data
|
// 3: Serialise data
|
||||||
$start_encode = microtime(true);
|
$this->perfcounter->start("encode");
|
||||||
$response = json_encode($data);
|
$response = json_encode($data);
|
||||||
|
$this->perfcounter->end("encode");
|
||||||
|
|
||||||
|
|
||||||
// 4: Send response
|
// 4: Send response
|
||||||
header("content-length: " . strlen($response));
|
header("content-length: " . strlen($response));
|
||||||
header("content-type: application/json");
|
header("content-type: application/json");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, $start_encode));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($response);
|
echo($response);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use \AirQuality\Repositories\IMeasurementTypeRepository;
|
||||||
use \AirQuality\ApiResponseSender;
|
use \AirQuality\ApiResponseSender;
|
||||||
|
|
||||||
use \AirQuality\Validator;
|
use \AirQuality\Validator;
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action that retrieves recent data for a device.
|
* Action that retrieves recent data for a device.
|
||||||
|
@ -17,6 +17,8 @@ use \AirQuality\PerfFormatter;
|
||||||
class DeviceDataRecent implements IAction {
|
class DeviceDataRecent implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var IMeasurementDataRepository */
|
/** @var IMeasurementDataRepository */
|
||||||
private $measurement_repo;
|
private $measurement_repo;
|
||||||
|
@ -33,11 +35,13 @@ class DeviceDataRecent implements IAction {
|
||||||
TomlConfig $in_settings,
|
TomlConfig $in_settings,
|
||||||
IMeasurementDataRepository $in_measurement_repo,
|
IMeasurementDataRepository $in_measurement_repo,
|
||||||
IMeasurementTypeRepository $in_type_repo,
|
IMeasurementTypeRepository $in_type_repo,
|
||||||
ApiResponseSender $in_sender) {
|
ApiResponseSender $in_sender,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
$this->measurement_repo = $in_measurement_repo;
|
$this->measurement_repo = $in_measurement_repo;
|
||||||
$this->type_repo = $in_type_repo;
|
$this->type_repo = $in_type_repo;
|
||||||
$this->sender = $in_sender;
|
$this->sender = $in_sender;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
|
|
||||||
$this->validator = new Validator($_GET);
|
$this->validator = new Validator($_GET);
|
||||||
}
|
}
|
||||||
|
@ -45,7 +49,6 @@ class DeviceDataRecent implements IAction {
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
// 1: Validate params
|
// 1: Validate params
|
||||||
$this->validator->is_numberish("device-id");
|
$this->validator->is_numberish("device-id");
|
||||||
|
@ -69,24 +72,26 @@ class DeviceDataRecent implements IAction {
|
||||||
if($reading_type_id == null) {
|
if($reading_type_id == null) {
|
||||||
$this->sender->send_error_plain(
|
$this->sender->send_error_plain(
|
||||||
400, "Error: That reading type is invalid.", [
|
400, "Error: That reading type is invalid.", [
|
||||||
[ "x-time-taken", PerfFormatter::format_perf_data($start_time, $start_handle, null) ]
|
[ "x-time-taken", $this->perfcounter->render() ]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2: Pull data from database
|
// 2: Pull data from database
|
||||||
|
$this->perfcounter->start("sql");
|
||||||
$data = $this->measurement_repo->get_recent_readings(
|
$data = $this->measurement_repo->get_recent_readings(
|
||||||
intval($_GET["device-id"]),
|
intval($_GET["device-id"]),
|
||||||
$reading_type_id,
|
$reading_type_id,
|
||||||
$count
|
$count
|
||||||
);
|
);
|
||||||
|
$this->perfcounter->end("sql");
|
||||||
|
|
||||||
// 2.5: Validate data from database
|
// 2.5: Validate data from database
|
||||||
if(empty($data)) {
|
if(empty($data)) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
header("content-type: text/plain");
|
header("content-type: text/plain");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, null));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo("Error: No data has been recorded from the device id for that measurement type in the selected time scale or it doesn't exist.");
|
echo("Error: No data has been recorded from the device id for that measurement type in the selected time scale or it doesn't exist.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +101,7 @@ class DeviceDataRecent implements IAction {
|
||||||
|
|
||||||
// FUTURE: Refactor this into an AbstractAction or something, but the careful not to shift too much work there
|
// FUTURE: Refactor this into an AbstractAction or something, but the careful not to shift too much work there
|
||||||
// We might want to consider a HttpResponse container or something if we can find a decent PSR implementation
|
// We might want to consider a HttpResponse container or something if we can find a decent PSR implementation
|
||||||
$start_encode = microtime(true);
|
$this->perfcounter->start("encode");
|
||||||
$response_type = "application/octet-stream";
|
$response_type = "application/octet-stream";
|
||||||
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
||||||
$response = null;
|
$response = null;
|
||||||
|
@ -112,13 +117,14 @@ class DeviceDataRecent implements IAction {
|
||||||
$response = ResponseEncoder::encode_csv($data);
|
$response = ResponseEncoder::encode_csv($data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
$this->perfcounter->end("encode");
|
||||||
|
|
||||||
|
|
||||||
// 4: Send response
|
// 4: Send response
|
||||||
header("content-length: " . strlen($response));
|
header("content-length: " . strlen($response));
|
||||||
header("content-type: $response_type");
|
header("content-type: $response_type");
|
||||||
header("content-disposition: inline; filename=$response_suggested_filename");
|
header("content-disposition: inline; filename=$response_suggested_filename");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, $start_encode));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($response);
|
echo($response);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,18 @@ namespace AirQuality\Actions;
|
||||||
|
|
||||||
use \SBRL\TomlConfig;
|
use \SBRL\TomlConfig;
|
||||||
use \AirQuality\Repositories\IDeviceRepository;
|
use \AirQuality\Repositories\IDeviceRepository;
|
||||||
|
use \AirQuality\Repositories\IMeasurementTypeRepository;
|
||||||
use \AirQuality\ApiResponseSender;
|
use \AirQuality\ApiResponseSender;
|
||||||
|
|
||||||
use \AirQuality\Validator;
|
use \AirQuality\Validator;
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class DeviceInfo implements IAction {
|
class DeviceInfo implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var IDeviceRepository */
|
/** @var IDeviceRepository */
|
||||||
private $device_repo;
|
private $device_repo;
|
||||||
|
|
||||||
|
@ -27,10 +31,12 @@ class DeviceInfo implements IAction {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TomlConfig $in_settings,
|
TomlConfig $in_settings,
|
||||||
IDeviceRepository $in_device_repo,
|
IDeviceRepository $in_device_repo,
|
||||||
ApiResponseSender $in_sender) {
|
ApiResponseSender $in_sender,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
$this->device_repo = $in_device_repo;
|
$this->device_repo = $in_device_repo;
|
||||||
$this->sender = $in_sender;
|
$this->sender = $in_sender;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
|
|
||||||
$this->validator = new Validator($_GET);
|
$this->validator = new Validator($_GET);
|
||||||
}
|
}
|
||||||
|
@ -38,28 +44,30 @@ class DeviceInfo implements IAction {
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
// 1: Validate params
|
// 1: Validate params
|
||||||
$this->validator->is_numberish("device-id");
|
$this->validator->is_numberish("device-id");
|
||||||
$this->validator->run();
|
$this->validator->run();
|
||||||
|
|
||||||
// 2: Pull data from database
|
// 2: Pull data from database
|
||||||
|
$this->perfcounter->start("sql");
|
||||||
$data = $this->device_repo->get_device_info_ext(
|
$data = $this->device_repo->get_device_info_ext(
|
||||||
$_GET["device-id"]
|
$_GET["device-id"]
|
||||||
);
|
);
|
||||||
|
$this->perfcounter->end("sql");
|
||||||
|
|
||||||
// 2.5: Validate data from database
|
// 2.5: Validate data from database
|
||||||
if(empty($data)) {
|
if(empty($data)) {
|
||||||
$this->sender->send_error_plain(404, "Error: No data could be found for that device id.", [
|
$this->sender->send_error_plain(404, "Error: No data could be found for that device id.", [
|
||||||
[ "x-time-taken: ", PerfFormatter::format_perf_data($start_time, $start_handle, null) ]
|
[ "x-time-taken: ", $this->perfcounter->render() ]
|
||||||
]);
|
]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3: Serialise data
|
// 3: Serialise data
|
||||||
$start_encode = microtime(true);
|
$this->perfcounter->start("encode");
|
||||||
$response = json_encode($data);
|
$response = json_encode($data);
|
||||||
|
$this->perfcounter->end("encode");
|
||||||
|
|
||||||
// 4: Send response
|
// 4: Send response
|
||||||
|
|
||||||
|
@ -70,7 +78,7 @@ class DeviceInfo implements IAction {
|
||||||
|
|
||||||
header("content-length: " . strlen($response));
|
header("content-length: " . strlen($response));
|
||||||
header("content-type: application/json");
|
header("content-type: application/json");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, $start_encode));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($response);
|
echo($response);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,13 @@ use \AirQuality\Repositories\IMeasurementTypeRepository;
|
||||||
use \AirQuality\ApiResponseSender;
|
use \AirQuality\ApiResponseSender;
|
||||||
|
|
||||||
use \AirQuality\Validator;
|
use \AirQuality\Validator;
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class FetchData implements IAction {
|
class FetchData implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var IMeasurementDataRepository */
|
/** @var IMeasurementDataRepository */
|
||||||
private $measurement_repo;
|
private $measurement_repo;
|
||||||
|
@ -30,11 +32,13 @@ class FetchData implements IAction {
|
||||||
TomlConfig $in_settings,
|
TomlConfig $in_settings,
|
||||||
IMeasurementDataRepository $in_measurement_repo,
|
IMeasurementDataRepository $in_measurement_repo,
|
||||||
IMeasurementTypeRepository $in_type_repo,
|
IMeasurementTypeRepository $in_type_repo,
|
||||||
ApiResponseSender $in_sender) {
|
ApiResponseSender $in_sender,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
$this->measurement_repo = $in_measurement_repo;
|
$this->measurement_repo = $in_measurement_repo;
|
||||||
$this->type_repo = $in_type_repo;
|
$this->type_repo = $in_type_repo;
|
||||||
$this->sender = $in_sender;
|
$this->sender = $in_sender;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
|
|
||||||
$this->validator = new Validator($_GET);
|
$this->validator = new Validator($_GET);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +46,6 @@ class FetchData implements IAction {
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
// 1: Validate params
|
// 1: Validate params
|
||||||
$this->validator->is_datetime("datetime");
|
$this->validator->is_datetime("datetime");
|
||||||
|
@ -58,7 +61,7 @@ class FetchData implements IAction {
|
||||||
if($measurement_type_id == null) {
|
if($measurement_type_id == null) {
|
||||||
$this->sender->send_error_plain(
|
$this->sender->send_error_plain(
|
||||||
400, "Error: That reading type is invalid.", [
|
400, "Error: That reading type is invalid.", [
|
||||||
[ "x-time-taken", PerfFormatter::format_perf_data($start_time, $start_handle, null) ]
|
[ "x-time-taken", $this->perfcounter->render() ]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -66,24 +69,26 @@ class FetchData implements IAction {
|
||||||
|
|
||||||
|
|
||||||
// 2: Pull data from database
|
// 2: Pull data from database
|
||||||
|
$this->perfcounter->start("sql");
|
||||||
$data = $this->measurement_repo->get_readings_by_date(
|
$data = $this->measurement_repo->get_readings_by_date(
|
||||||
new \DateTime($_GET["datetime"]),
|
new \DateTime($_GET["datetime"]),
|
||||||
$measurement_type_id
|
$measurement_type_id
|
||||||
);
|
);
|
||||||
|
$this->perfcounter->end("sql");
|
||||||
|
|
||||||
|
|
||||||
// 2.5: Validate data from database
|
// 2.5: Validate data from database
|
||||||
if(empty($data)) {
|
if(empty($data)) {
|
||||||
$this->sender->send_error_plain(404,
|
$this->sender->send_error_plain(404,
|
||||||
"Error: No data could be found for that timestamp.",
|
"Error: No data could be found for that timestamp.",
|
||||||
[ PerfFormatter::format_perf_data($start_time, $start_handle, null) ]
|
[ [ "x-time-taken", $this->perfcounter->render() ] ]
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 3: Serialise data
|
// 3: Serialise data
|
||||||
$start_encode = microtime(true);
|
$this->perfcounter->start("encode");
|
||||||
$response_type = "application/octet-stream";
|
$response_type = "application/octet-stream";
|
||||||
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
||||||
$response = null;
|
$response = null;
|
||||||
|
@ -99,6 +104,7 @@ class FetchData implements IAction {
|
||||||
$response = ResponseEncoder::encode_csv($data);
|
$response = ResponseEncoder::encode_csv($data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
$this->perfcounter->end("encode");
|
||||||
|
|
||||||
|
|
||||||
// 4: Send response
|
// 4: Send response
|
||||||
|
@ -111,7 +117,7 @@ class FetchData implements IAction {
|
||||||
header("content-type: $response_type");
|
header("content-type: $response_type");
|
||||||
header("content-length: " . strlen($response));
|
header("content-length: " . strlen($response));
|
||||||
header("content-disposition: inline; filename=$response_suggested_filename");
|
header("content-disposition: inline; filename=$response_suggested_filename");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, $start_encode));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($response);
|
echo($response);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,25 +4,27 @@ namespace AirQuality\Actions;
|
||||||
|
|
||||||
use \SBRL\TomlConfig;
|
use \SBRL\TomlConfig;
|
||||||
|
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class Index implements IAction {
|
class Index implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var \ParsedownExtra */
|
/** @var \ParsedownExtra */
|
||||||
private $parsedown_ext;
|
private $parsedown_ext;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TomlConfig $in_settings) {
|
TomlConfig $in_settings,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
$this->perfcounter->start("handle");
|
||||||
|
|
||||||
|
|
||||||
// 1: Parse markdown
|
// 1: Parse markdown
|
||||||
$result = "Welcome to the Air Quality Web HTTP API!
|
$result = "Welcome to the Air Quality Web HTTP API!
|
||||||
|
@ -38,7 +40,7 @@ Note that if you have deployed your own version of the air quality web interface
|
||||||
// 2: Send response
|
// 2: Send response
|
||||||
header("content-length: " . strlen($result));
|
header("content-length: " . strlen($result));
|
||||||
header("content-type: text/plain");
|
header("content-type: text/plain");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, null));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($result);
|
echo($result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,14 @@ use \SBRL\ResponseEncoder;
|
||||||
use \AirQuality\Repositories\IDeviceRepository;
|
use \AirQuality\Repositories\IDeviceRepository;
|
||||||
use \AirQuality\ApiResponseSender;
|
use \AirQuality\ApiResponseSender;
|
||||||
|
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class ListDevices implements IAction {
|
class ListDevices implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
/** @var IDeviceRepository */
|
/** @var IDeviceRepository */
|
||||||
private $device_repo;
|
private $device_repo;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var ApiResponseSender */
|
/** @var ApiResponseSender */
|
||||||
private $sender;
|
private $sender;
|
||||||
|
@ -21,16 +22,17 @@ class ListDevices implements IAction {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TomlConfig $in_settings,
|
TomlConfig $in_settings,
|
||||||
IDeviceRepository $in_device_repo,
|
IDeviceRepository $in_device_repo,
|
||||||
ApiResponseSender $in_sender) {
|
ApiResponseSender $in_sender,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
$this->device_repo = $in_device_repo;
|
$this->device_repo = $in_device_repo;
|
||||||
$this->sender = $in_sender;
|
$this->sender = $in_sender;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
// 1: Parse & validate parameters
|
// 1: Parse & validate parameters
|
||||||
$only_with_location = !empty($_GET["only-with-location"]);
|
$only_with_location = !empty($_GET["only-with-location"]);
|
||||||
|
@ -45,21 +47,23 @@ class ListDevices implements IAction {
|
||||||
|
|
||||||
|
|
||||||
// 2: Pull data from database
|
// 2: Pull data from database
|
||||||
|
$this->perfcounter->start("sql");
|
||||||
$data = $this->device_repo->get_all_devices($only_with_location);
|
$data = $this->device_repo->get_all_devices($only_with_location);
|
||||||
|
$this->perfcounter->end("sql");
|
||||||
|
|
||||||
|
|
||||||
// 2.5: Validate data from database
|
// 2.5: Validate data from database
|
||||||
if(empty($data)) {
|
if(empty($data)) {
|
||||||
$this->sender->send_error_plain(404,
|
$this->sender->send_error_plain(404,
|
||||||
"Error: No devices are currently present in the system.",
|
"Error: No devices are currently present in the system.",
|
||||||
[ "x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, null) ]
|
[ "x-time-taken: ", $this->perfcounter->render() ]
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 3: Serialise data
|
// 3: Serialise data
|
||||||
$start_encode = microtime(true);
|
$this->perfcounter->start("encode");
|
||||||
$response = null;
|
$response = null;
|
||||||
$response_type = "application/octet-stream";
|
$response_type = "application/octet-stream";
|
||||||
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
||||||
|
@ -75,6 +79,7 @@ class ListDevices implements IAction {
|
||||||
$response = ResponseEncoder::encode_csv($data);
|
$response = ResponseEncoder::encode_csv($data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
$this->perfcounter->end("encode");
|
||||||
|
|
||||||
// 4: Send response
|
// 4: Send response
|
||||||
|
|
||||||
|
@ -84,7 +89,7 @@ class ListDevices implements IAction {
|
||||||
header("content-length: " . strlen($response));
|
header("content-length: " . strlen($response));
|
||||||
header("content-type: $response_type");
|
header("content-type: $response_type");
|
||||||
header("content-disposition: inline; filename=$response_suggested_filename");
|
header("content-disposition: inline; filename=$response_suggested_filename");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, $start_encode));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($response);
|
echo($response);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,13 @@ use \SBRL\ResponseEncoder;
|
||||||
use \AirQuality\Repositories\IMeasurementTypeRepository;
|
use \AirQuality\Repositories\IMeasurementTypeRepository;
|
||||||
use \AirQuality\ApiResponseSender;
|
use \AirQuality\ApiResponseSender;
|
||||||
|
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class ListReadingTypes implements IAction {
|
class ListReadingTypes implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
/** @var IMeasurementTypeRepository */
|
/** @var IMeasurementTypeRepository */
|
||||||
private $types_repo;
|
private $types_repo;
|
||||||
|
|
||||||
|
@ -21,16 +23,17 @@ class ListReadingTypes implements IAction {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TomlConfig $in_settings,
|
TomlConfig $in_settings,
|
||||||
IMeasurementTypeRepository $in_types_repo,
|
IMeasurementTypeRepository $in_types_repo,
|
||||||
ApiResponseSender $in_sender) {
|
ApiResponseSender $in_sender,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
$this->types_repo = $in_types_repo;
|
$this->types_repo = $in_types_repo;
|
||||||
$this->sender = $in_sender;
|
$this->sender = $in_sender;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
// 1: Parse & validate parameters
|
// 1: Parse & validate parameters
|
||||||
$device_id = !empty($_GET["device-id"]) ? intval($_GET["device-id"]) : null;
|
$device_id = !empty($_GET["device-id"]) ? intval($_GET["device-id"]) : null;
|
||||||
|
@ -45,10 +48,13 @@ class ListReadingTypes implements IAction {
|
||||||
|
|
||||||
// 1: Pull data from database
|
// 1: Pull data from database
|
||||||
$data = null;
|
$data = null;
|
||||||
|
|
||||||
|
$this->perfcounter->start("sql");
|
||||||
if(!is_int($device_id))
|
if(!is_int($device_id))
|
||||||
$data = $this->types_repo->get_all_types();
|
$data = $this->types_repo->get_all_types();
|
||||||
else
|
else
|
||||||
$data = $this->types_repo->get_types_by_device($device_id);
|
$data = $this->types_repo->get_types_by_device($device_id);
|
||||||
|
$this->perfcounter->end("sql");
|
||||||
|
|
||||||
// 1.5: Validate data from database
|
// 1.5: Validate data from database
|
||||||
if(empty($data)) {
|
if(empty($data)) {
|
||||||
|
@ -56,7 +62,7 @@ class ListReadingTypes implements IAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3: Serialise data
|
// 3: Serialise data
|
||||||
$start_encode = microtime(true);
|
$this->perfcounter->start("encode");
|
||||||
$response = null;
|
$response = null;
|
||||||
$response_type = "application/octet-stream";
|
$response_type = "application/octet-stream";
|
||||||
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
$response_suggested_filename = "data-" . date(\DateTime::ATOM) . "";
|
||||||
|
@ -72,6 +78,7 @@ class ListReadingTypes implements IAction {
|
||||||
$response = ResponseEncoder::encode_csv($data);
|
$response = ResponseEncoder::encode_csv($data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
$this->perfcounter->end("encode");
|
||||||
|
|
||||||
// 4: Send response
|
// 4: Send response
|
||||||
|
|
||||||
|
@ -81,7 +88,7 @@ class ListReadingTypes implements IAction {
|
||||||
header("content-length: " . strlen($response));
|
header("content-length: " . strlen($response));
|
||||||
header("content-type: $response_type");
|
header("content-type: $response_type");
|
||||||
header("content-disposition: inline; filename=$response_suggested_filename");
|
header("content-disposition: inline; filename=$response_suggested_filename");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, $start_encode));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($response);
|
echo($response);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,23 +4,24 @@ namespace AirQuality\Actions;
|
||||||
|
|
||||||
use \SBRL\TomlConfig;
|
use \SBRL\TomlConfig;
|
||||||
|
|
||||||
use \AirQuality\PerfFormatter;
|
|
||||||
|
|
||||||
class Version implements IAction {
|
class Version implements IAction {
|
||||||
/** @var TomlConfig */
|
/** @var TomlConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
TomlConfig $in_settings) {
|
TomlConfig $in_settings,
|
||||||
|
\SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle() : bool {
|
public function handle() : bool {
|
||||||
global $start_time;
|
global $start_time;
|
||||||
|
|
||||||
$start_handle = microtime(true);
|
|
||||||
|
|
||||||
|
|
||||||
// 1: Parse markdown
|
// 1: Parse markdown
|
||||||
$result = file_get_contents(ROOT_DIR."version");
|
$result = file_get_contents(ROOT_DIR."version");
|
||||||
|
@ -29,7 +30,7 @@ class Version implements IAction {
|
||||||
// 2: Send response
|
// 2: Send response
|
||||||
header("content-length: " . strlen($result));
|
header("content-length: " . strlen($result));
|
||||||
header("content-type: text/plain");
|
header("content-type: text/plain");
|
||||||
header("x-time-taken: " . PerfFormatter::format_perf_data($start_time, $start_handle, null));
|
header("x-time-taken: " . $this->perfcounter->render());
|
||||||
echo($result);
|
echo($result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,16 @@ use Psr\Container\ContainerInterface;
|
||||||
*/
|
*/
|
||||||
class Database
|
class Database
|
||||||
{
|
{
|
||||||
// Whether the database connection should be read only or not.
|
/** @var TomlConfig */
|
||||||
// Defaults to true, as we don't need to write _anything_ to the database.
|
private $settings;
|
||||||
|
/** @var \SBRL\PerformanceCounter */
|
||||||
|
private $perfcounter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the database connection should be read only or not.
|
||||||
|
* Defaults to true, as we don't need to write _anything_ to the database.
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
private const read_only = true;
|
private const read_only = true;
|
||||||
private $connection;
|
private $connection;
|
||||||
|
|
||||||
|
@ -23,13 +31,15 @@ class Database
|
||||||
\PDO::ATTR_AUTOCOMMIT => false
|
\PDO::ATTR_AUTOCOMMIT => false
|
||||||
];
|
];
|
||||||
|
|
||||||
function __construct(TomlConfig $in_settings) {
|
function __construct(TomlConfig $in_settings, \SBRL\PerformanceCounter $in_perfcounter) {
|
||||||
$this->settings = $in_settings;
|
$this->settings = $in_settings;
|
||||||
|
$this->perfcounter = $in_perfcounter;
|
||||||
|
|
||||||
$this->connect(); // Connect automagically
|
$this->connect(); // Connect automagically
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connect() {
|
public function connect() {
|
||||||
|
$this->perfcounter->start("dbconnect");
|
||||||
$this->connection = new \PDO(
|
$this->connection = new \PDO(
|
||||||
$this->get_connection_string(),
|
$this->get_connection_string(),
|
||||||
$this->settings->get("database.username"),
|
$this->settings->get("database.username"),
|
||||||
|
@ -39,6 +49,7 @@ class Database
|
||||||
// Make this connection read-only
|
// Make this connection read-only
|
||||||
if(self::read_only)
|
if(self::read_only)
|
||||||
$this->connection->query("SET SESSION TRANSACTION READ ONLY;");
|
$this->connection->query("SET SESSION TRANSACTION READ ONLY;");
|
||||||
|
$this->perfcounter->end("dbconnect");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function query($sql, $variables = []) {
|
public function query($sql, $variables = []) {
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace AirQuality;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats performance data to be sent in a HTTP header.
|
|
||||||
*/
|
|
||||||
class PerfFormatter {
|
|
||||||
function __construct() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function format_perf_data($start_init, $start_handle, $start_encode) {
|
|
||||||
$now = microtime(true);
|
|
||||||
|
|
||||||
$time_total = round(($now - $start_init) * 1000, 2);
|
|
||||||
$time_setup = round(($start_handle - $start_init) * 1000, 2);
|
|
||||||
$time_handle = round((($start_encode ?? $now) - $start_handle) * 1000, 2);
|
|
||||||
$time_encode = round(($now - $start_encode) * 1000, 2);
|
|
||||||
|
|
||||||
$result = "{$time_total}ms total | {$time_setup}ms setup, {$time_handle}ms handle";
|
|
||||||
if(!empty($start_encode))
|
|
||||||
$result .= ", {$time_encode}ms encode";
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue