/** * \brief This function creates new node at verse server, when client sent * node_create command. */ static struct VSNode *vs_node_new(struct VS_CTX *vs_ctx, struct VSession *vsession, const uint16 type) { struct VSNode *node = NULL; struct VSNode find_node, *avatar_node; struct VSUser *owner; struct VBucket *bucket; struct VSNodePermission *perm; struct VSNodeSubscriber *node_subscriber; /* Try to find avatar node to be able to create initial link to * avatar node (initial parent of new created node) */ find_node.id = vsession->avatar_id; bucket = v_hash_array_find_item(&vs_ctx->data.nodes, &find_node); if(bucket != NULL) { avatar_node = (struct VSNode*)bucket->data; } else { v_print_log(VRS_PRINT_DEBUG_MSG, "vsession->avatar_id: %d not found\n", vsession->avatar_id); goto end; } /* Try to find owner of the new node */ if((owner = vs_user_find(vs_ctx, vsession->user_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "vsession->user_id: %d not found\n", vsession->user_id); goto end; } /* Try to create new verse node */ if( (node = vs_node_create(vs_ctx, avatar_node, owner, VRS_RESERVED_NODE_ID, type)) == NULL) { goto end; } /* Set initial state of this node */ node->state = ENTITY_CREATING; /* Find node representing fake user other_users */ if( vs_ctx->other_users != NULL) { /* Set access permissions for other users */ perm = (struct VSNodePermission *)calloc(1, sizeof(struct VSNodePermission)); perm->user = vs_ctx->other_users; /* TODO: implement default session permissions and use them, * when are available */ perm->permissions = vs_ctx->default_perm; v_list_add_tail(&node->permissions, perm); } /* Send node_create to all subscribers of avatar node data */ node_subscriber = avatar_node->node_subs.first; while(node_subscriber) { vs_node_send_create(node_subscriber, node, avatar_node); node_subscriber = node_subscriber->next; } end: return node; }
/** * \brief This function handle changing link between nodes */ int vs_handle_link_change(struct VS_CTX *vs_ctx, struct VSession *vsession, struct Generic_Cmd *node_link) { struct VSUser *user = (struct VSUser*)vsession->user; struct VSNode *old_parent_node, *parent_node, *child_node; struct VSLink *link; struct VSNodeSubscriber *node_subscriber; struct VSEntityFollower *node_follower; uint32 parent_node_id = UINT32(node_link->data[0]); uint32 child_node_id = UINT32(node_link->data[UINT32_SIZE]); int i; /* Try to find child node */ if((child_node = vs_node_find(vs_ctx, child_node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node (id: %d) not found\n", __FUNCTION__, __LINE__, child_node_id); return 0; } /* Child node has to be created */ if(! (child_node->state == ENTITY_CREATED || child_node->state == ENTITY_CREATING)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node id: %d is not in NODE_CREATED state: %d\n", __FUNCTION__, __LINE__, child_node->id, child_node->state); return 0; } /* Is user owner of child node or can user write to child node? */ if(vs_node_can_write(vsession, child_node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d user: %s can't write to child node: %d (owner: %s)\n", __FUNCTION__, __LINE__, user->username, child_node->id, child_node->owner->username); return 0; } /* Old link */ link = child_node->parent_link; /* Old parent node */ old_parent_node = link->parent; /* Is user owner of old parent node or can user write to old parent node? */ if(vs_node_can_write(vsession, old_parent_node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d user: %s can't write to old parent node: %d (owner: %s)\n", __FUNCTION__, __LINE__, user->username, old_parent_node->id, old_parent_node->owner->username); return 0; } /* Try to find new parent node */ if((parent_node = vs_node_find(vs_ctx, parent_node_id)) == NULL) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node (id: %d) not found\n", __FUNCTION__, __LINE__, parent_node_id); return 0; } /* Parent node has to be created */ if(! (parent_node->state == ENTITY_CREATED || parent_node->state == ENTITY_CREATING)) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node (id: %d) is not in NODE_CREATED state: %d\n", __FUNCTION__, __LINE__, parent_node->id, parent_node->state); return 0; } /* Test if client doesn't want to recreate existing link */ if( parent_node == old_parent_node) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d link between nodes (parent_id: %d) (child_id: %d) already exists\n", __FUNCTION__, __LINE__, parent_node->id, child_node->id); return 0; } /* Is user owner of parent node or can user write to parent node? */ if(vs_node_can_write(vsession, parent_node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d user: %s can't write to parent node: %d (owner: %s)\n", __FUNCTION__, __LINE__, user->username, parent_node->id, parent_node->owner->username); return 0; } /* Test, if new link could be created */ if(vs_link_test_nodes(parent_node, child_node) != 1) { v_print_log(VRS_PRINT_DEBUG_MSG, "%s():%d node: %d can't be child of node: %d\n", __FUNCTION__, __LINE__, child_node->id, parent_node->id); return 0; } /* Remove link from old parent node */ v_list_rem_item(&old_parent_node->children_links, link); /* Add link to new parent node */ v_list_add_tail(&parent_node->children_links, link); link->parent = parent_node; /* Update child node internal properties according new parent node */ vs_link_update_child(parent_node, child_node); /* Update version in child node, parent node and old parent node */ vs_node_inc_version(parent_node); vs_node_inc_version(child_node); vs_node_inc_version(old_parent_node); /* Subscribers of old and new parent node will receive information about * changing link between nodes. Prevent double sending command Node_Link, * when clients are subscribed to both nodes. */ /* Set temporary value in all sessions */ for(i=0; i<vs_ctx->max_sessions; i++) { vs_ctx->vsessions[i]->tmp = 0; } /* Send Node_Link command to subscribers of old parent node and set * session temporary value */ node_subscriber = old_parent_node->node_subs.first; while(node_subscriber != NULL) { if(vs_node_can_read(node_subscriber->session, old_parent_node) == 1) { node_subscriber->session->tmp = 1; vs_link_change_send(node_subscriber, link); } node_subscriber = node_subscriber->next; } /* When client is subscribed to the new parent node and aware of child * node, then send to the client only node_link */ node_follower = child_node->node_folls.first; while(node_follower != NULL) { if(node_follower->node_sub->session->tmp != 1) { vs_link_change_send(node_follower->node_sub, link); node_follower->node_sub->session->tmp = 1; } node_follower = node_follower->next; } /* Send Node_Create command to subscribers of new parent node, when * subscribers were not subscribed to child node */ node_subscriber = parent_node->node_subs.first; while(node_subscriber != NULL) { if(node_subscriber->session->tmp != 1) { if(vs_node_can_read(node_subscriber->session, parent_node) == 1) { vs_node_send_create(node_subscriber, child_node, NULL); } } node_subscriber = node_subscriber->next; } return 1; }
/** * \brief This function add session (client) to the list of clients that are * subscribed this node. */ static int vs_node_subscribe(struct VS_CTX *vs_ctx, struct VSession *vsession, struct VSNode *node, uint32 version) { struct VSNode *child_node; struct VSNodePermission *perm; struct VSNodeSubscriber *node_subscriber; struct VSLink *link; struct VBucket *bucket; struct VSTagGroup *tg; struct VSLayer *layer; int user_can_read = 0; /* Can user subscribe to this node? */ user_can_read = vs_node_can_read(vs_ctx, vsession, node); /* Add current session to the list of node subscribers */ node_subscriber = (struct VSNodeSubscriber*)calloc(1, sizeof(struct VSNodeSubscriber)); node_subscriber->session = vsession; node_subscriber->prio = VRS_DEFAULT_PRIORITY; v_list_add_tail(&node->node_subs, node_subscriber); /* TODO: send node_subscribe with version and commands with difference * between this version and current state, when versing will be supported */ if(version != 0) { v_print_log(VRS_PRINT_WARNING, "Version: %d != 0, versing is not supported yet\n", version); } /* Send node_perm commands to the new subscriber */ perm = node->permissions.first; while(perm != NULL) { vs_node_send_perm(node_subscriber, node, perm->user, perm->permissions); perm = perm->next; } /* If the node is locked, then send node_lock to the subscriber */ if(node->lock.session != NULL) { vs_node_send_lock(node_subscriber, node->lock.session, node); } /* If user doesn't have permission to subscribe to this node, then send * only node_perm command explaining, why user can't rest of this * node */ if(user_can_read == 0) { v_print_log(VRS_PRINT_DEBUG_MSG, "Insufficient permission to read content of the node: %d\n", node->id); return 0; } /* Send node_create of all child nodes of this node and corresponding * links */ link = node->children_links.first; while(link!=NULL) { child_node = link->child; vs_node_send_create(node_subscriber, child_node, NULL); link = link->next; } /* Send taggroup_create of all tag_groups in this node */ bucket = node->tag_groups.lb.first; while(bucket != NULL) { tg = (struct VSTagGroup*)bucket->data; if(tg->state == ENTITY_CREATING || tg->state == ENTITY_CREATED) { vs_taggroup_send_create(node_subscriber, node, tg); } bucket = bucket->next; } /* Send layer_create for all layers in this node */ bucket = node->layers.lb.first; while(bucket != NULL) { layer = (struct VSLayer*)bucket->data; if(layer->state == ENTITY_CREATING || layer->state == ENTITY_CREATED) { vs_layer_send_create(node_subscriber, node, layer); } bucket = bucket->next; } return 1; }