diff --git a/externals/ws.mxo/Contents/MacOS/ws b/externals/ws.mxo/Contents/MacOS/ws index 11e1bbd..72976c2 100755 Binary files a/externals/ws.mxo/Contents/MacOS/ws and b/externals/ws.mxo/Contents/MacOS/ws differ diff --git a/help/ws.maxhelp b/help/ws.maxhelp index 61791cf..a2762c6 100644 --- a/help/ws.maxhelp +++ b/help/ws.maxhelp @@ -3,13 +3,13 @@ "fileversion" : 1, "appversion" : { "major" : 7, - "minor" : 1, + "minor" : 2, "revision" : 0, - "architecture" : "x64", + "architecture" : "x86", "modernui" : 1 } , - "rect" : [ 250.0, 148.0, 823.0, 520.0 ], + "rect" : [ 61.0, 80.0, 927.0, 723.0 ], "bglocked" : 0, "openinpresentation" : 0, "default_fontsize" : 12.0, @@ -37,6 +37,134 @@ "style" : "", "subpatcher_template" : "", "boxes" : [ { + "box" : { + "id" : "obj-41", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 267.0, 275.0, 24.0, 24.0 ], + "style" : "" + } + + } +, { + "box" : { + "id" : "obj-38", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 4, + "outlettype" : [ "dictionary", "", "", "" ], + "patching_rect" : [ 229.0, 319.0, 67.0, 22.0 ], + "saved_object_attributes" : { + "embed" : 0, + "parameter_enable" : 0 + } +, + "style" : "", + "text" : "dict bigdict" + } + + } +, { + "box" : { + "id" : "obj-28", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 33.0, 397.0, 60.0, 22.0 ], + "style" : "", + "text" : "loadbang" + } + + } +, { + "box" : { + "id" : "obj-25", + "maxclass" : "dict.view", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 33.0, 468.0, 100.0, 100.0 ], + "style" : "" + } + + } +, { + "box" : { + "id" : "obj-23", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 4, + "outlettype" : [ "dictionary", "", "", "" ], + "patching_rect" : [ 33.0, 433.0, 67.0, 22.0 ], + "saved_object_attributes" : { + "embed" : 0, + "parameter_enable" : 0 + } +, + "style" : "", + "text" : "dict bigdict" + } + + } +, { + "box" : { + "id" : "obj-8", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 334.0, 512.0, 103.0, 22.0 ], + "style" : "", + "text" : "prepend received" + } + + } +, { + "box" : { + "id" : "obj-39", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 233.0, 473.0, 85.0, 22.0 ], + "style" : "", + "text" : "compile, bang" + } + + } +, { + "box" : { + "id" : "obj-34", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 190.0, 472.0, 24.0, 24.0 ], + "style" : "" + } + + } +, { + "box" : { + "id" : "obj-21", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 185.0, 521.0, 79.0, 22.0 ], + "saved_object_attributes" : { + "filename" : "ws_help.js", + "parameter_enable" : 0 + } +, + "style" : "", + "text" : "js ws_help.js" + } + + } +, { "box" : { "id" : "obj-29", "maxclass" : "message", @@ -148,54 +276,6 @@ "text" : "dict.pack num : 0" } - } -, { - "box" : { - "id" : "obj-28", - "maxclass" : "comment", - "numinlets" : 1, - "numoutlets" : 0, - "patching_rect" : [ 17.0, 321.0, 125.0, 20.0 ], - "style" : "", - "text" : "if we received JSON:" - } - - } -, { - "box" : { - "id" : "obj-25", - "maxclass" : "dict.view", - "numinlets" : 1, - "numoutlets" : 0, - "patching_rect" : [ 17.0, 379.0, 100.0, 100.0 ], - "style" : "" - } - - } -, { - "box" : { - "id" : "obj-23", - "maxclass" : "message", - "numinlets" : 2, - "numoutlets" : 1, - "outlettype" : [ "" ], - "patching_rect" : [ 162.0, 465.0, 138.0, 22.0 ], - "style" : "" - } - - } -, { - "box" : { - "id" : "obj-8", - "maxclass" : "newobj", - "numinlets" : 2, - "numoutlets" : 2, - "outlettype" : [ "", "" ], - "patching_rect" : [ 17.0, 345.0, 118.0, 22.0 ], - "style" : "", - "text" : "routepass dictionary" - } - } , { "box" : { @@ -213,14 +293,13 @@ , { "box" : { "id" : "obj-18", - "linecount" : 4, "maxclass" : "message", "numinlets" : 2, "numoutlets" : 1, "outlettype" : [ "" ], - "patching_rect" : [ 711.0, 198.0, 50.0, 62.0 ], + "patching_rect" : [ 654.0, 196.5, 237.0, 22.0 ], "style" : "", - "text" : "dictionary u347000377" + "text" : "{\\\"hello\\\":\\\"world\\\"}" } } @@ -465,7 +544,7 @@ "maxclass" : "newobj", "numinlets" : 1, "numoutlets" : 0, - "patching_rect" : [ 128.0, 409.0, 83.0, 22.0 ], + "patching_rect" : [ 114.0, 373.0, 83.0, 22.0 ], "style" : "", "text" : "print received" } @@ -478,7 +557,7 @@ "numinlets" : 1, "numoutlets" : 2, "outlettype" : [ "", "" ], - "patching_rect" : [ 147.5, 316.0, 81.0, 22.0 ], + "patching_rect" : [ 114.0, 319.0, 81.0, 22.0 ], "style" : "", "text" : "ws" } @@ -487,10 +566,10 @@ ], "lines" : [ { "patchline" : { - "destination" : [ "obj-23", 1 ], + "destination" : [ "obj-2", 0 ], "disabled" : 0, "hidden" : 0, - "source" : [ "obj-1", 1 ] + "source" : [ "obj-1", 0 ] } } @@ -502,15 +581,6 @@ "source" : [ "obj-1", 1 ] } - } -, { - "patchline" : { - "destination" : [ "obj-8", 0 ], - "disabled" : 0, - "hidden" : 0, - "source" : [ "obj-1", 0 ] - } - } , { "patchline" : { @@ -583,6 +653,15 @@ "source" : [ "obj-22", 0 ] } + } +, { + "patchline" : { + "destination" : [ "obj-25", 0 ], + "disabled" : 0, + "hidden" : 0, + "source" : [ "obj-23", 0 ] + } + } , { "patchline" : { @@ -619,6 +698,15 @@ "source" : [ "obj-27", 0 ] } + } +, { + "patchline" : { + "destination" : [ "obj-23", 0 ], + "disabled" : 0, + "hidden" : 0, + "source" : [ "obj-28", 0 ] + } + } , { "patchline" : { @@ -664,6 +752,33 @@ "source" : [ "obj-33", 0 ] } + } +, { + "patchline" : { + "destination" : [ "obj-21", 0 ], + "disabled" : 0, + "hidden" : 0, + "source" : [ "obj-34", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "disabled" : 0, + "hidden" : 0, + "source" : [ "obj-38", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-21", 0 ], + "disabled" : 0, + "hidden" : 0, + "source" : [ "obj-39", 0 ] + } + } , { "patchline" : { @@ -673,6 +788,15 @@ "source" : [ "obj-4", 0 ] } + } +, { + "patchline" : { + "destination" : [ "obj-38", 0 ], + "disabled" : 0, + "hidden" : 0, + "source" : [ "obj-41", 0 ] + } + } , { "patchline" : { @@ -694,25 +818,25 @@ } , { "patchline" : { - "destination" : [ "obj-13", 0 ], + "destination" : [ "obj-8", 0 ], "disabled" : 0, "hidden" : 0, - "source" : [ "obj-7", 0 ] + "source" : [ "obj-6", 0 ] } } , { "patchline" : { - "destination" : [ "obj-2", 0 ], + "destination" : [ "obj-13", 0 ], "disabled" : 0, "hidden" : 0, - "source" : [ "obj-8", 1 ] + "source" : [ "obj-7", 0 ] } } , { "patchline" : { - "destination" : [ "obj-25", 0 ], + "destination" : [ "obj-21", 0 ], "disabled" : 0, "hidden" : 0, "source" : [ "obj-8", 0 ] @@ -730,6 +854,12 @@ } ], "dependency_cache" : [ { + "name" : "ws_help.js", + "bootpath" : "~/Documents/Max 7/Packages/Max_Worldmaking_Package/help", + "type" : "TEXT", + "implicit" : 1 + } +, { "name" : "ws.mxo", "type" : "iLaX" } diff --git a/help/ws_help.html b/help/ws_help.html index 2df8e5b..6e0147a 100644 --- a/help/ws_help.html +++ b/help/ws_help.html @@ -35,7 +35,7 @@ // debug messaging: function post(msg) { console.log(msg); - document.getElementById("post").innerHTML = msg; + document.getElementById("post").innerHTML += msg + "
"; } ///// websocket ///// @@ -74,7 +74,18 @@ }; wsocket.onmessage = function(ev) { - post("msg:" + ev.data); + post("a msg:" + ev.data.length + ": " + ev.data.substr(0, 10) + "..."); + post(ev.data.charAt(0)); + if (ev.data.charAt(0) == "{") { + // attempt to json parse it: + post("parsing"); + var tree = JSON.parse(ev.data); + console.log("parsed", tree); + } else { + + // echo it back! + send(ev.data); + } }; wsocket.onerror = function(ev) { @@ -88,7 +99,8 @@ function send(msg) { if(wsocket != undefined) wsocket.send(msg); - post(msg); + post("sent msg:" + msg.length + ": " + msg); + } ///// sequencing ///// diff --git a/help/ws_help.js b/help/ws_help.js new file mode 100644 index 0000000..1a28b82 --- /dev/null +++ b/help/ws_help.js @@ -0,0 +1,20 @@ + +var bigdict = new Dict("bigdict"); + +function bang() { + bigdict.clear(); + var s = ""; + for (var i=0; i<64*128; i++) { + bigdict.set("var"+i, i); + } + + s = bigdict.stringify(); + + post("js made string of", s.length, "\n"); + + outlet(0, "bang"); +} + +function received(s) { + post("js received string of", s.length, "\n"); +} \ No newline at end of file diff --git a/media/lrintersection.jpg b/media/lrintersection.jpg new file mode 100644 index 0000000..29f093c Binary files /dev/null and b/media/lrintersection.jpg differ diff --git a/source/ws/ws.cpp b/source/ws/ws.cpp index 322d2ae..15895b4 100755 --- a/source/ws/ws.cpp +++ b/source/ws/ws.cpp @@ -46,6 +46,8 @@ class Server { server.start_accept(); server.clear_access_channels(websocketpp::log::alevel::all); // this will turn off everything in console output + post("maximum message size %d", server.get_max_message_size()); + received_dict_name = symbol_unique(); received_dict = dictionary_new(); atom_setsym(&received_dict_name_atom, received_dict_name); @@ -119,7 +121,19 @@ class Server { while (limit-- && server.poll_one()) {}; } + void forward(websocketpp::connection_hdl hdl, const std::string& msg) { + websocketpp::lib::error_code ec; + auto con = server.get_con_from_hdl(hdl, ec); + //server.get_connection_pt + for (websocketpp::connection_hdl client : clients) { + if (server.get_con_from_hdl(client, ec) != con) { + server.send(client, msg, websocketpp::frame::opcode::text); + } + } + } + void send(const std::string& msg) { + //post("sending string length %d", msg.size()); for (auto client : clients) { server.send(client, msg, websocketpp::frame::opcode::text); } @@ -133,7 +147,26 @@ class Server { clients.erase(hdl); } - void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg); + void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) { + const char * buf = msg->get_payload().c_str(); + + // if a broadcast... + if (buf[0] == '*') { + const char * trimmed = &buf[1]; + + // immediately forward to all *other* clients + forward(hdl, trimmed); + + // also share with server: + to_max_objects(trimmed); + + } else { + to_max_objects(buf); + } + + } + + void to_max_objects(const char * buf); }; @@ -178,32 +211,14 @@ class ws { } }; -void Server::on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) { - - const char * buf = msg->get_payload().c_str(); - -// // attempt to parse as dict? -// //dictobj_unregister(received_dict); -// char errstring[256]; -// t_dictionary * result = NULL; -// if (0 == dictobj_dictionaryfromstring(&result, buf, 1, errstring)) { -// object_release((t_object *)received_dict); -// received_dict = result; -// dictobj_register(received_dict, &received_dict_name); -// -// for (auto x : maxobjects) { -// outlet_anything(x->outlet_frame, _sym_dictionary, 1, &received_dict_name_atom); -// } -// } else { -// error("error parsing received message as JSON: %s", errstring); - - // just output as string: - t_symbol * sym = gensym(buf); - for (auto x : maxobjects) { - outlet_anything(x->outlet_frame, sym, 0, 0); - } +void Server::to_max_objects(const char * buf) { + //post("on_message string length %d", msg->get_payload().size()); -// } + // just output as string: + t_symbol * sym = gensym(buf); + for (auto x : maxobjects) { + outlet_anything(x->outlet_frame, sym, 0, 0); + } } @@ -249,6 +264,9 @@ void ws_send(ws * x, t_symbol * s) { x->send(std::string(s->s_name)); } +// kind of useless... +//extern "C" t_max_err compression_compressjson_headless(char *json, long srclen, t_handle compressedjson); + void ws_dictionary(ws * x, t_symbol * s) { t_dictionary *d = dictobj_findregistered_retain(s); if (d) { @@ -257,6 +275,21 @@ void ws_dictionary(ws * x, t_symbol * s) { object_method(jsonwriter, _sym_writedictionary, d); object_method(jsonwriter, _sym_getoutput, &json); + /* + // this compresses the JSON into a hash like maxpats + // only useful if we can uncompress at the browser end... + { + t_handle compressed_json = sysmem_newhandle(0); + t_max_err err; + err = compression_compressjson_headless(*json, strlen(*json), compressed_json); + if (!err) { + x->send(std::string(*compressed_json)); + sysmem_freehandle(compressed_json); + } + + } + */ + x->send(std::string(*json)); object_free(jsonwriter);