Skip to content

Commit 5c47272

Browse files
authored
Merge pull request #80 from TatankaConCube/fixes_and_improvements
Fixes and improvements
2 parents b6c6002 + 9f3e63f commit 5c47272

9 files changed

+69
-57
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ build/
99

1010
# Directory created by dartdoc
1111
doc/api/
12+
13+
# IDE directories
14+
/.idea/

README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ __Actively working on:__
3737
import 'package:xmpp_stone/xmpp_stone.dart' as xmpp;
3838
3939
main() {
40-
xmpp.Connection connection = new xmpp.Connection("user@domain", "password", 5222);
40+
xmpp.XmppAccountSettings accountSettings = xmpp.XmppAccountSettings.fromJid('nick@damain.com/resource', 'password');
41+
accountSettings.port = kIsWeb ? 5291 : 5222;
42+
accountSettings.wsPath = 'xmpp-websocket'; // null or your custom xmpp path
43+
accountSettings.wsProtocols = ['xmpp']; // or your custom protocols
44+
45+
xmpp.Connection connection = xmpp.Connection.getInstance(accountSettings);
4146
connection.open();
4247
}
4348
```

lib/src/Connection.dart

+25-36
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,19 @@ import 'package:collection/collection.dart' show IterableExtension;
55
import 'package:xml/xml.dart' as xml;
66
import 'package:synchronized/synchronized.dart';
77
import 'package:xmpp_stone/src/ReconnectionManager.dart';
8-
import 'package:xmpp_stone/src/account/XmppAccountSettings.dart';
98

10-
import 'package:xmpp_stone/src/data/Jid.dart';
119
import 'package:xmpp_stone/src/elements/nonzas/Nonza.dart';
12-
import 'package:xmpp_stone/src/elements/stanzas/AbstractStanza.dart';
13-
import 'package:xmpp_stone/src/extensions/ping/PingManager.dart';
1410
import 'package:xmpp_stone/src/features/ConnectionNegotatiorManager.dart';
1511
import 'package:xmpp_stone/src/features/servicediscovery/CarbonsNegotiator.dart';
1612
import 'package:xmpp_stone/src/features/servicediscovery/MAMNegotiator.dart';
1713
import 'package:xmpp_stone/src/features/servicediscovery/ServiceDiscoveryNegotiator.dart';
1814
import 'package:xmpp_stone/src/features/streammanagement/StreamManagmentModule.dart';
1915
import 'package:xmpp_stone/src/parser/StanzaParser.dart';
20-
import 'package:xmpp_stone/src/presence/PresenceManager.dart';
21-
import 'package:xmpp_stone/src/roster/RosterManager.dart';
2216
import 'package:xmpp_stone/xmpp_stone.dart';
2317

2418
import 'connection/XmppWebsocketApi.dart'
25-
if (dart.library.io) 'connection/XmppWebsocketIo.dart'
26-
if (dart.library.html) 'connection/XmppWebsocketHtml.dart' as xmppSocket;
19+
if (dart.library.io) 'connection/XmppWebsocketIo.dart'
20+
if (dart.library.html) 'connection/XmppWebsocketHtml.dart' as xmppSocket;
2721

2822
import 'logger/Log.dart';
2923

@@ -151,13 +145,7 @@ class Connection {
151145
}
152146

153147
void _openStream() {
154-
var streamOpeningString = """
155-
<?xml version='1.0'?>
156-
<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams'
157-
to='${fullJid.domain}'
158-
xml:lang='en'
159-
>
160-
""";
148+
var streamOpeningString = _socket?.getStreamOpeningElement(fullJid.domain);
161149
write(streamOpeningString);
162150
}
163151

@@ -208,16 +196,22 @@ xml:lang='en'
208196
connectionNegotatiorManager.init();
209197
setState(XmppConnectionState.SocketOpening);
210198
try {
211-
212199
var socket = xmppSocket.createSocket();
213200

214-
return await socket.connect(account.host ?? account.domain, account.port, map: prepareStreamResponse).then((socket) {
201+
return await socket
202+
.connect(
203+
account.host ?? account.domain,
204+
account.port,
205+
wsProtocols: account.wsProtocols,
206+
wsPath: account.wsPath,
207+
map: prepareStreamResponse,
208+
)
209+
.then((socket) {
215210
// if not closed in meantime
216211
if (_state != XmppConnectionState.Closed) {
217212
setState(XmppConnectionState.SocketOpened);
218213
_socket = socket;
219-
socket
220-
.listen(handleResponse, onDone: handleConnectionDone);
214+
socket.listen(handleResponse, onDone: handleConnectionDone);
221215
_openStream();
222216
} else {
223217
Log.d(TAG, 'Closed in meantime');
@@ -251,10 +245,10 @@ xml:lang='en'
251245

252246
/// Dispose of the connection so stops all activities and cannot be re-used.
253247
/// For the connection to be garbage collected.
254-
///
248+
///
255249
/// If the Connection instance was created with [getInstance],
256250
/// you must also call [Connection.removeInstance] after calling [dispose].
257-
///
251+
///
258252
/// If you intend to re-use the connection later, consider just calling [close] instead.
259253
void dispose() {
260254
close();
@@ -309,36 +303,30 @@ xml:lang='en'
309303
if (fullResponse.isNotEmpty) {
310304
xml.XmlNode? xmlResponse;
311305
try {
312-
xmlResponse = xml.XmlDocument.parse(fullResponse).firstChild;
306+
xmlResponse = xml.XmlDocument.parse(fullResponse.replaceAll('<?xml version=\'1.0\'?>', '')).firstChild;
313307
} catch (e) {
314308
_unparsedXmlResponse += fullResponse.substring(
315309
0, fullResponse.length - 13); //remove xmpp_stone end tag
316310
xmlResponse = xml.XmlElement(xml.XmlName('error'));
317311
}
318-
// xmlResponse.descendants.whereType<xml.XmlElement>().forEach((element) {
319-
// Log.d("element: " + element.name.local);
320-
// });
312+
321313
//TODO: Improve parser for children only
322-
xmlResponse!.descendants
323-
.whereType<xml.XmlElement>()
314+
xmlResponse!.childElements
324315
.where((element) => startMatcher(element))
325316
.forEach((element) => processInitialStream(element));
326317

327-
xmlResponse.children
328-
.whereType<xml.XmlElement>()
318+
xmlResponse.childElements
329319
.where((element) => stanzaMatcher(element))
330320
.map((xmlElement) => StanzaParser.parseStanza(xmlElement))
331321
.forEach((stanza) => _inStanzaStreamController.add(stanza));
332322

333-
xmlResponse.descendants
334-
.whereType<xml.XmlElement>()
323+
xmlResponse.childElements
335324
.where((element) => featureMatcher(element))
336325
.forEach((feature) =>
337326
connectionNegotatiorManager.negotiateFeatureList(feature));
338327

339328
//TODO: Probably will introduce bugs!!!
340-
xmlResponse.children
341-
.whereType<xml.XmlElement>()
329+
xmlResponse.childElements
342330
.where((element) => nonzaMatcher(element))
343331
.map((xmlElement) => Nonza.parse(xmlElement))
344332
.forEach((nonza) => _inNonzaStreamController.add(nonza));
@@ -405,9 +393,10 @@ xml:lang='en'
405393
void startSecureSocket() {
406394
Log.d(TAG, 'startSecureSocket');
407395

408-
_socket!.secure(onBadCertificate: _validateBadCertificate).
409-
then((secureSocket) {
410-
if(secureSocket == null) return;
396+
_socket!
397+
.secure(onBadCertificate: _validateBadCertificate)
398+
.then((secureSocket) {
399+
if (secureSocket == null) return;
411400

412401
secureSocket
413402
.cast<List<int>>()

lib/src/account/XmppAccountSettings.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ class XmppAccountSettings {
88
String password;
99
String? host;
1010
int port;
11+
String? wsPath;
12+
List<String>? wsProtocols;
1113
int totalReconnections = 3;
1214
int reconnectionTimeout = 1000;
1315
bool ackEnabled = true;
1416
bool smResumable = true;
1517

16-
XmppAccountSettings(this.name, this.username, this.domain, this.password, this.port, {this.host, this.resource} );
18+
XmppAccountSettings(this.name, this.username, this.domain, this.password, this.port, {this.host, this.resource, this.wsPath, this.wsProtocols} );
1719

1820
Jid get fullJid => Jid(username, domain, resource);
1921

lib/src/connection/XmppWebsocketApi.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ bool isTlsRequired() {
1111

1212
abstract class XmppWebSocket extends Stream<String> {
1313
Future<XmppWebSocket> connect<S>(String host, int port,
14-
{String Function(String event)? map});
14+
{String Function(String event)? map, List<String>? wsProtocols, String? wsPath});
1515

1616
void write(Object? message);
1717

@@ -22,4 +22,6 @@ abstract class XmppWebSocket extends Stream<String> {
2222
SecurityContext? context,
2323
bool Function(X509Certificate certificate)? onBadCertificate,
2424
List<String>? supportedProtocols});
25+
26+
String getStreamOpeningElement(String domain);
2527
}

lib/src/connection/XmppWebsocketHtml.dart

+10-3
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,24 @@ bool isTlsRequired() {
1717
}
1818

1919
class XmppWebSocketHtml extends XmppWebSocket {
20+
static String TAG = 'XmppWebSocketIo';
21+
2022
WebSocketChannel? _socket;
2123
late String Function(String event) _map;
2224

2325
XmppWebSocketHtml();
2426

2527
@override
2628
Future<XmppWebSocket> connect<S>(String host, int port,
27-
{String Function(String event)? map}) {
28-
print('[XmppWebSocketHtml][connect] host: $host, port: $port');
29+
{String Function(String event)? map, List<String>? wsProtocols, String? wsPath}) {
2930
_socket = WebSocketChannel.connect(
3031
Uri(
3132
scheme: 'wss',
3233
host: host,
3334
port: port,
35+
path: wsPath,
3436
),
35-
protocols: ['xmpp'],
37+
protocols: wsProtocols,
3638
);
3739

3840
if (map != null) {
@@ -73,4 +75,9 @@ class XmppWebSocketHtml extends XmppWebSocket {
7375
// return the `null`, cause for the 'html' socket initially creates as secured
7476
return Future.value(null);
7577
}
78+
79+
@override
80+
String getStreamOpeningElement(String domain) {
81+
return """<open xmlns='urn:ietf:params:xml:ns:xmpp-framing' to='$domain' version='1.0'/>""";
82+
}
7683
}

lib/src/connection/XmppWebsocketIo.dart

+7-1
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ bool isTlsRequired() {
1515
}
1616

1717
class XmppWebSocketIo extends XmppWebSocket {
18+
static String TAG = 'XmppWebSocketIo';
1819
Socket? _socket;
1920
late String Function(String event) _map;
2021

2122
XmppWebSocketIo();
2223

2324
@override
2425
Future<XmppWebSocket> connect<S>(String host, int port,
25-
{String Function(String event)? map}) async {
26+
{String Function(String event)? map, List<String>? wsProtocols, String? wsPath}) async {
2627
await Socket.connect(host, port).then((Socket socket) {
2728
_socket = socket;
2829

@@ -64,4 +65,9 @@ class XmppWebSocketIo extends XmppWebSocket {
6465
List<String>? supportedProtocols}) {
6566
return SecureSocket.secure(_socket!, onBadCertificate: onBadCertificate);
6667
}
68+
69+
@override
70+
String getStreamOpeningElement(String domain) {
71+
return """<?xml version='1.0'?><stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='$domain' xml:lang='en'>""";
72+
}
6773
}

lib/src/features/ConnectionNegotatiorManager.dart

+2-4
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,8 @@ class ConnectionNegotiatorManager {
4343

4444
void negotiateFeatureList(xml.XmlElement element) {
4545
Log.d(TAG, 'Negotiating features');
46-
var nonzas = element.descendants
47-
.whereType<xml.XmlElement>()
48-
.map((element) => Nonza.parse(element))
49-
.toList();
46+
var nonzas =
47+
element.childElements.map((element) => Nonza.parse(element)).toList();
5048
supportedNegotiatorList.forEach((negotiator) {
5149
var matchingNonzas = negotiator.match(nonzas);
5250
if (matchingNonzas != null && matchingNonzas.isNotEmpty) {

pubspec.yaml

+10-10
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,20 @@ environment:
1212
#dependencies:
1313
# path: ^1.4.1
1414
dependencies:
15-
xml: ^5.1.0
15+
xml: ^6.1.0
1616
cryptoutils: ^0.5.0
17-
crypto: ^3.0.1
18-
synchronized: ^3.0.0
17+
crypto: ^3.0.2
18+
synchronized: ^3.0.0+3
1919
tuple: ^2.0.0
2020
unorm_dart: ^0.2.0
21-
image: ^3.0.8
22-
quiver: ^3.0.1 #hash code generator
23-
console: ^4.0.0 #for example
21+
image: ^3.2.0
22+
quiver: ^3.1.0 #hash code generator
23+
console: ^4.1.0 #for example
2424
intl: ^0.17.0
25-
collection: ^1.15.0
25+
collection: ^1.16.0
2626
universal_io: ^2.0.4
27-
web_socket_channel: 2.1.0
27+
web_socket_channel: ^2.2.0
2828

2929
dev_dependencies:
30-
test: ^1.16.8
31-
mockito: ^5.0.3
30+
test: ^1.21.4
31+
mockito: ^5.3.1

0 commit comments

Comments
 (0)