Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • arf/world-analysis-api-helpers/unity-world-analysis-package
1 result
Show changes
Commits on Source (3)
Showing
with 890 additions and 319 deletions
fileFormatVersion: 2
guid: 953b8657509a139449794a24f2147730
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 4af05175caa96bb43844e080f1d8701b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File added
fileFormatVersion: 2
guid: 1494d109bc218c346ab7622ed734ea86
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 9d5dbed810c34cc4db0fe224cda88d0b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: bddbf4bf9ff11da4885638979b82efb2
labels:
- NuGetForUnity
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
userData:
assetBundleName:
assetBundleVariant:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>websocket-sharp-latest</id>
<version>1.0.2</version>
<authors>websocket-sharp-latest</authors>
<license type="expression">MIT</license>
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
<icon>websocket-sharp_icon.png</icon>
<description>Package Description</description>
<releaseNotes>https://github.com/garbles-labs/websocket-sharp/releases</releaseNotes>
<repository type="git" />
<dependencies>
<group targetFramework=".NETStandard2.0" />
</dependencies>
</metadata>
</package>
\ No newline at end of file
fileFormatVersion: 2
guid: a9d61c123a66f5b4a8d236c2972a3609
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: b3235afb951bf0a4f9e21db48a0937f6
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
......@@ -24,9 +24,15 @@ namespace ETSI.ARF.OpenAPI.WorldAnalysis
Name = name;
}
public string ToJson() { return JsonUtility.ToJson(this); }
public string ToJson() { return Newtonsoft.Json.JsonConvert.SerializeObject(this); }
}
//public class MatrixPose : Pose
//{
// [Newtonsoft.Json.JsonProperty("matrixValue", Required = Newtonsoft.Json.Required.AllowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
// public MatrixPoseValue MatrixValue { get; set; }
//}
//
// Implement here some constructors
//
......@@ -37,6 +43,6 @@ namespace ETSI.ARF.OpenAPI.WorldAnalysis
Uuid = Guid.NewGuid();
}
public string ToJson() { return JsonUtility.ToJson(this); }
public string ToJson() { return Newtonsoft.Json.JsonConvert.SerializeObject(this); }
}
}
\ No newline at end of file
......@@ -15,7 +15,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Last change: June 2024
// Last change: September 2024
//
// Depends on UniTask to support cancellation token and GetAwaiter: https://github.com/Cysharp/UniTask
......@@ -101,6 +101,21 @@ namespace ETSI.ARF.OpenAPI.WorldAnalysis
private readonly HttpClient _httpClient = new HttpClient();
private void AppendARFHeaders(HttpRequestMessage message, UnityWebRequest webRequest)
{
// Add some ARF headers
foreach (var item in message.Headers)
{
try
{
List<string> li = item.Value as List<string>;
if (item.Key == "token") webRequest.SetRequestHeader(item.Key, li[0].ToString()); // add it
if (item.Key == "sessionID") webRequest.SetRequestHeader(item.Key, li[0].ToString()); // add it
}
catch { } // ignore it
}
}
public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage message, HttpCompletionOption option, CancellationToken token)
{
var content = await (message.Content?.ReadAsStringAsync() ?? Task.FromResult(""));
......@@ -108,6 +123,9 @@ namespace ETSI.ARF.OpenAPI.WorldAnalysis
AppendHeaders(webRequest);
// Add the ARF API headers
AppendARFHeaders(message, webRequest);
Debug.Log("[HTTP] Request " + webRequest.uri.ToString());
try
{
......
......@@ -29,6 +29,18 @@ namespace ETSI.ARF.WorldAnalysis.REST
{
public class AdminRequest : RequestBase<string>
{
#region Test methods
static public void CheckServer(WorldAnalysisServer wa)
{
string ping = AdminRequest.PingSync(wa);
string state = AdminRequest.AdminSync(wa);
string ver = AdminRequest.VersionSync(wa);
Debug.Log("[REST] WA Ping: " + ping);
Debug.Log("[REST] WA State: " + state);
Debug.Log("[REST] WA Version: " + ver);
}
#endregion
//
// Wrapper for the endpoints
//
......
......@@ -151,7 +151,7 @@ public interface WorldAnalysisInterface
/// </summary>
/// <param name="subscriptionUUID">id of the subscription</param>
/// /// <returns>The unsubscription has been performed or not</returns>
public InformationSubscriptionResult UnSubscribeToPose(Guid subscriptionUUID);
public InformationSubscriptionResult UnsubscribeFromPose(Guid subscriptionUUID);
#endregion
......
......@@ -7,20 +7,28 @@ using ETSI.ARF.WorldAnalysis;
using static WorldAnalysisInterface;
using ETSI.ARF.WorldAnalysis.REST;
using WebSocketSharp;
using UnityEngine.Events;
//Implementation of the WorldAnalysis interface
public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
public partial class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
{
[Serializable]
public class StringEvent : UnityEvent<string> { }
//
// Inspector variables
//
// Name to register the client to the World Analysis
public string modulename = "UnityValidationApp";
/// <summary>
/// WorldSAnalysisServer
/// </summary>
public WorldAnalysisServer waServer;
public string token = "ETSI-ARF-STF";
public string sessionID = "RESTful-API";
public string sessionID = "ARF-STF669";
[Space(8)]
public bool isDebug = false;
......@@ -30,8 +38,6 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
//
private WorldAnalysisClient apiClient; // For sync calls
private WorldAnalysisClient apiClientAsync; // For async calls
private WebSocketSharp.WebSocket webSocket; // For WebSockets
private bool websocketConnected = false;
//
// Management of subscriptions
......@@ -39,14 +45,15 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
/// <summary>
/// Dictionnary of susbscription informations for poses, for each item, stored using the UUID of the item (anchor/trackable)
/// </summary>
private Dictionary<Guid, SubscriptionInfo> m_subscriptionsPoses;
private Dictionary<Guid, SubscriptionInfo> subscriptionsPoses;
public struct SubscriptionInfo
{
public ETSI.ARF.OpenAPI.WorldAnalysis.Pose pose;
public Guid uuid; // id of subscription (id is defined by the WA server)
public Guid uuidTarget; // id trackable or anchor
public float timeValidity; //The duration of the validity of the subscription
public ETSI.ARF.OpenAPI.WorldAnalysis.Pose pose;
public PoseCallback callback;
}
......@@ -60,7 +67,7 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
Instance = this;
//m_relocalizationInformations = new Dictionary<Guid, ETSI.ARF.OpenAPI.WorldStorage.RelocalizationInformation>();
//m_computedPoses = new Dictionary<Guid, ETSI.ARF.OpenAPI.WorldAnalysis.Pose>();
m_subscriptionsPoses = new Dictionary<Guid, SubscriptionInfo>();
subscriptionsPoses = new Dictionary<Guid, SubscriptionInfo>();
// sync
var httpClient = new BasicHTTPClient(waServer.URI);
......@@ -86,24 +93,19 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
ManageSubscriptionValidity();
// todo: Call subscription callback(s) here or in the websocket?!?
foreach (KeyValuePair<Guid, SubscriptionInfo> subPose in m_subscriptionsPoses)
foreach (KeyValuePair<Guid, SubscriptionInfo> subPose in subscriptionsPoses)
{
}
}
#endregion
#region Test methods
public void CheckServer()
private void OnDestroy()
{
string ping = AdminRequest.PingSync(waServer);
string state = AdminRequest.AdminSync(waServer);
string ver = AdminRequest.VersionSync(waServer);
Debug.Log("[REST] WA Ping: " + ping);
Debug.Log("[REST] WA State: " + state);
Debug.Log("[REST] WA Version: " + ver);
WebSocketClient_Close();
}
#endregion
#region Test methods
public void PrintCapabilities(Capability[] capabilities)
{
string res = "";
......@@ -117,105 +119,16 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
}
#endregion
#region Communication system
private void CreateWebHookServer()
{
throw new Exception("[REST] CreateWebHookServer(): Not implemented!");
}
private void DestroyWebHookServer()
{
return;
}
public WebSocket OpenWebSocketClient(string url)
{
webSocket = new WebSocketSharp.WebSocket(url);
//
// Define standard callbacks
//
webSocket.OnOpen += (sender, e) =>
{
Debug.Log("[WS] Connected");
websocketConnected = true;
webSocket.Send("RegisterClient:UnitySceneManagement");
};
webSocket.OnClose += (sender, e) =>
{
Debug.Log("[WS] Disconnected");
websocketConnected = false;
};
webSocket.OnError += (sender, e) => Debug.Log("[WS] Error!");
webSocket.OnMessage += (sender, e) => HandleWebSocketClient(e.Data);
webSocket.Connect();
return webSocket;
}
private void OnDestroy()
{
// State: red
CloseWebSocketClient();
}
private void CloseWebSocketClient()
{
if (websocketConnected)
{
webSocket.Send("UnregisterClient");
webSocket.Close();
}
}
bool ok = false;
public void HandleWebSocketClient(string data)
{
Debug.Log("[WS] Receiving: " + data);
if (data.Contains("You are now registered"))
{
ok = true;
if (isDebug) webSocket.Send("PoseStart:10"); // test
}
else if (data == "PoseStop")
{
//SetColor(Color.yellow);
}
else if (ok)
{
if (data.Contains("estimationState"))
{
// Handle pose
ETSI.ARF.OpenAPI.WorldAnalysis.Pose p = JsonUtility.FromJson<ETSI.ARF.OpenAPI.WorldAnalysis.Pose>(data);
Debug.Log("[WS][Pose] State: " + p.EstimationState.ToString());
PoseEstimationResult res = p.EstimationState == PoseEstimationState.OK ? PoseEstimationResult.OK : PoseEstimationResult.FAILURE;
// Search the corresponding callbacks
foreach (var item in m_subscriptionsPoses.Values)
{
if (p.Uuid == item.uuidTarget)
{
item.callback(res, p);
}
}
}
}
}
#endregion
#region Lifecycle
/// <summary>
/// Check the validity of all subscriptions and delete one if needed
/// </summary>
protected void ManageSubscriptionValidity()
{
if (m_subscriptionsPoses.Count == 0) return;
if (subscriptionsPoses.Count == 0) return;
List<Guid> subscriptionToDelete = new List<Guid>();
foreach (KeyValuePair<Guid, SubscriptionInfo> sub in m_subscriptionsPoses)
foreach (KeyValuePair<Guid, SubscriptionInfo> sub in subscriptionsPoses)
{
float validity = sub.Value.timeValidity;
if (Time.time > validity)
......@@ -226,7 +139,7 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
foreach (Guid s in subscriptionToDelete)
{
Debug.Log("ETSI ARF : Subscription deleted " + s);
m_subscriptionsPoses.Remove(s);
subscriptionsPoses.Remove(s);
}
}
#endregion
......@@ -262,16 +175,16 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
}
PoseEstimationResult[] resul = new PoseEstimationResult[uuids.Length];
poses = new ETSI.ARF.OpenAPI.WorldAnalysis.Pose[uuids.Length];
List<Anonymous> uuidList = new List<Anonymous>();
Response poses_ = apiClient.GetPoses(token, sessionID, uuidList.ToArray());
List<ETSI.ARF.OpenAPI.WorldAnalysis.Pose> posesList = poses_.Poses as List<ETSI.ARF.OpenAPI.WorldAnalysis.Pose>;
List<UuidAndMode> uuidList = new List<UuidAndMode>();
Poses poses_ = apiClient.GetPoses(token, sessionID, uuidList.ToArray());
List<ETSI.ARF.OpenAPI.WorldAnalysis.Pose> posesList = poses_.Poses1 as List<ETSI.ARF.OpenAPI.WorldAnalysis.Pose>;
if (poses_ != null && posesList != null && posesList.Count > 0)
{
for (int i = 0; i < uuids.Length; i++)
{
PoseEstimationResult poseResul = new PoseEstimationResult();
resul[i] = poseResul;
PoseEstimationResult poseResult = new PoseEstimationResult();
resul[i] = poseResult;
poses[i] = posesList[i];
}
return resul;
......@@ -283,6 +196,19 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
}
}
private string CreateWebsocket_URL(string originalURL)
{
string uri = originalURL;
//
// Overwrite server setting for testing local/extra servers
//
//if (isDebug) uri = "ws://localhost:61788/ws"; // for tests
//if (isDebug) uri = "wss://localhost:44301/ws"; // for tests
return uri;
}
public InformationSubscriptionResult SubscribeToPose(string token, Guid uuid, Mode_WorldAnalysis mode, PoseCallback callback, ref int validity, out Guid subscriptionUUID)
{
// Todo: Maintain the callback to the subscription id
......@@ -293,45 +219,54 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
body.Target = uuid;
body.Mode = mode;
body.Validity = validity;
body.WebhookUrl = callback == null ? "" : "https:\\..."; // empty -> app will use websockets (client)!
body.WebhookUrl = callback != null ? "" : "https:\\..."; // empty -> app will use websockets (client)!
// Get subscription info from the REST server
SubscriptionSingle response = apiClient.SubscribeToPose(token, sessionID, body);
subscriptionUUID = response.Uuid;
validity = response.Validity;
//SubscriptionMultipleRequest body_m = new SubscriptionMultipleRequest();
//body_m.Targets = new List<object>();
//body_m.Mode = new List<Mode_WorldAnalysis>();
//body_m.Validity = validity;
//body_m.WebhookUrl = callback == null ? "" : "https:\\..."; // empty -> app will use websockets (client)!
//SubscriptionMultiple response = apiClient.SubscribeToPose(token, sessionID, body_m);
// We add the subscription
SubscriptionInfo sub = new SubscriptionInfo();
sub.uuid = response.Uuid;
sub.uuid = subscriptionUUID;
sub.uuidTarget = uuid;
sub.timeValidity = Time.time + (validity / 1000.0f);
sub.callback = callback;
sub.pose = new ETSI.ARF.OpenAPI.WorldAnalysis.Pose();
sub.pose.Mode = mode;
sub.uuidTarget = uuid;
sub.callback = callback;
m_subscriptionsPoses.Add(sub.uuid, sub);
subscriptionsPoses.Add(sub.uuid, sub);
if (!string.IsNullOrEmpty(response.WebhookUrl))
{
CloseWebSocketClient();
// Create a REST server so that the WA server can send pose update to it
string webhookUrl = response.WebhookUrl;
// Close other communication channel
WebSocketClient_Close();
// todo: create a REST server so that the WA server can send pose update to it
// How to auto-generate the C# REST server for pose for Unity?
CreateWebHookServer();
// How to auto-generate the C# REST webhook server for pose for Unity?
WebHookServer_Create(webhookUrl);
}
else
else if (!string.IsNullOrEmpty(response.WebsocketUrl))
{
DestroyWebHookServer();
// Create the WebSockets client here (NOT in the scene scripts)
// todo: Open the websocket?
string websocketUrl = response.WebsocketUrl;
if (isDebug) websocketUrl = "ws://localhost:61788/ws"; // for tests
// Close other communication channel
WebHookServer_Close();
if (string.IsNullOrEmpty(websocketUrl))
{
// Create the WebSockets client here (NOT in the scene scripts)
if (!websocketConnected) OpenWebSocketClient(websocketUrl);
}
else throw new Exception("[REST] No valid WebSockets URL in server reponse.");
// Open the websocket
if (webSocket == null) WebSocketClient_Create(CreateWebsocket_URL(response.WebsocketUrl)); // only one instance
}
else throw new Exception("[REST] No valid URL in server reponse.");
return InformationSubscriptionResult.OK;
}
......@@ -363,7 +298,7 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
mode = Mode_WorldAnalysis.TRACKABLES_TO_DEVICE;
validity = 0;
if (m_subscriptionsPoses.ContainsKey(subscriptionUUID))
if (subscriptionsPoses.ContainsKey(subscriptionUUID))
{
// Check the server subscription
SubscriptionSingle sub = apiClient.GetSubscription(token, sessionID, subscriptionUUID);
......@@ -371,7 +306,7 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
// Check local one
if (sub.Uuid == subscriptionUUID)
{
SubscriptionInfo subInfo = m_subscriptionsPoses[subscriptionUUID];
SubscriptionInfo subInfo = subscriptionsPoses[subscriptionUUID];
callback = subInfo.callback;
target = subInfo.uuidTarget;
mode = subInfo.pose.Mode;
......@@ -395,18 +330,18 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
mode = Mode_WorldAnalysis.TRACKABLES_TO_DEVICE;
validity = 0;
if (m_subscriptionsPoses.ContainsKey(subscriptionUUID))
if (subscriptionsPoses.ContainsKey(subscriptionUUID))
{
SubscriptionInfo sub = m_subscriptionsPoses[subscriptionUUID];
SubscriptionInfo sub = subscriptionsPoses[subscriptionUUID];
PoseCallback oldCB = sub.callback;
Body body = new Body();
body.Mode = mode;
body.Validity = validity;
body.WebhookUrl = callback == null ? "" : "https:\\..."; // empty -> app will use websockets (client)!
Body newSub = new Body();
newSub.Mode = mode;
newSub.Validity = validity;
newSub.WebhookUrl = callback == null ? "" : "https:\\..."; // empty -> app will use websockets (client)!
// Update subscription info in the REST server
SubscriptionSingle response = apiClient.UpdateSubscription(token, sessionID, subscriptionUUID, body);
SubscriptionSingle response = apiClient.UpdateSubscription(token, sessionID, subscriptionUUID, newSub);
// Update local data
sub.pose.Mode = response.Mode;
......@@ -418,44 +353,43 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
//
if (oldCB != null && callback == null && !string.IsNullOrEmpty(response.WebhookUrl))
{
CloseWebSocketClient();
// Create a REST server so that the WA server can send pose update to it
string webhookUrl = response.WebhookUrl;
// Close other communication channel
WebSocketClient_Close();
// todo: create a REST server so that the WA server can send pose update to it
// How to auto-generate the C# REST server for pose for Unity?
CreateWebHookServer();
WebHookServer_Create(webhookUrl);
}
else if (oldCB == null && callback != null && string.IsNullOrEmpty(response.WebhookUrl))
else if (oldCB == null && callback != null && !string.IsNullOrEmpty(response.WebsocketUrl))
{
DestroyWebHookServer();
// todo: Open the websocket?
string websocketUrl = response.WebsocketUrl;
if (isDebug) websocketUrl = "ws://localhost:61788/ws"; // for tests
if (string.IsNullOrEmpty(websocketUrl))
{
// Create the WebSockets client here (NOT in the scene scripts)
if (!websocketConnected) OpenWebSocketClient(websocketUrl);
}
else throw new Exception("[REST] No valid WebSockets URL in server reponse.");
// Create the WebSockets client here (NOT in the scene scripts)
// Close other communication channel
WebHookServer_Close();
// Open the websocket?
if (webSocket == null) WebSocketClient_Create(CreateWebsocket_URL(response.WebsocketUrl));
}
else throw new Exception("[REST] No valid URL in server reponse.");
return InformationSubscriptionResult.OK;
}
return InformationSubscriptionResult.UNKNOWN_ID;
}
public InformationSubscriptionResult UnSubscribeToPose(Guid subscriptionUUID)
public InformationSubscriptionResult UnsubscribeFromPose(Guid subscriptionUUID)
{
if (m_subscriptionsPoses.ContainsKey(subscriptionUUID))
if (subscriptionsPoses.ContainsKey(subscriptionUUID))
{
apiClient.UnsubscribeFromPose(token, sessionID, subscriptionUUID);
m_subscriptionsPoses.Remove(subscriptionUUID);
subscriptionsPoses.Remove(subscriptionUUID);
if (m_subscriptionsPoses.Count == 0)
if (subscriptionsPoses.Count == 0)
{
// Close the connection via websockets
CloseWebSocketClient();
WebSocketClient_Close();
}
return InformationSubscriptionResult.OK;
}
......@@ -464,16 +398,16 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
public CapabilityResult GetCapabilities(string token, out Capability[] capabilities)
{
Response2 cap = apiClient.GetCapabilities(token, sessionID);
if (cap == null || cap.Capabilities == null || cap.Capabilities.Count == 0)
Capabilities cap = apiClient.GetCapabilities(token, sessionID);
if (cap == null || cap.Capabilities1 == null || cap.Capabilities1.Count == 0)
{
capabilities = null;
return CapabilityResult.FAIL;
}
else
{
capabilities = new Capability[cap.Capabilities.Count];
cap.Capabilities.CopyTo(capabilities, 0);
capabilities = new Capability[cap.Capabilities1.Count];
cap.Capabilities1.CopyTo(capabilities, 0);
return CapabilityResult.OK;
}
}
......@@ -484,7 +418,7 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
type = TypeWorldStorage.UNKNOWN;
capability = null;
Response3 cap = apiClient.GetSupport(token, sessionID, uuid);
Supports cap = apiClient.GetSupport(token, sessionID, uuid);
if (cap == null || cap.Capabilities == null || cap.Capabilities.Count == 0)
{
isSupported = false;
......
#define IS_HHI_LAN
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using WebSocketSharp;
using ETSI.ARF.OpenAPI.WorldAnalysis;
using static WorldAnalysisInterface;
//Implementation of the WorldAnalysis interface
public partial class WorldAnalysisREST
{
//
// Inspector variables
//
public StringEvent webSocketMessage;
//
// Private members
//
private WebSocketSharp.WebSocket webSocket = null; // For WebSockets
#region Communication system for WebSockets
public WebSocket WebSocketClient_Create(string url)
{
if (webSocket != null) return webSocket;
string _url = url;
#if IS_HHI_LAN
_url = "ws://192.168.20.29:8084/ws";
Debug.LogWarning("[WS] Changing the websocket URL to: " + _url + " (local network VM, HHI)");
#endif
webSocket = new WebSocketSharp.WebSocket(_url);
//
// Define standard callbacks
//
webSocket.OnOpen += (sender, e) =>
{
Debug.Log("[WS] Connected");
webSocket.Send("RegisterClient=" + modulename);
};
webSocket.OnClose += (sender, e) =>
{
Debug.Log("[WS] Disconnected");
};
webSocket.OnMessage += (sender, e) => WebSocketClient_OnReceive(e.Data);
webSocket.OnError += (sender, e) => Debug.Log("[WS] Websocket error!");
webSocket.Connect();
return webSocket;
}
private void WebSocketClient_Close()
{
if (webSocket != null)
{
webSocket.Send("UnregisterClient=" + modulename);
webSocket.Close();
webSocket = null;
}
}
public void WebSocketClient_Send(string msg)
{
webSocket?.Send(msg);
}
bool isRegistered = false;
public void WebSocketClient_OnReceive(string serverMessage)
{
//Debug.Log("[WS] Receiving: " + data);
if (serverMessage.Contains("You are now registered"))
{
isRegistered = true;
Debug.Log($"[WS] {serverMessage }");
//Debug.Log($"[WS] Registration of { modulename } was succesfull.");
}
else if (isRegistered)
{
if (serverMessage == "PoseStop")
{
//SetColor(Color.yellow);
}
else if (serverMessage == "PoseIsNowSubscribed")
{
}
else if (serverMessage == "PoseIsNowUnubscribed")
{
}
else if (serverMessage.StartsWith("NewPose=") && serverMessage.Contains("estimationState"))
{
// Handle the new pose
string _str = serverMessage.Substring("NewPose=".Length);
ETSI.ARF.OpenAPI.WorldAnalysis.Pose pose = JsonConvert.DeserializeObject<ETSI.ARF.OpenAPI.WorldAnalysis.Pose>(_str);
//Debug.Log("[WS] JSON - my new pose : " + pose.ToJson());
// to check: p.Confidence?
PoseEstimationResult res = pose.EstimationState == PoseEstimationState.OK ? PoseEstimationResult.OK : PoseEstimationResult.FAILURE;
// Look for the corresponding callbacks
foreach (var item in subscriptionsPoses.Values)
{
if (item.uuidTarget == pose.Uuid)
{
item.pose.Value = pose.Value;
item.callback(res, pose);
}
}
}
else webSocketMessage?.Invoke(serverMessage);
}
}
#endregion
}
\ No newline at end of file
fileFormatVersion: 2
guid: 7b7bcc535a949e24283db7e23c51dc46
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ETSI.ARF.OpenAPI.WorldAnalysis;
using ETSI.ARF.WorldAnalysis;
using ETSI.ARF.WorldAnalysis.REST;
//Implementation of the WorldAnalysis interface
public partial class WorldAnalysisREST
{
//
// Inspector variables
//
public StringEvent webhookMessage;
private bool webhookRunning = false;
#region Communication system for WebHooks
private void WebHookServer_Create(string url)
{
webhookRunning = true;
throw new Exception("[API] WebHookServer_Create(): Not implemented!");
}
private void WebHookServer_Close()
{
if (webhookRunning)
{
webhookRunning = false;
throw new Exception("[API] WebHookServer_Close(): Not implemented!");
}
}
private object WebHookServer_OnReceive()
{
throw new Exception("[API] WebHookServer_OnReceive(): Not implemented!");
}
private void WebHookServer_Send(object message)
{
throw new Exception("[API] WebHookServer_Send(): Not implemented!");
}
#endregion
}
\ No newline at end of file
fileFormatVersion: 2
guid: 67d4b99a5f7593e4a857b6c88249d564
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: