summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Suhr Christensen <jsc@umbraculum.org>2012-02-23 10:34:23 +0100
committerJonas Suhr Christensen <jsc@umbraculum.org>2012-02-23 10:34:23 +0100
commit3cbbce9bbe2e63554d253bca8c313e27a16c9b12 (patch)
treebda12b8eb1164606baac9367fe720cc172c6a481
parent93890eace0b7a35cb597272e7449b1e0ee533a73 (diff)
Implemented add and remove.
Implemented task list on new connection.
-rw-r--r--munia.html284
-rw-r--r--src/muniad.cc144
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"