/*! * \internal * Shared code for all handlers */ static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_ari_response *response) { struct ast_json *message = ast_json_pack("{s: s, s: {}, s: {}, s: {}}", "name", name, "get_params", "path_vars", "headers"); struct ast_json *get_params_obj = ast_json_object_get(message, "get_params"); struct ast_json *path_vars_obj = ast_json_object_get(message, "path_vars"); struct ast_json *headers_obj = ast_json_object_get(message, "headers"); for (; get_params != NULL; get_params = get_params->next) { ast_json_object_set(get_params_obj, get_params->name, ast_json_string_create(get_params->value)); } for (; path_vars != NULL; path_vars = path_vars->next) { ast_json_object_set(path_vars_obj, path_vars->name, ast_json_string_create(path_vars->value)); } for (; headers != NULL; headers = headers->next) { ast_json_object_set(headers_obj, headers->name, ast_json_string_create(headers->value)); } ++invocation_count; response->response_code = response_code; response->message = message; }
struct ast_json *ast_json_dialplan_cep(const char *context, const char *exten, int priority) { return ast_json_pack("{s: o, s: o, s: o}", "context", context ? ast_json_string_create(context) : ast_json_null(), "exten", exten ? ast_json_string_create(exten) : ast_json_null(), "priority", priority != -1 ? ast_json_integer_create(priority) : ast_json_null()); }
/*! \internal \brief convert multi object blob to ari json */ static struct ast_json *multi_user_event_to_json( struct stasis_message *message, const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, out, NULL, ast_json_unref); struct ast_multi_object_blob *multi = stasis_message_data(message); struct ast_json *blob = multi->blob; const struct timeval *tv = stasis_message_timestamp(message); enum stasis_user_multi_object_snapshot_type type; int i; out = ast_json_object_create(); if (!out) { return NULL; } ast_json_object_set(out, "type", ast_json_string_create("ChannelUserevent")); ast_json_object_set(out, "timestamp", ast_json_timeval(*tv, NULL)); ast_json_object_set(out, "eventname", ast_json_string_create(ast_json_string_get((ast_json_object_get(blob, "eventname"))))); ast_json_object_set(out, "userevent", ast_json_deep_copy(blob)); for (type = 0; type < STASIS_UMOS_MAX; ++type) { for (i = 0; i < AST_VECTOR_SIZE(&multi->snapshots[type]); ++i) { struct ast_json *json_object = NULL; char *name = NULL; void *snapshot = AST_VECTOR_GET(&multi->snapshots[type], i); switch (type) { case STASIS_UMOS_CHANNEL: json_object = ast_channel_snapshot_to_json(snapshot, sanitize); name = "channel"; break; case STASIS_UMOS_BRIDGE: json_object = ast_bridge_snapshot_to_json(snapshot, sanitize); name = "bridge"; break; case STASIS_UMOS_ENDPOINT: json_object = ast_endpoint_snapshot_to_json(snapshot, sanitize); name = "endpoint"; break; } if (json_object) { ast_json_object_set(out, name, json_object); } } } return ast_json_ref(out); }
/*! * \brief Send a message to the given application. * \param app App to send the message to. * \param message Message to send. */ void app_send(struct stasis_app *app, struct ast_json *message) { stasis_app_cb handler; char eid[20]; void *data; if (ast_json_object_set(message, "asterisk_id", ast_json_string_create( ast_eid_to_str(eid, sizeof(eid), &ast_eid_default)))) { ast_log(AST_LOG_WARNING, "Failed to append EID to outgoing event %s\n", ast_json_string_get(ast_json_object_get(message, "type"))); } /* Copy off mutable state with lock held */ ao2_lock(app); handler = app->handler; data = ao2_bump(app->data); ao2_unlock(app); /* Name is immutable; no need to copy */ if (handler) { handler(data, app->name, message); } else { ast_verb(3, "Inactive Stasis app '%s' missed message\n", app->name); } ao2_cleanup(data); }
static void sub_bridge_update_handler(void *data, struct stasis_subscription *sub, struct stasis_message *message) { struct ast_json *json = NULL; struct stasis_app *app = data; struct ast_bridge_snapshot_update *update; const struct timeval *tv; update = stasis_message_data(message); tv = stasis_message_timestamp(message); if (!update->new_snapshot) { json = simple_bridge_event("BridgeDestroyed", update->old_snapshot, tv); } else if (!update->old_snapshot) { json = simple_bridge_event("BridgeCreated", update->new_snapshot, tv); } else if (update->new_snapshot && update->old_snapshot && strcmp(update->new_snapshot->video_source_id, update->old_snapshot->video_source_id)) { json = simple_bridge_event("BridgeVideoSourceChanged", update->new_snapshot, tv); if (json && !ast_strlen_zero(update->old_snapshot->video_source_id)) { ast_json_object_set(json, "old_video_source_id", ast_json_string_create(update->old_snapshot->video_source_id)); } } if (json) { app_send(app, json); ast_json_unref(json); } if (!update->new_snapshot && update->old_snapshot) { unsubscribe(app, "bridge", update->old_snapshot->uniqueid, 1); } }
/*! * \brief Send a message to the given application. * \param app App to send the message to. * \param message Message to send. */ void app_send(struct stasis_app *app, struct ast_json *message) { stasis_app_cb handler; char eid[20]; RAII_VAR(void *, data, NULL, ao2_cleanup); if (ast_json_object_set(message, "asterisk_id", ast_json_string_create( ast_eid_to_str(eid, sizeof(eid), &ast_eid_default)))) { ast_log(AST_LOG_WARNING, "Failed to append EID to outgoing event %s\n", ast_json_string_get(ast_json_object_get(message, "type"))); } /* Copy off mutable state with lock held */ { SCOPED_AO2LOCK(lock, app); handler = app->handler; if (app->data) { ao2_ref(app->data, +1); data = app->data; } /* Name is immutable; no need to copy */ } if (!handler) { ast_verb(3, "Inactive Stasis app '%s' missed message\n", app->name); return; } handler(data, app->name, message); }
int delete_queue(const char* uuid) { struct ast_json* j_tmp; char* tmp; char* sql; int ret; if(uuid == NULL) { // invalid parameter. return false; } j_tmp = ast_json_object_create(); tmp = get_utc_timestamp(); ast_json_object_set(j_tmp, "tm_delete", ast_json_string_create(tmp)); ast_json_object_set(j_tmp, "in_use", ast_json_integer_create(E_DL_USE_NO)); ast_free(tmp); tmp = db_get_update_str(j_tmp); AST_JSON_UNREF(j_tmp); ast_asprintf(&sql, "update queue set %s where uuid=\"%s\";", tmp, uuid); ast_free(tmp); ret = db_exec(sql); ast_free(sql); if(ret == false) { ast_log(LOG_WARNING, "Could not delete queue. uuid[%s]\n", uuid); return false; } // send notification send_manager_evt_out_queue_delete(uuid); return true; }
int create_queue(struct ast_json* j_queue) { int ret; char* uuid; struct ast_json* j_tmp; if(j_queue == NULL) { return false; } j_tmp = ast_json_deep_copy(j_queue); uuid = gen_uuid(); ast_json_object_set(j_tmp, "uuid", ast_json_string_create(uuid)); ast_log(LOG_NOTICE, "Create queue. uuid[%s], name[%s]\n", ast_json_string_get(ast_json_object_get(j_tmp, "uuid")), ast_json_string_get(ast_json_object_get(j_tmp, "name")) ); ret = db_insert("queue", j_tmp); AST_JSON_UNREF(j_tmp); if(ret == false) { ast_free(uuid); return false; } // send ami event j_tmp = get_queue(uuid); send_manager_evt_out_queue_create(j_tmp); AST_JSON_UNREF(j_tmp); return true; }
/*! * \brief Callback handler for Stasis application messages. */ static void app_handler(void *data, const char *app_name, struct ast_json *message) { struct event_session *session = data; int res; const char *msg_type = S_OR( ast_json_string_get(ast_json_object_get(message, "type")), ""); const char *msg_application = S_OR( ast_json_string_get(ast_json_object_get(message, "application")), ""); /* Determine if we've been replaced */ if (strcmp(msg_type, "ApplicationReplaced") == 0 && strcmp(msg_application, app_name) == 0) { ao2_find(session->websocket_apps, msg_application, OBJ_UNLINK | OBJ_NODATA); } res = ast_json_object_set(message, "application", ast_json_string_create(app_name)); if(res != 0) { return; } ao2_lock(session); if (session->ws_session) { ast_ari_websocket_session_write(session->ws_session, message); } ao2_unlock(session); }
static void recording_publish(struct stasis_app_recording *recording, const char *cause) { RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); ast_assert(recording != NULL); json = stasis_app_recording_to_json(recording); if (json == NULL) { return; } if (!ast_strlen_zero(cause)) { struct ast_json *failure_cause = ast_json_string_create(cause); if (!failure_cause) { return; } if (ast_json_object_set(json, "cause", failure_cause)) { return; } } message = ast_channel_blob_create_from_cache( stasis_app_control_get_channel_id(recording->control), stasis_app_recording_snapshot_type(), json); if (message == NULL) { return; } stasis_app_control_publish(recording->control, message); }
/** * Create plan. * @param j_plan * @return */ bool create_plan(const struct ast_json* j_plan) { int ret; char* uuid; struct ast_json* j_tmp; char* tmp; if(j_plan == NULL) { return false; } j_tmp = ast_json_deep_copy(j_plan); uuid = gen_uuid(); ast_json_object_set(j_tmp, "uuid", ast_json_string_create(uuid)); tmp = get_utc_timestamp(); ast_json_object_set(j_tmp, "tm_create", ast_json_string_create(tmp)); ast_free(tmp); ast_log(LOG_NOTICE, "Create plan. uuid[%s], name[%s]\n", ast_json_string_get(ast_json_object_get(j_tmp, "uuid")), ast_json_string_get(ast_json_object_get(j_tmp, "name"))? : "<unknown>" ); ret = db_insert("plan", j_tmp); AST_JSON_UNREF(j_tmp); if(ret == false) { ast_free(uuid); return false; } ast_log(LOG_VERBOSE, "Finished insert.\n"); // send ami event j_tmp = get_plan(uuid); ast_log(LOG_VERBOSE, "Check plan info. uuid[%s]\n", ast_json_string_get(ast_json_object_get(j_tmp, "uuid")) ); ast_free(uuid); if(j_tmp == NULL) { ast_log(LOG_ERROR, "Could not get created plan info."); return false; } send_manager_evt_out_plan_create(j_tmp); AST_JSON_UNREF(j_tmp); return true; }
struct ast_json *ast_json_channel_vars(struct varshead *channelvars) { struct ast_json *ret; struct ast_var_t *var; ret = ast_json_object_create(); AST_LIST_TRAVERSE(channelvars, var, entries) { ast_json_object_set(ret, var->name, ast_json_string_create(var->value)); }
struct ast_json *ast_json_timeval(const struct timeval tv, const char *zone) { char buf[AST_ISO8601_LEN]; struct ast_tm tm = {}; ast_localtime(&tv, &tm, zone); ast_strftime(buf, sizeof(buf),AST_ISO8601_FORMAT, &tm); return ast_json_string_create(buf); }
struct ast_json *app_to_json(const struct stasis_app *app) { struct ast_json *json; struct ast_json *channels; struct ast_json *bridges; struct ast_json *endpoints; struct ao2_iterator i; struct app_forwards *forwards; json = ast_json_pack("{s: s, s: [], s: [], s: []}", "name", app->name, "channel_ids", "bridge_ids", "endpoint_ids"); if (!json) { return NULL; } channels = ast_json_object_get(json, "channel_ids"); bridges = ast_json_object_get(json, "bridge_ids"); endpoints = ast_json_object_get(json, "endpoint_ids"); i = ao2_iterator_init(app->forwards, 0); while ((forwards = ao2_iterator_next(&i))) { struct ast_json *array = NULL; int append_res; switch (forwards->forward_type) { case FORWARD_CHANNEL: array = channels; break; case FORWARD_BRIDGE: array = bridges; break; case FORWARD_ENDPOINT: array = endpoints; break; } /* If forward_type value is unexpected this will safely return an error. */ append_res = ast_json_array_append(array, ast_json_string_create(forwards->id)); ao2_ref(forwards, -1); if (append_res != 0) { ast_log(LOG_ERROR, "Error building response\n"); ao2_iterator_destroy(&i); ast_json_unref(json); return NULL; } } ao2_iterator_destroy(&i); return json; }
struct ast_json *app_to_json(const struct stasis_app *app) { RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json *channels; struct ast_json *bridges; struct ast_json *endpoints; struct ao2_iterator i; void *obj; json = ast_json_pack("{s: s, s: [], s: [], s: []}", "name", app->name, "channel_ids", "bridge_ids", "endpoint_ids"); channels = ast_json_object_get(json, "channel_ids"); bridges = ast_json_object_get(json, "bridge_ids"); endpoints = ast_json_object_get(json, "endpoint_ids"); i = ao2_iterator_init(app->forwards, 0); while ((obj = ao2_iterator_next(&i))) { RAII_VAR(struct app_forwards *, forwards, obj, ao2_cleanup); RAII_VAR(struct ast_json *, id, NULL, ast_json_unref); int append_res = -1; id = ast_json_string_create(forwards->id); switch (forwards->forward_type) { case FORWARD_CHANNEL: append_res = ast_json_array_append(channels, ast_json_ref(id)); break; case FORWARD_BRIDGE: append_res = ast_json_array_append(bridges, ast_json_ref(id)); break; case FORWARD_ENDPOINT: append_res = ast_json_array_append(endpoints, ast_json_ref(id)); break; } if (append_res != 0) { ast_log(LOG_ERROR, "Error building response\n"); ao2_iterator_destroy(&i); return NULL; } } ao2_iterator_destroy(&i); return ast_json_ref(json); }
/*! * \brief Identify module by name and process resource information * \param module Resource name * \param description Resource description * \param usecnt Resource use count * \param status Resource running status * \param like * \param support_level Resource support level * \param data JSON body for resource * \param condition Name to match resource to * * \retval 0 if no resource exists * \retval 1 if resource exists */ static int identify_module(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level, void *data, const char *condition) { int json_obj_set = 0; if (strcmp(condition, module) != 0) { return 0; } json_obj_set += ast_json_object_set(data, "name", ast_json_string_create(module)); json_obj_set += ast_json_object_set(data, "description", ast_json_string_create(description)); json_obj_set += ast_json_object_set(data, "use_count", ast_json_integer_create(usecnt)); json_obj_set += ast_json_object_set(data, "status", ast_json_string_create(status)); json_obj_set += ast_json_object_set(data, "support_level", ast_json_string_create( ast_module_support_level_to_string(support_level))); if (json_obj_set != 0) { return 0; } return 1; }
struct ast_json *ast_endpoint_snapshot_to_json( const struct ast_endpoint_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json *channel_array; int i; json = ast_json_pack("{s: s, s: s, s: s, s: []}", "technology", snapshot->tech, "resource", snapshot->resource, "state", ast_endpoint_state_to_string(snapshot->state), "channel_ids"); if (json == NULL) { return NULL; } if (snapshot->max_channels != -1) { int res = ast_json_object_set(json, "max_channels", ast_json_integer_create(snapshot->max_channels)); if (res != 0) { return NULL; } } channel_array = ast_json_object_get(json, "channel_ids"); ast_assert(channel_array != NULL); for (i = 0; i < snapshot->num_channels; ++i) { int res; if (sanitize && sanitize->channel_id && sanitize->channel_id(snapshot->channel_ids[i])) { continue; } res = ast_json_array_append(channel_array, ast_json_string_create(snapshot->channel_ids[i])); if (res != 0) { return NULL; } } return ast_json_ref(json); }
static struct ast_json *channel_blob_to_json( struct stasis_message *message, const char *type, const struct stasis_message_sanitizer *sanitize) { RAII_VAR(struct ast_json *, out, NULL, ast_json_unref); struct ast_channel_blob *channel_blob = stasis_message_data(message); struct ast_json *blob = channel_blob->blob; struct ast_channel_snapshot *snapshot = channel_blob->snapshot; const struct timeval *tv = stasis_message_timestamp(message); int res = 0; if (blob == NULL || ast_json_is_null(blob)) { out = ast_json_object_create(); } else { /* blobs are immutable, so shallow copies are fine */ out = ast_json_copy(blob); } if (!out) { return NULL; } res |= ast_json_object_set(out, "type", ast_json_string_create(type)); res |= ast_json_object_set(out, "timestamp", ast_json_timeval(*tv, NULL)); /* For global channel messages, the snapshot is optional */ if (snapshot) { struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize); if (!json_channel) { return NULL; } res |= ast_json_object_set(out, "channel", json_channel); } if (res != 0) { return NULL; } return ast_json_ref(out); }
static void sub_bridge_update_handler(void *data, struct stasis_subscription *sub, struct stasis_message *message) { RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct stasis_app *app = data; struct stasis_cache_update *update; struct ast_bridge_snapshot *new_snapshot; struct ast_bridge_snapshot *old_snapshot; const struct timeval *tv; ast_assert(stasis_message_type(message) == stasis_cache_update_type()); update = stasis_message_data(message); ast_assert(update->type == ast_bridge_snapshot_type()); new_snapshot = stasis_message_data(update->new_snapshot); old_snapshot = stasis_message_data(update->old_snapshot); tv = update->new_snapshot ? stasis_message_timestamp(update->new_snapshot) : stasis_message_timestamp(message); if (!new_snapshot) { json = simple_bridge_event("BridgeDestroyed", old_snapshot, tv); } else if (!old_snapshot) { json = simple_bridge_event("BridgeCreated", new_snapshot, tv); } else if (new_snapshot && old_snapshot && strcmp(new_snapshot->video_source_id, old_snapshot->video_source_id)) { json = simple_bridge_event("BridgeVideoSourceChanged", new_snapshot, tv); if (json && !ast_strlen_zero(old_snapshot->video_source_id)) { ast_json_object_set(json, "old_video_source_id", ast_json_string_create(old_snapshot->video_source_id)); } } if (json) { app_send(app, json); } if (!new_snapshot && old_snapshot) { unsubscribe(app, "bridge", old_snapshot->uniqueid, 1); } }
/*! \brief Helper function which converts from a sorcery object set to a json object */ static struct ast_json *sorcery_objectset_to_json(const struct ast_variable *objectset) { struct ast_json *json = ast_json_object_create(); const struct ast_variable *field; for (field = objectset; field; field = field->next) { struct ast_json *value = ast_json_string_create(field->value); if (!value) { ast_json_unref(json); return NULL; } else if (ast_json_object_set(json, field->name, value)) { ast_json_unref(json); return NULL; } } return json; }
struct ast_json *ast_json_ipaddr(const struct ast_sockaddr *addr, enum ast_transport transport_type) { struct ast_str *string = ast_str_alloca(64); if (!string) { return NULL; } ast_str_set(&string, 0, (ast_sockaddr_is_ipv4(addr) || ast_sockaddr_is_ipv4_mapped(addr)) ? "IPV4/" : "IPV6/"); if (transport_type) { char *transport_string = NULL; /* NOTE: None will be applied if multiple transport types are specified in transport_type */ switch(transport_type) { case AST_TRANSPORT_UDP: transport_string = "UDP"; break; case AST_TRANSPORT_TCP: transport_string = "TCP"; break; case AST_TRANSPORT_TLS: transport_string = "TLS"; break; case AST_TRANSPORT_WS: transport_string = "WS"; break; case AST_TRANSPORT_WSS: transport_string = "WSS"; break; } if (transport_string) { ast_str_append(&string, 0, "%s/", transport_string); } } ast_str_append(&string, 0, "%s", ast_sockaddr_stringify_addr(addr)); ast_str_append(&string, 0, "/%s", ast_sockaddr_stringify_port(addr)); return ast_json_string_create(ast_str_buffer(string)); }
/*! * \brief Callback handler for Stasis application messages. * * \internal * * \param data Void pointer to the event session (\ref event_session). * \param app_name Name of the Stasis application that dispatched the message. * \param message The dispatched message. */ static void stasis_app_message_handler( void *data, const char *app_name, struct ast_json *message) { struct event_session *session = data; const char *msg_type, *msg_application; ast_assert(session != NULL); ao2_lock(session); msg_type = S_OR(ast_json_string_get(ast_json_object_get(message, "type")), ""); msg_application = S_OR( ast_json_string_get(ast_json_object_get(message, "application")), ""); /* If we've been replaced, remove the application from our local websocket_apps container */ if (strcmp(msg_type, "ApplicationReplaced") == 0 && strcmp(msg_application, app_name) == 0) { ao2_find(session->websocket_apps, msg_application, OBJ_UNLINK | OBJ_NODATA); } /* Now, we need to determine our state to see how we will handle the message */ if (ast_json_object_set(message, "application", ast_json_string_create(app_name))) { /* We failed to add an application element to our json message */ ast_log(LOG_WARNING, "Failed to dispatch '%s' message from Stasis app '%s'; could not update message\n", msg_type, msg_application); } else if (!session->ws_session) { /* If the websocket is NULL, the message goes to the queue */ AST_VECTOR_APPEND(&session->message_queue, message); ast_log(LOG_WARNING, "Queued '%s' message for Stasis app '%s'; websocket is not ready\n", msg_type, msg_application); } else { /* We are ready to publish the message */ ast_ari_websocket_session_write(session->ws_session, message); } ao2_unlock(session); }
/** * Update plan * @param j_plan * @return */ bool update_plan(const struct ast_json* j_plan) { char* tmp; const char* tmp_const; char* sql; struct ast_json* j_tmp; int ret; char* uuid; if(j_plan == NULL) { return false; } j_tmp = ast_json_deep_copy(j_plan); if(j_tmp == NULL) { return false; } tmp_const = ast_json_string_get(ast_json_object_get(j_tmp, "uuid")); if(tmp_const == NULL) { ast_log(LOG_WARNING, "Could not get uuid.\n"); AST_JSON_UNREF(j_tmp); return false; } uuid = ast_strdup(tmp_const); tmp = get_utc_timestamp(); ast_json_object_set(j_tmp, "tm_update", ast_json_string_create(tmp)); ast_free(tmp); tmp = db_get_update_str(j_tmp); if(tmp == NULL) { ast_log(LOG_WARNING, "Could not get update str.\n"); AST_JSON_UNREF(j_tmp); ast_free(uuid); return false; } AST_JSON_UNREF(j_tmp); ast_asprintf(&sql, "update plan set %s where in_use=%d and uuid=\"%s\";", tmp, E_DL_USE_OK, uuid); ast_free(tmp); ret = db_exec(sql); ast_free(sql); if(ret == false) { ast_log(LOG_WARNING, "Could not update plan info. uuid[%s]\n", uuid); ast_free(uuid); return false; } j_tmp = get_plan(uuid); ast_free(uuid); if(j_tmp == NULL) { ast_log(LOG_WARNING, "Could not get updated plan info.\n"); return false; } send_manager_evt_out_plan_update(j_tmp); AST_JSON_UNREF(j_tmp); return true; }