From cafd4e6c5d163bd637415b09531f072fb38f1644 Mon Sep 17 00:00:00 2001
From: Sylvain Renault <sylvain.renault@hhi.fraunhofer.de>
Date: Thu, 8 Aug 2024 18:01:33 +0200
Subject: [PATCH] Preparation of REST and websocket client functions. Some
 namepsace changes.

---
 Editor/Scripts/WorldAnalysisInfoEditor.cs     |  39 +++
 .../Scripts/WorldAnalysisInfoEditor.cs.meta   |  11 +
 Editor/Scripts/WorldAnalysisServerEditor.cs   | 174 ++++++++++++++
 .../Scripts/WorldAnalysisServerEditor.cs.meta |  11 +
 Editor/Scripts/WorldAnalysisUserEditor.cs     |  51 ++++
 .../Scripts/WorldAnalysisUserEditor.cs.meta   |  11 +
 Runtime/Scriptables.meta                      |   8 +
 Runtime/Scriptables/WorldAnalysisServer.cs    |  39 +++
 .../Scriptables/WorldAnalysisServer.cs.meta   |  11 +
 Runtime/Scriptables/WorldAnalysisUser.cs      |  33 +++
 Runtime/Scriptables/WorldAnalysisUser.cs.meta |  11 +
 Runtime/Scripts/OpenAPI/BaseClient.cs         |  38 +++
 Runtime/Scripts/OpenAPI/BaseClient.cs.meta    |  11 +
 Runtime/Scripts/OpenAPI/DataModels.cs         |  42 ++++
 Runtime/Scripts/OpenAPI/DataModels.cs.meta    |  11 +
 .../OpenAPI/Generated/WorldAnalysisOpenAPI.cs |  10 +-
 Runtime/Scripts/OpenAPI/ResponseObject.cs     |  65 +++++
 .../Scripts/OpenAPI/ResponseObject.cs.meta    |  11 +
 .../OpenAPI/UnityWebRequestHttpClient.cs      | 225 ++++++++++++++++++
 .../OpenAPI/UnityWebRequestHttpClient.cs.meta |  11 +
 .../Scripts/OpenAPI/WorldAnalysisClient.cs    |  28 +++
 .../OpenAPI/WorldAnalysisClient.cs.meta       |  11 +
 Runtime/Scripts/REST.meta                     |   8 +
 Runtime/Scripts/REST/AdminRequest.cs          | 101 ++++++++
 Runtime/Scripts/REST/AdminRequest.cs.meta     |  11 +
 Runtime/Scripts/REST/RequestBase.cs           |  79 ++++++
 Runtime/Scripts/REST/RequestBase.cs.meta      |  11 +
 Runtime/Scripts/WorldAnalysisInfo.cs          |  45 ++++
 Runtime/Scripts/WorldAnalysisInfo.cs.meta     |  11 +
 Runtime/Scripts/WorldAnalysisREST.cs          |  69 +++++-
 30 files changed, 1186 insertions(+), 11 deletions(-)
 create mode 100644 Editor/Scripts/WorldAnalysisInfoEditor.cs
 create mode 100644 Editor/Scripts/WorldAnalysisInfoEditor.cs.meta
 create mode 100644 Editor/Scripts/WorldAnalysisServerEditor.cs
 create mode 100644 Editor/Scripts/WorldAnalysisServerEditor.cs.meta
 create mode 100644 Editor/Scripts/WorldAnalysisUserEditor.cs
 create mode 100644 Editor/Scripts/WorldAnalysisUserEditor.cs.meta
 create mode 100644 Runtime/Scriptables.meta
 create mode 100644 Runtime/Scriptables/WorldAnalysisServer.cs
 create mode 100644 Runtime/Scriptables/WorldAnalysisServer.cs.meta
 create mode 100644 Runtime/Scriptables/WorldAnalysisUser.cs
 create mode 100644 Runtime/Scriptables/WorldAnalysisUser.cs.meta
 create mode 100644 Runtime/Scripts/OpenAPI/BaseClient.cs
 create mode 100644 Runtime/Scripts/OpenAPI/BaseClient.cs.meta
 create mode 100644 Runtime/Scripts/OpenAPI/DataModels.cs
 create mode 100644 Runtime/Scripts/OpenAPI/DataModels.cs.meta
 create mode 100644 Runtime/Scripts/OpenAPI/ResponseObject.cs
 create mode 100644 Runtime/Scripts/OpenAPI/ResponseObject.cs.meta
 create mode 100644 Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs
 create mode 100644 Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs.meta
 create mode 100644 Runtime/Scripts/OpenAPI/WorldAnalysisClient.cs
 create mode 100644 Runtime/Scripts/OpenAPI/WorldAnalysisClient.cs.meta
 create mode 100644 Runtime/Scripts/REST.meta
 create mode 100644 Runtime/Scripts/REST/AdminRequest.cs
 create mode 100644 Runtime/Scripts/REST/AdminRequest.cs.meta
 create mode 100644 Runtime/Scripts/REST/RequestBase.cs
 create mode 100644 Runtime/Scripts/REST/RequestBase.cs.meta
 create mode 100644 Runtime/Scripts/WorldAnalysisInfo.cs
 create mode 100644 Runtime/Scripts/WorldAnalysisInfo.cs.meta

diff --git a/Editor/Scripts/WorldAnalysisInfoEditor.cs b/Editor/Scripts/WorldAnalysisInfoEditor.cs
new file mode 100644
index 0000000..70a489e
--- /dev/null
+++ b/Editor/Scripts/WorldAnalysisInfoEditor.cs
@@ -0,0 +1,39 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: August 2024
+//
+
+using UnityEditor;
+
+[CustomEditor(typeof(WorldAnalysisInfo))]
+public class WorldAnalysisInfoEditor : Editor
+{
+    public override void OnInspectorGUI()
+    {
+        base.OnInspectorGUI();
+
+        EditorGUILayout.Space();
+        WorldAnalysisInfo srv = (WorldAnalysisInfo)target;
+
+        string state = "";// srv.GetServerState();
+        EditorGUILayout.LabelField("Server State", state);
+
+        string api = "";// srv.GetAPIVersion();
+        EditorGUILayout.LabelField("OpenAPI Version", api);
+    }
+}
diff --git a/Editor/Scripts/WorldAnalysisInfoEditor.cs.meta b/Editor/Scripts/WorldAnalysisInfoEditor.cs.meta
new file mode 100644
index 0000000..0642c98
--- /dev/null
+++ b/Editor/Scripts/WorldAnalysisInfoEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4b890e537ebae974b862e97bfefa51ad
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Editor/Scripts/WorldAnalysisServerEditor.cs b/Editor/Scripts/WorldAnalysisServerEditor.cs
new file mode 100644
index 0000000..4fe96c9
--- /dev/null
+++ b/Editor/Scripts/WorldAnalysisServerEditor.cs
@@ -0,0 +1,174 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: July 2024
+//
+
+using System.Collections;
+using UnityEngine;
+using UnityEditor;
+
+using ETSI.ARF.OpenAPI;
+using ETSI.ARF.OpenAPI.WorldAnalysis;
+using ETSI.ARF.WorldAnalysis;
+using ETSI.ARF.WorldAnalysis.REST;
+
+[CustomEditor(typeof(WorldAnalysisServer))]
+public class WorldStorageServerEditor : Editor
+{
+    WorldAnalysisServer server;
+
+    private string state = "";
+    private string version = "";
+
+    private string test = "";
+
+    private Queue handleResponseQueue = new Queue();
+
+    private ResponseObject<string> pendingTest = null;
+    private ResponseObject<string> pendingState = null;
+    private ResponseObject<string> pendingVersion = null;
+
+    public void OnEnable()
+    {
+        server = (WorldAnalysisServer)target;
+    }
+
+    public override void OnInspectorGUI()
+    {
+        serializedObject.Update();
+
+        DrawDefaultInspector();
+        EditorGUILayout.Space();
+
+        if (GUILayout.Button("Test server"))
+        {
+            TestPing();
+        }
+        EditorGUILayout.LabelField("Test Response", test);
+
+        EditorGUILayout.Space();
+
+        if (GUILayout.Button("Query server"))
+        {
+            QueryServer();
+        }
+
+        EditorGUILayout.LabelField("Server State", state);
+        EditorGUILayout.LabelField("OpenAPI Version", version);
+
+        if (handleResponseQueue.Count > 0)
+        {
+            object o = handleResponseQueue.Dequeue();
+            if (o.Equals(pendingTest))
+            {
+                ResponseObject<string> response = o as ResponseObject<string>;
+                Debug.Log($"Get '{response.result}' from server");
+
+                test = response.result;
+                pendingTest = null;
+                EditorUtility.SetDirty(target);
+            }
+            else if (o.Equals(pendingState))
+            {
+                ResponseObject<string> response = o as ResponseObject<string>;
+                Debug.Log($"Get '{response.result}' from server");
+
+                state = response.result;
+                pendingState = null;
+                EditorUtility.SetDirty(target);
+            }
+            else if (o.Equals(pendingVersion))
+            {
+                ResponseObject<string> response = o as ResponseObject<string>;
+                Debug.Log($"Get '{response.result}' from server");
+
+                version = response.result;
+                pendingVersion = null;
+                EditorUtility.SetDirty(target);
+            }
+            else
+            {
+                Debug.Log("Unsupported response!");
+            }
+        }
+    }
+
+    public override bool RequiresConstantRepaint()
+    {
+        return handleResponseQueue.Count > 0;
+    }
+
+    void OnSceneGUI()
+    {
+        Debug.Log("OnSceneGUI");
+    }
+
+    private void TestPing()
+    {
+        test = "";
+        EditorUtility.SetDirty(target);
+
+        if (server == null)
+        {
+            Debug.LogError("No server defined!");
+            return;
+        }
+
+        //string response = AdminRequest.PingSync(server);
+        //EditorUtility.DisplayDialog("Test Server", $"Get '{response}' from server", "OK");
+
+        if (pendingTest != null)
+        {
+            pendingTest.Cancel();
+        }
+
+        pendingTest = AdminRequest.PingAsync(server, (response) =>
+        {
+            handleResponseQueue.Enqueue(response);
+            Debug.Log($"Request Time: { response.requestTime.ToLongTimeString() } / Total Time: { response.DeltaTime.TotalMilliseconds }ms\n\n<b>Content:</b>\n{ response.result }");
+        });
+        
+        Debug.Log("Starting request @ time: " + pendingTest.requestTime.ToLongTimeString() + "...");
+    }
+
+    private void QueryServer()
+    {
+        version = "";
+        state = "";
+
+        if (pendingState != null)
+        {
+            pendingState.Cancel();
+        }
+        
+        pendingState = AdminRequest.AdminAsync(server, (response) =>
+        {
+            handleResponseQueue.Enqueue(response);
+        });
+
+        if (pendingVersion != null)
+        {
+            pendingVersion.Cancel();
+        }
+
+        pendingVersion = AdminRequest.VersionAsync(server, (response) =>
+        {
+            handleResponseQueue.Enqueue(response);
+        });
+    }
+}
\ No newline at end of file
diff --git a/Editor/Scripts/WorldAnalysisServerEditor.cs.meta b/Editor/Scripts/WorldAnalysisServerEditor.cs.meta
new file mode 100644
index 0000000..b6c4ebc
--- /dev/null
+++ b/Editor/Scripts/WorldAnalysisServerEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9899978f4c750de4b98f81a9c6937a94
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Editor/Scripts/WorldAnalysisUserEditor.cs b/Editor/Scripts/WorldAnalysisUserEditor.cs
new file mode 100644
index 0000000..043379e
--- /dev/null
+++ b/Editor/Scripts/WorldAnalysisUserEditor.cs
@@ -0,0 +1,51 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2022 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: June 2022
+//
+
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEditor;
+
+using ETSI.ARF.WorldAnalysis;
+
+[CustomEditor(typeof(WorldAnalysisUser))]
+public class WorldStorageUserEditor : Editor
+{
+    WorldAnalysisUser user;
+
+    public void OnEnable()
+    {
+        user = (WorldAnalysisUser)target;
+    }
+
+    public override void OnInspectorGUI()
+    {
+        serializedObject.Update();
+
+        DrawDefaultInspector();
+        EditorGUILayout.Space();
+
+        if (GUILayout.Button("Generate New Creator UUID"))
+        {
+            user.UUID = System.Guid.NewGuid().ToString();
+            EditorUtility.SetDirty(target);
+        }
+    }
+}
diff --git a/Editor/Scripts/WorldAnalysisUserEditor.cs.meta b/Editor/Scripts/WorldAnalysisUserEditor.cs.meta
new file mode 100644
index 0000000..74303eb
--- /dev/null
+++ b/Editor/Scripts/WorldAnalysisUserEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b0d1b5ae7e5771b4496dfd778bfa031b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scriptables.meta b/Runtime/Scriptables.meta
new file mode 100644
index 0000000..058c09b
--- /dev/null
+++ b/Runtime/Scriptables.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 24a8b3224329f984c9b1737d44f11163
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scriptables/WorldAnalysisServer.cs b/Runtime/Scriptables/WorldAnalysisServer.cs
new file mode 100644
index 0000000..fb21b57
--- /dev/null
+++ b/Runtime/Scriptables/WorldAnalysisServer.cs
@@ -0,0 +1,39 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: August 2024
+//
+
+using UnityEngine;
+
+namespace ETSI.ARF.WorldAnalysis
+{
+    [System.Serializable]
+    [CreateAssetMenu(fileName = "ARFWorldAnalysisServer", menuName = "ARF World Analysis/Create Server", order = 1)]
+    public class WorldAnalysisServer : ScriptableObject
+    {
+        [SerializeField] public string serverName = "myServerName";
+        [SerializeField] public string company = "";
+        [SerializeField] public string basePath = "https://";
+        [SerializeField] public int port = 8080;
+
+        [Space(8)]
+        [SerializeField] public WorldAnalysisUser currentUser = null;
+
+        public string URI => port == 0 ? basePath : basePath + ":" + port.ToString();
+    }
+}
\ No newline at end of file
diff --git a/Runtime/Scriptables/WorldAnalysisServer.cs.meta b/Runtime/Scriptables/WorldAnalysisServer.cs.meta
new file mode 100644
index 0000000..7abd0ff
--- /dev/null
+++ b/Runtime/Scriptables/WorldAnalysisServer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4571d019d0609224aa4a14ed18de30cd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scriptables/WorldAnalysisUser.cs b/Runtime/Scriptables/WorldAnalysisUser.cs
new file mode 100644
index 0000000..85faade
--- /dev/null
+++ b/Runtime/Scriptables/WorldAnalysisUser.cs
@@ -0,0 +1,33 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: August 2024
+//
+
+using UnityEngine;
+
+namespace ETSI.ARF.WorldAnalysis
+{
+    [System.Serializable]
+    [CreateAssetMenu(fileName = "ARFWorldAnalysisUser", menuName = "ARF World Analysis/Create User", order = 1)]
+    public class WorldAnalysisUser : ScriptableObject
+    {
+        [SerializeField] public string userName = "myName";
+        [SerializeField] public string company = "";
+        [SerializeField] public string UUID = System.Guid.Empty.ToString();
+    }
+}
\ No newline at end of file
diff --git a/Runtime/Scriptables/WorldAnalysisUser.cs.meta b/Runtime/Scriptables/WorldAnalysisUser.cs.meta
new file mode 100644
index 0000000..93b285f
--- /dev/null
+++ b/Runtime/Scriptables/WorldAnalysisUser.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 01f9889f0a04026429aa8459e181e973
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/OpenAPI/BaseClient.cs b/Runtime/Scripts/OpenAPI/BaseClient.cs
new file mode 100644
index 0000000..c93808e
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/BaseClient.cs
@@ -0,0 +1,38 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace ETSI.ARF.OpenAPI.WorldAnalysis
+{
+    /// <summary>
+    /// Simple class to debug the requests
+    /// </summary>
+    public class BaseClient
+    {
+        static public bool EnableClientLog = true;
+        public string lastJsonText;
+        public long lastPayload;
+
+        protected void _prepareRequest(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url)
+        {
+            if (EnableClientLog)
+            {
+                Debug.Log("[REST][URL] Send request: " + client.BaseAddress + url);
+                Debug.Log("[REST][URL] Send request: " + request);
+            }
+        }
+
+        protected void _processResponse(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient client, System.Net.Http.HttpResponseMessage response)
+        {
+            lastJsonText = response.Content.ReadAsStringAsync().Result.ToString();
+            lastPayload = response.Content.Headers.ContentLength.Value;
+
+            var status_ = (int)response.StatusCode;
+
+            if (EnableClientLog)
+            {
+                Debug.Log("[REST][Data] Status: " + status_ + " Response: " + client.BaseAddress + " Len: " + lastPayload + " JSON: " + lastJsonText);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Runtime/Scripts/OpenAPI/BaseClient.cs.meta b/Runtime/Scripts/OpenAPI/BaseClient.cs.meta
new file mode 100644
index 0000000..0af7d2c
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/BaseClient.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 696362f892252db4ca192c6eccbbfa25
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/OpenAPI/DataModels.cs b/Runtime/Scripts/OpenAPI/DataModels.cs
new file mode 100644
index 0000000..91d04fc
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/DataModels.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace ETSI.ARF.OpenAPI.WorldAnalysis
+{
+    public interface IModel
+    {
+        public System.Guid Uuid { get; set; }  // Bug: SylR: Why is Uuid not capitalized (UUID)???
+
+        public string ToJson();
+    }
+
+    // Class to monitor the server
+    public class Server : IModel
+    {
+        public System.Guid Uuid { get; set; }
+        public string Name { get; set; }
+
+        public Server(string name)
+        {
+            Uuid = Guid.Empty;
+            Name = name;
+        }
+
+        public string ToJson() { return JsonUtility.ToJson(this); }
+    }
+
+    //
+    // Implement here some constructors
+    //
+    public partial class Pose : IModel
+    {
+        public Pose()
+        {
+            Uuid = Guid.NewGuid();
+        }
+
+        public string ToJson() { return JsonUtility.ToJson(this); }
+    }
+}
\ No newline at end of file
diff --git a/Runtime/Scripts/OpenAPI/DataModels.cs.meta b/Runtime/Scripts/OpenAPI/DataModels.cs.meta
new file mode 100644
index 0000000..ba6ef36
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/DataModels.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 90e60e9d41d419146b3b6207e4ef556e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/OpenAPI/Generated/WorldAnalysisOpenAPI.cs b/Runtime/Scripts/OpenAPI/Generated/WorldAnalysisOpenAPI.cs
index d9ac029..a59f807 100644
--- a/Runtime/Scripts/OpenAPI/Generated/WorldAnalysisOpenAPI.cs
+++ b/Runtime/Scripts/OpenAPI/Generated/WorldAnalysisOpenAPI.cs
@@ -24,11 +24,11 @@ namespace ETSI.ARF.OpenAPI.WorldAnalysis
     [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.7.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")]
     public partial class WorldAnalysisClient 
     {
-        private ETSI.ARF.OpenAPI.IHttpClient _httpClient;
+        private ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient _httpClient;
         private static System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings, true);
 
     #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
-        public WorldAnalysisClient(ETSI.ARF.OpenAPI.IHttpClient httpClient)
+        public WorldAnalysisClient(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient httpClient)
     #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
         {
             _httpClient = httpClient;
@@ -45,9 +45,9 @@ namespace ETSI.ARF.OpenAPI.WorldAnalysis
 
         static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);
 
-        partial void PrepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url);
-        partial void PrepareRequest(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
-        partial void ProcessResponse(ETSI.ARF.OpenAPI.IHttpClient client, System.Net.Http.HttpResponseMessage response);
+        partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url);
+        partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
+        partial void ProcessResponse(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient client, System.Net.Http.HttpResponseMessage response);
 
         /// <summary>
         /// Test the server availability.
diff --git a/Runtime/Scripts/OpenAPI/ResponseObject.cs b/Runtime/Scripts/OpenAPI/ResponseObject.cs
new file mode 100644
index 0000000..fa21f3d
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/ResponseObject.cs
@@ -0,0 +1,65 @@
+// The Fraunhofer HHI Unity Framework
+//  ___________                          .__            _____                ___ ___    ___ ___ .___ 
+//  \_   _____/___________   __ __  ____ |  |__   _____/ ____\___________   /   |   \  /   |   \|   |
+//   |    __) \_  __ \__  \ |  |  \/    \|  |  \ /  _ \   __\/ __ \_  __ \ /    ~    \/    ~    \   |
+//   |     \   |  | \// __ \|  |  /   |  \   Y  (  <_> )  | \  ___/|  | \/ \    Y    /\    Y    /   |
+//   \___  /   |__|  (____  /____/|___|  /___|  /\____/|__|  \___  >__|     \___|_  /  \___|_  /|___|
+//       \/               \/           \/     \/                 \/               \/         \/      
+// (C) Fraunhofer HHI, 2024
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+using UnityEngine;
+
+namespace ETSI.ARF.OpenAPI.WorldAnalysis
+{
+    public class CancelToken
+    {
+        protected CancellationTokenSource tokenSource;
+        protected CancellationToken ct;
+
+        public CancellationToken cancellationToken { get => ct; }
+
+        public void Cancel()
+        {
+            tokenSource.Cancel();
+        }
+    }
+
+    public class ResponseObject<T> : CancelToken
+    {
+        // Management stuffs
+        static int ID = 0;
+        public int transactionId = 0;
+        public string message = "";     // custom message, type of data...
+
+        // Time monitoring
+        public TimeSpan DeltaTime { get => responseTime - requestTime; }
+        public DateTime requestTime;
+        public DateTime responseTime;
+
+        // Incoming data
+        public T result;
+        public int payload;   // size of data
+
+        //public string result = "";      // text result
+        //public object data = null;      // custom result
+
+        // Callback
+        public Action<ResponseObject<T>> callback;
+
+
+        public ResponseObject(string msg, Action<ResponseObject<T>> func = null)
+        {
+            requestTime = DateTime.Now;
+            message = msg;
+            callback = func;
+            transactionId = ++ID;
+
+            tokenSource = new CancellationTokenSource();
+            ct = tokenSource.Token;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Runtime/Scripts/OpenAPI/ResponseObject.cs.meta b/Runtime/Scripts/OpenAPI/ResponseObject.cs.meta
new file mode 100644
index 0000000..0f1afb5
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/ResponseObject.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 82dc58594acebf747bd716fd00fcfb10
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs
new file mode 100644
index 0000000..8d696aa
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs
@@ -0,0 +1,225 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: June 2024
+//
+
+// Depends on UniTask to support cancellation token and GetAwaiter: https://github.com/Cysharp/UniTask
+// Otherwise, the code can be adapted using https://gist.github.com/krzys-h/9062552e33dd7bd7fe4a6c12db109a1a
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading;
+using System.Threading.Tasks;
+//using Cysharp.Threading.Tasks;
+
+using UnityEngine;
+using UnityEngine.Networking;
+
+namespace ETSI.ARF.OpenAPI.WorldAnalysis
+{
+    public interface IHttpClient
+    {
+        public Uri BaseAddress { get; set; }
+        public HttpRequestHeaders DefaultRequestHeaders { get; }
+
+        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage message, HttpCompletionOption option,
+            CancellationToken token);
+
+        public void Dispose();
+    }
+
+    public class BasicHTTPClient : IHttpClient
+    {
+
+        public BasicHTTPClient() { }
+
+        public BasicHTTPClient(string baseUri)
+        {
+            BaseAddress = new Uri(baseUri);
+            _httpClient.BaseAddress = BaseAddress;
+        }
+
+        public BasicHTTPClient(Uri baseUri)
+        {
+            BaseAddress = baseUri;
+            _httpClient.BaseAddress = BaseAddress;
+        }
+
+        public Uri BaseAddress { get; set; }
+        public HttpRequestHeaders DefaultRequestHeaders => _httpClient.DefaultRequestHeaders;
+
+        private readonly HttpClient _httpClient = new HttpClient();
+
+        public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage message, HttpCompletionOption option, CancellationToken token)
+        {
+            return await _httpClient.SendAsync(message, option, token);
+        }
+
+        public void Dispose()
+        {
+            _httpClient.Dispose();
+            DefaultRequestHeaders.Clear();
+            BaseAddress = null;
+        }
+    }
+
+    public class UnityWebRequestHttpClient : IHttpClient
+    {
+        public UnityWebRequestHttpClient() { }
+
+        public UnityWebRequestHttpClient(string baseUri)
+        {
+            BaseAddress = new Uri(baseUri);
+        }
+
+        public UnityWebRequestHttpClient(Uri baseUri)
+        {
+            BaseAddress = baseUri;
+        }
+
+        public Uri BaseAddress { get; set; }
+        public HttpRequestHeaders DefaultRequestHeaders => _httpClient.DefaultRequestHeaders;
+
+        private readonly HttpClient _httpClient = new HttpClient();
+
+        public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage message, HttpCompletionOption option, CancellationToken token)
+        {
+            var content = await (message.Content?.ReadAsStringAsync() ?? Task.FromResult(""));
+            var webRequest = GetUnityWebRequest(message.Method.Method, message.RequestUri, content);
+
+            AppendHeaders(webRequest);
+
+            Debug.Log("[HTTP] Request " + webRequest.uri.ToString());
+            try
+            {
+                //SylR
+                webRequest.SendWebRequest();
+                while (!webRequest.isDone)
+                {
+                    if (token.IsCancellationRequested)
+                    {
+                        Debug.Log($"Task '{ message.RequestUri }' cancelled");
+                        token.ThrowIfCancellationRequested();
+                    }
+                    await Task.Yield();
+                }
+
+                //await webRequest
+                //    .SendWebRequest()
+                //        .WithCancellation(cancellationToken: token);
+            }
+            catch (Exception)
+            {
+                webRequest.Dispose();
+                throw;
+            }
+
+            Debug.Log("[HTTP] Result: " + webRequest.result.ToString());
+
+            var responseMessage = CreateHttpResponseMessage(webRequest);
+            webRequest.Dispose();
+
+            Debug.Log("[HTTP] Response len: " + responseMessage.Content.Headers.ContentLength);
+
+            return responseMessage;
+        }
+
+        public void Dispose()
+        {
+            _httpClient.Dispose();
+            DefaultRequestHeaders.Clear();
+            BaseAddress = null;
+        }
+
+        private UnityWebRequest GetUnityWebRequest(string method, Uri endpoint, string content = "")
+        {
+            var requestUri = BaseAddress.AbsoluteUri + endpoint;
+            var webRequest = UnityWebRequest.Get(requestUri);
+            webRequest.method = method;
+
+            webRequest.disposeUploadHandlerOnDispose = true;
+            webRequest.disposeDownloadHandlerOnDispose = true;
+
+            if (!string.IsNullOrEmpty(content))
+            {
+                var data = new System.Text.UTF8Encoding().GetBytes(content);
+                webRequest.uploadHandler = new UploadHandlerRaw(data);
+                webRequest.SetRequestHeader("Content-Type", "application/json");
+                //webRequest.SetRequestHeader("Content-Type", "image/jpeg");
+            }
+            return webRequest;
+        }
+
+        private void AppendHeaders(UnityWebRequest webRequest)
+        {
+            using var enumerator = DefaultRequestHeaders.GetEnumerator();
+
+            while (enumerator.MoveNext())
+            {
+                var (key, value) = enumerator.Current;
+                webRequest.SetRequestHeader(key, value.First());
+            }
+        }
+
+        private HttpResponseMessage CreateHttpResponseMessage(UnityWebRequest webRequest)
+        {
+            var responseContent = webRequest.downloadHandler?.text;
+
+            var response = new HttpResponseMessage();
+            response.Content = new StringContent(responseContent);
+            response.StatusCode = (HttpStatusCode)webRequest.responseCode;
+
+            Dictionary<string, string> headers = webRequest.GetResponseHeaders();
+
+            if (headers != null)
+            {
+                Debug.Log("[HTTP] Header: " + headers.Count.ToString());
+                foreach (var h in headers)
+                {
+                    switch (h.Key.ToLower().Trim())
+                    {
+                        case "content-type":
+                            {
+                                var trimmed = h.Value.ToLower().Split(";").FirstOrDefault();
+                                response.Content.Headers.ContentType = new MediaTypeHeaderValue(trimmed);
+                                break;
+                            }
+                        case "content-length":
+                            response.Content.Headers.ContentLength = long.Parse(h.Value);
+                            break;
+
+                        default:
+                            if (h.Value == "gzip")
+                            {
+                                // bug???
+                            }
+                            else
+                                response.Headers.Add(h.Key, h.Value);
+                            break;
+                    }
+                }
+            }
+            return response;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs.meta b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs.meta
new file mode 100644
index 0000000..7524d3a
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/UnityWebRequestHttpClient.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4aa105d9487dc27408feffefde9e4475
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/OpenAPI/WorldAnalysisClient.cs b/Runtime/Scripts/OpenAPI/WorldAnalysisClient.cs
new file mode 100644
index 0000000..852ee38
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/WorldAnalysisClient.cs
@@ -0,0 +1,28 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Networking;
+
+namespace ETSI.ARF.OpenAPI.WorldAnalysis
+{
+    /// <summary>
+    /// Catch the pre/pos request methods from the autogenerated classes
+    /// </summary>
+    public partial class WorldAnalysisClient : BaseClient
+    {
+        partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient client, System.Net.Http.HttpRequestMessage request, string url)
+        {
+            _prepareRequest(client, request, url);
+        }
+
+        partial void PrepareRequest(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder)
+        {
+            // do something...
+        }
+
+        partial void ProcessResponse(ETSI.ARF.OpenAPI.WorldAnalysis.IHttpClient client, System.Net.Http.HttpResponseMessage response)
+        {
+            _processResponse(client, response);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Runtime/Scripts/OpenAPI/WorldAnalysisClient.cs.meta b/Runtime/Scripts/OpenAPI/WorldAnalysisClient.cs.meta
new file mode 100644
index 0000000..077447f
--- /dev/null
+++ b/Runtime/Scripts/OpenAPI/WorldAnalysisClient.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 748d04737c53fc04697ac6888226e399
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/REST.meta b/Runtime/Scripts/REST.meta
new file mode 100644
index 0000000..29c8716
--- /dev/null
+++ b/Runtime/Scripts/REST.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6f0fd52fd30564a4c838a545fe0d00ec
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/REST/AdminRequest.cs b/Runtime/Scripts/REST/AdminRequest.cs
new file mode 100644
index 0000000..9910526
--- /dev/null
+++ b/Runtime/Scripts/REST/AdminRequest.cs
@@ -0,0 +1,101 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: March 2024
+//
+
+using System;
+using System.Threading.Tasks;
+using UnityEngine;
+
+using ETSI.ARF.OpenAPI;
+using ETSI.ARF.OpenAPI.WorldAnalysis;
+
+namespace ETSI.ARF.WorldAnalysis.REST
+{
+    public class AdminRequest : RequestBase<string>
+    {
+        //
+        // Wrapper for the endpoints
+        //
+        static public string PingSync(WorldAnalysisServer ws)
+        {
+            wsServer = ws;
+            var httpClient = new BasicHTTPClient(ws.URI);
+            apiClient = new WorldAnalysisClient(httpClient);
+
+            string response = apiClient.GetPing();
+            return response;
+        }
+
+        static public ResponseObject<string> PingAsync(WorldAnalysisServer ws, Action<ResponseObject<string>> func)
+        {
+            wsServer = ws;
+            var httpClient = new UnityWebRequestHttpClient(ws.URI);
+            apiClient = new WorldAnalysisClient(httpClient);
+
+            Debug.Log("[REST] Request Ping...");
+            ResponseObject<string> ro = new ResponseObject<string>("Request Ping", func);
+            apiClient.GetPingAsync(ro.cancellationToken).ContinueWith(OnReceiveObject<string>, ro);
+            return ro;
+        }
+
+        static public string AdminSync(WorldAnalysisServer ws)
+        {
+            wsServer = ws;
+            var httpClient = new BasicHTTPClient(ws.URI);
+            apiClient = new WorldAnalysisClient(httpClient);
+
+            string response = apiClient.GetAdmin();
+            return response;
+        }
+
+        static public ResponseObject<string> AdminAsync(WorldAnalysisServer ws, Action<ResponseObject<string>> func)
+        {
+            wsServer = ws;
+            var httpClient = new UnityWebRequestHttpClient(ws.URI);
+            apiClient = new WorldAnalysisClient(httpClient);
+
+            Debug.Log("[REST] Request Admin...");
+            ResponseObject<string> ro = new ResponseObject<string>("Request Admin", func);
+            apiClient.GetAdminAsync(ro.cancellationToken).ContinueWith(OnReceiveObject<string>, ro);
+            return ro;
+        }
+
+        static public string VersionSync(WorldAnalysisServer ws)
+        {
+            wsServer = ws;
+            var httpClient = new BasicHTTPClient(ws.URI);
+            apiClient = new WorldAnalysisClient(httpClient);
+
+            string response = apiClient.GetVersion();
+            return response;
+        }
+
+        static public ResponseObject<string> VersionAsync(WorldAnalysisServer ws, Action<ResponseObject<string>> func)
+        {
+            wsServer = ws;
+            var httpClient = new UnityWebRequestHttpClient(ws.URI);
+            apiClient = new WorldAnalysisClient(httpClient);
+
+            Debug.Log("[REST] Request Version...");
+            ResponseObject<string> ro = new ResponseObject<string>("Request Version", func);
+            apiClient.GetVersionAsync(ro.cancellationToken).ContinueWith(OnReceiveObject<string>, ro);
+            return ro;
+        }
+    }
+}
diff --git a/Runtime/Scripts/REST/AdminRequest.cs.meta b/Runtime/Scripts/REST/AdminRequest.cs.meta
new file mode 100644
index 0000000..29a5fd8
--- /dev/null
+++ b/Runtime/Scripts/REST/AdminRequest.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f287a535887d14c46859e33386b90b0e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/REST/RequestBase.cs b/Runtime/Scripts/REST/RequestBase.cs
new file mode 100644
index 0000000..6650e8f
--- /dev/null
+++ b/Runtime/Scripts/REST/RequestBase.cs
@@ -0,0 +1,79 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: March 2024
+//
+
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using UnityEngine;
+
+using ETSI.ARF.OpenAPI;
+using ETSI.ARF.OpenAPI.WorldAnalysis;
+
+namespace ETSI.ARF.WorldAnalysis.REST
+{
+    public class RequestBase<T> // where T : Trackable, WorldAnchor, WorldLink
+    {
+        static protected WorldAnalysisServer wsServer;
+        static protected WorldAnalysisClient apiClient;
+
+        static protected string token = "ARF_Permission";
+
+        // Cache the current list
+        static public Dictionary<Guid, object> listOfObjects = new Dictionary<Guid, object>();
+
+
+        //
+        // Helpers
+        //
+        static protected void OnReceiveObject<TObj>(Task<TObj> t, object id)
+        {
+            if (t.IsCompleted)
+            {
+                ResponseObject<TObj> o = (ResponseObject<TObj>)id;
+                o.responseTime = DateTime.Now;
+                o.result = t.Result;
+                Debug.Log($"[REST] Server Response = {o.result.ToString()} (ID={o.transactionId}, Msg={o.message})");
+
+                o.callback?.Invoke(o);
+            }
+            else Debug.Log("[REST] OpenAPI Timeout!");
+        }
+
+        static protected void OnReceiveListOfObjects<TObj>(Task<List<TObj>> t, object id) where TObj : IModel
+        {
+            if (t.IsCompleted)
+            {
+                ResponseObject<List<TObj>> o = (ResponseObject<List<TObj>>)id;
+                o.responseTime = DateTime.Now;
+                o.result = t.Result;
+                Debug.Log($"[REST] Server Response = Got {o.result.Count} entrie(s) (ID={o.transactionId}, Msg={o.message})");
+
+                listOfObjects.Clear();
+                foreach (var i in o.result)
+                {
+                    listOfObjects.Add(i.Uuid, i);
+                }
+                o.callback?.Invoke(o);
+            }
+            else Debug.Log("[REST] OpenAPI Timeout!");
+        }
+
+    }
+}
diff --git a/Runtime/Scripts/REST/RequestBase.cs.meta b/Runtime/Scripts/REST/RequestBase.cs.meta
new file mode 100644
index 0000000..2bb32b0
--- /dev/null
+++ b/Runtime/Scripts/REST/RequestBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c6453e5289606a848ae29ddffa0f7288
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/WorldAnalysisInfo.cs b/Runtime/Scripts/WorldAnalysisInfo.cs
new file mode 100644
index 0000000..b461d5e
--- /dev/null
+++ b/Runtime/Scripts/WorldAnalysisInfo.cs
@@ -0,0 +1,45 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: August 2024
+//
+
+using ETSI.ARF.WorldAnalysis;
+using UnityEngine;
+
+public class WorldAnalysisInfo : MonoBehaviour
+{
+    public WorldAnalysisServer worldAnalysisServer;
+
+    //public bool isServerAlive()
+    //{
+    //    if (worldStorageServer == null) return false;
+    //    return !string.IsNullOrEmpty(ETSI.ARF.WorldStorage.REST.AdminRequest.Ping(worldStorageServer));
+    //}
+
+    //public string GetServerState()
+    //{
+    //    if (worldStorageServer == null) return "No Server Defined!";
+    //    return ETSI.ARF.WorldStorage.REST.AdminRequest.GetAdminInfo(worldStorageServer);
+    //}
+
+    //public string GetAPIVersion()
+    //{
+    //    if (worldStorageServer == null) return "Unknown Version!";
+    //    return ETSI.ARF.WorldStorage.REST.AdminRequest.GetVersion(worldStorageServer);
+    //}
+}
diff --git a/Runtime/Scripts/WorldAnalysisInfo.cs.meta b/Runtime/Scripts/WorldAnalysisInfo.cs.meta
new file mode 100644
index 0000000..3190dcd
--- /dev/null
+++ b/Runtime/Scripts/WorldAnalysisInfo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 269d5f98c3c478c4983c24ec09d10a70
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Scripts/WorldAnalysisREST.cs b/Runtime/Scripts/WorldAnalysisREST.cs
index 5c18ceb..ca881cc 100644
--- a/Runtime/Scripts/WorldAnalysisREST.cs
+++ b/Runtime/Scripts/WorldAnalysisREST.cs
@@ -1,11 +1,23 @@
+using System;
 using UnityEngine;
 using ETSI.ARF.OpenAPI.WorldAnalysis;
+using ETSI.ARF.WorldAnalysis;
 using static WorldAnalysisInterface;
-using System;
+using ETSI.ARF.WorldAnalysis.REST;
 
 //Implementation of the WorldAnalysis interface
 public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
 {
+    static protected string token = "ARF_Permission";
+
+    public WorldAnalysisServer waServer;
+
+    // For sync calls
+    private WorldAnalysisClient apiClient;
+
+    // For async calls
+    private WorldAnalysisClient apiClientAsync;
+
 
     #region Unity_Methods
 
@@ -14,6 +26,13 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
     /// </summary>
     protected void Awake()
     {
+        // sync
+        var httpClient = new BasicHTTPClient(waServer.URI);
+        apiClient = new WorldAnalysisClient(httpClient);
+
+        // async
+        //var httpClientAsync = new UnityWebRequestHttpClient(waServer.URI);
+        //apiClientAsync = new WorldAnalysisClient(httpClientAsync);
     }
 
     /// <summary>
@@ -32,10 +51,48 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
 
     #endregion
 
+    #region Test methods
+    public void CheckServer()
+    {
+        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);
+    }
 
-    #region ARF_API
+    public string GetWebSocketEndpoint()
+    {
+        string res = "empty";
+
+        SubscriptionSingleRequest param = new SubscriptionSingleRequest();
+        param.Mode = Mode_WorldAnalysis.DEVICE_TO_TRACKABLES;
+        param.Target = Guid.Parse("fa8bbe40-8052-11ec-a8a3-0242ac120002"); // test
+
+        SubscriptionSingle response = apiClient.SubscribeToPose(token, "1", param);
+        res = response.WebsocketUrl;
+        return res;
+    } 
+    
+    public void PrintCapabilities()
+    {
+        string res = "Capabilities:";
+
+        Response2 cap = apiClient.GetCapabilities(token, "1");
+        foreach (var item in cap.Capabilities)
+        {
+            res += "\n" + item.TrackableType;
+        }
+        Debug.Log("[REST] Capabilities: " + res);
+    }
+    #endregion
 
-    public  AskFrameRateResult SetPoseEstimationFramerate(string token, PoseConfigurationTrackableType type, EncodingInformationStructure encodingInformation, int minimumFramerate)
+    #region ARF_API
+    //
+    // Implementation of the endpoints
+    //
+    public AskFrameRateResult SetPoseEstimationFramerate(string token, PoseConfigurationTrackableType type, EncodingInformationStructure encodingInformation, int minimumFramerate)
     {
         return AskFrameRateResult.NOT_SUPPORTED; ///We cannot set any framerate for tracking on ARKit and ARCore
     }
@@ -47,7 +104,7 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
     }
 
 
-    public PoseEstimationResult[] GetLastPoses(string token, Guid[] uuids, Mode_WorldAnalysis [] modes, out ETSI.ARF.OpenAPI.WorldAnalysis.Pose[] poses)
+    public PoseEstimationResult[] GetLastPoses(string token, Guid[] uuids, Mode_WorldAnalysis[] modes, out ETSI.ARF.OpenAPI.WorldAnalysis.Pose[] poses)
     {
         poses = null;
         return null;
@@ -59,7 +116,7 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
         return InformationSubscriptionResult.OK;
     }
 
-    public InformationSubscriptionResult[] SubscribeToPoses(string token, Guid[] uuids, Mode_WorldAnalysis [] modes, PoseCallback callback, ref int validity, out Guid[] subscriptionUUIDs)
+    public InformationSubscriptionResult[] SubscribeToPoses(string token, Guid[] uuids, Mode_WorldAnalysis[] modes, PoseCallback callback, ref int validity, out Guid[] subscriptionUUIDs)
     {
         subscriptionUUIDs = null;
         return null;
@@ -90,7 +147,7 @@ public class WorldAnalysisREST : MonoBehaviour, WorldAnalysisInterface
         return CapabilityResult.OK;
     }
 
-    public CapabilityResult GetCapability(string token, Guid uuid, out bool isSupported, out TypeWorldStorage type, out Capability [] capability)
+    public CapabilityResult GetCapability(string token, Guid uuid, out bool isSupported, out TypeWorldStorage type, out Capability[] capability)
     {
         isSupported = false;
         type = TypeWorldStorage.UNKNOWN;
-- 
GitLab