diff options
author | Jonas Suhr Christensen <jsc@umbraculum.org> | 2012-02-23 10:34:23 +0100 |
---|---|---|
committer | Jonas Suhr Christensen <jsc@umbraculum.org> | 2012-02-23 10:34:23 +0100 |
commit | 3cbbce9bbe2e63554d253bca8c313e27a16c9b12 (patch) | |
tree | bda12b8eb1164606baac9367fe720cc172c6a481 | |
parent | 93890eace0b7a35cb597272e7449b1e0ee533a73 (diff) |
Implemented add and remove.
Implemented task list on new connection.
-rw-r--r-- | munia.html | 284 | ||||
-rw-r--r-- | src/muniad.cc | 144 |
2 files changed, 411 insertions, 17 deletions
diff --git a/munia.html b/munia.html new file mode 100644 index 0000000..74f5e75 --- /dev/null +++ b/munia.html @@ -0,0 +1,284 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <title>Munia</title> +</head> +<body id="body"> +<select id="color" onchange="update_color();"> + <option value="#000000">Black</option> + <option value="#0000ff">Blue</option> + <option value="#20ff20">Green</option> + <option value="#802020">Dark Red</option> +</select> +<div id="wslm_status">Not initialized</div> +<div id="wslm_lastmsg"></div> +<div id="wslm_drawing"></div> +<div id="box" style="position: absolute;">Hello World</div> +<input type="text" id="input_data" value="Do magic here" onfocus="clear()"/> +<input type="button" value="submit" onclick="submit()"/> +</div> +<script> +var BrowserDetect = { + init: function () { + this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; + this.version = this.searchVersion(navigator.userAgent) + || this.searchVersion(navigator.appVersion) + || "an unknown version"; + this.OS = this.searchString(this.dataOS) || "an unknown OS"; + }, + searchString: function (data) { + for (var i=0;i<data.length;i++) { + var dataString = data[i].string; + var dataProp = data[i].prop; + this.versionSearchString = data[i].versionSearch || data[i].identity; + if (dataString) { + if (dataString.indexOf(data[i].subString) != -1) + return data[i].identity; + } + else if (dataProp) + return data[i].identity; + } + }, + searchVersion: function (dataString) { + var index = dataString.indexOf(this.versionSearchString); + if (index == -1) return; + return parseFloat(dataString.substring(index+this.versionSearchString.length+1)); + }, + dataBrowser: [{ string: navigator.userAgent, subString: "Chrome", identity: "Chrome" }, + { string: navigator.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb" }, + { string: navigator.vendor, subString: "Apple", identity: "Safari", versionSearch: "Version" }, + { prop: window.opera, identity: "Opera", versionSearch: "Version" }, + { string: navigator.vendor, subString: "iCab", identity: "iCab" }, + { string: navigator.vendor, subString: "KDE", identity: "Konqueror" }, + { string: navigator.userAgent, subString: "Firefox", identity: "Firefox" }, + { string: navigator.vendor, subString: "Camino", identity: "Camino" }, + // for newer Netscapes (6+) + { string: navigator.userAgent, subString: "Netscape", identity: "Netscape" }, + { string: navigator.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE" }, + { string: navigator.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv" }, + // for older Netscapes (4-) + { string: navigator.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla" } + ], + dataOS : [ { string: navigator.platform, subString: "Win", identity: "Windows" }, + { string: navigator.platform, subString: "Mac", identity: "Mac" }, + { string: navigator.userAgent, subString: "iPhone", identity: "iPhone/iPod" }, + { string: navigator.platform, subString: "Linux", identity: "Linux" } + ] + +}; +</script> +<script> +//document.cursor = crosshair; + + +BrowserDetect.init(); + +function get_appropriate_ws_url() +{ + var pcol; + var u = document.URL; + + /* + * We open the websocket encrypted if this page came on an + * https:// url itself, otherwise unencrypted + */ + + if (u.substring(0, 5) == "https") { + pcol = "wss://"; + u = u.substr(8); + } else { + pcol = "ws://"; + if (u.substring(0, 4) == "http") + u = u.substr(7); + } + + u = u.split('/'); + + return pcol + u[0]; +} + + +//document.getElementById("create_task").style.display = ''; + +/* lws-mirror protocol */ + +var down = 0; +var no_last = 1; +var last_x = 0, last_y = 0; +var ctx; +var socket_lm; +var color = "#000000"; +var dragged = 0; + +// alert(BrowserDetect.browser); +if (BrowserDetect.browser == "Firefox") { + socket_lm = new MozWebSocket(get_appropriate_ws_url(), "lws-mirror-protocol"); +} else { + socket_lm = new WebSocket(get_appropriate_ws_url(), "lws-mirror-protocol"); +} + +try { + socket_lm.onopen = function() { + document.getElementById("wslm_status").style.backgroundColor = "#40ff40"; + document.getElementById("wslm_status").textContent = " websocket connection opened "; + document.getElementById("box").style.display = "none"; + } + + socket_lm.onmessage = function got_packet(msg) { +// alert(msg.data); + document.getElementById("wslm_lastmsg").textContent = msg.data; + + j = msg.data.split(';'); + f = 0; + while (f < j.length - 1) { + i = j[f].split(' '); + if (i[0] == 'd') { + ctx.strokeStyle = i[1]; + ctx.beginPath(); + ctx.moveTo(+(i[2]), +(i[3])); + ctx.lineTo(+(i[4]), +(i[5])); + ctx.stroke(); + } + else if (i[0] == 'c') { + ctx.strokeStyle = i[1]; + ctx.beginPath(); + ctx.arc(+(i[2]), +(i[3]), +(i[4]), 0, Math.PI*2, true); + ctx.stroke(); + } + else if (i[0] == "del") { +// alert("Deleting task"); + var task = document.getElementById("task_" + i[1]); +// task.style.display = "none"; + document.body.removeChild(task); + } + else if (i[0] == "add") { + var task = document.createElement("div"); + task.name = "task"; + task.id = "task_" + i[1]; + + var taskText = document.createTextNode(i[2] + ": " + i[3] + " :" + task.id); + task.appendChild(taskText); + + task.style.position = "absolute"; + task.style.left = i[4] + "px"; + task.style.top = i[5] + "px"; + task.style.backgroundColor = "grey"; + task.style.borderStyle= "solid"; + task.style.borderWidth= "medium"; + task.style.borderRadius= "15px"; + task.style.padding = "4px"; + + var dlButton = document.createElement("input"); + dlButton.type = "button"; + dlButton.value = "Remove"; +// dlButton.onclick = "deleteTask(document.getElementById(" + task.id + ").id"; + dlButton.setAttribute("onclick", "deleteTask(" + i[1] +")"); + task.appendChild(dlButton); + + document.body.appendChild(task); + } + f++; +// document.getElementById("box").style.top = i[3] + "px"; +// document.getElementById("box").style.left = i[2] + "px"; +// document.getElementById("box").style.display = "block"; + } + } + + socket_lm.onclose = function(){ + document.getElementById("wslm_status").style.backgroundColor = "#ff4040"; + document.getElementById("wslm_status").textContent = " websocket connection CLOSED "; + } +} catch(exception) { + alert('<p>Error' + exception + '</p>'); +} + +var canvas = document.createElement('canvas'); +canvas.height = 600; +canvas.width = 800; +ctx = canvas.getContext("2d"); + +document.getElementById('wslm_drawing').appendChild(canvas); + +canvas.addEventListener('mousemove', ev_mousemove, false); +canvas.addEventListener('mousedown', ev_mousedown, false); +canvas.addEventListener('mouseup', ev_mouseup, false); +//cancas.addEventListener('dragend', ev_mousemove, false); + +offsetX = offsetY = 0; +element = canvas; +if (element.offsetParent) { + do { + offsetX += element.offsetLeft; + offsetY += element.offsetTop; + } while ((element = element.offsetParent)); +} + +function update_color() { + color = document.getElementById("color").value; +} + +function ev_mousedown (ev) { + down = 1; + + var x, y; + + if (ev.offsetX) { + x = ev.offsetX; + y = ev.offsetY; + } else { + x = ev.layerX - offsetX; + y = ev.layerY - offsetY; + } +} + +function ev_mouseup(ev) { + down = 0; + no_last = 1; +} + +function ev_mousemove (ev) { + var x, y; + + if (ev.offsetX) { + x = ev.offsetX; + y = ev.offsetY; + } else { + x = ev.layerX - offsetX; + y = ev.layerY - offsetY; + + } + + if (!down) + return; + if (no_last) { + no_last = 0; + last_x = x; + last_y = y; + return; + } + socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y + ';'); + + last_x = x; + last_y = y; +} + +function submit() { + var data = document.getElementById("input_data").value; + alert(data); + socket_lm.send(data); +} + +function clear() { + alert('asd'); + document.getElementById("input_data").value = ""; +} + +function deleteTask(id) { +// alert(id); + socket_lm.send("del " + id + ";"); +} + +</script> + +</body> +</html> diff --git a/src/muniad.cc b/src/muniad.cc index f5d4d6a..e349e7c 100644 --- a/src/muniad.cc +++ b/src/muniad.cc @@ -31,6 +31,7 @@ #include <getopt.h> #include <string.h> #include <sys/time.h> +#include <list> #include <libwebsockets.h> @@ -71,14 +72,17 @@ static int callback_http(struct libwebsocket_context * context, case LWS_CALLBACK_HTTP: fprintf(stderr, "serving HTTP URI %s\n", (char *)in); +// add favicon later if(in && strcmp((const char *)in, "/favicon.ico") == 0) { if(libwebsockets_serve_http_file(wsi, LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon")) fprintf(stderr, "Failed to send favicon\n"); break; } + /* send the script... when it runs it'll start websockets */ - if (libwebsockets_serve_http_file(wsi, LOCAL_RESOURCE_PATH"/test.html", "text/html")) +// if (libwebsockets_serve_http_file(wsi, LOCAL_RESOURCE_PATH"/test.html", "text/html")) + if (libwebsockets_serve_http_file(wsi, LOCAL_RESOURCE_PATH"/munia.html", "text/html")) fprintf(stderr, "Failed to send HTTP file\n"); break; @@ -184,21 +188,35 @@ Protocol: Server -> client: update [id] [title] [description]; move [id] [x] [y]; - add [title] [description]; + add [id] [title] [description] [x] [y]; + del [id] Client -> server: update [id] [title] [description]; move [id] [x] [y]; - add [id] [title] [description] [x] [y]; + add [title] [description] [x] [y]; + del [id] title and description are " encapsulated utf-8 string with " escaped with a backslash. x and y are integers as strings id are an integer as a string */ +struct task { + int x, y; + int id; + std::string title; + std::string desc; +}; +typedef std::list<struct libwebsocket*> ClientList; +typedef std::list<struct task> TaskList; + +static TaskList tasklist; + static struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; static int ringbuffer_head; - +static ClientList clientlist; +static int id_count = 0; static int callback_lws_mirror(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, @@ -207,6 +225,8 @@ static int callback_lws_mirror(struct libwebsocket_context * context, int n; struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user; + printf("Current number of clients: %d\n", clientlist.size()); + switch (reason) { case LWS_CALLBACK_ESTABLISHED: @@ -214,12 +234,35 @@ static int callback_lws_mirror(struct libwebsocket_context * context, fprintf(stderr, "callback_lws_mirror: LWS_CALLBACK_ESTABLISHED\n"); pss->ringbuffer_tail = ringbuffer_head; pss->wsi = wsi; + clientlist.push_back(wsi); + + // send all current tasks + char buf[32]; + std::string init_str; + TaskList::iterator it; + for(it = tasklist.begin(); it != tasklist.end(); it++) { + struct task t = *it; + + sprintf(buf, "add %d %s %s %d %d;", + t.id, t.title.c_str(), t.desc.c_str(), t.x, t.y); + init_str.append(buf); + } + + libwebsocket_write(wsi, (unsigned char*) init_str.data(), init_str.length(), LWS_WRITE_TEXT); + } break; + case LWS_CALLBACK_CLOSED: + { + printf("Closing connection\n"); + clientlist.remove(wsi); + } + case LWS_CALLBACK_SERVER_WRITEABLE: { printf("LWS_CALLBACK_SERVER_WRITEABLE\n"); + if(close_testing) break; if(pss->ringbuffer_tail != ringbuffer_head) { @@ -258,31 +301,98 @@ static int callback_lws_mirror(struct libwebsocket_context * context, std::string data; data.append((char*)in, len); + + struct a_message &msg = ringbuffer[ringbuffer_head]; + if(msg.payload) { + free(msg.payload); + msg.payload = NULL; + } + + char* buf = (char*) malloc(1024); + int buf_len = 0; + std::string cmd = data.substr(0, data.find(' ')); printf("Cmd: %s\n", cmd.c_str()); if(cmd == "add") { - printf("Add\n"); + printf("Handling add cmd:\n"); + int offset = cmd.length() + 1; + std::string title = data.substr(offset, data.find(' ', offset) - offset); + offset += title.length() + 1; + std::string desc = data.substr(offset, data.find(' ', offset) - offset); + offset += desc.length() + 1; + std::string x_str = data.substr(offset, data.find(' ', offset) - offset); + int x = atoi(x_str.c_str()); + offset += x_str.length() + 1; + std::string y_str = data.substr(offset, data.find(' ', offset) - offset); + int y = atoi(y_str.c_str()); + + struct task t; + t.x = x; + t.y = y; + t.title = title; + t.desc = desc; + t.id = id_count; id_count++; + tasklist.push_back(t); + + buf_len = sprintf(buf, "add %d %s %s %d %d;", + t.id, t.title.c_str(), t.desc.c_str(), + t.x, t.y); + + printf("Adding task: %s\n", buf); + + } else if(cmd == "del") { + printf("Delete\n"); + int offset = cmd.length() + 1; + std::string id_str = data.substr(offset, data.find(' ', offset) - offset); + int id = atoi(id_str.c_str()); + printf("Deleting task with id %d\n", id); + + bool id_found = false; + TaskList::iterator it; + for(it = tasklist.begin(); it != tasklist.end(); it++) { + struct task t = *it; + if(t.id == id) { + id_found = true; + tasklist.erase(it); + break; + } + } + + if(!id_found) { + printf("\t!!!Could not locate task with id %d\n", id); + } + + buf_len = sprintf(buf, "del %d;", id); + printf("Deleting task: %s\n", buf); } else if(cmd == "move") { printf("Move\n"); } else if(cmd == "update") { printf("Update\n"); - } else { // unknown command - + } else if(cmd == "d") { + memcpy(buf, in, len); + buf_len = len; } - - struct a_message &msg = ringbuffer[ringbuffer_head]; - if(msg.payload) { - free(msg.payload); - msg.payload = NULL; + else { // unknown command + printf("Unknown command :(\n"); + break; } - msg.payload = malloc(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING); - msg.len = len; - memcpy((char *)msg.payload + LWS_SEND_BUFFER_PRE_PADDING, in, len); +// msg.payload = malloc(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING); +// msg.len = len; +// memcpy((char *)msg.payload + LWS_SEND_BUFFER_PRE_PADDING, in, len); +// if(ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) ringbuffer_head = 0; +// else ringbuffer_head++; + + msg.payload = malloc(LWS_SEND_BUFFER_PRE_PADDING + buf_len + + LWS_SEND_BUFFER_POST_PADDING); + msg.len = buf_len; + memcpy((char *)msg.payload + LWS_SEND_BUFFER_PRE_PADDING, + buf, buf_len); if(ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) ringbuffer_head = 0; else ringbuffer_head++; - + + if(((ringbuffer_head - pss->ringbuffer_tail) % MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10)) libwebsocket_rx_flow_control(wsi, 0); @@ -355,7 +465,7 @@ int main(int argc, char **argv) char interface_name[128] = ""; const char * interface = NULL; #ifdef LWS_NO_FORK - unsigned int oldus = 0; +// unsigned int oldus = 0; #endif fprintf(stderr, "libwebsockets test server\n" |