to laptptop

This commit is contained in:
ImBenji
2024-02-28 04:56:50 +00:00
parent 2ef40e6b27
commit 675c42d2da
19 changed files with 1758 additions and 151 deletions

View File

@@ -2,7 +2,11 @@
// Singleton
import 'dart:async';
import 'package:appwrite/appwrite.dart' as appwrite;
import 'package:appwrite/models.dart' as models;
import 'package:bus_infotainment/audio_cache.dart';
import 'package:bus_infotainment/auth/api_constants.dart';
import 'package:bus_infotainment/auth/auth_api.dart';
import 'package:bus_infotainment/tfl_datasets.dart';
import 'package:bus_infotainment/utils/audio%20wrapper.dart';
import 'package:bus_infotainment/utils/delegates.dart';
@@ -19,7 +23,7 @@ class LiveInformation {
LiveInformation._internal();
Future<void> LoadDatasets() async {
Future<void> Initialize() async {
{
// Load the bus sequences
@@ -41,6 +45,16 @@ class LiveInformation {
print("Loaded bus sequences from assets");
}
if (auth.isAuthenticated()){
print("Auth is authenticated");
setupRealtime();
} else {
print("Auth is not authenticated");
auth.onLogin.addListener((value) {
setupRealtime();
});
}
}
refreshTimer();
@@ -54,28 +68,33 @@ class LiveInformation {
AudioWrapper audioPlayer = AudioWrapper();
AnnouncementCache announcementCache = AnnouncementCache();
List<AnnouncementQueueEntry> announcementQueue = [];
DateTime lastAnnouncement = DateTime.now();
EventDelegate<AnnouncementQueueEntry> announcementDelegate = EventDelegate();
String CurrentAnnouncement = "*** NO MESSAGE ***";
String _currentAnnouncement = "*** NO MESSAGE ***";
String get currentAnnouncement => _currentAnnouncement;
void set currentAnnouncement(String value) {
_currentAnnouncement = value;
}
void _handleAnnouncementQueue() async {
print("Handling announcement queue");
if (audioPlayer.state != AudioWrapper_State.Playing) {
if (announcementQueue.isNotEmpty) {
AnnouncementQueueEntry announcement = announcementQueue.first;
announcementDelegate.trigger(announcement);
CurrentAnnouncement = announcement.displayText;
_currentAnnouncement = announcement.displayText;
lastAnnouncement = DateTime.now();
for (AudioWrapperSource source in announcement.audioSources) {
Duration? duration = await audioPlayer.play(source);
if (source == announcement.audioSources.last) {
announcementQueue.removeAt(0);
}
await Future.delayed(duration!);
await Future.delayed(Duration(milliseconds: 150));
}
audioPlayer.stop();
announcementQueue.removeAt(0);
print("Popped announcement queue");
}
}
@@ -119,6 +138,38 @@ class LiveInformation {
void queueAnnouncement(AnnouncementQueueEntry announcement) {
announcementQueue.add(announcement);
// Make sure the timestamp of the announcement is after the last announcement
// If so, dont queue it
// If timestamp is null, then skip this check
if (announcement.timestamp != null && announcement.timestamp!.isBefore(lastAnnouncement)) {
return;
}
if (!announcement.sendToServer) {
return;
}
final databases = appwrite.Databases(auth.client);
if (announcement is ManualAnnouncementEntry) {
final document = databases.createDocument(
documentId: appwrite.ID.unique(),
databaseId: ApiConstants.INFO_Q_DATABASE_ID,
collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID,
data: {
"ManualAnnouncementIndex": manualAnnouncements.indexOf(announcement),
"SessionID": sessionID,
}
);
print("Queued manual announcement: ${announcement.shortName}");
} else if (announcement is AnnouncementQueueEntry) {
}
}
List<ManualAnnouncementEntry> manualAnnouncements = [
@@ -204,17 +255,206 @@ class LiveInformation {
),
];
AuthAPI auth = AuthAPI();
String sessionID = "65de648aa7f44684ecce";
void updateServer() async {
final databases = appwrite.Databases(auth.client);
// final document = databases.updateDocument(
// databaseId: ApiConstants.INFO_DATABASE_ID,
// collectionId: ApiConstants.INFO_COLLECTION_ID,
// documentId: documentID,
// data: {
// "Display": _currentAnnouncement,
// }
// );
print("Updated server with announcement: $_currentAnnouncement");
}
void pullServer() async {
if (auth.status == AuthStatus.UNAUTHENTICATED) {
return;
}
final databases = appwrite.Databases(auth.client);
// final document = await databases.getDocument(
// databaseId: ApiConstants.INFO_DATABASE_ID,
// collectionId: ApiConstants.INFO_COLLECTION_ID,
// documentId: documentID,
// );
// queueAnnouncement(AnnouncementQueueEntry(
// displayText: document.data['Display'],
// audioSources: [],
// sendToServer: false, // Don't send this back to the server, else we'll get an infinite loop
// ));
// print("Pulled announcement from server: ${document.data['Display']}");
}
bool purgeRunning = false;
Future<void> deleteAllManualQueueEntries() async {
if (purgeRunning) {
return;
}
purgeRunning = true;
final databases = appwrite.Databases(auth.client);
int offset = 0;
const int limit = 25; // Maximum number of documents that can be fetched at once
while (true) {
// Fetch a page of documents from the manual queue collection
print("Deleting manual queue entries");
final manual_q = await databases.listDocuments(
databaseId: ApiConstants.INFO_Q_DATABASE_ID,
collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID,
queries: [
appwrite.Query.search("SessionID", sessionID),
appwrite.Query.limit(limit),
appwrite.Query.offset(offset),
appwrite.Query.orderDesc('\$createdAt')
]
);
// If there are no documents in the fetched page, break the loop
if (manual_q.documents.isEmpty) {
break;
}
// Delete each document in the fetched page
for (models.Document doc in manual_q.documents) {
await databases.deleteDocument(
databaseId: ApiConstants.INFO_Q_DATABASE_ID,
collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID,
documentId: doc.$id,
);
}
// Go to the next page
offset += limit;
}
print("Deleted all manual queue entries");
}
void pullQueue() async {
if (auth.status == AuthStatus.UNAUTHENTICATED) {
return;
}
final databases = appwrite.Databases(auth.client);
// Pull the manual queue
final manual_q = await databases.listDocuments(
databaseId: ApiConstants.INFO_Q_DATABASE_ID,
collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID,
queries: [
appwrite.Query.search("SessionID", sessionID),
appwrite.Query.limit(25),
appwrite.Query.offset(0),
appwrite.Query.orderDesc('\$createdAt')
]
);
List<AnnouncementQueueEntry> queue = [];
for (models.Document doc in manual_q.documents) {
int index = doc.data['ManualAnnouncementIndex'];
ManualAnnouncementEntry announcement_clone = ManualAnnouncementEntry(
shortName: manualAnnouncements[index].shortName,
informationText: manualAnnouncements[index].displayText,
audioSources: manualAnnouncements[index].audioSources,
timestamp: DateTime.parse(doc.$createdAt),
sendToServer: false,
);
// sort the queue by timestamp, so the oldest announcements are at the front
queue.add(announcement_clone);
}
for (AnnouncementQueueEntry entry in queue) {
queueAnnouncement(entry);
}
}
appwrite.RealtimeSubscription? manual_q_subscription;
Future<void> setupRealtime() async {
if (manual_q_subscription != null) {
return;
}
// await deleteAllManualQueueEntries(); //todo
print("Setting up realtime");
// Websocket
appwrite.Realtime realtime = appwrite.Realtime(auth.client);
manual_q_subscription = realtime.subscribe(
['databases.${ApiConstants.INFO_Q_DATABASE_ID}.collections.${ApiConstants.MANUAL_Q_COLLECTION_ID}.documents'],
);
manual_q_subscription?.stream.listen((event) {
print("Manual queue entry added");
pullQueue();
});
print("Subscribed to servers");
await Future.delayed(Duration(seconds: 90));
manual_q_subscription?.close();
manual_q_subscription = null;
setupRealtime();
}
}
class AnnouncementQueueEntry {
final String displayText;
final List<AudioWrapperSource> audioSources;
bool sendToServer = true;
DateTime? timestamp;
AnnouncementQueueEntry({required this.displayText, required this.audioSources});
AnnouncementQueueEntry({required this.displayText, required this.audioSources, this.sendToServer = true, this.timestamp});
}
class ManualAnnouncementEntry extends AnnouncementQueueEntry {
final String shortName;
ManualAnnouncementEntry({required this.shortName, required String informationText, required List<AudioWrapperSource> audioSources}) : super(displayText: informationText, audioSources: audioSources);
ManualAnnouncementEntry({
required this.shortName,
required String informationText,
required List<AudioWrapperSource> audioSources,
DateTime? timestamp,
bool sendToServer = true,
}) : super(
displayText: informationText,
audioSources: audioSources,
sendToServer: sendToServer,
timestamp: timestamp,
);
}