/// <summary> /// Tests app resource URI as key in dictionies /// </summary> public void TestKeyInDictionary() { // set up var uri1 = new AppResourceUri(AppResourceUri.ResourceType.FindMeSpotPos, "xxx"); var uri2 = new AppResourceUri(AppResourceUri.ResourceType.GarminInreachPos, "yyy"); var uri3 = new AppResourceUri(AppResourceUri.ResourceType.GarminInreachPos, "yyy"); var dict = new Dictionary <AppResourceUri, int>(); // run + check Assert.IsFalse(dict.Any(), "there must be no items in the dictionary"); dict[uri1] = 42; Assert.IsTrue(dict.Any(), "there must be an item in the dictionary"); Assert.IsTrue(dict.ContainsKey(uri1), "dict must contain value for uri1"); Assert.IsFalse(dict.ContainsKey(uri2), "dict must not contain value for uri1"); dict[uri2] = 64; Assert.AreEqual(2, dict.Count, "there must be 2 items in the dictionary"); dict[uri3] = 128; Assert.AreEqual(2, dict.Count, "there must still be 2 items in the dictionary"); Assert.AreEqual(42, dict[uri1], "value of key with uri 1 must match"); Assert.AreEqual(128, dict[uri2], "value of key with uri 2 must match"); Assert.AreEqual(128, dict[uri3], "value of key with uri 3 must match"); }
/// <summary> /// Retrieves current live track points /// </summary> /// <param name="trackName">track name to use</param> /// <param name="appResourceUri">app resource uri to use</param> /// <returns>loaded live track</returns> private static async Task <Track> GetLiveTrack(string trackName, AppResourceUri appResourceUri) { var dataService = DependencyService.Get <IDataService>(); LiveTrackQueryResult result = await dataService.GetLiveTrackDataAsync( appResourceUri.ToString(), null); var track = new Track { Id = result.Data.ID, Name = trackName ?? result.Data.Name, Description = HtmlConverter.Sanitize(result.Data.Description), IsFlightTrack = true, IsLiveTrack = true, Color = "ff8000", TrackPoints = result.Data.TrackPoints.Select( trackPoint => new TrackPoint( latitude: trackPoint.Latitude, longitude: trackPoint.Longitude, altitude: trackPoint.Altitude, null) { Time = result.Data.TrackStart.AddSeconds(trackPoint.Offset), }).ToList() }; track.CalculateStatistics(); return(track); }
/// <summary> /// Checks next request date if a new request can be made; when not, returns cache entry /// when available. /// </summary> /// <param name="uri">live waypoint ID</param> /// <returns> /// query result from cache, or null when there's no request in cache or when a request /// can be made online /// </returns> private LiveWaypointQueryResult CheckCache(AppResourceUri uri) { if (this.IsNextRequestPossible(uri)) { return(null); } // ask cache string id = uri.ToString(); LiveWaypointData cachedData; lock (this.lockCacheAndQueue) { cachedData = this.liveWaypointCache.ContainsKey(id) ? this.liveWaypointCache[id] : null; } if (cachedData == null) { return(null); } return(new LiveWaypointQueryResult { Data = cachedData, NextRequestDate = this.GetNextRequestDate(uri) }); }
/// <summary> /// Returns a test position, based on the current time /// </summary> /// <param name="uri">live waypoint ID to use</param> /// <returns>live waypoint query result</returns> private Task <LiveWaypointQueryResult> GetTestPosResult(AppResourceUri uri) { DateTimeOffset nextRequestDate = DateTimeOffset.Now + TimeSpan.FromMinutes(1.0); var mapPoint = new MapPoint(47.664601, 11.885455, 0.0); double timeAngleInDegrees = (DateTimeOffset.Now.TimeOfDay.TotalMinutes * 6.0) % 360; double timeAngle = timeAngleInDegrees / 180.0 * Math.PI; mapPoint.Latitude += 0.025 * Math.Sin(timeAngle); mapPoint.Longitude -= 0.025 * Math.Cos(timeAngle); return(Task.FromResult( new LiveWaypointQueryResult { Data = new LiveWaypointData { ID = uri.ToString(), TimeStamp = DateTimeOffset.Now, Longitude = mapPoint.Longitude, Latitude = mapPoint.Latitude, Altitude = mapPoint.Altitude.Value, Name = "Live waypoint test position", Description = "Hello from the Where-to-fly backend services!<br/>" + $"Next request date is {nextRequestDate.ToString()}", DetailsLink = string.Empty }, NextRequestDate = nextRequestDate })); }
/// <summary> /// Adds a new live waypoint resource URI /// </summary> /// <param name="uri">URI as string</param> /// <param name="appResourceUri">app resource URI</param> /// <returns>task to wait on</returns> private static async Task AddLiveWaypoint(string uri, AppResourceUri appResourceUri) { var rawUri = new Uri(uri); string waypointName = "Live Waypoint"; if (!string.IsNullOrEmpty(rawUri.Fragment)) { waypointName = System.Net.WebUtility.UrlDecode(rawUri.Fragment.TrimStart('#')); } Location liveWaypoint = await GetLiveWaypointLocation(waypointName, appResourceUri); if (!await ShowAddLiveWaypointDialog(liveWaypoint)) { return; } await StoreLiveWaypoint(liveWaypoint); App.ShowToast("Live waypoint was loaded."); await NavigationService.GoToMap(); await App.UpdateLastShownPositionAsync(liveWaypoint.MapLocation); App.MapView.AddLocation(liveWaypoint); App.MapView.ZoomToLocation(liveWaypoint.MapLocation); }
/// <summary> /// Opens app resource URI, e.g. a live waypoint /// </summary> /// <param name="uri">app resource URI to open</param> /// <returns>task to wait on</returns> public static async Task OpenAsync(string uri) { try { var appResourceUri = new AppResourceUri(uri); if (!appResourceUri.IsValid) { await App.Current.MainPage.DisplayAlert( Constants.AppTitle, "Not a valid Where-to-fly weblink: " + uri, "OK"); return; } if (!appResourceUri.IsTrackResourceType) { await AddLiveWaypoint(uri, appResourceUri); } else { await AddLiveTrack(uri, appResourceUri); } } catch (Exception ex) { App.LogError(ex); await App.Current.MainPage.DisplayAlert( Constants.AppTitle, "Error while opening weblink: " + ex.Message, "OK"); } }
/// <summary> /// Gets query result for a Find Me SPOT live waypoint ID /// </summary> /// <param name="uri">live waypoint ID</param> /// <returns>live waypoint query result</returns> private async Task <LiveWaypointQueryResult> GetFindMeSpotPosResult(AppResourceUri uri) { var liveWaypointData = await this.findMeSpotTrackerService.GetDataAsync(uri); return(new LiveWaypointQueryResult { Data = liveWaypointData, NextRequestDate = this.findMeSpotTrackerService.GetNextRequestDate(uri) }); }
public void TestLiveWaypointData() { // set up var dataService = new FindMeSpotTrackerDataService(); var uri = new AppResourceUri(AppResourceUri.ResourceType.FindMeSpotPos, "xxx"); // run var liveWaypointData = dataService.GetDataAsync(uri).Result; // check Assert.AreEqual(uri.ToString(), liveWaypointData.ID, "requested ID and app resource URI"); }
/// <summary> /// Gets query result for a Garmin inReach live waypoint ID /// </summary> /// <param name="uri">live waypoint Id</param> /// <returns>live waypoint query result</returns> private async Task <LiveWaypointQueryResult> GetGarminInreachPosResult(AppResourceUri uri) { string mapShareIdentifier = uri.Data; var liveWaypointData = await this.garminInreachService.GetDataAsync(mapShareIdentifier); return(new LiveWaypointQueryResult { Data = liveWaypointData, NextRequestDate = this.garminInreachService.GetNextRequestDate(mapShareIdentifier) }); }
/// <summary> /// Parses a raw live waypoint ID and returns an AppResourceId object from it /// </summary> /// <param name="rawId">raw live waypoint ID</param> /// <returns>live waypoint ID as AppResourceUri object</returns> private static AppResourceUri GetAndCheckLiveWaypointId(string rawId) { string id = System.Net.WebUtility.UrlDecode(rawId); var uri = new AppResourceUri(id); if (!uri.IsValid) { throw new ArgumentException("invalid live waypoint ID", nameof(rawId)); } return(uri); }
public void TestSerializeDeserialize() { // set up var uri = new AppResourceUri("where-to-fly://GarminInreachPos/yyy"); // run string json = JsonConvert.SerializeObject(uri); AppResourceUri uri2 = JsonConvert.DeserializeObject <AppResourceUri>(json); // check Assert.IsTrue(uri2.IsValid, "deserialized uri must be valid"); Assert.AreEqual(uri, uri2, "uris must be equal"); }
public void TestCreateUriFromTypeAndData() { // run var uri1 = new AppResourceUri(AppResourceUri.ResourceType.FindMeSpotPos, "xxx"); var uri2 = new AppResourceUri(AppResourceUri.ResourceType.GarminInreachPos, "yyy"); // check Assert.IsTrue(uri1.IsValid, "uri1 must be valid"); Assert.IsTrue(uri2.IsValid, "uri2 must be valid"); Assert.AreEqual("where-to-fly://findmespotpos/xxx", uri1.ToString(), "uri text and ToString() result must match"); Assert.AreEqual("where-to-fly://garmininreachpos/yyy", uri2.ToString(), "uri text and ToString() result must match"); }
/// <summary> /// Opens app resource URI, e.g. a live waypoint /// </summary> /// <param name="uri">app resource URI to open</param> /// <returns>task to wait on</returns> public static async Task Open(string uri) { try { var appResourceUri = new AppResourceUri(uri); if (!appResourceUri.IsValid) { await App.Current.MainPage.DisplayAlert( Constants.AppTitle, "Not a valid Where-to-fly weblink: " + uri, "OK"); return; } var rawUri = new Uri(uri); string waypointName = "Live Waypoint"; if (!string.IsNullOrEmpty(rawUri.Fragment)) { waypointName = System.Net.WebUtility.UrlDecode(rawUri.Fragment.TrimStart('#')); } var liveWaypoint = await GetLiveWaypointLocation(waypointName, appResourceUri); if (!await ShowAddLiveWaypointDialog(liveWaypoint)) { return; } await StoreLiveWaypoint(liveWaypoint); App.ShowToast("Live waypoint was loaded."); await NavigationService.Instance.NavigateAsync(Constants.PageKeyMapPage, animated : true); App.ZoomToLocation(liveWaypoint.MapLocation); App.UpdateMapLocationsList(); } catch (Exception ex) { App.LogError(ex); await App.Current.MainPage.DisplayAlert( Constants.AppTitle, "Error while opening weblink: " + ex.Message, "OK"); } }
public void TestCreateUriFromString() { // set up string uriText1 = "where-to-fly://FindMeSpotPos/xxx"; string uriText2 = "where-to-fly://GarminInreachPos/yyy"; // run var uri1 = new AppResourceUri(uriText1); var uri2 = new AppResourceUri(uriText2); // check Assert.IsTrue(uri1.IsValid, "uri1 must be valid"); Assert.IsTrue(uri2.IsValid, "uri2 must be valid"); Assert.IsTrue(uriText1.ToLowerInvariant() == uri1.ToString(), "uri text and ToString() result must match"); Assert.IsTrue(uriText2.ToLowerInvariant() == uri2.ToString(), "uri text and ToString() result must match"); }
/// <summary> /// Returns if next request is possible for the given app resource URI /// </summary> /// <param name="uri">live waypoint ID</param> /// <returns> /// true when web service request is possible, false when cache should be used /// </returns> private bool IsNextRequestPossible(AppResourceUri uri) { switch (uri.Type) { case AppResourceUri.ResourceType.FindMeSpotPos: case AppResourceUri.ResourceType.GarminInreachPos: DateTimeOffset nextRequestDate = this.GetNextRequestDate(uri); return(nextRequestDate <= DateTimeOffset.Now); case AppResourceUri.ResourceType.TestPos: return(true); // request is always possible default: Debug.Assert(false, "invalid app resource URI type"); return(false); } }
/// <summary> /// Gets actual live waypoint query result from web services /// </summary> /// <param name="uri">live waypoint ID</param> /// <returns>query result</returns> private async Task <LiveWaypointQueryResult> GetLiveWaypointQueryResult(AppResourceUri uri) { switch (uri.Type) { case AppResourceUri.ResourceType.FindMeSpotPos: return(await this.GetFindMeSpotPosResult(uri)); case AppResourceUri.ResourceType.GarminInreachPos: return(await this.GetGarminInreachPosResult(uri)); case AppResourceUri.ResourceType.TestPos: return(await this.GetTestPosResult(uri)); default: Debug.Assert(false, "invalid app resource URI type"); return(null); } }
/// <summary> /// Returns next request date for live waypoint in given ID /// </summary> /// <param name="uri">live waypoint ID</param> /// <returns>date time offset of next possible request for this ID</returns> private DateTimeOffset GetNextRequestDate(AppResourceUri uri) { switch (uri.Type) { case AppResourceUri.ResourceType.FindMeSpotPos: return(this.findMeSpotTrackerService.GetNextRequestDate(uri)); case AppResourceUri.ResourceType.GarminInreachPos: return(this.garminInreachService.GetNextRequestDate(uri.Data)); case AppResourceUri.ResourceType.TestPos: return(DateTimeOffset.Now + TimeSpan.FromMinutes(1.0)); default: Debug.Assert(false, "invalid app resource URI type"); return(DateTimeOffset.MaxValue); } }
/// <summary> /// Returns live waypoint data for given live waypoint ID. May throw an exception when the /// data is not readily available and must be fetched. /// </summary> /// <param name="rawId">live waypoint ID (maybe urlencoded)</param> /// <returns>live waypoint query result</returns> public async Task <LiveWaypointQueryResult> GetLiveWaypointData(string rawId) { AppResourceUri uri = GetAndCheckLiveWaypointId(rawId); LiveWaypointQueryResult result = this.CheckCache(uri); if (result != null) { return(result); } result = await this.GetLiveWaypointQueryResult(uri); if (result != null) { this.CacheLiveWaypointData(result.Data); } return(result); }
public void TestEquality() { // set up var uri1 = new AppResourceUri(AppResourceUri.ResourceType.FindMeSpotPos, "xxx"); var uri2 = new AppResourceUri(AppResourceUri.ResourceType.GarminInreachPos, "yyy"); var uri3 = new AppResourceUri(AppResourceUri.ResourceType.GarminInreachPos, "yyy"); // run Assert.AreEqual <object>(uri1, uri1, "same objects must be equal"); Assert.AreNotEqual <object>(uri1, uri2, "different objects must be equal"); Assert.AreEqual <object>(uri2, uri3, "different references must be equal"); Assert.AreNotEqual <object>("hello", uri1, "different object types must not be equal"); Assert.AreEqual <AppResourceUri>(uri1, uri1, "same objects must be equal"); Assert.AreNotEqual <AppResourceUri>(uri1, uri2, "different objects must be equal"); Assert.AreEqual <AppResourceUri>(uri2, uri3, "different references must be equal"); Assert.AreNotEqual <AppResourceUri>(null, uri1, "object must not be equal to null"); Assert.AreEqual(uri2.GetHashCode(), uri3.GetHashCode(), "hash codes of same objects must be equal"); }
public void TestParseInvalidUris() { // run Assert.ThrowsException <ArgumentNullException>(() => new AppResourceUri(null)); Assert.ThrowsException <ArgumentException>(() => new AppResourceUri(AppResourceUri.ResourceType.None, "123")); Assert.ThrowsException <ArgumentNullException>(() => new AppResourceUri(AppResourceUri.ResourceType.FindMeSpotPos, null)); Assert.ThrowsException <UriFormatException>(() => new AppResourceUri(string.Empty)); var uri1 = new AppResourceUri("https://github.com/"); var uri2 = new AppResourceUri("where-to-fly://"); var uri3 = new AppResourceUri("where-to-fly://xxx"); var uri4 = new AppResourceUri("where-to-fly://findmespotpos/"); // check Assert.IsFalse(uri1.IsValid, "uri must be invalid"); Assert.IsFalse(uri2.IsValid, "uri must be invalid"); Assert.IsFalse(uri3.IsValid, "uri must be invalid"); Assert.IsFalse(uri4.IsValid, "uri must be invalid"); Assert.AreEqual("invalid", uri1.ToString(), "invalid URI must return proper ToString() result"); }
/// <summary> /// GET handler when page parameters uri and name are passed to set a custom live waypoint /// to show in the page. /// </summary> /// <param name="uri">live waypoint uri to show</param> /// <param name="name">name of live waypoint to show</param> public void OnGet(string uri, string name) { if (string.IsNullOrEmpty(uri)) { return; } var liveWaypointUri = new AppResourceUri(uri); if (liveWaypointUri.IsValid) { this.LiveTrackingInfoList = new List <LiveTrackingInfo> { new LiveTrackingInfo { Name = name ?? "Live Waypoint", Uri = liveWaypointUri.ToString(), IsLiveTrack = liveWaypointUri.IsTrackResourceType, } }; } }
/// <summary> /// Returns data for live waypoint with given app resource URI /// </summary> /// <param name="uri">live waypoint ID</param> /// <returns>live waypoint data</returns> public async Task <LiveWaypointData> GetDataAsync(AppResourceUri uri) { Debug.Assert( uri.Type == AppResourceUri.ResourceType.FindMeSpotPos, "app resource URI must be of FindMeSpotPos type!"); string liveFeedId = uri.Data; Model.RootObject result = null; if (liveFeedId != "xxx") { result = await this.findMeSpotApi.GetLatest(liveFeedId); this.lastRequest = DateTimeOffset.Now; } else { // support for unit test string feedText = @"{""response"":{""feedMessageResponse"":{""count"":1,""feed"":{""id"":""abc123"",""name"":""name1"",""description"":""desc1"",""status"":""ACTIVE"",""usage"":0,""daysRange"":7,""detailedMessageShown"":true,""type"":""SHARED_PAGE""},""totalCount"":1,""activityCount"":0,""messages"":{""message"":{""@clientUnixTime"":""0"",""id"":942821234,""messengerId"":""0-123456"",""messengerName"":""Spot"",""unixTime"":1521991234,""messageType"":""UNLIMITED-TRACK"",""latitude"":48.12345,""longitude"":11.12345,""modelId"":""SPOT3"",""showCustomMsg"":""Y"",""dateTime"":""2018-03-26T20:52:00+0000"",""batteryState"":""GOOD"",""hidden"":0,""altitude"":1234}}}}}"; result = Newtonsoft.Json.JsonConvert.DeserializeObject <Model.RootObject>(feedText); } var latestMessage = result.Response.FeedMessageResponse.Messages.Message; return(new LiveWaypointData { ID = uri.ToString(), TimeStamp = new DateTimeOffset(latestMessage.DateTime), Latitude = latestMessage.Latitude, Longitude = latestMessage.Longitude, Altitude = latestMessage.Altitude, Name = "FindMeSpot " + result.Response.FeedMessageResponse.Feed.Name, Description = FormatDescription( result.Response.FeedMessageResponse.Feed, latestMessage), DetailsLink = FormatSpotLink(liveFeedId), }); }
/// <summary> /// Adds a new live track resource URI /// </summary> /// <param name="uri">URI as string</param> /// <param name="appResourceUri">app resource URI</param> /// <returns>task to wait on</returns> private static async Task AddLiveTrack(string uri, AppResourceUri appResourceUri) { var rawUri = new Uri(uri); string trackName = "Live Track"; if (!string.IsNullOrEmpty(rawUri.Fragment)) { trackName = System.Net.WebUtility.UrlDecode(rawUri.Fragment.TrimStart('#')); } Track liveTrack = await GetLiveTrack(trackName, appResourceUri); await StoreLiveTrack(liveTrack); App.ShowToast("Live track was loaded."); await NavigationService.GoToMap(); App.MapView.AddTrack(liveTrack); App.MapView.ZoomToTrack(liveTrack); }
/// <summary> /// Returns next possible request date for given MapShare identifier /// </summary> /// <param name="uri">live waypoint ID</param> /// <returns>next possible request date</returns> public DateTimeOffset GetNextRequestDate(AppResourceUri uri) { return(this.lastRequest.HasValue ? this.lastRequest.Value + TimeSpan.FromMinutes(1.0) : DateTimeOffset.Now); }
/// <summary> /// Retrieves current live waypoint map location /// </summary> /// <param name="waypointName">waypoint name to use</param> /// <param name="appResourceUri">app resource uri to use</param> /// <returns>map location, or invalid location when it couldn't be retrieved</returns> private static async Task <Location> GetLiveWaypointLocation(string waypointName, AppResourceUri appResourceUri) { var dataService = DependencyService.Get <IDataService>(); LiveWaypointQueryResult result = await dataService.GetLiveWaypointDataAsync(appResourceUri.ToString()); var mapPoint = new MapPoint(result.Data.Latitude, result.Data.Longitude, result.Data.Altitude); return(new Location { Id = result.Data.ID, Name = waypointName ?? result.Data.Name, MapLocation = mapPoint, Description = result.Data.Description.Replace("\n", "<br/>"), Type = LocationType.LiveWaypoint, InternetLink = appResourceUri.ToString() }); }