feat: add local cache for activity session analytics (#3878)
This commit is contained in:
parent
85ac0317b8
commit
6bf699c190
5 changed files with 113 additions and 4 deletions
|
|
@ -8,6 +8,7 @@ import 'package:matrix/matrix.dart';
|
|||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_role_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_roles_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_session_analytics_repo.dart';
|
||||
import 'package:fluffychat/pangea/activity_summary/activity_summary_analytics_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_summary/activity_summary_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_summary/activity_summary_request_model.dart';
|
||||
|
|
@ -19,6 +20,7 @@ import 'package:fluffychat/pangea/course_plans/course_plan_room_extension.dart';
|
|||
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../activity_summary/activity_summary_repo.dart';
|
||||
|
||||
extension ActivityRoomExtension on Room {
|
||||
|
|
@ -326,4 +328,41 @@ extension ActivityRoomExtension on Room {
|
|||
roomType?.startsWith(PangeaRoomTypes.activitySession) == true;
|
||||
|
||||
bool get isActivitySession => isActivityRoomType || activityPlan != null;
|
||||
|
||||
Future<ActivitySummaryAnalyticsModel> getActivityAnalytics() async {
|
||||
// wait for local storage box to init in getAnalytics initialization
|
||||
if (!MatrixState.pangeaController.getAnalytics.initCompleter.isCompleted) {
|
||||
await MatrixState.pangeaController.getAnalytics.initCompleter.future;
|
||||
}
|
||||
|
||||
final cached = ActivitySessionAnalyticsRepo.get(id);
|
||||
final analytics = cached?.analytics ?? ActivitySummaryAnalyticsModel();
|
||||
|
||||
final eventsSince = await getAllEvents(since: cached?.lastEventId);
|
||||
final timeline = this.timeline ?? await getTimeline();
|
||||
final messageEvents = getPangeaMessageEvents(
|
||||
eventsSince,
|
||||
timeline,
|
||||
msgtypes: [
|
||||
MessageTypes.Text,
|
||||
MessageTypes.Audio,
|
||||
],
|
||||
);
|
||||
|
||||
if (messageEvents.isEmpty) {
|
||||
return analytics;
|
||||
}
|
||||
|
||||
for (final pangeaMessage in messageEvents) {
|
||||
analytics.addConstructs(pangeaMessage);
|
||||
}
|
||||
|
||||
await ActivitySessionAnalyticsRepo.set(
|
||||
id,
|
||||
messageEvents.last.eventId,
|
||||
analytics,
|
||||
);
|
||||
|
||||
return analytics;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
import 'package:get_storage/get_storage.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/activity_summary/activity_summary_analytics_model.dart';
|
||||
|
||||
class CachedActivityAnalytics {
|
||||
final DateTime timestamp;
|
||||
final String lastEventId;
|
||||
final ActivitySummaryAnalyticsModel analytics;
|
||||
|
||||
CachedActivityAnalytics(
|
||||
this.timestamp,
|
||||
this.lastEventId,
|
||||
this.analytics,
|
||||
);
|
||||
}
|
||||
|
||||
class ActivitySessionAnalyticsRepo {
|
||||
static final GetStorage _activityAnalyticsStorage =
|
||||
GetStorage('activity_analytics_storage');
|
||||
|
||||
static Duration cacheDuration = const Duration(minutes: 30);
|
||||
|
||||
static CachedActivityAnalytics? get(String roomId) {
|
||||
final json = _activityAnalyticsStorage.read(roomId);
|
||||
if (json == null) return null;
|
||||
|
||||
try {
|
||||
final timestamp = DateTime.parse(json['timestamp'] as String);
|
||||
if (DateTime.now().difference(timestamp) > cacheDuration) {
|
||||
_activityAnalyticsStorage.remove(roomId);
|
||||
return null;
|
||||
}
|
||||
|
||||
final lastEventId = json['last_event_id'] as String;
|
||||
final analyticsJson = json['analytics'] as Map<String, dynamic>;
|
||||
final analytics = ActivitySummaryAnalyticsModel.fromJson(analyticsJson);
|
||||
return CachedActivityAnalytics(timestamp, lastEventId, analytics);
|
||||
} catch (e) {
|
||||
_activityAnalyticsStorage.remove(roomId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> set(
|
||||
String roomId,
|
||||
String lastEventId,
|
||||
ActivitySummaryAnalyticsModel analytics,
|
||||
) async {
|
||||
final json = {
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
'last_event_id': lastEventId,
|
||||
'analytics': analytics.toJson(),
|
||||
};
|
||||
await _activityAnalyticsStorage.write(roomId, json);
|
||||
}
|
||||
}
|
||||
|
|
@ -76,6 +76,7 @@ class GetAnalyticsController extends BaseController {
|
|||
|
||||
try {
|
||||
await GetStorage.init("analytics_storage");
|
||||
await GetStorage.init("activity_analytics_storage");
|
||||
_client.updateAnalyticsRoomJoinRules();
|
||||
_client.addAnalyticsRoomsToSpaces();
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ class PangeaController {
|
|||
'vocab_storage',
|
||||
'onboarding_storage',
|
||||
'analytics_request_storage',
|
||||
'activity_analytics_storage',
|
||||
];
|
||||
|
||||
Future<void> clearCache({List<String> exclude = const []}) async {
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ extension EventsRoomExtension on Room {
|
|||
return resp.chunk.map((e) => Event.fromMatrixEvent(e, this)).toList();
|
||||
}
|
||||
|
||||
Future<List<Event>> getAllEvents() async {
|
||||
Future<List<Event>> getAllEvents({String? since}) async {
|
||||
final GetRoomEventsResponse initalResp =
|
||||
await client.getRoomEvents(id, Direction.b);
|
||||
|
||||
|
|
@ -340,9 +340,20 @@ extension EventsRoomExtension on Room {
|
|||
resp.end != nextStartToken
|
||||
? nextStartToken = resp.end
|
||||
: nextStartToken = null;
|
||||
|
||||
if (since != null && chunkMessages.any((e) => e.eventId == since)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
allMatrixEvents = allMatrixEvents.reversed.toList();
|
||||
if (since != null) {
|
||||
final index = allMatrixEvents.indexWhere((e) => e.eventId == since);
|
||||
if (index != -1) {
|
||||
allMatrixEvents = allMatrixEvents.sublist(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
final List<Event> allEvents = allMatrixEvents
|
||||
.map((MatrixEvent message) => Event.fromMatrixEvent(message, this))
|
||||
.toList();
|
||||
|
|
@ -352,13 +363,14 @@ extension EventsRoomExtension on Room {
|
|||
|
||||
List<PangeaMessageEvent> getPangeaMessageEvents(
|
||||
List<Event> events,
|
||||
Timeline timeline,
|
||||
) {
|
||||
Timeline timeline, {
|
||||
List<String> msgtypes = const [MessageTypes.Text],
|
||||
}) {
|
||||
final List<PangeaMessageEvent> allPangeaMessages = events
|
||||
.where(
|
||||
(Event event) =>
|
||||
event.type == EventTypes.Message &&
|
||||
event.content['msgtype'] == MessageTypes.Text,
|
||||
msgtypes.contains(event.content['msgtype']),
|
||||
)
|
||||
.map(
|
||||
(Event message) => PangeaMessageEvent(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue