├── 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 |
--------------------------------------------------------------------------------