Skip to content

Commit 7ea1b10

Browse files
committed
Support multiple responses
1 parent 2796a5f commit 7ea1b10

File tree

2 files changed

+74
-35
lines changed

2 files changed

+74
-35
lines changed

ipynao/nao_robot.py

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ def _create_msg(self, method_name, *args, **kwargs):
3232
# convert tuple to list to avoid empty arg values
3333
data['args'] = list(args)
3434
data['kwargs'] = kwargs
35+
data['requestID'] = self.widget.request_id
36+
self.widget.request_id += 1
3537
return data
3638

3739
def call_service(self, method_name, *args, **kwargs):
@@ -41,14 +43,19 @@ def call_service(self, method_name, *args, **kwargs):
4143
async def async_call_service(self, method_name, *args, **kwargs):
4244
data = self._create_msg(method_name, *args, **kwargs)
4345
self.widget.send(data)
46+
request_id = data['requestID']
4447

4548
try:
4649
self.output.clear_output()
4750
self.output.append_stdout('Calling service... \n')
48-
await self.widget.wait_for_change('counter', self.output)
51+
await self.widget.wait_for_change('counter', self.output, request_id)
4952
except Exception as e:
5053
return e
51-
return self.widget.response['data']
54+
55+
response = self.widget.response[request_id]['data']
56+
del self.widget.response[request_id]
57+
58+
return response
5259

5360

5461
def __getattr__(self, method_name):
@@ -69,7 +76,8 @@ class NaoRobotWidget(DOMWidget):
6976
connected = Unicode('Disconnected').tag(sync=True)
7077
status = Unicode('Not busy').tag(sync=True)
7178
counter = Integer(0).tag(sync=True)
72-
response = None
79+
response = {}
80+
request_id = 0
7381

7482

7583
def __init__(self, **kwargs):
@@ -79,24 +87,35 @@ def __init__(self, **kwargs):
7987

8088
def _handle_frontend_msg(self, model, msg, buffer):
8189
print('Received frontend msg: ', msg)
82-
self.response = msg
90+
request_id = msg['requestID']
91+
self.response[request_id] = {
92+
'isError': msg['isError'],
93+
'data': msg['data']
94+
}
8395

8496

85-
def wait_for_change(widget, value_name, output=Output()):
97+
def wait_for_change(widget, value_name, output=Output(), request_id=0):
8698
future = asyncio.Future()
87-
widget.response = None
99+
widget.response[request_id] = {
100+
'isError': False,
101+
'data': None
102+
}
88103

89104
def get_value_change(change):
90-
widget.unobserve(get_value_change, names=value_name)
91-
if (widget.response != None):
92-
if (widget.response['isError']):
93-
future.set_exception(Exception(widget.response['data']))
94-
output.append_stderr(widget.response['data'])
105+
response = widget.response[request_id]
106+
107+
if (response['data'] != None):
108+
widget.unobserve(get_value_change, names=value_name)
109+
110+
if (response['isError']):
111+
future.set_exception(Exception(response['data']))
112+
output.append_stderr(response['data'])
95113
else:
96-
future.set_result(widget.response['data'])
97-
output.append_stdout(widget.response['data'])
114+
future.set_result(response['data'])
115+
output.append_stdout(response['data'])
116+
98117
else:
99-
future.set_result(change)
118+
future.set_result(change)
100119

101120
widget.observe(get_value_change, names=value_name)
102121
return future
@@ -107,18 +126,24 @@ def connect(self, ip_address='nao.local', port='80'):
107126
data['command'] = str('connect')
108127
data['ipAddress'] = str(ip_address)
109128
data['port'] = str(port)
129+
data['requestID'] = self.request_id
110130
self.send(data)
131+
self.request_id += 1
111132

112133

113134
def disconnect(self):
114135
data = {}
115136
data['command'] = str('disconnect')
137+
data['requestID'] = self.request_id
116138
self.send(data)
139+
self.request_id += 1
117140

118141

119142
def service(self, service_name, output=Output()):
120143
data = {}
121144
data['command'] = str('createService')
122145
data['service'] = str(service_name)
146+
data['requestID'] = self.request_id
123147
self.send(data)
148+
self.request_id += 1
124149
return NaoRobotService(self, service_name, output)

src/widget.ts

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export class NaoRobotModel extends DOMWidgetModel {
6666
}
6767
}
6868

69-
async connect(ipAddress: string, port: string) {
69+
async connect(ipAddress: string, port: string, requestID: number) {
7070
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
7171

7272
this.changeStatus('Establishing connection');
@@ -104,7 +104,7 @@ export class NaoRobotModel extends DOMWidgetModel {
104104
}
105105

106106
disconnect() {
107-
if (this.qiSession) {
107+
if (this.qiSession && this.qiSession.isConnected()) {
108108
this.qiSession.disconnect();
109109
};
110110
this._services = {};
@@ -113,12 +113,13 @@ export class NaoRobotModel extends DOMWidgetModel {
113113
this.changeStatus('Unavailable');
114114
}
115115

116-
private async checkConnection() {
116+
private async checkConnection(requestID: number) {
117117
// Cannot reconnect without initial connection
118118
if (!this._ipAddress) {
119119
this.send({
120120
isError: true,
121121
data: 'Cannot connect without IP Address.',
122+
requestID: requestID
122123
});
123124
this.set('counter', this.get('counter') + 1);
124125
this.save_changes();
@@ -127,15 +128,14 @@ export class NaoRobotModel extends DOMWidgetModel {
127128

128129
// Reconnect if possible
129130
if (!this.qiSession.isConnected()) {
130-
this.set('connected', 'Disconnected');
131-
this.save_changes();
132-
await this.connect(this._ipAddress, this._port);
131+
this.disconnect();
132+
await this.connect(this._ipAddress, this._port, requestID);
133133
}
134134
return true;
135135
}
136136

137-
private async createService(serviceName: string) {
138-
const isConnected: boolean = await this.checkConnection();
137+
private async createService(serviceName: string, requestID: number) {
138+
const isConnected: boolean = await this.checkConnection(requestID);
139139
if (!isConnected) {
140140
return;
141141
}
@@ -149,11 +149,14 @@ export class NaoRobotModel extends DOMWidgetModel {
149149
this.changeStatus('Creating service ' + serviceName);
150150
const servicePromise = this.qiSession.service(serviceName);
151151

152+
// TODO: This func is not async in the kernel. To show error messages
153+
// the request ID is the next one which is used to call the service
152154
const naoService = await servicePromise
153155
.then((resolution: any) => {
154156
this.send({
155157
isError: false,
156-
data: resolution ?? true,
158+
data: true, // TODO: resolution ?? true,
159+
requestID: requestID + 1 // Note above
157160
});
158161
return resolution;
159162
})
@@ -162,6 +165,7 @@ export class NaoRobotModel extends DOMWidgetModel {
162165
this.send({
163166
isError: true,
164167
data: rejection,
168+
requestID: requestID + 1 // Note above
165169
});
166170
this.set('counter', this.get('counter') + 1);
167171
this.save_changes();
@@ -179,25 +183,23 @@ export class NaoRobotModel extends DOMWidgetModel {
179183
serviceName: string,
180184
methodName: string,
181185
args: any,
182-
_kwargs: any
186+
_kwargs: any,
187+
requestID: number = 1000
183188
) {
184-
const isConnected: boolean = await this.checkConnection();
189+
const isConnected: boolean = await this.checkConnection(requestID);
185190
if (!isConnected) {
186191
return;
187192
}
188193

189194
// Wait for service to become available
190195
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
196+
this.changeStatus('Waiting for service ' + serviceName);
191197

192198
// Timeout after ~10 seconds
193199
for (let i = 0; i < 100; i++) {
194-
// Do not wait for service if there is no connection
195-
if (!this.qiSession.isConnected()) {
196-
this.disconnect();
197-
break;
198-
}
199200
if (this._services[serviceName]) {
200201
console.log('Service available after ', i / 10.0, ' seconds.');
202+
this.changeStatus(serviceName + ' available');
201203
break;
202204
}
203205
await sleep(100);
@@ -207,7 +209,8 @@ export class NaoRobotModel extends DOMWidgetModel {
207209
this.changeStatus(serviceName + ' not available');
208210
this.send({
209211
isError: true,
210-
data: serviceName + ' not available'
212+
data: serviceName + ' not available',
213+
requestID: requestID
211214
});
212215
this.set('counter', this.get('counter') + 1);
213216
this.save_changes();
@@ -218,7 +221,8 @@ export class NaoRobotModel extends DOMWidgetModel {
218221
this.changeStatus(`${methodName} does not exist for ${serviceName}`);
219222
this.send({
220223
isError: true,
221-
data: `${methodName} does not exist for ${serviceName}`
224+
data: `${methodName} does not exist for ${serviceName}`,
225+
requestID: requestID
222226
});
223227
this.set('counter', this.get('counter') + 1);
224228
this.save_changes();
@@ -234,13 +238,15 @@ export class NaoRobotModel extends DOMWidgetModel {
234238
this.send({
235239
isError: false,
236240
data: resolution ?? true,
241+
requestID: requestID
237242
});
238243
})
239244
.catch((rejection: string) => {
240245
this.changeStatus(rejection);
241246
this.send({
242247
isError: true,
243248
data: rejection,
249+
requestID: requestID
244250
});
245251
});
246252

@@ -253,23 +259,31 @@ export class NaoRobotModel extends DOMWidgetModel {
253259

254260
switch (cmd) {
255261
case 'connect':
256-
await this.connect(commandData['ipAddress'], commandData['port']);
262+
await this.connect(
263+
commandData['ipAddress'],
264+
commandData['port'],
265+
commandData['requestID']
266+
);
257267
break;
258268

259269
case 'disconnect':
260270
this.disconnect();
261271
break;
262272

263273
case 'createService':
264-
await this.createService(commandData['service']);
274+
await this.createService(
275+
commandData['service'],
276+
commandData['requestID']
277+
);
265278
break;
266279

267280
case 'callService':
268281
await this.callService(
269282
commandData['service'],
270283
commandData['method'],
271284
commandData['args'],
272-
commandData['kwargs']
285+
commandData['kwargs'],
286+
commandData['requestID']
273287
);
274288
break;
275289
}

0 commit comments

Comments
 (0)