int connection::redis_raw_cmd(redisCallbackFn* fn, void* priv_data, const sds* src) {
     if (NULL == context) {
         return error_code::REDIS_HAPP_CREATE;
     }
     
     return redisAsyncFormattedCommand(context, fn, priv_data, *src, sdslen(*src));           
 }
Beispiel #2
0
gboolean
rspamd_redis_process_tokens (struct rspamd_task *task,
		GPtrArray *tokens,
		gint id, gpointer p)
{
	struct redis_stat_runtime *rt = REDIS_RUNTIME (p);
	rspamd_fstring_t *query;
	struct timeval tv;
	gint ret;

	if (tokens == NULL || tokens->len == 0 || rt->redis == NULL) {
		return FALSE;
	}

	rt->id = id;

	if (redisAsyncCommand (rt->redis, rspamd_redis_connected, rt, "HGET %s %s",
			rt->redis_object_expanded, "learns") == REDIS_OK) {

		rspamd_session_add_event (task->s, rspamd_redis_fin, rt,
				rspamd_redis_stat_quark ());
		rt->has_event = TRUE;

		if (event_get_base (&rt->timeout_event)) {
			event_del (&rt->timeout_event);
		}
		event_set (&rt->timeout_event, -1, EV_TIMEOUT, rspamd_redis_timeout, rt);
		event_base_set (task->ev_base, &rt->timeout_event);
		double_to_tv (rt->ctx->timeout, &tv);
		event_add (&rt->timeout_event, &tv);

		query = rspamd_redis_tokens_to_query (task, tokens,
				"HMGET", rt->redis_object_expanded, FALSE, -1,
				rt->stcf->clcf->flags & RSPAMD_FLAG_CLASSIFIER_INTEGER);
		g_assert (query != NULL);
		rspamd_mempool_add_destructor (task->task_pool,
				(rspamd_mempool_destruct_t)rspamd_fstring_free, query);

		ret = redisAsyncFormattedCommand (rt->redis, rspamd_redis_processed, rt,
				query->str, query->len);

		if (ret == REDIS_OK) {
			return TRUE;
		}
		else {
			msg_err_task ("call to redis failed: %s", rt->redis->errstr);
		}
	}

	return FALSE;
}
        int connection::redis_cmd(cmd_exec* c, redisCallbackFn fn) {
            if (NULL == c) {
                return error_code::REDIS_HAPP_PARAM;
            }

            if (NULL == context) {
                return error_code::REDIS_HAPP_CREATE;
            }

            switch (conn_status) {
            case status::DISCONNECTED: { // 未连接则直接失败
                return error_code::REDIS_HAPP_CONNECTION;
            }

            // 正在连接也直接发送,hiredis底层会缓存队列
            // 不发送会导致连接回调不被触发
            case status::CONNECTING:
            case status::CONNECTED: {
                int res = 0;
                const char* cstr = NULL;
                size_t clen = 0;
                if (0 == c->cmd.raw_len) {
                    res = redisAsyncFormattedCommand(context, fn, c, c->cmd.content.redis_sds, sdslen(c->cmd.content.redis_sds));
                } else {
                    res = redisAsyncFormattedCommand(context, fn, c, c->cmd.content.raw, c->cmd.raw_len);
                }

                if (REDIS_OK == res) {
                    c->pick_cmd(&cstr, &clen);
                    if (NULL == cstr) {
                        reply_list.push_back(c);
                    } else {
                        bool is_pattern = tolower(cstr[0]) == 'p';
                        if (is_pattern) {
                            ++ cstr;
                        }
                        
                        // according to the hiredis code, we can not use both monitor and subscribe in the same connection
                        // @note hiredis use a tricky way to check if a reply is subscribe message or request-response message, 
                        //       so it 's  recommanded not to use both subscribe message and request-response message at a connection.
                        if (0 == HIREDIS_HAPP_STRNCASE_CMP(cstr, "subscribe\r\n", 11)) {
                            // subscribe message has not reply
                            cmd_exec::destroy(c);
                        } else if (0 == HIREDIS_HAPP_STRNCASE_CMP(cstr, "unsubscribe\r\n", 13)) {
                            // unsubscribe message has not reply
                            cmd_exec::destroy(c);
                        } else if (0 == HIREDIS_HAPP_STRNCASE_CMP(cstr, "monitor\r\n", 9)) {
                            // monitor message has not reply
                            cmd_exec::destroy(c);
                        } else {
                            // request-response message
                            reply_list.push_back(c);
                        }
                    }
                }

                return res;
            }
            default: {
                assert(0);
                break;
            }
            }

            // 未知异常,回收cmd
            c->call_reply(error_code::REDIS_HAPP_UNKNOWD, context, NULL);
            cmd_exec::destroy(c);

            return error_code::REDIS_HAPP_OK;
        }
Beispiel #4
0
gboolean
rspamd_redis_learn_tokens (struct rspamd_task *task, GPtrArray *tokens,
		gint id, gpointer p)
{
	struct redis_stat_runtime *rt = REDIS_RUNTIME (p);
	struct upstream *up;
	rspamd_inet_addr_t *addr;
	struct timeval tv;
	rspamd_fstring_t *query;
	const gchar *redis_cmd;
	rspamd_token_t *tok;
	gint ret;

	up = rspamd_upstream_get (rt->ctx->write_servers,
			RSPAMD_UPSTREAM_MASTER_SLAVE,
			NULL,
			0);

	if (up == NULL) {
		msg_err_task ("no upstreams reachable");
		return FALSE;
	}

	rt->selected = up;

	addr = rspamd_upstream_addr (up);
	g_assert (addr != NULL);
	rt->redis = redisAsyncConnect (rspamd_inet_address_to_string (addr),
			rspamd_inet_address_get_port (addr));
	g_assert (rt->redis != NULL);

	redisLibeventAttach (rt->redis, task->ev_base);
	rspamd_redis_maybe_auth (rt->ctx, rt->redis);

	/*
	 * Add the current key to the set of learned keys
	 */
	redisAsyncCommand (rt->redis, NULL, NULL, "SADD %s_keys %s",
			rt->stcf->symbol, rt->redis_object_expanded);

	if (rt->stcf->clcf->flags & RSPAMD_FLAG_CLASSIFIER_INTEGER) {
		redis_cmd = "HINCRBY";
	}
	else {
		redis_cmd = "HINCRBYFLOAT";
	}

	rt->id = id;
	query = rspamd_redis_tokens_to_query (task, tokens,
			redis_cmd, rt->redis_object_expanded, TRUE, id,
			rt->stcf->clcf->flags & RSPAMD_FLAG_CLASSIFIER_INTEGER);
	g_assert (query != NULL);

	/*
	 * XXX:
	 * Dirty hack: we get a token and check if it's value is -1 or 1, so
	 * we could understand that we are learning or unlearning
	 */

	tok = g_ptr_array_index (task->tokens, 0);

	if (tok->values[id] > 0) {
		rspamd_printf_fstring (&query, ""
				"*4\r\n"
				"$7\r\n"
				"HINCRBY\r\n"
				"$%d\r\n"
				"%s\r\n"
				"$6\r\n"
				"learns\r\n"
				"$1\r\n"
				"1\r\n",
				(gint)strlen (rt->redis_object_expanded),
				rt->redis_object_expanded);
	}
	else {
		rspamd_printf_fstring (&query, ""
				"*4\r\n"
				"$7\r\n"
				"HINCRBY\r\n"
				"$%d\r\n"
				"%s\r\n"
				"$6\r\n"
				"learns\r\n"
				"$2\r\n"
				"-1\r\n",
				(gint)strlen (rt->redis_object_expanded),
				rt->redis_object_expanded);
	}

	rspamd_mempool_add_destructor (task->task_pool,
				(rspamd_mempool_destruct_t)rspamd_fstring_free, query);

	ret = redisAsyncFormattedCommand (rt->redis, rspamd_redis_learned, rt,
			query->str, query->len);

	if (ret == REDIS_OK) {
		rspamd_session_add_event (task->s, rspamd_redis_fin_learn, rt,
				rspamd_redis_stat_quark ());
		rt->has_event = TRUE;

		/* Set timeout */
		if (event_get_base (&rt->timeout_event)) {
			event_del (&rt->timeout_event);
		}
		event_set (&rt->timeout_event, -1, EV_TIMEOUT, rspamd_redis_timeout, rt);
		event_base_set (task->ev_base, &rt->timeout_event);
		double_to_tv (rt->ctx->timeout, &tv);
		event_add (&rt->timeout_event, &tv);

		return TRUE;
	}
	else {
		msg_err_task ("call to redis failed: %s", rt->redis->errstr);
	}

	return FALSE;
}