From 21900f115afbcadbf96eabdab99f8114e710b5b3 Mon Sep 17 00:00:00 2001 From: ggurdin <46800240+ggurdin@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:16:40 -0500 Subject: [PATCH] chore: add ttl to morph cache and new parts of speech to default morph mapping (#5629) --- lib/pangea/morphs/default_morph_mapping.dart | 3 ++ lib/pangea/morphs/morph_repo.dart | 47 ++++++++++++++++---- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/lib/pangea/morphs/default_morph_mapping.dart b/lib/pangea/morphs/default_morph_mapping.dart index fb6003db5..2c25854dd 100644 --- a/lib/pangea/morphs/default_morph_mapping.dart +++ b/lib/pangea/morphs/default_morph_mapping.dart @@ -12,11 +12,14 @@ final MorphFeaturesAndTags defaultMorphMapping = MorphFeaturesAndTags.fromJson({ "AFFIX", "AUX", "CCONJ", + "COMPN", "DET", + "IDIOM", "INTJ", "NOUN", "NUM", "PART", + "PHRASALV", "PRON", "PUNCT", "SCONJ", diff --git a/lib/pangea/morphs/morph_repo.dart b/lib/pangea/morphs/morph_repo.dart index 473582956..e05b2391b 100644 --- a/lib/pangea/morphs/morph_repo.dart +++ b/lib/pangea/morphs/morph_repo.dart @@ -22,6 +22,28 @@ class _APICallCacheItem { _APICallCacheItem(this.time, this.future); } +class _MorphRepoCacheItem { + final DateTime time; + final MorphFeaturesAndTags morphs; + + _MorphRepoCacheItem(this.time, this.morphs); + + bool get isExpired => + DateTime.now().difference(time).inMinutes > 1440; // 24 hours + + Map toJson() => { + "time": time.toIso8601String(), + "morphs": morphs.toJson(), + }; + + factory _MorphRepoCacheItem.fromJson(Map json) { + return _MorphRepoCacheItem( + DateTime.parse(json["time"]), + MorphFeaturesAndTags.fromJson(json["morphs"]), + ); + } +} + class MorphsRepo { // long-term storage of morphs static final GetStorage _morphsStorage = GetStorage('morphs_storage'); @@ -32,11 +54,8 @@ class MorphsRepo { static const int _cacheDurationMinutes = 1; static void set(String languageCode, MorphFeaturesAndTags response) { - _morphsStorage.write(languageCode, response.toJson()); - } - - static MorphFeaturesAndTags fromJson(Map json) { - return MorphFeaturesAndTags.fromJson(json); + final entry = _MorphRepoCacheItem(DateTime.now(), response); + _morphsStorage.write(languageCode, entry.toJson()); } static Future _fetch(String languageCode) async { @@ -51,7 +70,7 @@ class MorphsRepo { ); final decodedBody = jsonDecode(utf8.decode(res.bodyBytes)); - final response = MorphsRepo.fromJson(decodedBody); + final response = MorphFeaturesAndTags.fromJson(decodedBody); set(languageCode, response); @@ -81,7 +100,16 @@ class MorphsRepo { // check if we have a cached morphs for this language code final cachedJson = _morphsStorage.read(langCodeShort); if (cachedJson != null) { - return MorphsRepo.fromJson(cachedJson); + try { + final cacheItem = _MorphRepoCacheItem.fromJson(cachedJson); + if (!cacheItem.isExpired) { + return cacheItem.morphs; + } else { + _morphsStorage.remove(langCodeShort); + } + } catch (e) { + _morphsStorage.remove(langCodeShort); + } } // check if we have a cached call for this language code @@ -110,7 +138,10 @@ class MorphsRepo { MatrixState.pangeaController.userController.userL2!.langCodeShort, ); if (cachedJson != null) { - return MorphsRepo.fromJson(cachedJson); + final cacheItem = _MorphRepoCacheItem.fromJson(cachedJson); + if (!cacheItem.isExpired) { + return cacheItem.morphs; + } } return defaultMorphMapping; }