import 'dart:async'; import 'dart:ffi'; import 'package:flutter/material.dart'; import 'ros.dart'; import 'request.dart'; import 'dart:math'; typedef ActionHandler = void Function(Map response); typedef UUID = List; class GoalHandle { ActionHandler onSendGoal; ActionHandler onFeedback; ActionHandler onResult; GoalHandle({ required this.onSendGoal, required this.onFeedback, required this.onResult, }); } // 每次发送goal都要构造Action class Action { Ros ros; String name; String type; // 每次发送goal时,都会生成唯一一个uuid,不能出现重复,用于后续发送cancel_goal, Map> uuids = {}; StreamSubscription? goalListener; StreamSubscription? feedbackListener; StreamSubscription? resultListener; StreamSubscription? cancelListener; GoalHandle goalHandle; Action({ required this.name, required this.ros, required this.type, required this.goalHandle, }); List generateRandomString(int length) { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; Random random = Random(); return List.generate(length, (index) { return characters[random.nextInt(characters.length)].codeUnitAt(0); }); } void _bindFeedbackAndResult(String callId) { final feedbackLis = ros.stream; feedbackLis.listen((message) { goalHandle.onFeedback(message); }); final resultReceiver = ros.stream.where((message) => message['op'] == 'action_result' && message['id'] == callId) .map((Map message) => message['result'] == null ? message['values']! : message['values']); resultListener = resultReceiver.listen((d) { goalHandle.onResult(d); resultListener!.cancel(); }); } String sendGoal(dynamic req) { final callId = ros.requestServiceCaller(name); final completer = Completer(); final uuid = generateRandomString(16); var reqObj = Request( op: 'send_action_goal', id: callId, action: req['action'], type: req['type'], args: { "goal_id" : { "uuid": uuid, }, "goal": req['args'], }, ); if (uuids.containsKey(callId)) { uuids[callId] = uuid; } else { uuids.addAll({callId: uuid}); } ros.send(reqObj); final receiver = ros.stream.where((message) { return message['id'] == callId && message['op'] != 'cancel_goal_response'; } ); goalListener = receiver.listen((d) { if (d["op"] == "action_result") { goalHandle.onResult(d); goalListener!.cancel(); } else if (d["op"] == "action_feedback") { goalHandle.onFeedback(d); } else if (d["op"] == 'send_goal_response') { completer.complete(uuids[callId]); goalHandle.onSendGoal(d); } }); return callId; } Future cancelGoal(dynamic req, String callId, ActionHandler onCancel) { final completer = Completer(); var cancelReq = Request( op: 'cancel_action_goal', id: callId, action: req['action'], ); print("cancelReq: ${cancelReq.toJson()}"); ros.send(cancelReq); final receiver = ros.stream.where( (message) => message['id'] == callId && message['op'] == 'cancel_goal_response' ); cancelListener = receiver.listen((d) { onCancel(d); completer.complete(); cancelListener!.cancel(); }); return completer.future; } }