Improve chat future performance w/ parallelization
This commit is contained in:
parent
8b24356399
commit
9caad1f6c9
3 changed files with 73 additions and 71 deletions
|
|
@ -4,6 +4,7 @@ import 'package:frosty/api/seventv_api.dart';
|
|||
import 'package:frosty/api/twitch_api.dart';
|
||||
import 'package:frosty/models/badges.dart';
|
||||
import 'package:frosty/models/emotes.dart';
|
||||
import 'package:frosty/models/user.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'chat_assets_store.g.dart';
|
||||
|
|
@ -23,6 +24,9 @@ abstract class _ChatAssetsStoreBase with Store {
|
|||
@computed
|
||||
List<Emote> get sevenTvEmotes => _emoteToObject.values.where((emote) => is7TV(emote)).toList();
|
||||
|
||||
/// The map of badges ids to their object representation.
|
||||
final twitchBadgesToObject = ObservableMap<String, BadgeInfoTwitch>();
|
||||
|
||||
/// The map of emote words to their image or GIF URL. May be used by anyone in the chat.
|
||||
@readonly
|
||||
var _emoteToObject = <String, Emote>{};
|
||||
|
|
@ -31,10 +35,6 @@ abstract class _ChatAssetsStoreBase with Store {
|
|||
@readonly
|
||||
var _userEmoteToObject = <String, Emote>{};
|
||||
|
||||
/// The map of badges ids to their object representation.
|
||||
@readonly
|
||||
var _twitchBadgesToObject = <String, BadgeInfoTwitch>{};
|
||||
|
||||
/// The map of usernames to their FFZ badges.
|
||||
@readonly
|
||||
var _userToFFZBadges = <String, List<BadgeInfoFFZ>>{};
|
||||
|
|
@ -76,49 +76,47 @@ abstract class _ChatAssetsStoreBase with Store {
|
|||
if (channelInfo != null) {
|
||||
// Fetch the global and channel's assets (emotes & badges).
|
||||
// Async awaits are placed in a list so they are performed in parallel.
|
||||
final assets = [
|
||||
...await FFZ.getEmotesGlobal(),
|
||||
...await BTTV.getEmotesGlobal(),
|
||||
...await BTTV.getEmotesChannel(id: channelInfo.id),
|
||||
...await Twitch.getEmotesGlobal(headers: headers),
|
||||
...await Twitch.getEmotesChannel(id: channelInfo.id, headers: headers),
|
||||
...await SevenTV.getEmotesGlobal(),
|
||||
...await SevenTV.getEmotesChannel(user: channelInfo.login)
|
||||
];
|
||||
|
||||
final ffzRoom = await FFZ.getRoomInfo(name: channelInfo.login);
|
||||
if (ffzRoom != null) {
|
||||
assets.addAll(ffzRoom.item2);
|
||||
ffzRoomInfo = ffzRoom.item1;
|
||||
}
|
||||
|
||||
_emoteToObject = {for (final emote in assets) emote.name: emote};
|
||||
|
||||
_twitchBadgesToObject = {
|
||||
...await Twitch.getBadgesGlobal(),
|
||||
...await Twitch.getBadgesChannel(id: channelInfo.id),
|
||||
};
|
||||
|
||||
final ffzBadges = await FFZ.getBadges();
|
||||
if (ffzBadges != null) _userToFFZBadges = ffzBadges;
|
||||
|
||||
final sevenTVBadges = await SevenTV.getBadges();
|
||||
if (sevenTVBadges != null) _userTo7TVBadges = sevenTVBadges;
|
||||
|
||||
final bttvBadges = await BTTV.getBadges();
|
||||
if (bttvBadges != null) _userToBTTVBadges = bttvBadges;
|
||||
await Future.wait([
|
||||
getEmotes(channelInfo: channelInfo, headers: headers),
|
||||
getBadges(channelInfo: channelInfo, headers: headers),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> getUserEmotes({List<String>? emoteSets, required Map<String, String> headers}) async {
|
||||
if (emoteSets != null) {
|
||||
final userEmotes = <Emote>[];
|
||||
for (final setId in emoteSets) {
|
||||
userEmotes.addAll(await Twitch.getEmotesSets(setId: setId, headers: headers));
|
||||
}
|
||||
Future<void> getEmotes({required UserTwitch channelInfo, required Map<String, String> headers}) async {
|
||||
final assets = await Future.wait([
|
||||
FFZ.getEmotesGlobal(),
|
||||
BTTV.getEmotesGlobal(),
|
||||
BTTV.getEmotesChannel(id: channelInfo.id),
|
||||
Twitch.getEmotesGlobal(headers: headers),
|
||||
Twitch.getEmotesChannel(id: channelInfo.id, headers: headers),
|
||||
SevenTV.getEmotesGlobal(),
|
||||
SevenTV.getEmotesChannel(user: channelInfo.login),
|
||||
FFZ.getRoomInfo(name: channelInfo.login).then((ffzRoom) {
|
||||
ffzRoomInfo = ffzRoom?.item1;
|
||||
return ffzRoom?.item2 ?? <Emote>[];
|
||||
}),
|
||||
]);
|
||||
|
||||
_userEmoteToObject = {for (final emote in userEmotes) emote.name: emote}.asObservable();
|
||||
}
|
||||
final emotes = assets.expand((list) => list);
|
||||
|
||||
_emoteToObject = {for (final emote in emotes) emote.name: emote};
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> getBadges({required UserTwitch channelInfo, required Map<String, String> headers}) async => await Future.wait([
|
||||
Twitch.getBadgesGlobal().then((badges) => twitchBadgesToObject.addAll(badges)),
|
||||
Twitch.getBadgesChannel(id: channelInfo.id).then((badges) => twitchBadgesToObject.addAll(badges)),
|
||||
FFZ.getBadges().then((badges) => _userToFFZBadges = badges ?? {}),
|
||||
SevenTV.getBadges().then((badges) => _userTo7TVBadges = badges ?? {}),
|
||||
BTTV.getBadges().then((badges) => _userToBTTVBadges = badges ?? {}),
|
||||
]);
|
||||
|
||||
@action
|
||||
Future<void> getUserEmotes({required List<String> emoteSets, required Map<String, String> headers}) async =>
|
||||
await Future.wait(emoteSets.map((setId) => Twitch.getEmotesSets(setId: setId, headers: headers)))
|
||||
.then((emotes) => emotes.expand((list) => list).toList())
|
||||
.then((userEmotes) => _userEmoteToObject = {for (final emote in userEmotes) emote.name: emote}.asObservable());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,26 +67,6 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
});
|
||||
}
|
||||
|
||||
final _$_twitchBadgesToObjectAtom =
|
||||
Atom(name: '_ChatAssetsStoreBase._twitchBadgesToObject');
|
||||
|
||||
Map<String, BadgeInfoTwitch> get twitchBadgesToObject {
|
||||
_$_twitchBadgesToObjectAtom.reportRead();
|
||||
return super._twitchBadgesToObject;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, BadgeInfoTwitch> get _twitchBadgesToObject =>
|
||||
twitchBadgesToObject;
|
||||
|
||||
@override
|
||||
set _twitchBadgesToObject(Map<String, BadgeInfoTwitch> value) {
|
||||
_$_twitchBadgesToObjectAtom.reportWrite(value, super._twitchBadgesToObject,
|
||||
() {
|
||||
super._twitchBadgesToObject = value;
|
||||
});
|
||||
}
|
||||
|
||||
final _$_userToFFZBadgesAtom =
|
||||
Atom(name: '_ChatAssetsStoreBase._userToFFZBadges');
|
||||
|
||||
|
|
@ -181,12 +161,30 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
.run(() => super.getAssets(channelName: channelName, headers: headers));
|
||||
}
|
||||
|
||||
final _$getEmotesAsyncAction = AsyncAction('_ChatAssetsStoreBase.getEmotes');
|
||||
|
||||
@override
|
||||
Future<void> getEmotes(
|
||||
{required UserTwitch channelInfo, required Map<String, String> headers}) {
|
||||
return _$getEmotesAsyncAction
|
||||
.run(() => super.getEmotes(channelInfo: channelInfo, headers: headers));
|
||||
}
|
||||
|
||||
final _$getBadgesAsyncAction = AsyncAction('_ChatAssetsStoreBase.getBadges');
|
||||
|
||||
@override
|
||||
Future<void> getBadges(
|
||||
{required UserTwitch channelInfo, required Map<String, String> headers}) {
|
||||
return _$getBadgesAsyncAction
|
||||
.run(() => super.getBadges(channelInfo: channelInfo, headers: headers));
|
||||
}
|
||||
|
||||
final _$getUserEmotesAsyncAction =
|
||||
AsyncAction('_ChatAssetsStoreBase.getUserEmotes');
|
||||
|
||||
@override
|
||||
Future<void> getUserEmotes(
|
||||
{List<String>? emoteSets, required Map<String, String> headers}) {
|
||||
{required List<String> emoteSets, required Map<String, String> headers}) {
|
||||
return _$getUserEmotesAsyncAction
|
||||
.run(() => super.getUserEmotes(emoteSets: emoteSets, headers: headers));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,11 +139,13 @@ abstract class _ChatStoreBase with Store {
|
|||
break;
|
||||
case Command.globalUserState:
|
||||
final setIds = parsedIRCMessage.tags['emote-sets']?.split(',');
|
||||
_messages.add(IRCMessage.createNotice(message: 'Fetching user emotes...'));
|
||||
assetsStore
|
||||
.getUserEmotes(emoteSets: setIds, headers: auth.headersTwitch)
|
||||
.then((_) => _messages.add(IRCMessage.createNotice(message: 'User emotes fetched!')))
|
||||
.onError((error, stackTrace) => _messages.add(IRCMessage.createNotice(message: 'Failed to fetch user emotes: ${error.toString()}')));
|
||||
if (setIds != null) {
|
||||
_messages.add(IRCMessage.createNotice(message: 'Fetching user emotes...'));
|
||||
assetsStore
|
||||
.getUserEmotes(emoteSets: setIds, headers: auth.headersTwitch)
|
||||
.then((_) => _messages.add(IRCMessage.createNotice(message: 'User emotes fetched!')))
|
||||
.onError((error, stackTrace) => _messages.add(IRCMessage.createNotice(message: 'Failed to fetch user emotes: ${error.toString()}')));
|
||||
}
|
||||
continue;
|
||||
case Command.none:
|
||||
debugPrint('Unknown command: ${parsedIRCMessage.command}');
|
||||
|
|
@ -213,8 +215,12 @@ abstract class _ChatStoreBase with Store {
|
|||
onDone: () async {
|
||||
if (_channel == null) return;
|
||||
|
||||
// Add notice that chat was disconnected and then wait the backoff time before reconnecting.
|
||||
_messages.add(IRCMessage.createNotice(message: 'Disconnected from chat, waiting $_backoffTime seconds before reconnecting...'));
|
||||
if (_backoffTime > 0) {
|
||||
// Add notice that chat was disconnected and then wait the backoff time before reconnecting.
|
||||
final notice = 'Disconnected from chat, waiting ${_backoffTime == 1 ? 'second' : 'seconds'} before reconnecting...';
|
||||
_messages.add(IRCMessage.createNotice(message: notice));
|
||||
}
|
||||
|
||||
await Future.delayed(Duration(seconds: _backoffTime));
|
||||
|
||||
// Increase the backoff time for the next retry.
|
||||
|
|
@ -222,7 +228,7 @@ abstract class _ChatStoreBase with Store {
|
|||
|
||||
// Increment the retry count and attempt the reconnect.
|
||||
_retries++;
|
||||
_messages.add(IRCMessage.createNotice(message: 'Reconnecting to chat (attempt $_retries).'));
|
||||
_messages.add(IRCMessage.createNotice(message: 'Reconnecting to chat (attempt $_retries)...'));
|
||||
reconnect();
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue