#include #include #include #include #include #include "workflow/WFGlobal.h" #include "workflow/WFNameService.h" #include "workflow/WFTaskFactory.h" #include "workflow/WFFacilities.h" #include "workflow/HttpUtil.h" // The example domonstrate the simplest user defined naming policy. /* 'MyNSPolicy' is a naming policy, which use local file for naming. * The format of naming file is similar to 'hosts' file, but we allow * domain name and IP address as destination. For example: * * 127.0.0.1 localhost * 127.0.0.1 mydomain # another alias for 127.0.0.1 * www.sogou.com sogou # sogou -> www.sogou.com */ class MyNSPolicy : public WFNSPolicy { public: WFRouterTask *create_router_task(const struct WFNSParams *params, router_callback_t callback) override; private: std::string path; private: std::string read_from_fp(FILE *fp, const char *name); std::string parse_line(char *p, const char *name); public: MyNSPolicy(const char *naming_file) : path(naming_file) { } }; std::string MyNSPolicy::parse_line(char *p, const char *name) { const char *dest = NULL; char *start; start = p; while (*start != '\0' && *start != '#') start++; *start = '\0'; while (1) { while (isspace(*p)) p++; start = p; while (*p != '\0' && !isspace(*p)) p++; if (start == p) break; if (*p != '\0') *p++ = '\0'; if (dest == NULL) { dest = start; continue; } if (strcasecmp(name, start) == 0) return std::string(dest); } return std::string(); } std::string MyNSPolicy::read_from_fp(FILE *fp, const char *name) { char *line = NULL; size_t bufsize = 0; std::string result; while (getline(&line, &bufsize, fp) > 0) { result = this->parse_line(line, name); if (result.size() > 0) break; } free(line); return result; } WFRouterTask *MyNSPolicy::create_router_task(const struct WFNSParams *params, router_callback_t callback) { WFDnsResolver *dns_resolver = WFGlobal::get_dns_resolver(); if (params->uri.host) { FILE *fp = fopen(this->path.c_str(), "r"); if (fp) { std::string dest = this->read_from_fp(fp, params->uri.host); if (dest.size() > 0) { /* Update the uri structure's 'host' field directly. * You can also update the 'port' field if needed. */ free(params->uri.host); params->uri.host = strdup(dest.c_str()); } fclose(fp); } } /* Simply, use the global dns resolver to create a router task. */ return dns_resolver->create_router_task(params, std::move(callback)); } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "USAGE: %s \n", argv[0]); exit(1); } ParsedURI uri; URIParser::parse(argv[1], uri); char *name = uri.host; if (name == NULL) { fprintf(stderr, "Invalid http URI\n"); exit(1); } /* Create an naming policy. */ MyNSPolicy *policy = new MyNSPolicy(argv[2]); /* Get the global name service object.*/ WFNameService *ns = WFGlobal::get_name_service(); /* Add the our name with policy to global name service. * You can add mutilply names with one policy object. */ ns->add_policy(name, policy); WFFacilities::WaitGroup wg(1); WFHttpTask *task = WFTaskFactory::create_http_task(argv[1], 2, 3, [&wg](WFHttpTask *task) { int state = task->get_state(); int error = task->get_error(); if (state != WFT_STATE_SUCCESS) { fprintf(stderr, "error: %s\n", WFGlobal::get_error_string(state, error)); } else { auto *r = task->get_resp(); std::string body = protocol::HttpUtil::decode_chunked_body(r); fwrite(body.c_str(), 1, body.size(), stdout); } wg.done(); }); task->start(); wg.wait(); /* clean up */ ns->del_policy(name); delete policy; return 0; }