input('show', null); $fromCheckin = $request->input('from', null); $toCheckin = $request->input('to', null); $forceDownload = $request->input('force', false); $cherryPickedCheckins = explode(',', $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) { $tripData->checkins = array_filter( $tripData->checkins, function ($checkin) use ($cherryPickedCheckins) { return in_array($checkin->id, $cherryPickedCheckins); } ); } 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 1–3 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; } }