moxxy/lib/service/blocking.dart

212 lines
5.4 KiB
Dart

import 'dart:async';
import 'package:get_it/get_it.dart';
import 'package:logging/logging.dart';
import 'package:moxxmpp/moxxmpp.dart';
import 'package:moxxyv2/service/database/constants.dart';
import 'package:moxxyv2/service/database/database.dart';
import 'package:moxxyv2/service/service.dart';
import 'package:moxxyv2/shared/events.dart';
enum BlockPushType { block, unblock }
class BlocklistService {
BlocklistService();
List<String>? _blocklist;
bool _requested = false;
bool? _supported;
final Logger _log = Logger('BlocklistService');
Future<void> _removeBlocklistEntry(String jid) async {
await GetIt.I.get<DatabaseService>().database.delete(
blocklistTable,
where: 'jid = ?',
whereArgs: [jid],
);
}
Future<void> _addBlocklistEntry(String jid) async {
await GetIt.I.get<DatabaseService>().database.insert(
blocklistTable,
{
'jid': jid,
},
);
}
void onNewConnection() {
// Invalidate the caches
_blocklist = null;
_requested = false;
_supported = null;
}
Future<bool> _checkSupport() async {
return _supported ??= await GetIt.I
.get<XmppConnection>()
.getManagerById<BlockingManager>(blockingManager)!
.isSupported();
}
Future<void> _requestBlocklist() async {
assert(
_blocklist != null,
'The blocklist must be loaded from the database before requesting',
);
// Check if blocking is supported
if (!(await _checkSupport())) {
_log.warning('Blocklist requested but server does not support it.');
return;
}
final blocklist = await GetIt.I
.get<XmppConnection>()
.getManagerById<BlockingManager>(blockingManager)!
.getBlocklist();
// Diff the received blocklist with the cache
final newItems = List<String>.empty(growable: true);
final removedItems = List<String>.empty(growable: true);
for (final item in blocklist) {
if (!_blocklist!.contains(item)) {
await _addBlocklistEntry(item);
_blocklist!.add(item);
newItems.add(item);
}
}
// Diff the cache with the received blocklist
for (final item in _blocklist!) {
if (!blocklist.contains(item)) {
await _removeBlocklistEntry(item);
_blocklist!.remove(item);
removedItems.add(item);
}
}
_requested = true;
// Trigger an UI event if we have anything to tell the UI
if (newItems.isNotEmpty || removedItems.isNotEmpty) {
sendEvent(
BlocklistPushEvent(
added: newItems,
removed: removedItems,
),
);
}
}
/// Returns the blocklist from the database
Future<List<String>> getBlocklist() async {
if (_blocklist == null) {
final blocklistRaw =
await GetIt.I.get<DatabaseService>().database.query(blocklistTable);
_blocklist = blocklistRaw.map((m) => m['jid']! as String).toList();
if (!_requested) {
unawaited(_requestBlocklist());
}
return _blocklist!;
}
if (!_requested) {
unawaited(_requestBlocklist());
}
return _blocklist!;
}
void onUnblockAllPush() {
_blocklist = List<String>.empty(growable: true);
sendEvent(
BlocklistUnblockAllEvent(),
);
}
Future<void> onBlocklistPush(BlockPushType type, List<String> items) async {
// We will fetch it later when getBlocklist is called
if (!_requested) return;
final newBlocks = List<String>.empty(growable: true);
final removedBlocks = List<String>.empty(growable: true);
for (final item in items) {
switch (type) {
case BlockPushType.block:
{
if (_blocklist!.contains(item)) continue;
_blocklist!.add(item);
newBlocks.add(item);
await _addBlocklistEntry(item);
}
break;
case BlockPushType.unblock:
{
_blocklist!.removeWhere((i) => i == item);
removedBlocks.add(item);
await _removeBlocklistEntry(item);
}
break;
}
}
sendEvent(
BlocklistPushEvent(
added: newBlocks,
removed: removedBlocks,
),
);
}
Future<bool> blockJid(String jid) async {
// Check if blocking is supported
if (!(await _checkSupport())) {
_log.warning('Blocking $jid requested but server does not support it.');
return false;
}
_blocklist!.add(jid);
await _addBlocklistEntry(jid);
return GetIt.I
.get<XmppConnection>()
.getManagerById<BlockingManager>(blockingManager)!
.block([jid]);
}
Future<bool> unblockJid(String jid) async {
// Check if blocking is supported
if (!(await _checkSupport())) {
_log.warning('Unblocking $jid requested but server does not support it.');
return false;
}
_blocklist!.remove(jid);
await _removeBlocklistEntry(jid);
return GetIt.I
.get<XmppConnection>()
.getManagerById<BlockingManager>(blockingManager)!
.unblock([jid]);
}
Future<bool> unblockAll() async {
// Check if blocking is supported
if (!(await _checkSupport())) {
_log.warning(
'Unblocking all JIDs requested but server does not support it.',
);
return false;
}
_blocklist!.clear();
await GetIt.I.get<DatabaseService>().database.delete(blocklistTable);
return GetIt.I
.get<XmppConnection>()
.getManagerById<BlockingManager>(blockingManager)!
.unblockAll();
}
}