/** * Call the remote API server * * @param \V1\APICall $apicall_obj The APICall object we're using to make calls * @return array The array of data ready for display (Response array or error array) */ public function make_the_call(\V1\APICall $apicall_obj) { /** * RUNCLE RICK'S RAD RUN CALL :) */ $api = \V1\Model\APIs::get_api(); $account = \V1\Model\Account::get_account(); /* * When we make a call from the local server, we'll get the localhost IP. If that's the case, * we'll set our public IP. DO NOT use X-Forwarded-For in the request headers to us. It's unreliable. * We'll still set our X-Forwarded-For in case the API provider wishes to use it. */ $forwarded_for = \Input::real_ip('0.0.0.0', true); if ($internal_call = \Utility::is_internal_call()) { $forwarded_for = \Config::get('engine.call_test_ip'); } /* * Add our own headers to allow for authenticating our server and customers. We overwrite any * of these headers that were specified by the API Provider through RAML, or by the developer * through thier configuration. */ $headers = static::get_headers($apicall_obj->get_headers()); $call = array('url' => $apicall_obj->get_url(), 'method' => $apicall_obj->get_method(), 'headers' => $headers, 'body' => $apicall_obj->get_method_params(), 'body-type' => $apicall_obj->get_body_type()); if (\Fuel::$env !== 'production' && \Config::get('engine.dev_disable_live_calls', false) === true) { /** * In dev mode we can disable calls to the remote server. Feel free to change the * dummy response to whatever you'd like to. */ $response = array('status' => 200, 'headers' => array('X-Dev-Mode' => 'Dummy header'), 'body' => array('dummy_key' => 'dummy_val')); return \Utility::format_response(200, $response); } else { /* * We'll see if anyone got a cached entry into our system while we were configuring stuff. * That way we'll save time. */ if (\V1\APIRequest::is_static() && is_array($cached_data = \V1\Call\StaticCall::get_call_cache())) { // Return the response-formatted data from the cached entry. return $cached_data; } $queued = \V1\Socket::forge()->queue_call(\V1\APIRequest::get('api'), $call, $apicall_obj); } // Non-Data Calls grab the request right away. if (\Session::get('data_call', false) === false) { if ($queued === false) { // Server unavailable return \Utility::format_error(503, \Err::SERVER_ERROR, \Lang::get('v1::errors.remote_unavailable')); } // Pull the results. $result = \V1\Socket::forge()->get_results(); if (is_array($result)) { // We only have one call. return $result[\V1\APIRequest::get('api')][0]; } else { // If the request failed with false, it means that all streams timed out. return \Utility::format_error(500); } } $dc_response = array('status' => 200, 'headers' => array(), 'body' => \V1\Constant::QUEUED_CALL); // In Data Call mode we just signify that we've queued the call. return \Utility::format_response(200, $dc_response); }
/** * Run the Data Call * * @return mixed The array of responses and template data, or the HTML template if the format is "html" */ public static function run() { if (\Session::get('public', true) === true) { return \Utility::format_error(400, \V1\Err::NO_JS_CALLS, \Lang::get('v1::errors.no_js_calls')); } // Make sure the Data Call exists, and is part of their account. if (empty($data_call_data = \V1\Model\DataCalls::get_data_call())) { return \Utility::format_error(404, \V1\Err::BAD_DATA_CALL, \Lang::get('v1::errors.bad_data_call')); } $account_data = \V1\Model\Account::get_account(); // Make sure they are allowed to access it. if ($account_data['access_level'] < $data_call_data['min_access_level']) { return \Utility::format_error(402, \V1\Err::UPGRADE_REQUIRED, \Lang::get('v1::errors.upgrade_required')); } // Make sure that the Data Call is enabled or callable. if ($data_call_data['active_level'] === 0 && ($account_data['can_run_inactive'] === 0 && $account_data['id'] !== $data_call_data['account_id'])) { return \Utility::format_error(403, \V1\Err::DISABLED_DATA_CALL, \Lang::get('v1::errors.disabled_data_call')); } // Custom Data Calls allow the user to send us their workload (call script) and we'll process it for them. if (\V1\APIRequest::get('data-call', false) === 'custom') { $call_script = \V1\APIRequest::get('call-script', false); } else { $call_script = json_decode($data_call_data['call_script'], true); } // Make sure we have a call script. if (empty($call_script) || !is_array($call_script)) { return \Utility::format_error(503, \V1\Err::DATA_CALL_MISCONFIG, \Lang::get('v1::errors.data_call_misconfig')); } // Free accounts may not change their Data Calls, as they may only use public data calls. if ($account_data['access_level'] > 1 && is_array($call_options = \V1\APIRequest::data_call('call-options', false))) { $call_script = array_replace_recursive($call_script, $call_options); } /* * Set the Data Call flag to bypass things that no longer pertain to further calls, such as * authentication to Bit API Hub. */ \Session::set('data_call', true); $response = array(); $template_data = null; foreach ($call_script as $key => $call) { // If we have template data for widgets, gadgets, graphs, and charts, oh my, then we'll use it later. if ($key === 'template') { $template_data = $call; continue; } // We need a name. Even custom calls use the "custom" API. if (empty($call['api'])) { continue; } // Set the post data as defined in our script. \Session::set('posted_data', $call); // Make the call. $api_call = \Request::forge('v1/index', false)->execute()->response->body; // Bad decode if (empty($api_call)) { $response[$call['api']][] = \Utility::format_error(500); } // The response cometh forth, not stuck in zein queue. if (!empty($api_call[0]['response']['body']) && $api_call[0]['response']['body'] === \V1\Constant::QUEUED_CALL) { // Keep the order of calls right proper. :P $response[$call['api']][] = \V1\Constant::QUEUED_CALL; } else { // We have our response, so we set that now. $response[$call['api']][] = $api_call[0]; } } // If the customer doesn't need any response data, then we don't make them wait while we retrieve the results. if (\V1\APIRequest::data_call('no-response', false) === true) { $response = array('status' => 200, 'headers' => array(), 'body' => \Lang::get('v1::response.done')); return \Utility::format_response(200, $response); } // Check for responses. $call_queue = \V1\Socket::forge()->get_results(); // If we have queued responses, and possibly place holders, then we'll loop. if (!empty($call_queue) && !empty($response)) { // Let's loop. :) foreach ($call_queue as $api_name => $call_number_data) { /* * Somehow we don't need the response. Odd... I don't know why they bother giving me this stuff * if they don't want me to use it. */ if (empty($response[$api_name])) { continue; } // Find the next queued placeholder. $queued_placeholder = array_search(\V1\Constant::QUEUED_CALL, $response[$api_name]); // If we have a placeholder, then put it's value in place. if ($queued_placeholder !== false) { $response[$api_name][$queued_placeholder] = $call_number_data[(int) key($call_number_data)]; } } } // If we have template data to display, then format that now. if (!empty($template_data)) { // We only want the template we just compiled, so return that. if (\Session::get('response_format') === 'html') { return static::process_template($template_data, $response, true); } // Set the template to the array of template data. $response['template'] = static::process_template($template_data, $response); return \Utility::format_response(200, $response); } else { // No template data, so just return the responses. return \Utility::format_response(200, $response); } }