Open main menu

Halon, SMTP software for hosting providers β

API calls

One of the most powerful features of the Halon platform is the HSL scripting language, which enables you tailor and integrate the system to perfection.

Query external sources using REST

The combination of json_decode(), http() and the cache's update_function allows us to create very fast and resilient API call functions. The example below uses a normal (short) cache for performance, and a "long term" cache for resilience, in case the API is down. It uses the rate() function to determine if the API takes too long to answer, in order to ensure high performance even if the API is slow. If more than 10 requests during the last 5 minutes took more than 1 second to finish, or it fails to verify the response with is_array(), the value in the long-term cache is returned instead. In other words; the code below assumes that the result is always a JSON array.

Include file
// API call function
function api_call($query$args)
{
    
$apiurl "http://api.example.com/halon?api-key=Zu97uDyS9QeufBId";
    
$httpoption = ["timeout" => 5];

    return 
cache [
                    
"ttl_function" => function($result) {
                            if (!
is_array($result))
                                return 
60/* cache short time */
                            
return 3600;
                        },
                    
"size" => 100000
                    
"update_function" => function($old$new) {
                            if (
is_array($new)) /* expect array from API */
                                
return $new;
                            
cache [] syslog("crit""api_call: Invalid response, using long-term cache");
                            return 
$old;
                        }
    ] 
timed_call(http$apiurl.$query$httpoption$args);
}

// The timed call (helper) function, it expects the execution to take less than 1 sec
// if it exceeds that for more than 10 times in the last 5 minutes, it should
// return an empty response.
//
function timed_call($function, ...$args)
{
    if (
rate("timed_call:" serial(), $function0300) >= 10)
        return; 
// call was slow in the past 5 minutes

    
$t1 executiontime();
    
$ret $function(...$args); // call the function
    
$time executiontime() - $t1;

    if (
$time 1)
        
rate("timed_call:" serial(), $function10300);
    return 
json_decode($ret);

Below is an example of how the api_call() function can be used; as domain-based routing in the pre-delivery context:

include "file:X";
if (
$transportid == "mailtransport:1") {
    
// Should use API routing
    
$route api_call("&type=route&recipientdomain=$1", [$recipientdomain]);
    if (!isset(
$route["dest"]))
        
Reschedule(3600, ["reason" => "No route""increment_retry" => false]);
    
SetDestination($route["dest"], number($route["port"]));
    if (
$route["sasl_user"])
        
SetSASL($route["sasl_user"], $route["sasl_pass"]);