#include "pn_cmd_node.h" #include "pn_trans.h" #include "pn_parser.h" #include "pn_cmd.h" #include "pn_buffer.h" #include #include "pn_log.h" static void *parent_class; struct pn_cmd_node_priv { unsigned counter; GHashTable *transactions; }; struct pn_cmd_node * pn_cmd_node_new(void) { return g_object_new(PN_CMD_NODE_TYPE, NULL); } void pn_cmd_node_free(struct pn_cmd_node *conn) { if (!conn) return; g_object_unref(conn); } static inline void show_cmd(bool incoming, const char *str, size_t len) { const char *mark = incoming ? "<-" : "->"; pn_info(NULL, "%s %.*s", mark, len, str); } static void send_valist(struct pn_cmd_node *self, pn_trans_cb_t cb, const char *command, const char *format, va_list args) { struct pn_cmd_node_priv *priv = self->priv; struct pn_trans *trans; trans = pn_trans_new(); trans->id = ++priv->counter; trans->command = g_strdup(command); trans->params = g_strdup_vprintf(format, args); trans->cb = cb; g_hash_table_insert(priv->transactions, GINT_TO_POINTER(trans->id), trans); { char *data; size_t len; data = pn_trans_to_string(trans); len = strlen(data); show_cmd(false, data, len - 2); pn_node_write(PN_NODE(self), data, len); } } void pn_cmd_node_send(struct pn_cmd_node *self, pn_trans_cb_t cb, const char *command, const char *format, ...) { va_list args; va_start(args, format); send_valist(self, cb, command, format, args); va_end(args); } /* pn_node stuff */ static void got_command(struct pn_cmd_node *self, const char *string, gsize length) { struct pn_cmd_node_priv *priv = self->priv; struct pn_cmd *cmd; struct pn_trans *trans = NULL; pn_trans_cb_t cb = NULL; show_cmd(true, string, length); cmd = pn_cmd_new_from_string(string, length); if (cmd->tr_id) trans = g_hash_table_lookup(priv->transactions, GINT_TO_POINTER(cmd->tr_id)); if (trans) cb = trans->cb; if (cb) cb(self, cmd); else pn_warn(self, "unhandled command: %.*s", length, string); pn_cmd_free(cmd); } static void parse_impl(struct pn_node *node, struct pn_buffer *buffer) { bool more; do { char *cmd; gsize length; more = pn_buffer_read_line(buffer, &cmd, &length); if (cmd) got_command(PN_CMD_NODE(node), cmd, length); } while (more); if (buffer->offset) { size_t cur_len = buffer->len - buffer->offset; pn_buffer_prepare(buffer, cur_len); memmove(buffer->data, buffer->data + buffer->offset, cur_len); } } /* GObject stuff */ static void finalize(GObject *obj) { struct pn_cmd_node_priv *priv = PN_CMD_NODE(obj)->priv; g_hash_table_destroy(priv->transactions); G_OBJECT_CLASS(parent_class)->finalize(obj); } static void class_init(void *g_class, void *class_data) { struct pn_node_class *node_class = PN_NODE_CLASS(g_class); GObjectClass *gobject_class = G_OBJECT_CLASS(g_class); parent_class = g_type_class_peek_parent(g_class); g_type_class_add_private(g_class, sizeof(struct pn_cmd_node_priv)); node_class->parse = &parse_impl; gobject_class->finalize = finalize; } static void instance_init(GTypeInstance *instance, void *g_class) { struct pn_cmd_node *self = PN_CMD_NODE(instance); struct pn_cmd_node_priv *priv; self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(instance, PN_CMD_NODE_TYPE, struct pn_cmd_node_priv); priv->transactions = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) pn_trans_free); } GType pn_cmd_node_get_type(void) { static gsize init_type; if (g_once_init_enter(&init_type)) { GType type; GTypeInfo type_info = { .class_size = sizeof(struct pn_cmd_node_class), .class_init = class_init, .instance_size = sizeof(struct pn_cmd_node), .instance_init = instance_init, }; type = g_type_register_static(PN_NODE_TYPE, "PnCmdNode", &type_info, 0); g_once_init_leave(&init_type, type); } return init_type; }