diff --git a/OrcanodeMonitor/Core/Fetcher.cs b/OrcanodeMonitor/Core/Fetcher.cs
index 348b487..8f4261e 100644
--- a/OrcanodeMonitor/Core/Fetcher.cs
+++ b/OrcanodeMonitor/Core/Fetcher.cs
@@ -28,7 +28,9 @@ public class Fetcher
{
private static TimeZoneInfo _pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
private static HttpClient _httpClient = new HttpClient();
- private static string _orcasoundFeedsUrl = "https://live.orcasound.net/api/json/feeds";
+ private static string _orcasoundProdSite = "live.orcasound.net";
+ private static string _orcasoundDevSite = "dev.orcasound.net";
+ private static string _orcasoundFeedsUrlPath = "/api/json/feeds";
private static string _dataplicityDevicesUrl = "https://apps.dataplicity.com/devices/";
private static string _orcaHelloHydrophonesUrl = "https://aifororcasdetections2.azurewebsites.net/api/hydrophones";
private static DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
@@ -447,147 +449,188 @@ public async static Task UpdateDataplicityDataAsync(OrcanodeMonitorContext conte
}
}
- ///
- /// Update the current list of Orcanodes using data from orcasound.net.
- ///
- /// Database context to update
- ///
- public async static Task UpdateOrcasoundDataAsync(OrcanodeMonitorContext context)
+ private async static Task GetOrcasoundDataAsync(OrcanodeMonitorContext context, string site)
{
try
{
- string json = await _httpClient.GetStringAsync(_orcasoundFeedsUrl);
+ string url = "https://" + site + _orcasoundFeedsUrlPath;
+ string json = await _httpClient.GetStringAsync(url);
if (json.IsNullOrEmpty())
{
- return;
+ return null;
}
dynamic response = JsonSerializer.Deserialize(json);
if (response == null)
{
- return;
+ return null;
}
JsonElement dataArray = response.data;
if (dataArray.ValueKind != JsonValueKind.Array)
{
- return;
+ return null;
}
+ return dataArray;
+ }
+ catch (Exception ex)
+ {
+ string msg = ex.ToString();
+ return null;
+ }
+ }
- var foundList = context.Orcanodes.ToList();
+ private static void UpdateOrcasoundNode(JsonElement feed, List foundList, List unfoundList, OrcanodeMonitorContext context, string site)
+ {
+ if (!feed.TryGetProperty("id", out var feedId))
+ {
+ return;
+ }
+ if (!feed.TryGetProperty("attributes", out JsonElement attributes))
+ {
+ return;
+ }
+ if (!attributes.TryGetProperty("name", out var name))
+ {
+ return;
+ }
+ string orcasoundName = name.ToString();
+ if (!attributes.TryGetProperty("dataplicity_id", out var dataplicity_id))
+ {
+ return;
+ }
+ bool hidden = false;
+ if (attributes.TryGetProperty("hidden", out var hiddenElement))
+ {
+ hidden = hiddenElement.GetBoolean();
+ }
+ string dataplicitySerial = dataplicity_id.ToString();
- // Create a list to track what nodes are no longer returned.
- var unfoundList = foundList.ToList();
+ // Remove the found node from the unfound list.
+ Orcanode? oldListNode = unfoundList.Find(a => a.OrcasoundFeedId == feedId.ToString());
+ if (oldListNode != null)
+ {
+ unfoundList.Remove(oldListNode);
+ }
- foreach (JsonElement feed in dataArray.EnumerateArray())
+ Orcanode? node = null;
+ node = FindOrcanodeByOrcasoundFeedId(foundList, feedId.ToString());
+ if (node == null)
+ {
+ // We didn't used to store the feed ID, only the name, so try again by name.
+ Orcanode? possibleNode = FindOrcanodeByOrcasoundName(foundList, orcasoundName);
+ if ((possibleNode != null) && possibleNode.OrcasoundFeedId.IsNullOrEmpty())
{
- if (!feed.TryGetProperty("id", out var feedId))
- {
- continue;
- }
- if (!feed.TryGetProperty("attributes", out JsonElement attributes))
- {
- continue;
- }
- if (!attributes.TryGetProperty("name", out var name))
- {
- continue;
- }
- string orcasoundName = name.ToString();
- if (!attributes.TryGetProperty("dataplicity_id", out var dataplicity_id))
- {
- continue;
- }
- bool hidden = false;
- if (attributes.TryGetProperty("hidden", out var hiddenElement))
- {
- hidden = hiddenElement.GetBoolean();
- }
- string dataplicitySerial = dataplicity_id.ToString();
-
- // Remove the found node from the unfound list.
- Orcanode? oldListNode = unfoundList.Find(a => a.OrcasoundFeedId == feedId.ToString());
+ node = possibleNode;
+ oldListNode = unfoundList.Find(a => a.OrcasoundName == orcasoundName);
if (oldListNode != null)
{
unfoundList.Remove(oldListNode);
}
+ }
+ }
- Orcanode? node = null;
- node = FindOrcanodeByOrcasoundFeedId(foundList, feedId.ToString());
+ // See if we can find a node by dataplicity ID, so that if a node
+ // shows up in dataplicity first and Orcasite later, we don't create a
+ // duplicate entry.
+ Orcanode? dataplicityNode = null;
+ if (!dataplicitySerial.IsNullOrEmpty())
+ {
+ dataplicityNode = FindOrcanodeByDataplicitySerial(foundList, dataplicitySerial, out OrcanodeOnlineStatus oldStatus);
+ if (dataplicityNode != null)
+ {
if (node == null)
{
- // We didn't used to store the feed ID, only the name, so try again by name.
- node = FindOrcanodeByOrcasoundName(foundList, orcasoundName);
+ node = dataplicityNode;
}
-
- // See if we can find a node by dataplicity ID, so that if a node
- // shows up in dataplicity first and Orcasite later, we don't create a
- // duplicate entry.
- Orcanode? dataplicityNode = null;
- if (!dataplicitySerial.IsNullOrEmpty())
+ else if (node != dataplicityNode)
{
- dataplicityNode = FindOrcanodeByDataplicitySerial(foundList, dataplicitySerial, out OrcanodeOnlineStatus oldStatus);
- if (dataplicityNode != null)
- {
- if (node == null)
- {
- node = dataplicityNode;
- }
- else if (node != dataplicityNode)
- {
- // We have duplicate nodes to merge. In theory we shouldn't have any
- // node state for the dataplicity-only node. (TODO: verify this)
- node.DataplicityDescription = dataplicityNode.DataplicityDescription;
- node.DataplicityName = dataplicityNode.DataplicityName;
- node.DataplicityOnline = dataplicityNode.DataplicityOnline;
- node.AgentVersion = dataplicityNode.AgentVersion;
- node.DiskCapacity = dataplicityNode.DiskCapacity;
- node.DiskUsed = dataplicityNode.DiskUsed;
- node.DataplicityUpgradeAvailable = dataplicityNode.DataplicityUpgradeAvailable;
- context.Orcanodes.Remove(dataplicityNode);
- }
- }
+ // We have duplicate nodes to merge. In theory we shouldn't have any
+ // node state for the dataplicity-only node. (TODO: verify this)
+ node.DataplicityDescription = dataplicityNode.DataplicityDescription;
+ node.DataplicityName = dataplicityNode.DataplicityName;
+ node.DataplicityOnline = dataplicityNode.DataplicityOnline;
+ node.AgentVersion = dataplicityNode.AgentVersion;
+ node.DiskCapacity = dataplicityNode.DiskCapacity;
+ node.DiskUsed = dataplicityNode.DiskUsed;
+ node.DataplicityUpgradeAvailable = dataplicityNode.DataplicityUpgradeAvailable;
+ context.Orcanodes.Remove(dataplicityNode);
}
+ }
+ }
- if (node == null)
- {
- node = CreateOrcanode(context.Orcanodes);
- node.OrcasoundName = name.ToString();
- }
+ if (node == null)
+ {
+ node = CreateOrcanode(context.Orcanodes);
+ node.OrcasoundName = name.ToString();
+ }
- if (!dataplicitySerial.IsNullOrEmpty())
- {
- if (!node.DataplicitySerial.IsNullOrEmpty() && dataplicitySerial != node.DataplicitySerial)
- {
- // TODO: The orcasound entry for the node changed its dataplicity_id.
- }
- node.DataplicitySerial = dataplicitySerial;
- }
+ if (!dataplicitySerial.IsNullOrEmpty())
+ {
+ if (!node.DataplicitySerial.IsNullOrEmpty() && dataplicitySerial != node.DataplicitySerial)
+ {
+ // TODO: The orcasound entry for the node changed its dataplicity_id.
+ }
+ node.DataplicitySerial = dataplicitySerial;
+ }
- if (node.OrcasoundFeedId.IsNullOrEmpty())
- {
- node.OrcasoundFeedId = feedId.ToString();
- }
- if (orcasoundName != node.OrcasoundName)
- {
- // We just detected a name change.
- node.OrcasoundName = orcasoundName;
- }
- if (attributes.TryGetProperty("node_name", out var nodeName))
- {
- node.S3NodeName = nodeName.ToString();
- }
- if (attributes.TryGetProperty("bucket", out var bucket))
- {
- node.S3Bucket = bucket.ToString();
- }
- if (attributes.TryGetProperty("slug", out var slug))
- {
- node.OrcasoundSlug = slug.ToString();
- }
- if (attributes.TryGetProperty("visible", out var visible))
- {
- node.OrcasoundVisible = visible.GetBoolean();
- }
+ if (node.OrcasoundFeedId.IsNullOrEmpty())
+ {
+ node.OrcasoundFeedId = feedId.ToString();
+ }
+ if (!site.IsNullOrEmpty())
+ {
+ node.OrcasoundHost = site;
+ }
+ if (orcasoundName != node.OrcasoundName)
+ {
+ // We just detected a name change.
+ node.OrcasoundName = orcasoundName;
+ }
+ if (attributes.TryGetProperty("node_name", out var nodeName))
+ {
+ node.S3NodeName = nodeName.ToString();
+ }
+ if (attributes.TryGetProperty("bucket", out var bucket))
+ {
+ node.S3Bucket = bucket.ToString();
+ }
+ if (attributes.TryGetProperty("slug", out var slug))
+ {
+ node.OrcasoundSlug = slug.ToString();
+ }
+ if (attributes.TryGetProperty("visible", out var visible))
+ {
+ node.OrcasoundVisible = visible.GetBoolean();
+ }
+ }
+
+ private async static Task UpdateOrcasoundSiteDataAsync(OrcanodeMonitorContext context, string site, List foundList, List unfoundList)
+ {
+ JsonElement? dataArray = await GetOrcasoundDataAsync(context, site);
+ if (dataArray.HasValue)
+ {
+ foreach (JsonElement feed in dataArray.Value.EnumerateArray())
+ {
+ UpdateOrcasoundNode(feed, foundList, unfoundList, context, site);
}
+ }
+ }
+
+ ///
+ /// Update the current list of Orcanodes using data from orcasound.net.
+ ///
+ /// Database context to update
+ ///
+ public async static Task UpdateOrcasoundDataAsync(OrcanodeMonitorContext context)
+ {
+ var foundList = context.Orcanodes.ToList();
+
+ // Create a list to track what nodes are no longer returned.
+ var unfoundList = foundList.ToList();
+
+ try
+ {
+ await UpdateOrcasoundSiteDataAsync(context, _orcasoundProdSite, foundList, unfoundList);
+ await UpdateOrcasoundSiteDataAsync(context, _orcasoundDevSite, foundList, unfoundList);
// Mark any remaining unfound nodes as absent.
foreach (var unfoundNode in unfoundList)
diff --git a/OrcanodeMonitor/Models/Orcanode.cs b/OrcanodeMonitor/Models/Orcanode.cs
index eca79aa..2bd2c48 100644
--- a/OrcanodeMonitor/Models/Orcanode.cs
+++ b/OrcanodeMonitor/Models/Orcanode.cs
@@ -51,6 +51,7 @@ public Orcanode()
OrcasoundName = string.Empty;
OrcasoundSlug = string.Empty;
OrcasoundFeedId = string.Empty;
+ OrcasoundHost = string.Empty;
S3Bucket = string.Empty;
S3NodeName = string.Empty;
AgentVersion = string.Empty;
@@ -187,6 +188,11 @@ public Orcanode()
/// Audio stream status of most recent sample (defaults to absent).
///
public OrcanodeOnlineStatus? AudioStreamStatus { get; set; }
+
+ ///
+ /// Orcasound site host (defaults to empty).
+ ///
+ public string OrcasoundHost { get; set; }
#endregion persisted
@@ -300,6 +306,24 @@ public OrcanodeOnlineStatus S3StreamStatus
}
}
+ private bool IsDev
+ {
+ get
+ {
+ if (this.S3Bucket.StartsWith("dev"))
+ {
+ return true;
+ }
+ if (this.DataplicityName.ToLower().StartsWith("dev"))
+ {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public string Type => IsDev ? "Dev" : "Prod";
+
public string OrcasoundOnlineStatusString {
get
{
diff --git a/OrcanodeMonitor/Pages/Index.cshtml b/OrcanodeMonitor/Pages/Index.cshtml
index 06ccfc3..018e75d 100644
--- a/OrcanodeMonitor/Pages/Index.cshtml
+++ b/OrcanodeMonitor/Pages/Index.cshtml
@@ -12,6 +12,7 @@