From cc204b709d3a2f041b586362f7ae39876eefab77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Sat, 19 Apr 2008 12:08:48 +0000 Subject: [PATCH] Use one mailbox per client. Much more robust and does not risk to hang browser if we get too many open boxes --- ajaxui/ajaxui.c | 34 +++++++++++++- ajaxui/ajaxui.h | 2 + ajaxui/ajaxui_config_dvb.c | 3 -- ajaxui/ajaxui_config_xmltv.c | 3 -- ajaxui/ajaxui_mailbox.c | 90 +++++++++++++++++++++++------------- ajaxui/ajaxui_mailbox.h | 2 +- ajaxui/tvheadend.js | 9 ++++ 7 files changed, 104 insertions(+), 39 deletions(-) diff --git a/ajaxui/ajaxui.c b/ajaxui/ajaxui.c index 1f75a8c2..84782f12 100644 --- a/ajaxui/ajaxui.c +++ b/ajaxui/ajaxui.c @@ -26,6 +26,7 @@ #include "tvhead.h" #include "http.h" #include "ajaxui.h" +#include "ajaxui_mailbox.h" #include "dispatch.h" #include "obj/ajaxui.cssh" @@ -57,6 +58,22 @@ const char *ajax_tabnames[] = { [AJAX_TAB_ABOUT] = "About", }; + +const char * +ajaxui_escape_apostrophe(const char *content) +{ + static char buf[2000]; + int i = 0; + + while(i < sizeof(buf) - 2 && *content) { + if(*content == '\'') + buf[i++] = '\\'; + buf[i++] = *content++; + } + buf[i] = 0; + return buf; +} + /** * AJAX table header */ @@ -410,7 +427,22 @@ ajax_page_root(http_connection_t *hc, http_reply_t *hr, tcp_qprintf(tq, "
"); - ajax_box_begin(tq, AJAX_BOX_FILLED, "topmenu", NULL, NULL); + ajax_box_begin(tq, AJAX_BOX_FILLED, NULL, NULL, NULL); + + tcp_qprintf(tq, + "
" + "
" + "Tvheadend v1.x (r?)" + "
" + "
" + "
" + " " + "Dynamic updates" + "
" + "
"); + + ajax_mailbox_start(tq); + ajax_box_end(tq, AJAX_BOX_FILLED); tcp_qprintf(tq, "
"); diff --git a/ajaxui/ajaxui.h b/ajaxui/ajaxui.h index e695d751..d1b3839d 100644 --- a/ajaxui/ajaxui.h +++ b/ajaxui/ajaxui.h @@ -79,4 +79,6 @@ void ajax_table_header(http_connection_t *hc, tcp_queue_t *tq, void ajax_table_row(tcp_queue_t *tq, const char *cells[], int columnsizes[], int *bgptr, const char *idprefix[], const char *idpostfix); +const char *ajaxui_escape_apostrophe(const char *content); + #endif /* AJAXUI_H_ */ diff --git a/ajaxui/ajaxui_config_dvb.c b/ajaxui/ajaxui_config_dvb.c index b650819f..28722e14 100644 --- a/ajaxui/ajaxui_config_dvb.c +++ b/ajaxui/ajaxui_config_dvb.c @@ -229,9 +229,6 @@ ajax_adaptereditor(http_connection_t *hc, http_reply_t *hr, "'/ajax/dvbadaptermuxlist/%s', {method: 'get', evalScripts: true})", tda->tda_identifier, tda->tda_identifier); - ajax_mailbox_start(tq, tda->tda_identifier); - - tcp_qprintf(tq, "
"); dvb_make_add_link(tq, tda, NULL); tcp_qprintf(tq, "
"); diff --git a/ajaxui/ajaxui_config_xmltv.c b/ajaxui/ajaxui_config_xmltv.c index c69b0872..a917fe05 100644 --- a/ajaxui/ajaxui_config_xmltv.c +++ b/ajaxui/ajaxui_config_xmltv.c @@ -107,7 +107,6 @@ ajax_config_xmltv_tab(http_connection_t *hc, http_reply_t *hr) xg->xg_identifier); } - ajax_mailbox_start(tq, "xmltvgrabbers"); tcp_qprintf(tq, "
"); ajax_box_end(tq, AJAX_BOX_SIDEBOX); @@ -165,8 +164,6 @@ ajax_xmltvgrabber(http_connection_t *hc, http_reply_t *hr, tcp_qprintf(tq,""); ajax_box_end(tq, AJAX_BOX_SIDEBOX); - - ajax_mailbox_start(tq, xg->xg_identifier); http_output_html(hc, hr); return 0; } diff --git a/ajaxui/ajaxui_mailbox.c b/ajaxui/ajaxui_mailbox.c index 4c7862db..43a16542 100644 --- a/ajaxui/ajaxui_mailbox.c +++ b/ajaxui/ajaxui_mailbox.c @@ -23,6 +23,8 @@ #include #include +#include + #include "tvhead.h" #include "dispatch.h" #include "http.h" @@ -34,6 +36,10 @@ #define MAILBOX_EMPTY_REPLY_TIMEOUT 10 +//#define mbdebug(fmt...) printf(fmt); +#define mbdebug(fmt...) + + static LIST_HEAD(, ajaxui_mailbox) mailboxes; int mailbox_tally; @@ -50,8 +56,7 @@ typedef struct ajaxui_letter { typedef struct ajaxui_mailbox { LIST_ENTRY(ajaxui_mailbox) amb_link; - uint32_t amb_boxid; - char *amb_subscriptionid; + char *amb_boxid; /* an md5hash */ dtimer_t amb_timer; @@ -83,6 +88,8 @@ amb_destroy(ajaxui_mailbox_t *amb) { ajaxui_letter_t *al; + mbdebug("mailbox[%s]: destroyed\n", amb->amb_boxid); + while((al = TAILQ_FIRST(&amb->amb_letters)) != NULL) al_destroy(amb, al); @@ -90,7 +97,7 @@ amb_destroy(ajaxui_mailbox_t *amb) dtimer_disarm(&amb->amb_timer); - free(amb->amb_subscriptionid); + free(amb->amb_boxid); free(amb); } @@ -123,45 +130,55 @@ ajax_mailbox_connection_lost(http_reply_t *hr, void *opaque) /** * */ -int -ajax_mailbox_create(const char *subscriptionid) +static ajaxui_mailbox_t * +ajax_mailbox_create(const char *id) { ajaxui_mailbox_t *amb = calloc(1, sizeof(ajaxui_mailbox_t)); + amb->amb_boxid = strdup(id); + mailbox_tally++; - amb->amb_boxid = mailbox_tally; - amb->amb_subscriptionid = strdup(subscriptionid); - LIST_INSERT_HEAD(&mailboxes, amb, amb_link); TAILQ_INIT(&amb->amb_letters); dtimer_arm(&amb->amb_timer, ajax_mailbox_unused, amb, MAILBOX_UNUSED_TIMEOUT); - return amb->amb_boxid; + return amb; } /** * */ void -ajax_mailbox_start(tcp_queue_t *tq, const char *identifier) +ajax_mailbox_start(tcp_queue_t *tq) { - int boxid = ajax_mailbox_create(identifier); + struct timeval tv; + uint8_t sum[16]; + char id[33]; + int i; + struct AVMD5 *ctx; - /* We need to keep a hidden element in a part of the document that - is directly mapped to this mailbox. + ctx = alloca(av_md5_size); - This element is updated in every reply and if it fails, - there will be no more updates. + gettimeofday(&tv, NULL); - This avoid getting stale updaters that keeps on going if parts - of the document is reloaded faster than the mailbox sees it */ + av_md5_init(ctx); + av_md5_update(ctx, (void *)&tv, sizeof(tv)); + av_md5_update(ctx, (void *)&mailbox_tally, sizeof(uint32_t)); + av_md5_final(ctx, sum); - tcp_qprintf(tq, "
", boxid); + for(i = 0; i < 16; i++) { + id[i * 2 + 0] = "0123456789abcdef"[sum[i] >> 4]; + id[i * 2 + 1] = "0123456789abcdef"[sum[i] & 15]; + } + id[32] = 0; - ajax_js(tq, "new Ajax.Request('/ajax/mailbox/%d')", boxid); + mbdebug("Generated mailbox %s\n", id); + + ajax_mailbox_create(id); + ajax_js(tq, "mailboxquery('%s')", id); } @@ -177,15 +194,19 @@ ajax_mailbox_reply(ajaxui_mailbox_t *amb, http_reply_t *hr) if this div no longer exist, the rest of the javascript will bail out and we will not be reloaded */ - tcp_qprintf(&hr->hr_tq, "$('mbox_%d').innerHTML='';\r\n", amb->amb_boxid); + mbdebug("mailbox[%s]: sending reply\n", amb->amb_boxid); while((al = TAILQ_FIRST(&amb->amb_letters)) != NULL) { + tcp_qprintf(&hr->hr_tq, "try {\r\n"); tcp_qprintf(&hr->hr_tq, "%s%s", al->al_payload_a, al->al_payload_b ?: ""); + mbdebug("\t%s%s", al->al_payload_a, al->al_payload_b ?: ""); + + tcp_qprintf(&hr->hr_tq, "}\r\n" + "catch(err) {}\r\n"); al_destroy(amb, al); } - tcp_qprintf(&hr->hr_tq, "new Ajax.Request('/ajax/mailbox/%d');\r\n", - amb->amb_boxid); + tcp_qprintf(&hr->hr_tq, "mailboxquery('%s');\r\n", amb->amb_boxid); http_output(hr->hr_connection, hr, "text/javascript", NULL, 0); amb->amb_hr = NULL; @@ -218,28 +239,35 @@ static int ajax_mailbox_poll(http_connection_t *hc, http_reply_t *hr, const char *remain, void *opaque) { - uint32_t boxid; ajaxui_mailbox_t *amb; if(remain == NULL) return HTTP_STATUS_NOT_FOUND; - boxid = atoi(remain); + mbdebug("mailbox[%s]: Incomming request ... ", remain); + LIST_FOREACH(amb, &mailboxes, amb_link) - if(amb->amb_boxid == boxid) + if(!strcmp(amb->amb_boxid, remain)) break; - if(amb == NULL) - return HTTP_STATUS_NOT_FOUND; - if(amb->amb_hr != NULL) + if(amb == NULL) { + amb = ajax_mailbox_create(remain); + mbdebug("creating mailbox ... "); + } + + if(amb->amb_hr != NULL) { + mbdebug("mailbox already processing\n"); return 409; - + } if(TAILQ_FIRST(&amb->amb_letters) != NULL) { /* Pending letters, direct reply */ + mbdebug("direct reply\n"); ajax_mailbox_reply(amb, hr); return 0; } + mbdebug("nothing in queue, waiting\n"); + amb->amb_hr = hr; hr->hr_opaque = amb; @@ -286,8 +314,6 @@ ajax_mailbox_add_to_subscription(const char *subscription, ajaxui_letter_t *al; LIST_FOREACH(amb, &mailboxes, amb_link) { - if(strcmp(subscription, amb->amb_subscriptionid)) - continue; /* Avoid inserting the same message twice */ @@ -329,6 +355,8 @@ ajax_mailbox_update_div(const char *subscription, const char *prefix, char buf_a[500]; char buf_b[500]; + content = ajaxui_escape_apostrophe(content); + snprintf(buf_a, sizeof(buf_a), "$('%s_%s').innerHTML=", prefix, postfix); snprintf(buf_b, sizeof(buf_b), "'%s';\n\r", content); diff --git a/ajaxui/ajaxui_mailbox.h b/ajaxui/ajaxui_mailbox.h index 611ec749..7dcb6c1a 100644 --- a/ajaxui/ajaxui_mailbox.h +++ b/ajaxui/ajaxui_mailbox.h @@ -33,7 +33,7 @@ void ajax_mailbox_tdmi_services_change(th_dvb_mux_instance_t *tdmi); void ajax_mailbox_tda_change(th_dvb_adapter_t *tda); -void ajax_mailbox_start(tcp_queue_t *tq, const char *identifier); +void ajax_mailbox_start(tcp_queue_t *tq); struct xmltv_grabber; diff --git a/ajaxui/tvheadend.js b/ajaxui/tvheadend.js index 306c5f7e..51b532bc 100644 --- a/ajaxui/tvheadend.js +++ b/ajaxui/tvheadend.js @@ -66,3 +66,12 @@ function tentative_chname(id, url, name) parameters: { newname: newname }}); } } + +function mailboxquery(boxid) +{ + new Ajax.Request('/ajax/mailbox/' + boxid, + { + onFailure: function(req) { alert(req.responseText); }, + onException: function(t,e) { alert(e); } + }) +} \ No newline at end of file