Created
September 9, 2012 20:38
-
-
Save michael-grunder/3687125 to your computer and use it in GitHub Desktop.
Different way of detecting callback
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PHPAPI void generic_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, char *sub_cmd) | |
zval *object, *array, **data; | |
HashTable *arr_hash; | |
HashPosition pointer; | |
RedisSock *redis_sock; | |
char *cmd = "", *old_cmd = NULL; | |
int cmd_len, array_count; | |
zval *z_tab, **tmp; | |
char *type_response; | |
// Function call information | |
zend_fcall_info z_callback; | |
zend_fcall_info_cache z_callback_cache; | |
zval *z_ret, **z_args[4]; | |
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oaf", | |
&object, redis_ce, &array, &z_callback, &z_callback_cache) == FAILURE) { | |
RETURN_FALSE; | |
} | |
if (redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) { | |
RETURN_FALSE; | |
} | |
arr_hash = Z_ARRVAL_P(array); | |
array_count = zend_hash_num_elements(arr_hash); | |
if (array_count == 0) { | |
RETURN_FALSE; | |
} | |
for (zend_hash_internal_pointer_reset_ex(arr_hash, &pointer); | |
zend_hash_get_current_data_ex(arr_hash, (void**) &data, | |
&pointer) == SUCCESS; | |
zend_hash_move_forward_ex(arr_hash, &pointer)) { | |
if (Z_TYPE_PP(data) == IS_STRING) { | |
char *old_cmd = NULL; | |
if(*cmd) { | |
old_cmd = cmd; | |
} | |
cmd_len = spprintf(&cmd, 0, "%s %s", cmd, Z_STRVAL_PP(data)); | |
if(old_cmd) { | |
efree(old_cmd); | |
} | |
} | |
} | |
old_cmd = cmd; | |
cmd_len = spprintf(&cmd, 0, "%s %s\r\n", sub_cmd, cmd); | |
efree(old_cmd); | |
if (redis_sock_write(redis_sock, cmd, cmd_len TSRMLS_CC) < 0) { | |
efree(cmd); | |
RETURN_FALSE; | |
} | |
efree(cmd); | |
/* read the status of the execution of the command `subscribe` */ | |
z_tab = redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock); | |
if(z_tab == NULL) { | |
RETURN_FALSE; | |
} | |
if (zend_hash_index_find(Z_ARRVAL_P(z_tab), 0, (void**)&tmp) == SUCCESS) { | |
type_response = Z_STRVAL_PP(tmp); | |
if(strcmp(type_response, sub_cmd) != 0) { | |
efree(tmp); | |
efree(z_tab); | |
RETURN_FALSE; | |
} | |
} else { | |
efree(z_tab); | |
RETURN_FALSE; | |
} | |
efree(z_tab); | |
// Set a pointer to our return value and to our arguments. | |
z_callback.retval_ptr_ptr = &z_ret; | |
z_callback.params = z_args; | |
z_callback.no_separation = 0; | |
/* Multibulk Response, format : {message type, originating channel, message payload} */ | |
while(1) { | |
/* call the callback with this z_tab in argument */ | |
zval **type, **channel, **pattern, **data; | |
z_tab = redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock); | |
int is_pmsg, tab_idx = 1; | |
if(z_tab == NULL || Z_TYPE_P(z_tab) != IS_ARRAY) { | |
//ERROR | |
break; | |
} | |
if (zend_hash_index_find(Z_ARRVAL_P(z_tab), 0, (void**)&type) == FAILURE || Z_TYPE_PP(type) != IS_STRING) { | |
break; | |
} | |
// Make sure we have a message or pmessage | |
if(!strncmp(Z_STRVAL_PP(type), "message", 7) || !strncmp(Z_STRVAL_PP(type), "pmessage", 8)) { | |
// Is this a pmessage | |
is_pmsg = *Z_STRVAL_PP(type) == 'p'; | |
} else { | |
continue; // It's not a message or pmessage | |
} | |
// If this is a pmessage, we'll want to extract the pattern first | |
if(is_pmsg) { | |
// Extract pattern | |
if(zend_hash_index_find(Z_ARRVAL_P(z_tab), tab_idx++, (void**)&pattern) == FAILURE) { | |
break; | |
} | |
} | |
// Extract channel and data | |
if (zend_hash_index_find(Z_ARRVAL_P(z_tab), tab_idx++, (void**)&channel) == FAILURE) { | |
break; | |
} | |
if (zend_hash_index_find(Z_ARRVAL_P(z_tab), tab_idx++, (void**)&data) == FAILURE) { | |
break; | |
} | |
// Always pass the Redis object through | |
z_args[0] = &getThis(); | |
// Set up our callback args depending on the message type | |
if(is_pmsg) { | |
z_args[1] = pattern; | |
z_args[2] = channel; | |
z_args[3] = data; | |
} else { | |
z_args[1] = channel; | |
z_args[2] = data; | |
} | |
// Set our argument information | |
z_callback.param_count = tab_idx; | |
// Break if we can't call the function | |
if(zend_call_function(&z_callback, &z_callback_cache TSRMLS_CC) != SUCCESS) { | |
break; | |
} | |
// If we have a return value, free it. Note, we could use the return value to break the subscribe loop | |
if(z_ret) zval_ptr_dtor(&z_ret); | |
/* TODO: provide a way to break out of the loop. */ | |
zval_dtor(z_tab); | |
efree(z_tab); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment