remove byType bools and replace with interface and structs for type safety
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Dan Ballard 2022-01-20 15:58:14 -05:00
parent 889d398343
commit ccdd7d0e27
4 changed files with 74 additions and 47 deletions

View File

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cwtch/config.dart'; import 'package:cwtch/config.dart';
import 'package:cwtch/cwtch/cwtch.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -61,26 +62,76 @@ Message compileOverlay(MessageMetadata metadata, String messageData) {
} }
} }
Future<Message> messageHandler(BuildContext context, String profileOnion, int conversationIdentifier, abstract class CacheHandler {
{bool byIndex = false, int? index, bool byID = false, int? id, bool byHash = false, String? hash}) { MessageInfo? lookup(MessageCache cache);
var malformedMetadata = MessageMetadata(profileOnion, conversationIdentifier, 0, DateTime.now(), "", "", "", <String, String>{}, false, true, false); Future<dynamic> fetch(Cwtch cwtch, String profileOnion, int conversationIdentifier);
if (!byIndex && !byID && !byHash) { void add(MessageCache cache, MessageInfo messageInfo, String contenthash);
EnvironmentConfig.debugLog("Error calling messageHandler: one of byIndex, byID, byHash must be set"); }
return Future.value(MalformedMessage(malformedMetadata));
} class ByIndex implements CacheHandler {
if ((byID && id == null) || (byIndex && index == null) || (byHash && hash == null)) { int index;
EnvironmentConfig.debugLog("Error calling messageHandler: byType needs corresponding value and it was not set");
return Future.value(MalformedMessage(malformedMetadata)); ByIndex(this.index);
MessageInfo? lookup(MessageCache cache) {
return cache.getByIndex(index);
} }
Future<dynamic> fetch(Cwtch cwtch, String profileOnion, int conversationIdentifier) {
return cwtch.GetMessage(profileOnion, conversationIdentifier, index);
}
void add(MessageCache cache, MessageInfo messageInfo, String contenthash) {
cache.add(messageInfo, index, contenthash);
}
}
class ById implements CacheHandler {
int id;
ById(this.id);
MessageInfo? lookup(MessageCache cache) {
return cache.getById(id);
}
Future<dynamic> fetch(Cwtch cwtch, String profileOnion, int conversationIdentifier) {
return cwtch.GetMessageByID(profileOnion, conversationIdentifier, id);
}
void add(MessageCache cache, MessageInfo messageInfo, String contenthash) {
cache.addUnindexed(messageInfo, contenthash);
}
}
class ByContentHash implements CacheHandler {
String hash;
ByContentHash(this.hash);
MessageInfo? lookup(MessageCache cache) {
return cache.getByContentHash(hash);
}
Future<dynamic> fetch(Cwtch cwtch, String profileOnion, int conversationIdentifier) {
return cwtch.GetMessageByContentHash(profileOnion, conversationIdentifier, hash);
}
void add(MessageCache cache, MessageInfo messageInfo, String contenthash) {
cache.addUnindexed(messageInfo, contenthash);
}
}
Future<Message> messageHandler(BuildContext context, String profileOnion, int conversationIdentifier, CacheHandler cacheHandler) {
var malformedMetadata = MessageMetadata(profileOnion, conversationIdentifier, 0, DateTime.now(), "", "", "", <String, String>{}, false, true, false);
// Hit cache // Hit cache
MessageInfo? messageInfo = getMessageInfoFromCache(context, profileOnion, conversationIdentifier, byIndex: byIndex, index: index, byID: byID, id: id, byHash: byHash, hash: hash); MessageInfo? messageInfo = getMessageInfoFromCache(context, profileOnion, conversationIdentifier, cacheHandler);
if (messageInfo != null) { if (messageInfo != null) {
return Future.value(compileOverlay(messageInfo.metadata, messageInfo.wrapper)); return Future.value(compileOverlay(messageInfo.metadata, messageInfo.wrapper));
} }
// Fetch and Cache // Fetch and Cache
var messageInfoFuture = fetchAndCacheMessageInfo(context, profileOnion, conversationIdentifier, byIndex: byIndex, index: index, byID: byID, id: id, byHash: byHash, hash: hash); var messageInfoFuture = fetchAndCacheMessageInfo(context, profileOnion, conversationIdentifier, cacheHandler);
return messageInfoFuture.then((MessageInfo? messageInfo) { return messageInfoFuture.then((MessageInfo? messageInfo) {
if (messageInfo != null) { if (messageInfo != null) {
return compileOverlay(messageInfo.metadata, messageInfo.wrapper); return compileOverlay(messageInfo.metadata, messageInfo.wrapper);
@ -90,20 +141,12 @@ Future<Message> messageHandler(BuildContext context, String profileOnion, int co
}); });
} }
MessageInfo? getMessageInfoFromCache(BuildContext context, String profileOnion, int conversationIdentifier, MessageInfo? getMessageInfoFromCache(BuildContext context, String profileOnion, int conversationIdentifier, CacheHandler cacheHandler) {
{bool byIndex = false, int? index, bool byID = false, int? id, bool byHash = false, String? hash}) {
// Hit cache // Hit cache
try { try {
var cache = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(conversationIdentifier)?.messageCache; var cache = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(conversationIdentifier)?.messageCache;
if (cache != null) { if (cache != null) {
MessageInfo? messageInfo = null; MessageInfo? messageInfo = cacheHandler.lookup(cache);
if (byID) {
messageInfo = cache.getById(id!);
} else if (byHash) {
messageInfo = cache.getByContentHash(hash!);
} else {
messageInfo = cache.getByIndex(index!);
}
if (messageInfo != null) { if (messageInfo != null) {
return messageInfo; return messageInfo;
} }
@ -115,19 +158,12 @@ MessageInfo? getMessageInfoFromCache(BuildContext context, String profileOnion,
return null; return null;
} }
Future<MessageInfo?> fetchAndCacheMessageInfo(BuildContext context, String profileOnion, int conversationIdentifier, Future<MessageInfo?> fetchAndCacheMessageInfo(BuildContext context, String profileOnion, int conversationIdentifier, CacheHandler cacheHandler) {
{bool byIndex = false, int? index, bool byID = false, int? id, bool byHash = false, String? hash}) {
// Load and cache // Load and cache
try { try {
Future<dynamic> rawMessageEnvelopeFuture; Future<dynamic> rawMessageEnvelopeFuture;
if (byID) { rawMessageEnvelopeFuture = cacheHandler.fetch(Provider.of<FlwtchState>(context, listen: false).cwtch, profileOnion, conversationIdentifier);
rawMessageEnvelopeFuture = Provider.of<FlwtchState>(context, listen: false).cwtch.GetMessageByID(profileOnion, conversationIdentifier, id!);
} else if (byHash) {
rawMessageEnvelopeFuture = Provider.of<FlwtchState>(context, listen: false).cwtch.GetMessageByContentHash(profileOnion, conversationIdentifier, hash!);
} else {
rawMessageEnvelopeFuture = Provider.of<FlwtchState>(context, listen: false).cwtch.GetMessage(profileOnion, conversationIdentifier, index!);
}
return rawMessageEnvelopeFuture.then((dynamic rawMessageEnvelope) { return rawMessageEnvelopeFuture.then((dynamic rawMessageEnvelope) {
try { try {
@ -144,11 +180,11 @@ Future<MessageInfo?> fetchAndCacheMessageInfo(BuildContext context, String profi
if (messageWrapper['Message'] == null || messageWrapper['Message'] == '' || messageWrapper['Message'] == '{}') { if (messageWrapper['Message'] == null || messageWrapper['Message'] == '' || messageWrapper['Message'] == '{}') {
return Future.delayed(Duration(seconds: 2), () { return Future.delayed(Duration(seconds: 2), () {
print("Tail recursive call to messageHandler called. This should be a rare event. If you see multiples of this log over a short period of time please log it as a bug."); print("Tail recursive call to messageHandler called. This should be a rare event. If you see multiples of this log over a short period of time please log it as a bug.");
return fetchAndCacheMessageInfo(context, profileOnion, conversationIdentifier, byIndex: byIndex, index: index, byID: byID, id: id, byHash: byHash, hash: hash).then((value) => value); return fetchAndCacheMessageInfo(context, profileOnion, conversationIdentifier, cacheHandler);
}); });
} }
// Construct the initial metadata // Construct the initial metadata
var messageID = messageWrapper['ID']; var messageID = messageWrapper['ID'];
var timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!; var timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!;
var senderHandle = messageWrapper['PeerID']; var senderHandle = messageWrapper['PeerID'];
@ -163,15 +199,8 @@ Future<MessageInfo?> fetchAndCacheMessageInfo(BuildContext context, String profi
var messageInfo = new MessageInfo(metadata, messageWrapper['Message']); var messageInfo = new MessageInfo(metadata, messageWrapper['Message']);
var cache = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(conversationIdentifier)?.messageCache; var cache = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(conversationIdentifier)?.messageCache;
if (cache != null) { if (cache != null) {
if (byID) { cacheHandler.add(cache, messageInfo, contenthash);
cache.addUnindexed(messageInfo, contenthash);
} else if (byHash) {
cache.addUnindexed(messageInfo, contenthash);
} else {
cache.add(messageInfo, index!, contenthash);
}
} }
return messageInfo; return messageInfo;

View File

@ -59,8 +59,7 @@ class QuotedMessage extends Message {
return ChangeNotifierProvider.value( return ChangeNotifierProvider.value(
value: this.metadata, value: this.metadata,
builder: (bcontext, child) { builder: (bcontext, child) {
return MessageRow(QuotedMessageBubble(message["body"], messageHandler(bcontext, metadata.profileOnion, metadata.conversationIdentifier, byHash: true, hash: message["quotedHash"])), return MessageRow(QuotedMessageBubble(message["body"], messageHandler(bcontext, metadata.profileOnion, metadata.conversationIdentifier, ByContentHash(message["quotedHash"]))), key: key);
key: key);
}); });
} catch (e) { } catch (e) {
return MalformedBubble(); return MalformedBubble();

View File

@ -227,7 +227,7 @@ class _MessageViewState extends State<MessageView> {
Future.delayed(const Duration(milliseconds: 80), () { Future.delayed(const Duration(milliseconds: 80), () {
var profile = Provider.of<ContactInfoState>(context, listen: false).profileOnion; var profile = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier; var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
fetchAndCacheMessageInfo(context, profile, identifier, byIndex: true, index: 0); fetchAndCacheMessageInfo(context, profile, identifier, ByIndex(0));
Provider.of<ContactInfoState>(context, listen: false).newMarker++; Provider.of<ContactInfoState>(context, listen: false).newMarker++;
Provider.of<ContactInfoState>(context, listen: false).totalMessages += 1; Provider.of<ContactInfoState>(context, listen: false).totalMessages += 1;
// Resort the contact list... // Resort the contact list...
@ -284,8 +284,7 @@ class _MessageViewState extends State<MessageView> {
var children; var children;
if (Provider.of<AppState>(context).selectedConversation != null && Provider.of<AppState>(context).selectedIndex != null) { if (Provider.of<AppState>(context).selectedConversation != null && Provider.of<AppState>(context).selectedIndex != null) {
var quoted = FutureBuilder( var quoted = FutureBuilder(
future: messageHandler(context, Provider.of<AppState>(context).selectedProfile!, Provider.of<AppState>(context).selectedConversation!, future: messageHandler(context, Provider.of<AppState>(context).selectedProfile!, Provider.of<AppState>(context).selectedConversation!, ById(Provider.of<AppState>(context).selectedIndex!)),
id: Provider.of<AppState>(context).selectedIndex!, byID: true),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
var message = snapshot.data! as Message; var message = snapshot.data! as Message;

View File

@ -83,7 +83,7 @@ class _MessageListState extends State<MessageList> {
var messageIndex = index; var messageIndex = index;
return FutureBuilder( return FutureBuilder(
future: messageHandler(outerContext, profileOnion, contactHandle, byIndex: true, index: messageIndex), future: messageHandler(outerContext, profileOnion, contactHandle, ByIndex(messageIndex)),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
var message = snapshot.data as Message; var message = snapshot.data as Message;