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

Feature/blip chat sdk #10

Merged
merged 7 commits into from
Nov 7, 2022
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
2 changes: 1 addition & 1 deletion .fvm/fvm_config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"flutterSdkVersion": "3.0.4",
"flutterSdkVersion": "3.3.5",
"flavors": {}
}
24 changes: 24 additions & 0 deletions assets/keys/certificate.cer
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIUczUTebcj+DOcv4SFWOJR+kJt8k8wDQYJKoZIhvcNAQEL
BQAwgagxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
Ew1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBDbG91ZGZsYXJlLCBJbmMuMRswGQYD
VQQLExJ3d3cuY2xvdWRmbGFyZS5jb20xNDAyBgNVBAMTK01hbmFnZWQgQ0EgOWVi
NzNlOWI3NTQzMWJkNTZiZmQ2MjQ4YmJhMzMxMDQwHhcNMjIwOTE0MTkxOTAwWhcN
MzcwOTEwMTkxOTAwWjAiMQswCQYDVQQGEwJVUzETMBEGA1UEAxMKQ2xvdWRmbGFy
ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5BLR5zXpq8X4uRd6yD
nYCk0c735kFtuvkzJv/dXroWDQCz5pfHHjmXW0mBtGUV4CyowKymVakjQd6iSeDP
SVkUqMjXbgQ2wYMnlJF3hJKREe9RcEa5vJOu/tJFuUDf/fMWlQJSbH1MyoC1uBRX
wSE96oxZU6EDvluroq7roZX3oaK36EwK2AKCRxlzjjS3FnMxpH1nNh+EdWgsNqi2
+Qmr3+DKhZMgR6FsZ8XlwnJVMS8pJxDLwN11HMXpeorg9BblYBRR5UHQoqIgM2qD
jZiprnpEfn2Kp1Qh6cjwfy49BrC4rBQJSnEZJGCkpVg0+OkU/rI/GdQSPdIfbZ+A
VzUCAwEAAaOBuzCBuDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA
MB0GA1UdDgQWBBRvDaKkJ7HxmZSSxXyguiOMw37JYjAfBgNVHSMEGDAWgBQm6tVr
jXZOViYsrBOCio26eL+hoDBTBgNVHR8ETDBKMEigRqBEhkJodHRwOi8vY3JsLmNs
b3VkZmxhcmUuY29tL2Y2ZjRhMzhlLTI5MjgtNGQxNy05M2I4LWZhNWU4ZTIyNjIw
Mi5jcmwwDQYJKoZIhvcNAQELBQADggEBACWzu7Q7CyW/ObuUisTGKhVTwbd0pNs2
vGTDj5Ue1Sn2+9Vc5FuQsENS05S74039hiQKV0KYRZMxsAqbcPayFbqEsqsw7kmd
Iz5E0n4iQGhKUukWBCd9VcSwaKhZans8ZHpUzIUuUMVD3mLkZClAnj/7PZk+hje2
JhTaf4mpKM1qjnXa2ImFpjBxINrO9jDwD9/dIODfyFFT4qR5QcJOZeCEoiR4tQmq
ybG26DzIjk55HaoaP46gN/vsfmXz2t0SqVmjFiT7+18PwQW4QMkzpq0keEJlqJIN
lAYEiYblRMliNqo1ysjL8M336n9zw8LisI7SSRv4Ci/LENTuM0xXnm0=
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions assets/keys/private.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDeQS0ec16avF+L
kXesg52ApNHO9+ZBbbr5Myb/3V66Fg0As+aXxx45l1tJgbRlFeAsqMCsplWpI0He
okngz0lZFKjI124ENsGDJ5SRd4SSkRHvUXBGubyTrv7SRblA3/3zFpUCUmx9TMqA
tbgUV8EhPeqMWVOhA75bq6Ku66GV96Git+hMCtgCgkcZc440txZzMaR9ZzYfhHVo
LDaotvkJq9/gyoWTIEehbGfF5cJyVTEvKScQy8DddRzF6XqK4PQW5WAUUeVB0KKi
IDNqg42Yqa56RH59iqdUIenI8H8uPQawuKwUCUpxGSRgpKVYNPjpFP6yPxnUEj3S
H22fgFc1AgMBAAECggEAZCUGCYR+ikZ63s6LGAat/3tEtndpHu4so4Dy/7NlrX+m
GDz3mEg2TEjw7ywsdqfmvPjE6IaCbpXeZkzF8TA1opf2fZjkj62EgG5jOTCbYddQ
N3+Akb27ROhDFcgo8xx6tv/j4In3LHZfgKNg8HmiIjJd7yOI1TJ0oaWyxhKSWpnF
GeGtBSwKJEICTKalAzR8TclEYIhFHffdHrvUwoj4Yge03tF3HjLOi+cWUx6e6NEt
KcuulsV6lQM028KKGdumVX0xxTdX4hmR2ygjKM6SzIL3XmAcX6NkFC+3ub+sVjCz
cX5ouPHsCT2/M1bu1w0g9ybChVaH4ZISJyoDHFaeuQKBgQDwNiZzRAWKSin7yAJS
m3R1dOWS8oYwWJKXck/tPfpt+YXqyUfQ/u5HNTtfn5DfJLlI5/AfBTT2+X/w4w8v
ytIVefLS7+hU0CZVIT3/Y82ky/N5qwGN12TXylCtJJC8w64dNG4ULfNRdNGnwaoq
AHB8YxKNl9HMBFKFYJMQuhWoRwKBgQDs3OEDyZxpryd/2PNF4a/Lige8o3n3fQF6
umYzNBI4nFzBhe9vNhVr8tgMuaoNql5ApKJbt0okQOAftM6xodtfh+KxdmDQ8oLK
BVS4TytuibOFF3ZyFOOzxBxHHnm/sgAZgstl0GPZBVlb15qrNspUS9MYADg8+aN/
AiX14uM+owKBgQDEakK+dZxiG4qAyma7zUlI0bD2m0CGP6Z+F4arYsZnLmUGOldy
2UFVEH3gDsWS8KBgsOZzNvq8B/9JpSBB4AIwdWrMeEbtMtZlPa1IKv94BRytG9tF
dB6NJG0bZo7DCu5QCxMHhRs0O+VC2uSdO4a+7vO4u69ctxwS24jlYINc+QKBgQCb
t5ZilA+1VwZDwZAld/rHeAYgGOUdNFxdn9+CeBAmkX1VaMUBOvAYWL16mDDY7REr
tFBctYITlWcC0S41j3AWPNJm0qlRlK0xPRH2XW3zLKoNrGAdHeiYjSv+AWYPBWmV
W+x2EesiiKa3f2Xae5nGk1bC55oRVBkNbY8hOLkmuwKBgQDHXFdCQFpG+Rg3XI69
RH2aEYqhqZNx6vOrN1BPKRJo85gLb27w2FP5a3v440YdJAoN+BGpk+CzrGtqj5SC
kaRWqlDC6zLBQkTmp1DhgR8/OJcg3eYM8ALLSq3DdwUTHQU+cH5mCixmrJiCc1Eh
K4WUZQ9rWiFnjy0W3gNwhDY67A==
-----END PRIVATE KEY-----
27 changes: 19 additions & 8 deletions lib/lime.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ library lime;

export 'src/protocol/guid.dart' show guid;
export 'src/protocol/extensions/string.extension.dart' show StringExtension;
export 'src/protocol/extensions/notification_event.extension.dart' show NotificationEventExtension;
export 'src/protocol/extensions/notification_event.extension.dart'
show NotificationEventExtension;
export 'src/protocol/command.dart' show Command;
export 'src/protocol/document.dart' show Document;
export 'src/protocol/envelope.dart' show Envelope;
Expand All @@ -16,7 +17,8 @@ export 'src/protocol/reason.dart' show Reason;
export 'src/protocol/enums/command_method.enum.dart' show CommandMethod;
export 'src/protocol/enums/command_status.enum.dart' show CommandStatus;
export 'src/protocol/enums/notification_event.enum.dart' show NotificationEvent;
export 'src/protocol/enums/session_compression.enum.dart' show SessionCompression;
export 'src/protocol/enums/session_compression.enum.dart'
show SessionCompression;
export 'src/protocol/enums/session_encryption.enum.dart' show SessionEncryption;
export 'src/protocol/enums/session_state.enum.dart' show SessionState;
export 'src/protocol/enums/presence_status.enum.dart' show PresenceStatus;
Expand All @@ -30,13 +32,22 @@ export 'src/protocol/identity.dart' show Identity;
export 'src/protocol/session.dart' show Session;
export 'src/protocol/presence.dart' show Presence;
export 'src/protocol/security/authentication.dart' show Authentication;
export 'src/protocol/security/guest_authentication.dart' show GuestAuthentication;
export 'src/protocol/security/guest_authentication.dart'
show GuestAuthentication;
export 'src/protocol/security/key_authentication.dart' show KeyAuthentication;
export 'src/protocol/security/external_authentication.dart' show ExternalAuthentication;
export 'src/protocol/security/plain_authentication.dart' show PlainAuthentication;
export 'src/protocol/security/transport_authentication.dart' show TransportAuthentication;
export 'src/protocol/security/enums/authentication_scheme.enum.dart' show AuthenticationScheme;
export 'src/protocol/security/external_authentication.dart'
show ExternalAuthentication;
export 'src/protocol/security/plain_authentication.dart'
show PlainAuthentication;
export 'src/protocol/security/transport_authentication.dart'
show TransportAuthentication;
export 'src/protocol/security/enums/authentication_scheme.enum.dart'
show AuthenticationScheme;
export 'package:lime/src/protocol/extensions/authentication_schema.extension.dart'
show AuthenticationSchemaExtension;
export 'src/protocol/client/client_channel.dart' show ClientChannel;
export 'src/protocol/network/transport.dart' show Transport;
export 'src/protocol/network/web_socket_transport.dart' show WebSocketTransport;
export 'src/protocol/network/lime.exception.dart' show LimeException;
export 'src/protocol/exceptions/lime.exception.dart' show LimeException;
export 'src/protocol/exceptions/insecure_socket.exception.dart'
show InsecureSocketException;
20 changes: 17 additions & 3 deletions lib/src/protocol/client/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ abstract class Channel {
state = SessionState.isNew;

// Start listening to the stream
transport.onEvelope?.stream.listen(
transport.onEnvelope?.stream.listen(
(event) {
if (event.containsKey('state')) {
logger.info('Received envelope is a Session');
Expand All @@ -63,7 +63,10 @@ abstract class Channel {
logger.info('Received envelope is a Command');
final command = Command.fromJson(event);

if (autoReplyPings && command.uri == '/ping' && command.method == CommandMethod.get && isForMe(command)) {
if (autoReplyPings &&
command.uri == '/ping' &&
command.method == CommandMethod.get &&
isForMe(command)) {
logger.info('Auto reply ping..');

final commandSend = Command(
Expand Down Expand Up @@ -93,6 +96,11 @@ abstract class Channel {
onError: (e) => logger.shout('stream error: $e'),
onDone: () => logger.info('stream done'),
);

//Start listening to onConnectionDone Stream
transport.onConnectionDone?.stream.listen((bool closed) {
onCloseConnection(closed);
});
}

/// Open the connection with the transport
Expand Down Expand Up @@ -152,7 +160,10 @@ abstract class Channel {
bool isForMe(Envelope envelope) {
return envelope.to == null ||
envelope.to.toString() == localNode?.toString() ||
localNode?.toString().substring(0, envelope.to.toString().length).toLowerCase() ==
localNode
?.toString()
.substring(0, envelope.to.toString().length)
.toLowerCase() ==
envelope.to.toString().toLowerCase();
}

Expand All @@ -167,4 +178,7 @@ abstract class Channel {

/// A function that will be executed when an [Envelope] of type [Command] is received by the [Transport] layer
void onCommand(Command command) {}

/// A function that will be executed when the server close the connection
void onCloseConnection(bool closed) {}
}
14 changes: 12 additions & 2 deletions lib/src/protocol/client/client_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class ClientChannel extends Channel {
/// Exposes a [StreamController] to allow listening when a new [Session] with [SessionState.failed] type is received by the channel
final onSessionFailed = StreamController<Session>();

/// Exposes a [StreamController] to allow listening when the server closes the connection
final onConnectionDone = StreamController<bool>();

/// A function that will be completed when a [Session] of type [SessionState.authenticating] is received
late Function(Session) _onSessionAuthenticating;

Expand All @@ -51,7 +54,8 @@ class ClientChannel extends Channel {
late Function(Session) _onSessionFinished;

/// Establishes the session
Future<Session> establishSession(String identity, String instance, Authentication authentication) async {
Future<Session> establishSession(
String identity, String instance, Authentication authentication) async {
Session session = await startNewSession();
session = await authenticateSession(identity, instance, authentication);

Expand Down Expand Up @@ -144,7 +148,8 @@ class ClientChannel extends Channel {
}

/// Send a [Session] type [Envelope] with state [SessionState.authenticating] to start the authenticate
Future<Session> authenticateSession(String identity, String instance, Authentication authentication) async {
Future<Session> authenticateSession(
String identity, String instance, Authentication authentication) async {
if (state != SessionState.authenticating) {
throw Exception('Cannot authenticate a session in the $state state.');
}
Expand Down Expand Up @@ -237,4 +242,9 @@ class ClientChannel extends Channel {
void onMessage(Message message) {
onReceiveMessage.sink.add(message);
}

@override
void onCloseConnection(bool closed) {
onConnectionDone.sink.add(closed);
}
}
20 changes: 7 additions & 13 deletions lib/src/protocol/command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Command extends Envelope {
dynamic resource;

/// Action to be taken to the resource
CommandMethod? method;
CommandMethod method;

/// Indicates the status of the action taken to the resource
CommandStatus? status = CommandStatus.pending;
Expand All @@ -42,7 +42,7 @@ class Command extends Envelope {
final Node? pp,
final Map<String, dynamic>? metadata,
this.uri,
this.method,
required this.method,
this.reason,
this.resource,
this.status,
Expand All @@ -54,6 +54,7 @@ class Command extends Envelope {
Map<String, dynamic> command = {};

command[Envelope.idKey] = id;
command[methodKey] = describeEnum(method);

if (from != null) {
command[Envelope.fromKey] = from.toString();
Expand All @@ -71,10 +72,6 @@ class Command extends Envelope {
command[Envelope.metadataKey] = metadata;
}

if (method != null) {
command[methodKey] = describeEnum(method!);
}

if (status != null) {
command[statusKey] = describeEnum(status!);
}
Expand Down Expand Up @@ -108,20 +105,17 @@ class Command extends Envelope {
to: envelope.to,
pp: envelope.pp,
metadata: envelope.metadata,
method: json[methodKey] != null
? CommandMethod.values.firstWhere((e) => describeEnum(e) == json[methodKey])
: CommandMethod.unknown,
);

if (json.containsKey(reasonKey)) {
command.reason = Reason.fromJson(json[reasonKey]);
}

if (json.containsKey(statusKey)) {
command.status = CommandStatus.values
.firstWhere((e) => describeEnum(e) == json[statusKey]);
}

if (json.containsKey(methodKey)) {
command.method = CommandMethod.values
.firstWhere((e) => describeEnum(e) == json[methodKey]);
command.status = CommandStatus.values.firstWhere((e) => describeEnum(e) == json[statusKey]);
}

if (json.containsKey(uriKey)) {
Expand Down
2 changes: 2 additions & 0 deletions lib/src/protocol/enums/command_method.enum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ enum CommandMethod {

/// Merges the resource document with an existing one. If the resource doesn't exists, it is created.
merge,

unknown,
}
24 changes: 13 additions & 11 deletions lib/src/protocol/enums/notification_event.enum.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
enum NotificationEvent {
/// A problem occurred during the processing of the message.
failed,
export 'package:lime/src/protocol/extensions/notification_event.extension.dart';

enum NotificationEvent {
/// The message was received and accepted by the server.
/// This event is similar to the <see cref="Received"/> but is emitted by an intermediate node (hop) and not by the message's final destination.
accepted,

/// The message format was validated by the server.
@Deprecated("This specific event should not be sent anymore")
validated,

/// The dispatch of the message was authorized by the server.
@Deprecated("This specific event should not be sent anymore")
authorized,

/// The message was dispatched to the destination by the server.
/// This event is similar to the <see cref="Consumed"/> but is emitted by an intermediate node (hop) and not by the message's final destination.
dispatched,
Expand All @@ -24,5 +15,16 @@ enum NotificationEvent {
/// The node has consumed the content of the message.
consumed,

/// A problem occurred during the processing of the message.
failed,

/// The message format was validated by the server.
@Deprecated("This specific event should not be sent anymore")
validated,

/// The dispatch of the message was authorized by the server.
@Deprecated("This specific event should not be sent anymore")
authorized,

unknown,
}
3 changes: 2 additions & 1 deletion lib/src/protocol/envelope.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'guid.dart';
import 'media_type.dart';
import 'node.dart';

Expand Down Expand Up @@ -34,7 +35,7 @@ class Envelope {
/// Allows converting a collection of key/value pairs, [Map] to a [Envelope] object
factory Envelope.fromJson(Map<String, dynamic> json) {
return Envelope(
id: json.containsKey(idKey) ? json[idKey] : null,
id: json.containsKey(idKey) ? json[idKey] : guid(),
from: json.containsKey(fromKey) ? Node.parse(json[fromKey]) : null,
to: json.containsKey(toKey) ? Node.parse(json[toKey]) : null,
pp: json.containsKey(ppKey) ? Node.parse(json[ppKey]) : null,
Expand Down
9 changes: 9 additions & 0 deletions lib/src/protocol/exceptions/insecure_socket.exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class InsecureSocketException implements Exception {
String message;

InsecureSocketException(this.message);

Map<String, dynamic> toJson() => {
'message': message,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:flutter/foundation.dart';
import 'package:lime/lime.dart';

extension AuthenticationSchemaExtension on AuthenticationScheme {
AuthenticationScheme getValue(String? value) =>
AuthenticationScheme.values.firstWhere((e) => describeEnum(e) == value,
orElse: () => AuthenticationScheme.unknown);
}
15 changes: 14 additions & 1 deletion lib/src/protocol/extensions/notification_event.extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ import 'package:flutter/foundation.dart';
import '../enums/notification_event.enum.dart';

extension NotificationEventExtension on NotificationEvent {
NotificationEvent getValue(String value) =>
NotificationEvent getValue(String? value) =>
NotificationEvent.values.firstWhere((e) => describeEnum(e) == value, orElse: () => NotificationEvent.unknown);

bool isLowerThan(NotificationEvent? other) {
const events = {
NotificationEvent.accepted: 0,
NotificationEvent.dispatched: 1,
NotificationEvent.received: 2,
NotificationEvent.consumed: 3,
NotificationEvent.failed: 4,
NotificationEvent.unknown: 99,
};

return (events[this] ?? 99) < (events[other ?? NotificationEvent.unknown] ?? 99);
}
}
9 changes: 4 additions & 5 deletions lib/src/protocol/identity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,13 @@ class Identity implements IIdentity {
}

/// Tries to parse the string to a valid Identity.
static bool tryParse(
String s,
static Identity? tryParse(
String? s,
) {
try {
parse(s);
return true;
return parse(s);
} catch (e) {
return false;
return null;
}
}

Expand Down
5 changes: 4 additions & 1 deletion lib/src/protocol/network/envelope_listener.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ import 'dart:async';

class EnvelopeListener {
/// A [StreamController] to allow listening when a new envelope is received by the websocket
StreamController<Map<String, dynamic>>? onEvelope;
StreamController<Map<String, dynamic>>? onEnvelope;

/// A [StreamController] to allow listening when server close the connection
StreamController<bool>? onConnectionDone;
}
Loading