Skip to content

Async Calls

Some RPCs can not be performed in one step. Typically this is the case for all RPC that require reboot or restart of the relevant daemon.

This example illustrates this using configuration update as en example.

Example

import json
import requests
import sys
import time

# `token` is the value of the `token` attribute in the response from the `login.cgi` RPC.
# @see: <./login.md>
token = "<auth_token_string>"

target = "https://ripex2a.racom.eu/cgi-bin/"

# Download existing configuration
res = requests.post(
    f"{target}/rpc.cgi",
    data=json.dumps({ 'method': 'settings_get' }),
    headers={
        'Content-Type': 'application/json',
        'apikey': token})

if res.status_code != 200:
    print('Error: HTTP status code:', res.status_code)
    sys.exit(42) #error

# Make changes to the existing configuration
cnf_data = res.json()['result']['config_data']
cnf_data['main']['RR_StationDesc'] = 'Test 123'

# Initialize configuration update in device
res = requests.post(
    f"{target}/rpc.cgi",
    data=json.dumps({
        'method': 'settings_save_init',
        'params': { 'config_data': cnf_data } }),
    headers={
        'Content-Type': 'application/json',
        'apikey': token})

if res.status_code != 200:
    print('Error: HTTP status code:', res.status_code)
    sys.exit(42) #error

# The unit can reboot now and it might be offline.
# The parameters of the poll are returned in the response from the `settings_save_init` RPC.
#
# Polling intervals are based on the type of communication (local / remote)
# and the difficulty of action to be executed. In order to get the best performance
# out of network, these intervals must be respected.
#
# Detailed description of poll object in <../Methods/.partials/async_init_response_attribs.md>
poll_result = res.json()['result']

# `timeout` is measured from the moment this response was received, so the
# initial `delay` counts toward it. Start a real monotonic clock before waiting.
start = time.monotonic()

# Wait before starting to poll
time.sleep(poll_result['delay'])

# The interval between attempts grows by `interval_increase` after each attempt.
interval = poll_result['interval']
interval_increase = poll_result['interval_increase']

# Periodically poll for results until the real elapsed time exceeds the timeout
while time.monotonic() - start < poll_result['timeout']:
    rsp = requests.post(
        f"{target}/rpc.cgi",
        data=json.dumps({
            'method': 'settings_save_reconnect',
            'params': { 'session_id': poll_result['session_id'] } }),
        headers={
        'Content-Type': 'application/json',
        'apikey': token})

    if 'error' in rsp.json():
         if rsp.json()['error']['code'] != 'rpc_async_action_in_progress':
              print('Error: ', rsp.json()['error'])
              sys.exit(42) #error
    else:
         break

    time.sleep(interval)
    interval = interval + interval_increase
else:
    print('Error: polling timed out')
    sys.exit(42) #error

print('Configuration update completed.')