forked from sefidgaran/signalr_client
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Vladyslav Hupalo
committed
Aug 30, 2023
1 parent
8c93dac
commit 84e583b
Showing
12 changed files
with
338 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:signalr_netcore/sse_channel/src/channel.dart'; | ||
import 'package:sse/client/sse_client.dart'; | ||
import 'package:stream_channel/stream_channel.dart'; | ||
|
||
class HtmlSseChannel extends StreamChannelMixin implements SseChannel { | ||
HtmlSseChannel(this.client); | ||
|
||
factory HtmlSseChannel.connect(Uri url) { | ||
return HtmlSseChannel(SseClient(url.toString())); | ||
} | ||
|
||
final SseClient client; | ||
|
||
@override | ||
StreamSink get sink => client.sink; | ||
|
||
@override | ||
Stream get stream => client.stream; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import 'dart:async'; | ||
import 'dart:convert'; | ||
|
||
import 'package:http/http.dart'; | ||
import 'package:pool/pool.dart'; | ||
import 'package:signalr_netcore/sse_channel/src/channel.dart'; | ||
import 'package:stream_channel/stream_channel.dart'; | ||
import 'package:uuid/uuid.dart'; | ||
|
||
import 'src/event_source_transformer.dart'; | ||
|
||
final _requestPool = Pool(1000); | ||
|
||
typedef OnConnected = void Function(); | ||
|
||
class IOSseChannel extends StreamChannelMixin implements SseChannel { | ||
int _lastMessageId = -1; | ||
final Uri _serverUrl; | ||
final String _clientId; | ||
late final StreamController<String?> _incomingController; | ||
late final StreamController<String?> _outgoingController; | ||
final _onConnected = Completer(); | ||
|
||
StreamSubscription? _incomingSubscription; | ||
StreamSubscription? _outgoingSubscription; | ||
|
||
@override | ||
StreamSink get sink => _outgoingController.sink; | ||
|
||
@override | ||
Stream get stream => _incomingController.stream; | ||
|
||
factory IOSseChannel.connect(Uri url) { | ||
return IOSseChannel._(url); | ||
} | ||
|
||
IOSseChannel._(Uri serverUrl) | ||
: _serverUrl = serverUrl, | ||
_clientId = Uuid().v4(), | ||
_outgoingController = StreamController<String?>() { | ||
_incomingController = StreamController<String?>.broadcast( | ||
onListen: () => _initialize(), | ||
onCancel: () => _stop(), | ||
); | ||
|
||
_onConnected.future.whenComplete(() { | ||
return _outgoingSubscription = | ||
_outgoingController.stream.listen(_onOutgoingMessage); | ||
}); | ||
} | ||
|
||
Future<void> _initialize() async { | ||
final queryParameters = Map<String, String>(); | ||
queryParameters.addAll({'sseClientId': _clientId}); | ||
queryParameters.addAll(_serverUrl.queryParameters); | ||
|
||
final request = Request( | ||
'GET', | ||
_serverUrl.replace(queryParameters: queryParameters), | ||
)..headers['Accept'] = 'text/event-stream'; | ||
|
||
await Client().send(request).then((response) { | ||
if (response.statusCode == 200) { | ||
_incomingSubscription = | ||
response.stream.transform(EventSourceTransformer()).listen((event) { | ||
_incomingController.sink.add(event.data); | ||
}); | ||
|
||
_onConnected.complete(); | ||
} else { | ||
_incomingController.addError( | ||
SseClientException('Failed to connect to $_serverUrl'), | ||
); | ||
} | ||
}); | ||
} | ||
|
||
void _stop() { | ||
_incomingSubscription?.cancel(); | ||
_outgoingSubscription?.cancel(); | ||
_incomingController.sink.close(); | ||
_incomingController.close(); | ||
_outgoingController.sink.close(); | ||
_outgoingController.close(); | ||
} | ||
|
||
Future<void> _onOutgoingMessage(String? message) { | ||
String? encodedMessage; | ||
|
||
return _requestPool.withResource(() async { | ||
try { | ||
encodedMessage = jsonEncode(message); | ||
} on JsonUnsupportedObjectError { | ||
//_logger.warning('[$_clientId] Unable to encode outgoing message: $e'); | ||
} on ArgumentError { | ||
//_logger.warning('[$_clientId] Invalid argument: $e'); | ||
} | ||
|
||
try { | ||
final url = | ||
'$_serverUrl?sseClientId=$_clientId&messageId=${_lastMessageId++}'; | ||
await post(Uri.parse(url), body: encodedMessage); | ||
} catch (error) { | ||
//final augmentedError = | ||
// '[$_clientId] SSE client failed to send $message:\n $error'; | ||
//_logger.severe(augmentedError); | ||
//_closeWithError(augmentedError); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
class SseClientException implements Exception { | ||
final String message; | ||
|
||
const SseClientException(this.message); | ||
|
||
@override | ||
String toString() { | ||
return 'SseClientException: $message'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import 'channel.dart'; | ||
|
||
/// Creates a new Server Sent Events connection. | ||
SseChannel connect(Uri url) { | ||
throw UnsupportedError('No implementation of the connect api provided'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import 'package:signalr_netcore/sse_channel/html.dart'; | ||
|
||
import 'channel.dart'; | ||
|
||
SseChannel connect(Uri url) => HtmlSseChannel.connect(url); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
import 'package:signalr_netcore/sse_channel/io.dart'; | ||
|
||
import 'channel.dart'; | ||
|
||
SseChannel connect(Uri url) => IOSseChannel.connect(url); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import 'package:stream_channel/stream_channel.dart'; | ||
|
||
// ignore: uri_does_not_exist | ||
import '_connect_api.dart' | ||
// ignore: uri_does_not_exist | ||
if (dart.library.html) '_connect_html.dart' | ||
// ignore: uri_does_not_exist | ||
if (dart.library.io) '_connect_io.dart' as platform; | ||
|
||
abstract class SseChannel extends StreamChannelMixin { | ||
factory SseChannel.connect(Uri url) => platform.connect(url); | ||
} |
Oops, something went wrong.