Skip to content

Commit 75e01f4

Browse files
authored
Create a simple WebSocket interface (#1128)
1 parent 6d9f9ef commit 75e01f4

File tree

8 files changed

+256
-22
lines changed

8 files changed

+256
-22
lines changed

.github/workflows/dart.yml

Lines changed: 82 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkgs/web_socket/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 0.1.0-wip
2+
3+
- Abstract interface definition.

pkgs/web_socket/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
TODO: Put a short description of the package here that helps potential users
2+
know whether this package might be useful for them.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void main() {
2+
// TODO: add an example.
3+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import 'dart:typed_data';
2+
3+
/// An event received from the peer through the [WebSocket].
4+
sealed class WebSocketEvent {}
5+
6+
/// Text data received from the peer through the [WebSocket].
7+
///
8+
/// See [WebSocket.events].
9+
final class TextDataReceived extends WebSocketEvent {
10+
final String text;
11+
TextDataReceived(this.text);
12+
13+
@override
14+
bool operator ==(Object other) =>
15+
other is TextDataReceived && other.text == text;
16+
17+
@override
18+
int get hashCode => text.hashCode;
19+
}
20+
21+
/// Binary data received from the peer through the [WebSocket].
22+
///
23+
/// See [WebSocket.events].
24+
final class BinaryDataReceived extends WebSocketEvent {
25+
final Uint8List data;
26+
BinaryDataReceived(this.data);
27+
28+
@override
29+
bool operator ==(Object other) {
30+
if (other is BinaryDataReceived && other.data.length == data.length) {
31+
for (var i = 0; i < data.length; ++i) {
32+
if (other.data[i] != data[i]) return false;
33+
}
34+
return true;
35+
}
36+
return false;
37+
}
38+
39+
@override
40+
int get hashCode => data.hashCode;
41+
42+
@override
43+
String toString() => 'BinaryDataReceived($data)';
44+
}
45+
46+
/// A close notification (Close frame) received from the peer through the
47+
/// [WebSocket] or a failure indication.
48+
///
49+
/// See [WebSocket.events].
50+
final class CloseReceived extends WebSocketEvent {
51+
/// A numerical code indicating the reason why the WebSocket was closed.
52+
///
53+
/// See [RFC-6455 7.4](https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4)
54+
/// for guidance on how to interpret these codes.
55+
final int? code;
56+
57+
/// A textual explanation of the reason why the WebSocket was closed.
58+
///
59+
/// Will be empty if the peer did not specify a reason.
60+
final String reason;
61+
62+
CloseReceived([this.code, this.reason = '']);
63+
64+
@override
65+
bool operator ==(Object other) =>
66+
other is CloseReceived && other.code == code && other.reason == reason;
67+
68+
@override
69+
int get hashCode => [code, reason].hashCode;
70+
71+
@override
72+
String toString() => 'CloseReceived($code, $reason)';
73+
}
74+
75+
class WebSocketException implements Exception {
76+
final String message;
77+
WebSocketException([this.message = '']);
78+
}
79+
80+
/// Thrown if [WebSocket.sendText], [WebSocket.sendBytes], or
81+
/// [WebSocket.close] is called when the [WebSocket] is closed.
82+
class WebSocketConnectionClosed extends WebSocketException {
83+
WebSocketConnectionClosed([super.message = 'Connection Closed']);
84+
}
85+
86+
/// The interface for WebSocket connections.
87+
///
88+
/// TODO: insert a usage example.
89+
abstract interface class WebSocket {
90+
/// Sends text data to the connected peer.
91+
///
92+
/// Throws [WebSocketConnectionClosed] if the [WebSocket] is
93+
/// closed (either through [close] or by the peer).
94+
///
95+
/// Data sent through [sendText] will be silently discarded if the peer is
96+
/// disconnected but the disconnect has not yet been detected.
97+
void sendText(String s);
98+
99+
/// Sends binary data to the connected peer.
100+
///
101+
/// Throws [WebSocketConnectionClosed] if the [WebSocket] is
102+
/// closed (either through [close] or by the peer).
103+
///
104+
/// Data sent through [sendBytes] will be silently discarded if the peer is
105+
/// disconnected but the disconnect has not yet been detected.
106+
void sendBytes(Uint8List b);
107+
108+
/// Closes the WebSocket connection and the [events] `Stream`.
109+
///
110+
/// Sends a Close frame to the peer. If the optional [code] and [reason]
111+
/// arguments are given, they will be included in the Close frame. If no
112+
/// [code] is set then the peer will see a 1005 status code. If no [reason]
113+
/// is set then the peer will not receive a reason string.
114+
///
115+
/// Throws a [RangeError] if [code] is not in the range 3000-4999.
116+
///
117+
/// Throws an [ArgumentError] if [reason] is longer than 123 bytes when
118+
/// encoded as UTF-8
119+
///
120+
/// Throws [WebSocketConnectionClosed] if the connection is already
121+
/// closed (including by the peer).
122+
Future<void> close([int? code, String? reason]);
123+
124+
/// A [Stream] of [WebSocketEvent] received from the peer.
125+
///
126+
/// Data received by the peer will be delivered as a [TextDataReceived] or
127+
/// [BinaryDataReceived].
128+
///
129+
/// If a [CloseReceived] event is received then the [Stream] will be closed. A
130+
/// [CloseReceived] event indicates either that:
131+
///
132+
/// - A close frame was received from the peer. [CloseReceived.code] and
133+
/// [CloseReceived.reason] will be set by the peer.
134+
/// - A failure occured (e.g. the peer disconnected). [CloseReceived.code] and
135+
/// [CloseReceived.reason] will be a failure code defined by
136+
/// (RFC-6455)[https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1]
137+
/// (e.g. 1006).
138+
///
139+
/// Errors will never appear in this [Stream].
140+
Stream<WebSocketEvent> get events;
141+
}

pkgs/web_socket/lib/web_socket.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/// TODO: write this doc string.
2+
library;
3+
4+
export 'src/web_socket.dart';

0 commit comments

Comments
 (0)