feat(xep): Allow ignoring the discussion history

Also allow specifying the amount of stanzas of discussion history we
want.
This commit is contained in:
PapaTutuWawa 2023-09-22 19:23:35 +02:00
parent d4416c8a47
commit d7c13abde6
3 changed files with 105 additions and 13 deletions

View File

@ -58,7 +58,11 @@ void main(List<String> args) async {
Logger.root.info('Connected.'); Logger.root.info('Connected.');
// Join room // Join room
await connection.getManagerById<MUCManager>(mucManager)!.joinRoom(muc, nick); await connection.getManagerById<MUCManager>(mucManager)!.joinRoom(
muc,
nick,
maxHistoryStanzas: 0,
);
final repl = Repl(prompt: '> '); final repl = Repl(prompt: '> ');
await for (final line in repl.runAsync()) { await for (final line in repl.runAsync()) {

View File

@ -34,10 +34,25 @@ class RoomInformation {
} }
class RoomState { class RoomState {
RoomState({ RoomState({required this.roomJid, this.nick, required this.joined});
required this.roomJid,
this.nick, /// The JID of the room.
});
final JID roomJid; final JID roomJid;
/// The nick we're joined with.
String? nick; String? nick;
/// Flag whether we're joined and can process messages
bool joined;
RoomState copyWith({
bool? joined,
String? nick,
}) {
return RoomState(
roomJid: roomJid,
joined: joined ?? this.joined,
nick: nick ?? this.nick,
);
}
} }

View File

@ -1,6 +1,8 @@
import 'package:moxlib/moxlib.dart'; import 'package:moxlib/moxlib.dart';
import 'package:moxxmpp/src/jid.dart'; import 'package:moxxmpp/src/jid.dart';
import 'package:moxxmpp/src/managers/base.dart'; import 'package:moxxmpp/src/managers/base.dart';
import 'package:moxxmpp/src/managers/data.dart';
import 'package:moxxmpp/src/managers/handlers.dart';
import 'package:moxxmpp/src/managers/namespaces.dart'; import 'package:moxxmpp/src/managers/namespaces.dart';
import 'package:moxxmpp/src/namespaces.dart'; import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/stanza.dart'; import 'package:moxxmpp/src/stanza.dart';
@ -9,6 +11,7 @@ import 'package:moxxmpp/src/xeps/xep_0030/types.dart';
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart'; import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
import 'package:moxxmpp/src/xeps/xep_0045/errors.dart'; import 'package:moxxmpp/src/xeps/xep_0045/errors.dart';
import 'package:moxxmpp/src/xeps/xep_0045/types.dart'; import 'package:moxxmpp/src/xeps/xep_0045/types.dart';
import 'package:synchronized/extension.dart';
import 'package:synchronized/synchronized.dart'; import 'package:synchronized/synchronized.dart';
class MUCManager extends XmppManagerBase { class MUCManager extends XmppManagerBase {
@ -23,6 +26,16 @@ class MUCManager extends XmppManagerBase {
/// Cache lock /// Cache lock
final Lock _cacheLock = Lock(); final Lock _cacheLock = Lock();
@override
List<StanzaHandler> getIncomingStanzaHandlers() => [
StanzaHandler(
stanzaTag: 'message',
callback: _onMessage,
// Before the message handler
priority: -99,
)
];
/// Queries the information of a Multi-User Chat room. /// Queries the information of a Multi-User Chat room.
/// ///
/// Retrieves the information about the specified MUC room by performing a /// Retrieves the information about the specified MUC room by performing a
@ -55,11 +68,23 @@ class MUCManager extends XmppManagerBase {
/// if applicable. /// if applicable.
Future<Result<bool, MUCError>> joinRoom( Future<Result<bool, MUCError>> joinRoom(
JID roomJid, JID roomJid,
String nick, String nick, {
) async { int? maxHistoryStanzas,
}) async {
if (nick.isEmpty) { if (nick.isEmpty) {
return Result(NoNicknameSpecified()); return Result(NoNicknameSpecified());
} }
await _cacheLock.synchronized(
() {
_mucRoomCache[roomJid] = RoomState(
roomJid: roomJid,
nick: nick,
joined: false,
);
},
);
await getAttributes().sendStanza( await getAttributes().sendStanza(
StanzaDetails( StanzaDetails(
Stanza.presence( Stanza.presence(
@ -68,16 +93,20 @@ class MUCManager extends XmppManagerBase {
XMLNode.xmlns( XMLNode.xmlns(
tag: 'x', tag: 'x',
xmlns: mucXmlns, xmlns: mucXmlns,
) children: [
if (maxHistoryStanzas != null)
XMLNode(
tag: 'history',
attributes: {
'maxstanzas': maxHistoryStanzas.toString(),
},
),
],
),
], ],
), ),
), ),
); );
await _cacheLock.synchronized(
() {
_mucRoomCache[roomJid] = RoomState(roomJid: roomJid, nick: nick);
},
);
return const Result(true); return const Result(true);
} }
@ -108,4 +137,48 @@ class MUCManager extends XmppManagerBase {
); );
return const Result(true); return const Result(true);
} }
Future<StanzaHandlerData> _onMessage(
Stanza message,
StanzaHandlerData state,
) async {
final roomJid = JID.fromString(message.from!).toBare();
return _mucRoomCache.synchronized(() {
final roomState = _mucRoomCache[roomJid];
if (roomState == null) {
return state;
}
if (message.type == 'groupchat' && message.firstTag('subject') != null) {
// The room subject marks the end of the join flow.
if (!roomState.joined) {
// Mark the room as joined.
_mucRoomCache[roomJid] = roomState.copyWith(joined: true);
logger.finest('$roomJid is now joined');
}
// TODO(Unknown): Signal the subject?
return StanzaHandlerData(
true,
false,
message,
state.extensions,
);
} else {
if (!roomState.joined) {
// Ignore the discussion history.
// TODO: Implement a copyWith method
return StanzaHandlerData(
true,
false,
message,
state.extensions,
);
}
}
return state;
});
}
} }