Files
workflow/tutorial/tutorial-03-wget_to_redis.cc

154 lines
3.7 KiB
C++

#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include "workflow/HttpMessage.h"
#include "workflow/HttpUtil.h"
#include "workflow/RedisMessage.h"
#include "workflow/Workflow.h"
#include "workflow/WFTaskFactory.h"
#include "workflow/WFFacilities.h"
using namespace protocol;
#define REDIRECT_MAX 5
#define RETRY_MAX 2
struct tutorial_series_context
{
std::string http_url;
std::string redis_url;
size_t body_len;
bool success;
};
void redis_callback(WFRedisTask *task)
{
int state = task->get_state();
tutorial_series_context *context =
(tutorial_series_context *)series_of(task)->get_context();
RedisValue value;
if (state == WFT_STATE_SUCCESS)
{
task->get_resp()->get_result(value);
if (!value.is_error())
{
fprintf(stderr, "redis SET success: key: %s, value size: %zu\n",
context->http_url.c_str(), context->body_len);
context->success = true;
}
else
fprintf(stderr, "redis error reply! Need password?\n");
}
else
{
fprintf(stderr, "redis SET error: state = %d, error = %d\n",
state, task->get_error());
}
}
void http_callback(WFHttpTask *task)
{
HttpResponse *resp = task->get_resp();
int state = task->get_state();
int error = task->get_error();
if (state != WFT_STATE_SUCCESS)
{
fprintf(stderr, "http task error: state = %d, error = %d\n",
state, error);
return;
}
SeriesWork *series = series_of(task); /* get the series of this task */
tutorial_series_context *context =
(tutorial_series_context *)series->get_context();
const void *body;
size_t body_len;
resp->get_parsed_body(&body, &body_len);
if (body_len == 0)
{
fprintf(stderr, "Error: empty http body!");
return;
}
context->body_len = body_len;
WFRedisTask *redis_task =
WFTaskFactory::create_redis_task(context->redis_url, RETRY_MAX,
redis_callback);
std::string value((char *)body, body_len);
redis_task->get_req()->set_request("SET", { context->http_url, value });
*series << redis_task; /* equal to series->push_back(redis_task) */
}
int main(int argc, char *argv[])
{
WFHttpTask *http_task;
if (argc != 3)
{
fprintf(stderr, "USAGE: %s <http URL> <redis URL>\n", argv[0]);
exit(1);
}
struct tutorial_series_context context;
context.success = false;
context.http_url = argv[1];
if (strncasecmp(argv[1], "http://", 7) != 0)
context.http_url = "http://" + context.http_url;
context.redis_url = argv[2];
if (strncasecmp(argv[2], "redis://", 8) != 0 &&
strncasecmp(argv[2], "rediss://", 9) != 0)
{
context.redis_url = "redis://" + context.redis_url;
}
http_task = WFTaskFactory::create_http_task(context.http_url,
REDIRECT_MAX, RETRY_MAX,
http_callback);
HttpRequest *req = http_task->get_req();
req->add_header_pair("Accept", "*/*");
req->add_header_pair("User-Agent", "Wget/1.14 (linux-gnu)");
req->add_header_pair("Connection", "close");
/* Limit the http response size to 20M. */
http_task->get_resp()->set_size_limit(20 * 1024 * 1024);
/* no more than 30 seconds receiving http response. */
http_task->set_receive_timeout(30 * 1000);
WFFacilities::WaitGroup wait_group(1);
auto series_callback = [&wait_group](const SeriesWork *series)
{
tutorial_series_context *context = (tutorial_series_context *)
series->get_context();
if (context->success)
fprintf(stderr, "Series finished. all success!\n");
else
fprintf(stderr, "Series finished. failed!\n");
/* signal the main() to terminate */
wait_group.done();
};
/* Create a series */
SeriesWork *series = Workflow::create_series_work(http_task,
series_callback);
series->set_context(&context);
series->start();
wait_group.wait();
return 0;
}