/** * cockpit_channel_close: * @self: a channel * @problem: the problem or NULL * * Close the channel. This can be called mulitple times. * * It may be that the channel doesn't close immediately. * The channel will emit the CockpitChannel::closed signal when the * channel actually closes. * * If this is called immediately after or during construction then * the closing will happen after the main loop so that handlers * can connect appropriately. * * A @problem of NULL represents an orderly close. */ void cockpit_channel_close (CockpitChannel *self, const gchar *problem) { CockpitChannelClass *klass; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); /* No further messages should be received */ if (self->priv->recv_sig) g_signal_handler_disconnect (self->priv->transport, self->priv->recv_sig); self->priv->recv_sig = 0; if (self->priv->control_sig) g_signal_handler_disconnect (self->priv->transport, self->priv->control_sig); self->priv->control_sig = 0; if (self->priv->close_sig) g_signal_handler_disconnect (self->priv->transport, self->priv->close_sig); self->priv->close_sig = 0; klass = COCKPIT_CHANNEL_GET_CLASS (self); g_assert (klass->close != NULL); self->priv->emitted_close = TRUE; (klass->close) (self, problem); }
/** * cockpit_channel_control: * @self: the channel * @command: the control command * @options: optional control message or NULL * * Send a control message to the other side. * * If @options is not NULL, then it may be modified by this code. * * With @command of "done" will send an EOF to the other side. This * should only be called once. Whether an EOF should be sent or not * depends on the payload type. */ void cockpit_channel_control (CockpitChannel *self, const gchar *command, JsonObject *options) { JsonObject *object; GBytes *message; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); g_return_if_fail (command != NULL); if (g_str_equal (command, "done")) { g_return_if_fail (self->priv->sent_done == FALSE); self->priv->sent_done = TRUE; } if (options) object = json_object_ref (options); else object = json_object_new (); json_object_set_string_member (object, "command", command); json_object_set_string_member (object, "channel", self->priv->id); message = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (self->priv->transport, NULL, message); g_bytes_unref (message); }
/* * cockpit_channel_fail: * @self: a channel * @problem: the problem * * Close the channel with a @problem. In addition a "message" field * will be set on the channel, using the @format argument to bulid * the message. The message will also be logged. * * See cockpit_channel_close() for further info. */ void cockpit_channel_fail (CockpitChannel *self, const gchar *problem, const gchar *format, ...) { JsonObject *options; gchar *message; va_list va; g_return_if_fail (problem != NULL); g_return_if_fail (COCKPIT_IS_CHANNEL (self)); va_start (va, format); message = g_strdup_vprintf (format, va); va_end (va); options = cockpit_channel_close_options (self); if (!json_object_has_member (options, "message")) json_object_set_string_member (options, "message", message); g_message ("%s: %s", self->priv->id, message); g_free (message); cockpit_channel_close (self, problem); }
/** * cockpit_channel_close_options * @self: a channel * * Called by implementations to get the channel's close options. * * Returns: (transfer none): the close options, should not be NULL */ JsonObject * cockpit_channel_close_options (CockpitChannel *self) { g_return_val_if_fail (COCKPIT_IS_CHANNEL (self), NULL); if (!self->priv->close_options) self->priv->close_options = json_object_new (); return self->priv->close_options; }
/** * cockpit_channel_control: * @self: the channel * @command: the control command * @options: optional control message or NULL * * Send a control message to the other side. * * If @options is not NULL, then it may be modified by this code. * * With @command of "done" will send an EOF to the other side. This * should only be called once. Whether an EOF should be sent or not * depends on the payload type. */ void cockpit_channel_control (CockpitChannel *self, const gchar *command, JsonObject *options) { JsonObject *object; GBytes *message; const gchar *problem; gchar *problem_copy = NULL; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); g_return_if_fail (command != NULL); if (g_str_equal (command, "done")) { g_return_if_fail (self->priv->sent_done == FALSE); self->priv->sent_done = TRUE; } /* If closing save the close options * and let close send the message */ else if (g_str_equal (command, "close")) { if (!self->priv->close_options) { /* Ref for close_options, freed in parent */ self->priv->close_options = json_object_ref (options); } if (!cockpit_json_get_string (options, "problem", NULL, &problem)) problem = NULL; /* Use a problem copy so it out lasts the value in close_options */ problem_copy = g_strdup (problem); cockpit_channel_close (self, problem_copy); goto out; } if (options) object = json_object_ref (options); else object = json_object_new (); json_object_set_string_member (object, "command", command); json_object_set_string_member (object, "channel", self->priv->id); message = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (self->priv->transport, NULL, message); g_bytes_unref (message); out: g_free (problem_copy); }
/** * cockpit_channel_close_int_option: * @self: a channel * @name: the option name * @value: the value to add * * Add a value to the close message for this channel. This must * be called before the cockpit_channel_close base class * implementation. */ void cockpit_channel_close_int_option (CockpitChannel *self, const gchar *name, gint64 value) { g_return_if_fail (COCKPIT_IS_CHANNEL (self)); g_return_if_fail (name != NULL); if (!self->priv->close_options) self->priv->close_options = json_object_new (); json_object_set_int_member (self->priv->close_options, name, value); }
/** * cockpit_channel_close: * @self: a channel * @problem: the problem or NULL * * Close the channel. This can be called mulitple times. * * It may be that the channel doesn't close immediately. * The channel will emit the CockpitChannel::closed signal when the * channel actually closes. * * A @reason of NULL represents an orderly close. */ void cockpit_channel_close (CockpitChannel *self, const gchar *reason) { CockpitChannelClass *klass; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); klass = COCKPIT_CHANNEL_GET_CLASS (self); g_assert (klass->close != NULL); (klass->close) (self, reason); }
void cockpit_channel_close_obj_option (CockpitChannel *self, const gchar *name, JsonObject *object) { g_return_if_fail (COCKPIT_IS_CHANNEL (self)); g_return_if_fail (name != NULL); g_return_if_fail (object != NULL); if (!self->priv->close_options) self->priv->close_options = json_object_new (); json_object_set_object_member (self->priv->close_options, name, json_object_ref (object)); }
/** * cockpit_channel_prepare: * @self: the channel * * Usually this is automatically called after the channel is * created and control returns to the mainloop. However you * can preempt that by calling this function. */ void cockpit_channel_prepare (CockpitChannel *self) { CockpitChannelClass *klass; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); if (!self->priv->prepare_tag) return; g_source_remove (self->priv->prepare_tag); self->priv->prepare_tag = 0; if (!self->priv->emitted_close) { klass = COCKPIT_CHANNEL_GET_CLASS (self); g_assert (klass->prepare); (klass->prepare) (self); } }
/** * cockpit_channel_done: * @self: the channel * * Send an EOF to the other side. This should only be called once. * Whether an EOF should be sent or not depends on the payload type. */ void cockpit_channel_done (CockpitChannel *self) { JsonObject *object; GBytes *message; g_return_if_fail (COCKPIT_IS_CHANNEL (self)); g_return_if_fail (self->priv->sent_done == FALSE); self->priv->sent_done = TRUE; object = json_object_new (); json_object_set_string_member (object, "command", "done"); json_object_set_string_member (object, "channel", self->priv->id); message = cockpit_json_write_bytes (object); json_object_unref (object); cockpit_transport_send (self->priv->transport, NULL, message); g_bytes_unref (message); }
/** * cockpit_channel_get_id: * @self a channel * * Get the identifier for this channel. * * Returns: (transfer none): the identifier */ const gchar * cockpit_channel_get_id (CockpitChannel *self) { g_return_val_if_fail (COCKPIT_IS_CHANNEL (self), NULL); return self->priv->id; }
/** * cockpit_channel_get_option: * @self: a channel * * Called by implementations to get the channel's open options. * * Returns: (transfer none): the open options, should not be NULL */ JsonObject * cockpit_channel_get_options (CockpitChannel *self) { g_return_val_if_fail (COCKPIT_IS_CHANNEL (self), NULL); return self->priv->open_options; }
/** * cockpit_channel_get_transport: * @self: a channel * * Called by implementations to get the channel's transtport. * * Returns: (transfer none): the transport, should not be NULL */ CockpitTransport * cockpit_channel_get_transport (CockpitChannel *self) { g_return_val_if_fail (COCKPIT_IS_CHANNEL (self), NULL); return self->priv->transport; }