Example #1
0
static PHP_METHOD(swoole_redis, __call)
{
    zval *params;
    char *command;
    zend_size_t command_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &command, &command_len, &params) == FAILURE)
    {
        return;
    }

    if (Z_TYPE_P(params) != IS_ARRAY)
    {
        swoole_php_fatal_error(E_WARNING, "invalid params.");
        RETURN_FALSE;
    }

    swRedisClient *redis = swoole_get_object(getThis());
    if (!redis)
    {
        swoole_php_fatal_error(E_WARNING, "the object is not an instance of swoole_redis.");
        RETURN_FALSE;
    }

    switch (redis->state)
    {
    case SWOOLE_REDIS_STATE_CONNECT:
        swoole_php_error(E_WARNING, "redis client is not connected.");
        RETURN_FALSE;
        break;
    case SWOOLE_REDIS_STATE_WAIT_RESULT:
        if (swoole_redis_is_message_command(command, command_len))
        {
            swoole_php_error(E_WARNING, "redis client is waiting for response.");
            RETURN_FALSE;
        }
        break;
    case SWOOLE_REDIS_STATE_SUBSCRIBE:
        if (!swoole_redis_is_message_command(command, command_len))
        {
            swoole_php_error(E_WARNING, "redis client is waiting for subscribed messages.");
            RETURN_FALSE;
        }
        break;
    case SWOOLE_REDIS_STATE_CLOSED:
        swoole_php_error(E_WARNING, "redis client connection is closed.");
        RETURN_FALSE;
        break;
    default:
        break;
    }

    int argc = zend_hash_num_elements(Z_ARRVAL_P(params));
    size_t stack_argvlen[SW_REDIS_COMMAND_BUFFER_SIZE];
    char *stack_argv[SW_REDIS_COMMAND_BUFFER_SIZE];

    size_t *argvlen;
    char **argv;
    zend_bool free_mm = 0;

    if (argc > SW_REDIS_COMMAND_BUFFER_SIZE)
    {
        argvlen = emalloc(sizeof(size_t) * argc);
        argv = emalloc(sizeof(char*) * argc);
        free_mm = 1;
    }
    else
    {
        argvlen = stack_argvlen;
        argv = stack_argv;
    }
#define FREE_MEM() do {                 \
    for (i = 1; i < argc; i++)          \
    {                                   \
        efree((void* )argv[i]);         \
    }                                   \
                                        \
    if (redis->state == SWOOLE_REDIS_STATE_SUBSCRIBE) \
    {                                   \
        efree(argv[argc]);              \
    }                                   \
                                        \
    if (free_mm)                        \
    {                                   \
        efree(argvlen);                 \
        efree(argv);                    \
    }                                   \
} while (0)

    assert(command_len < SW_REDIS_COMMAND_KEY_SIZE - 1);

    char command_name[SW_REDIS_COMMAND_KEY_SIZE];
    memcpy(command_name, command, command_len);
    command_name[command_len] = '\0';

    argv[0] = command_name;
    argvlen[0] = command_len;

    zval *value;
    int i = 1;

    /**
     * subscribe command
     */
    if (redis->state == SWOOLE_REDIS_STATE_SUBSCRIBE || (redis->subscribe && swoole_redis_is_message_command(command, command_len)))
    {
        redis->state = SWOOLE_REDIS_STATE_SUBSCRIBE;

        SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value)
            convert_to_string(value);
            argvlen[i] = (size_t) Z_STRLEN_P(value);
            argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
            if (i == argc)
            {
                break;
            }
            i++;
        SW_HASHTABLE_FOREACH_END();

        if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, NULL, argc + 1, (const char **) argv, (const size_t *) argvlen) < 0)
        {
            swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed.");
            FREE_MEM();
            RETURN_FALSE;
        }
    }
    /**
     * storage command
     */
    else
    {
        redis->state = SWOOLE_REDIS_STATE_WAIT_RESULT;
        redis->reqnum++;

#if PHP_MAJOR_VERSION < 7
        zval *callback;
        zval **cb_tmp;
        if (zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1, (void **) &cb_tmp) == FAILURE)
        {
            swoole_php_error(E_WARNING, "index out of array bounds.");
            FREE_MEM();
            RETURN_FALSE;
        }
        callback = *cb_tmp;
#else
        zval *callback = zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1);
        if (callback == NULL)
        {
            swoole_php_error(E_WARNING, "index out of array bounds.");
            FREE_MEM();
            RETURN_FALSE;
        }
#endif

        sw_zval_add_ref(&callback);
        callback = sw_zval_dup(callback);

        SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value)
            if (i == argc)
            {
                break;
            }

            convert_to_string(value);
            argvlen[i] = (size_t) Z_STRLEN_P(value);
            argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
            i++;
        SW_HASHTABLE_FOREACH_END();

        if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, callback, argc, (const char **) argv, (const size_t *) argvlen) < 0)
        {
            swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed.");
            FREE_MEM();
            RETURN_FALSE;
        }
    }

    FREE_MEM();
    RETURN_TRUE;
}
Example #2
0
static PHP_METHOD(swoole_redis, __call)
{
    zval *params;
    char *command;
    zend_size_t command_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &command, &command_len, &params) == FAILURE)
    {
        return;
    }

    swRedisClient *redis = swoole_get_object(getThis());
    switch (redis->state)
    {
    case SWOOLE_REDIS_STATE_CONNECT:
        swoole_php_error(E_WARNING, "redis client is not connected.");
        RETURN_FALSE;
        break;
    case SWOOLE_REDIS_STATE_WAIT:
        swoole_php_error(E_WARNING, "redis client is waiting for response.");
        RETURN_FALSE;
        break;
    case SWOOLE_REDIS_STATE_CLOSED:
        swoole_php_error(E_WARNING, "redis client connection is closed.");
        RETURN_FALSE;
        break;
    default:
        break;
    }

#if PHP_MAJOR_VERSION < 7
    zval *callback;
    zval **cb_tmp;
    if (zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1, (void **) &cb_tmp) == FAILURE)
    {
        swoole_php_error(E_WARNING, "index out of array.");
        RETURN_FALSE;
    }
    callback = *cb_tmp;
    redis->result_callback = callback;
#else
    zval *callback = zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1);
    if (callback == NULL)
    {
        swoole_php_error(E_WARNING, "index out of array.");
        RETURN_FALSE;
    }
    redis->result_callback = &redis->_result_callback;
    memcpy(redis->result_callback, callback, sizeof(zval));
#endif

    sw_zval_add_ref(&redis->result_callback);

    redis->state = SWOOLE_REDIS_STATE_WAIT;

    int argc = zend_hash_num_elements(Z_ARRVAL_P(params));

    size_t stack_argvlen[SW_REDIS_COMMAND_BUFFER_SIZE];
    char *stack_argv[SW_REDIS_COMMAND_BUFFER_SIZE];

    size_t *argvlen;
    char **argv;
    zend_bool free_mm = 0;

    if (argc > SW_REDIS_COMMAND_BUFFER_SIZE)
    {
        argvlen = emalloc(sizeof(size_t) * argc);
        argv = emalloc(sizeof(char*) * argc);
        free_mm = 1;
    }
    else
    {
        argvlen = stack_argvlen;
        argv = stack_argv;
    }

    assert(command_len < SW_REDIS_COMMAND_KEY_SIZE - 1);

    char command_name[SW_REDIS_COMMAND_KEY_SIZE];
    memcpy(command_name, command, command_len);
    command_name[command_len] = '\0';

    argv[0] = command_name;
    argvlen[0] = command_len;

    zval *value;
    int i = 1;

    SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value)
        convert_to_string(value);
        argvlen[i] = (size_t) Z_STRLEN_P(value);
        argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
        if (i == argc - 1)
        {
            break;
        }
        i++;
    SW_HASHTABLE_FOREACH_END();

    if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, NULL, argc, (const char **) argv, (const size_t *) argvlen) < 0)
    {
        swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed.");
        RETURN_FALSE;
    }

    for (i = 1; i < argc; i++)
    {
        efree((void* )argv[i]);
    }

    if (free_mm)
    {
        efree(argvlen);
        efree(argv);
    }

    redis->state = SWOOLE_REDIS_STATE_WAIT;
    RETURN_TRUE;
}