├── README.md.meta ├── Prefabs ├── SelfSpeechGesture.prefab.meta ├── SelfStatusGesture.prefab.meta ├── TopicClientWidget.prefab.meta ├── SelfDisplayGesture.prefab.meta ├── SelfMicrophoneSensor.prefab.meta ├── SelfRemoteSpeechGesture.prefab.meta ├── SelfMicrophoneSensor.prefab ├── SelfRemoteSpeechGesture.prefab ├── SelfSpeechGesture.prefab ├── SelfStatusGesture.prefab ├── SelfDisplayGesture.prefab └── TopicClientWidget.prefab ├── Prefabs.meta ├── Scripts.meta ├── Scripts ├── Agents.meta ├── Gestures.meta ├── Sensors.meta ├── Services.meta ├── Topics.meta ├── Utils.meta ├── Widgets.meta ├── UnitTests.meta ├── Agents │ ├── IThing.cs.meta │ ├── BlackBoard.cs.meta │ ├── IThing.cs │ └── BlackBoard.cs ├── Gestures │ ├── IGesture.cs.meta │ ├── GestureManager.cs.meta │ ├── IGesture.cs │ └── GestureManager.cs ├── Sensors │ ├── AudioData.cs.meta │ ├── ISensor.cs.meta │ ├── ISensorData.cs.meta │ ├── SensorManager.cs.meta │ ├── ISensorData.cs │ ├── AudioData.cs │ ├── ISensor.cs │ └── SensorManager.cs ├── Topics │ ├── TopicClient.cs.meta │ └── TopicClient.cs ├── Utils │ ├── ISerializable.cs.meta │ ├── SelfExplorer.cs.meta │ ├── SelfLogin.cs.meta │ ├── SelfDiscovery.cs.meta │ ├── ISerializable.cs │ ├── SelfLogin.cs │ ├── SelfDiscovery.cs │ └── SelfExplorer.cs ├── Widgets │ ├── DataTypes.cs.meta │ ├── SelfDisplayGesture.cs.meta │ ├── SelfMicrophoneSensor.cs.meta │ ├── SelfSpeechGesture.cs.meta │ ├── SelfStatusGesture.cs.meta │ ├── TopicClientWidget.cs.meta │ ├── SelfRemoteSpeechGesture.cs.meta │ ├── TopicClientWidget.cs │ ├── DataTypes.cs │ ├── SelfStatusGesture.cs │ ├── SelfDisplayGesture.cs │ ├── SelfRemoteSpeechGesture.cs │ ├── SelfSpeechGesture.cs │ └── SelfMicrophoneSensor.cs ├── Services │ ├── RobotGateway.cs.meta │ └── RobotGateway.cs └── UnitTests │ ├── TestBlackBoard.cs.meta │ ├── TestSelfDiscovery.cs.meta │ ├── TestSelfExplorer.cs.meta │ ├── TestTopicClient.cs.meta │ ├── TestSelfDiscovery.cs │ ├── TestSelfExplorer.cs │ ├── TestBlackBoard.cs │ └── TestTopicClient.cs └── README.md /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8f36e531be47ec84196e2c27b5f16a66 3 | timeCreated: 1472569055 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/SelfSpeechGesture.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 320d2ecea8d2a944494ee6dae16873f9 3 | timeCreated: 1473547287 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/SelfStatusGesture.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0999f39fba7df0841ab684474c2fe293 3 | timeCreated: 1473623147 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/TopicClientWidget.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 09ed28a12f15e411984f46f568e2e7b4 3 | timeCreated: 1488848419 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 852c85624961db84f80ab702ca74a417 3 | folderAsset: yes 4 | timeCreated: 1472572569 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Prefabs/SelfDisplayGesture.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e719691533f23f64dbc6c4a21f71bd5d 3 | timeCreated: 1475434334 4 | licenseType: Free 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Prefabs/SelfMicrophoneSensor.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8c47d3d598fc887438b876b673f3cffc 3 | timeCreated: 1473200514 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b13071ea1789a4f4c83e6a13cfe80f75 3 | folderAsset: yes 4 | timeCreated: 1472572575 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Prefabs/SelfRemoteSpeechGesture.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 58cd0a981ee3b4e54880c571e6f3d54b 3 | timeCreated: 1484773043 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/Agents.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 633898b896fcd874aac4161450430231 3 | folderAsset: yes 4 | timeCreated: 1473707477 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scripts/Gestures.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 17776b62069143b48bd891f6eb86884e 3 | folderAsset: yes 4 | timeCreated: 1472744179 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scripts/Sensors.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1dec029ded233e04cb161f6c95548c89 3 | folderAsset: yes 4 | timeCreated: 1472744180 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scripts/Services.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cdd8dcfce0ad4f24b969ce3b1a829621 3 | folderAsset: yes 4 | timeCreated: 1475013803 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scripts/Topics.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 879943443e9584a47a89731b2615de1b 3 | folderAsset: yes 4 | timeCreated: 1472744180 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scripts/Utils.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 023cc35bda1567549a9a99b4c035f528 3 | folderAsset: yes 4 | timeCreated: 1473792964 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scripts/Widgets.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ce6dbd8d3eabf1e4797bef43369d6fe2 3 | folderAsset: yes 4 | timeCreated: 1475866250 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scripts/UnitTests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 90bd4409537cdf64da7e8a3414d3881e 3 | folderAsset: yes 4 | timeCreated: 1472745175 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scripts/Agents/IThing.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0939fdc95885e6a4e85bc415a724b317 3 | timeCreated: 1473709609 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Agents/BlackBoard.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 38e22ba79ab0f214d8785594b1492ee4 3 | timeCreated: 1473707477 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Gestures/IGesture.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a80ce7b205e5fef4c84f9a44569139ec 3 | timeCreated: 1473278569 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Sensors/AudioData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3efbb6cd3d083984cb46785b3f553777 3 | timeCreated: 1473279206 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Sensors/ISensor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82670acba055138498e2edf44028bbb2 3 | timeCreated: 1472744180 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Sensors/ISensorData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8bbfe48bb793a0f43b22355a44721cd9 3 | timeCreated: 1472744180 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Topics/TopicClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1b8d2cef4c51974ebb09ea285a43e71 3 | timeCreated: 1472593600 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Utils/ISerializable.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5bed19895ee14804baf8e54aa664be61 3 | timeCreated: 1473792964 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Utils/SelfExplorer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2cba4dd9ca8a5d94e945b37652e50fe3 3 | timeCreated: 1474475306 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Utils/SelfLogin.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 671d5be2cb2787c499d2386fd071a693 3 | timeCreated: 1475079431 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Widgets/DataTypes.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6b349e8fbdf90f24fb6ed6f0d5d503e0 3 | timeCreated: 1473566634 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Gestures/GestureManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f28d7c39fc74716418483596705b4ad4 3 | timeCreated: 1472739737 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Sensors/SensorManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af33131e9fc1acd469e7c7addac20798 3 | timeCreated: 1472744180 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Services/RobotGateway.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d2d900082ccd6e4aad5e782b5a351dd 3 | timeCreated: 1475013803 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/UnitTests/TestBlackBoard.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 076496b0450d04645b800d8eb71a2570 3 | timeCreated: 1473793164 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Utils/SelfDiscovery.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b03fa0258cc982742b91a32098d207d1 3 | timeCreated: 1485406119 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/UnitTests/TestSelfDiscovery.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 167ef1e4a192f4247af3db9c62a19a00 3 | timeCreated: 1485407398 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/UnitTests/TestSelfExplorer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e8bc286c078ff584588351b620b15f8c 3 | timeCreated: 1474475306 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/UnitTests/TestTopicClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 019bcafdc8e71994db0b2b0fa9dacfd1 3 | timeCreated: 1472745175 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfDisplayGesture.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 85a3a8e3eae0b444abcbf4d836a2f773 3 | timeCreated: 1475866250 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfMicrophoneSensor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5341aa4b34dd09b428ef78cf43cd69e3 3 | timeCreated: 1473546411 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfSpeechGesture.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a64bdd0024f28bc4d87c02c3b116be93 3 | timeCreated: 1475866250 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfStatusGesture.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9e7ec43af1bb337428b72eaee79aeb71 3 | timeCreated: 1475866250 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Widgets/TopicClientWidget.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b1f688dcd9b234e068abe046cf5f667e 3 | timeCreated: 1488843355 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfRemoteSpeechGesture.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: de2736dc372b64ce9ab08773a6909791 3 | timeCreated: 1484767824 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scripts/Utils/ISerializable.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System.Collections; 19 | 20 | namespace IBM.Watson.Self.Utils 21 | { 22 | public interface ISerializable 23 | { 24 | //! This object should serialize into a IDictionary object 25 | IDictionary Serialize(); 26 | //! This object should create itself from a IDictionary object 27 | void Deserialize( IDictionary a_json ); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Scripts/Sensors/ISensorData.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System; 19 | using System.Collections; 20 | using System.Text; 21 | 22 | namespace IBM.Watson.Self.Sensors 23 | { 24 | /// 25 | /// Interface for any type of data that can be sent by a sensor. 26 | /// 27 | public abstract class ISensorData 28 | { 29 | #region ISensorData interface 30 | public abstract byte [] ToBinary(); // convert this data into a binary block of data suitable for sending 31 | #endregion 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Scripts/Sensors/AudioData.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using IBM.Watson.DeveloperCloud.Utilities; 19 | 20 | namespace IBM.Watson.Self.Sensors 21 | { 22 | /// 23 | /// Data container object for AudioData. 24 | /// 25 | public class AudioData : ISensorData 26 | { 27 | public AudioData( DeveloperCloud.DataTypes.AudioData a_Audio ) 28 | { 29 | m_Audio = a_Audio; 30 | } 31 | 32 | public override byte[] ToBinary() 33 | { 34 | return AudioClipUtil.GetL16(m_Audio.Clip); 35 | } 36 | 37 | private DeveloperCloud.DataTypes.AudioData m_Audio; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Scripts/Gestures/IGesture.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | using System; 19 | using System.Collections; 20 | 21 | namespace IBM.Watson.Self.Gestures 22 | { 23 | public delegate void OnGestureDone(IGesture a_Gesture, bool a_bError); 24 | 25 | //! This is the base class for a self gesture. 26 | public interface IGesture 27 | { 28 | //! The ID of this gesture. 29 | string GetGestureId(); 30 | //! return an ID unique to this instance 31 | string GetInstanceId(); 32 | //! Initialize this gesture object, returns false if gesture can't be initialized 33 | bool OnStart(); 34 | //! Shutdown this gesture object. 35 | bool OnStop(); 36 | //! Execute this gesture, the provided callback should be invoked when the gesture is complete. 37 | bool Execute(OnGestureDone a_Callback, IDictionary a_Params); 38 | //! Abort this gesture, if true is returned then abort succeeded and callback will NOT be invoked. 39 | bool Abort(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Prefabs/SelfMicrophoneSensor.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1000011007810106} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1000011007810106 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 4 20 | m_Component: 21 | - 4: {fileID: 4000012735503970} 22 | - 114: {fileID: 114000010217018618} 23 | m_Layer: 0 24 | m_Name: SelfMicrophoneSensor 25 | m_TagString: Untagged 26 | m_Icon: {fileID: 0} 27 | m_NavMeshLayer: 0 28 | m_StaticEditorFlags: 0 29 | m_IsActive: 1 30 | --- !u!4 &4000012735503970 31 | Transform: 32 | m_ObjectHideFlags: 1 33 | m_PrefabParentObject: {fileID: 0} 34 | m_PrefabInternal: {fileID: 100100000} 35 | m_GameObject: {fileID: 1000011007810106} 36 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 37 | m_LocalPosition: {x: 0, y: 0, z: 0} 38 | m_LocalScale: {x: 1, y: 1, z: 1} 39 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 40 | m_Children: [] 41 | m_Father: {fileID: 0} 42 | m_RootOrder: 0 43 | --- !u!114 &114000010217018618 44 | MonoBehaviour: 45 | m_ObjectHideFlags: 1 46 | m_PrefabParentObject: {fileID: 0} 47 | m_PrefabInternal: {fileID: 100100000} 48 | m_GameObject: {fileID: 1000011007810106} 49 | m_Enabled: 1 50 | m_EditorHideFlags: 0 51 | m_Script: {fileID: 11500000, guid: 5341aa4b34dd09b428ef78cf43cd69e3, type: 3} 52 | m_Name: 53 | m_EditorClassIdentifier: 54 | m_AutoConnect: 1 55 | -------------------------------------------------------------------------------- /Prefabs/SelfRemoteSpeechGesture.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1000012018470834} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1000012018470834 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 4 20 | m_Component: 21 | - 4: {fileID: 4000012655068784} 22 | - 114: {fileID: 114000011888535922} 23 | m_Layer: 0 24 | m_Name: SelfRemoteSpeechGesture 25 | m_TagString: Untagged 26 | m_Icon: {fileID: 0} 27 | m_NavMeshLayer: 0 28 | m_StaticEditorFlags: 0 29 | m_IsActive: 1 30 | --- !u!4 &4000012655068784 31 | Transform: 32 | m_ObjectHideFlags: 1 33 | m_PrefabParentObject: {fileID: 0} 34 | m_PrefabInternal: {fileID: 100100000} 35 | m_GameObject: {fileID: 1000012018470834} 36 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 37 | m_LocalPosition: {x: 0, y: 0, z: 0} 38 | m_LocalScale: {x: 1, y: 1, z: 1} 39 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 40 | m_Children: [] 41 | m_Father: {fileID: 0} 42 | m_RootOrder: 0 43 | --- !u!114 &114000011888535922 44 | MonoBehaviour: 45 | m_ObjectHideFlags: 1 46 | m_PrefabParentObject: {fileID: 0} 47 | m_PrefabInternal: {fileID: 100100000} 48 | m_GameObject: {fileID: 1000012018470834} 49 | m_Enabled: 1 50 | m_EditorHideFlags: 0 51 | m_Script: {fileID: 11500000, guid: de2736dc372b64ce9ab08773a6909791, type: 3} 52 | m_Name: 53 | m_EditorClassIdentifier: 54 | m_AutoConnect: 1 55 | m_InstanceId: ff8c6b16-3806-4dd2-8731-36d83c1c0024 56 | -------------------------------------------------------------------------------- /Prefabs/SelfSpeechGesture.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1000012211108868} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1000012211108868 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 4 20 | m_Component: 21 | - 4: {fileID: 4000013839730502} 22 | - 114: {fileID: 114000013885358580} 23 | m_Layer: 0 24 | m_Name: SelfSpeechGesture 25 | m_TagString: Untagged 26 | m_Icon: {fileID: 0} 27 | m_NavMeshLayer: 0 28 | m_StaticEditorFlags: 0 29 | m_IsActive: 1 30 | --- !u!4 &4000013839730502 31 | Transform: 32 | m_ObjectHideFlags: 1 33 | m_PrefabParentObject: {fileID: 0} 34 | m_PrefabInternal: {fileID: 100100000} 35 | m_GameObject: {fileID: 1000012211108868} 36 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 37 | m_LocalPosition: {x: 0, y: 0, z: 0} 38 | m_LocalScale: {x: 1, y: 1, z: 1} 39 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 40 | m_Children: [] 41 | m_Father: {fileID: 0} 42 | m_RootOrder: 0 43 | --- !u!114 &114000013885358580 44 | MonoBehaviour: 45 | m_ObjectHideFlags: 1 46 | m_PrefabParentObject: {fileID: 0} 47 | m_PrefabInternal: {fileID: 100100000} 48 | m_GameObject: {fileID: 1000012211108868} 49 | m_Enabled: 1 50 | m_EditorHideFlags: 0 51 | m_Script: {fileID: 11500000, guid: a64bdd0024f28bc4d87c02c3b116be93, type: 3} 52 | m_Name: 53 | m_EditorClassIdentifier: 54 | m_AutoConnect: 1 55 | m_TextOutput: 56 | m_Connections: [] 57 | m_GestureId: tts 58 | m_Override: 1 59 | -------------------------------------------------------------------------------- /Prefabs/SelfStatusGesture.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1000013702581504} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1000013702581504 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 4 20 | m_Component: 21 | - 4: {fileID: 4000010753274002} 22 | - 114: {fileID: 114000012160666170} 23 | m_Layer: 0 24 | m_Name: SelfStatusGesture 25 | m_TagString: Untagged 26 | m_Icon: {fileID: 0} 27 | m_NavMeshLayer: 0 28 | m_StaticEditorFlags: 0 29 | m_IsActive: 1 30 | --- !u!4 &4000010753274002 31 | Transform: 32 | m_ObjectHideFlags: 1 33 | m_PrefabParentObject: {fileID: 0} 34 | m_PrefabInternal: {fileID: 100100000} 35 | m_GameObject: {fileID: 1000013702581504} 36 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 37 | m_LocalPosition: {x: 0, y: 0, z: 0} 38 | m_LocalScale: {x: 1, y: 1, z: 1} 39 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 40 | m_Children: [] 41 | m_Father: {fileID: 0} 42 | m_RootOrder: 0 43 | --- !u!114 &114000012160666170 44 | MonoBehaviour: 45 | m_ObjectHideFlags: 1 46 | m_PrefabParentObject: {fileID: 0} 47 | m_PrefabInternal: {fileID: 100100000} 48 | m_GameObject: {fileID: 1000013702581504} 49 | m_Enabled: 1 50 | m_EditorHideFlags: 0 51 | m_Script: {fileID: 11500000, guid: 9e7ec43af1bb337428b72eaee79aeb71, type: 3} 52 | m_Name: 53 | m_EditorClassIdentifier: 54 | m_AutoConnect: 1 55 | m_GestureId: update_status 56 | m_Override: 1 57 | m_Status: 58 | m_Connections: [] 59 | -------------------------------------------------------------------------------- /Prefabs/SelfDisplayGesture.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1000013858366688} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1000013858366688 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 4 20 | m_Component: 21 | - 4: {fileID: 4000014020568490} 22 | - 114: {fileID: 114000012466614398} 23 | m_Layer: 0 24 | m_Name: SelfDisplayGesture 25 | m_TagString: Untagged 26 | m_Icon: {fileID: 0} 27 | m_NavMeshLayer: 0 28 | m_StaticEditorFlags: 0 29 | m_IsActive: 1 30 | --- !u!4 &4000014020568490 31 | Transform: 32 | m_ObjectHideFlags: 1 33 | m_PrefabParentObject: {fileID: 0} 34 | m_PrefabInternal: {fileID: 100100000} 35 | m_GameObject: {fileID: 1000013858366688} 36 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 37 | m_LocalPosition: {x: 21.73504, y: -44.28981, z: 60.40911} 38 | m_LocalScale: {x: 1, y: 1, z: 1} 39 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 40 | m_Children: [] 41 | m_Father: {fileID: 0} 42 | m_RootOrder: 0 43 | --- !u!114 &114000012466614398 44 | MonoBehaviour: 45 | m_ObjectHideFlags: 1 46 | m_PrefabParentObject: {fileID: 0} 47 | m_PrefabInternal: {fileID: 100100000} 48 | m_GameObject: {fileID: 1000013858366688} 49 | m_Enabled: 1 50 | m_EditorHideFlags: 0 51 | m_Script: {fileID: 11500000, guid: 85a3a8e3eae0b444abcbf4d836a2f773, type: 3} 52 | m_Name: 53 | m_EditorClassIdentifier: 54 | m_AutoConnect: 1 55 | m_GestureId: display 56 | m_Override: 1 57 | m_DocumentOutput: 58 | m_Connections: [] 59 | -------------------------------------------------------------------------------- /Scripts/Sensors/ISensor.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using IBM.Watson.DeveloperCloud.Utilities; 19 | using IBM.Watson.Self.Topics; 20 | using System; 21 | 22 | namespace IBM.Watson.Self.Sensors 23 | { 24 | /// 25 | /// interface for any object that should be a sensor. The user should implement the interface, register the object with SensorManager, 26 | /// then should invoke SensorManager.SendData() when new sensor data is generated. 27 | /// 28 | public interface ISensor 29 | { 30 | //! This should return a unique ID for this sensor 31 | string GetSensorId(); 32 | //! This should return a text name for this sensor 33 | string GetSensorName(); 34 | //! This should return the type of data class this sensor sends 35 | string GetDataType(); 36 | //! This should return the type of binary data 37 | string GetBinaryType(); 38 | //! This is invoked when this sensor shoudl start calling SendData() 39 | bool OnStart(); 40 | //! This is invoked when the last subscriber unsubscribe from this sensor 41 | bool OnStop(); 42 | void OnPause(); 43 | void OnResume(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Prefabs/TopicClientWidget.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1000013323663760} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1000013323663760 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 4 20 | m_Component: 21 | - 4: {fileID: 4000012921387902} 22 | - 114: {fileID: 114000012782245376} 23 | m_Layer: 0 24 | m_Name: TopicClientWidget 25 | m_TagString: Untagged 26 | m_Icon: {fileID: 0} 27 | m_NavMeshLayer: 0 28 | m_StaticEditorFlags: 0 29 | m_IsActive: 1 30 | --- !u!4 &4000012921387902 31 | Transform: 32 | m_ObjectHideFlags: 1 33 | m_PrefabParentObject: {fileID: 0} 34 | m_PrefabInternal: {fileID: 100100000} 35 | m_GameObject: {fileID: 1000013323663760} 36 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 37 | m_LocalPosition: {x: 0, y: 0, z: 0} 38 | m_LocalScale: {x: 1, y: 1, z: 1} 39 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 40 | m_Children: [] 41 | m_Father: {fileID: 0} 42 | m_RootOrder: 0 43 | --- !u!114 &114000012782245376 44 | MonoBehaviour: 45 | m_ObjectHideFlags: 1 46 | m_PrefabParentObject: {fileID: 0} 47 | m_PrefabInternal: {fileID: 100100000} 48 | m_GameObject: {fileID: 1000013323663760} 49 | m_Enabled: 1 50 | m_EditorHideFlags: 0 51 | m_Script: {fileID: 11500000, guid: b1f688dcd9b234e068abe046cf5f667e, type: 3} 52 | m_Name: 53 | m_EditorClassIdentifier: 54 | m_AutoConnect: 1 55 | m_Host: 56 | m_EmbodimentId: 57 | m_Token: 58 | m_ParentInstance: 59 | m_TopicClientOutput: 60 | m_Connections: [] 61 | -------------------------------------------------------------------------------- /Scripts/UnitTests/TestSelfDiscovery.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System.Collections; 19 | using IBM.Watson.DeveloperCloud.UnitTests; 20 | using IBM.Watson.DeveloperCloud.Logging; 21 | using IBM.Watson.Self.Utils; 22 | using UnityEngine; 23 | 24 | namespace IBM.Watson.Self.UnitTests 25 | { 26 | public class TestSelfDiscovery : UnitTest 27 | { 28 | bool m_bDiscoveryTested = false; 29 | int m_WaitForConnection = 2; 30 | 31 | public override IEnumerator RunTest() 32 | { 33 | m_WaitForConnection = 2; 34 | m_bDiscoveryTested = false; 35 | 36 | if(SelfDiscovery.Instance.OnDiscovered == null) 37 | SelfDiscovery.Instance.OnDiscovered += OnDiscovered; 38 | 39 | SelfDiscovery.Instance.StartDiscovery(); 40 | 41 | while(! m_bDiscoveryTested ) 42 | { 43 | yield return null; 44 | } 45 | 46 | yield break; 47 | } 48 | 49 | private void OnDiscovered( SelfDiscovery.SelfInstance a_Instance ) 50 | { 51 | Log.Debug( "TestSelfDiscovery", "OnNodeAdded: {0}", a_Instance ); 52 | m_WaitForConnection--; 53 | if (m_WaitForConnection <= 0) 54 | { 55 | SelfDiscovery.Instance.StopDiscovery(); 56 | m_bDiscoveryTested = true; 57 | Test(true); 58 | } 59 | } 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /Scripts/Widgets/TopicClientWidget.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using UnityEngine; 19 | using System.Collections; 20 | using IBM.Watson.DeveloperCloud.Widgets; 21 | using IBM.Watson.Self.Topics; 22 | 23 | namespace IBM.Watson.Self.Widgets 24 | { 25 | public class TopicClientWidget : Widget 26 | { 27 | #region Private Data 28 | [SerializeField] 29 | private string m_Host = "ws://127.0.0.1:9443"; 30 | [SerializeField] 31 | private string m_EmbodimentId = null; 32 | [SerializeField] 33 | private string m_Token = null; 34 | [SerializeField] 35 | private string m_ParentInstance = null; 36 | 37 | 38 | [SerializeField] 39 | private Output m_TopicClientOutput = new Output(typeof(TopicClientData), true); 40 | private TopicClient m_TopicClient = null; 41 | #endregion 42 | 43 | #region Public Properties 44 | 45 | public TopicClient TopicClient 46 | { 47 | get 48 | { 49 | if (m_TopicClient == null) 50 | { 51 | m_TopicClient = new TopicClient(); 52 | m_TopicClient.Connect(m_Host, m_EmbodimentId, m_Token, m_ParentInstance); 53 | } 54 | return m_TopicClient; 55 | } 56 | } 57 | 58 | #endregion 59 | 60 | protected override void Start() 61 | { 62 | base.Start(); 63 | m_TopicClientOutput.OnInputAdded += HandleOnInputAdded; 64 | } 65 | 66 | public void OnDestroy() 67 | { 68 | m_TopicClientOutput.OnInputAdded -= HandleOnInputAdded; 69 | } 70 | 71 | void HandleOnInputAdded (Input input) 72 | { 73 | input.ReceiveData(new TopicClientData(TopicClient)); 74 | } 75 | 76 | #region Widget interface 77 | protected override string GetName() 78 | { 79 | return "SelfTopicClient"; 80 | } 81 | #endregion 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Scripts/UnitTests/TestSelfExplorer.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System.Collections; 19 | using IBM.Watson.DeveloperCloud.UnitTests; 20 | using IBM.Watson.Self.Topics; 21 | using IBM.Watson.DeveloperCloud.Logging; 22 | using IBM.Watson.Self.Utils; 23 | 24 | namespace IBM.Watson.Self.UnitTests 25 | { 26 | public class TestSelfExplorer : UnitTest 27 | { 28 | bool m_bExplorerTested = false; 29 | SelfExplorer m_Explorer = null; 30 | 31 | public override IEnumerator RunTest() 32 | { 33 | TopicClient client = new TopicClient(); 34 | m_Explorer = new SelfExplorer(client); 35 | 36 | if ( client.IsActive ) 37 | { 38 | client.Disconnect(); 39 | while( client.IsActive ) 40 | yield return null; 41 | } 42 | 43 | client.Connect(); 44 | 45 | m_Explorer.OnNodeAdded += OnNodeAdded; 46 | m_Explorer.OnNodeRemoved += OnNodeRemoved; 47 | m_Explorer.OnNodeReady += OnNodeReady; 48 | m_Explorer.OnExplorerDone += OnExploreDone; 49 | 50 | m_Explorer.Explore(); 51 | while(! m_bExplorerTested ) 52 | yield return null; 53 | 54 | yield break; 55 | } 56 | 57 | private void OnNodeAdded( SelfExplorer.Node a_Added ) 58 | { 59 | Log.Debug( "TestSelfExplorer", "OnNodeAdded: {0}", a_Added ); 60 | } 61 | private void OnNodeRemoved( SelfExplorer.Node a_Added ) 62 | { 63 | Log.Debug( "TestSelfExplorer", "OnNodeRemoved: {0}", a_Added ); 64 | } 65 | private void OnNodeReady( SelfExplorer.Node a_Node ) 66 | { 67 | Log.Debug( "TestSelfExplorer", "OnNodeReady: {0}", a_Node); 68 | } 69 | private void OnExploreDone( SelfExplorer a_Explorer ) 70 | { 71 | Log.Debug( "TestSelfExplorer", "OnExploreDone: {0}", a_Explorer ); 72 | //m_bExplorerTested = true; 73 | } 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /Scripts/UnitTests/TestBlackBoard.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System.Collections; 19 | using IBM.Watson.DeveloperCloud.UnitTests; 20 | using IBM.Watson.Self.Topics; 21 | using IBM.Watson.Self.Agents; 22 | using IBM.Watson.DeveloperCloud.Logging; 23 | 24 | namespace IBM.Watson.Self.UnitTests 25 | { 26 | public class TestBlackBoard : UnitTest 27 | { 28 | string m_TargetPath = ""; 29 | 30 | bool m_bSubscribeTested = false; 31 | bool m_ConnectionClosed = false; 32 | 33 | TopicClient m_Client = null; 34 | BlackBoard m_BlackBoard = null; 35 | 36 | public override IEnumerator RunTest() 37 | { 38 | m_Client = new TopicClient(); 39 | m_BlackBoard = new BlackBoard(m_Client); 40 | 41 | if ( m_Client.IsActive ) 42 | { 43 | m_Client.Disconnect(); 44 | while( m_Client.IsActive ) 45 | yield return null; 46 | } 47 | 48 | m_Client.StateChangedEvent += OnStateChanged; 49 | 50 | m_Client.Connect(); 51 | 52 | while(! m_bSubscribeTested ) 53 | yield return null; 54 | 55 | Log.Debug( "TestBlackBoard", "Tested Subscription now disconnecting" ); 56 | m_Client.Disconnect(); 57 | 58 | while(! m_ConnectionClosed ) 59 | yield return null; 60 | 61 | m_Client.StateChangedEvent -= OnStateChanged; 62 | 63 | yield break; 64 | } 65 | 66 | void OnStateChanged(TopicClient.ClientState a_CurrentState) 67 | { 68 | Log.Debug( "TestBlackBoard", "OnStateChanged to {0}" , a_CurrentState); 69 | 70 | switch (a_CurrentState) 71 | { 72 | case TopicClient.ClientState.Connected: 73 | OnConnected(); 74 | break; 75 | case TopicClient.ClientState.Disconnected: 76 | OnDisconnected(); 77 | break; 78 | default: 79 | break; 80 | } 81 | } 82 | 83 | private void OnConnected() 84 | { 85 | Log.Debug( "TestBlackBoard", "OnConnected" ); 86 | m_BlackBoard.SubscribeToType( "Text", OnText, a_Path:m_TargetPath ); 87 | m_ConnectionClosed = false; 88 | } 89 | 90 | private void OnDisconnected() 91 | { 92 | Log.Debug( "TestBlackBoard", "OnDisconnected" ); 93 | m_ConnectionClosed = true; 94 | } 95 | 96 | private void OnText( ThingEvent a_Event ) 97 | { 98 | Log.Debug( "TestBlackBoard", "OnText : {0}", a_Event ); 99 | m_bSubscribeTested = true; 100 | 101 | } 102 | } 103 | } 104 | 105 | -------------------------------------------------------------------------------- /Scripts/Widgets/DataTypes.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using IBM.Watson.DeveloperCloud.Widgets; 19 | using System; 20 | using UnityEngine; 21 | 22 | namespace IBM.Watson.Self.Widgets 23 | { 24 | /// 25 | /// This data class is for status data output by the SelfStatusGesture. 26 | /// 27 | public class StatusData : Widget.Data 28 | { 29 | /// 30 | /// Default constructor. 31 | /// 32 | public StatusData() 33 | { } 34 | /// 35 | /// String constructor. 36 | /// 37 | /// 38 | public StatusData(string status) 39 | { 40 | Status = status; 41 | } 42 | /// 43 | /// Name of this data type. 44 | /// 45 | /// A human readable name for this data type. 46 | public override string GetName() 47 | { 48 | return "StatusData"; 49 | } 50 | 51 | /// 52 | /// The text to convert to speech. 53 | /// 54 | public string Status { get; set; } 55 | }; 56 | 57 | /// 58 | /// This class is the container for the data of a document. The DocumentType property is matched 59 | /// against a matching DocumentUI object to get displayed. 60 | /// 61 | [Serializable] 62 | public class DocumentModel : Widget.Data 63 | { 64 | #region Private Data 65 | [SerializeField] 66 | private string m_Type = null; 67 | [SerializeField] 68 | private object m_Document = null; 69 | [SerializeField] 70 | private string m_GroupId = null; 71 | #endregion 72 | 73 | #region Public Properties 74 | public string Type { get { return m_Type; } set { m_Type = value; } } 75 | public object Document { get { return m_Document; } set { m_Document = value; } } 76 | public string GroupId { get { return m_GroupId; } set { m_GroupId = value; } } 77 | #endregion 78 | 79 | #region Public Functions 80 | public DocumentModel(string a_DocumentType, object a_Document, string a_GroupId = null ) 81 | { 82 | m_Type = a_DocumentType; 83 | m_Document = a_Document; 84 | 85 | if ( string.IsNullOrEmpty( a_GroupId ) ) 86 | a_GroupId = Guid.NewGuid().ToString(); 87 | m_GroupId = a_GroupId; 88 | } 89 | #endregion 90 | 91 | #region Widget.Data interface 92 | /// 93 | /// Name of this data type. 94 | /// 95 | /// A human readable name for this data type. 96 | public override string GetName() 97 | { 98 | return "DocumentModel"; 99 | } 100 | #endregion 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfStatusGesture.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using IBM.Watson.DeveloperCloud.Widgets; 19 | using IBM.Watson.Self.Gestures; 20 | using System; 21 | using System.Collections; 22 | using UnityEngine; 23 | using IBM.Watson.DeveloperCloud.Utilities; 24 | using IBM.Watson.Self.Topics; 25 | 26 | namespace IBM.Watson.Self.Widgets 27 | { 28 | public class SelfStatusGesture : Widget, IGesture 29 | { 30 | #region Private Data 31 | [SerializeField] 32 | private string m_GestureId = "update_status"; 33 | [SerializeField] 34 | private bool m_Override = true; 35 | [SerializeField] 36 | private Output m_Status = new Output( typeof(StatusData), true ); 37 | [SerializeField] 38 | private Input m_TopicClientInput = new Input("TopicClientInput", typeof(TopicClientData), "OnTopicClientInput"); 39 | private string m_InstanceId = Guid.NewGuid().ToString(); 40 | #endregion 41 | 42 | #region Public Properties 43 | public GestureManager GestureManager{ get; private set; } 44 | #endregion 45 | 46 | #region Widget interface 47 | protected override string GetName() 48 | { 49 | return "SelfSpeechGesture"; 50 | } 51 | #endregion 52 | 53 | #region IGesture interface 54 | public string GetGestureId() 55 | { 56 | return m_GestureId; 57 | } 58 | //! return an ID unique to this instance 59 | public string GetInstanceId() 60 | { 61 | return m_InstanceId; 62 | } 63 | //! Initialize this gesture object, returns false if gesture can't be initialized 64 | public bool OnStart() 65 | { 66 | return true; 67 | } 68 | 69 | //! Shutdown this gesture object. 70 | public bool OnStop() 71 | { 72 | return true; 73 | } 74 | //! Execute this gesture, the provided callback should be invoked when the gesture is complete. 75 | public bool Execute(OnGestureDone a_Callback, IDictionary a_Params) 76 | { 77 | bool bError = false; 78 | 79 | string status = a_Params["status"] as string; 80 | m_Status.SendData( new StatusData(status)); 81 | 82 | if (a_Callback != null) 83 | a_Callback(this, bError); 84 | return true; 85 | } 86 | //! Abort this gesture, if true is returned then abort succeeded and callback will NOT be invoked. 87 | public bool Abort() 88 | { 89 | return true; 90 | } 91 | #endregion 92 | 93 | #region Input Handlers 94 | private void OnTopicClientInput(Data data) 95 | { 96 | TopicClientData a_TopicClientData = (TopicClientData)data; 97 | if (a_TopicClientData == null || a_TopicClientData.TopicClient == null) 98 | { 99 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 100 | } 101 | GestureManager = new GestureManager(a_TopicClientData.TopicClient); 102 | GestureManager.AddGesture(this, m_Override); 103 | } 104 | #endregion 105 | 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfDisplayGesture.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System; 19 | using System.Collections; 20 | using UnityEngine; 21 | using IBM.Watson.DeveloperCloud.Widgets; 22 | using IBM.Watson.DeveloperCloud.Logging; 23 | using IBM.Watson.Self.Gestures; 24 | using IBM.Watson.Self.Topics; 25 | using IBM.Watson.DeveloperCloud.Utilities; 26 | using IBM.Watson.DeveloperCloud.DataTypes; 27 | 28 | namespace IBM.Watson.Self.Widgets 29 | { 30 | public class SelfDisplayGesture : Widget, IGesture 31 | { 32 | #region Private Data 33 | [SerializeField] 34 | private string m_GestureId = "display"; 35 | [SerializeField] 36 | private bool m_Override = true; 37 | [SerializeField] 38 | private Output m_DocumentOutput = new Output( typeof(DocumentModel), true ); 39 | [SerializeField] 40 | private Input m_TopicClientInput = new Input("TopicClientInput", typeof(TopicClientData), "OnTopicClientInput"); 41 | 42 | private string m_InstanceId = Guid.NewGuid().ToString(); 43 | #endregion 44 | 45 | #region Public Properties 46 | public GestureManager GestureManager{ get; private set; } 47 | #endregion 48 | 49 | #region Widget interface 50 | protected override string GetName() 51 | { 52 | return "SelfDisplayGesture"; 53 | } 54 | #endregion 55 | 56 | #region IGesture interface 57 | public string GetGestureId() 58 | { 59 | return m_GestureId; 60 | } 61 | //! return an ID unique to this instance 62 | public string GetInstanceId() 63 | { 64 | return m_InstanceId; 65 | } 66 | //! Initialize this gesture object, returns false if gesture can't be initialized 67 | public bool OnStart() 68 | { 69 | return true; 70 | } 71 | 72 | //! Shutdown this gesture object. 73 | public bool OnStop() 74 | { 75 | return true; 76 | } 77 | //! Execute this gesture, the provided callback should be invoked when the gesture is complete. 78 | public bool Execute(OnGestureDone a_Callback, IDictionary a_Params) 79 | { 80 | bool bError = false; 81 | 82 | string type = a_Params["display"] as string; 83 | string data = a_Params["data"] as string; 84 | 85 | if (! m_DocumentOutput.SendData( new DocumentModel( type, data ) ) ) 86 | { 87 | Log.Error( "SelfDisplayGesture", "Failed to send data." ); 88 | bError = true; 89 | } 90 | 91 | if (a_Callback != null) 92 | a_Callback(this, bError ); 93 | return true; 94 | } 95 | //! Abort this gesture, if true is returned then abort succeeded and callback will NOT be invoked. 96 | public bool Abort() 97 | { 98 | return true; 99 | } 100 | #endregion 101 | 102 | #region Event Handlers 103 | private void OnTopicClientInput(Data data) 104 | { 105 | TopicClientData a_TopicClientData = (TopicClientData)data; 106 | if (a_TopicClientData == null || a_TopicClientData.TopicClient == null) 107 | { 108 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 109 | } 110 | if (GestureManager != null) 111 | { 112 | GestureManager.RemoveGesture(this); 113 | } 114 | 115 | GestureManager = new GestureManager(a_TopicClientData.TopicClient); 116 | GestureManager.AddGesture(this, m_Override); 117 | } 118 | #endregion 119 | 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Scripts/UnitTests/TestTopicClient.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System.Collections; 19 | using IBM.Watson.DeveloperCloud.UnitTests; 20 | using IBM.Watson.Self.Topics; 21 | using IBM.Watson.DeveloperCloud.Logging; 22 | using System.Text; 23 | 24 | namespace IBM.Watson.Self.UnitTests 25 | { 26 | public class TestTopicClient : UnitTest 27 | { 28 | bool m_bQueryTested = false; 29 | bool m_bSubFailedTested = false; 30 | bool m_bSubscribeBinaryTested = false; 31 | bool m_bSubscribeTextTested = false; 32 | TopicClient m_TopicClient = null; 33 | 34 | public override IEnumerator RunTest() 35 | { 36 | m_TopicClient = new TopicClient(); 37 | if ( m_TopicClient.IsActive ) 38 | { 39 | m_TopicClient.Disconnect(); 40 | while( m_TopicClient.IsActive ) 41 | yield return null; 42 | } 43 | 44 | m_TopicClient.StateChangedEvent += OnStateChanged; 45 | 46 | m_TopicClient.Connect(); 47 | while(! m_bQueryTested ) 48 | yield return null; 49 | while(! m_bSubscribeBinaryTested ) 50 | yield return null; 51 | while(! m_bSubscribeTextTested ) 52 | yield return null; 53 | while(! m_bSubFailedTested ) 54 | yield return null; 55 | 56 | m_TopicClient.StateChangedEvent -= OnStateChanged; 57 | 58 | yield break; 59 | } 60 | 61 | void OnStateChanged(TopicClient.ClientState a_CurrentState) 62 | { 63 | Log.Debug( "TestBlackBoard", "OnStateChanged to {0}" , a_CurrentState); 64 | 65 | switch (a_CurrentState) 66 | { 67 | case TopicClient.ClientState.Connected: 68 | OnConnected(); 69 | break; 70 | case TopicClient.ClientState.Disconnected: 71 | OnDisconnected(); 72 | break; 73 | default: 74 | break; 75 | } 76 | } 77 | 78 | private void OnConnected() 79 | { 80 | Log.Debug( "TestTopicClient", "OnConnected" ); 81 | m_TopicClient.Query( ".", OnQuery ); 82 | } 83 | 84 | private void OnDisconnected() 85 | { 86 | Log.Debug( "TestTopicClient", "OnDisconnected" ); 87 | } 88 | 89 | private void OnQuery( TopicClient.QueryInfo a_Query ) 90 | { 91 | Log.Debug( "TopicClient", "OnQuery(). QueryResponse: {0}", a_Query ); 92 | m_bQueryTested = true; 93 | 94 | m_TopicClient.Subscribe( "sensor-Microphone", OnMicrophoneData ); 95 | } 96 | 97 | private void OnMicrophoneData( TopicClient.Payload a_Payload ) 98 | { 99 | Log.Debug( "TopicClient", "OnMicrophoneData() received. Payload: {0}", a_Payload ); 100 | Test( m_TopicClient.Unsubscribe( "sensor-Microphone", OnMicrophoneData ) ); 101 | m_bSubscribeBinaryTested = true; 102 | 103 | m_TopicClient.Subscribe( "blackboard", OnBlackboard ); 104 | m_TopicClient.Subscribe( "invalid-topic", OnInvalidTopic ); 105 | m_TopicClient.Publish( "conversation", "tell me a joke" ); 106 | } 107 | 108 | private void OnBlackboard( TopicClient.Payload a_Payload ) 109 | { 110 | Log.Debug( "TopicClient", "OnBlackboard(). Payload: {0} \n Data: {1}", a_Payload, Encoding.UTF8.GetString( a_Payload.Data ) ); 111 | Test( m_TopicClient.Unsubscribe( "blackboard", OnBlackboard ) ); 112 | m_bSubscribeTextTested = true; 113 | } 114 | 115 | private void OnInvalidTopic( TopicClient.Payload a_Payload ) 116 | { 117 | Log.Debug( "TopicClient", "OnInvalidTopic(). Payload: {0}", a_Payload ); 118 | Test( a_Payload == null ); 119 | m_bSubFailedTested = true; 120 | } 121 | } 122 | } 123 | 124 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfRemoteSpeechGesture.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | 19 | using System.Collections; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | 23 | using IBM.Watson.DeveloperCloud.DataTypes; 24 | using IBM.Watson.DeveloperCloud.Widgets; 25 | using IBM.Watson.DeveloperCloud.Logging; 26 | using IBM.Watson.DeveloperCloud.Utilities; 27 | using IBM.Watson.Self.Topics; 28 | using System; 29 | using UnityEngine; 30 | using MiniJSON; 31 | 32 | namespace IBM.Watson.Self.Widgets 33 | { 34 | public class SelfRemoteSpeechGesture : Widget 35 | { 36 | #region Private Data 37 | [SerializeField] 38 | private Output m_Status = new Output( typeof(StatusData), true ); 39 | [SerializeField] 40 | private Output m_DisableMic = new Output(typeof(DisableMicData)); 41 | [SerializeField] 42 | private Input m_TopicClientInput = new Input("TopicClientInput", typeof(TopicClientData), "OnTopicClientInput"); 43 | #endregion 44 | 45 | #region Public Properties 46 | public TopicClient TopicClient { get; private set;} 47 | #endregion 48 | 49 | #region MonoBehavior interface 50 | 51 | public void OnDestroy() 52 | { 53 | if (TopicClient != null) 54 | { 55 | TopicClient.StateChangedEvent -= OnStateChanged; 56 | TopicClient.Unsubscribe("audio-out", OnAudioEvent); 57 | } 58 | } 59 | 60 | #endregion 61 | 62 | #region Widget interface 63 | protected override string GetName() 64 | { 65 | return "SelfRemoteSpeechGesture"; 66 | } 67 | #endregion 68 | 69 | #region Event Handlers 70 | private void OnTopicClientInput(Data data) 71 | { 72 | TopicClientData a_TopicClientData = (TopicClientData)data; 73 | if (a_TopicClientData == null || a_TopicClientData.TopicClient == null) 74 | { 75 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 76 | } 77 | if (TopicClient != null) 78 | { 79 | TopicClient.StateChangedEvent -= OnStateChanged; 80 | TopicClient.Unsubscribe( "audio-out", OnAudioEvent ); 81 | } 82 | 83 | TopicClient = a_TopicClientData.TopicClient; 84 | TopicClient.StateChangedEvent += OnStateChanged; 85 | TopicClient.Subscribe("audio-out", OnAudioEvent); 86 | } 87 | #endregion 88 | 89 | #region Callback Functions 90 | 91 | void OnStateChanged(TopicClient.ClientState a_CurrentState) 92 | { 93 | Log.Status ("SelfRemoteSpeechGesture", "TopicClient state has changed"); 94 | } 95 | 96 | void OnAudioEvent(TopicClient.Payload a_Payload) 97 | { 98 | Log.Status ("SelfRemoteSpeechGesture", "OnAudioEvent() Called!"); 99 | float[] f = ConvertByteToFloat (a_Payload.Data); 100 | AudioClip clip = AudioClip.Create("test",f.Length,1,22050, false); 101 | clip.SetData (f, 0); 102 | PlayClip (clip); 103 | } 104 | 105 | private float[] ConvertByteToFloat(byte[] array) 106 | { 107 | float[] floatArr = new float[array.Length / 2]; 108 | for (int i = 0; i < floatArr.Length; i++) 109 | { 110 | floatArr [i] = (float)BitConverter.ToInt16 (array, i * 2) / 32768.0f; 111 | } 112 | return floatArr; 113 | } 114 | 115 | private void PlayClip(AudioClip clip) 116 | { 117 | if (Application.isPlaying && clip != null) 118 | { 119 | m_Status.SendData( new StatusData("ANSWERING")); 120 | m_DisableMic.SendData(new DisableMicData(true)); 121 | GameObject audioObject = new GameObject("AudioObject"); 122 | AudioSource source = audioObject.AddComponent(); 123 | source.spatialBlend = 0.0f; // 2D sound 124 | source.loop = false; // do not loop 125 | source.clip = clip; // clip 126 | source.Play(); 127 | // automatically destroy the object after the sound has played.. 128 | GameObject.Destroy(audioObject, clip.length); 129 | Invoke ("onClipFinished", clip.length); 130 | } 131 | } 132 | 133 | private void onClipFinished() 134 | { 135 | m_Status.SendData (new StatusData ("LISTENING")); 136 | m_DisableMic.SendData(new DisableMicData(false)); 137 | } 138 | 139 | 140 | #endregion 141 | 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Scripts/Utils/SelfLogin.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using IBM.Watson.DeveloperCloud.Logging; 19 | using IBM.Watson.DeveloperCloud.Utilities; 20 | using IBM.Watson.Self.Services; 21 | 22 | namespace IBM.Watson.Self.Utils 23 | { 24 | /// 25 | /// This class wraps the functions necessary to login and register an embodiment wth the self backend. 26 | /// 27 | public class SelfLogin 28 | { 29 | #region Public Types 30 | public delegate void OnRegistered( string a_SelfId, string a_Token ); 31 | public delegate void OnError(); 32 | #endregion 33 | 34 | #region Public Properties 35 | public string GroupId { get; set; } 36 | public string OrgId { get; set; } 37 | public string SelfId { get; set; } 38 | public string Token { get; set; } 39 | public string Name { get; set; } 40 | public string Type { get; set; } 41 | 42 | public OnRegistered OnRegisteredEvent { get; set; } 43 | public OnError OnErrorEvent { get; set; } 44 | #endregion 45 | 46 | #region Private Data 47 | private RobotGateway m_Gateway = new RobotGateway(); 48 | #endregion 49 | 50 | #region Public Functions 51 | /// 52 | /// Load the current configuration information from the the local configuration file. 53 | /// 54 | public void LoadConfig() 55 | { 56 | GroupId = Config.Instance.GetVariableValue( "GroupID" ); 57 | OrgId = Config.Instance.GetVariableValue( "OrgID" ); 58 | Token = Config.Instance.GetVariableValue("BearerToken"); 59 | SelfId = Config.Instance.GetVariableValue("SelfID"); 60 | Name = Config.Instance.GetVariableValue("EmbodimentName"); 61 | if ( string.IsNullOrEmpty( Name ) ) 62 | Name = "SelfUnitySDK"; 63 | Type = Config.Instance.GetVariableValue("EmbodimentType"); 64 | if ( string.IsNullOrEmpty( Type ) ) 65 | Type = "SelfUnitySDK"; 66 | } 67 | 68 | /// 69 | /// Save the current configuration information from the local configuration file. 70 | /// 71 | public void SaveConfig() 72 | { 73 | Config.Instance.SetVariableValue( "GroupID", GroupId, true ); 74 | Config.Instance.SetVariableValue( "OrgID", OrgId, true ); 75 | Config.Instance.SetVariableValue( "BearerToken", Token, true ); 76 | Config.Instance.SetVariableValue( "SelfID", SelfId, true ); 77 | Config.Instance.SetVariableValue( "EmbodimentName", Name, true ); 78 | Config.Instance.SetVariableValue( "EmbodimentType", Type, true ); 79 | Config.Instance.SaveConfigToFileSystem(); 80 | } 81 | 82 | /// 83 | /// Register with the gateway using the loaded groupId, orgId, and bearer token. 84 | /// 85 | /// 86 | /// 87 | public bool RegisterEmbodiment( bool a_bLoadConfig = true ) 88 | { 89 | if ( a_bLoadConfig ) 90 | LoadConfig(); 91 | 92 | return m_Gateway.RegisterEmbodiment( GroupId, OrgId, Token, Name, Type, OnRegisteredEmbodiment ); 93 | } 94 | #endregion 95 | 96 | /// 97 | /// Callback for RobotGateway.RegisterEmbodiment() 98 | /// 99 | /// 100 | /// 101 | private void OnRegisteredEmbodiment( string a_Token, string a_EmbodimentId ) 102 | { 103 | if (! string.IsNullOrEmpty( a_Token ) 104 | && !string.IsNullOrEmpty( a_EmbodimentId ) ) 105 | { 106 | Log.Status( "SelfLogin", "Embodiment Registered: {0}", a_EmbodimentId ); 107 | 108 | SelfId = a_EmbodimentId; 109 | Token = a_Token; 110 | SaveConfig(); 111 | 112 | if ( OnRegisteredEvent != null ) 113 | OnRegisteredEvent( SelfId, Token ); 114 | } 115 | else 116 | { 117 | Log.Error( "SelfLogin", "Failed to register embodiment." ); 118 | if ( OnErrorEvent != null ) 119 | OnErrorEvent(); 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Scripts/Agents/IThing.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System; 19 | using System.Collections; 20 | using System.Collections.Generic; 21 | using IBM.Watson.Self.Utils; 22 | using IBM.Watson.DeveloperCloud.Utilities; 23 | 24 | namespace IBM.Watson.Self.Agents 25 | { 26 | public enum ThingCategory 27 | { 28 | TT_INVALID = -1, 29 | TT_PERCEPTION, 30 | TT_AGENCY, 31 | TT_MODEL 32 | } 33 | 34 | /// 35 | /// This is the base class of any object that can be added into the blackboard. 36 | /// 37 | public class IThing : ISerializable 38 | { 39 | public IThing() 40 | { 41 | Type = "IThing"; 42 | Category = ThingCategory.TT_PERCEPTION; 43 | GUID = Guid.NewGuid().ToString(); 44 | Importance = 1.0f; 45 | State = "ADDED"; 46 | CreateTime = Utility.GetEpochUTCSeconds(); 47 | LifeSpan = 3600.0; 48 | } 49 | 50 | #region Public Properties 51 | // IMplementation type 52 | public string Type { get; set; } 53 | public IDictionary Body { get; set; } 54 | public ThingCategory Category { get; set; } 55 | public string GUID { get; set; } 56 | public double Importance { get; set; } 57 | public string State { get; set; } 58 | public double CreateTime { get; set; } 59 | public double LifeSpan { get; set; } 60 | // data driven type 61 | public string DataType { get; set; } 62 | public IDictionary Data { get; set; } 63 | public string ParentGUID { get; set; } 64 | public string Origin { get; set; } 65 | 66 | #endregion 67 | 68 | #region ISerializable interface 69 | public void Deserialize( IDictionary a_Json ) 70 | { 71 | Body = a_Json; 72 | Type = a_Json["Type_"] as string; 73 | Category = (ThingCategory)(long)a_Json["m_eCategory"]; 74 | GUID = a_Json["m_GUID"] as string; 75 | State = a_Json["m_State"] as string; 76 | 77 | if ( a_Json["m_fImportance"] is double ) 78 | Importance = (double)a_Json["m_fImportance"]; 79 | if ( a_Json["m_CreateTime"] is double ) 80 | CreateTime = (double)a_Json["m_CreateTime"]; 81 | if ( a_Json["m_fLifeSpan"] is double ) 82 | LifeSpan = (double)a_Json["m_fLifeSpan"]; 83 | if ( a_Json.Contains( "m_DataType" ) ) 84 | DataType = a_Json["m_DataType"] as string; 85 | if ( a_Json.Contains( "m_Data" ) ) 86 | Data = a_Json["m_Data"] as IDictionary; 87 | } 88 | public IDictionary Serialize() 89 | { 90 | Dictionary json = new Dictionary(); 91 | 92 | if ( Body != null ) 93 | { 94 | foreach( string key in Body.Keys ) 95 | json[key] = Body[key]; 96 | } 97 | json["Type_"] = Type; 98 | json["m_eCategory"] = (int)Category; 99 | json["m_GUID"] = GUID; 100 | json["m_fImportance"] = Importance; 101 | json["m_State"] = State; 102 | json["m_CreateTime"] = CreateTime; 103 | json["m_fLifeSpan"] = LifeSpan; 104 | 105 | if (! string.IsNullOrEmpty( DataType ) ) 106 | { 107 | json["m_DataType"] = DataType; 108 | json["m_Data"] = Data; 109 | } 110 | 111 | return json; 112 | } 113 | #endregion 114 | } 115 | 116 | public enum ThingEventType 117 | { 118 | TE_NONE = 0x0, // no flags 119 | TE_ADDED = 0x1, // IThing has been added 120 | TE_REMOVED = 0x2, // IThing has been removed 121 | TE_STATE = 0x4, // state of IThing has changed. 122 | TE_IMPORTANCE = 0x8, // Importance of IThing has changed. 123 | 124 | TE_ALL = TE_ADDED | TE_REMOVED | TE_STATE | TE_IMPORTANCE, 125 | TE_ADDED_OR_STATE = TE_ADDED | TE_STATE 126 | } 127 | public struct ThingEvent 128 | { 129 | public ThingEventType m_EventType; 130 | public IDictionary m_Event; 131 | public IThing m_Thing; 132 | 133 | public override string ToString() 134 | { 135 | return string.Format("[ThingEvent: ThingEventType={0}]", m_EventType); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Scripts/Services/RobotGateway.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using IBM.Watson.DeveloperCloud.Connection; 19 | using IBM.Watson.DeveloperCloud.Logging; 20 | using IBM.Watson.DeveloperCloud.Services; 21 | using IBM.Watson.DeveloperCloud.Utilities; 22 | using MiniJSON; 23 | using System; 24 | using System.Collections; 25 | using System.Collections.Generic; 26 | using System.Text; 27 | 28 | namespace IBM.Watson.Self.Services 29 | { 30 | public class RobotGateway : IWatsonService 31 | { 32 | private const string SERVICE_ID = "RobotGatewayV1"; 33 | 34 | #region IWatsonService interface 35 | public string GetServiceID() 36 | { 37 | return "RobotGatewayV1"; 38 | } 39 | public void GetServiceStatus(ServiceStatus callback) 40 | { 41 | callback( SERVICE_ID, true ); 42 | } 43 | #endregion 44 | 45 | #region Public Types 46 | public delegate void OnRegisteredEmbodiment( string a_Token, string a_SelfId ); 47 | #endregion 48 | 49 | #region RegisterEmbodiment 50 | private class RegisterEmbodimentReq : RESTConnector.Request 51 | { 52 | public OnRegisteredEmbodiment Callback { get; set; } 53 | }; 54 | 55 | /// 56 | /// Register an embodiment with the gateway. 57 | /// 58 | /// 59 | /// 60 | /// 61 | /// 62 | /// 63 | /// 64 | /// 65 | public bool RegisterEmbodiment( string a_GroupId, 66 | string a_OrgId, 67 | string a_BearerToken, 68 | string a_EmbodimentName, 69 | string a_EmbodimentType, 70 | OnRegisteredEmbodiment a_Callback ) 71 | { 72 | RESTConnector connection = RESTConnector.GetConnector( SERVICE_ID, "/v1/auth/registerEmbodiment" ); 73 | if ( connection == null ) 74 | { 75 | Log.Error( "TopicClient", "RobotGatewayV1 service credentials not found." ); 76 | return false; 77 | } 78 | 79 | Dictionary headers = new Dictionary(); 80 | headers["Content-Type"] = "application/json"; 81 | headers["Authorization"] = "Bearer " + a_BearerToken; 82 | headers["groupId"] = a_GroupId; 83 | headers["orgId"] = a_OrgId; 84 | headers["macId" ] = Utility.MacAddress; 85 | 86 | Dictionary json = new Dictionary(); 87 | json["embodimentName"] = a_EmbodimentName; 88 | json["type"] = a_EmbodimentType; 89 | json["groupId"] = a_GroupId; 90 | json["orgId"] = a_OrgId; 91 | json["macId"] = Utility.MacAddress; 92 | json["embodimentToken"] = "token"; 93 | 94 | RegisterEmbodimentReq req = new RegisterEmbodimentReq(); 95 | req.Send = Encoding.UTF8.GetBytes( Json.Serialize( json ) ); 96 | req.Headers = headers; 97 | req.Callback = a_Callback; 98 | 99 | req.OnResponse += OnRegisterEmbodiment; 100 | return connection.Send( req ); 101 | } 102 | 103 | private void OnRegisterEmbodiment(RESTConnector.Request req, RESTConnector.Response resp) 104 | { 105 | RegisterEmbodimentReq ereq = req as RegisterEmbodimentReq; 106 | 107 | if (resp.Success) 108 | { 109 | try { 110 | IDictionary json = Json.Deserialize( Encoding.UTF8.GetString( resp.Data ) ) as IDictionary; 111 | string embodimentId = json["_id"] as string; 112 | string token = json["embodimentToken"] as string; 113 | 114 | if ( ereq.Callback != null ) 115 | ereq.Callback( token, embodimentId ); 116 | } 117 | catch (Exception e) 118 | { 119 | Log.Error("TopicClient", "OnRegisterEmbodiment Exception: {0}", e.ToString()); 120 | resp.Success = false; 121 | } 122 | } 123 | 124 | if (! resp.Success && ereq.Callback != null ) 125 | ereq.Callback( null, null ); 126 | } 127 | #endregion 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfSpeechGesture.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | 19 | using IBM.Watson.DeveloperCloud.DataTypes; 20 | using IBM.Watson.DeveloperCloud.Widgets; 21 | using IBM.Watson.Self.Gestures; 22 | using System; 23 | using System.Collections; 24 | using UnityEngine; 25 | using IBM.Watson.Self.Topics; 26 | using IBM.Watson.DeveloperCloud.Utilities; 27 | 28 | namespace IBM.Watson.Self.Widgets 29 | { 30 | public class SelfSpeechGesture : Widget, IGesture 31 | { 32 | #region Private Data 33 | [SerializeField] 34 | private Output m_TextOutput = new Output(typeof(TextToSpeechData), true); 35 | [SerializeField] 36 | private Input m_SpeakingInput = new Input( "Speaking Input", typeof(SpeakingStateData), "OnSpeakingState" ); 37 | [SerializeField] 38 | private Input m_TopicClientInput = new Input("TopicClientInput", typeof(TopicClientData), "OnTopicClientInput"); 39 | [SerializeField] 40 | private string m_GestureId = "tts"; 41 | [SerializeField] 42 | private bool m_Override = true; 43 | private string m_InstanceId = Guid.NewGuid().ToString(); 44 | private OnGestureDone m_Callback = null; 45 | #endregion 46 | 47 | #region Public Properties 48 | public GestureManager GestureManager{ get; private set; } 49 | #endregion 50 | 51 | #region Widget interface 52 | protected override string GetName() 53 | { 54 | return "SelfSpeechGesture"; 55 | } 56 | #endregion 57 | 58 | #region IGesture interface 59 | public string GetGestureId() 60 | { 61 | return m_GestureId; 62 | } 63 | //! return an ID unique to this instance 64 | public string GetInstanceId() 65 | { 66 | return m_InstanceId; 67 | } 68 | //! Initialize this gesture object, returns false if gesture can't be initialized 69 | public bool OnStart() 70 | { 71 | return true; 72 | } 73 | 74 | //! Shutdown this gesture object. 75 | public bool OnStop() 76 | { 77 | return true; 78 | } 79 | //! Execute this gesture, the provided callback should be invoked when the gesture is complete. 80 | public bool Execute(OnGestureDone a_Callback, IDictionary a_Params) 81 | { 82 | m_Callback = a_Callback; 83 | 84 | bool bError = false; 85 | string text = a_Params["text"] as string; 86 | string gender = a_Params["gender"] as string; 87 | string language = a_Params["language"] as string; 88 | 89 | // TODO: implement gender & language support 90 | if (string.IsNullOrEmpty(text) || !m_TextOutput.SendData(new TextToSpeechData(text))) 91 | bError = true; 92 | 93 | if ( bError ) 94 | { 95 | if ( m_Callback != null ) 96 | m_Callback(this, true ); 97 | m_Callback = null; 98 | } 99 | 100 | return true; 101 | } 102 | //! Abort this gesture, if true is returned then abort succeeded and callback will NOT be invoked. 103 | public bool Abort() 104 | { 105 | return true; 106 | } 107 | #endregion 108 | 109 | #region Event Handlers 110 | private void OnTopicClientInput(Data data) 111 | { 112 | TopicClientData a_TopicClientData = (TopicClientData)data; 113 | if (a_TopicClientData == null || a_TopicClientData.TopicClient == null) 114 | { 115 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 116 | } 117 | if (GestureManager != null) 118 | { 119 | GestureManager.RemoveGesture(this); 120 | } 121 | 122 | GestureManager = new GestureManager(a_TopicClientData.TopicClient); 123 | GestureManager.AddGesture(this, m_Override); 124 | } 125 | 126 | private void OnSpeakingState(Data data) 127 | { 128 | SpeakingStateData state = data as SpeakingStateData; 129 | if ( state != null ) 130 | { 131 | if ( !state.Boolean ) 132 | { 133 | if (m_Callback != null) 134 | m_Callback(this, false); 135 | } 136 | } 137 | } 138 | #endregion 139 | 140 | 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Scripts/Widgets/SelfMicrophoneSensor.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using System; 19 | using UnityEngine; 20 | using IBM.Watson.DeveloperCloud.Widgets; 21 | using IBM.Watson.Self.Sensors; 22 | using IBM.Watson.DeveloperCloud.Utilities; 23 | using IBM.Watson.DeveloperCloud.Logging; 24 | using IBM.Watson.Self.Topics; 25 | 26 | namespace IBM.Watson.Self.Widgets 27 | { 28 | /// 29 | /// This widget works with the existing MicrophoneWidget from the Unity SDK 30 | /// 31 | public class SelfMicrophoneSensor : Widget, ISensor 32 | { 33 | #region Private Data 34 | private string m_SensorId = Guid.NewGuid().ToString(); 35 | private bool m_IsAdded = false; 36 | private bool m_IsStarted = false; 37 | private bool m_IsPaused = false; 38 | private int m_Rate = 0; 39 | private int m_Channels = 0; 40 | 41 | [SerializeField] 42 | protected Input m_AudioInput = new Input("Audio", typeof(DeveloperCloud.DataTypes.AudioData), "OnAudioInput"); 43 | [SerializeField] 44 | private Input m_TopicClientInput = new Input("TopicClientInput", typeof(TopicClientData), "OnTopicClientInput"); 45 | [SerializeField] 46 | protected bool m_bOverride = true; 47 | #endregion 48 | 49 | #region Public Properties 50 | public SensorManager SensorManager{ get; private set; } 51 | #endregion 52 | 53 | #region Widget interface 54 | protected override string GetName() 55 | { 56 | return "SelfMicrophoneSensor"; 57 | } 58 | #endregion 59 | 60 | #region ISensor interface 61 | public string GetSensorId() 62 | { 63 | return m_SensorId; 64 | } 65 | public string GetSensorName() 66 | { 67 | return "Microphone"; 68 | } 69 | public string GetDataType() 70 | { 71 | return "AudioData"; 72 | } 73 | 74 | public string GetBinaryType() 75 | { 76 | return string.Format("audio/L16;rate={0};channels={1}", m_Rate, m_Channels); 77 | } 78 | 79 | public bool OnStart() 80 | { 81 | m_IsStarted = true; 82 | return true; 83 | } 84 | 85 | public bool OnStop() 86 | { 87 | m_IsStarted = false; 88 | return true; 89 | } 90 | 91 | public void OnPause() 92 | { 93 | m_IsPaused = true; 94 | } 95 | 96 | public void OnResume() 97 | { 98 | m_IsPaused = false; 99 | } 100 | #endregion 101 | 102 | #region Input Handlers 103 | private void OnAudioInput(Data data) 104 | { 105 | DeveloperCloud.DataTypes.AudioData audioData = data as DeveloperCloud.DataTypes.AudioData; 106 | if (audioData != null) 107 | { 108 | if (!m_IsAdded) 109 | Add(audioData.Clip.frequency, audioData.Clip.channels); 110 | 111 | if (IsStarted && !IsPaused) 112 | { 113 | if(SensorManager != null) 114 | SensorManager.SendData(this, new Sensors.AudioData(audioData)); 115 | else 116 | Log.Error("SelfMicrophoneSensor", "SensorManager needs to be supported and can't be null."); 117 | } 118 | } 119 | } 120 | 121 | private void OnTopicClientInput(Data data) 122 | { 123 | TopicClientData a_TopicClientData = (TopicClientData)data; 124 | if (a_TopicClientData == null || a_TopicClientData.TopicClient == null) 125 | { 126 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 127 | } 128 | SensorManager = new SensorManager(a_TopicClientData.TopicClient); 129 | } 130 | #endregion 131 | 132 | #region Public Properties 133 | public bool IsStarted { get { return m_IsStarted; } } 134 | public bool IsPaused { get { return m_IsPaused; } } 135 | #endregion 136 | 137 | #region Public Functions 138 | public void Add(int a_Rate, int a_Channels) 139 | { 140 | m_Rate = a_Rate; 141 | m_Channels = a_Channels; 142 | m_IsAdded = true; 143 | 144 | if(SensorManager != null) 145 | SensorManager.AddSensor(this, m_bOverride ); 146 | else 147 | Log.Error("SelfMicrophoneSensor", "SensorManager needs to be supported and can't be null."); 148 | } 149 | public void Remove() 150 | { 151 | if (m_IsAdded) 152 | { 153 | if(SensorManager != null) 154 | SensorManager.RemoveSensor(this); 155 | else 156 | Log.Error("SelfMicrophoneSensor", "SensorManager needs to be supported and can't be null."); 157 | 158 | m_IsAdded = false; 159 | } 160 | } 161 | #endregion 162 | 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Intu Unity SDK 2 | 3 | Intu is an architecture that enables Watson services in devices that perceive by vision, audition, olfaction, sonar, infrared energy, temperature, and vibration. Intu-enabled devices express themselves and interact with their environments, other devices, and people through speakers, actuators, gestures, scent emitters, lights, navigation, and more. 4 | 5 | This SDK allows a Unity 3D application to connect to a running self instance and extend self with sensors, gestures, or agents implemented within unity. 6 | 7 | ## Before you begin 8 | 9 | * To use Intu, you must have a Bluemix account. To register for a Bluemix account, go to https://console.ng.bluemix.net/registration/. 10 | * Ensure your hardware meets the following requirements: 11 | 12 | * Windows 13 | 14 | * Intel® Core 2 or AMD Athlon® 64 processor; 2 GHz or faster processor 15 | * Microsoft Windows 7 with Service Pack 1, Windows 8.1, or Windows 10, Windows 2013 16 | * 2 GB of RAM (8 GB recommended) 17 | * 1 GB of available hard-disk space for 32-bit installation; 1 GB of available hard-disk space for 64-bit installation; additional free space required during installation (cannot install on a volume that uses a case-sensitive file system) 18 | * 1024 x 768 display (1280x800 recommended) with 16-bit color and 512 MB of dedicated VRAM; 2 GB is recommended 19 | * OpenGL 2.0–capable system 20 | * CPU: SSE2 instruction set support 21 | * Graphics card: DX9 (shader model 3.0) or DX11 with feature level 9.3 capabilities. 22 | * Internet connection and registration are necessary for required software activation, validation of subscriptions, and access to online services. 23 | 24 | * Mac OS 25 | 26 | * Multicore Intel processor with 64-bit support 27 | * Mac OS 10.12, 10.11, 10.10, 10.9 28 | * 2 GB of RAM (8 GB recommended) 29 | * 1GB of available hard-disk space for installation; additional free space required during installation (cannot install on a volume that uses a case-sensitive file system) 30 | * 1024 x 768 display (1280x800 recommended) with 16-bit color and 512 MB of dedicated VRAM; 2 GB is recommended 31 | * OpenGL 2.0–capable system (This is must have for Unity Application) 32 | * CPU: SSE2 instruction set support 33 | * Graphics card: DX9 (shader model 3.0) or DX11 with feature level 9.3 capabilities. 34 | * Internet connection and registration are necessary for required software activation, membership validation, and access to online services. 35 | 36 | ## Getting started 37 | 38 | Getting started includes the following tasks: 39 | 40 | 1. [Requesting access to the Watson Intu Gateway](#requesting-access-to-the-watson-intu-gateway) 41 | 2. [Downloading Intu](#downloading-intu) 42 | 3. [Installing Intu](#installing-intu) 43 | 44 | ### Requesting access to the Watson Intu Gateway 45 | 46 | 1. Request access to the Watson Intu Gateway. Open [Intu Gateway](https://rg-gateway.mybluemix.net/). 47 | 2. Click **Log In** and specify your IBM Bluemix credentials. 48 | 3. In the **Organization** field, specify the name of the organization that you represent. 49 | 4. In the **Business Justification** field, briefly explain why you need access to the Intu Gateway. 50 | 5. Click **Submit**. After your request for access is approved, you receive a confirmation email. 51 | 6. Open the confirmation email, and click the link. The Intu Gateway Log In page is displayed again. 52 | 7. Click **Log In**. The Intu Downloads page is displayed. 53 | 54 | ### Downloading Intu 55 | 56 | 1. On the Intu Downloads page, download the appropriate installation package for your platform. 57 | 2. Extract the files from the package into your working directory. 58 | 59 | ### Installing Intu 60 | 61 | 1. In your working directory, double-click Intu Manager. If a security warning is displayed, accept the risk and open the file. 62 | 2. Select the **Windowed** checkbox, and click **Play!**. The Intu Tooling page is displayed. 63 | 3. Click **Install Intu**, and a new Intu Tooling sign-in page is displayed. 64 | 4. Click **Log In**. You are prompted to return to the Intu Manager application. 65 | 5. A page displays options for where you can choose to install Intu. For this workshop, select local machine, and click **Next**. A page displays your organization in the dropdown menu, and defaultGroup is selected. 66 | 6. Click **Install**. Installing Intu takes a few minutes. During the installation process, if you see one or more security prompts, allow access. After the installation process is complete, your instance of Intu is preconfigured with the following Watson services: Conversation, Natural Language Classifier, Speech to Text, and Text to Speech. The preconfiguration is enabled for a trial period of 24 hours. If you want to test Intu after the trial period, see [After DevCon ends](#after-devcon-ends). 67 | 68 | After Intu is installed, the Intu Manager window is displayed, and you're prompted to select your group. Your organization and group should be preselected in the dropdown menu. 69 | 70 | 3. Click **Next**. A "Connecting to parent..." message is displayed while your Intu embodiment tries to establish a connection. During this part of the process, the box beside your embodiment is red and labeled with Off. After the connection is established, the box is green and labeled On. 71 | 4. Doubleclick your embodiment. The Menu option is displayed. 72 | 73 | ## Configuring Intu 74 | Your installation is preconfigured to use the Conversation, Natural Language Classifier, Speech to Text, and Text to Speech services. To configure Intu to use your instances of these services, complete the following steps. 75 | 76 | **Pro tip:** As you complete this task, you'll receive credentials for each service instance, and you'll need these credentials later. Open a new file in your favorite text editor and create a section for each service so that you can temporarily store its credentials. 77 | 78 | 1. [Log in to Bluemix](http://www.ibm.com/cloud-computing/bluemix/). 79 | 2. On the Bluemix dashboard, click **Catalog** in the navigation bar. 80 | 3. Click **Watson** in the categories menu. 81 | 4. Create an instance of the Conversation service. 82 | 1. Click the **Conversation** tile. 83 | 2. Keep all the default values, and click **Create**. 84 | 3. Click the **Service Credentials** tab. 85 | 4. Click **View Credentials** for the new service instance. 86 | 5. Copy the values of the `password` and `username` parameters and paste them in your text file. 87 | 6. Click the **Watson** breadcrumb. 88 | 7. Add the next service instance by clicking the hexagonal **+** button. 89 | 5. Create instances of the Natural Language Classifier, Speech to Text, and Text to Speech services by repeating the same steps 1 - 7 that you completed to create the Conversation service instance. 90 | 6. Specify your service credentials in Intu Gateway. 91 | 1. Expand **All Organizations** by clicking the arrow icon. 92 | 2. Click the name of your organization. 93 | 3. Expand your organization by clicking the arrow icon. 94 | 4. Click the name of your group. 95 | 5. Click **Services** in the navigation bar. 96 | 6. For your instances of the Conversation, Natural Language Classifier, Speech to Text, and Text to Speech services, click **Edit**, specify the user ID and password, and click **Save**. 97 | 98 | **Important:** Do not change the service endpoint unless you are an enterprise user. 99 | 100 | ### Installing the Intu Starter Kit 101 | 102 | The Intu Starter Kit contains a Conversation service workspace that helps you visualize how intents, entities, and dialog are developed. You can expand on the workspace in the kit or use it as a guide for developing your own later. 103 | 104 | 1. Log in to Intu Gateway. 105 | 2. Click **Downloads**. 106 | 3. Download the Intu Starter Kit. 107 | 4. Complete the instructions in `readme.txt`. 108 | 109 | ## Using Intu for Unity 110 | 111 | ### Getting the files 112 | 113 | Download the code to your computer. You can do download the code in either of the following ways: 114 | 115 | * This project depends on the Watson Developer Cloud Unity SDK, you will need to install that into your Unity project before installing this project. See https://github.com/watson-developer-cloud/unity-sdk 116 | * Download the .zip file of this repository to a local directory. 117 | * Clone this repository locally. 118 | 119 | 120 | ### Release Notes 121 | * None 122 | 123 | ### Installing Files 124 | 125 | 1. Copy the files from the zip or git clone into your Unity project Assets/ folder (typically Assets/SelfUnitySDK) 126 | 127 | ## Feedback 128 | 129 | Post your comments and questions and include the `self` tag on 130 | [dW Answers](https://developer.ibm.com/answers/questions/ask/?topics=watson) 131 | or [Stack Overflow](http://stackoverflow.com/questions/ask?tags=ibm-watson). 132 | -------------------------------------------------------------------------------- /Scripts/Sensors/SensorManager.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using IBM.Watson.DeveloperCloud.Utilities; 19 | using IBM.Watson.Self.Topics; 20 | using IBM.Watson.DeveloperCloud.Logging; 21 | 22 | using System.Collections; 23 | using System.Text; 24 | using System.Collections.Generic; 25 | using MiniJSON; 26 | 27 | namespace IBM.Watson.Self.Sensors 28 | { 29 | /// 30 | /// This sensor manager allows the user to register/unregister sensors with the remote 31 | /// self instance through the TopicClient. 32 | /// 33 | public class SensorManager 34 | { 35 | #region Private Data 36 | 37 | Dictionary m_Sensors = new Dictionary(); 38 | Dictionary m_Overrides = new Dictionary(); 39 | bool m_bDisconnected = false; 40 | #endregion 41 | 42 | #region Public Properties 43 | public TopicClient TopicClient { get; protected set;} 44 | #endregion 45 | 46 | #region Public Interface 47 | public SensorManager(TopicClient a_TopicClient) 48 | { 49 | if (a_TopicClient == null) 50 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 51 | TopicClient = a_TopicClient; 52 | TopicClient.StateChangedEvent += OnStateChanged; 53 | TopicClient.Subscribe( "sensor-manager", OnSensorManagerEvent ); 54 | } 55 | 56 | ~SensorManager() 57 | { 58 | TopicClient.StateChangedEvent -= OnStateChanged; 59 | TopicClient.Unsubscribe( "sensor-manager", OnSensorManagerEvent ); 60 | } 61 | 62 | public bool IsRegistered( ISensor a_Sensor ) 63 | { 64 | return m_Sensors.ContainsKey( a_Sensor.GetSensorId() ); 65 | } 66 | 67 | /// 68 | /// Add a sensor with the remote self instance, agents may now subscribe to this 69 | /// sensor and OnStart() will be invoked automatically by this framework. 70 | /// 71 | /// The sensor object to add. 72 | /// If true, then any remote sensor with the same name will be overridden. 73 | public void AddSensor( ISensor a_Sensor, bool a_bOverride ) 74 | { 75 | if (! m_Sensors.ContainsKey( a_Sensor.GetSensorId() ) ) 76 | { 77 | Dictionary register = new Dictionary(); 78 | register["event"] = "add_sensor_proxy"; 79 | register["sensorId"] = a_Sensor.GetSensorId(); 80 | register["name"] = a_Sensor.GetSensorName(); 81 | register["data_type"] = a_Sensor.GetDataType(); 82 | register["binary_type"] = a_Sensor.GetBinaryType(); 83 | register["override"] = a_bOverride; 84 | 85 | TopicClient.Publish( "sensor-manager", Json.Serialize( register ) ); 86 | m_Sensors[ a_Sensor.GetSensorId() ] = a_Sensor; 87 | m_Overrides[a_Sensor.GetSensorId()] = a_bOverride; 88 | 89 | Log.Status( "SensorManager", "Sensor {0} added.", a_Sensor.GetSensorId() ); 90 | } 91 | } 92 | 93 | public void SendData( ISensor a_Sensor, ISensorData a_Data) 94 | { 95 | if (!IsRegistered(a_Sensor)) 96 | throw new WatsonException("SendData() invoked on unregisted sensors."); 97 | 98 | TopicClient.Publish("sensor-proxy-" + a_Sensor.GetSensorId(), a_Data.ToBinary()); 99 | } 100 | 101 | //! Remove the provided sensor from the remote self instance. 102 | public void RemoveSensor( ISensor a_Sensor ) 103 | { 104 | if ( m_Sensors.ContainsKey( a_Sensor.GetSensorId() ) ) 105 | { 106 | m_Sensors.Remove( a_Sensor.GetSensorId() ); 107 | m_Overrides.Remove(a_Sensor.GetSensorId()); 108 | 109 | Dictionary register = new Dictionary(); 110 | register["event"] = "remove_sensor_proxy"; 111 | register["sensorId"] = a_Sensor.GetSensorId(); 112 | 113 | TopicClient.Publish( "sensor-manager", Json.Serialize( register ) ); 114 | Log.Status( "SensorManager", "Sensor {0} removed.", a_Sensor.GetSensorId() ); 115 | } 116 | } 117 | 118 | #endregion 119 | 120 | #region Callback Functions 121 | void OnStateChanged(TopicClient.ClientState a_CurrentState) 122 | { 123 | switch (a_CurrentState) 124 | { 125 | case TopicClient.ClientState.Connected: 126 | OnConnected(); 127 | break; 128 | case TopicClient.ClientState.Disconnected: 129 | OnDisconnected(); 130 | break; 131 | default: 132 | break; 133 | } 134 | } 135 | 136 | void OnConnected() 137 | { 138 | if (m_bDisconnected) 139 | { 140 | // re-register all our sensors on reconnect. 141 | foreach (var kv in m_Sensors) 142 | { 143 | string sensorId = kv.Key; 144 | ISensor sensor = kv.Value; 145 | 146 | Dictionary register = new Dictionary(); 147 | register["event"] = "add_sensor_proxy"; 148 | register["sensorId"] = sensor.GetSensorId(); 149 | register["name"] = sensor.GetSensorName(); 150 | register["data_type"] = sensor.GetDataType(); 151 | register["binary_type"] = sensor.GetBinaryType(); 152 | register["override"] = m_Overrides[sensorId]; 153 | 154 | TopicClient.Publish("sensor-manager", Json.Serialize(register)); 155 | Log.Status("SensorManager", "Sensor {0} restored.", sensor.GetSensorId()); 156 | } 157 | m_bDisconnected = false; 158 | } 159 | } 160 | void OnDisconnected() 161 | { 162 | m_bDisconnected = true; 163 | } 164 | 165 | //! Callback for sensor-manager topic. 166 | void OnSensorManagerEvent( TopicClient.Payload a_Payload ) 167 | { 168 | IDictionary json = Json.Deserialize( Encoding.UTF8.GetString( a_Payload.Data ) ) as IDictionary; 169 | 170 | bool bFailed = false; 171 | string sensorId = json["sensorId"] as string; 172 | 173 | ISensor sensor = null; 174 | if ( m_Sensors.TryGetValue( sensorId, out sensor ) ) 175 | { 176 | string event_name = json["event"] as string; 177 | if (event_name.CompareTo("start_sensor") == 0) 178 | { 179 | if (!sensor.OnStart()) 180 | { 181 | Log.Error("SensorManager", "Failed to start sensor {0}", sensorId); 182 | bFailed = true; 183 | } 184 | } 185 | else if (event_name.CompareTo("stop_sensor") == 0) 186 | { 187 | if (!sensor.OnStop()) 188 | { 189 | Log.Error("SensorManager", "OnStop() returned failure for sensor {0}", sensorId); 190 | bFailed = true; 191 | } 192 | } 193 | else if (event_name.CompareTo("pause_sensor") == 0) 194 | sensor.OnPause(); 195 | else if (event_name.CompareTo("resume_sensor") == 0) 196 | sensor.OnResume(); 197 | } 198 | else 199 | { 200 | Log.Error( "SensorManager", "Failed to find sensor {0}", sensorId ); 201 | bFailed = true; 202 | } 203 | 204 | // if we failed, send the message back with a different event 205 | if ( bFailed ) 206 | { 207 | json["failed_event"] = json["event"]; 208 | json["event"] = "error"; 209 | 210 | TopicClient.Publish( "sensor-manager", Json.Serialize( json ) ); 211 | } 212 | } 213 | #endregion 214 | 215 | } 216 | 217 | } -------------------------------------------------------------------------------- /Scripts/Gestures/GestureManager.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | 19 | using System.Collections; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | 23 | using IBM.Watson.Self.Topics; 24 | using IBM.Watson.DeveloperCloud.Utilities; 25 | using IBM.Watson.DeveloperCloud.Logging; 26 | using MiniJSON; 27 | 28 | namespace IBM.Watson.Self.Gestures 29 | { 30 | public class GestureManager 31 | { 32 | #region Private Data 33 | private Dictionary m_Gestures = new Dictionary(); 34 | private Dictionary m_Overrides = new Dictionary(); 35 | private bool m_bDisconnected = false; 36 | #endregion 37 | 38 | #region Public Interface 39 | 40 | /// 41 | /// Gets the topic client. 42 | /// 43 | /// The topic client. 44 | public TopicClient TopicClient{ get; private set; } 45 | 46 | /// 47 | /// Default constructor. 48 | /// 49 | public GestureManager(TopicClient a_TopicClient) 50 | { 51 | if (a_TopicClient == null) 52 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 53 | 54 | TopicClient = a_TopicClient; 55 | TopicClient.StateChangedEvent += OnStateChanged; 56 | TopicClient.Subscribe( "gesture-manager", OnGestureManagerEvent ); 57 | } 58 | 59 | /// 60 | /// Releases unmanaged resources and performs other cleanup operations before the 61 | /// is reclaimed by garbage collection. 62 | /// 63 | ~GestureManager() 64 | { 65 | TopicClient.StateChangedEvent -= OnStateChanged; 66 | TopicClient.Unsubscribe( "gesture-manager", OnGestureManagerEvent ); 67 | } 68 | 69 | /// 70 | /// Checks if a given IGesture objects ia already registered. 71 | /// 72 | /// The IGestue object to check. 73 | /// True is returned if registered. 74 | public bool IsRegistered( IGesture a_Gesture ) 75 | { 76 | return m_Gestures.ContainsKey( a_Gesture.GetGestureId() ); 77 | } 78 | 79 | /// 80 | /// Register a new gesture with self. If a_bOVerride is true, then any previous gesture with the same ID 81 | /// will be replaced by this new gesture. If false, then this gesture will be added alongside any existing gestures 82 | /// with the same ID. 83 | /// 84 | /// 85 | /// 86 | public void AddGesture( IGesture a_Gesture, bool a_bOverride = true ) 87 | { 88 | string gestureKey = a_Gesture.GetGestureId() + "/" + a_Gesture.GetInstanceId(); 89 | if (! m_Gestures.ContainsKey(gestureKey) ) 90 | { 91 | if ( a_Gesture.OnStart() ) 92 | { 93 | Dictionary register = new Dictionary(); 94 | register["event"] = "add_gesture_proxy"; 95 | register["gestureId"] = a_Gesture.GetGestureId(); 96 | register["instanceId"] = a_Gesture.GetInstanceId(); 97 | register["override"] = a_bOverride; 98 | 99 | TopicClient.Publish( "gesture-manager", Json.Serialize( register ) ); 100 | m_Gestures[gestureKey] = a_Gesture; 101 | m_Overrides[gestureKey] = a_bOverride; 102 | 103 | Log.Status( "GestureManager", "Gesture {0} added.", gestureKey ); 104 | } 105 | } 106 | } 107 | 108 | /// 109 | /// Remove the provided gesture from the remote self instance. 110 | /// 111 | /// 112 | public void RemoveGesture( IGesture a_Gesture ) 113 | { 114 | string gestureKey = a_Gesture.GetGestureId() + "/" + a_Gesture.GetInstanceId(); 115 | if ( m_Gestures.ContainsKey(gestureKey) ) 116 | { 117 | if ( a_Gesture.OnStop() ) 118 | { 119 | m_Gestures.Remove(gestureKey); 120 | m_Overrides.Remove(gestureKey); 121 | 122 | Dictionary register = new Dictionary(); 123 | register["event"] = "remove_gesture_proxy"; 124 | register["gestureId"] = a_Gesture.GetGestureId(); 125 | register["instanceId"] = a_Gesture.GetInstanceId(); 126 | 127 | TopicClient.Publish( "gesture-manager", Json.Serialize( register ) ); 128 | Log.Status( "GestureManager", "Gesture {0} removed.", gestureKey ); 129 | } 130 | } 131 | } 132 | 133 | #endregion 134 | 135 | #region Callback Functions 136 | 137 | void OnStateChanged(TopicClient.ClientState a_CurrentState) 138 | { 139 | switch (a_CurrentState) 140 | { 141 | case TopicClient.ClientState.Connected: 142 | OnConnected(); 143 | break; 144 | case TopicClient.ClientState.Disconnected: 145 | OnDisconnected(); 146 | break; 147 | default: 148 | break; 149 | } 150 | } 151 | 152 | void OnConnected() 153 | { 154 | if (m_bDisconnected) 155 | { 156 | // re-register all our gestures on reconnect. 157 | foreach (var kv in m_Gestures) 158 | { 159 | string gestureKey = kv.Key; 160 | IGesture gesture = kv.Value; 161 | 162 | Dictionary register = new Dictionary(); 163 | register["event"] = "add_gesture_proxy"; 164 | register["gestureId"] = gesture.GetGestureId(); 165 | register["instanceId"] = gesture.GetInstanceId(); 166 | register["override"] = m_Overrides[gestureKey]; 167 | 168 | TopicClient.Publish("gesture-manager", Json.Serialize(register)); 169 | Log.Status("GestureManager", "Gesture {0} restored.", gestureKey); 170 | } 171 | m_bDisconnected = false; 172 | } 173 | } 174 | void OnDisconnected() 175 | { 176 | m_bDisconnected = true; 177 | } 178 | 179 | //! Callback for sensor-manager topic. 180 | void OnGestureManagerEvent( TopicClient.Payload a_Payload ) 181 | { 182 | IDictionary json = Json.Deserialize( Encoding.UTF8.GetString( a_Payload.Data ) ) as IDictionary; 183 | 184 | bool bFailed = false; 185 | string gestureId = json["gestureId"] as string; 186 | string instanceId = json["instanceId"] as string; 187 | string gestureKey = gestureId + "/" + instanceId; 188 | string event_name = json["event"] as string; 189 | 190 | IGesture gesture = null; 191 | if (m_Gestures.ContainsKey(gestureKey)) 192 | { 193 | if (m_Gestures.TryGetValue(gestureKey, out gesture)) 194 | { 195 | if (event_name.CompareTo("execute_gesture") == 0) 196 | { 197 | if (!gesture.Execute(OnGestureDone, json["params"] as IDictionary)) 198 | { 199 | Log.Error("GestureManager", "Failed to execute gesture {0}", gestureId); 200 | bFailed = true; 201 | } 202 | } 203 | else if (event_name.CompareTo("abort_gesture") == 0) 204 | { 205 | if (!gesture.Abort()) 206 | { 207 | Log.Error("GestureManager", "Failed to abort gesture {0}", gestureId); 208 | bFailed = true; 209 | } 210 | } 211 | } 212 | else 213 | { 214 | Log.Error("GestureManager", "Failed to find gesture {0}", gestureKey); 215 | bFailed = true; 216 | } 217 | 218 | // if we failed, send the message back with a different event 219 | if (bFailed) 220 | { 221 | json["failed_event"] = event_name; 222 | json["event"] = "error"; 223 | 224 | TopicClient.Publish("gesture-manager", Json.Serialize(json)); 225 | } 226 | } 227 | else 228 | { 229 | //do nothing 230 | } 231 | } 232 | void OnGestureDone(IGesture a_Gesture, bool a_Error) 233 | { 234 | Dictionary response = new Dictionary(); 235 | response["event"] = "execute_done"; 236 | response["gestureId"] = a_Gesture.GetGestureId(); 237 | response["instanceId"] = a_Gesture.GetInstanceId(); 238 | response["error"] = a_Error; 239 | 240 | TopicClient.Publish("gesture-manager", Json.Serialize(response)); 241 | } 242 | 243 | #endregion 244 | } 245 | 246 | } 247 | -------------------------------------------------------------------------------- /Scripts/Utils/SelfDiscovery.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using MiniJSON; 19 | using System; 20 | using System.Collections; 21 | using System.Collections.Generic; 22 | using System.Net; 23 | using System.Net.Sockets; 24 | using System.Text; 25 | using System.Threading; 26 | using IBM.Watson.DeveloperCloud.Logging; 27 | using IBM.Watson.DeveloperCloud.Utilities; 28 | 29 | namespace IBM.Watson.Self.Utils 30 | { 31 | /// 32 | /// This object is created to explore the graph of self instances through the TopicClient object. 33 | /// 34 | public class SelfDiscovery 35 | { 36 | #region Private Data 37 | private string m_MulticastAddress = "239.255.0.1"; 38 | private int m_Port = 9444; 39 | private int m_DefaultListeningPort = 9443; 40 | private Thread m_ReceiveThread = null; 41 | private List m_Discovered = new List(); 42 | private int m_IPMulticastTimeToLive = 5; 43 | private int m_NumberOfInstances = 0; 44 | private UdpClient m_UdpClient = null; 45 | private int m_AsyncDiscoveredID = -1; 46 | #endregion 47 | 48 | #region Public Types 49 | public class SelfInstance 50 | { 51 | #region Public Properties 52 | public string Name { get; set; } 53 | public string Type { get; set; } 54 | public string MacId { get; set; } 55 | public string IPv4 { get; set; } 56 | public int Port { get; set; } 57 | public string EmbodimentId { get; set; } 58 | public string InstanceId { get; set; } 59 | public string GroupId { get; set; } 60 | public string OrgId { get; set; } 61 | public DateTime LastPing { get; set; } 62 | #endregion 63 | 64 | public override string ToString() 65 | { 66 | return string.Format("[SelfInstance: Name={0}, Type={1}, MacId={2}, IPv4={3}, Port={4}, EmbodimentId={5}, InstanceId={6}, GroupId={7}, OrgId={8}, LastPing={9}]", 67 | Name, Type, MacId, IPv4, Port, EmbodimentId, InstanceId, GroupId, OrgId, LastPing); 68 | } 69 | } 70 | public delegate void OnInstance( SelfInstance a_Instance ); 71 | #endregion 72 | 73 | #region Public Properties 74 | public static SelfDiscovery Instance { get { return Singleton.Instance; } } 75 | public OnInstance OnDiscovered { get; set; } // callback invoked from the non-main thread 76 | public List Discovered { get { return m_Discovered; } } // the user should lock this list before accessing 77 | #endregion 78 | 79 | #region Destructor to Stop Discovery 80 | ~SelfDiscovery() 81 | { 82 | StopDiscovery(); 83 | } 84 | 85 | public void OnApplicationQuit() 86 | { 87 | StopDiscovery(); 88 | } 89 | #endregion 90 | 91 | #region Public Functions 92 | public void StartDiscovery() 93 | { 94 | Log.Debug("SelfDiscovery", "Discovery started with multicast address: {0} and port {1}", m_MulticastAddress, m_Port); 95 | m_Discovered.Clear(); 96 | m_NumberOfInstances = 0; 97 | bool successOnSocketBind = false; 98 | 99 | if (m_UdpClient == null) 100 | { 101 | IPAddress multicastAddr = IPAddress.Parse( m_MulticastAddress ); 102 | m_UdpClient = new UdpClient(); 103 | m_UdpClient.ExclusiveAddressUse = true; 104 | 105 | //TODO: Fix it to make it ultimate 106 | try 107 | { 108 | m_UdpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); 109 | } 110 | catch (Exception e) 111 | { 112 | Log.Error("SelfDiscovery", "Exception UDP client settint reuse address. Message: {0}, StackTrace: {1}", e.Message, e.StackTrace); 113 | } 114 | 115 | try 116 | { 117 | m_UdpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); 118 | m_UdpClient.Client.Bind(new IPEndPoint(IPAddress.Any, m_Port)); 119 | m_UdpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddr, IPAddress.Any)); 120 | m_UdpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, m_IPMulticastTimeToLive); 121 | successOnSocketBind = true; 122 | } 123 | catch (Exception e) 124 | { 125 | Log.Error("SelfDiscovery", "Exception UDP client setting. Message: {0}, StackTrace: {1}", e.Message, e.StackTrace); 126 | } 127 | 128 | if (successOnSocketBind) 129 | { 130 | if (m_ReceiveThread != null && m_ReceiveThread.IsAlive) 131 | m_ReceiveThread.Abort(); 132 | 133 | m_ReceiveThread = new Thread(() => ReceiveThread()); 134 | m_ReceiveThread.IsBackground = true; 135 | m_ReceiveThread.Start(); 136 | 137 | m_AsyncDiscoveredID = Runnable.Run(AsyncOnDiscovered()); 138 | } 139 | } 140 | else 141 | { 142 | successOnSocketBind = true; 143 | } 144 | 145 | if (successOnSocketBind) 146 | { 147 | Log.Debug("SelfDiscovery", "Broadcasting Ping"); 148 | Dictionary message = new Dictionary(); 149 | message["action"] = "ping"; 150 | byte[] packet = Encoding.UTF8.GetBytes(Json.Serialize(message)); 151 | m_UdpClient.EnableBroadcast = true; 152 | m_UdpClient.Send(packet, packet.Length, new IPEndPoint(IPAddress.Broadcast, m_Port)); 153 | } 154 | else 155 | { 156 | StopDiscovery(); 157 | } 158 | 159 | } 160 | 161 | public void StopDiscovery() 162 | { 163 | if (m_AsyncDiscoveredID >= 0) 164 | { 165 | Log.Debug( "SelfDiscovery", "Stopping discover co-routine" ); 166 | Runnable.Stop(m_AsyncDiscoveredID); 167 | m_AsyncDiscoveredID = -1; 168 | } 169 | 170 | if ( m_ReceiveThread != null && m_ReceiveThread.IsAlive) 171 | { 172 | Log.Debug( "SelfDiscovery", "Stopping Receive thread" ); 173 | m_ReceiveThread.Abort(); 174 | } 175 | 176 | if (m_UdpClient != null) 177 | { 178 | Log.Debug( "SelfDiscovery", "Stopping UDP Client" ); 179 | m_UdpClient.Close(); 180 | m_UdpClient = null; 181 | } 182 | } 183 | #endregion 184 | 185 | #region Private Functions 186 | 187 | private IEnumerator AsyncOnDiscovered() 188 | { 189 | while (m_UdpClient != null) 190 | { 191 | if (m_NumberOfInstances != m_Discovered.Count) 192 | { 193 | for (int i = m_NumberOfInstances; i < m_Discovered.Count; i++) 194 | { 195 | if (OnDiscovered != null) 196 | OnDiscovered(m_Discovered[i]); 197 | 198 | m_NumberOfInstances++; 199 | } 200 | } 201 | yield return null; 202 | } 203 | yield break; 204 | 205 | } 206 | 207 | private void ReceiveThread() 208 | { 209 | Log.Debug("SelfDiscovery", "Started listening UDP broadcast to port {0}", m_Port); 210 | 211 | while (m_UdpClient != null) 212 | { 213 | IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, m_Port); 214 | byte[] data = m_UdpClient.Receive(ref remoteEP); 215 | if ( data.Length > 0 ) 216 | { 217 | IDictionary json = Json.Deserialize( Encoding.UTF8.GetString( data ) ) as IDictionary; 218 | if (json != null) 219 | { 220 | string action = json["action"] as string; 221 | if (action == "pong") 222 | { 223 | SelfInstance instance = new SelfInstance(); 224 | instance.Name = json["name"] as string; 225 | instance.Type = json["type"] as string; 226 | instance.MacId = json["macId"] as string; 227 | instance.IPv4 = remoteEP.Address.ToString(); 228 | instance.EmbodimentId = json["embodimentId"] as string; 229 | instance.InstanceId = json["instanceId"] as string; 230 | instance.GroupId = json["groupId"] as string; 231 | instance.OrgId = json["orgId"] as string; 232 | if (json.Contains("port")) 233 | { 234 | int portNumber = 0; 235 | if (int.TryParse(json["port"].ToString(), out portNumber) && portNumber != 0) 236 | { 237 | instance.Port = portNumber; 238 | } 239 | else 240 | { 241 | Log.Error("SelfDiscovery", "Port value couldn't be cast {0} Using default port {1}", json["port"].ToString(), m_DefaultListeningPort); 242 | instance.Port = m_DefaultListeningPort; 243 | } 244 | } 245 | else 246 | { 247 | Log.Error("SelfDiscovery", "Port needs to supported to be connect. Using default port {0}", m_DefaultListeningPort); 248 | instance.Port = m_DefaultListeningPort; 249 | } 250 | 251 | instance.LastPing = DateTime.Now; 252 | 253 | Log.Debug("SelfDiscovery", "Received Pong message from Intu : {0} from IP: {1}", instance,remoteEP.ToString()); 254 | 255 | lock (m_Discovered) 256 | { 257 | if(!m_Discovered.Exists( e => e.InstanceId == instance.InstanceId)) 258 | { 259 | m_Discovered.Add(instance); 260 | } 261 | } 262 | } 263 | else 264 | { 265 | Log.Debug("SelfDiscovery", "Received JSON data but not pong action. Action is : {0}", action); 266 | } 267 | } 268 | else 269 | { 270 | Log.Error("SelfDiscovery", "Received some data but not in JSON format so ignoring it. Message: \n{0}", Encoding.UTF8.GetString( data )); 271 | } 272 | } 273 | } 274 | 275 | Log.Debug("SelfDiscovery", "Finished listening "); 276 | } 277 | #endregion 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /Scripts/Utils/SelfExplorer.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | using IBM.Watson.DeveloperCloud.Logging; 19 | using IBM.Watson.DeveloperCloud.Utilities; 20 | using IBM.Watson.Self.Topics; 21 | using System; 22 | using System.Collections; 23 | using System.Collections.Generic; 24 | 25 | namespace IBM.Watson.Self.Utils 26 | { 27 | /// 28 | /// This object is created to explore the graph of self instances through the TopicClient object. 29 | /// 30 | public class SelfExplorer 31 | { 32 | #region Private Data 33 | private int m_PendingRequests = 0; 34 | #endregion 35 | 36 | #region Public Types 37 | public class Node 38 | { 39 | #region Private Data 40 | private SelfExplorer m_Explorer = null; 41 | private Node m_Parent = null; 42 | private List m_Children = new List(); 43 | private string m_Path = null; 44 | private TopicClient.QueryInfo m_Info = null; 45 | private string m_Source = null; // selfId of who created this node, so we don't backtrack 46 | private bool m_bError = false; 47 | private bool m_bSubscribed = false; 48 | private int m_RetryRoutine = -1; 49 | private bool m_Active = false; 50 | #endregion 51 | 52 | #region Public Properties 53 | public bool IsReady { get { return m_Info != null; } } 54 | public bool IsError { get { return m_bError; } } 55 | public Node Parent { get { return m_Parent; } set { m_Parent = value; } } 56 | public List Children { get { return m_Children; } } 57 | public string Path { get { return m_Path; } } 58 | public TopicClient.QueryInfo Info { get { return m_Info; } } 59 | public string SelfId { get { return m_Info != null ? m_Info.SelfId : ""; } } 60 | public string ParentId { get { return m_Info != null ? m_Info.ParentId : ""; } } 61 | public TopicClient TopicClient { get; set;} 62 | #endregion 63 | 64 | /// 65 | /// Refresh this node and all connected nodes. 66 | /// 67 | public void Refresh( string a_Path, string a_Source ) 68 | { 69 | m_Active = true; 70 | m_Path = a_Path; 71 | m_Source = a_Source; 72 | m_bError = false; 73 | 74 | m_Explorer.m_PendingRequests += 1; 75 | TopicClient.Query( m_Path, OnQueryResponse ); 76 | } 77 | 78 | public void Stop() 79 | { 80 | m_Active = false; 81 | 82 | if ( m_bSubscribed ) 83 | { 84 | TopicClient.Unsubscribe( m_Path + "topic-manager", OnTopicManagerEvent ); 85 | m_bSubscribed = false; 86 | } 87 | if ( m_RetryRoutine >= 0 ) 88 | { 89 | Runnable.Stop( m_RetryRoutine ); 90 | m_RetryRoutine = -1; 91 | } 92 | } 93 | 94 | public Node( SelfExplorer a_Explorer ) 95 | { 96 | m_Explorer = a_Explorer; 97 | TopicClient = a_Explorer.TopicClient; 98 | } 99 | 100 | private bool IsCircular( string a_Id ) 101 | { 102 | if ( a_Id == SelfId ) 103 | return true; 104 | if ( Parent != null ) 105 | return Parent.IsCircular( a_Id ); 106 | return false; 107 | } 108 | 109 | private void OnTopicManagerEvent( TopicClient.Payload a_Event ) 110 | { 111 | if ( a_Event != null ) 112 | { 113 | IDictionary json = a_Event.ParseJson(); 114 | 115 | string event_name = json["event"] as string; 116 | if ( event_name == "connected" ) 117 | { 118 | string selfId = json["selfId"] as string; 119 | 120 | if ( (bool)json["parent"] ) 121 | { 122 | if ( Parent != null ) 123 | throw new WatsonException( "Parent is already set!" ); 124 | 125 | Parent = new Node(m_Explorer); 126 | Parent.Children.Add( this ); 127 | if ( m_Explorer.OnNodeAdded != null ) 128 | m_Explorer.OnNodeAdded( Parent ); 129 | Parent.Refresh( m_Path + "../", SelfId ); 130 | } 131 | else 132 | { 133 | Node child = new Node(m_Explorer); 134 | m_Children.Add( child ); 135 | 136 | if ( m_Explorer.OnNodeAdded != null ) 137 | m_Explorer.OnNodeAdded( child ); 138 | 139 | child.Refresh( m_Path + selfId + "/", SelfId ); 140 | } 141 | } 142 | else if ( event_name == "disconnected" ) 143 | { 144 | string selfId = json["selfId"] as string; 145 | 146 | if ( Parent != null && Parent.SelfId == selfId ) 147 | { 148 | if ( m_Explorer.OnNodeRemoved != null ) 149 | m_Explorer.OnNodeRemoved( Parent ); 150 | Parent = null; 151 | } 152 | else 153 | { 154 | foreach( Node child in m_Children ) 155 | if ( child.SelfId == selfId ) 156 | { 157 | if ( m_Explorer.OnNodeRemoved != null ) 158 | m_Explorer.OnNodeRemoved( child ); 159 | 160 | m_Children.Remove( child ); 161 | break; 162 | } 163 | } 164 | } 165 | } 166 | else 167 | { 168 | Log.Error( "SelfExplorer", "Failed to subscribe to topic-manager, node: {0}", ToString() ); 169 | } 170 | } 171 | 172 | private void OnQueryResponse( TopicClient.QueryInfo a_Info ) 173 | { 174 | m_Explorer.m_PendingRequests -= 1; 175 | m_Info = a_Info; 176 | 177 | if ( m_Info != null ) 178 | { 179 | TopicClient.Subscribe( m_Path + "topic-manager", OnTopicManagerEvent ); 180 | m_bSubscribed = true; 181 | 182 | if (! string.IsNullOrEmpty( m_Info.ParentId ) ) 183 | { 184 | if ( m_Info.ParentId != m_Source ) 185 | { 186 | if (! IsCircular( m_Info.ParentId ) ) 187 | { 188 | Parent = new Node(m_Explorer); 189 | Parent.Children.Add( this ); 190 | 191 | if ( m_Explorer.OnNodeAdded != null ) 192 | m_Explorer.OnNodeAdded( Parent ); 193 | 194 | Parent.Refresh( m_Path + "../", SelfId ); 195 | } 196 | else 197 | Log.Warning( "SelfExplorer", "Circular parent detected {0}", m_Info.ParentId ); 198 | } 199 | } 200 | else if ( Parent != null ) 201 | { 202 | if ( m_Explorer.OnNodeRemoved != null ) 203 | m_Explorer.OnNodeRemoved( Parent ); 204 | 205 | Parent = null; 206 | } 207 | 208 | if ( m_Info.Children != null ) 209 | { 210 | foreach( string childId in m_Info.Children ) 211 | { 212 | if ( childId == m_Source || childId == SelfId ) 213 | continue; // skip our source 214 | 215 | // look for an existing node first.. 216 | Node child = null; 217 | foreach( Node node in m_Children ) 218 | if ( node.SelfId == childId ) 219 | { 220 | child = node; 221 | break; 222 | } 223 | 224 | if ( child == null ) 225 | { 226 | // no existing node found, create one.. 227 | child = new Node(m_Explorer); 228 | m_Children.Add( child ); 229 | 230 | if ( m_Explorer.OnNodeAdded != null ) 231 | m_Explorer.OnNodeAdded( child ); 232 | } 233 | 234 | // refresh the child node.. 235 | child.Refresh( m_Path + childId + "/", SelfId ); 236 | } 237 | } 238 | 239 | // remove children.. 240 | List remove = new List(); 241 | foreach( Node child in m_Children ) 242 | { 243 | bool bFoundChild = false; 244 | if ( m_Info.Children != null ) 245 | { 246 | foreach( string childId in m_Info.Children ) 247 | if ( childId == child.SelfId ) 248 | { 249 | bFoundChild = true; 250 | break; 251 | } 252 | } 253 | 254 | if (! bFoundChild ) 255 | { 256 | if ( m_Explorer.OnNodeRemoved != null ) 257 | m_Explorer.OnNodeRemoved( child ); 258 | remove.Add( child ); 259 | } 260 | } 261 | 262 | foreach( Node purge in remove ) 263 | m_Children.Remove( purge ); 264 | } 265 | else if(m_Active) 266 | { 267 | Log.Error( "SelfExplorer", "Failed to query {0}", m_Path ); 268 | m_bError = true; 269 | 270 | if ( m_Explorer.Root == this ) 271 | m_RetryRoutine = Runnable.Run( OnRetryRefresh() ); 272 | } 273 | 274 | if ( m_Explorer.OnNodeReady != null ) 275 | m_Explorer.OnNodeReady( this ); 276 | if ( m_Explorer.m_PendingRequests == 0 && m_Explorer.OnExplorerDone != null ) 277 | m_Explorer.OnExplorerDone( m_Explorer ); 278 | } 279 | 280 | public override string ToString() 281 | { 282 | return string.Format("[Node: IsReady={0}, IsError={1}, Parent={2}, Children Count={3}, Path={4}, Info={5}, SelfId={6}, ParentId={7}]", 283 | IsReady, IsError, Parent, (Children != null)? Children.Count.ToString() : " - ", Path, Info, SelfId, ParentId); 284 | } 285 | 286 | private IEnumerator OnRetryRefresh( float a_fTime = 5.0f ) 287 | { 288 | DateTime start = DateTime.Now; 289 | while( (DateTime.Now - start).TotalSeconds < a_fTime ) 290 | yield return null; 291 | 292 | m_RetryRoutine = -1; 293 | Log.Status( "SelfExplorer", "Retrying refresh!" ); 294 | 295 | if (m_Explorer.OnExplorerRefresh != null) 296 | m_Explorer.OnExplorerRefresh(m_Explorer); 297 | 298 | Refresh( m_Path, m_Source ); 299 | yield break; 300 | } 301 | } 302 | public delegate void OnNode( Node a_Node ); 303 | public delegate void OnDone( SelfExplorer a_Explorer ); 304 | #endregion 305 | 306 | #region Public Properties 307 | public int PendingRequests { get { return m_PendingRequests; } } 308 | public Node Root { get; set; } 309 | public OnNode OnNodeReady { get; set; } 310 | public OnNode OnNodeAdded { get; set; } 311 | public OnNode OnNodeRemoved { get; set; } 312 | public OnDone OnExplorerDone { get; set; } 313 | public OnDone OnExplorerRefresh { get; set; } 314 | public TopicClient TopicClient {get; private set;} 315 | #endregion 316 | 317 | #region Constuction & Destruction 318 | public SelfExplorer(TopicClient a_TopicClient) 319 | { 320 | if (a_TopicClient == null) 321 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 322 | TopicClient = a_TopicClient; 323 | } 324 | #endregion 325 | 326 | #region Public Functions 327 | public void Explore( string a_StartTarget = "" ) 328 | { 329 | if ( Root != null ) 330 | Root.Stop(); 331 | 332 | Root = new Node(this); 333 | Root.Refresh( a_StartTarget, TopicClient.SelfId ); 334 | } 335 | 336 | public void Stop() 337 | { 338 | if ( Root != null ) 339 | Root.Stop(); 340 | } 341 | 342 | public override string ToString() 343 | { 344 | return string.Format("[SelfExplorer: PendingRequests={0}, Root={1}]", PendingRequests, Root); 345 | } 346 | #endregion 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /Scripts/Agents/BlackBoard.cs: -------------------------------------------------------------------------------- 1 | //#define ENABLE_DEBUGGING 2 | 3 | /** 4 | * Copyright 2015 IBM Corp. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Collections; 23 | using IBM.Watson.DeveloperCloud.Utilities; 24 | using IBM.Watson.Self.Topics; 25 | using IBM.Watson.DeveloperCloud.Logging; 26 | 27 | using MiniJSON; 28 | 29 | namespace IBM.Watson.Self.Agents 30 | { 31 | public class BlackBoard 32 | { 33 | #region Public Types 34 | public delegate void OnThingEvent( ThingEvent a_Event ); 35 | #endregion 36 | 37 | #region Private Data 38 | private class Subscriber 39 | { 40 | public Subscriber( OnThingEvent a_Callback, ThingEventType a_EventMask, string a_Path ) 41 | { 42 | m_Callback = a_Callback; 43 | m_EventMask = a_EventMask; 44 | m_Path = a_Path; 45 | } 46 | 47 | public OnThingEvent m_Callback; 48 | public ThingEventType m_EventMask; 49 | public string m_Path; 50 | } 51 | private Dictionary>> m_SubscriberMap = new Dictionary>>(); 52 | private Dictionary m_ThingMap = new Dictionary(); 53 | private bool m_bDisconnected = false; 54 | #endregion 55 | 56 | #region Public Properties 57 | public TopicClient TopicClient { get; protected set;} 58 | #endregion 59 | 60 | #region Public Interface 61 | 62 | public BlackBoard(TopicClient a_TopicClient) 63 | { 64 | if (a_TopicClient == null) 65 | throw new WatsonException("TopicClient needs to be supported and can't be null."); 66 | 67 | TopicClient = a_TopicClient; 68 | TopicClient.StateChangedEvent += OnStateChanged; 69 | } 70 | 71 | ~BlackBoard() // destructor to clean-up events listeners 72 | { 73 | TopicClient.StateChangedEvent -= OnStateChanged; 74 | 75 | foreach( var kv in m_SubscriberMap ) 76 | TopicClient.Unsubscribe( kv.Key + "blackboard", OnBlackBoardEvent ); 77 | } 78 | 79 | public void SubscribeToType( string a_Type, OnThingEvent a_Callback, ThingEventType a_EventMask = ThingEventType.TE_ALL, string a_Path = "" ) 80 | { 81 | if (! m_SubscriberMap.ContainsKey(a_Path) ) 82 | { 83 | TopicClient.Subscribe( a_Path + "blackboard", OnBlackBoardEvent ); 84 | m_SubscriberMap[ a_Path ] = new Dictionary>(); 85 | } 86 | 87 | Dictionary> types = m_SubscriberMap[ a_Path ]; 88 | if (!types.ContainsKey(a_Type)) 89 | { 90 | types[a_Type] = new List(); 91 | 92 | Dictionary subscribe = new Dictionary(); 93 | subscribe["event"] = "subscribe_to_type"; 94 | subscribe["type"] = a_Type; 95 | subscribe["event_mask"] = (int)ThingEventType.TE_ALL; // we want all events, we will filter those events on this side 96 | 97 | TopicClient.Publish( a_Path + "blackboard", Json.Serialize(subscribe)); 98 | } 99 | 100 | types[a_Type].Add( new Subscriber( a_Callback, a_EventMask, a_Path ) ); 101 | } 102 | 103 | public void UnsubscribeFromType( string a_Type, OnThingEvent a_Callback = null, string a_Path = "" ) 104 | { 105 | if ( m_SubscriberMap.ContainsKey( a_Path ) ) 106 | { 107 | Dictionary> types = m_SubscriberMap[ a_Path ]; 108 | if ( types.ContainsKey( a_Type ) ) 109 | { 110 | if ( a_Callback != null ) 111 | { 112 | List subs = types[ a_Type ]; 113 | for(int i=0;i unsubscribe = new Dictionary(); 131 | unsubscribe["event"] = "unsubscribe_from_type"; 132 | unsubscribe["type"] = a_Type; 133 | 134 | TopicClient.Publish( a_Path + "blackboard", Json.Serialize(unsubscribe)); 135 | } 136 | } 137 | } 138 | 139 | public void AddThing( IThing a_Thing, string a_Path = "" ) 140 | { 141 | Dictionary add_object = new Dictionary(); 142 | add_object["event"] = "add_object"; 143 | add_object["type"] = string.IsNullOrEmpty( a_Thing.DataType ) ? a_Thing.Type : a_Thing.DataType; 144 | add_object["thing"] = a_Thing.Serialize(); 145 | if (!string.IsNullOrEmpty( a_Thing.ParentGUID ) ) 146 | add_object["parent"] = a_Thing.ParentGUID; 147 | 148 | TopicClient.Publish( a_Path + "blackboard", Json.Serialize(add_object) ); 149 | } 150 | public void RemoveThing( string a_GUID, string a_Path = "" ) 151 | { 152 | Dictionary remove_object = new Dictionary(); 153 | remove_object["event"] = "remove_object"; 154 | remove_object["thing_guid"] = a_GUID; 155 | 156 | TopicClient.Publish( a_Path + "blackboard", Json.Serialize(remove_object) ); 157 | } 158 | public void RemoveThing( IThing a_Thing, string a_Path = "" ) 159 | { 160 | RemoveThing( a_Thing.GUID, a_Path ); 161 | } 162 | public void SetState( string a_GUID, string a_State, string a_Path = "" ) 163 | { 164 | Dictionary set_object = new Dictionary(); 165 | set_object["event"] = "set_object_state"; 166 | set_object["thing_guid"] = a_GUID; 167 | set_object["state"] = a_State; 168 | 169 | TopicClient.Publish( a_Path + "blackboard", Json.Serialize(set_object) ); 170 | } 171 | public void SetState( IThing a_Thing, string a_State, string a_Path = "" ) 172 | { 173 | a_Thing.State = a_State; 174 | SetState( a_Thing.GUID, a_State, a_Path ); 175 | } 176 | public void SetImportance( string a_GUID, double a_Importance, string a_Path = "" ) 177 | { 178 | Dictionary set_object = new Dictionary(); 179 | set_object["event"] = "set_object_importance"; 180 | set_object["thing_guid"] = a_GUID; 181 | set_object["importance"] = a_Importance; 182 | 183 | TopicClient.Publish( a_Path + "blackboard", Json.Serialize(set_object) ); 184 | } 185 | public void SetImportance( IThing a_Thing, double a_Importance, string a_Path = "" ) 186 | { 187 | a_Thing.Importance = a_Importance; 188 | SetImportance( a_Thing.GUID, a_Importance, a_Path ); 189 | } 190 | 191 | #endregion 192 | 193 | #region Event Handlers 194 | 195 | void OnStateChanged(TopicClient.ClientState a_CurrentState) 196 | { 197 | switch (a_CurrentState) 198 | { 199 | case TopicClient.ClientState.Connected: 200 | OnConnected(); 201 | break; 202 | case TopicClient.ClientState.Disconnected: 203 | OnDisconnected(); 204 | break; 205 | default: 206 | break; 207 | } 208 | } 209 | 210 | void OnConnected() 211 | { 212 | if (m_bDisconnected) 213 | { 214 | // restore our subscriptions.. 215 | foreach (var path in m_SubscriberMap) 216 | { 217 | if (! TopicClient.IsSubscribed( path.Key + "blackboard", OnBlackBoardEvent ) ) 218 | TopicClient.Subscribe( path.Key + "blackboard", OnBlackBoardEvent ); 219 | 220 | Dictionary> types = path.Value; 221 | foreach( var kv in types ) 222 | { 223 | string type = kv.Key; 224 | 225 | Dictionary subscribe = new Dictionary(); 226 | subscribe["event"] = "subscribe_to_type"; 227 | subscribe["type"] = type; 228 | subscribe["event_mask"] = (int)ThingEventType.TE_ALL; // we want all events, we will filter those events on this side 229 | 230 | TopicClient.Publish( path.Key + "blackboard", Json.Serialize(subscribe)); 231 | Log.Status("BlackBoard", "Subscription to type {0} restored.", type ); 232 | } 233 | } 234 | m_bDisconnected = false; 235 | } 236 | } 237 | void OnDisconnected() 238 | { 239 | m_bDisconnected = true; 240 | } 241 | 242 | void OnBlackBoardEvent( TopicClient.Payload a_Payload ) 243 | { 244 | IDictionary json = a_Payload.ParseJson(); 245 | 246 | bool bFailed = false; 247 | string event_name = json["event"] as string; 248 | string type = json["type"] as string; 249 | 250 | ThingEvent te = new ThingEvent(); 251 | te.m_EventType = ThingEventType.TE_NONE; 252 | te.m_Event = json; 253 | 254 | if ( event_name == "add_object" ) 255 | { 256 | te.m_EventType = ThingEventType.TE_ADDED; 257 | 258 | // TODO: Create correct type based on type name, fall back to just making an IThing object 259 | te.m_Thing = new IThing(); 260 | try { 261 | te.m_Thing.Deserialize( json["thing"] as IDictionary ); 262 | te.m_Thing.Origin = a_Payload.Origin; 263 | #if ENABLE_DEBUGGING 264 | Log.Debug( "BlackBoard", "Adding object {0} from {1}", te.m_Thing.GUID, te.m_Thing.Origin ); 265 | #endif 266 | if ( json.Contains( "parent" ) ) 267 | te.m_Thing.ParentGUID = json["parent"] as string; 268 | m_ThingMap[ te.m_Thing.GUID ] = te.m_Thing; 269 | } 270 | catch( Exception e ) 271 | { 272 | Log.Error( "BlackBoard", "Failed to deserialize object: {0}, stack: {1}", e.Message, e.StackTrace ); 273 | bFailed = true; 274 | } 275 | } 276 | else if ( event_name == "remove_object" ) 277 | { 278 | te.m_EventType = ThingEventType.TE_REMOVED; 279 | 280 | string guid = json["thing_guid"] as string; 281 | if ( m_ThingMap.TryGetValue( guid, out te.m_Thing ) ) 282 | { 283 | #if ENABLE_DEBUGGING 284 | Log.Debug( "BlackBoard", "Removing object {0}", guid ); 285 | #endif 286 | m_ThingMap.Remove( guid ); 287 | } 288 | #if ENABLE_DEBUGGING 289 | else 290 | Log.Debug( "BlackBoard", "Failed to find object by guid {0}.", guid ); 291 | #endif 292 | } 293 | else if ( event_name == "set_object_state" ) 294 | { 295 | string guid = json["thing_guid"] as string; 296 | if ( m_ThingMap.TryGetValue( guid, out te.m_Thing ) ) 297 | { 298 | string state = json["state"] as string; 299 | #if ENABLE_DEBUGGING 300 | Log.Debug( "BlackBoard", "Updating object {0} state to {1}", guid, state ); 301 | #endif 302 | te.m_Thing.State = state; 303 | } 304 | #if ENABLE_DEBUGGING 305 | else 306 | Log.Debug( "BlackBoard", "Failed to find object by guid {0}.", guid ); 307 | #endif 308 | } 309 | else if ( event_name == "set_object_importance" ) 310 | { 311 | string guid = json["thing_guid"] as string; 312 | if ( m_ThingMap.TryGetValue( guid, out te.m_Thing ) ) 313 | { 314 | float fImportance = (float)json["importance"]; 315 | #if ENABLE_DEBUGGING 316 | Log.Debug( "BlackBoard", "Updating object {0} importance to {1}", guid, fImportance ); 317 | #endif 318 | te.m_Thing.Importance = fImportance; 319 | } 320 | #if ENABLE_DEBUGGING 321 | else 322 | Log.Debug( "BlackBoard", "Failed to find object by guid {0}.", guid ); 323 | #endif 324 | } 325 | 326 | // if we failed, send the message back with a different event 327 | if ( bFailed ) 328 | { 329 | json["failed_event"] = event_name; 330 | json["event"] = "error"; 331 | 332 | TopicClient.Publish( a_Payload.Origin, Json.Serialize( json ) ); 333 | } 334 | else if ( te.m_EventType != ThingEventType.TE_NONE ) 335 | { 336 | foreach( var path in m_SubscriberMap ) 337 | { 338 | List subs = null; 339 | if ( path.Value.TryGetValue( type, out subs ) ) 340 | { 341 | for(int i=0;i 34 | /// This client allows a user to connect to the TopicManager embedded in SELF. 35 | /// 36 | public class TopicClient 37 | { 38 | #region Public Types 39 | public enum ClientState { 40 | Inactive, 41 | Connecting, 42 | Connected, 43 | Closing, 44 | Disconnected 45 | }; 46 | public struct SubInfo 47 | { 48 | public bool Subscribed { get; set; } // true if subscribing, false if un-subscribing 49 | public string Origin { get; set; } // who is the subscriber 50 | public string Topic { get; set; } // topic they are subscribing too 51 | }; 52 | public delegate void OnSubscriber(SubInfo a_Info); 53 | 54 | public class Payload 55 | { 56 | public string Topic { get; set; } // the topic of this payload 57 | public string Origin { get; set; } // who sent this payload 58 | public byte [] Data { get; set; } // the payload data 59 | public string Type { get; set; } // the type of data 60 | public bool Persisted { get; set; } // true if this was a persisted payload 61 | public string RemoteOrigin { get; set; } // this is set to the origin that published this payload 62 | 63 | public override string ToString() 64 | { 65 | return string.Format("[Payload: Topic={0}, Origin={1}, Data Length={2}, Type={3}, Persisted={4}, RemoteOrigin={5}]", 66 | Topic, Origin, ((Data != null)? Data.Length.ToString() : "-"), Type, Persisted, RemoteOrigin); 67 | } 68 | 69 | public IDictionary ParseJson() 70 | { 71 | if (m_ParsedJson == null && Data != null) 72 | { 73 | try 74 | { 75 | m_ParsedJson = Json.Deserialize(Encoding.UTF8.GetString(Data)) as IDictionary; 76 | } 77 | catch (Exception ex) 78 | { 79 | Log.Error("Exception", "Payload can't converted to JSON. Original text: {0}", Encoding.UTF8.GetString(Data)); 80 | } 81 | } 82 | 83 | return m_ParsedJson; 84 | } 85 | 86 | private IDictionary m_ParsedJson = null; 87 | }; 88 | public delegate void OnPayload(Payload a_Payload); 89 | 90 | public class TopicInfo 91 | { 92 | public string TopicId { get; set; } // the ID of this topic 93 | public string Type { get; set; } // type of topic 94 | 95 | public override string ToString() 96 | { 97 | return string.Format("[TopicInfo: TopicId={0}, Type={1}]", TopicId, Type); 98 | } 99 | }; 100 | 101 | public class QueryInfo 102 | { 103 | public bool bSuccess { get; set; } 104 | public string Path { get; set; } 105 | public string SelfId { get; set; } 106 | public string ParentId { get; set; } 107 | public string Name { get; set; } 108 | public string Type { get; set; } 109 | public string Version { get; set; } 110 | public string[] Children { get; set; } 111 | public TopicInfo[] Topics { get; set; } 112 | 113 | public override string ToString() 114 | { 115 | return string.Format("[QueryInfo: bSuccess={0}, Path={1}, SelfId={2}, ParentId={3}, Name={4}, Type={5}, Version={6}, \nChildren={7}, \nTopics={8}]", 116 | bSuccess, 117 | Path, 118 | SelfId, 119 | ParentId, 120 | Name, 121 | Type, 122 | Version, 123 | (Children != null)? string.Join(",", Children) : "-" , 124 | (Topics != null)? string.Join(", \n", Array.ConvertAll(Topics, Convert.ToString)) : "-"); 125 | } 126 | }; 127 | public delegate void OnQueryResponse(QueryInfo a_Info); 128 | public delegate void MessageHandler( IDictionary a_Message ); 129 | public delegate void OnStateStateChanged(ClientState a_State); 130 | #endregion 131 | 132 | #region Private Types 133 | private class Subscription 134 | { 135 | public Subscription() 136 | { } 137 | public Subscription( string a_Path, OnPayload a_Callback ) 138 | { 139 | m_Path = a_Path; 140 | m_Callback = a_Callback; 141 | } 142 | 143 | public string m_Path; 144 | public OnPayload m_Callback; 145 | }; 146 | #endregion 147 | 148 | #region Constants 149 | const float RECONNECT_INTERVAL = 5.0f; 150 | #endregion 151 | 152 | #region Private Data 153 | int m_ReconnectRoutine = -1; 154 | string m_Host = null; 155 | string m_SelfId = null; 156 | string m_Token = null; 157 | bool m_bAuthenticated = false; 158 | string m_ParentId = null; 159 | string m_ParentInstance = null; 160 | WebSocket m_Socket = null; 161 | ClientState m_eState = ClientState.Inactive; 162 | List 163 | m_SendQueue = new List(); 164 | int m_ReqId = 1; 165 | Dictionary 166 | m_QueryRequestMap = new Dictionary(); 167 | Dictionary 168 | m_MessageHandlers = new Dictionary(); 169 | Dictionary > 170 | m_SubscriptionMap = new Dictionary>(); 171 | 172 | int m_PublishRoutine = -1; 173 | List m_PublishList = new List(); 174 | int m_MessageRoutine = -1; 175 | List m_Incoming = new List(); 176 | SelfLogin m_Login = null; 177 | List m_StateList = new List(); 178 | int m_StateChangeRoutine = -1; 179 | #endregion 180 | 181 | #region Public Interface 182 | public bool IsActive { get { return m_eState != ClientState.Inactive && m_eState != ClientState.Disconnected; } } 183 | public ClientState State { get { return m_eState; } private set{ m_eState = value; lock (m_StateList) m_StateList.Add(value); } } 184 | public string SelfId { get { return m_SelfId; } } 185 | public string Token { get { return m_Token; } } 186 | public bool Authenticated { get { return m_bAuthenticated; } } 187 | 188 | public OnStateStateChanged StateChangedEvent {get;set;} 189 | 190 | public TopicClient() 191 | { 192 | m_MessageHandlers["publish"] = HandlePublish; 193 | m_MessageHandlers["subscribe_failed"] = HandleSubFailed; 194 | m_MessageHandlers["no_route"] = HandleNoRoute; 195 | m_MessageHandlers["query"] = HandleQuery; 196 | m_MessageHandlers["query_response"] = HandleQueryResponse; 197 | } 198 | 199 | public bool Connect( string a_Host = null, 200 | string a_selfId = null, 201 | string a_Token = null, 202 | string a_ParentInstance = null) 203 | { 204 | if ( m_eState != ClientState.Inactive 205 | && m_eState != ClientState.Disconnected ) 206 | { 207 | Log.Error( "TopicClient", "Client is wrong state for Connect()." ); 208 | return false; 209 | } 210 | 211 | if (string.IsNullOrEmpty(a_Host)) 212 | a_Host = Config.Instance.GetVariableValue("Host"); 213 | if (string.IsNullOrEmpty(a_Host)) 214 | a_Host = "ws://127.0.0.1:9443"; 215 | if (string.IsNullOrEmpty(a_Token)) 216 | a_Token = Config.Instance.GetVariableValue("BearerToken"); 217 | if (string.IsNullOrEmpty(a_selfId)) 218 | a_selfId = Config.Instance.GetVariableValue("SelfID"); 219 | if (string.IsNullOrEmpty(a_ParentInstance)) 220 | a_ParentInstance = Config.Instance.GetVariableValue("ParentInstance"); 221 | 222 | if (! a_Host.StartsWith( "ws://", StringComparison.CurrentCultureIgnoreCase ) 223 | && a_Host.StartsWith( "wss://", StringComparison.CurrentCultureIgnoreCase ) ) 224 | { 225 | Log.Error( "TopicClient", "Host doesn't begin with ws:// or wss://" ); 226 | return false; 227 | } 228 | 229 | State = ClientState.Connecting; 230 | m_Host = a_Host; 231 | m_SelfId = a_selfId; 232 | m_Token = a_Token; 233 | m_ParentInstance = a_ParentInstance; 234 | m_bAuthenticated = false; 235 | 236 | if (string.IsNullOrEmpty(m_SelfId)) 237 | { 238 | m_Login = new SelfLogin(); 239 | m_Login.OnRegisteredEvent += OnRegisteredEmbodiment; 240 | m_Login.OnErrorEvent += OnRegisterError; 241 | 242 | Log.Status( "TopicClient", "Registering embodiment." ); 243 | if (! m_Login.RegisterEmbodiment() ) 244 | OnRegisterError(); 245 | 246 | return true; 247 | } 248 | 249 | DoConnect(); 250 | 251 | return true; 252 | } 253 | 254 | private void DoConnect() 255 | { 256 | m_Socket = new WebSocket( new Uri( new Uri( m_Host ), "/stream").AbsoluteUri ); 257 | m_Socket.Headers = new Dictionary(); 258 | m_Socket.Headers.Add("selfId", m_SelfId ); 259 | m_Socket.Headers.Add("token", m_Token ); 260 | m_Socket.Headers.Add ("parentInstance", m_ParentInstance); 261 | 262 | m_Socket.OnMessage += OnSocketMessage; 263 | m_Socket.OnOpen += OnSocketOpen; 264 | m_Socket.OnError += OnSocketError; 265 | m_Socket.OnClose += OnSocketClosed; 266 | 267 | m_Socket.ConnectAsync(); 268 | 269 | if ( m_ReconnectRoutine < 0 ) 270 | m_ReconnectRoutine = Runnable.Run( OnReconnect() ); // start the OnReconnect co-routine to keep us connected 271 | if ( m_PublishRoutine < 0 ) 272 | m_PublishRoutine = Runnable.Run( OnPublish() ); // start our main thread routine for publishing incoming data on the right thread 273 | if ( m_MessageRoutine < 0 ) 274 | m_MessageRoutine = Runnable.Run( OnMessage() ); 275 | if (m_StateChangeRoutine < 0) 276 | m_StateChangeRoutine = Runnable.Run( OnStateChange() ); 277 | } 278 | 279 | private void OnRegisteredEmbodiment( string a_SelfId, string a_Token ) 280 | { 281 | m_SelfId = a_SelfId; 282 | m_Token = a_Token; 283 | m_Login = null; 284 | 285 | DoConnect(); 286 | } 287 | private void OnRegisterError() 288 | { 289 | Log.Error( "TopicClient", "Failed to register embodiment." ); 290 | m_Login = null; 291 | 292 | DoConnect(); 293 | } 294 | 295 | public void Disconnect() 296 | { 297 | if ( m_ReconnectRoutine >= 0 ) 298 | { 299 | Runnable.Stop( m_ReconnectRoutine ); 300 | m_ReconnectRoutine = -1; 301 | } 302 | if ( m_PublishRoutine >= 0 ) 303 | { 304 | Runnable.Stop( m_PublishRoutine ); 305 | m_PublishRoutine = -1; 306 | } 307 | if ( m_MessageRoutine >= 0 ) 308 | { 309 | Runnable.Stop( m_MessageRoutine ); 310 | m_MessageRoutine = -1; 311 | } 312 | 313 | if (m_StateChangeRoutine >= 0) 314 | { 315 | Runnable.Stop(m_StateChangeRoutine); 316 | m_StateChangeRoutine = -1; 317 | } 318 | 319 | if ( m_Socket != null ) 320 | { 321 | State = ClientState.Closing; 322 | m_Socket.CloseAsync(); 323 | m_Socket = null; 324 | } 325 | } 326 | 327 | //! Publish data for a remote target specified by the provided path. 328 | public void Publish( 329 | string a_Path, 330 | string a_Data, 331 | bool a_bPersisted = false) 332 | { 333 | Dictionary publish = new Dictionary(); 334 | publish["targets"] = new string[] { a_Path }; 335 | publish["msg"] = "publish_at"; 336 | publish["data"] = a_Data; 337 | publish["binary"] = false; 338 | publish["persisted"] = a_bPersisted; 339 | 340 | SendMessage( publish ); 341 | } 342 | 343 | //! Publish binary data to the remote target by the specified path. 344 | public void Publish( 345 | string a_Path, 346 | byte [] a_Data, 347 | bool a_bPersisted = false ) 348 | { 349 | Dictionary publish = new Dictionary(); 350 | publish["targets"] = new string[] { a_Path }; 351 | publish["msg"] = "publish_at"; 352 | publish["data"] = a_Data; 353 | publish["binary"] = true; 354 | publish["persisted"] = a_bPersisted; 355 | 356 | SendMessage( publish ); 357 | } 358 | 359 | //! This queries a node specified by the given path. 360 | public void Query(string a_Path, //! the path to the node, we will invoke the callback with a QueryInfo structure 361 | OnQueryResponse a_Callback, float a_fTimeout = 10.0f ) 362 | { 363 | string reqId = string.Format( "{0}", m_ReqId++ ); 364 | m_QueryRequestMap[ reqId ] = a_Callback; 365 | 366 | Dictionary query = new Dictionary(); 367 | query["targets"] = new string[] { a_Path }; 368 | query["msg"] = "query"; 369 | query["request"] = reqId; 370 | 371 | SendMessage( query ); 372 | 373 | Runnable.Run( QueryTimeout( reqId, a_fTimeout ) ); 374 | } 375 | 376 | public bool IsSubscribed( string a_Path, OnPayload a_Callback = null ) 377 | { 378 | if ( m_SubscriptionMap.ContainsKey( a_Path ) ) 379 | { 380 | if ( a_Callback != null ) 381 | { 382 | foreach( var cb in m_SubscriptionMap[ a_Path ] ) 383 | if ( cb.m_Callback == a_Callback ) 384 | return true; 385 | return false; 386 | } 387 | 388 | return true; 389 | } 390 | 391 | return false; 392 | } 393 | 394 | //! Subscribe to the given topic specified by the provided path. 395 | public void Subscribe( string a_Path, //! The topic to subscribe, ".." moves up to a parent self 396 | OnPayload a_Callback) 397 | { 398 | string path = a_Path; 399 | if (! m_SubscriptionMap.ContainsKey( path ) ) 400 | { 401 | m_SubscriptionMap[ path ] = new List(); 402 | 403 | Dictionary sub = new Dictionary(); 404 | sub["targets"] = new string[] { path }; 405 | sub["msg"] = "subscribe"; 406 | 407 | SendMessage( sub ); 408 | } 409 | 410 | m_SubscriptionMap[ path ].Add( new Subscription( path, a_Callback ) ); 411 | } 412 | 413 | //! Unsubscribe from the given topic 414 | public bool Unsubscribe( string a_Path, 415 | OnPayload a_Callback = null) 416 | { 417 | string path = a_Path; 418 | 419 | bool bSuccess = false; 420 | 421 | List subs = null; 422 | if ( m_SubscriptionMap.TryGetValue( path, out subs ) ) 423 | { 424 | for(int i=0;i unsub = new Dictionary(); 441 | unsub["targets"] = new string[] { path }; 442 | unsub["msg"] = "unsubscribe"; 443 | 444 | SendMessage( unsub ); 445 | } 446 | 447 | return bSuccess; 448 | } 449 | 450 | //! Helper function for appending a topic onto a origin 451 | public static string GetPath(string a_Origin, string a_Topic) 452 | { 453 | string sPath; 454 | int nLastDot = a_Origin.LastIndexOf( "/." ); 455 | if (nLastDot > 0 ) 456 | sPath = a_Origin.Substring( 0, nLastDot + 1 ) + a_Topic; 457 | else 458 | sPath = a_Topic; 459 | 460 | return sPath; 461 | } 462 | #endregion 463 | 464 | #region WebSocket Callbacks 465 | void OnSocketMessage(object sender, MessageEventArgs message) 466 | { 467 | IDictionary json = null; 468 | if ( message.IsBinary ) 469 | { 470 | // the first part up to the first /0 character will be the json.. 471 | byte [] data = message.RawData; 472 | 473 | int headerSize = 0; 474 | while( data[headerSize] != 0 ) 475 | headerSize += 1; 476 | 477 | byte [] headerData = new byte[ headerSize - 1 ]; 478 | Buffer.BlockCopy( data, 0, headerData, 0, headerSize - 1 ); 479 | byte [] payload = new byte[ data.Length - headerSize - 1 ]; 480 | Buffer.BlockCopy( data, headerSize + 1, payload, 0, payload.Length ); 481 | 482 | json = Json.Deserialize( Encoding.UTF8.GetString(headerData) ) as IDictionary; 483 | json["data"] = payload; 484 | } 485 | else if ( message.IsText ) 486 | json = Json.Deserialize( message.Data ) as IDictionary; 487 | 488 | lock( m_Incoming ) 489 | m_Incoming.Add( json ); 490 | } 491 | 492 | void OnSocketOpen(object sender, EventArgs e) 493 | { 494 | Log.Status("TopicClient", "Connected to {0}", m_Host ); 495 | State = ClientState.Connected; 496 | 497 | for(int i=0;i 0 ) 549 | { 550 | for(int i=0;i subs = null; 555 | if ( m_SubscriptionMap.TryGetValue( payload.Origin, out subs ) ) 556 | { 557 | for(int j=0;j subs = null; 726 | if ( m_SubscriptionMap.TryGetValue( path, out subs ) ) 727 | { 728 | for(int i=0;i resp = new Dictionary(); 759 | resp["targets"] = new string[] { OriginToPath( (string)a_Message["origin"] ) }; 760 | resp["msg"] = "query_response"; 761 | resp["request"] = (string)a_Message["request"]; 762 | resp["selfId"] = m_SelfId; 763 | resp["name"] = "TopicClient"; 764 | resp["type"] = "Unity"; 765 | resp["version"] = Config.Instance.GetVariableValue( "version" ); 766 | resp["parentId"] = m_ParentId; 767 | 768 | SendMessage( resp ); 769 | } 770 | 771 | //! We are a client, not a manager, so all our origin's should come through our connection which we consider our parent 772 | string OriginToPath( string a_Origin ) 773 | { 774 | if ( a_Origin.StartsWith( "../" ) ) 775 | return a_Origin.Substring( 3 ); // remove the ../ from the origin... 776 | 777 | Log.Warning( "TopicClient", "Unexpected origin {0}", a_Origin ); 778 | return a_Origin; 779 | } 780 | 781 | void HandleQueryResponse(IDictionary a_Message) 782 | { 783 | Log.Debug( "TopicClient", "HandleQueryResponse()" ); 784 | 785 | QueryInfo info = new QueryInfo(); 786 | info.bSuccess = true; 787 | info.Path = OriginToPath( (string)a_Message["origin"] ); 788 | info.SelfId = (string)a_Message["selfId"]; 789 | if ( a_Message.Contains( "name" ) ) 790 | { 791 | info.Name = (string)a_Message["name"]; 792 | info.Type = (string)a_Message["type"]; 793 | info.Version = (string)a_Message["version"]; 794 | } 795 | if ( a_Message.Contains( "parentId" ) ) 796 | info.ParentId = (string)a_Message["parentId"]; 797 | 798 | if ( a_Message.Contains( "children" ) ) 799 | { 800 | IList children = (IList)a_Message["children"]; 801 | info.Children = new string[ children.Count ]; 802 | for(int i=0;i 834 | /// This class is used for query Intu instances via TopicClient 835 | /// 836 | public class TopicClientData : Widget.Data 837 | { 838 | /// 839 | /// Initializes a new instance of the class. 840 | /// 841 | public TopicClientData() 842 | {} 843 | 844 | /// 845 | /// Initializes a new instance of the class. 846 | /// 847 | /// A topic client. 848 | public TopicClientData(TopicClient a_TopicClient) 849 | { 850 | TopicClient = a_TopicClient; 851 | } 852 | 853 | /// 854 | /// Should return a print friendly name for this data. 855 | /// 856 | /// Returns a user-friendly name for this type of data. 857 | public override string GetName() 858 | { 859 | return "TopicClient"; 860 | } 861 | 862 | /// 863 | /// Gets or sets the topic client. 864 | /// 865 | /// The topic client. 866 | public TopicClient TopicClient { get; set; } 867 | } 868 | } 869 | --------------------------------------------------------------------------------