128 lines
2.9 KiB
C
128 lines
2.9 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include "cmsg_private.h"
|
|
#include "ref.h"
|
|
#include "sexp.h"
|
|
#include "hashtable.h"
|
|
#include "node.h"
|
|
|
|
static hashtable_t node_class_table;
|
|
static hashtable_t directory;
|
|
|
|
static void *node_incref(void *arg) {
|
|
return INCREF((node_t *) arg);
|
|
}
|
|
|
|
static void node_decref(void *arg) {
|
|
DECREF((node_t *) arg, node_destructor);
|
|
}
|
|
|
|
void init_node(void) {
|
|
init_hashtable(&node_class_table,
|
|
31,
|
|
NULL,
|
|
NULL);
|
|
init_hashtable(&directory,
|
|
10007,
|
|
node_incref,
|
|
node_decref);
|
|
}
|
|
|
|
void register_node_class(node_class_t *nc) {
|
|
cmsg_bytes_t key = cmsg_cstring_bytes(nc->name);
|
|
if (hashtable_contains(&node_class_table, key)) {
|
|
die("Duplicate node class name %s\n", nc->name);
|
|
}
|
|
hashtable_put(&node_class_table, key, nc);
|
|
}
|
|
|
|
node_class_t *lookup_node_class(cmsg_bytes_t name) {
|
|
node_class_t *nc = NULL;
|
|
hashtable_get(&node_class_table, name, (void **) &nc);
|
|
return nc;
|
|
}
|
|
|
|
node_t *new_node(node_class_t *nc, sexp_t *args) {
|
|
node_t *n = nc->construct(nc, args);
|
|
n->refcount = ZERO_REFCOUNT();
|
|
n->node_class = nc;
|
|
init_hashtable(&n->names, 5, NULL, NULL);
|
|
return n;
|
|
}
|
|
|
|
void node_destructor(node_t *n) {
|
|
unbind_all_names_for_node(n);
|
|
destroy_hashtable(&n->names);
|
|
n->node_class->destroy(n);
|
|
}
|
|
|
|
node_t *lookup_node(cmsg_bytes_t name) {
|
|
node_t *n = NULL;
|
|
hashtable_get(&directory, name, (void **) &n);
|
|
return n;
|
|
}
|
|
|
|
int bind_node(cmsg_bytes_t name, node_t *n) {
|
|
if (hashtable_contains(&directory, name)) {
|
|
return 0;
|
|
}
|
|
hashtable_put(&directory, name, n);
|
|
hashtable_put(&n->names, name, NULL);
|
|
info("Binding node <<%.*s>> of class %s\n", name.len, name.bytes, n->node_class->name);
|
|
return 1;
|
|
}
|
|
|
|
int unbind_node(cmsg_bytes_t name) {
|
|
node_t *n = NULL;
|
|
hashtable_get(&directory, name, (void **) &n);
|
|
if (n == NULL) {
|
|
return 0;
|
|
} else {
|
|
info("Unbinding node <<%.*s>> of class %s\n", name.len, name.bytes, n->node_class->name);
|
|
hashtable_erase(&n->names, name);
|
|
hashtable_erase(&directory, name);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static void unbind_on_destroy(void *context, cmsg_bytes_t key, void *value) {
|
|
unbind_node(key);
|
|
}
|
|
|
|
void unbind_all_names_for_node(node_t *n) {
|
|
hashtable_foreach(&n->names, unbind_on_destroy, NULL);
|
|
}
|
|
|
|
int post_node(cmsg_bytes_t node, cmsg_bytes_t name, sexp_t *body) {
|
|
static sexp_t *post_atom = NULL;
|
|
sexp_t *msg = NULL;
|
|
int result;
|
|
|
|
if (post_atom == NULL) {
|
|
post_atom = INCREF(sexp_bytes(cmsg_cstring_bytes("post")));
|
|
}
|
|
|
|
msg = sexp_cons(body, msg);
|
|
msg = sexp_cons(sexp_bytes(name), msg);
|
|
msg = sexp_cons(post_atom, msg);
|
|
INCREF(msg);
|
|
result = send_node(node, msg);
|
|
DECREF(msg, sexp_destructor);
|
|
|
|
return result;
|
|
}
|
|
|
|
int send_node(cmsg_bytes_t node, sexp_t *message) {
|
|
node_t *n = lookup_node(node);
|
|
if (n == NULL) {
|
|
return 0;
|
|
}
|
|
n->node_class->handle_message(n, message);
|
|
return 1;
|
|
}
|