From 00e6d660af1cf34ab3cf785de3d1f6ed17ed2eb2 Mon Sep 17 00:00:00 2001 From: AyushChothe <40957514+AyushChothe@users.noreply.github.com> Date: Thu, 9 Jun 2022 01:00:11 +0530 Subject: [PATCH] Type System Simplified --- CHANGELOG.md | 6 +++ README.md | 15 +++--- polo_client/example/polo_client_example.dart | 49 ++++++++---------- polo_client/lib/polo_client.dart | 1 + polo_client/lib/src/polo_client_stub.dart | 8 ++- polo_client/lib/src/polo_io_client_base.dart | 33 ++++++++---- polo_client/lib/src/polo_type.dart | 12 ++++- polo_client/lib/src/polo_web_client_base.dart | 34 +++++++++---- polo_client/pubspec.yaml | 2 +- polo_server/example/polo_server_example.dart | 50 +++++++------------ polo_server/lib/polo_server.dart | 1 + polo_server/lib/src/polo_client_base.dart | 31 ++++++++---- polo_server/lib/src/polo_server_base.dart | 10 +++- polo_server/lib/src/polo_type.dart | 12 ++++- polo_server/pubspec.yaml | 2 +- 15 files changed, 164 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb03dc7..06c77e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.0.3 + +- Typed Events Added (`PoloType` and `PoloTypeAdapter`) +- Rooms Feature Added +- Broadcast Feature Added + ## 0.0.2+2 - Flutter Web Support Added diff --git a/README.md b/README.md index 9edb877..2c4716e 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,15 @@ - **Multi-Platform** - `Android`, `IOS`, `Windows`, `Linux`, `macOS`, `Web`. -- **Easy to Use API** +- **Typed Events** + - Refer `PoloType` and `PoloTypeAdapter`. - **Library Officially Available in Multiple Programming Languages** + - `Dart`, `TypeScript`. +- **Easy to Use API** ## 📖 Getting Started -### **Baic Chat App** +### **Basic Chat App** - Server Code (Dart) @@ -30,8 +33,8 @@ server.onClientConnect((client) { print("Client(${client.id}) Connected!"); - client.onEvent('message', - (message) => server.broadcastFrom(client.id, 'message', message)); + client.onEvent('message', + (message) => server.broadcastFrom(client, 'message', message)); }); server.onClientDisconnect((client) { @@ -53,7 +56,7 @@ print("Client Disconnected from Server"); }); - client.onEvent('message', (message) { + client.onEvent('message', (message) { print("$message"); }); @@ -74,7 +77,7 @@ client.onDisconnect(() => { console.log("Client Disconnected from Server"); }); -client.onEvent("message", (message) => { +client.onEvent("message", (message) => { console.log(`${message}`); }); diff --git a/polo_client/example/polo_client_example.dart b/polo_client/example/polo_client_example.dart index 658be85..cbd82a1 100644 --- a/polo_client/example/polo_client_example.dart +++ b/polo_client/example/polo_client_example.dart @@ -1,16 +1,13 @@ -import 'dart:io'; - import 'package:polo_client/polo_client.dart'; -import 'package:polo_client/src/polo_type.dart'; class UserType implements PoloType { - String? name; - int? age; + final String name; + final int age; - UserType({this.name, this.age}); + UserType({required this.name, required this.age}); @override - UserType fromMap(Map map) { + factory UserType.fromMap(Map map) { return UserType(name: map['name'], age: map['age']); } @@ -21,30 +18,25 @@ class UserType implements PoloType { } void main() async { - stdout.write("Enter Room to join: "); - // String room = stdin.readLineSync() ?? "root"; - // Polo Client PoloClient client = await Polo.connect("ws://127.0.0.1:3000/"); - // PoloClient client = - // await Polo.connect("ws://polo-chat-server.herokuapp.com/"); - - // Future getInput() async { - // stdin.listen((msg) { - // client.send('message', String.fromCharCodes(msg).trim()); - // // client.send('messageToRoom', - // // {"room": room, "message": String.fromCharCodes(msg).trim()}); - // }); - // } + client.registerType( + PoloTypeAdapter( + toMap: ((type) => type.toMap()), + fromMap: (map) => UserType.fromMap(map), + ), + ); client.onConnect(() { print("Client Connected to Server"); + client.send('dynamic', "Ayush"); client.send('dynamic', 1); client.send('dynamic', 3.14); client.send('dynamic', true); client.send('dynamic', [1, 2, 3]); + client.send('dynamic', null); client.send('dynamic', { "String": {"dynamic": true} }); @@ -52,22 +44,21 @@ void main() async { client.send('userJoined', UserType(name: "Ayush", age: 22)); }); - client.onDisconnect(() { - print("Client Disconnected from Server"); - }); - client.onEvent('dynamic', (dyn) { - stdout.writeln("Dynamic: $dyn : ${dyn.runtimeType}"); + print("Dynamic: $dyn : ${dyn.runtimeType}"); }); client.onEvent('message', (message) { - stdout.writeln("Message: $message : ${message.runtimeType}"); + print("Message: $message : ${message.runtimeType}"); }); client.onEvent('userJoined', (user) { - stdout.writeln("userJoined : ${user.toMap()} : ${user.runtimeType}"); - }, converter: UserType()); + print("userJoined : ${user.toMap()} : ${user.runtimeType}"); + }); + + client.onDisconnect(() { + print("Client Disconnected from Server"); + }); client.listen(); - // getInput(); } diff --git a/polo_client/lib/polo_client.dart b/polo_client/lib/polo_client.dart index 785c601..0a29586 100644 --- a/polo_client/lib/polo_client.dart +++ b/polo_client/lib/polo_client.dart @@ -4,3 +4,4 @@ library polo_client; export 'src/polo_client_stub.dart' if (dart.library.io) 'src/polo_io_client_helper.dart' if (dart.library.html) 'src/polo_web_client_helper.dart'; +export 'src/polo_type.dart'; diff --git a/polo_client/lib/src/polo_client_stub.dart b/polo_client/lib/src/polo_client_stub.dart index 42ea631..8541292 100644 --- a/polo_client/lib/src/polo_client_stub.dart +++ b/polo_client/lib/src/polo_client_stub.dart @@ -12,8 +12,7 @@ abstract class PoloClient { } /// Adds a Callback to an Event - void onEvent(String event, void Function(T data) callback, - {PoloType? converter}) { + void onEvent(String event, void Function(T data) callback) { throw UnsupportedError("Platform is not Supported"); } @@ -27,6 +26,11 @@ abstract class PoloClient { throw UnsupportedError("Platform is not Supported"); } + /// Register a custom Object as a Type with `PoloTypeAdapter` + void registerType(PoloTypeAdapter type) { + throw UnsupportedError("Platform is not Supported"); + } + /// Closes the connection to the `PoloServer` Future close() async { throw UnsupportedError("Platform is not Supported"); diff --git a/polo_client/lib/src/polo_io_client_base.dart b/polo_client/lib/src/polo_io_client_base.dart index 6d49db4..7d84506 100644 --- a/polo_client/lib/src/polo_io_client_base.dart +++ b/polo_client/lib/src/polo_io_client_base.dart @@ -4,7 +4,7 @@ part of 'polo_io_client_helper.dart'; class PoloClient implements stub.PoloClient { final io.WebSocket _webSocket; final Map _callbacks = {}; - + final Map _registeredTypes = {}; void Function() _onDisconnectCallback = () {}; void Function() _onConnectCallback = () {}; @@ -21,12 +21,13 @@ class PoloClient implements stub.PoloClient { /// Adds a Callback to an Event @override - void onEvent(String event, void Function(T data) callback, - {PoloType? converter}) { - if (converter != null) { - assert(converter is T); - _callbacks[event] = (data) { - T typedData = converter.fromMap(data) as T; + void onEvent(String event, void Function(T data) callback) { + String typeStr = T.toString(); + if (_registeredTypes.containsKey(typeStr)) { + _callbacks[event] = (Map data) { + PoloTypeAdapter typeAdapter = + _registeredTypes[typeStr]! as PoloTypeAdapter; + T typedData = typeAdapter.fromMap(data); callback(typedData); }; } else { @@ -46,14 +47,26 @@ class PoloClient implements stub.PoloClient { /// Sends message to the Server from Client @override - void send(String event, dynamic data) { - if (data is PoloType) { - _webSocket.add(jsonEncode({'event': event, 'data': data.toMap()})); + void send(String event, T data) { + String typeStr = T.toString(); + + if (_registeredTypes.containsKey(typeStr)) { + PoloTypeAdapter typeAdapter = + _registeredTypes[typeStr]! as PoloTypeAdapter; + _webSocket + .add(jsonEncode({'event': event, 'data': typeAdapter.toMap(data)})); } else { _webSocket.add(jsonEncode({'event': event, 'data': data})); } } + /// Register a Type to the `PoloClient` + @override + void registerType(PoloTypeAdapter type) { + final typeString = T.toString(); + _registeredTypes[typeString] = type; + } + /// Closes the connection to the `PoloServer` @override Future close() { diff --git a/polo_client/lib/src/polo_type.dart b/polo_client/lib/src/polo_type.dart index 2f19b0c..b90be8b 100644 --- a/polo_client/lib/src/polo_type.dart +++ b/polo_client/lib/src/polo_type.dart @@ -1,9 +1,19 @@ +/// Helps to build a `Polo` compatible Type abstract class PoloType { Map toMap() { throw UnimplementedError(); } - PoloType fromMap(Map map) { + factory PoloType.fromMap(Map map) { throw UnimplementedError(); } } + +/// Registers a Object or `PoloType` as a Type +class PoloTypeAdapter { + PoloTypeAdapter({required this.toMap, required this.fromMap}); + + final Map Function(T type) toMap; + + final T Function(Map map) fromMap; +} diff --git a/polo_client/lib/src/polo_web_client_base.dart b/polo_client/lib/src/polo_web_client_base.dart index a315aa6..1ad5b88 100644 --- a/polo_client/lib/src/polo_web_client_base.dart +++ b/polo_client/lib/src/polo_web_client_base.dart @@ -4,7 +4,7 @@ part of 'polo_web_client_helper.dart'; class PoloClient implements stub.PoloClient { final html.WebSocket _webSocket; final Map _callbacks = {}; - + final Map _registeredTypes = {}; void Function() _onDisconnectCallback = () {}; void Function() _onConnectCallback = () {}; @@ -21,12 +21,16 @@ class PoloClient implements stub.PoloClient { /// Adds a Callback to an Event @override - void onEvent(String event, void Function(T data) callback, - {PoloType? converter}) { - if (converter != null) { - assert(converter is T); - _callbacks[event] = (data) { - T typedData = converter.fromMap(data) as T; + void onEvent( + String event, + void Function(T data) callback, + ) { + String typeStr = T.toString(); + if (_registeredTypes.containsKey(typeStr)) { + _callbacks[event] = (Map data) { + PoloTypeAdapter typeAdapter = + _registeredTypes[typeStr]! as PoloTypeAdapter; + T typedData = typeAdapter.fromMap(data); callback(typedData); }; } else { @@ -47,13 +51,25 @@ class PoloClient implements stub.PoloClient { /// Sends message to the Server from Client @override void send(String event, T data) { - if (data is PoloType) { - _webSocket.sendString(jsonEncode({'event': event, 'data': data.toMap()})); + String typeStr = T.toString(); + + if (_registeredTypes.containsKey(typeStr)) { + PoloTypeAdapter typeAdapter = + _registeredTypes[typeStr]! as PoloTypeAdapter; + _webSocket.sendString( + jsonEncode({'event': event, 'data': typeAdapter.toMap(data)})); } else { _webSocket.sendString(jsonEncode({'event': event, 'data': data})); } } + /// Register a Type to the `PoloClient` + @override + void registerType(PoloTypeAdapter type) { + final typeString = T.toString(); + _registeredTypes[typeString] = type; + } + /// Closes the connection to the `PoloServer` @override Future close() async { diff --git a/polo_client/pubspec.yaml b/polo_client/pubspec.yaml index 0672f70..c0cb014 100644 --- a/polo_client/pubspec.yaml +++ b/polo_client/pubspec.yaml @@ -1,7 +1,7 @@ name: polo_client description: A WebSocket Library written in Pure Dart. Easy API for writing WebSocket based Apps or Games. Also Support for Flutter and Web. repository: https://github.com/AyushChothe/polo -version: 0.0.2+2 +version: 0.0.3 # homepage: https://www.example.com environment: diff --git a/polo_server/example/polo_server_example.dart b/polo_server/example/polo_server_example.dart index b69a481..78ce721 100644 --- a/polo_server/example/polo_server_example.dart +++ b/polo_server/example/polo_server_example.dart @@ -1,14 +1,12 @@ import 'package:polo_server/polo_server.dart'; -import 'package:polo_server/src/polo_type.dart'; class UserType implements PoloType { - String? name; - int? age; + final String name; + final int age; - UserType({this.name, this.age}); + UserType({required this.name, required this.age}); - @override - UserType fromMap(Map map) { + factory UserType.fromMap(Map map) { return UserType(name: map['name'], age: map['age']); } @@ -21,10 +19,18 @@ class UserType implements PoloType { void main() async { // Manager // Polo polo = await Polo.createManager(); - // PoloServer server = polo.of('/chat'); + // PoloServer server = polo.of('/'); // Direct Server - PoloServer server = await Polo.createServer(); + PoloServer server = await Polo.createServer(address: "127.0.0.1", port: 3000); + + // Register a Type + server.registerType( + PoloTypeAdapter( + toMap: (type) => type.toMap(), + fromMap: (map) => UserType.fromMap(map), + ), + ); server.onClientConnect((client) { print("Client(${client.id}) Connected!"); @@ -39,30 +45,10 @@ void main() async { client.send('message', "Hello from Server"); }); - client.onEvent( - 'userJoined', - (user) { - print("userJoined : ${user.toMap()} : ${user.runtimeType}"); - client.send('userJoined', user); - }, - converter: UserType(), - ); - - // client.onEvent('message', - // (message) => server.broadcastFrom(client, 'message', message)); - - // client.onEvent( - // 'messageToRoom', - // (payload) => server.broadcastToRoom( - // client, payload['room'], 'message', payload['message'])); - - // client.onEvent('joinRoom', (room) { - // client.joinRoom(room); - // }); - - // client.onEvent('leaveRoom', (room) { - // client.leaveRoom(room); - // }); + client.onEvent('userJoined', (user) { + print("userJoined : ${user.toMap()} : ${user.runtimeType}"); + client.send('userJoined', user); + }); }); server.onClientDisconnect((client) { diff --git a/polo_server/lib/polo_server.dart b/polo_server/lib/polo_server.dart index be7a294..59ed527 100644 --- a/polo_server/lib/polo_server.dart +++ b/polo_server/lib/polo_server.dart @@ -4,3 +4,4 @@ library polo_server; export 'src/polo_server_helper.dart'; +export 'src/polo_type.dart'; diff --git a/polo_server/lib/src/polo_client_base.dart b/polo_server/lib/src/polo_client_base.dart index 0983f17..46a1550 100644 --- a/polo_server/lib/src/polo_client_base.dart +++ b/polo_server/lib/src/polo_client_base.dart @@ -3,14 +3,18 @@ part of 'polo_server_helper.dart'; /// `PoloClient` is used to handle Connected WebSocket class PoloClient { final WebSocket _webSocket; + late final String _id; String get id => _id; + final Map _callbacks = {}; + final Map _registeredTypes; + final Set _rooms = {}; void Function(PoloClient) _onDisconnectCallback = (poloClient) {}; - PoloClient._(this._webSocket) { + PoloClient._(this._webSocket, this._registeredTypes) { _id = Uuid().v4(); _handleEvents(); } @@ -19,12 +23,16 @@ class PoloClient { _onDisconnectCallback = callback; /// Adds a Callback to an Event - void onEvent(String event, void Function(T data) callback, - {PoloType? converter}) { - if (converter != null) { - assert(converter is T); - _callbacks[event] = (data) { - T typedData = converter.fromMap(data) as T; + void onEvent( + String event, + void Function(T data) callback, + ) { + String typeStr = T.toString(); + if (_registeredTypes.containsKey(typeStr)) { + _callbacks[event] = (Map data) { + PoloTypeAdapter typeAdapter = + _registeredTypes[typeStr]! as PoloTypeAdapter; + T typedData = typeAdapter.fromMap(data); callback(typedData); }; } else { @@ -38,8 +46,13 @@ class PoloClient { /// Sends message to the Client from Server void send(String event, T data) { - if (data is PoloType) { - _webSocket.add(jsonEncode({'event': event, 'data': data.toMap()})); + String typeStr = T.toString(); + + if (_registeredTypes.containsKey(typeStr)) { + PoloTypeAdapter typeAdapter = + _registeredTypes[typeStr]! as PoloTypeAdapter; + _webSocket + .add(jsonEncode({'event': event, 'data': typeAdapter.toMap(data)})); } else { _webSocket.add(jsonEncode({'event': event, 'data': data})); } diff --git a/polo_server/lib/src/polo_server_base.dart b/polo_server/lib/src/polo_server_base.dart index 933b2ab..249938a 100644 --- a/polo_server/lib/src/polo_server_base.dart +++ b/polo_server/lib/src/polo_server_base.dart @@ -10,6 +10,8 @@ class PoloServer { final Map _clients = {}; + final Map _registeredTypes = {}; + void Function(PoloClient client) _onConnectCallback = (client) {}; void Function(PoloClient client) _onDisconnectCallback = (client) {}; @@ -62,7 +64,7 @@ class PoloServer { } void _handleClient(WebSocket webSocket) { - PoloClient client = PoloClient._(webSocket); + PoloClient client = PoloClient._(webSocket, _registeredTypes); // On Client Connected _onConnect(client); // On Client Disconnected @@ -114,6 +116,12 @@ class PoloServer { } } + /// Register a Type to the `PoloServer` + void registerType(PoloTypeAdapter type) { + final typeString = T.toString(); + _registeredTypes[typeString] = type; + } + /// Closes the Server Future close() async { if (_httpServer != null) { diff --git a/polo_server/lib/src/polo_type.dart b/polo_server/lib/src/polo_type.dart index 2f19b0c..b90be8b 100644 --- a/polo_server/lib/src/polo_type.dart +++ b/polo_server/lib/src/polo_type.dart @@ -1,9 +1,19 @@ +/// Helps to build a `Polo` compatible Type abstract class PoloType { Map toMap() { throw UnimplementedError(); } - PoloType fromMap(Map map) { + factory PoloType.fromMap(Map map) { throw UnimplementedError(); } } + +/// Registers a Object or `PoloType` as a Type +class PoloTypeAdapter { + PoloTypeAdapter({required this.toMap, required this.fromMap}); + + final Map Function(T type) toMap; + + final T Function(Map map) fromMap; +} diff --git a/polo_server/pubspec.yaml b/polo_server/pubspec.yaml index 1e85f9b..2b4146a 100644 --- a/polo_server/pubspec.yaml +++ b/polo_server/pubspec.yaml @@ -1,7 +1,7 @@ name: polo_server description: A WebSocket Library written in Pure Dart. Easy API for writing WebSocket based Apps or Games. Also Support for Flutter and Web. repository: https://github.com/AyushChothe/polo -version: 0.0.2 +version: 0.0.3 # homepage: https://www.example.com environment: