Exemplo n.º 1
0
Arquivo: buf.c Projeto: ra1fh/nxtctl
int buf_vpack(Buf *self, char *fmt, va_list ap) {
	char *s;
	char *p;
	uint8_t u8;
	uint16_t u16;
	uint32_t u32;
	size_t len;
	int res;
	int bytes = 0;

	for (p = fmt; *p != '\0'; p++) {
		switch(*p) {
		case 'b': /* char */
			u8 = va_arg(ap, int);
			res = buf_write_byte(self, u8);
			break;
		case 'h': /* short */
			u16 = va_arg(ap, int);
			res = buf_write_short(self, u16);
			break;
		case 'u': /* uint */
			u32 = va_arg(ap, uint32_t);
			res = buf_write_uint(self, u32);
			break;
		case 's': /* string */
			s = va_arg(ap, char*);
			len = va_arg(ap, size_t);
			res = buf_write_string(self, s, len);
			break;
		case 'd': /* data */
			s = va_arg(ap, char*);
			len = va_arg(ap, size_t);
			res = buf_write_data(self, s, len);
			break;
		default: /* illegal format */
			res = -1;
		}
		if (res == -1) {
			return -1;
		}
		bytes += res;
	}
	return bytes;
}
/*
 * Program entry point.
 */
int
main(int argc, char** argv)
{
        /*
         * Standard command-line parsing.
         */
        const HASH_T *options = parse_cmdline(argc, argv, arg_opts);
        if(options == NULL || hash_get(options, "help") != NULL) {
                show_usage(argc, argv, arg_opts);
                return EXIT_FAILURE;
        }

        const char *url = hash_get(options, "url");
        const char *principal = hash_get(options, "principal");
        CREDENTIALS_T *credentials = NULL;
        const char *password = hash_get(options, "credentials");
        if(password != NULL) {
                credentials = credentials_create_password(password);
        }
        const char *topic_name = hash_get(options, "topic");
        const long seconds = atol(hash_get(options, "seconds"));

        /*
         * Setup for condition variable.
         */
        apr_initialize();
        apr_pool_create(&pool, NULL);
        apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_UNNESTED, pool);
        apr_thread_cond_create(&cond, pool);

        /*
         * Create a session with the Diffusion server.
         */
        SESSION_T *session;
        DIFFUSION_ERROR_T error = { 0 };
        session = session_create(url, principal, credentials, NULL, NULL, &error);
        if(session == NULL) {
                fprintf(stderr, "TEST: Failed to create session\n");
                fprintf(stderr, "ERR : %s\n", error.message);
                return EXIT_FAILURE;
        }

        /*
         * Create a topic holding simple string content.
         */
        TOPIC_DETAILS_T *string_topic_details = create_topic_details_single_value(M_DATA_TYPE_STRING);
        const ADD_TOPIC_PARAMS_T add_topic_params = {
                .topic_path = topic_name,
                .details = string_topic_details,
                .on_topic_added = on_topic_added,
                .on_topic_add_failed = on_topic_add_failed,
                .on_discard = on_topic_add_discard,
        };

        apr_thread_mutex_lock(mutex);
        add_topic(session, add_topic_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        topic_details_free(string_topic_details);

        /*
         * Define the handlers for add_update_source()
         */
        const UPDATE_SOURCE_REGISTRATION_PARAMS_T update_reg_params = {
                .topic_path = topic_name,
                .on_init = on_update_source_init,
                .on_registered = on_update_source_registered,
                .on_active = on_update_source_active,
                .on_standby = on_update_source_standby,
                .on_close = on_update_source_closed
        };

        /*
         * Register an updater.
         */
        apr_thread_mutex_lock(mutex);
        CONVERSATION_ID_T *updater_id = register_update_source(session, update_reg_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Define default parameters for an update source.
         */
        UPDATE_SOURCE_PARAMS_T update_source_params_base = {
                .updater_id = updater_id,
                .topic_path = topic_name,
                .on_success = on_update_success,
                .on_failure = on_update_failure
        };

        time_t end_time = time(NULL) + seconds;

        while(time(NULL) < end_time) {

                if(active) {
                        /*
                         * Create an update structure containing the current time.
                         */
                        BUF_T *buf = buf_create();
                        const time_t time_now = time(NULL);
                        buf_write_string(buf, ctime(&time_now));

                        CONTENT_T *content = content_create(CONTENT_ENCODING_NONE, buf);

                        UPDATE_T *upd = update_create(UPDATE_ACTION_REFRESH,
                                                      UPDATE_TYPE_CONTENT,
                                                      content);

                        UPDATE_SOURCE_PARAMS_T update_source_params = update_source_params_base;
                        update_source_params.update = upd;

                        /*
                         * Update the topic.
                         */
                        update(session, update_source_params);

                        content_free(content);
                        update_free(upd);
                        buf_free(buf);
                }

                sleep(1);
        }

        if(active) {
                UPDATE_SOURCE_DEREGISTRATION_PARAMS_T update_dereg_params = {
                        .updater_id = updater_id,
                        .on_deregistered = on_update_source_deregistered
                };

                apr_thread_mutex_lock(mutex);
                deregister_update_source(session, update_dereg_params);
                apr_thread_cond_wait(cond, mutex);
                apr_thread_mutex_unlock(mutex);
        }

        /*
         * Close session and free resources.
         */
        session_close(session, NULL);
        session_free(session);

        conversation_id_free(updater_id);
        credentials_free(credentials);

        apr_thread_mutex_destroy(mutex);
        apr_thread_cond_destroy(cond);
        apr_pool_destroy(pool);
        apr_terminate();

        return EXIT_SUCCESS;

}
int main(int argc, char** argv)
{
        /*
         * Standard command-line parsing.
         */
        HASH_T *options = parse_cmdline(argc, argv, arg_opts);
        if(options == NULL || hash_get(options, "help") != NULL) {
                show_usage(argc, argv, arg_opts);
                return EXIT_FAILURE;
        }

        char *url = hash_get(options, "url");
        const char *principal = hash_get(options, "principal");
        CREDENTIALS_T *credentials = NULL;
        const char *password = hash_get(options, "credentials");
        if(password != NULL) {
                credentials = credentials_create_password(password);
        }

        // Setup for condition variable
        apr_initialize();
        apr_pool_create(&pool, NULL);
        apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_UNNESTED, pool);
        apr_thread_cond_create(&cond, pool);

        // Setup for session
        SESSION_T *session;
        DIFFUSION_ERROR_T error = { 0 };
        session = session_create(url, principal, credentials, NULL, NULL, &error);
        if(session == NULL) {
                fprintf(stderr, "TEST: Failed to create session\n");
                fprintf(stderr, "ERR : %s\n", error.message);
                return EXIT_FAILURE;
        }

        // Common params for all add_topic() functions.
        ADD_TOPIC_PARAMS_T common_params = {
                .on_topic_added = on_topic_added,
                .on_topic_add_failed = on_topic_add_failed,
                .on_discard = on_topic_add_discard
        };

        /*
         * Create a stateless topic.
         */
        TOPIC_DETAILS_T *topic_details = create_topic_details_stateless();
        ADD_TOPIC_PARAMS_T stateless_params = common_params;
        stateless_params.topic_path = "stateless";
        stateless_params.details = topic_details;

        apr_thread_mutex_lock(mutex);
        add_topic(session, stateless_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Create a topic with single value string data, but with
         * containing no default data.
         */
        TOPIC_DETAILS_T *string_topic_details = create_topic_details_single_value(M_DATA_TYPE_STRING);
        ADD_TOPIC_PARAMS_T string_params = common_params;
        string_params.topic_path = "string";
        string_params.details = string_topic_details;

        apr_thread_mutex_lock(mutex);
        add_topic(session, string_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Create a topic with single value string data and containing
         * some default data.
         */
        ADD_TOPIC_PARAMS_T string_data_params = common_params;
        string_data_params.topic_path = "string-data";
        string_data_params.details = string_topic_details;
        BUF_T *sample_data_buf = buf_create();
        buf_write_string(sample_data_buf, "Hello, world");
        string_data_params.content = content_create(CONTENT_ENCODING_NONE, sample_data_buf);

        apr_thread_mutex_lock(mutex);
        add_topic(session, string_data_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Create a topic with single value integer data, and with a
         * default value.
         */
        TOPIC_DETAILS_T *integer_topic_details = create_topic_details_single_value(M_DATA_TYPE_INTEGER_STRING);
        integer_topic_details->topic_details_params.integer.default_value = 999;

        ADD_TOPIC_PARAMS_T integer_params = common_params;
        integer_params.topic_path = "integer";
        integer_params.details = integer_topic_details;

        apr_thread_mutex_lock(mutex);
        add_topic(session, integer_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Create a topic with integer data, but using a CONTENT_T to
         * specify the initial data.
         */
        ADD_TOPIC_PARAMS_T integer_data_params = common_params;
        integer_data_params.topic_path = "integer-data";
        integer_data_params.details = integer_topic_details;
        BUF_T *integer_data_buf = buf_create();
        buf_sprintf(integer_data_buf, "%d", 123);
        integer_data_params.content = content_create(CONTENT_ENCODING_NONE, integer_data_buf);

        apr_thread_mutex_lock(mutex);
        add_topic(session, integer_data_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Create a topic with single value decimal data, with a
         * default value and specifying the scale (i.e. positions
         * after the decimal place).
         */
        TOPIC_DETAILS_T *decimal_topic_details = create_topic_details_single_value(M_DATA_TYPE_DECIMAL_STRING);
        decimal_topic_details->topic_details_params.decimal.default_value = 123.456;
        decimal_topic_details->topic_details_params.decimal.scale = 4;

        ADD_TOPIC_PARAMS_T decimal_params = common_params;
        decimal_params.topic_path = "decimal";
        decimal_params.details = decimal_topic_details;

        apr_thread_mutex_lock(mutex);
        add_topic(session, decimal_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Create a topic with decimal data, using a CONTENT_T to
         * specify the initial data.
         */
        ADD_TOPIC_PARAMS_T decimal_data_params = common_params;
        decimal_data_params.topic_path = "decimal-data";
        decimal_data_params.details = decimal_topic_details;
        BUF_T *decimal_data_buf = buf_create();
        buf_sprintf(decimal_data_buf, "%f", 987.654);
        decimal_data_params.content = content_create(CONTENT_ENCODING_NONE, decimal_data_buf);

        apr_thread_mutex_lock(mutex);
        add_topic(session, decimal_data_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Record topic data.
         *
         * The C API does not have the concept of "builders" for
         * creating record topic data, but requires you to build a
         * string containing XML that describes the structure of the
         * messages.
         */

        /*
         * First of all, this adds a topic equivalent to single-value
         * strings, but defined with XML.
         */
        BUF_T *manual_schema = buf_create();
        buf_write_string(manual_schema,
                "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
        buf_write_string(manual_schema,
                "<field name=\"x\" type=\"string\" default=\"xyzzy\" allowsEmpty=\"true\"/>");
        TOPIC_DETAILS_T *manual_topic_details = create_topic_details_single_value(M_DATA_TYPE_STRING);
        manual_topic_details->user_defined_schema = manual_schema;

        ADD_TOPIC_PARAMS_T string_manual_params = common_params;
        string_manual_params.topic_path = "string-manual";
        string_manual_params.details = manual_topic_details;

        apr_thread_mutex_lock(mutex);
        add_topic(session, string_manual_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * This adds a topic with a record containing multiple fields
         * of different types.
         */
        BUF_T *record_schema = buf_create();
        buf_write_string(record_schema,
                "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
        buf_write_string(record_schema,
                "<message topicDataType=\"record\" name=\"MyContent\">");
        buf_write_string(record_schema,
                "<record name=\"Record1\">");
        buf_write_string(record_schema,
                "<field type=\"string\" default=\"\" allowsEmpty=\"true\" name=\"Field1\"/>");
        buf_write_string(record_schema,
                "<field type=\"integerString\" default=\"0\" allowsEmpty=\"false\" name=\"Field2\"/>");
        buf_write_string(record_schema,
                "<field type=\"decimalString\" default=\"0.00\" scale=\"2\" allowsEmpty=\"false\" name=\"Field3\"/>");
        buf_write_string(record_schema,
                "</record>");
        buf_write_string(record_schema,
                "</message>");
        TOPIC_DETAILS_T *record_topic_details = create_topic_details_record();
        record_topic_details->user_defined_schema = record_schema;

        ADD_TOPIC_PARAMS_T record_params = common_params;
        record_params.topic_path = "record";
        record_params.details = record_topic_details;

        apr_thread_mutex_lock(mutex);
        add_topic(session, record_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * We can also remove topics. First, add a couple of topics
         * and then remove their parent topic. All child topics are
         * removed with the parent.
         */
        puts("Adding topics remove_me/1 and remove_me/2");

        ADD_TOPIC_PARAMS_T topic_params = common_params;
        topic_params.details = topic_details;
        topic_params.topic_path = "remove_me/1";

        apr_thread_mutex_lock(mutex);
        add_topic(session, topic_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        topic_params.topic_path = "remove_me/2";
        apr_thread_mutex_lock(mutex);
        add_topic(session, topic_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        puts("Removing topics in 5 seconds...");
        sleep(5);

        REMOVE_TOPICS_PARAMS_T remove_params = {
                .on_removed = on_topic_removed,
                .on_discard = on_topic_remove_discard,
                .topic_selector = ">remove_me"
        };

        apr_thread_mutex_lock(mutex);
        remove_topics(session, remove_params);
        apr_thread_cond_wait(cond, mutex);
        apr_thread_mutex_unlock(mutex);

        /*
         * Close our session, and release resources and memory.
         */
        session_close(session, NULL);
        session_free(session);

        apr_thread_mutex_destroy(mutex);
        apr_thread_cond_destroy(cond);
        apr_pool_destroy(pool);
        apr_terminate();

        return EXIT_SUCCESS;
}