- fixed final "map update" sync request beforeUnload event
- fixed a bug where "multi character location tracking" is not working on different browser tabs, #446 - fixed a "map sync" bug with 2 open browser tabs with the same character active
This commit is contained in:
@@ -74,15 +74,25 @@ class AccessController extends Controller {
|
||||
return $loginStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* broadcast MapModel to clients
|
||||
* @see broadcastMapData()
|
||||
* @param Pathfinder\MapModel $map
|
||||
*/
|
||||
protected function broadcastMap(Pathfinder\MapModel $map) : void {
|
||||
$this->broadcastMapData($this->getFormattedMapData($map));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* broadcast map data to clients
|
||||
* -> send over TCP Socket
|
||||
* @param Pathfinder\MapModel $map
|
||||
* @throws \Exception
|
||||
* @param array|null $mapData
|
||||
*/
|
||||
protected function broadcastMapData(Pathfinder\MapModel $map) : void {
|
||||
$mapData = $this->getFormattedMapData($map);
|
||||
$this->getF3()->webSocket()->write('mapUpdate', $mapData);
|
||||
protected function broadcastMapData(?array $mapData) : void {
|
||||
if(!empty($mapData)){
|
||||
$this->getF3()->webSocket()->write('mapUpdate', $mapData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,16 +101,27 @@ class AccessController extends Controller {
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getFormattedMapData(Pathfinder\MapModel $map) : array {
|
||||
$mapData = $map->getData();
|
||||
|
||||
return [
|
||||
'config' => $mapData->mapData,
|
||||
'data' => [
|
||||
'systems' => $mapData->systems,
|
||||
'connections' => $mapData->connections,
|
||||
]
|
||||
];
|
||||
/**
|
||||
* @param Pathfinder\MapModel $map
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getFormattedMapData(Pathfinder\MapModel $map) : ?array {
|
||||
$data = null;
|
||||
try{
|
||||
$mapData = $map->getData();
|
||||
$data = [
|
||||
'config' => $mapData->mapData,
|
||||
'data' => [
|
||||
'systems' => $mapData->systems,
|
||||
'connections' => $mapData->connections,
|
||||
]
|
||||
];
|
||||
}catch(\Exception $e){
|
||||
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -660,7 +660,7 @@ class Map extends Controller\AccessController {
|
||||
$this->getF3()->webSocket()->write('mapAccess', $mapAccess);
|
||||
|
||||
// map has (probably) active connections that should receive map Data
|
||||
$this->broadcastMapData($map);
|
||||
$this->broadcastMap($map);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -689,9 +689,12 @@ class Map extends Controller\AccessController {
|
||||
unset($characterData->corporation->rights);
|
||||
}
|
||||
|
||||
// access token
|
||||
$token = bin2hex(random_bytes(16));
|
||||
|
||||
$return->data = [
|
||||
'id' => $activeCharacter->_id,
|
||||
'token' => bin2hex(random_bytes(16)), // token for character access
|
||||
'token' => $token, // character access
|
||||
'characterData' => $characterData,
|
||||
'mapData' => []
|
||||
];
|
||||
@@ -700,7 +703,7 @@ class Map extends Controller\AccessController {
|
||||
foreach($maps as $map){
|
||||
$return->data['mapData'][] = [
|
||||
'id' => $map->_id,
|
||||
'token' => bin2hex(random_bytes(16)), // token for map access
|
||||
'token' => $token, // map access
|
||||
'name' => $map->name
|
||||
];
|
||||
}
|
||||
@@ -722,41 +725,33 @@ class Map extends Controller\AccessController {
|
||||
}
|
||||
|
||||
/**
|
||||
* update map data
|
||||
* -> function is called continuously (trigger) by any active client
|
||||
* @param \Base $f3
|
||||
* @throws Exception
|
||||
* update maps with $mapsData where $character has access to
|
||||
* @param Pathfinder\CharacterModel $character
|
||||
* @param array $mapsData
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function updateData(\Base $f3){
|
||||
$postData = (array)$f3->get('POST');
|
||||
$mapData = (array)$postData['mapData'];
|
||||
$userDataRequired = (bool)$postData['getUserData'];
|
||||
|
||||
protected function updateMapsData(Pathfinder\CharacterModel $character, array $mapsData) : \stdClass {
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
$return->mapData = [];
|
||||
|
||||
$activeCharacter = $this->getCharacter();
|
||||
$mapIdsChanged = [];
|
||||
$maps = $character->getMaps();
|
||||
|
||||
// get current map data
|
||||
$maps = $activeCharacter->getMaps();
|
||||
|
||||
// if there is any system/connection change data submitted -> save new data
|
||||
if( !empty($maps) && !empty($mapData) ){
|
||||
|
||||
// loop all submitted map data that should be saved
|
||||
if(!empty($mapsData) && !empty($maps)){
|
||||
// loop all $mapsData that should be saved
|
||||
// -> currently there will only be ONE map data change submitted -> single loop
|
||||
foreach($mapData as $data){
|
||||
|
||||
foreach($mapsData as $data){
|
||||
$systems = [];
|
||||
$connections = [];
|
||||
|
||||
// check whether system data and/or connection data is send
|
||||
// empty arrays are not included in ajax requests
|
||||
if( isset($data['data']['systems']) ){
|
||||
if(isset($data['data']['systems'])){
|
||||
$systems = (array)$data['data']['systems'];
|
||||
}
|
||||
|
||||
if( isset($data['data']['connections']) ){
|
||||
if(isset($data['data']['connections'])){
|
||||
$connections = (array)$data['data']['connections'];
|
||||
}
|
||||
|
||||
@@ -769,15 +764,15 @@ class Map extends Controller\AccessController {
|
||||
|
||||
// loop current user maps and check for changes
|
||||
foreach($maps as $map){
|
||||
$mapChanged = false;
|
||||
|
||||
// update system data -------------------------------------------------------------------------
|
||||
foreach($systems as $i => $systemData){
|
||||
// check if current system belongs to the current map
|
||||
if($system = $map->getSystemById((int)$systemData['id'])){
|
||||
$system->copyfrom($systemData, ['alias', 'status', 'position', 'locked', 'rallyUpdated', 'rallyPoke']);
|
||||
if($system->save($activeCharacter)){
|
||||
$mapChanged = true;
|
||||
if($system->save($character)){
|
||||
if(!in_array($map->_id, $mapIdsChanged)){
|
||||
$mapIdsChanged[] = $map->_id;
|
||||
}
|
||||
// one system belongs to ONE map -> speed up for multiple maps
|
||||
unset($systemData[$i]);
|
||||
}else{
|
||||
@@ -791,8 +786,10 @@ class Map extends Controller\AccessController {
|
||||
// check if the current connection belongs to the current map
|
||||
if($connection = $map->getConnectionById((int)$connectionData['id'])){
|
||||
$connection->copyfrom($connectionData, ['scope', 'type', 'endpoints']);
|
||||
if($connection->save($activeCharacter)){
|
||||
$mapChanged = true;
|
||||
if($connection->save($character)){
|
||||
if(!in_array($map->_id, $mapIdsChanged)){
|
||||
$mapIdsChanged[] = $map->_id;
|
||||
}
|
||||
// one connection belongs to ONE map -> speed up for multiple maps
|
||||
unset($connectionData[$i]);
|
||||
}else{
|
||||
@@ -800,17 +797,39 @@ class Map extends Controller\AccessController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($mapChanged){
|
||||
$this->broadcastMapData($map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// format map Data for return
|
||||
$return->mapData = $this->getFormattedMapsData($maps);
|
||||
foreach($maps as $map){
|
||||
// format map Data for return/broadcast
|
||||
if($mapData = $this->getFormattedMapData($map)){
|
||||
if(in_array($map->_id, $mapIdsChanged)){
|
||||
$this->broadcastMapData($mapData);
|
||||
}
|
||||
|
||||
$return->mapData[] = $mapData;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* update map data
|
||||
* -> function is called continuously (trigger) by any active client
|
||||
* @param \Base $f3
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateData(\Base $f3){
|
||||
$postData = (array)$f3->get('POST');
|
||||
$mapsData = (array)$postData['mapData'];
|
||||
$userDataRequired = (bool)$postData['getUserData'];
|
||||
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$return = $this->updateMapsData($activeCharacter, $mapsData);
|
||||
|
||||
// if userData is requested -> add it as well
|
||||
// -> Only first trigger call should request this data!
|
||||
@@ -822,18 +841,22 @@ class Map extends Controller\AccessController {
|
||||
}
|
||||
|
||||
/**
|
||||
* get formatted map data
|
||||
* @param Pathfinder\MapModel[] $mapModels
|
||||
* @return array
|
||||
* onUnload map sync
|
||||
* @see https://developer.mozilla.org/docs/Web/API/Navigator/sendBeacon
|
||||
* @param \Base $f3
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getFormattedMapsData(array $mapModels) : array {
|
||||
$mapData = [];
|
||||
foreach($mapModels as $mapModel){
|
||||
$mapData[] = $this->getFormattedMapData($mapModel);
|
||||
}
|
||||
public function updateUnloadData(\Base $f3){
|
||||
$postData = (array)$f3->get('POST');
|
||||
|
||||
return $mapData;
|
||||
if(!empty($mapsData = (string)$postData['mapData'])){
|
||||
$mapsData = (array)json_decode($mapsData, true);
|
||||
if(($jsonError = json_last_error()) === JSON_ERROR_NONE){
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$this->updateMapsData($activeCharacter, $mapsData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1137,7 +1160,7 @@ class Map extends Controller\AccessController {
|
||||
}
|
||||
|
||||
if($mapDataChanged){
|
||||
$this->broadcastMapData($map);
|
||||
$this->broadcastMap($map);
|
||||
}
|
||||
|
||||
return $map;
|
||||
|
||||
@@ -56,7 +56,7 @@ class Connection extends AbstractRestController {
|
||||
$connectionData = $connection->getData();
|
||||
|
||||
// broadcast map changes
|
||||
$this->broadcastMapData($connection->mapId);
|
||||
$this->broadcastMap($connection->mapId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ class Connection extends AbstractRestController {
|
||||
|
||||
// broadcast map changes
|
||||
if(count($deletedConnectionIds)){
|
||||
$this->broadcastMapData($map);
|
||||
$this->broadcastMap($map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ class System extends AbstractRestController {
|
||||
}
|
||||
// broadcast map changes
|
||||
if(count($deletedSystemIds)){
|
||||
$this->broadcastMapData($map);
|
||||
$this->broadcastMap($map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ class System extends AbstractRestController {
|
||||
$newSystem->clearCacheData();
|
||||
|
||||
// broadcast map changes
|
||||
$this->broadcastMapData($newSystem->mapId);
|
||||
$this->broadcastMap($newSystem->mapId);
|
||||
|
||||
return $newSystem;
|
||||
}
|
||||
|
||||
@@ -64,10 +64,15 @@ class CharacterUpdate extends AbstractCron {
|
||||
* @var $characterLog Pathfinder\CharacterLogModel
|
||||
*/
|
||||
if(is_object($characterLog->characterId)){
|
||||
// force characterLog as "updated" even if no changes were made
|
||||
$characterLog->characterId->updateLog([
|
||||
'markUpdated' => true
|
||||
]);
|
||||
if($accessToken = $characterLog->characterId->getAccessToken()){
|
||||
if($this->isOnline($accessToken)){
|
||||
// force characterLog as "updated" even if no changes were made
|
||||
$characterLog->touch('updated');
|
||||
$characterLog->save();
|
||||
}else{
|
||||
$characterLog->erase();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// character_log does not have a character assigned -> delete
|
||||
$characterLog->erase();
|
||||
|
||||
@@ -507,7 +507,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* get ESI API "access_token" from OAuth
|
||||
* @return bool|mixed
|
||||
* @return bool|string
|
||||
*/
|
||||
public function getAccessToken(){
|
||||
$accessToken = false;
|
||||
@@ -797,6 +797,31 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
$this->roleId = $this->requestRole();
|
||||
}
|
||||
|
||||
/**
|
||||
* get online status data from ESI
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getOnlineData(string $accessToken) : array {
|
||||
return self::getF3()->ccpClient()->getCharacterOnlineData($this->_id, $accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* check online state from ESI
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isOnline(string $accessToken) : bool {
|
||||
$isOnline = false;
|
||||
$onlineData = $this->getOnlineData($accessToken);
|
||||
|
||||
if($onlineData['online'] === true){
|
||||
$isOnline = true;
|
||||
}
|
||||
|
||||
return $isOnline;
|
||||
}
|
||||
|
||||
/**
|
||||
* update character log (active system, ...)
|
||||
* -> API request for character log data
|
||||
@@ -815,170 +840,162 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
$this->hasBasicScopes()
|
||||
){
|
||||
// Try to pull data from API
|
||||
if( $accessToken = $this->getAccessToken() ){
|
||||
$onlineData = self::getF3()->ccpClient()->getCharacterOnlineData($this->_id, $accessToken);
|
||||
if($accessToken = $this->getAccessToken()){
|
||||
if($this->isOnline($accessToken)){
|
||||
$locationData = self::getF3()->ccpClient()->getCharacterLocationData($this->_id, $accessToken);
|
||||
|
||||
// check whether character is currently ingame online
|
||||
if(is_bool($onlineData['online'])){
|
||||
if($onlineData['online'] === true){
|
||||
$locationData = self::getF3()->ccpClient()->getCharacterLocationData($this->_id, $accessToken);
|
||||
if( !empty($locationData['system']['id']) ){
|
||||
// character is currently in-game
|
||||
|
||||
if( !empty($locationData['system']['id']) ){
|
||||
// character is currently in-game
|
||||
// get current $characterLog or get new ---------------------------------------------------
|
||||
if( !($characterLog = $this->getLog()) ){
|
||||
// create new log
|
||||
$characterLog = $this->rel('characterLog');
|
||||
}
|
||||
|
||||
// get current $characterLog or get new ---------------------------------------------------
|
||||
if( !($characterLog = $this->getLog()) ){
|
||||
// create new log
|
||||
$characterLog = $this->rel('characterLog');
|
||||
}
|
||||
// get current log data and modify on change
|
||||
$logData = json_decode(json_encode( $characterLog->getData()), true);
|
||||
|
||||
// get current log data and modify on change
|
||||
$logData = json_decode(json_encode( $characterLog->getData()), true);
|
||||
// check system and station data for changes ----------------------------------------------
|
||||
|
||||
// check system and station data for changes ----------------------------------------------
|
||||
// IDs for "systemId", "stationId" that require more data
|
||||
$lookupUniverseIds = [];
|
||||
|
||||
// IDs for "systemId", "stationId" that require more data
|
||||
$lookupUniverseIds = [];
|
||||
if(
|
||||
empty($logData['system']['name']) ||
|
||||
$logData['system']['id'] !== $locationData['system']['id']
|
||||
){
|
||||
// system changed -> request "system name" for current system
|
||||
$lookupUniverseIds[] = $locationData['system']['id'];
|
||||
}
|
||||
|
||||
if( !empty($locationData['station']['id']) ){
|
||||
if(
|
||||
empty($logData['system']['name']) ||
|
||||
$logData['system']['id'] !== $locationData['system']['id']
|
||||
empty($logData['station']['name']) ||
|
||||
$logData['station']['id'] !== $locationData['station']['id']
|
||||
){
|
||||
// system changed -> request "system name" for current system
|
||||
$lookupUniverseIds[] = $locationData['system']['id'];
|
||||
// station changed -> request "station name" for current station
|
||||
$lookupUniverseIds[] = $locationData['station']['id'];
|
||||
}
|
||||
}else{
|
||||
unset($logData['station']);
|
||||
}
|
||||
|
||||
if( !empty($locationData['station']['id']) ){
|
||||
$logData = array_replace_recursive($logData, $locationData);
|
||||
|
||||
// get "more" data for systemId and/or stationId -----------------------------------------
|
||||
if( !empty($lookupUniverseIds) ){
|
||||
// get "more" information for some Ids (e.g. name)
|
||||
$universeData = self::getF3()->ccpClient()->getUniverseNamesData($lookupUniverseIds);
|
||||
|
||||
if( !empty($universeData) && !isset($universeData['error']) ){
|
||||
// We expect max ONE system AND/OR station data, not an array of e.g. systems
|
||||
if(!empty($universeData['system'])){
|
||||
$universeData['system'] = reset($universeData['system']);
|
||||
}
|
||||
if(!empty($universeData['station'])){
|
||||
$universeData['station'] = reset($universeData['station']);
|
||||
}
|
||||
|
||||
$logData = array_replace_recursive($logData, $universeData);
|
||||
}else{
|
||||
// this is important! universe data is a MUST HAVE!
|
||||
$deleteLog = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check structure data for changes -------------------------------------------------------
|
||||
if(!$deleteLog){
|
||||
|
||||
// IDs for "structureId" that require more data
|
||||
$lookupStructureId = 0;
|
||||
if( !empty($locationData['structure']['id']) ){
|
||||
if(
|
||||
empty($logData['station']['name']) ||
|
||||
$logData['station']['id'] !== $locationData['station']['id']
|
||||
empty($logData['structure']['name']) ||
|
||||
$logData['structure']['id'] !== $locationData['structure']['id']
|
||||
){
|
||||
// station changed -> request "station name" for current station
|
||||
$lookupUniverseIds[] = $locationData['station']['id'];
|
||||
// structure changed -> request "structure name" for current station
|
||||
$lookupStructureId = $locationData['structure']['id'];
|
||||
}
|
||||
}else{
|
||||
unset($logData['station']);
|
||||
unset($logData['structure']);
|
||||
}
|
||||
|
||||
$logData = array_replace_recursive($logData, $locationData);
|
||||
|
||||
// get "more" data for systemId and/or stationId -----------------------------------------
|
||||
if( !empty($lookupUniverseIds) ){
|
||||
// get "more" information for some Ids (e.g. name)
|
||||
$universeData = self::getF3()->ccpClient()->getUniverseNamesData($lookupUniverseIds);
|
||||
|
||||
if( !empty($universeData) && !isset($universeData['error']) ){
|
||||
// We expect max ONE system AND/OR station data, not an array of e.g. systems
|
||||
if(!empty($universeData['system'])){
|
||||
$universeData['system'] = reset($universeData['system']);
|
||||
}
|
||||
if(!empty($universeData['station'])){
|
||||
$universeData['station'] = reset($universeData['station']);
|
||||
}
|
||||
|
||||
$logData = array_replace_recursive($logData, $universeData);
|
||||
}else{
|
||||
// this is important! universe data is a MUST HAVE!
|
||||
$deleteLog = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check structure data for changes -------------------------------------------------------
|
||||
if(!$deleteLog){
|
||||
|
||||
// IDs for "structureId" that require more data
|
||||
$lookupStructureId = 0;
|
||||
if( !empty($locationData['structure']['id']) ){
|
||||
if(
|
||||
empty($logData['structure']['name']) ||
|
||||
$logData['structure']['id'] !== $locationData['structure']['id']
|
||||
){
|
||||
// structure changed -> request "structure name" for current station
|
||||
$lookupStructureId = $locationData['structure']['id'];
|
||||
}
|
||||
// get "more" data for structureId ---------------------------------------------------
|
||||
if($lookupStructureId > 0){
|
||||
/**
|
||||
* @var $structureModel Universe\StructureModel
|
||||
*/
|
||||
$structureModel = Universe\AbstractUniverseModel::getNew('StructureModel');
|
||||
$structureModel->loadById($lookupStructureId, $accessToken, $additionalOptions);
|
||||
if(!$structureModel->dry()){
|
||||
$structureData['structure'] = (array)$structureModel->getData();
|
||||
$logData = array_replace_recursive($logData, $structureData);
|
||||
}else{
|
||||
unset($logData['structure']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get "more" data for structureId ---------------------------------------------------
|
||||
if($lookupStructureId > 0){
|
||||
/**
|
||||
* @var $structureModel Universe\StructureModel
|
||||
*/
|
||||
$structureModel = Universe\AbstractUniverseModel::getNew('StructureModel');
|
||||
$structureModel->loadById($lookupStructureId, $accessToken, $additionalOptions);
|
||||
if(!$structureModel->dry()){
|
||||
$structureData['structure'] = (array)$structureModel->getData();
|
||||
$logData = array_replace_recursive($logData, $structureData);
|
||||
}else{
|
||||
unset($logData['structure']);
|
||||
}
|
||||
// check ship data for changes ------------------------------------------------------------
|
||||
if( !$deleteLog ){
|
||||
$shipData = self::getF3()->ccpClient()->getCharacterShipData($this->_id, $accessToken);
|
||||
|
||||
// IDs for "shipTypeId" that require more data
|
||||
$lookupShipTypeId = 0;
|
||||
if( !empty($shipData['ship']['typeId']) ){
|
||||
if(
|
||||
empty($logData['ship']['typeName']) ||
|
||||
$logData['ship']['typeId'] !== $shipData['ship']['typeId']
|
||||
){
|
||||
// ship changed -> request "station name" for current station
|
||||
$lookupShipTypeId = $shipData['ship']['typeId'];
|
||||
}
|
||||
|
||||
// "shipName"/"shipId" could have changed...
|
||||
$logData = array_replace_recursive($logData, $shipData);
|
||||
}else{
|
||||
// ship data should never be empty -> keep current one
|
||||
//unset($logData['ship']);
|
||||
$invalidResponse = true;
|
||||
}
|
||||
|
||||
// check ship data for changes ------------------------------------------------------------
|
||||
if( !$deleteLog ){
|
||||
$shipData = self::getF3()->ccpClient()->getCharacterShipData($this->_id, $accessToken);
|
||||
|
||||
// IDs for "shipTypeId" that require more data
|
||||
$lookupShipTypeId = 0;
|
||||
if( !empty($shipData['ship']['typeId']) ){
|
||||
if(
|
||||
empty($logData['ship']['typeName']) ||
|
||||
$logData['ship']['typeId'] !== $shipData['ship']['typeId']
|
||||
){
|
||||
// ship changed -> request "station name" for current station
|
||||
$lookupShipTypeId = $shipData['ship']['typeId'];
|
||||
}
|
||||
|
||||
// "shipName"/"shipId" could have changed...
|
||||
// get "more" data for shipTypeId ----------------------------------------------------
|
||||
if($lookupShipTypeId > 0){
|
||||
/**
|
||||
* @var $typeModel Universe\TypeModel
|
||||
*/
|
||||
$typeModel = Universe\AbstractUniverseModel::getNew('TypeModel');
|
||||
$typeModel->loadById($lookupShipTypeId, '', $additionalOptions);
|
||||
if(!$typeModel->dry()){
|
||||
$shipData['ship'] = (array)$typeModel->getShipData();
|
||||
$logData = array_replace_recursive($logData, $shipData);
|
||||
}else{
|
||||
// ship data should never be empty -> keep current one
|
||||
//unset($logData['ship']);
|
||||
$invalidResponse = true;
|
||||
}
|
||||
|
||||
// get "more" data for shipTypeId ----------------------------------------------------
|
||||
if($lookupShipTypeId > 0){
|
||||
/**
|
||||
* @var $typeModel Universe\TypeModel
|
||||
*/
|
||||
$typeModel = Universe\AbstractUniverseModel::getNew('TypeModel');
|
||||
$typeModel->loadById($lookupShipTypeId, '', $additionalOptions);
|
||||
if(!$typeModel->dry()){
|
||||
$shipData['ship'] = (array)$typeModel->getShipData();
|
||||
$logData = array_replace_recursive($logData, $shipData);
|
||||
}else{
|
||||
// this is important! ship data is a MUST HAVE!
|
||||
$deleteLog = true;
|
||||
}
|
||||
// this is important! ship data is a MUST HAVE!
|
||||
$deleteLog = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !$deleteLog ){
|
||||
// mark log as "updated" even if no changes were made
|
||||
if($additionalOptions['markUpdated'] === true){
|
||||
$characterLog->touch('updated');
|
||||
}
|
||||
|
||||
$characterLog->setData($logData);
|
||||
$characterLog->characterId = $this->id;
|
||||
$characterLog->save();
|
||||
|
||||
$this->characterLog = $characterLog;
|
||||
if( !$deleteLog ){
|
||||
// mark log as "updated" even if no changes were made
|
||||
if($additionalOptions['markUpdated'] === true){
|
||||
$characterLog->touch('updated');
|
||||
}
|
||||
}else{
|
||||
// systemId should always exists
|
||||
$invalidResponse = true;
|
||||
|
||||
$characterLog->setData($logData);
|
||||
$characterLog->characterId = $this->id;
|
||||
$characterLog->save();
|
||||
|
||||
$this->characterLog = $characterLog;
|
||||
}
|
||||
}else{
|
||||
// user is in-game offline
|
||||
$deleteLog = true;
|
||||
// systemId should always exists
|
||||
$invalidResponse = true;
|
||||
}
|
||||
}else{
|
||||
// online status request failed
|
||||
$invalidResponse = true;
|
||||
// user is in-game offline
|
||||
$deleteLog = true;
|
||||
}
|
||||
}else{
|
||||
// access token request failed
|
||||
|
||||
@@ -287,7 +287,8 @@ EXECUTION_LIMIT = 50
|
||||
|
||||
; CACHE ===========================================================================================
|
||||
[PATHFINDER.CACHE]
|
||||
; Delete character log data if nothing (ship/system/...) changed for X seconds
|
||||
; Checks "character log" data by cronjob after x seconds
|
||||
; If character is ingame offline -> delete "character log"
|
||||
; Syntax: Integer (seconds)
|
||||
; Default: 180
|
||||
CHARACTER_LOG_INACTIVE = 180
|
||||
|
||||
@@ -18,6 +18,9 @@ GET|POST /api/@controller/@action [ajax] = Controller\Api\@cont
|
||||
GET|POST /api/@controller/@action/@arg1 [ajax] = Controller\Api\@controller->@action, 0, 512
|
||||
GET|POST /api/@controller/@action/@arg1/@arg2 [ajax] = Controller\Api\@controller->@action, 0, 512
|
||||
|
||||
; onUnload route or final map sync (@see https://developer.mozilla.org/docs/Web/API/Navigator/sendBeacon)
|
||||
POST /api/map/updateUnloadData = Controller\Api\map->updateUnloadData, 0, 512
|
||||
|
||||
[maps]
|
||||
; REST API wildcard endpoints (not cached, throttled)
|
||||
/api/rest/@controller* [ajax] = Controller\Api\Rest\@controller, 0, 512
|
||||
|
||||
@@ -27,6 +27,7 @@ define(['jquery'], ($) => {
|
||||
getAccessData: '/api/map/getAccessData', // ajax URL - get map access tokens (WebSocket)
|
||||
updateMapData: '/api/map/updateData', // ajax URL - main map update trigger
|
||||
updateUserData: '/api/map/updateUserData', // ajax URL - main map user data trigger
|
||||
updateUnloadData: '/api/map/updateUnloadData', // post URL - for my sync onUnload
|
||||
// map API
|
||||
saveMap: '/api/map/save', // ajax URL - save/update map
|
||||
deleteMap: '/api/map/delete', // ajax URL - delete map
|
||||
|
||||
@@ -121,9 +121,12 @@ define([
|
||||
* -> this removes the port from its port collection and closes it
|
||||
*/
|
||||
let close = () => {
|
||||
let MsgWorkerClose = new MsgWorker('sw:closePort');
|
||||
MsgWorkerClose.task('unsubscribe');
|
||||
sendMessage(MsgWorkerClose);
|
||||
// check if MsgWorker is available (SharedWorker was initialized)
|
||||
if(MsgWorker){
|
||||
let MsgWorkerClose = new MsgWorker('sw:closePort');
|
||||
MsgWorkerClose.task('unsubscribe');
|
||||
sendMessage(MsgWorkerClose);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -549,14 +549,42 @@ define([
|
||||
// initial start of the map update function
|
||||
triggerMapUpdatePing(true);
|
||||
|
||||
/**
|
||||
* handles "final" map update request before window.unload event
|
||||
* -> navigator.sendBeacon browser support required
|
||||
* ajax would not work here, because browsers might cancel the request!
|
||||
* @param mapModule
|
||||
*/
|
||||
let mapUpdateUnload = mapModule => {
|
||||
// get updated map data
|
||||
let mapData = ModuleMap.getMapModuleDataForUpdate(mapModule);
|
||||
|
||||
if(mapData.length){
|
||||
let fd = new FormData();
|
||||
fd.set('mapData', JSON.stringify(mapData));
|
||||
navigator.sendBeacon(Init.path.updateUnloadData, fd);
|
||||
|
||||
console.info('Map update request send by: %O', navigator.sendBeacon);
|
||||
}
|
||||
};
|
||||
|
||||
// Send map update request on tab close/reload, in order to save map changes that
|
||||
// haven´t been saved through default update trigger
|
||||
window.addEventListener('beforeunload', function(e){
|
||||
// close connection to "SharedWorker"
|
||||
// close "SharedWorker" connection
|
||||
MapWorker.close();
|
||||
|
||||
// clear periodic update timeouts
|
||||
// -> this function will handle the final map update request
|
||||
clearUpdateTimeouts();
|
||||
|
||||
// save unsaved map changes ...
|
||||
triggerMapUpdatePing();
|
||||
if(navigator.sendBeacon){
|
||||
mapUpdateUnload(mapModule);
|
||||
}else{
|
||||
// fallback if sendBeacon() is not supported by browser
|
||||
triggerMapUpdatePing();
|
||||
}
|
||||
|
||||
// check if character should be switched on reload or current character should be loaded afterwards
|
||||
let characterSwitch = Boolean( $('body').data('characterSwitch') );
|
||||
@@ -569,7 +597,7 @@ define([
|
||||
|
||||
// IMPORTANT, return false in order to not "abort" ajax request in background!
|
||||
return false;
|
||||
});
|
||||
}, false);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1339,16 +1339,17 @@ define([
|
||||
* collect all data (systems/connections) for export/save from each active map in the map module
|
||||
* if no change detected -> do not attach map data to return array
|
||||
* @param mapModule
|
||||
* @param filter
|
||||
* @returns {Array}
|
||||
*/
|
||||
let getMapModuleDataForUpdate = mapModule => {
|
||||
let getMapModuleDataForUpdate = (mapModule, filter = ['hasId', 'hasChanged']) => {
|
||||
// get all active map elements for module
|
||||
let mapElements = getMaps(mapModule);
|
||||
|
||||
let data = [];
|
||||
for(let i = 0; i < mapElements.length; i++){
|
||||
// get all changed (system / connection) data from this map
|
||||
let mapData = Map.getMapDataForSync($(mapElements[i]), ['hasId', 'hasChanged']);
|
||||
let mapData = Map.getMapDataForSync($(mapElements[i]), filter);
|
||||
if(mapData !== false){
|
||||
if(
|
||||
mapData.data.systems.length > 0 ||
|
||||
|
||||
@@ -182,10 +182,20 @@ self.addEventListener('connect', event => { // jshint ignore:line
|
||||
case 'sw:closePort':
|
||||
port.close();
|
||||
|
||||
socket.send(JSON.stringify({
|
||||
task: MsgWorkerMessage.task(),
|
||||
load: removePort(port)
|
||||
}));
|
||||
// remove port from store
|
||||
// -> charIds managed by closed port
|
||||
let characterIds = removePort(port);
|
||||
|
||||
// check if there are still other ports active that manage removed ports
|
||||
// .. if not -> send "unsubscribe" event to WebSocket server
|
||||
let portsLeft = getPortsByCharacterIds(characterIds);
|
||||
|
||||
if(!portsLeft.length){
|
||||
socket.send(JSON.stringify({
|
||||
task: MsgWorkerMessage.task(),
|
||||
load: characterIds
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case 'ws:close':
|
||||
// closeSocket();
|
||||
|
||||
@@ -27,6 +27,7 @@ define(['jquery'], ($) => {
|
||||
getAccessData: '/api/map/getAccessData', // ajax URL - get map access tokens (WebSocket)
|
||||
updateMapData: '/api/map/updateData', // ajax URL - main map update trigger
|
||||
updateUserData: '/api/map/updateUserData', // ajax URL - main map user data trigger
|
||||
updateUnloadData: '/api/map/updateUnloadData', // post URL - for my sync onUnload
|
||||
// map API
|
||||
saveMap: '/api/map/save', // ajax URL - save/update map
|
||||
deleteMap: '/api/map/delete', // ajax URL - delete map
|
||||
|
||||
@@ -121,9 +121,12 @@ define([
|
||||
* -> this removes the port from its port collection and closes it
|
||||
*/
|
||||
let close = () => {
|
||||
let MsgWorkerClose = new MsgWorker('sw:closePort');
|
||||
MsgWorkerClose.task('unsubscribe');
|
||||
sendMessage(MsgWorkerClose);
|
||||
// check if MsgWorker is available (SharedWorker was initialized)
|
||||
if(MsgWorker){
|
||||
let MsgWorkerClose = new MsgWorker('sw:closePort');
|
||||
MsgWorkerClose.task('unsubscribe');
|
||||
sendMessage(MsgWorkerClose);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -549,14 +549,42 @@ define([
|
||||
// initial start of the map update function
|
||||
triggerMapUpdatePing(true);
|
||||
|
||||
/**
|
||||
* handles "final" map update request before window.unload event
|
||||
* -> navigator.sendBeacon browser support required
|
||||
* ajax would not work here, because browsers might cancel the request!
|
||||
* @param mapModule
|
||||
*/
|
||||
let mapUpdateUnload = mapModule => {
|
||||
// get updated map data
|
||||
let mapData = ModuleMap.getMapModuleDataForUpdate(mapModule);
|
||||
|
||||
if(mapData.length){
|
||||
let fd = new FormData();
|
||||
fd.set('mapData', JSON.stringify(mapData));
|
||||
navigator.sendBeacon(Init.path.updateUnloadData, fd);
|
||||
|
||||
console.info('Map update request send by: %O', navigator.sendBeacon);
|
||||
}
|
||||
};
|
||||
|
||||
// Send map update request on tab close/reload, in order to save map changes that
|
||||
// haven´t been saved through default update trigger
|
||||
window.addEventListener('beforeunload', function(e){
|
||||
// close connection to "SharedWorker"
|
||||
// close "SharedWorker" connection
|
||||
MapWorker.close();
|
||||
|
||||
// clear periodic update timeouts
|
||||
// -> this function will handle the final map update request
|
||||
clearUpdateTimeouts();
|
||||
|
||||
// save unsaved map changes ...
|
||||
triggerMapUpdatePing();
|
||||
if(navigator.sendBeacon){
|
||||
mapUpdateUnload(mapModule);
|
||||
}else{
|
||||
// fallback if sendBeacon() is not supported by browser
|
||||
triggerMapUpdatePing();
|
||||
}
|
||||
|
||||
// check if character should be switched on reload or current character should be loaded afterwards
|
||||
let characterSwitch = Boolean( $('body').data('characterSwitch') );
|
||||
@@ -569,7 +597,7 @@ define([
|
||||
|
||||
// IMPORTANT, return false in order to not "abort" ajax request in background!
|
||||
return false;
|
||||
});
|
||||
}, false);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1339,16 +1339,17 @@ define([
|
||||
* collect all data (systems/connections) for export/save from each active map in the map module
|
||||
* if no change detected -> do not attach map data to return array
|
||||
* @param mapModule
|
||||
* @param filter
|
||||
* @returns {Array}
|
||||
*/
|
||||
let getMapModuleDataForUpdate = mapModule => {
|
||||
let getMapModuleDataForUpdate = (mapModule, filter = ['hasId', 'hasChanged']) => {
|
||||
// get all active map elements for module
|
||||
let mapElements = getMaps(mapModule);
|
||||
|
||||
let data = [];
|
||||
for(let i = 0; i < mapElements.length; i++){
|
||||
// get all changed (system / connection) data from this map
|
||||
let mapData = Map.getMapDataForSync($(mapElements[i]), ['hasId', 'hasChanged']);
|
||||
let mapData = Map.getMapDataForSync($(mapElements[i]), filter);
|
||||
if(mapData !== false){
|
||||
if(
|
||||
mapData.data.systems.length > 0 ||
|
||||
|
||||
@@ -182,10 +182,20 @@ self.addEventListener('connect', event => { // jshint ignore:line
|
||||
case 'sw:closePort':
|
||||
port.close();
|
||||
|
||||
socket.send(JSON.stringify({
|
||||
task: MsgWorkerMessage.task(),
|
||||
load: removePort(port)
|
||||
}));
|
||||
// remove port from store
|
||||
// -> charIds managed by closed port
|
||||
let characterIds = removePort(port);
|
||||
|
||||
// check if there are still other ports active that manage removed ports
|
||||
// .. if not -> send "unsubscribe" event to WebSocket server
|
||||
let portsLeft = getPortsByCharacterIds(characterIds);
|
||||
|
||||
if(!portsLeft.length){
|
||||
socket.send(JSON.stringify({
|
||||
task: MsgWorkerMessage.task(),
|
||||
load: characterIds
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case 'ws:close':
|
||||
// closeSocket();
|
||||
|
||||
Reference in New Issue
Block a user