Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client_state database table and endpoints to create and read them #377

Merged
merged 5 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docroot/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ function loadModule($params) {
'updateDataCoverage' => 'WebClient', // Deprecated, remove in V3, replaced by management scripts
'shortenURL' => 'WebClient',
'goto' => 'WebClient',
'saveWebClientState' => 'WebClient',
'getWebClientState' => 'WebClient',
'takeScreenshot' => 'WebClient',
'getRandomSeed' => 'WebClient',
'getJP2Image' => 'JHelioviewer',
Expand Down
4 changes: 2 additions & 2 deletions docroot/statistics/statistics.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var heirarchy = {
"Movies":["buildMovie","getMovieStatus","queueMovie","reQueueMovie","playMovie","downloadMovie","getUserVideos","getObservationDateVideos","uploadMovieToYouTube","checkYouTubeAuth","getYouTubeAuth"],
"Events":["getEventGlossary", "events", "getEvents","getFRMs","getEvent","getEventFRMs","getDefaultEventTypes","getEventsByEventLayers","importEvents"],
"Data":["getRandomSeed","getDataSources","getJP2Header","getDataCoverage","getStatus","getNewsFeed","getDataCoverageTimeline","getClosestData","getSolarBodiesGlossary","getSolarBodies","getTrajectoryTime","sciScript-SSWIDL","sciScript-SunPy","getSciDataScript","updateDataCoverage","getEclipseImage"],
"Other":["shortenURL", "goto", "getUsageStatistics","movie-notifications-granted","movie-notifications-denied","logNotificationStatistics","launchJHelioviewer"],
"Other":["shortenURL", "goto", "getUsageStatistics","movie-notifications-granted","movie-notifications-denied","logNotificationStatistics","launchJHelioviewer", "saveWebClientState", "getWebClientState"],
"WebGL":["getTexture","getGeometryServiceData"]
};

Expand Down Expand Up @@ -644,4 +644,4 @@ function createDeviceChart(id, deviceSummary, size) {

chart = new google.visualization.PieChart(document.getElementById(id));
chart.draw(data, {width: size, height: size*pieHeightScale, colors: colors, title: "Client Devices"});
};
};
6 changes: 6 additions & 0 deletions install/database/2024_05_16_create_client_states_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS `client_states` (
`id` CHAR(64) PRIMARY KEY,
`state` JSON NOT NULL DEFAULT '{}',
`created` DATETIME DEFAULT CURRENT_TIMESTAMP,
`updated` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
14 changes: 14 additions & 0 deletions install/helioviewer/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def setup_database_schema(adminuser, adminpass, dbhost, dbname, dbuser, dbpass,
create_flare_prediction_dataset_table(cursor)
print("Creating flare prediction table")
create_flare_prediction_table(cursor)
print("Creating client_states table")
create_client_states_table(cursor)

return db, cursor

Expand Down Expand Up @@ -888,6 +890,18 @@ def create_rate_limit_table(cursor):
PRIMARY KEY (`datetime`, `identifier`)
) DEFAULT CHARSET=utf8;""")

def create_client_states_table(cursor):
"""
Create table for client states
"""
cursor.execute("""
CREATE TABLE IF NOT EXISTS `client_states` (
`id` CHAR(64) PRIMARY KEY,
`state` JSON NOT NULL DEFAULT '{}',
`created` DATETIME DEFAULT CURRENT_TIMESTAMP,
`updated` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;""")

def create_flare_prediction_table(cursor):
"""
Create table for storing CCMC Flare Predictions
Expand Down
2 changes: 1 addition & 1 deletion scripts/hv_stats/hv_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -2274,7 +2274,7 @@ def add_harea_if_timestamp_in_range(start_time, end_time, color, alpha, label):
"Movies":["buildMovie","getMovieStatus","queueMovie","reQueueMovie","playMovie","downloadMovie","getUserVideos","getObservationDateVideos","uploadMovieToYouTube","checkYouTubeAuth","getYouTubeAuth"],
"Events":["getEventGlossary","getEvents","getFRMs","getEvent","getEventFRMs","getDefaultEventTypes","getEventsByEventLayers","importEvents"],
"Data":["getRandomSeed","getDataSources","getJP2Header","getDataCoverage","getStatus","getNewsFeed","getDataCoverageTimeline","getClosestData","getSolarBodiesGlossary","getSolarBodies","getTrajectoryTime","sciScript-SSWIDL","sciScript-SunPy","getSciDataScript","updateDataCoverage","getEclipseImage"],
"Other":["shortenURL","getUsageStatistics","movie-notifications-granted","movie-notifications-denied","logNotificationStatistics","launchJHelioviewer"],
"Other":["shortenURL","getUsageStatistics","movie-notifications-granted","movie-notifications-denied","logNotificationStatistics","launchJHelioviewer", "saveWebClientState", "getWebClientState"],
"WebGL":["getTexture","getGeometryServiceData"]
};

Expand Down
61 changes: 61 additions & 0 deletions src/Database/ClientState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Client State class for managing client_states table
*
* @category Database
* @package Helioviewer
* @author Kasim Necdet Percinel <[email protected]>
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
* @link https://github.com/Helioviewer-Project/
*/

require_once HV_ROOT_DIR.'/../src/Database/DbConnection.php';

class ClientState extends Database_DbConnection
{
/**
* This function creates or updates the state in database.
*
* @return string
*/
public function upsert(array $state): string
{
$state_json = json_encode($state);
$state_key = hash('sha256',$state_json);

$create_sql = "REPLACE INTO client_states(id, state) VALUES ('%s','%s')";
$create_state_sql = sprintf($create_sql, $state_key, $this->link->real_escape_string($state_json));

// intentionally let exception thrown
$result = $this->query($create_state_sql);
dgarciabriseno marked this conversation as resolved.
Show resolved Hide resolved

return $state_key;
}

/**
* This function finds the client state in db, with our given id
* @param string, state_key is the id of the client state in database
* @return array?
*/
public function find(string $state_key): ?array
{
$find_sql = "SELECT * FROM client_states WHERE id = '%s' LIMIT 1";

$find_state_sql = sprintf($find_sql, $this->link->real_escape_string($state_key));

$query_result = $this->query($find_state_sql);

$res = null;

while ($row = $query_result->fetch_array(MYSQLI_ASSOC)) {
$res = json_decode($row['state'], true);
}

$query_result->close();

return $res;

}

}
14 changes: 13 additions & 1 deletion src/Database/DbConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,17 @@ public function query($query) {
public function setEncoding($encoding) {
mysqli_set_charset($this->link, $encoding);
}

/**
* Deconstructor should be executed when this class instance is not referenced
*
* @return void
*/
public function __destruct() {
if ($this->link) {
mysqli_close($this->link);
}
}

}
?>
?>
4 changes: 4 additions & 0 deletions src/Database/Statistics.php
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,8 @@ private function _createCountsArray(){
'getDataCoverage' => array(),
'updateDataCoverage' => array(),
'shortenURL' => array(),
'saveWebClientState' => array(),
'getWebClientState' => array(),
'goto' => array(),
'takeScreenshot' => array(),
'getRandomSeed' => array(),
Expand Down Expand Up @@ -890,6 +892,8 @@ private function _createSummaryArray(){
'getDataCoverage' => 0,
'updateDataCoverage' => 0,
'shortenURL' => 0,
'saveWebClientState' => 0,
'getWebClientState' => 0,
'goto' => 0,
'takeScreenshot' => 0,
'getRandomSeed' => 0,
Expand Down
93 changes: 88 additions & 5 deletions src/Module/WebClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -619,14 +619,13 @@ public function getNewsFeed() {
}

private static function GetClientUrl(): string {
$base = self::GetApiUrl();
return str_replace('api.', '', $base);
// i.e. http://helioviewer.org
return HV_CLIENT_URL;
}

private static function GetApiUrl(): string {
$http = ($_SERVER['HTTPS'] ?? false) ? 'https' : 'http';
$baseUrl = "$http://".$_SERVER['SERVER_NAME'];
return $baseUrl;
// i.e. http://api.helioviewer.org
return HV_WEB_ROOT_URL;
}

public function goto() {
Expand All @@ -641,6 +640,58 @@ public function goto() {
}
}

/**
* This function saves event state into our database
*
* It saves the event and returns the identifier
*/
public function saveWebClientState() {

require_once HV_ROOT_DIR.'/../src/Database/ClientState.php';

$client_state = new ClientState();

try {

$state_key = $client_state->upsert($this->_params['state']);

return $this->_sendResponse(200, 'OK', $state_key);

} catch (\Exception $e) {
return $this->_sendResponse(500, 'Server Error', '');
}


}

/**
* This function returns the event state for the given id
*/
public function getWebClientState()
{
require_once HV_ROOT_DIR.'/../src/Database/ClientState.php';

$client_state = new ClientState();

try {

$state = $client_state->find($this->_params['state_id']);

if(is_null($state)) {
return $this->_sendResponse(404, 'Not Found', '');
}

return $this->_sendResponse(200, 'OK', $state);

} catch (\Exception $e) {

return $this->_sendResponse(500, 'Server Error', '');

}


}

/**
* Uses bit.ly to generate a shortened URL
*
Expand Down Expand Up @@ -1341,6 +1392,26 @@ private function _getTileCacheFilename($directory, $filename, $scale, $x, $y, $d
);
}

/**
* Helper function to handle response code and response message with
* output result as either JSON or JSONP
*
* @param int $code HTTP response code to return
* @param string $message Message for the response code,
* @param mixed $data Data can be anything
*
* @return void
*/
private function _sendResponse(int $code, string $message, mixed $data) : void
{
http_response_code($code);
$this->_printJSON(json_encode([
'status_code' => $code,
'status_txt' => $message,
'data' => $data,
]));
}

/**
* Helper function to output result as either JSON or JSONP
*
Expand Down Expand Up @@ -1435,6 +1506,18 @@ public function validate() {

switch( $this->_params['action'] ) {

case 'saveWebClientState':
$expected = array(
'required' => array('state'),
);
break;

case 'getWebClientState':
$expected = array(
'required' => array('state_id'),
);
break;

case 'downloadScreenshot':
$expected = array(
'required' => array('id'),
Expand Down
Loading
Loading