Where-in-the-World-is-Ben/app/Http/Controllers/TrackerController.php

254 lines
8.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Http\Controllers;
use DateTime;
use App\Mail\WeeklyDigest;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
class TrackerController extends Controller
{
/**
* Show the list of past trips.
* TODO: Get these from the Wayward API rather than hard-coding them.
*
* @return \Illuminate\View\View
*/
public function show_past_trips_list()
{
return view('past-trips');
}
/**
* Show a trip in tracker app.
*
* @param Request $request
* @param string? $tripId
* @return \Illuminate\View\View
*/
public function show_trip(Request $request, string $tripId = null)
{
$tripId = $tripId ?? config('app.current_trip_id');
if (!$tripId) {
return view('no-trip');
}
$viewMode = $request->input('show', null);
$fromCheckin = $request->input('from', null);
$toCheckin = $request->input('to', null);
$forceDownload = $request->input('force', false);
$cherryPickedCheckins = $request->input('cherrypick', null);
try {
$tripData = $this->get_trip_data($tripId, $forceDownload);
} catch (ConnectException) {
return view(
'error',
[
'message' => "App timed out whilst downloading trip data" .
" from Wayward's servers. They may be down currently."
]
);
}
if ($fromCheckin) {
$tripData->checkins = array_filter(
$tripData->checkins,
function ($checkin) use ($fromCheckin) {
return $checkin->id >= $fromCheckin;
}
);
}
if ($toCheckin) {
$tripData->checkins = array_filter(
$tripData->checkins,
function ($checkin) use ($toCheckin) {
return $checkin->id <= $toCheckin;
}
);
}
if ($cherryPickedCheckins) {
$explodedCherryPickedCheckins = explode(',', $cherryPickedCheckins);
$tripData->checkins = array_filter(
$tripData->checkins,
function ($checkin) use ($explodedCherryPickedCheckins) {
return in_array($checkin->id, $explodedCherryPickedCheckins);
}
);
}
return view(
'tracker',
[
'trip' => $tripData,
'showAllCheckins' => ($viewMode === 'all'),
'fromCheckin' => $fromCheckin,
'toCheckin' => $toCheckin
]
);
}
/**
* Retrieves a trip from the local cache, or from the Wayward API.
*
* The retrieval algorithm is as follows:
* 1. If no local cache exists, download the trip data
* 2. If a local cache exists:
* 1. If the trip is inactive (i.e., finished), use the cache
* 2. If the trip is active:
* 1. If the trip was actively tracking at last check, use the
* cache if it's less than an hour old. Otherwise, download
* the new trip data.
* 2. If the trip was not actively tracking at lest check, use
* the cache if it's less than three hours old. Otherwise,
* download the new trip data.
* 3. If new trip data is downloaded, overwrite any cached data.
*
* @param string $tripId
* @param bool $forceDownload
* @return string
*/
public function get_trip_data(string $tripId, bool $forceDownload = false)
{
$tripFileName = ( $tripId ?? config('app.current_trip_id') ) . '.json';
// Returns the cached trip data if the trip is inactive (i.e., finished)
// or less than 13 hours old, depending on whether it was tracking
// at last check or not.
if (!$forceDownload && Storage::disk('local')->exists($tripFileName)) {
Log::debug("Cached trip file '{$tripFileName}' found...");
$cachedData = json_decode(Storage::disk('local')->get($tripFileName))->trip;
if ($cachedData->is_active) {
Log::debug("Cached trip file '{$tripFileName}' is for an active trip.");
$cachedDataUpdatedAt = new DateTime($cachedData->updated_at);
$now = new DateTime();
$cachingTimeout = ($cachedData->is_tracking) ? 1 : 3;
$cachedDataAge = intval(($now->getTimestamp() - $cachedDataUpdatedAt->getTimestamp()) / 3600);
if ($cachedDataAge <= $cachingTimeout) {
Log::debug(
"Cached trip file '" .
$tripFileName .
"' is younger than " .
$cachingTimeout .
" hours, showing from cache..."
);
return $cachedData;
}
} else {
Log::debug(
"Cached trip file '" .
$tripFileName .
"' is for an old trip, showing from cache..."
);
return $cachedData;
}
}
// Otherwise, download the trip data from the Wayward API.
if ($forceDownload) {
Log::debug("Forcing download for '{$tripFileName}'.");
Storage::disk('local')->delete($tripFileName);
} else {
Log::debug("No cached trip file found for '{$tripFileName}'.");
}
$client = new Client([
'base_uri' => 'https://app.wayward.travel/',
'timeout' => 20.0
]);
$response = $client->get('trip/'.($tripId ?? config('app.current_trip_id')).'/user/zmld8ko6qy7d9j3xvq10/json');
switch ($response->getStatusCode()) {
case 200:
$data = json_decode($response->getBody());
$data->trip->locations = $this->decode_polyline($data->trip->route);
// Cache the downloaded file if it does not exist locally.
if (Storage::disk('local')->missing($tripFileName)) {
Log::debug("Caching new trip file '{$tripFileName}'.");
Storage::disk('local')->put($tripFileName, json_encode($data));
} else {
$cachedData = json_decode(Storage::disk('local')->get($tripFileName));
if (end($data->trip->checkins)->date !== end($cachedData->trip->checkins)->date) {
Log::debug(
"Cached trip file '" .
$tripFileName .
"' has different 'updated_at' time, updating cache..."
);
Storage::disk('local')->put($tripFileName, json_encode($data));
// TODO: Cache photos locally
} else {
Log::debug(
"Cached trip file '" .
$tripFileName .
"' has same 'updated_at' time, showing from cache..."
);
$data = $cachedData;
}
}
return $data->trip;
default:
}
}
/*
* Decode route polyline.
*
* Source: https://github.com/dyaaj/polyline-encoder
*
* @param object $value
* @return object
*/
public function decode_polyline($value)
{
$index = 0;
$points = array();
$lat = 0;
$lng = 0;
$id = 0;
while ($index < strlen($value)) {
$b;
$shift = 0;
$result = 0;
do {
$b = ord(substr($value, $index++, 1)) - 63;
$result |= ($b & 0x1f) << $shift;
$shift += 5;
} while ($b > 31);
$dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1));
$lat += $dlat;
$shift = 0;
$result = 0;
do {
$b = ord(substr($value, $index++, 1)) - 63;
$result |= ($b & 0x1f) << $shift;
$shift += 5;
} while ($b > 31);
$dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1));
$lng += $dlng;
array_push($points, (object)[
'id' => $id++,
'latitude' => $lat/100000,
'longitude' => $lng/100000
]);
}
return $points;
}
}