/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * task_proto.cc * * Fri Feb 24 08:23:16 CET 2012 * Copyright 2012 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of Munia. * * Munia is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Munia is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Munia; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "task_proto.h" #include #include #include #include #include "task.h" #include "msgparser.h" static void dump_handshake_info(struct lws_tokens *lwst) { int n; static const char *token_names[WSI_TOKEN_COUNT] = { /*[WSI_TOKEN_GET_URI] =*/ "GET URI", /*[WSI_TOKEN_HOST] =*/ "Host", /*[WSI_TOKEN_CONNECTION] =*/ "Connection", /*[WSI_TOKEN_KEY1] =*/ "key 1", /*[WSI_TOKEN_KEY2] =*/ "key 2", /*[WSI_TOKEN_PROTOCOL] =*/ "Protocol", /*[WSI_TOKEN_UPGRADE] =*/ "Upgrade", /*[WSI_TOKEN_ORIGIN] =*/ "Origin", /*[WSI_TOKEN_DRAFT] =*/ "Draft", /*[WSI_TOKEN_CHALLENGE] =*/ "Challenge", /* new for 04 */ /*[WSI_TOKEN_KEY] =*/ "Key", /*[WSI_TOKEN_VERSION] =*/ "Version", /*[WSI_TOKEN_SWORIGIN] =*/ "Sworigin", /* new for 05 */ /*[WSI_TOKEN_EXTENSIONS] =*/ "Extensions", /* client receives these */ /*[WSI_TOKEN_ACCEPT] =*/ "Accept", /*[WSI_TOKEN_NONCE] =*/ "Nonce", /*[WSI_TOKEN_HTTP] =*/ "Http", /*[WSI_TOKEN_MUXURL] =*/ "MuxURL", }; for (n = 0; n < WSI_TOKEN_COUNT; n++) { if (lwst[n].token == NULL || lwst[n].token_len == 0) continue; fprintf(stderr, " %s = ", token_names[n]); if(fwrite(lwst[n].token, 1, lwst[n].token_len, stderr)) {} fprintf(stderr, "\n"); } } std::map > msgqueue; int callback_lws_task(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { int n; struct per_session_data__lws_task *pss = (struct per_session_data__lws_task *)user; switch (reason) { printf("============= Reason %d\n", reason); case LWS_CALLBACK_ESTABLISHED: { fprintf(stderr, "callback_lws_task: LWS_CALLBACK_ESTABLISHED\n"); // pss->ringbuffer_tail = ringbuffer_head; pss->wsi = wsi; // send all current tasks char buf[32]; std::string init_str; TaskList::iterator it; for(it = tasklist.begin(); it != tasklist.end(); it++) { task_t 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); } std::string msg; msg.append((size_t)LWS_SEND_BUFFER_PRE_PADDING, ' '); msg.append(init_str); msg.append((size_t)LWS_SEND_BUFFER_POST_PADDING, ' '); msgqueue[wsi].push(msg); libwebsocket_callback_on_writable(context, wsi); } break; case LWS_CALLBACK_CLOSED: { printf("Closing connection\n"); msgqueue.erase(wsi); } case LWS_CALLBACK_SERVER_WRITEABLE: { printf("LWS_CALLBACK_SERVER_WRITEABLE\n"); // if(pss->ringbuffer_tail != ringbuffer_head) { if(msgqueue[wsi].size() > 0) { std::string msg = msgqueue[wsi].front(); msgqueue[wsi].pop(); n = libwebsocket_write(wsi, (unsigned char *) msg.c_str() + LWS_SEND_BUFFER_PRE_PADDING, msg.length() - LWS_SEND_BUFFER_POST_PADDING - LWS_SEND_BUFFER_PRE_PADDING, LWS_WRITE_TEXT); if(n < 0) { fprintf(stderr, "ERROR writing to socket"); exit(1); } } if(msgqueue[wsi].size()) { libwebsocket_rx_flow_control(wsi, 1); libwebsocket_callback_on_writable(context, wsi); } } break; case LWS_CALLBACK_BROADCAST: printf("LWS_CALLBACK_BROADCAST\n"); n = libwebsocket_write(wsi, (unsigned char*)in, len, LWS_WRITE_TEXT); if (n < 0) fprintf(stderr, "task write failed\n"); break; case LWS_CALLBACK_RECEIVE: { printf("LWS_CALLBACK_RECEIVE\n"); printf("%s\n", (char*)in); 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[1024]; size_t buf_len = 0; msg_t m = parse_msg(data)[0]; switch(m.cmd) { case cmd::add: { printf("Handling add cmd:\n"); task_t t =create_task(m.add.title, m.add.desc, m.add.x, m.add.y); 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); break; } case cmd::del: { printf("Delete\n"); printf("Deleting task with id %d\n", m.del.id); bool id_found = false; TaskList::iterator it; for(it = tasklist.begin(); it != tasklist.end(); it++) { task_t t = *it; if(t.id == m.del.id) { id_found = true; tasklist.erase(it); break; } } if(!id_found) { printf("\t!!!Could not locate task with id %d\n", m.del.id); } buf_len = sprintf(buf, "del %d;", m.del.id); printf("Deleting task: %s\n", buf); break; } case cmd::move: { printf("Move\n"); printf("Moving task with id %d to (%d,%d)\n", m.move.id, m.move.x, m.move.y); bool id_found = false; TaskList::iterator it; int x = m.move.x / 300 * 300; for(it = tasklist.begin(); it != tasklist.end(); it++) { task_t t = *it; if(t.id == m.move.id) { id_found = true; t.x = x; t.y = m.move.y; break; } } if(!id_found) { printf("\t!!!Could not locate task with id %d\n", m.move.id); } buf_len = sprintf(buf, "move %d %d %d;", m.move.id, x, m.move.y); printf("Moving task: %s\n", buf); break; } case cmd::update: printf("Update\n"); break; default: printf("Wrong 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); // 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++; */ std::string msg; msg.append((size_t)LWS_SEND_BUFFER_PRE_PADDING, ' '); msg.append(buf, buf_len); msg.append((size_t)LWS_SEND_BUFFER_POST_PADDING, ' '); std::map >::iterator it = msgqueue.begin(); while(it != msgqueue.end()) { printf("!!\n"); it->second.push(msg); it++; } /* if(((ringbuffer_head - pss->ringbuffer_tail) % MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10)) libwebsocket_rx_flow_control(wsi, 0); */ libwebsocket_callback_on_writable_all_protocol(libwebsockets_get_protocol(wsi)); //libwebsocket_rx_flow_control(wsi, 0); } break; /* * this just demonstrates how to use the protocol filter. If you won't * study and reject connections based on header content, you don't need * to handle this callback */ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: printf("LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION\n"); dump_handshake_info((struct lws_tokens *)(long)user); /* you could return non-zero here and kill the connection */ break; default: break; } return 0; }