diff --git a/examples/pubsub.html b/examples/pubsub.html new file mode 100644 index 00000000..f73d8f68 --- /dev/null +++ b/examples/pubsub.html @@ -0,0 +1,98 @@ + + + + + WebSocket Test + + + + + + +
+

Websocket PubSub Demonstration

+ +

+ This page demonstrates how Mongoose web server could be used to implement + + publish–subscribe pattern. Open this page in several browser + windows. Each window initiates persistent + WebSocket + connection with Mongoose, making each browser window a websocket client. + Join a room, send messages, and see messages sent by other clients. +

+ +

+ My ID: +

+

+ Join room: +

+ +
+
+ +

+ + +

+
+ + diff --git a/examples/websocket2.c b/examples/websocket2.c new file mode 100644 index 00000000..d0be9bbe --- /dev/null +++ b/examples/websocket2.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include "mongoose.h" + +static int s_signal_received = 0; +static struct mg_server *s_server = NULL; + +// Data associated with each websocket connection +struct conn_data { + int room; +}; + +static void signal_handler(int sig_num) { + signal(sig_num, signal_handler); // Reinstantiate signal handler + s_signal_received = sig_num; +} + +#if 0 +static int iterate_callback(struct mg_connection *c, enum mg_event ev) { + if (ev == MG_POLL && c->is_websocket) { + char buf[20]; + int len = snprintf(buf, sizeof(buf), "%lu", + (unsigned long) * (time_t *) c->callback_param); + mg_websocket_write(c, 1, buf, len); + } + return MG_TRUE; +} +#endif + +static void handle_websocket_message(struct mg_connection *conn) { + struct conn_data *d = (struct conn_data *) conn->connection_param; + struct mg_connection *c; + + printf("[%.*s]\n", (int) conn->content_len, conn->content); + if (conn->content_len > 5 && !memcmp(conn->content, "join ", 5)) { + // Client joined new room + d->room = conn->content[5]; + } else if (conn->content_len > 4 && !memcmp(conn->content, "msg ", 4) && + d->room != 0 && d->room != '?') { + // Client has sent a message. Push this message to all clients + // that are subscribed to the same room as client + for (c = mg_next(s_server, NULL); c != NULL; c = mg_next(s_server, c)) { + struct conn_data *d2 = (struct conn_data *) c->connection_param; + if (!c->is_websocket || d2->room != d->room) continue; + mg_websocket_printf(c, WEBSOCKET_OPCODE_TEXT, "msg %c %p %.*s", + (char) d->room, conn, + conn->content_len - 4, conn->content + 4); + } + } +} + +static int ev_handler(struct mg_connection *conn, enum mg_event ev) { + switch (ev) { + case MG_REQUEST: + if (conn->is_websocket) { + handle_websocket_message(conn); + return MG_TRUE; + } else { + mg_send_file(conn, "pubsub.html"); // Return MG_MORE after mg_send_file() + return MG_MORE; + } + case MG_WS_CONNECT: + // New websocket connection. Send connection ID back to the client. + conn->connection_param = calloc(1, sizeof(struct conn_data)); + mg_websocket_printf(conn, WEBSOCKET_OPCODE_TEXT, "id %p", conn); + return MG_FALSE; + case MG_CLOSE: + free(conn->connection_param); + return MG_TRUE; + case MG_AUTH: + return MG_TRUE; + default: + return MG_FALSE; + } +} + +int main(void) { + s_server = mg_create_server(NULL, ev_handler); + mg_set_option(s_server, "listening_port", "8080"); + + signal(SIGTERM, signal_handler); + signal(SIGINT, signal_handler); + + printf("Started on port %s\n", mg_get_option(s_server, "listening_port")); + while (s_signal_received == 0) { + mg_poll_server(s_server, 100); + } + mg_destroy_server(&s_server); + return 0; +}