Variant f_call_user_func_rpc(int _argc, const String& host, int port, const String& auth, int timeout, CVarRef function, CArrRef _argv /* = null_array */) { string shost = host.data(); if (!RuntimeOption::DebuggerRpcHostDomain.empty()) { unsigned int pos = shost.find(RuntimeOption::DebuggerRpcHostDomain); if (pos != shost.length() - RuntimeOption::DebuggerRpcHostDomain.size()) { shost += RuntimeOption::DebuggerRpcHostDomain; } } string url = "http://"; url += shost; url += ":"; url += lexical_cast<string>(port); url += "/call_user_func_serialized?auth="; url += auth.data(); Array blob = make_map_array(s_func, function, s_args, _argv); String message = f_serialize(blob); vector<string> headers; LibEventHttpClientPtr http = LibEventHttpClient::Get(shost, port); if (!http->send(url, headers, timeout < 0 ? 0 : timeout, false, message.data(), message.size())) { raise_error("Unable to send RPC request"); return false; } int code = http->getCode(); if (code <= 0) { raise_error("Server timed out or unable to find specified URL: %s", url.c_str()); return false; } int len = 0; char *response = http->recv(len); String sresponse(response, len, AttachString); if (code != 200) { raise_error("Internal server error: %d %s", code, HttpProtocol::GetReasonString(code)); return false; } // This double decoding can be avoided by modifying RPC server to directly // take PHP serialization format. Variant res = unserialize_from_string(f_json_decode(sresponse)); if (!res.isArray()) { raise_error("Internal protocol error"); return false; } if (res.toArray().exists(s_exception)) { throw res[s_exception]; } return res[s_ret]; }
Variant f_call_user_func_rpc(int _argc, CStrRef host, int port, CStrRef auth, int timeout, CVarRef function, CArrRef _argv /* = null_array */) { string url = "http://"; url += host.data(); url += ":"; url += lexical_cast<string>(port); url += "/call_user_func_serialized?auth="; url += auth.data(); Array blob = CREATE_MAP2("func", function, "args", _argv); String message = f_serialize(blob); string hostStr(host.data()); vector<string> headers; LibEventHttpClientPtr http = LibEventHttpClient::Get(hostStr, port); if (!http->send(url, headers, timeout < 0 ? 0 : timeout, false, message.data(), message.size())) { raise_warning("Unable to send RPC request"); return false; } int code = http->getCode(); if (code <= 0) { raise_warning("Server timed out or unable to find specified URL: %s", url.c_str()); return false; } int len = 0; char *response = http->recv(len); String sresponse(response, len, AttachString); if (code != 200) { raise_warning("Internal server error: %d %s", code, HttpProtocol::GetReasonString(code)); return false; } // This double decoding can be avoided by modifying RPC server to directly // take PHP serialization format. Variant res = f_unserialize(f_json_decode(sresponse)); if (!res.isArray()) { raise_warning("Internal protocol error"); return false; } if (res.toArray().exists("exception")) { throw res["exception"]; } return res["ret"]; }
bool XboxServer::PostMessage(const String& message, const String& host /* = "localhost" */) { if (isLocalHost(host)) { Lock l(s_dispatchMutex); if (!s_dispatcher) { return false; } XboxTransport *job = new XboxTransport(message.toCppString()); job->incRefCount(); // paired with worker's decRefCount() assert(s_dispatcher); s_dispatcher->enqueue(job); return true; } else { // remote string url = "http://"; url += host.data(); url += "/xbox_post_message"; std::vector<std::string> headers; std::string hostStr(host.data()); LibEventHttpClientPtr http = LibEventHttpClient::Get(hostStr, RuntimeOption::XboxServerPort); if (http->send(url, headers, 0, false, message.data(), message.size())) { int code = http->getCode(); if (code > 0) { int len = 0; char *response = http->recv(len); String sresponse(response, len, AttachString); if (code == 200 && same( unserialize_from_string( sresponse, VariableUnserializer::Type::Internal ), true ) ) { return true; } } } } return false; }
bool XboxServer::SendMessage(const String& message, Array& ret, int timeout_ms, const String& host /* = "localhost" */) { if (isLocalHost(host)) { XboxTransport *job; { Lock l(s_dispatchMutex); if (!s_dispatcher) { return false; } job = new XboxTransport(message); job->incRefCount(); // paired with worker's decRefCount() job->incRefCount(); // paired with decRefCount() at below assert(s_dispatcher); s_dispatcher->enqueue(job); } if (timeout_ms <= 0) { timeout_ms = RuntimeOption::XboxDefaultLocalTimeoutMilliSeconds; } int code = 0; String response = job->getResults(code, timeout_ms); job->decRefCount(); // i'm done with this job if (code > 0) { ret.set(s_code, code); if (code == 200) { ret.set(s_response, unserialize_from_string(response)); } else { ret.set(s_error, response); } return true; } } else { // remote string url = "http://"; url += host.data(); url += '/'; url += RuntimeOption::XboxProcessMessageFunc; int timeoutSeconds = timeout_ms / 1000; if (timeoutSeconds <= 0) { timeoutSeconds = RuntimeOption::XboxDefaultRemoteTimeoutSeconds; } string hostStr(host.data()); std::vector<std::string> headers; LibEventHttpClientPtr http = LibEventHttpClient::Get(hostStr, RuntimeOption::XboxServerPort); if (http->send(url, headers, timeoutSeconds, false, message.data(), message.size())) { int code = http->getCode(); if (code > 0) { int len = 0; char *response = http->recv(len); String sresponse(response, len, AttachString); ret.set(s_code, code); if (code == 200) { ret.set(s_response, unserialize_from_string(sresponse)); } else { ret.set(s_error, sresponse); } return true; } // code wasn't correctly set by http client, treat it as not found ret.set(s_code, 404); ret.set(s_error, "http client failed"); } } return false; }