#include "notify.h"
#include "channels.h"
#include "config.h"
+#include "htsmsg_json.h"
#if ENABLE_ANDROID
#include <sys/socket.h>
http_rc2str(int code)
{
switch(code) {
+ case HTTP_STATUS_PSWITCH: /* 101 */ return "Switching Protocols";
case HTTP_STATUS_OK: /* 200 */ return "OK";
case HTTP_STATUS_PARTIAL_CONTENT: /* 206 */ return "Partial Content";
case HTTP_STATUS_FOUND: /* 302 */ return "Found";
tcp_write_queue(hc->hc_fd, &hdrs);
}
+/*
+ * Transmit a websocket upgrade reply
+ */
+int
+http_send_header_websocket(http_connection_t *hc, const char *protocol)
+{
+ htsbuf_queue_t hdrs;
+ const int rc = HTTP_STATUS_PSWITCH;
+ uint8_t hash[20];
+ const char *s;
+ const char *guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ char encoded[512];
+
+ s = http_arg_get(&hc->hc_args, "sec-websocket-key");
+ if (s == NULL || strlen(s) < 10) {
+ http_error(hc, HTTP_STATUS_UNSUPPORTED);
+ return -1;
+ }
+
+ htsbuf_queue_init(&hdrs, 0);
+
+ htsbuf_qprintf(&hdrs, "%s %d %s\r\n",
+ http_ver2str(hc->hc_version), rc, http_rc2str(rc));
+
+ sha1_calc(hash, (uint8_t *)s, strlen(s), (uint8_t *)guid, strlen(guid));
+ base64_encode(encoded, sizeof(encoded), hash, sizeof(hash));
+
+ htsbuf_qprintf(&hdrs, "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Accept: %s\r\n"
+ "Sec-WebSocket-Protocol: %s\r\n"
+ "\r\n",
+ encoded, protocol);
+
+ pthread_mutex_lock(&hc->hc_fd_lock);
+ tcp_write_queue(hc->hc_fd, &hdrs);
+ pthread_mutex_unlock(&hc->hc_fd_lock);
+ return 0;
+}
+
/*
*
*/
return 0;
}
+/**
+ *
+ */
+int
+http_header_match(http_connection_t *hc, const char *name, const char *value)
+{
+ char *tokbuf, *tok, *saveptr = NULL, *q, *s;
+
+ s = http_arg_get(&hc->hc_args, name);
+ if (s == NULL)
+ return 0;
+ tokbuf = tvh_strdupa(s);
+ tok = strtok_r(tokbuf, ",", &saveptr);
+ while (tok) {
+ while (*tok == ' ')
+ tok++;
+ s = tok;
+ if (*s == '"') {
+ q = strchr(++s, '"');
+ if (q)
+ *q = '\0';
+ } else {
+ q = strchr(s, ' ');
+ if (q)
+ *q = '\0';
+ }
+ if (strcasecmp(s, value) == 0)
+ return 1;
+ tok = strtok_r(NULL, ",", &saveptr);
+ }
+ return 0;
+}
+
/**
*
*/
return res;
}
+/**
+ *
+ */
+static int
+http_websocket_valid(http_connection_t *hc)
+{
+ if (!http_header_match(hc, "connection", "upgrade") ||
+ http_arg_get(&hc->hc_args, "sec-websocket-key") == NULL)
+ return HTTP_STATUS_UNSUPPORTED;
+ return 0;
+}
+
/**
* Execute url callback
*
if ((hc->hc_username && hc->hc_username[0] == '\0') ||
http_access_verify(hc, hp->hp_accessmask)) {
- if (!hp->hp_no_verification) {
+ if ((hp->hp_flags & HTTP_PATH_NO_VERIFICATION) == 0) {
err = HTTP_STATUS_UNAUTHORIZED;
goto destroy;
}
}
+ if (hp->hp_flags & HTTP_PATH_WEBSOCKET) {
+ err = http_websocket_valid(hc);
+ if (err)
+ goto destroy;
+ }
err = hp->hp_callback(hc, remain, hp->hp_opaque);
destroy:
access_destroy(hc->hc_access);
hp->hp_callback = callback;
hp->hp_accessmask = accessmask;
hp->hp_path_modify = path_modify;
- hp->hp_no_verification = 0;
+ hp->hp_flags = 0;
pthread_mutex_lock(&http_paths_mutex);
LIST_INSERT_HEAD(&http_paths, hp, hp_link);
pthread_mutex_unlock(&http_paths_mutex);
return http_path_add_modify(path, opaque, callback, accessmask, NULL);
}
+/**
+ *
+ */
+int
+http_websocket_send(http_connection_t *hc, uint8_t *buf, uint64_t buflen,
+ int opcode)
+{
+ int op, r = 0;
+ uint8_t b[10];
+ uint64_t bsize;
+
+ switch (opcode) {
+ case HTTP_WSOP_TEXT: op = 0x01; break;
+ case HTTP_WSOP_BINARY: op = 0x02; break;
+ case HTTP_WSOP_PING: op = 0x09; break;
+ case HTTP_WSOP_PONG: op = 0x0a; break;
+ default: return -1;
+ }
+
+ b[0] = 0x80 | op; /* FIN + opcode */
+ if (buflen <= 125) {
+ b[1] = buflen;
+ bsize = 2;
+ } else if (buflen <= 65535) {
+ b[1] = 126;
+ b[2] = (buflen >> 8) & 0xff;
+ b[3] = buflen & 0xff;
+ bsize = 4;
+ } else {
+ b[1] = 127;
+ b[2] = (buflen >> 56) & 0xff;
+ b[3] = (buflen >> 48) & 0xff;
+ b[4] = (buflen >> 40) & 0xff;
+ b[5] = (buflen >> 32) & 0xff;
+ b[6] = (buflen >> 24) & 0xff;
+ b[7] = (buflen >> 16) & 0xff;
+ b[8] = (buflen >> 8) & 0xff;
+ b[9] = (buflen >> 0) & 0xff;
+ bsize = 10;
+ }
+ pthread_mutex_lock(&hc->hc_fd_lock);
+ if (tvh_write(hc->hc_fd, b, bsize))
+ r = -1;
+ if (r == 0 && tvh_write(hc->hc_fd, buf, buflen))
+ r = -1;
+ pthread_mutex_unlock(&hc->hc_fd_lock);
+ return r;
+}
+
+/**
+ *
+ */
+int
+http_websocket_send_json(http_connection_t *hc, htsmsg_t *msg)
+{
+ htsbuf_queue_t q;
+ char *s;
+ int r;
+
+ htsbuf_queue_init(&q, 0);
+ htsmsg_json_serialize(msg, &q, 0);
+ s = htsbuf_to_string(&q);
+ htsbuf_queue_flush(&q);
+ r = http_websocket_send(hc, (uint8_t *)s, strlen(s), HTTP_WSOP_TEXT);
+ free(s);
+ return r;
+}
+
+/**
+ *
+ */
+int
+http_websocket_read(http_connection_t *hc, htsmsg_t **_res, int timeout)
+{
+ htsmsg_t *msg, *msg1;
+ uint8_t b[2], bl[8], *p;
+ int op, r;
+ uint64_t plen, pi;
+
+ *_res = NULL;
+again:
+ r = tcp_read_timeout(hc->hc_fd, b, 2, timeout);
+ if (r == ETIMEDOUT)
+ return 0;
+ if (r) /* closed connection */
+ return -1;
+ if ((b[1] & 0x80) == 0) /* accept only masked messages */
+ return -1;
+ switch (b[0] & 0x0f) { /* opcode */
+ case 0x0: /* continuation */
+ goto again;
+ case 0x1: /* text */
+ op = HTTP_WSOP_TEXT;
+ break;
+ case 0x2: /* binary */
+ op = HTTP_WSOP_BINARY;
+ break;
+ case 0x8: /* close connection */
+ return -1;
+ case 0x9: /* ping */
+ op = HTTP_WSOP_PING;
+ break;
+ case 0xa: /* pong */
+ op = HTTP_WSOP_PONG;
+ break;
+ default:
+ return -1;
+ }
+ plen = b[1] & 0x7f;
+ if (plen == 126) {
+ if (tcp_read(hc->hc_fd, bl, 2))
+ return -1;
+ plen = (bl[0] << 8) | bl[1];
+ } else if (plen == 127) {
+ if (tcp_read(hc->hc_fd, bl, 8))
+ return -1;
+ plen = ((uint64_t)bl[0] << 56) | ((uint64_t)bl[1] << 48) |
+ ((uint64_t)bl[2] << 40) | ((uint64_t)bl[3] << 32) |
+ ((uint64_t)bl[4] << 24) | ((uint64_t)bl[5] << 16) |
+ ((uint64_t)bl[6] << 8 ) | ((uint64_t)bl[7] << 0);
+ }
+ if (plen > 5*1024*1024)
+ return -1;
+ p = malloc(plen + 1);
+ if (p == NULL)
+ return -1;
+ if (tcp_read(hc->hc_fd, bl, 4))
+ return -1;
+ if (tcp_read(hc->hc_fd, p, plen))
+ return -1;
+ /* apply mask descrambling */
+ for (pi = 0; pi < plen; pi++)
+ p[pi] ^= bl[pi & 3];
+ if (op == HTTP_WSOP_PING) {
+ http_websocket_send(hc, p, plen, HTTP_WSOP_PONG);
+ goto again;
+ }
+ msg = htsmsg_create_map();
+ htsmsg_add_s32(msg, "op", op);
+ if (op == HTTP_WSOP_TEXT) {
+ p[plen] = '\0';
+ msg1 = p[0] == '{' || p[0] == '[' ?
+ htsmsg_json_deserialize((char *)p) : NULL;
+ if (msg1)
+ htsmsg_add_msg(msg, "json", msg1);
+ else
+ htsmsg_add_str(msg, "text", (char *)p);
+ } else {
+ htsmsg_add_bin(msg, "bin", p, plen);
+ }
+ *_res = msg;
+ return 0;
+}
+
/**
* Parse arguments of a HTTP GET url, not perfect, but works for us
*/
#define HTTP_H_
#include "htsbuf.h"
+#include "htsmsg.h"
#include "url.h"
#include "tvhpoll.h"
- #include "access.h"
+#include "access.h"
struct channel;
struct http_path;
RTSP_VERSION_1_0,
} http_ver_t;
+typedef enum http_wsop {
+ HTTP_WSOP_TEXT = 0,
+ HTTP_WSOP_BINARY = 1,
+ HTTP_WSOP_PING = 2,
+ HTTP_WSOP_PONG = 3
+} http_wsop_t;
+
typedef struct http_connection {
pthread_mutex_t hc_fd_lock;
int hc_fd;
int http_encoding_valid(http_connection_t *hc, const char *encoding);
+int http_header_match(http_connection_t *hc, const char *name, const char *value);
+
void http_output_html(http_connection_t *hc);
void http_output_content(http_connection_t *hc, const char *content);
const char *location, int maxage, const char *range,
const char *disposition, http_arg_list_t *args);
+int http_send_header_websocket(http_connection_t *hc, const char *protocol);
+
+int http_websocket_send(http_connection_t *hc, uint8_t *buf, uint64_t buflen, int opcode);
+
+int http_websocket_send_json(http_connection_t *hc, htsmsg_t *msg);
+
+int http_websocket_read(http_connection_t *hc, htsmsg_t **_res, int timeout);
+
void http_serve_requests(http_connection_t *hc);
void http_cancel(void *opaque);
typedef char * (http_path_modify_t)(http_connection_t *hc,
const char * path, int *cut);
+#define HTTP_PATH_NO_VERIFICATION (1 << 0)
+#define HTTP_PATH_WEBSOCKET (1 << 1)
typedef struct http_path {
LIST_ENTRY(http_path) hp_link;
void *hp_opaque;
http_callback_t *hp_callback;
int hp_len;
- int hp_no_verification;
+ uint32_t hp_flags;
uint32_t hp_accessmask;
http_path_modify_t *hp_path_modify;
} http_path_t;
typedef struct comet_mailbox {
char *cmb_boxid; /* SHA-1 hash */
char *cmb_lang; /* UI language */
+ int cmb_refcount;
int cmb_restricted; /* !admin */
htsmsg_t *cmb_messages; /* A vector */
int64_t cmb_last_used;
free(cmb);
}
-
/**
*
*/
for(cmb = LIST_FIRST(&mailboxes); cmb != NULL; cmb = next) {
next = LIST_NEXT(cmb, cmb_link);
- if(cmb->cmb_last_used && cmb->cmb_last_used + sec2mono(60) < mclk())
+ if(cmb->cmb_refcount == 1 &&
+ cmb->cmb_last_used && cmb->cmb_last_used + sec2mono(60) < mclk())
cmb_destroy(cmb);
}
pthread_mutex_unlock(&comet_mutex);
}
-
/**
*
*/
cmb->cmb_boxid = strdup(id);
cmb->cmb_lang = lang ? strdup(lang) : NULL;
+ cmb->cmb_refcount = 1;
cmb->cmb_last_used = mclk();
mailbox_tally++;
htsmsg_add_msg(cmb->cmb_messages, NULL, m);
}
-
/**
- * Poll callback
+ *
*/
-static int
-comet_mailbox_poll(http_connection_t *hc, const char *remain, void *opaque)
+static htsmsg_t *
+comet_message(comet_mailbox_t *cmb, int include_boxid, int ignore_null)
{
- comet_mailbox_t *cmb = NULL;
- const char *cometid = http_arg_get(&hc->hc_req_args, "boxid");
- const char *immediate = http_arg_get(&hc->hc_req_args, "immediate");
- const char *lang = hc->hc_access->aa_lang_ui;
- int im = immediate ? atoi(immediate) : 0, e;
- int64_t mono;
htsmsg_t *m;
- if(!im)
- tvh_safe_usleep(100000); /* Always sleep 0.1 sec to avoid comet storms */
+ if (ignore_null && cmb->cmb_messages == NULL)
+ return NULL;
+ m = htsmsg_create_map();
+ if (include_boxid)
+ htsmsg_add_str(m, "boxid", cmb->cmb_boxid);
+ htsmsg_add_msg(m, "messages", cmb->cmb_messages ?: htsmsg_create_list());
+ cmb->cmb_messages = NULL;
+ cmb->cmb_last_used = mclk();
+ return m;
+}
- pthread_mutex_lock(&comet_mutex);
- if (!atomic_get(&comet_running)) {
- pthread_mutex_unlock(&comet_mutex);
- return HTTP_STATUS_BAD_REQUEST;
- }
+/**
+ *
+ */
+static comet_mailbox_t *
+comet_find_mailbox(http_connection_t *hc, const char *cometid, const char *lang, int create)
+{
+ comet_mailbox_t *cmb = NULL;
- if(cometid != NULL)
+ if (!atomic_get(&comet_running))
+ return NULL;
+
+ if (cometid != NULL)
LIST_FOREACH(cmb, &mailboxes, cmb_link)
if(!strcmp(cmb->cmb_boxid, cometid))
break;
+
+ if (!create)
+ return cmb;
- if(cmb == NULL) {
+ if (cmb == NULL) {
cmb = comet_mailbox_create(lang);
comet_access_update(hc, cmb);
comet_serverIpPort(hc, cmb);
}
}
+ return cmb;
+}
+
+/**
+ * Poll callback
+ */
+static int
+comet_mailbox_poll(http_connection_t *hc, const char *remain, void *opaque)
+{
+ comet_mailbox_t *cmb = NULL;
+ const char *cometid = http_arg_get(&hc->hc_req_args, "boxid");
+ const char *immediate = http_arg_get(&hc->hc_req_args, "immediate");
+ const char *lang = hc->hc_access->aa_lang_ui;
+ int im = immediate ? atoi(immediate) : 0, e;
+ int64_t mono;
+ htsmsg_t *m;
+
+ if(!im)
+ tvh_safe_usleep(100000); /* Always sleep 0.1 sec to avoid comet storms */
+
+ pthread_mutex_lock(&comet_mutex);
+ cmb = comet_find_mailbox(hc, cometid, lang, 1);
+ if (cmb == NULL) {
+ pthread_mutex_unlock(&comet_mutex);
+ return HTTP_STATUS_BAD_REQUEST;
+ }
+
if(!im && cmb->cmb_messages == NULL) {
mono = mclk() + sec2mono(10);
comet_waiting++;
comet_waiting--;
if (!atomic_get(&comet_running)) {
pthread_mutex_unlock(&comet_mutex);
- return 400;
+ return HTTP_STATUS_BAD_REQUEST;
}
}
- m = htsmsg_create_map();
- htsmsg_add_str(m, "boxid", cmb->cmb_boxid);
- htsmsg_add_msg(m, "messages", cmb->cmb_messages ?: htsmsg_create_list());
- cmb->cmb_messages = NULL;
-
- cmb->cmb_last_used = mclk();
-
+ m = comet_message(cmb, 1, 0);
pthread_mutex_unlock(&comet_mutex);
htsmsg_json_serialize(m, &hc->hc_reply, 0);
return 0;
}
-
/**
* Poll callback
*/
const char *s;
if(cometid == NULL)
- return 400;
+ return HTTP_STATUS_BAD_REQUEST;
pthread_mutex_lock(&comet_mutex);
-
- LIST_FOREACH(cmb, &mailboxes, cmb_link) {
- if(!strcmp(cmb->cmb_boxid, cometid)) {
- char buf[64];
- cmb->cmb_debug = !cmb->cmb_debug;
-
- if(cmb->cmb_messages == NULL)
- cmb->cmb_messages = htsmsg_create_list();
-
- if(cmb->cmb_restricted || http_access_verify(hc, ACCESS_ADMIN))
- s = N_("Only admin can watch the realtime log.");
- else if(cmb->cmb_debug)
- s = N_("Loglevel debug: enabled");
- else
- s = N_("Loglevel debug: disabled");
- snprintf(buf, sizeof(buf), "%s", tvh_gettext_lang(lang, s));
-
- htsmsg_t *m = htsmsg_create_map();
- htsmsg_add_str(m, "notificationClass", "logmessage");
- htsmsg_add_str(m, "logtxt", buf);
- htsmsg_add_msg(cmb->cmb_messages, NULL, m);
-
- tvh_cond_signal(&comet_cond, 1);
- break;
- }
+ cmb = comet_find_mailbox(hc, cometid, lang, 0);
+ if (cmb) {
+ char buf[64];
+ cmb->cmb_debug = !cmb->cmb_debug;
+
+ if(cmb->cmb_messages == NULL)
+ cmb->cmb_messages = htsmsg_create_list();
+
+ if(cmb->cmb_restricted || http_access_verify(hc, ACCESS_ADMIN))
+ s = N_("Only admin can watch the realtime log.");
+ else if(cmb->cmb_debug)
+ s = N_("Loglevel debug: enabled");
+ else
+ s = N_("Loglevel debug: disabled");
+ snprintf(buf, sizeof(buf), "%s", tvh_gettext_lang(lang, s));
+
+ htsmsg_t *m = htsmsg_create_map();
+ htsmsg_add_str(m, "notificationClass", "logmessage");
+ htsmsg_add_str(m, "logtxt", buf);
+ htsmsg_add_msg(cmb->cmb_messages, NULL, m);
+
+ tvh_cond_signal(&comet_cond, 1);
}
pthread_mutex_unlock(&comet_mutex);
return 0;
}
+/**
+ *
+ */
+static void
+comet_mailbox_ws_msg(http_connection_t *hc, comet_mailbox_t *cmb, int first, htsmsg_t *msg)
+{
+ htsmsg_t *m = NULL;
+ pthread_mutex_lock(&comet_mutex);
+ if (!atomic_get(&comet_running)) {
+ pthread_mutex_unlock(&comet_mutex);
+ return;
+ }
+ m = comet_message(cmb, first, 1);
+ cmb->cmb_last_used = 0;
+ pthread_mutex_unlock(&comet_mutex);
+ if (m)
+ http_websocket_send_json(hc, m);
+}
+
+/**
+ * Websocket handler
+ */
+static int
+comet_mailbox_ws(http_connection_t *hc, const char *remain, void *opaque)
+{
+ int res, first = 1;
+ htsmsg_t *msg;
+ const char *cometid = http_arg_get(&hc->hc_req_args, "boxid");
+ const char *lang = hc->hc_access->aa_lang_ui;
+ comet_mailbox_t *cmb;
+
+ res = http_send_header_websocket(hc, "tvheadend-comet");
+
+ pthread_mutex_lock(&comet_mutex);
+ cmb = comet_find_mailbox(hc, cometid, lang, 1);
+ if (cmb)
+ cmb->cmb_refcount++;
+ pthread_mutex_unlock(&comet_mutex);
+ if (!cmb)
+ return -1;
+
+ while (res == 0) {
+ if (!atomic_get(&comet_running)) {
+ res = -1;
+ continue;
+ }
+ res = http_websocket_read(hc, &msg, 1000);
+ if (res >= 0) {
+ comet_mailbox_ws_msg(hc, cmb, first, msg);
+ htsmsg_destroy(msg);
+ first = 0;
+ }
+ }
+
+ pthread_mutex_lock(&comet_mutex);
+ cmb->cmb_refcount--;
+ pthread_mutex_unlock(&comet_mutex);
+
+ return res;
+}
+
/**
*
*/
void
comet_init(void)
{
+ http_path_t *hp;
+
pthread_mutex_lock(&comet_mutex);
tvh_cond_init(&comet_cond);
atomic_set(&comet_running, 1);
comet_waiting = 0;
pthread_mutex_unlock(&comet_mutex);
+ hp = http_path_add("/comet/ws", NULL, comet_mailbox_ws, ACCESS_WEB_INTERFACE);
+ hp->hp_flags = HTTP_PATH_WEBSOCKET;
http_path_add("/comet/poll", NULL, comet_mailbox_poll, ACCESS_WEB_INTERFACE);
http_path_add("/comet/debug", NULL, comet_mailbox_dbg, ACCESS_WEB_INTERFACE);
}
}, Ext.util.Observable);
tvheadend.comet = new tvheadend.Comet();
+tvheadend.ws = null;
+tvheadend.wsURI = null;
tvheadend.boxid = null;
-tvheadend.cometPoller = function() {
+tvheadend.cometError = function() {
+ tvheadend.log(_('There seems to be a problem with the '
+ + 'live update feed from Tvheadend. '
+ + 'Trying to reconnect...'),
+ 'font-weight: bold; color: #f00');
+};
- var failures = 0;
+tvheadend.cometReconnected = function() {
+ tvheadend.log(_('Reconnected to Tvheadend'),
+ 'font-weight: bold; color: #080');
+}
+
+tvheadend.cometParse = function(responsetxt) {
+ var response = Ext.util.JSON.decode(responsetxt);
+ if ('boxid' in response) {
+ if (tvheadend.boxid && tvheadend.boxid !== response.boxid)
+ window.location.reload();
+ tvheadend.boxid = response.boxid;
+ }
+ for (x = 0; x < response.messages.length; x++) {
+ m = response.messages[x];
+ if (0) console.log(JSON.stringify(m), null, " ");
+ try {
+ tvheadend.comet.fireEvent(m.notificationClass, m);
+ } catch (e) {
+ tvheadend.log(_('Comet failure') + ' [e=' + e.message + ']');
+ }
+ }
+};
+tvheadend.cometPoller = function() {
+ var failures = 0;
var cometRequest = new Ext.util.DelayedTask(function() {
+ Ext.Ajax.request({
+ url: 'comet/poll',
+ params: {
+ boxid: (tvheadend.boxid ? tvheadend.boxid : null),
+ immediate: failures > 0 ? 1 : 0
+ },
+ success: function(result, request) {
+ tvheadend.cometParse(result.responseText);
+ cometRequest.delay(100);
- Ext.Ajax
- .request({
- url: 'comet/poll',
- params: {
- boxid: (tvheadend.boxid ? tvheadend.boxid : null),
- immediate: failures > 0 ? 1 : 0
- },
- success: function(result, request) {
- parse_comet_response(result.responseText);
-
- if (failures > 1) {
- tvheadend.log(_('Reconnected to Tvheadend'),
- 'font-weight: bold; color: #080');
- }
- failures = 0;
- },
- failure: function(result, request) {
- cometRequest.delay(failures ? 1000 : 1);
- if (failures === 1) {
- tvheadend.log(_('There seems to be a problem with the '
- + 'live update feed from Tvheadend. '
- + 'Trying to reconnect...'),
- 'font-weight: bold; color: #f00');
- }
- failures++;
- }
- });
+ if (failures > 1)
+ tvheadend.cometReconnected();
+ failures = 0;
+ },
+ failure: function(result, request) {
+ cometRequest.delay(failures ? 1000 : 1);
+ if (failures === 1)
+ tvheadend.cometError();
+ failures++;
+ }
+ });
});
+ cometRequest.delay(100);
+};
- function parse_comet_response(responsetxt) {
- response = Ext.util.JSON.decode(responsetxt);
- tvheadend.boxid = response.boxid;
- for (x = 0; x < response.messages.length; x++) {
- m = response.messages[x];
- if (0) console.log(JSON.stringify(m), null, " ");
- try {
- tvheadend.comet.fireEvent(m.notificationClass, m);
- } catch (e) {
- tvheadend.log(_('Comet failure') + ' [e=' + e.message + ']');
- }
+tvheadend.cometWebsocket = function() {
+ var failures = 0;
+ var cometRequest = new Ext.util.DelayedTask(function() {
+ var uri = tvheadend.wsURI;
+ if (tvheadend.boxid)
+ uri = uri + '?boxid=' + tvheadend.boxid;
+ tvheadend.ws = new WebSocket(uri);
+ if (failures > 5)
+ window.location.reload();
+ if (failures > 1)
+ tvheadend.cometReconnected();
+ tvheadend.ws.onmessage = function(ev) {
+ failures = 0;
+ tvheadend.cometParse(ev.data);
}
- cometRequest.delay(100);
- }
- ;
-
+ tvheadend.ws.onerror = function(ev) {
+ if (failures === 1)
+ tvheadend.cometError();
+ failures++;
+ };
+ tvheadend.ws.onclose = function(ev) {
+ cometRequest.delay(failures ? 1000 : 50);
+ };
+ });
cometRequest.delay(100);
};
+
+tvheadend.cometInit = function() {
+ if ("WebSocket" in window) {
+ var loc = window.location;
+ var path = loc.pathname.substring(0, loc.pathname.lastIndexOf("/"));
+ tvheadend.wsURI = (loc.protocol === "https:" ? "wss:" : "ws:") + "//" + loc.host + path + "/comet/ws";
+ new tvheadend.cometWebsocket;
+ } else {
+ new tvheadend.cometPoller;
+ }
+};
tvheadend.log(m.logtxt);
});
- new tvheadend.cometPoller;
+ tvheadend.cometInit();
Ext.QuickTips.init();
}
http_path_add("", NULL, page_root2, ACCESS_WEB_INTERFACE);
hp = http_path_add("/", NULL, page_root, ACCESS_WEB_INTERFACE);
- hp->hp_no_verification = 1; /* redirect only */
+ hp->hp_flags = HTTP_PATH_NO_VERIFICATION; /* redirect only */
http_path_add("/login", NULL, page_login, ACCESS_WEB_INTERFACE);
hp = http_path_add("/logout", NULL, page_logout, ACCESS_WEB_INTERFACE);
- hp->hp_no_verification = 1;
+ hp->hp_flags = HTTP_PATH_NO_VERIFICATION;
#if CONFIG_SATIP_SERVER
http_path_add("/satip_server", NULL, satip_server_http_page, ACCESS_ANONYMOUS);