near final
This commit is contained in:
224
lib/backend/modules/commands.dart
Normal file
224
lib/backend/modules/commands.dart
Normal file
@@ -0,0 +1,224 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:bus_infotainment/auth/api_constants.dart';
|
||||
import 'package:bus_infotainment/backend/live_information.dart';
|
||||
import 'package:bus_infotainment/tfl_datasets.dart';
|
||||
import 'package:bus_infotainment/utils/audio%20wrapper.dart';
|
||||
import 'package:bus_infotainment/utils/delegates.dart';
|
||||
import 'package:appwrite/appwrite.dart' as appwrite;
|
||||
import 'package:appwrite/models.dart' as models;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../auth/auth_api.dart';
|
||||
import 'info_module.dart';
|
||||
|
||||
class CommandModule extends InfoModule {
|
||||
|
||||
final String sessionID;
|
||||
late final String clientID;
|
||||
|
||||
List<CommandInfo> _commandHistory = [];
|
||||
get commandHistory => _commandHistory;
|
||||
EventDelegate<CommandInfo> onCommandReceived = EventDelegate();
|
||||
|
||||
CommandModule(this.sessionID){
|
||||
// generate a random client ID
|
||||
var uuid = Uuid();
|
||||
|
||||
clientID = uuid.v4();
|
||||
|
||||
if (liveInformation.auth.isAuthenticated()){
|
||||
print("Auth is authenticated");
|
||||
_setupListener();
|
||||
} else {
|
||||
print("Auth is not authenticated");
|
||||
liveInformation.auth.onLogin.addListener((value) {
|
||||
_setupListener();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Will execute the command an event which is triggered when a response is received
|
||||
Future<EventDelegate> executeCommand(String command) async {
|
||||
EventDelegate<String> delegate = EventDelegate();
|
||||
|
||||
final client = liveInformation.auth.client;
|
||||
|
||||
final databases = appwrite.Databases(client);
|
||||
|
||||
if (liveInformation.auth.status == AuthStatus.AUTHENTICATED) {
|
||||
final document = await databases.createDocument(
|
||||
databaseId: ApiConstants.INFO_Q_DATABASE_ID,
|
||||
collectionId: ApiConstants.COMMANDS_COLLECTION_ID,
|
||||
documentId: appwrite.ID.unique(),
|
||||
data: {
|
||||
"session_id": sessionID,
|
||||
"command": command,
|
||||
"client_id": clientID,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_onCommandReceived(CommandInfo(command, clientID));
|
||||
|
||||
return delegate;
|
||||
}
|
||||
|
||||
Future<void> _onCommandReceived(CommandInfo commandInfo) async {
|
||||
|
||||
commandHistory.add(commandInfo);
|
||||
onCommandReceived.trigger(commandInfo);
|
||||
|
||||
print("Received command: ${commandInfo.command}");
|
||||
|
||||
List<String> commandParts = splitCommand(commandInfo.command);
|
||||
String command = commandParts[0];
|
||||
List<String> args = commandParts.sublist(1);
|
||||
|
||||
if (command == "Response:") {
|
||||
|
||||
}
|
||||
else if (command == "announce") {
|
||||
|
||||
final displayText = args[1];
|
||||
|
||||
if (args[0] == "manual") {
|
||||
// announce manual <DisplayText> <AudioFileName>... <ScheduledTime>
|
||||
|
||||
|
||||
List<String> audioFileNames = args.sublist(2);
|
||||
try {
|
||||
if (int.parse(audioFileNames.last) != null) {
|
||||
audioFileNames.removeLast();
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
DateTime scheduledTime = LiveInformation().syncedTimeModule.Now().add(Duration(seconds: 1));
|
||||
try {
|
||||
if (int.parse(args.last) != null) {
|
||||
scheduledTime = DateTime.fromMillisecondsSinceEpoch(int.parse(args.last));
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
liveInformation.announcementModule.queueAnnounceByAudioName(
|
||||
displayText: displayText,
|
||||
audioNames: audioFileNames,
|
||||
scheduledTime: scheduledTime,
|
||||
sendToServer: false
|
||||
);
|
||||
|
||||
}
|
||||
else if (args[0] == "info") {
|
||||
|
||||
int InfoIndex = int.parse(args[1]);
|
||||
|
||||
DateTime scheduledTime = LiveInformation().syncedTimeModule.Now();
|
||||
try {
|
||||
if (int.parse(args.last) != null) {
|
||||
scheduledTime = DateTime.fromMillisecondsSinceEpoch(int.parse(args.last));
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
liveInformation.announcementModule.queueAnnounementByInfoIndex(
|
||||
infoIndex: InfoIndex,
|
||||
scheduledTime: scheduledTime,
|
||||
sendToServer: false
|
||||
);
|
||||
}
|
||||
else if (args[0].startsWith("dest")) {
|
||||
// announce destination <RouteNumber> <RouteVariantIndex> <ScheduledTime>
|
||||
|
||||
String routeNumber = args[1];
|
||||
int routeVariantIndex = int.parse(args[2]);
|
||||
|
||||
DateTime scheduledTime = LiveInformation().syncedTimeModule.Now();
|
||||
try {
|
||||
if (int.parse(args.last) != null) {
|
||||
scheduledTime = DateTime.fromMillisecondsSinceEpoch(int.parse(args.last));
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
BusRoute route = LiveInformation().busSequences.routes[routeNumber]!;
|
||||
BusRouteVariant routeVariant = route.routeVariants.values.toList()[routeVariantIndex];
|
||||
|
||||
liveInformation.announcementModule.queueAnnouncementByRouteVariant(
|
||||
routeVariant: routeVariant,
|
||||
scheduledTime: scheduledTime,
|
||||
sendToServer: false
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if (command == "setroute") {
|
||||
// setroute <RouteNumber> <RouteVariantIndex>
|
||||
|
||||
LiveInformation liveInformation = LiveInformation();
|
||||
|
||||
String routeNumber = args[0];
|
||||
int routeVariantIndex = int.parse(args[1]);
|
||||
|
||||
BusRoute route = liveInformation.busSequences.routes[routeNumber]!;
|
||||
BusRouteVariant routeVariant = route.routeVariants.values.toList()[routeVariantIndex];
|
||||
|
||||
liveInformation.setRouteVariant_Internal(
|
||||
routeVariant
|
||||
);
|
||||
executeCommand("Response: v \"Client $clientID set its route to ($routeNumber to ${routeVariant.busStops.last.formattedStopName})\"");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
appwrite.RealtimeSubscription? _subscription;
|
||||
Future<void> _setupListener() async {
|
||||
if (_subscription != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final realtime = appwrite.Realtime(LiveInformation().auth.client);
|
||||
|
||||
_subscription = realtime.subscribe(
|
||||
['databases.${ApiConstants.INFO_Q_DATABASE_ID}.collections.${ApiConstants.COMMANDS_COLLECTION_ID}.documents']
|
||||
);
|
||||
_subscription!.stream.listen((event) {
|
||||
print(jsonEncode(event.payload));
|
||||
|
||||
// Only do something if the document was created or updated
|
||||
if (!(event.events.first.contains("create") || event.events.first.contains("update"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
final commandInfo = CommandInfo(event.payload['command'], event.payload['client_id']);
|
||||
|
||||
if (commandInfo.clientID != clientID) {
|
||||
_onCommandReceived(commandInfo);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
print("Listening for commands");
|
||||
|
||||
await Future.delayed(Duration(seconds: 90));
|
||||
|
||||
await _subscription!.close();
|
||||
_subscription = null;
|
||||
_setupListener();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CommandInfo {
|
||||
final String command;
|
||||
final String clientID;
|
||||
|
||||
CommandInfo(this.command, this.clientID);
|
||||
}
|
||||
|
||||
List<String> splitCommand(String command) {
|
||||
var regex = RegExp(r'([^\s"]+)|"([^"]*)"');
|
||||
var matches = regex.allMatches(command);
|
||||
return matches.map((match) => match.group(0)!.replaceAll('"', '')).toList();
|
||||
}
|
||||
Reference in New Issue
Block a user