static ngx_int_t publish_callback(ngx_int_t status, nchan_channel_t *ch, safe_request_ptr_t *pd) { nchan_request_ctx_t *ctx; static nchan_msg_id_t empty_msgid = NCHAN_ZERO_MSGID; ngx_http_request_t *r = nchan_get_safe_request_ptr(pd); if(r == NULL) { // the request has since disappered return NGX_ERROR; } ctx = ngx_http_get_module_ctx(r, ngx_nchan_module); //DBG("publish_callback %V owner %i status %i", ch_id, memstore_channel_owner(ch_id), status); switch(status) { case NCHAN_MESSAGE_QUEUED: //message was queued successfully, but there were no subscribers to receive it. ctx->prev_msg_id = ctx->msg_id; ctx->msg_id = ch != NULL ? ch->last_published_msg_id : empty_msgid; nchan_maybe_send_channel_event_message(r, CHAN_PUBLISH); ngx_http_finalize_request(r, nchan_response_channel_ptr_info(ch, r, NGX_HTTP_ACCEPTED)); return NGX_OK; case NCHAN_MESSAGE_RECEIVED: //message was queued successfully, and it was already sent to at least one subscriber ctx->prev_msg_id = ctx->msg_id; ctx->msg_id = ch != NULL ? ch->last_published_msg_id : empty_msgid; nchan_maybe_send_channel_event_message(r, CHAN_PUBLISH); ngx_http_finalize_request(r, nchan_response_channel_ptr_info(ch, r, NGX_HTTP_CREATED)); return NGX_OK; case NGX_ERROR: case NGX_HTTP_INTERNAL_SERVER_ERROR: //WTF? nchan_log_request_error(r, "error publishing message"); ctx->prev_msg_id = empty_msgid;; ctx->msg_id = empty_msgid; ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; default: //for debugging, mostly. I don't expect this branch to behit during regular operation ctx->prev_msg_id = empty_msgid;; ctx->msg_id = empty_msgid; nchan_log_request_error(r, "TOTALLY UNEXPECTED error publishing message, status code %i", status); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; } }
static void nchan_publisher_body_handler_continued(ngx_http_request_t *r, ngx_str_t *channel_id, nchan_loc_conf_t *cf) { ngx_http_complex_value_t *publisher_upstream_request_url_ccv; static ngx_str_t POST_REQUEST_STRING = {4, (u_char *)"POST "}; switch(r->method) { case NGX_HTTP_GET: cf->storage_engine->find_channel(channel_id, (callback_pt) &channel_info_callback, (void *)r); break; case NGX_HTTP_PUT: case NGX_HTTP_POST: publisher_upstream_request_url_ccv = cf->publisher_upstream_request_url; if(publisher_upstream_request_url_ccv == NULL) { ngx_str_t *content_type = (r->headers_in.content_type ? &r->headers_in.content_type->value : NULL); ngx_int_t content_length = r->headers_in.content_length_n > 0 ? r->headers_in.content_length_n : 0; nchan_publisher_post_request(r, content_type, content_length, r->request_body->bufs, channel_id, cf); } else { nchan_pub_upstream_stuff_t *psr_stuff; if((psr_stuff = ngx_palloc(r->pool, sizeof(*psr_stuff))) == NULL) { ERR("can't allocate memory for publisher auth subrequest"); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } ngx_http_post_subrequest_t *psr = &psr_stuff->psr; nchan_pub_upstream_data_t *psrd = &psr_stuff->psr_data; ngx_http_request_t *sr; ngx_str_t publisher_upstream_request_url; ngx_http_complex_value(r, publisher_upstream_request_url_ccv, &publisher_upstream_request_url); psr->handler = nchan_publisher_upstream_handler; psr->data = psrd; psrd->ch_id = channel_id; ngx_http_subrequest(r, &publisher_upstream_request_url, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY); nchan_adjust_subrequest(sr, NGX_HTTP_POST, &POST_REQUEST_STRING, r->request_body, r->headers_in.content_length_n, NULL); } break; case NGX_HTTP_DELETE: cf->storage_engine->delete_channel(channel_id, (callback_pt) &channel_info_callback, (void *)r); nchan_maybe_send_channel_event_message(r, CHAN_DELETE); break; default: nchan_respond_status(r, NGX_HTTP_FORBIDDEN, NULL, 0); } }
static void spool_sub_dequeue_callback(subscriber_t *sub, void *data) { spooled_subscriber_cleanup_t *d = (spooled_subscriber_cleanup_t *)data; subscriber_pool_t *spool = d->spool; DBG("sub %p dequeue callback", sub); assert(sub == d->ssub->sub); spool_remove_subscriber(spool, d->ssub); spool_bubbleup_dequeue_handler(spool, sub, spool->spooler); if(sub->type != INTERNAL && spool->spooler->publish_events) { nchan_maybe_send_channel_event_message(sub->request, SUB_DEQUEUE); } }
static ngx_int_t spool_add_subscriber(subscriber_pool_t *self, subscriber_t *sub, uint8_t enqueue) { spooled_subscriber_t *ssub; ssub = ngx_calloc(sizeof(*ssub), ngx_cycle->log); //DBG("add sub %p to spool %p", sub, self); if(ssub == NULL) { ERR("failed to allocate new sub for spool"); return NGX_ERROR; } ssub->next = self->first; ssub->prev = NULL; if(self->first != NULL) { self->first->prev = ssub; } self->first = ssub; self->sub_count++; if(sub->type != INTERNAL) { self->non_internal_sub_count++; } ssub->dequeue_callback_data.ssub = ssub; ssub->dequeue_callback_data.spool = self; if(enqueue) { sub->fn->enqueue(sub); } if(sub->type != INTERNAL && self->spooler->publish_events) { nchan_maybe_send_channel_event_message(sub->request, SUB_ENQUEUE); } sub->fn->set_dequeue_callback(sub, spool_sub_dequeue_callback, &ssub->dequeue_callback_data); ssub->sub = sub; return NGX_OK; }