Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor - version 2.0.0+beta1 #34

Merged
merged 4 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 30 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,63 @@
# EchoX
# Whixp

![Github last build (main)][last_build]
[![License: MIT][license_badge]][license_link]
![GitHub Repo stars][star_count]

EchoX is a lightweight and pure Dart library that allows you to connect to XMPP (Extensible Messaging and Presence Protocol) servers. This package provides a range of fundamental functionalities for XMPP communication. And is built on top of the popular [Strophe.js](https://github.com/strophe/strophejs) library, providing a streamlined and efficient solution for XMPP communication in Dart applications.
Whixp is a lightweight and pure Dart library that allows you to connect to XMPP (Extensible Messaging and Presence Protocol) servers. This package provides a range of fundamental functionalities for XMPP communication.

## XMPP

XMPP is an open source standart protocol widely used for real-time communication, enabling features such as instant messaging, presence information, and contact list management. With this package, you can easily integrate XMPP capabilities into your Dart & Flutter applications, facilitating secure communication between users.

## Features

**WebSocket Connectivity**: EchoX establishes connections to XMPP servers exclusively over the WebSocket protocol, ensuring efficient and reliable communication.
**Connection Management**: Establishes secure connections to XMPP servers effortlessly. Manage connection states with ease: connect, disconnect, and handle reconnections properly.

**Authentication Mechanisms**: Provides support for various XMPP authentication mechanisms, including **SASL SCRAM** with encryption options such as SHA-1, SHA-256, SHA-384, SHA-512, XOAUTH-2, OAUTHBEARER, Anonymous, and EXTERNAL.
**Stanzas Handling**: Efficiently handles various XMPP stanzas, including IQ, message, and presence stanzas. You can customize stanza handling based on your application's requirements.

**Extensions Support**: Extensible architecture supports XMPP protocol extensions.

**Authentication Mechanisms**: Provides support for various XMPP authentication mechanisms, including **SASL SCRAM** with encryption options such as SHA-1, SHA-256, SHA-384, SHA-512, and Anonymous.

**Pluggable Architecture**: Build on top of a modular and pluggable architecture. You can easily extend and customize Whixp to fit your specific use case.

> While support for these mechanisms are available, only SHA-1, PLAIN, and SHA-256 have been tested thoroughly.

**Fundamental Functionalities**: EchoX provides a set of fundamental functionalities, including sending and retrieving messages, presence management, roster management, and more.
**Fundamental Functionalities**: Whixp provides a set of fundamental functionalities, including sending and retrieving messages, presence management, roster management, and more.

**Pure Dart implementation**: Written in pure Dart, enabling easy integration with Dart and Flutter projects.

**Lightweight**: EchoX is designed to be lightweight, providing a streamlined solution for XMPP connectivity without unnecessary dependencies or overhead.
**Lightweight**: Whixp is designed to be lightweight, providing a streamlined solution for XMPP connectivity without unnecessary dependencies or overhead.

## API

This code snippet demonstrates how to establish a connection using the `EchoX` package.
This code snippet demonstrates how to establish a connection using the `Whixp` package.

```dart
import 'package:echox/echox.dart';

void main() async {
final echox = EchoX(
service: 'ws://example.com:port/ws',
jid: JabberID(
'user',
domain: 'localhost',
resource: 'mobile',
),
password: 'somepsw',
import 'package:whixp/whixp.dart';

void main() {
final whixp = Whixp(
'vsevex@example.com/desktop',
'tester123',
host: 'example.com',
logger: Log(enableError: true, enableWarning: true),
);

debug(echox);
echox.connect();
whixp.connect();
whixp.addEventHandler('sessionStart', (_) {
whixp.getRoster();
whixp.sendPresence();
});
}
```

## Contributing to EchoX
## Contributing to Whixp

We welcome and appreciate contributions from the community to enhance the `EchoX`. If you have any improvements, bug fixes, or new features to contribute, you can do so by creating a pull request.
We welcome and appreciate contributions from the community to enhance the `Whixp`. If you have any improvements, bug fixes, or new features to contribute, you can do so by creating a pull request.

[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg
[license_link]: https://opensource.org/licenses/MIT
[star_count]: https://img.shields.io/github/stars/vsevex/echox
[last_build]: https://img.shields.io/github/actions/workflow/status/vsevex/echox/dart.yml
[star_count]: https://img.shields.io/github/stars/vsevex/whixp
[last_build]: https://img.shields.io/github/actions/workflow/status/vsevex/whixp/dart.yml
23 changes: 12 additions & 11 deletions example/main.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import 'package:echox/echox.dart';
import 'package:whixp/whixp.dart';

Future<void> main() async {
final echox = EchoX(
service: 'ws://localhost:5443/ws',
jid: JabberID(
'user',
domain: 'localhost',
resource: 'mobile',
),
password: 'somepsw',
void main() {
final whixp = Whixp(
'alyosha@example.com/desktop',
'alyosha13',
host: 'example.com',
logger: Log(enableError: true, enableWarning: true),
);

echox.connect();
whixp.connect();
whixp.addEventHandler('sessionStart', (_) {
whixp.getRoster();
whixp.sendPresence();
});
}
65 changes: 52 additions & 13 deletions lib/src/client.dart
Original file line number Diff line number Diff line change
@@ -1,30 +1,68 @@
part of 'whixp.dart';

class Whixp extends WhixpBase {
/// Client class for [Whixp].
///
/// Extends [WhixpBase] class and represents an XMPP client with additional
/// functionalities.
///
/// ### Example:
/// ```dart
/// final whixp = Whixp('vsevex@example.com', 'passwd');
/// whixp.connect();
/// ```
Whixp(
/// Jabber ID associated with the client
String jabberID,

/// Password for authenticating the client.
String password, {
/// Server host address
super.host,

/// Port number for the server
super.port,

/// If set to `true`, attempt to use IPv6
super.useIPv6,
super.useTLS = true,

/// DirectTLS activator. Defaults to `false`
super.useTLS = false,

/// Disable StartTLS for secure communication. Defaults to `false`
super.disableStartTLS,

/// Default language to use in stanza communication
String language = 'en',

/// [List] of paths to a file containing certificates for verifying the
/// server TLS certificate
super.certs,
this.language = 'en',

/// [Log] instance to print out various log messages properly
super.logger,

/// Timeout for establishing the connection (in milliseconds). Defaults to
/// `2000`
super.connectionTimeout,

/// Maximum number of reconnection attempts. Defaults to `3`
super.maxReconnectionAttempt,
}) : super(jabberID: jabberID) {
setup();
_language = language;

/// Automatically calls the `_setup()` method to configure the XMPP client.
_setup();

credentials.addAll({'password': password});
}

void setup() {
reset();
void _setup() {
_reset();

/// Set [streamHeader] of declared transport for initial send.
transport.streamHeader =
"<stream:stream to='${transport.boundJID.host}' xmlns:stream='$streamNamespace' xmlns='$defaultNamespace' xml:lang='$language' version='1.0'>";
"<stream:stream to='${transport.boundJID.host}' xmlns:stream='$streamNamespace' xmlns='$defaultNamespace' xml:lang='$_language' version='1.0'>";
transport.streamFooter = "</stream:stream>";

StanzaBase features = StreamFeatures();
Expand All @@ -45,7 +83,7 @@ class Whixp extends WhixpBase {
FutureCallbackHandler(
'Stream Features',
(stanza) async {
features = features.copy(stanza.element);
features = features.copy(element: stanza.element);
_handleStreamFeatures(features);
return;
},
Expand All @@ -61,15 +99,13 @@ class Whixp extends WhixpBase {
(stanza) => _handleRoster(stanza!),
);

transport.defaultLanguage = language;
transport.defaultLanguage = _language;
}

void reset() {
streamFeatureHandlers.clear();
}
void _reset() => streamFeatureHandlers.clear();

/// Default language to use in stanza communication.
final String language;
late final String _language;

Future<bool> _handleStreamFeatures(StanzaBase features) async {
for (final feature in streamFeatureOrder) {
Expand Down Expand Up @@ -111,7 +147,6 @@ class Whixp extends WhixpBase {
}

final items = stanza['items'] as Map<String, Map<String, dynamic>>;
print('items is $items');

final validSubs = {'to', 'from', 'both', 'none', 'remove'};
for (final item in items.entries) {
Expand Down Expand Up @@ -140,5 +175,9 @@ class Whixp extends WhixpBase {
}
}

/// Connects to the server.
///
/// When no address is given, a SRV lookup for the server will be attempted.
/// If that fails, the server user in the JID will be used.
void connect() => transport.connect();
}
7 changes: 0 additions & 7 deletions lib/src/echotils/README.md

This file was deleted.

6 changes: 0 additions & 6 deletions lib/src/echotils/echotils.dart

This file was deleted.

87 changes: 70 additions & 17 deletions lib/src/exception.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:echox/src/stream/base.dart';
import 'package:whixp/src/stream/base.dart';

/// The given given class is a custom written [Exception] class for [Whixp].
///
Expand All @@ -14,55 +14,92 @@ import 'package:echox/src/stream/base.dart';
abstract class WhixpException implements Exception {
/// Constructs an [WhixpException] object with the provided [message] and
/// [code].
const WhixpException(this.message, [this.code]);

/// An optional [int] representing the error code associated with the
/// exception. If not provided, it defaults to `null`.
final int? code;
const WhixpException(this.message);

/// A [String] containing the error message associated with the exception.
final String message;

@override
String toString() =>
'''Whixp Exception: $message${code != null ? ' (code: $code)' : ''} ''';
String toString() => '''Whixp Exception: $message''';
}

/// Represents an exception related to XMPP stanzas within the context of the
/// [Whixp].
///
/// ### Example:
/// ```dart
/// try {
/// // ...some XMPP-related code that may throw StanzaException
/// } catch (error) {
/// if (error is StanzaException) {
/// print('Stanza Exception: ${error.toString()}');
/// }
/// }
/// ```
class StanzaException extends WhixpException {
/// Creates a [StanzaException] with the specified error message, stanza, and
/// optional details.
StanzaException(
/// The error message associated with the exception
super.message,

/// The XMPP stanza associated with the exception
this.stanza, {
/// Additional text information from the stanza related to the exception
this.text = '',

/// The condition associated with the exception, defaults to
/// 'undefined-condition'
this.condition = 'undefined-condition',

/// The type of error associated with the exception, defaults to 'cancel'
this.errorType = 'cancel',
});

/// The error message associated with the exception.
final String text;

/// The condition associated with the exception.
final String condition;

/// The type of error associated with the exception.
final String errorType;

/// The XMPP stanza associated with the exception.
final XMLBase stanza;

/// Creates a [StanzaException] for a timed-out response from the server.
factory StanzaException.timeout(StanzaBase stanza) => StanzaException(
'Waiting for response from the server is timed out',
stanza,
condition: 'remote-server-timeout',
);

/// Creates a [StanzaException] for a received service unavailable stanza.
factory StanzaException.serviceUnavailable(StanzaBase stanza) =>
StanzaException(
'Received service unavailable stanza',
stanza,
condition: stanza['condition'] as String,
);
factory StanzaException.iq(XMLBase stanza) {
return StanzaException(
'IQ error is occured',
stanza,
text: stanza['text'] as String,
condition: stanza['condition'] as String,
errorType: stanza['type'] as String,
);
}

/// Creates a [StanzaException] for an IQ error with additional details.
factory StanzaException.iq(XMLBase iq) => StanzaException(
'IQ error has occured',
iq,
text: (iq['error'] as XMLBase)['text'] as String,
condition: (iq['error'] as XMLBase)['condition'] as String,
errorType: (iq['error'] as XMLBase)['type'] as String,
);

/// Creates a [StanzaException] for an IQ timeout.
factory StanzaException.iqTimeout(XMLBase iq) => StanzaException(
'IQ timeout has occured',
iq,
condition: 'remote-server-timeout',
);

/// Formats the exception details.
String get _format {
final text = StringBuffer('$errorType: $condition');

Expand All @@ -73,6 +110,8 @@ class StanzaException extends WhixpException {
return text.toString();
}

/// Overrides the [toString] method to provide a formatted string
/// representation of the exception.
@override
String toString() => _format;
}
Expand All @@ -92,7 +131,21 @@ class StringPreparationException extends WhixpException {
StringPreparationException(message);
}

/// Represents an exception related to SASL (Simple Authentication and Security
/// Layer) mechanisms within the context of the [Whixp].
///
/// ### Example:
/// ```dart
/// try {
/// // ...some SASL-related code that may throw SASLException
/// } catch (error) {
/// if (error is SASLException) {
/// log('SASL Exception: ${e.message}');
/// }
/// }
/// ```
class SASLException extends WhixpException {
/// Creates a [SASLException] with the specified error message.
SASLException(super.message);

factory SASLException.cancelled(String message) => SASLException(message);
Expand Down
Loading
Loading