From 62794cb85668904f3f23502f27efb89a1491b6a8 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Wed, 29 Jan 2020 11:39:51 +0900 Subject: [PATCH 01/13] WebSocket without name. It's from v0.4.0, but, the websocket message format is changed without name. --- example/app.dart | 9 +++------ lib/socket.dart | 14 ++++++-------- lib/src/message.dart | 35 ----------------------------------- lib/src/socket.dart | 13 +++++-------- lib/src/socket_base.dart | 6 ++---- 5 files changed, 16 insertions(+), 61 deletions(-) delete mode 100644 lib/src/message.dart diff --git a/example/app.dart b/example/app.dart index 6fea2bb..dc824ed 100644 --- a/example/app.dart +++ b/example/app.dart @@ -38,13 +38,10 @@ void main() { }); }); - app.ws('/socket').listen((socket) { - socket.on('connected').listen((data) { - socket.send('ping', 'data-from-ping'); - }); + app.ws('/').listen((socket) { - socket.on('pong').listen((data) { - print('pong: $data'); + socket.onMessage().listen((data) { + print('msg: $data'); socket.close(1000, 'requested'); }); diff --git a/lib/socket.dart b/lib/socket.dart index 928f7e0..9bf562b 100644 --- a/lib/socket.dart +++ b/lib/socket.dart @@ -14,19 +14,17 @@ class Socket implements SocketBase { this._ws = new WebSocket(url) { _messages = _messageController.stream.asBroadcastStream(); _ws.onMessage.listen((e) { - var msg = new Message.fromPacket(e.data); + var msg = e.data; _messageController.add(msg); }); } - void send(String messageName, [ data ]) { - var message = new Message(messageName, data); - _ws.send(message.toPacket()); + void send(String message) { + _ws.send(message); } - Stream on(String messageName) { - return _messages.where((msg) => msg.name == messageName).map((msg) => - msg.data); + Stream onMessage() { + return _messages; } Stream get onOpen => _ws.onOpen; @@ -36,4 +34,4 @@ class Socket implements SocketBase { void close([int status, String reason]) { _ws.close(status, reason); } -} \ No newline at end of file +} diff --git a/lib/src/message.dart b/lib/src/message.dart deleted file mode 100644 index 28c6b9c..0000000 --- a/lib/src/message.dart +++ /dev/null @@ -1,35 +0,0 @@ -library start_message; - -import 'dart:convert'; - -class Message { - final String name; - final Object data; - - Message(this.name, [this.data]); - - factory Message.fromPacket(String message) { - if (message.isEmpty) { - return new Message.empty(); - } - - List parts = message.split(':'); - String name = parts.first; - var data = null; - - if (parts.length > 1 && !parts[1].isEmpty) { - data = jsonDecode(parts.sublist(1).join(':')); - } - - return new Message(name, data); - } - - Message.empty() : this(''); - - String toPacket() { - if (data == null) { - return name; - } - return '$name:${jsonEncode(data)}'; - } -} \ No newline at end of file diff --git a/lib/src/socket.dart b/lib/src/socket.dart index 9a01aea..d47a476 100644 --- a/lib/src/socket.dart +++ b/lib/src/socket.dart @@ -13,22 +13,19 @@ class Socket implements SocketBase { _openController.add(_ws); _ws.listen((data) { - var msg = new Message.fromPacket(data); - _messageController.add(msg); + _messageController.add(data); }, onDone: () { _closeController.add(_ws); }); } - void send(String messageName, [ data ]) { - var message = new Message(messageName, data); - _ws.add(message.toPacket()); + void send(String message) { + _ws.add(message); } - Stream on(String messageName) { - return _messages.where((msg) => msg.name == messageName).map((msg) => - msg.data); + Stream onMessage() { + return _messages; } Stream get onOpen => _openController.stream; diff --git a/lib/src/socket_base.dart b/lib/src/socket_base.dart index 76c4247..332b7d4 100644 --- a/lib/src/socket_base.dart +++ b/lib/src/socket_base.dart @@ -2,12 +2,10 @@ library start_socket; import 'dart:async'; -export 'message.dart' show Message; - abstract class SocketBase { - void send(String msg_name, [ data ]); + void send(String msg); - Stream on(String message_name); + Stream onMessage(); void close([int status, String reason]); } From a50e597c8472beca1f749d4e3817996ad18cf18f Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Wed, 29 Jan 2020 11:49:36 +0900 Subject: [PATCH 02/13] Update pubspec.yaml - version 0.5.0 --- CHANGELOG.md | 4 ++++ pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4392e1e..7345508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.5.0 + +Websocket format is changed. + ## 0.4.0 Fix Websockets diff --git a/pubspec.yaml b/pubspec.yaml index 9593a15..afcad66 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: start -author: Yehor Lvivski -version: 0.4.0 +author: Yehor Lvivski , Benjamin Jung +version: 0.5.0 homepage: http://github.com/lvivski/start description: Sinatra inspired Web framework environment: From 7d03d4491237304837073ac405d717580ab779b0 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 09:59:10 +0900 Subject: [PATCH 03/13] Update Start web framework - set the default option of isMime 'loose' true. --- lib/src/request.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/request.dart b/lib/src/request.dart index 0273ca3..ea9d39a 100644 --- a/lib/src/request.dart +++ b/lib/src/request.dart @@ -13,7 +13,7 @@ class Request { .where((name) => name.split(',').indexOf(type) > 0) .length > 0; - bool isMime(String type, {loose: false}) => + bool isMime(String type, {loose: true}) => _request.headers[HttpHeaders.contentTypeHeader] .where((value) => loose ? value.contains(type) : value == type) .isNotEmpty; From 672169ec396a66e3f6adeae25fefba59bd92a631 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 16:33:04 +0900 Subject: [PATCH 04/13] Update Start web framework - server.dart : CORS enable --- lib/src/server.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/src/server.dart b/lib/src/server.dart index 3599675..38af58c 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -21,6 +21,7 @@ class Server { handle(HttpServer server) { _server = server; server.listen((HttpRequest req) { + addCorsHeaders(req.response); var route = _routes.firstWhere((Route route) => route.match(req), orElse: () => null); if (route != null) { @@ -28,6 +29,7 @@ class Server { } else if (_staticServer != null) { _staticServer.serveRequest(req); } else { + print("[DEBUG] server error 404"); _send404(req); } }); @@ -50,6 +52,13 @@ class Server { return HttpServer.bind(host, port).then(handle); } + void addCorsHeaders(HttpResponse response) { + response.headers.add('Access-Control-Allow-Origin', '*'); + response.headers.add('Access-Control-Allow-Methods', 'POST, OPTIONS'); + response.headers.add('Access-Control-Allow-Headers', + 'Origin, X-Requested-With, Content-Type, Accept'); + } + void static(path, { listing: true, links: true, jail: true }) { _staticServer = new VirtualDirectory(path) ..allowDirectoryListing = listing From 7e65db1b71ba30aead9c1651f3e6880abd4e96c0 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 16:39:44 +0900 Subject: [PATCH 05/13] CORS : add GET method --- lib/src/server.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/server.dart b/lib/src/server.dart index 38af58c..04a49ce 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -54,7 +54,7 @@ class Server { void addCorsHeaders(HttpResponse response) { response.headers.add('Access-Control-Allow-Origin', '*'); - response.headers.add('Access-Control-Allow-Methods', 'POST, OPTIONS'); + response.headers.add('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); response.headers.add('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); } From bdd81a1e85f0ef2e5d8a059fe7cac302cca3dcd6 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 17:08:47 +0900 Subject: [PATCH 06/13] CORS option is always enabled. --- lib/src/server.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/server.dart b/lib/src/server.dart index 04a49ce..e71e546 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -54,9 +54,9 @@ class Server { void addCorsHeaders(HttpResponse response) { response.headers.add('Access-Control-Allow-Origin', '*'); - response.headers.add('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); + response.headers.add('Access-Control-Allow-Methods', 'GET,HEAD,PUT,PATCH,POST,DELETE'); response.headers.add('Access-Control-Allow-Headers', - 'Origin, X-Requested-With, Content-Type, Accept'); + 'access-control-allow-origin,content-type,x-access-token'); } void static(path, { listing: true, links: true, jail: true }) { From 6c145b1d182e8c1098c4f31c9f50af168cb35322 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 18:02:49 +0900 Subject: [PATCH 07/13] Start Web framework - CORS is enabled with option flags. --- lib/src/server.dart | 4 ++-- lib/start.dart | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/server.dart b/lib/src/server.dart index e71e546..cb3bc37 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -16,12 +16,12 @@ class Server { } Future listen(String host, num port, - {String certificateChain, String privateKey, String password}) { + {String certificateChain, String privateKey, String password, bool cors}) { handle(HttpServer server) { _server = server; server.listen((HttpRequest req) { - addCorsHeaders(req.response); + if (cors) addCorsHeaders(req.response); var route = _routes.firstWhere((Route route) => route.match(req), orElse: () => null); if (route != null) { diff --git a/lib/start.dart b/lib/start.dart index 563bc8b..2fe736e 100644 --- a/lib/start.dart +++ b/lib/start.dart @@ -20,6 +20,6 @@ part 'src/server.dart'; part 'src/socket.dart'; -Future start({ String host: '127.0.0.1', int port: 80, String certificateChain, String privateKey, String password}) { - return new Server().listen(host, port, certificateChain: certificateChain, privateKey: privateKey, password: password); +Future start({ String host: '127.0.0.1', int port: 80, String certificateChain, String privateKey, String password, bool cors}) { + return new Server().listen(host, port, certificateChain: certificateChain, privateKey: privateKey, password: password, cors: cors); } From 0f3ad04515d9265c41b5cb5032a73e009a2f0e51 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 18:25:16 +0900 Subject: [PATCH 08/13] Update CORS default value (false). --- lib/start.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/start.dart b/lib/start.dart index 2fe736e..2e7e579 100644 --- a/lib/start.dart +++ b/lib/start.dart @@ -20,6 +20,6 @@ part 'src/server.dart'; part 'src/socket.dart'; -Future start({ String host: '127.0.0.1', int port: 80, String certificateChain, String privateKey, String password, bool cors}) { +Future start({ String host: '127.0.0.1', int port: 80, String certificateChain, String privateKey, String password, bool cors:false}) { return new Server().listen(host, port, certificateChain: certificateChain, privateKey: privateKey, password: password, cors: cors); } From 7d73fcf59a16cfc44156b29d9c00f25ee1ce1782 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 19:03:04 +0900 Subject: [PATCH 09/13] Update README.md - add bsjung@gmail.com --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 730c27a..22c66a4 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,8 @@ close(status, reason) // closes socket Copyright (c) 2012 Yehor Lvivski +Copyright (c) 2020 Benjamin Jung + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including From ea390c38a5df8ebb4249f971544da0f3039af4a5 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 19:10:36 +0900 Subject: [PATCH 10/13] Update README.md - add new WebSocket document. --- README.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 22c66a4..28afe58 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,21 @@ void main() { }); app.ws('/socket').listen((socket) { - socket.on('ping').listen((data) => socket.send('pong')); - socket.on('pong').listen((data) => socket.close(1000, 'requested')); - }); - }); + socket.onMessage().listen((data) { + print('data: $data'); + socket.send(data); + }); + + socket.onOpen.listen((ws) { + print('new socket opened'); + }); + + socket.onClose.listen((ws) { + print('socket has been closed'); + }); + + }); } ``` From 7dc594f92135fd3f0ee4ed750a82d1006315a204 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 19:14:03 +0900 Subject: [PATCH 11/13] Update REAME.md - v0.5.0 new Websocket : onMessage() --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 28afe58..387012b 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ render(viewName, [Map params]) // renders server view ```dart send(message) // sends message -on(message, action) // adds handler to message +onMessage() // adds handler to message close(status, reason) // closes socket ``` From 6b2a9a35ca4493eb84a5afe8c63d23fe07c8e703 Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sat, 1 Feb 2020 19:35:38 +0900 Subject: [PATCH 12/13] Update README.md - add CORS document. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 387012b..582b6b6 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ You start the server with `start()` function. It has 3 named arguments and returns `Server` future ```dart -start({String host: '127.0.0.1', int port: 80}) +start({String host: '127.0.0.1', int port: 80, cors : false}) ``` ### Server From 70bc07926859c13b23cc6f56766f33c8c9dbe38b Mon Sep 17 00:00:00 2001 From: Benjamin Jung Date: Sun, 2 Feb 2020 13:57:25 +0900 Subject: [PATCH 13/13] update CORS - add _sendDummy() for req.method='options' --- lib/src/route.dart | 13 +++++-------- lib/src/server.dart | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/src/route.dart b/lib/src/route.dart index edb2633..b9fda60 100644 --- a/lib/src/route.dart +++ b/lib/src/route.dart @@ -8,21 +8,19 @@ class Route { Stream requestStream; Stream socketStream; - Route(String method, path, { List keys }) - : + Route(String method, path, { List keys }) : _method = method.toUpperCase(), _path = _normalize(path, keys: keys) { requestStream = _requestController.stream; } - Route.ws(dynamic path, { List keys }) - : + Route.ws(dynamic path, { List keys }) : _method = 'WS', _path = _normalize(path, keys: keys) { socketStream = _socketController.stream .transform(new WebSocketTransformer()) .map((WebSocket ws) => new Socket(ws)); - } + } bool match(HttpRequest req) { return ((_method == req.method || _method == 'WS') @@ -33,15 +31,14 @@ class Route { if (_method == 'WS') { _socketController.add(req); } else { - var request = new Request(req); + var request = new Request(req); request.params = _parseParams(req.uri.path, _path); request.response = new Response(req.response); _requestController.add(request); } } - static Map _normalize(dynamic path, - { List keys, bool strict: false }) { + static Map _normalize(dynamic path, { List keys, bool strict: false }) { if (keys == null) { keys = []; } diff --git a/lib/src/server.dart b/lib/src/server.dart index cb3bc37..e24994d 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -21,7 +21,13 @@ class Server { handle(HttpServer server) { _server = server; server.listen((HttpRequest req) { - if (cors) addCorsHeaders(req.response); + if (cors) { + addCorsHeaders(req.response); + if (req.method.toLowerCase() == 'options') { + _sendDummy(req); + return; + } + } var route = _routes.firstWhere((Route route) => route.match(req), orElse: () => null); if (route != null) { @@ -29,7 +35,6 @@ class Server { } else if (_staticServer != null) { _staticServer.serveRequest(req); } else { - print("[DEBUG] server error 404"); _send404(req); } }); @@ -115,6 +120,13 @@ class Server { return route.requestStream; } + void _sendDummy(HttpRequest req) { + var msg = {}; + msg['status'] = 'ok'; + req.response.write(jsonEncode(msg)); + req.response.close(); + } + void _send404(HttpRequest req) { req.response ..statusCode = HttpStatus.notFound