void h2o_http2_conn_unregister_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream) { khiter_t iter = kh_get(h2o_http2_stream_t, conn->open_streams, stream->stream_id); assert(iter != kh_end(conn->open_streams)); kh_del(h2o_http2_stream_t, conn->open_streams, iter); switch (stream->state) { case H2O_HTTP2_STREAM_STATE_RECV_PSUEDO_HEADERS: case H2O_HTTP2_STREAM_STATE_RECV_HEADERS: case H2O_HTTP2_STREAM_STATE_RECV_BODY: assert(! h2o_http2_conn_stream_is_linked(stream)); break; case H2O_HTTP2_STREAM_STATE_REQ_PENDING: if (h2o_http2_conn_stream_is_linked(stream)) { unlink_stream(&conn->_pending_reqs, stream); } break; case H2O_HTTP2_STREAM_STATE_SEND_HEADERS: case H2O_HTTP2_STREAM_STATE_SEND_BODY: case H2O_HTTP2_STREAM_STATE_END_STREAM: --conn->num_responding_streams; if (h2o_http2_conn_stream_is_linked(stream)) { unlink_stream( h2o_http2_stream_has_pending_data(stream) ? &conn->_write.streams_with_pending_data : &conn->_write.streams_without_pending_data, stream); } break; } if (conn->state != H2O_HTTP2_CONN_STATE_IS_CLOSING) run_pending_requests(conn); }
void h2o_http2_conn_unregister_stream(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream) { khiter_t iter = kh_get(h2o_http2_stream_t, conn->streams, stream->stream_id); assert(iter != kh_end(conn->streams)); kh_del(h2o_http2_stream_t, conn->streams, iter); assert(h2o_http2_scheduler_is_open(&stream->_refs.scheduler)); h2o_http2_scheduler_close(&stream->_refs.scheduler); switch (stream->state) { case H2O_HTTP2_STREAM_STATE_IDLE: case H2O_HTTP2_STREAM_STATE_RECV_HEADERS: case H2O_HTTP2_STREAM_STATE_RECV_BODY: assert(!h2o_linklist_is_linked(&stream->_refs.link)); break; case H2O_HTTP2_STREAM_STATE_REQ_PENDING: assert(h2o_linklist_is_linked(&stream->_refs.link)); h2o_linklist_unlink(&stream->_refs.link); break; case H2O_HTTP2_STREAM_STATE_SEND_HEADERS: case H2O_HTTP2_STREAM_STATE_SEND_BODY: case H2O_HTTP2_STREAM_STATE_END_STREAM: if (h2o_linklist_is_linked(&stream->_refs.link)) h2o_linklist_unlink(&stream->_refs.link); break; } if (stream->state != H2O_HTTP2_STREAM_STATE_END_STREAM) h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_END_STREAM); if (conn->state < H2O_HTTP2_CONN_STATE_IS_CLOSING) { run_pending_requests(conn); update_idle_timeout(conn); } }
static void execute_or_enqueue_request(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream) { assert(stream->state < H2O_HTTP2_STREAM_STATE_REQ_PENDING); stream->state = H2O_HTTP2_STREAM_STATE_REQ_PENDING; link_stream(&conn->_pending_reqs, stream); run_pending_requests(conn); }
static void on_configuration_ready (GObject *source, GAsyncResult *result, gpointer user_data) { ResolveClosure *closure = (ResolveClosure *) user_data; GrlTmdbRequest *request = GRL_TMDB_REQUEST (source); GrlTmdbSource *self = closure->self; GError *error = NULL; GValue *value; GRL_DEBUG ("Configuration request ready..."); if (!grl_tmdb_request_run_finish (GRL_TMDB_REQUEST (source), result, &error)) { resolve_closure_callback (closure, error); resolve_closure_free (closure); /* Notify pending requests about failure */ while (!g_queue_is_empty (self->priv->pending_resolves)) { ResolveClosure *pending_closure; pending_closure = g_queue_pop_head (self->priv->pending_resolves); resolve_closure_callback (pending_closure, error); resolve_closure_free (pending_closure); } g_error_free (error); return; } self->priv->configuration = g_object_ref (request); remove_request (closure, request); value = grl_tmdb_request_get (request, "$.images.base_url"); if (value != NULL) { GRL_DEBUG ("Got TMDb configuration."); self->priv->image_base_uri = soup_uri_new (g_value_get_string (value)); g_value_unset (value); g_free (value); } g_queue_push_head (self->priv->pending_resolves, closure); /* Flush queue. GrlNetWc will take care of throttling */ while (!g_queue_is_empty (self->priv->pending_resolves)) { ResolveClosure *pending_closure; pending_closure = g_queue_pop_head (self->priv->pending_resolves); run_pending_requests (pending_closure, G_MAXINT); } }
static void execute_or_enqueue_request(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream) { assert(stream->state < H2O_HTTP2_STREAM_STATE_REQ_PENDING); if (stream->_req_body != NULL && stream->_expected_content_length != SIZE_MAX && stream->_req_body->size != stream->_expected_content_length) { send_stream_error(conn, stream->stream_id, H2O_HTTP2_ERROR_PROTOCOL); h2o_http2_stream_reset(conn, stream); return; } h2o_http2_stream_set_state(conn, stream, H2O_HTTP2_STREAM_STATE_REQ_PENDING); /* TODO schedule the pending reqs using the scheduler */ h2o_linklist_insert(&conn->_pending_reqs, &stream->_refs.link); run_pending_requests(conn); update_idle_timeout(conn); }
static void on_search_ready (GObject *source, GAsyncResult *result, gpointer user_data) { ResolveClosure *closure = (ResolveClosure *) user_data; GrlTmdbRequest *request = GRL_TMDB_REQUEST (source); GValue *value; GError *error = NULL; GRL_DEBUG ("Initial search ready..."); if (!grl_tmdb_request_run_finish (GRL_TMDB_REQUEST (source), result, &error)) { resolve_closure_callback (closure, error); resolve_closure_free (closure); g_error_free (error); return; } value = grl_tmdb_request_get (request, "$.total_results"); if (g_value_get_int64 (value) == 0) { /* Nothing found */ resolve_closure_callback (closure, NULL); resolve_closure_free (closure); g_value_unset (value); g_free (value); return; } g_value_unset (value); g_free (value); value = grl_tmdb_request_get (request, "$.results[0].id"); if (value == NULL) { /* Cannot continue without id */ error = g_error_new_literal (GRL_CORE_ERROR, GRL_CORE_ERROR_RESOLVE_FAILED, _("Remote data does not contain valid identifier")); resolve_closure_callback (closure, error); resolve_closure_free (closure); g_error_free (error); return; } if (SHOULD_RESOLVE (GRL_TMDB_METADATA_KEY_TMDB_ID)) { char *tmdb_id = g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (value)); grl_data_set_string (GRL_DATA (closure->rs->media), GRL_TMDB_METADATA_KEY_TMDB_ID, tmdb_id); g_free (tmdb_id); } closure->id = g_value_get_int64 (value); g_value_unset (value); g_free (value); if (grl_data_get_boolean (GRL_DATA (closure->rs->media), GRL_METADATA_KEY_TITLE_FROM_FILENAME)) { value = grl_tmdb_request_get (request, "$.results[0].title"); if (value) { grl_media_set_title (closure->rs->media, g_value_get_string (value)); grl_data_set_boolean (GRL_DATA (closure->rs->media), GRL_METADATA_KEY_TITLE_FROM_FILENAME, FALSE); g_value_unset (value); g_free (value); } } if (SHOULD_RESOLVE (GRL_METADATA_KEY_RATING)) { value = grl_tmdb_request_get (request, "$.results[0].vote_average"); if (value != NULL) { grl_media_set_rating (closure->rs->media, (float) g_value_get_double (value), 10.0f); g_value_unset (value); g_free (value); } g_hash_table_remove (closure->keys, GRLKEYID_TO_POINTER (GRL_METADATA_KEY_RATING)); } /* Add thumbnails first, and posters and backdrops later. * Posters more likely make a good thumbnail than backdrops. */ if (SHOULD_RESOLVE (GRL_METADATA_KEY_THUMBNAIL)) { value = grl_tmdb_request_get (request, "$.results[0].poster_path"); if (value != NULL) { add_image (closure->self, closure->rs->media, GRL_METADATA_KEY_THUMBNAIL, g_value_get_string (value)); g_value_unset (value); g_free (value); } } if (SHOULD_RESOLVE (GRL_TMDB_METADATA_KEY_POSTER)) { value = grl_tmdb_request_get (request, "$.results[0].poster_path"); if (value != NULL) { add_image (closure->self, closure->rs->media, GRL_TMDB_METADATA_KEY_POSTER, g_value_get_string (value)); g_value_unset (value); g_free (value); } } if (SHOULD_RESOLVE (GRL_TMDB_METADATA_KEY_BACKDROP)) { value = grl_tmdb_request_get (request, "$.results[0].backdrop_path"); if (value != NULL) { add_image (closure->self, closure->rs->media, GRL_TMDB_METADATA_KEY_BACKDROP, g_value_get_string (value)); g_value_unset (value); g_free (value); } } if (SHOULD_RESOLVE (GRL_METADATA_KEY_ORIGINAL_TITLE)) { value = grl_tmdb_request_get (request, "$.results[0].original_title"); if (value != NULL) { grl_media_set_original_title (closure->rs->media, g_value_get_string (value)); g_value_unset (value); g_free (value); } g_hash_table_remove (closure->keys, GRLKEYID_TO_POINTER (GRL_METADATA_KEY_ORIGINAL_TITLE)); } remove_request (closure, request); /* Check if we need to do additional requests. */ if (closure->slow) { resolve_slow_details (closure); if (run_pending_requests (closure, G_MAXINT) > 0) return; } resolve_closure_callback (closure, NULL); resolve_closure_free (closure); }
static void grl_tmdb_source_resolve (GrlSource *source, GrlSourceResolveSpec *rs) { ResolveClosure *closure; GrlTmdbRequest *request; const char *title = NULL; const char *str_movie_id; GrlTmdbSource *self = GRL_TMDB_SOURCE (source); guint64 movie_id = 0; GList *it; if (!grl_media_is_video (rs->media)) { /* We only entertain videos */ rs->callback (source, rs->operation_id, rs->media, rs->user_data, NULL); return; } /* If the media is a TV show, don't handle it */ if (grl_media_get_show (rs->media) != NULL) { rs->callback (source, rs->operation_id, rs->media, rs->user_data, NULL); return; } /* Prefer resolving by movie-id: This is more reliable and saves the search query. */ str_movie_id = grl_data_get_string (GRL_DATA (rs->media), GRL_TMDB_METADATA_KEY_TMDB_ID); if (str_movie_id) movie_id = strtoull (str_movie_id, NULL, 10); /* Try title if no movie-id could be found. */ if (movie_id == 0) title = grl_media_get_title (rs->media); if (movie_id == 0 && title == NULL) { /* Can't search for anything without a title or the movie-id ... */ rs->callback (source, rs->operation_id, rs->media, rs->user_data, NULL); return; } GRL_DEBUG ("grl_tmdb_source_resolve"); closure = g_slice_new0 (ResolveClosure); closure->self = g_object_ref (self); closure->rs = rs; closure->pending_requests = g_queue_new (); closure->keys = g_hash_table_new (g_direct_hash, g_direct_equal); closure->slow = FALSE; closure->id = movie_id; it = rs->keys; /* Copy keys to list for faster lookup */ while (it) { g_hash_table_add (closure->keys, it->data); /* Enable slow resolution if slow keys are requested */ closure->slow |= g_hash_table_contains (self->priv->slow_keys, it->data); it = it->next; } /* Disable slow resolution if slow keys where requested, but the operation * options explicitly ask for fast resolving only. */ if (grl_operation_options_get_resolution_flags (rs->options) & GRL_RESOLVE_FAST_ONLY) closure->slow = FALSE; /* We did not receive the config yet, queue request. Config callback will * take care of flushing the queue when ready. */ if (self->priv->configuration == NULL && self->priv->config_pending) { g_queue_push_tail (self->priv->pending_resolves, closure); return; } if (self->priv->configuration == NULL) { GRL_DEBUG ("Fetching TMDb configuration..."); /* We need to fetch TMDb's configuration for the image paths */ request = grl_tmdb_request_new_configuration (closure->self->priv->api_key); g_assert (g_queue_is_empty (closure->pending_requests)); queue_request (closure, request, on_configuration_ready); self->priv->config_pending = TRUE; } if (title) { GRL_DEBUG ("Running initial search for title \"%s\"...", title); request = grl_tmdb_request_new_search (closure->self->priv->api_key, title); queue_request (closure, request, on_search_ready); run_pending_requests (closure, 1); } else { GRL_DEBUG ("Running %s lookup for movie #%" G_GUINT64_FORMAT "...", closure->slow ? "slow" : "fast", movie_id); if (closure->slow) { resolve_slow_details (closure); } else { queue_detail_request (closure, GRL_TMDB_REQUEST_DETAIL_MOVIE); } run_pending_requests (closure, G_MAXINT); } }