Skip to content

12. Third Party Add on API

Zomboided edited this page Feb 8, 2018 · 5 revisions

VPN Manager can be integrated into third party add-ons using some simple Python calls. This gives scope for third party add-ons to switch a connection based on the VPN Manager add-on or window ID filtering function, as well as do general connect and disconnect type calls. The primary use case is TV Guide type add-ons where different channels are sourced via streams provided by different add-ons, some of which may have differing connection requirements.

The API is provided for add-on creators and not for regular end users.

During any connection change the VPN Manager notification boxes detailing the state of the connection will continue to be displayed.

Integration without Dependencies

Rather than creating add-on dependencies (forcing users to use the VPN Manager add-on when they may not be using a VPN), a Python file can be copied into the third party add-on and called directly.

Copy the service.vpn.manager/libs/vpnapi.py file into the third party add-on directory structure. Then in the modules where the API is to be used add a from vpnapi import VPNAPI type statement that matches where the vpnapi.py file resides.

The vpnapi.py file should remain compatible with future releases of VPN Manager. If a new version of vpnapi.py is needed then this may pre-req a newer version of the VPN Manager add-on and will require this file copying across again. I don't anticipate this file changing much, if at all.

Integration with a VPN Manager Dependency

If the third party add-on wants to ensure that VPN Manager is installed, then the addon.xml structure has a <requires> section that will let you add <import addon="service.vpn.manager" version="3.1.0"/>

VPN Manager provides a python module extension point which should allow from vpnapi import VPNAPI to be successfully added to the modules where the API is to be used.

Initialising the API

To initialise the API, create a VPNAPI class. The example below shows some code that can be added to a class init function in a class where the API will be called.

try:
    self.api = VPNAPI()
except:
    self.api = None

If VPN Manager 3.1.0 or later is not installed then a RuntimeError exception will be thrown.

During initialisation the current VPN connection state will be identified and stored as the default state. This can be changed using the setDefault() method.

If you don't want to rely on an exception to determine if VPN Manager has been installed you can also use something like if xbmc.getCondVisibility("System.HasAddon(service.vpn.manager)"): before initialising the API.

Determining if a VPN has been setup

Calls to change connections will first determine whether the VPN has been setup so there's not a need to do determine that separately. However there maybe cases where you want to know whether the VPN has been setup (e.g. to advise the users that this function is available but they're not taking advantage of it), and this can be done using this code :

vpnenabled = False
if self.api is not None:
    vpnenabled = self.api.isVPNSetup()

Connected to a Validated VPN Connection

To connect to a validated VPN connection, use this code :

if self.api is not None:
    result = self.api.connectToValidated(1, True)

The first parameter is the number of the connection between 1 to 10, relating to the number of the primary VPNs setup in VPN Manager. If the connection requested matches the VPN connection in use then no change will occur.

The second parameter is a boolean indicating if the call should wait for the connection to complete before returning. If this is set to True then it'll wait for up to the number of seconds specified by the setTimeOut function (default is 30 seconds). If it's set to False, then it'll cause the VPN connection to start to change, but will not wait for the result.

The return value from this function is True if the connection was made successfully within the time allowed (or the second parameter was False); or no connection change was needed. False will be returned if the VPN has not been set up; or the connection was not made successfully within the time allowed.

Connect to Any VPN Connection

To connect to a VPN connection represented by a .ovpn file, use this code :

if self.api is not None:
    result = self.api.connectTo(ovpn_filename, True)

The first parameter should be a fully qualified filename to an ovpn file that will be used to make the connection. If the connection requested matches the VPN connection in use then no change will occur.

The second parameter is a boolean indicating if the call should wait for the connection to complete before returning. If this is set to True then it'll wait for up to the number of seconds specified by the setTimeOut function (default is 30 seconds). If it's set to False, then it'll cause the VPN connection to start to change, but will not wait for the result.

The return value from this function is True if the connection was made successfully within the time allowed (or the second parameter was False); or no connection change was needed. False will be returned if the VPN has not been set up; or the connection was not made successfully within the time allowed.

Disconnecting the VPN

To disconnect the existing VPN connection, use this code :

if self.api is not None:
    result = self.api.disconnect(True)

The only parameter is a boolean indicating if the call should wait for the connection to disconnect before returning. If this is set to True then it'll wait for up to the number of seconds specified by the setTimeOut function (default is 30 seconds). If it's set to False, then it'll cause the VPN connection to start to disconnect, but will not wait for the result.

The return value from this function is True if the disconnect happened successfully within the time allowed (or the parameter was False); or no connection change was needed. False will be returned if the VPN has not been set up; or the disconnect did not happen successfully within the time allowed.

Reconnecting the VPN

To reconnect the existing VPN connection, use this code :

if self.api is not None:
    result = self.api.reconnect()

The return value from this function is True if the VPN has been set up. If the connection is not active, nothing will happen. False will be returned if the VPN has not been set up.

Pausing VPN Filtering

To pause the VPN filtering function, use this code :

if self.api is not None:
    result = self.api.pause()

The return value from this function is True if the VPN has been set up. The filtering will be paused until it's restarted either in the VPN Manager GUI or programmatically. False will be returned if the VPN has not been set up.

Restart VPN Filtering

To restart the VPN filtering function, use this code :

if self.api is not None:
    result = self.api.restart()

The return value from this function is True if the VPN has been set up. The filtering will be restarted. False will be returned if the VPN has not been set up.

Restoring the Default VPN State

To return to the default VPN state (which will either be disconnected, or connected to the default connection), use this code:

if self.api is not None:
    self.defaultVPN(wait)

The only parameter is a boolean indicating if the call should wait for the connection to disconnect before returning. If this is set to True then it'll wait for up to the number of seconds specified by the setTimeOut function (default is 30 seconds). If it's set to False, then it'll cause the VPN connection to start to disconect, but will not wait for the result.

The return value from this function is True if the disconnect happened successfully within the time allowed (or the parameter was False); or no connection change was needed. False will be returned if the VPN has not been set up; or the disconnect did not happen successfully within the time allowed.

Filtering Connections

A single call is needed to switch to the right connection for the add-on that's about to be used. The code to do this looks like this :

if self.api is not None:
    result = self.api.filterAndSwitch(path, 0, True, True)

The filterAndSwitch function takes 4 parameters. The first is the full path name of the add-on to be filtered (e.g. plugin://plugin.video.iplayerwww/?url=bbc_one_hd...). The text in bold is the name of the add-on and is used to do the filtering, but in order to recognise it as an add-on filter, the plugin:// string must not be omitted. The text after the bold are parameters for the add-on. These are ignored during filtering.

The second parameter is the window ID to be filtered. For add-on filtering, you can just set this to 0, otherwise pass in the current window ID. For the most part, this parameter doesn't make sense unless the third party add-on is changing window IDs with differing function.

The third parameter is a boolean indicating whether or not the default VPN should be used if there is no filter identified.

The final parameter is a boolean indicating if the call should wait for the connection to complete before returning. If this is set to True then it'll wait for up to the number of seconds specified by the setTimeOut function (default is 30 seconds). If it's set to False, then it'll cause the VPN connection to start to change, but will not wait for the result. This can lead to the network connection changing a small number of seconds after the call has returned, which may cause an interruption for any processes using the network.

The return value from this function is True if the connection was made successfully within the time allowed (or the final parameter was false); or no connection change was needed; or no filter was found. False will be returned if the VPN has not been set up; or the connection was not made successfully within the time allowed.

Determining if a Connection is Filtered

If a third party add-on just wants to know if an add-on or window is filtered, then this code will let you do that :

if self.api is not None:
    result = self.api.isFiltered(path, 0)

The first two parameters match those used by filterAndSwitch.

The return values are -1 if no filter is found, 0 if the filter is Disconnect (ie run without a VPN), or 1 to 10, relating to the number of the primary VPNs setup in VPN Manager.

Adjusting Timeout

The default timeout to wait for a connection to succeed is 30 seconds. This can be changed using this call, where the only parameter is the number of seconds :

if self.api is not None:
     self.api.setTimeOut(30)

Setting the Default Connection State

The default connection state is determined during the initialisation of the API object, but this can be updated using this code :

if self.api is not None:
     self.api.setDefault(ovpn_filename)

The only parameter should be a fully qualified filename to an ovpn file that represents the default connection, or an empty string (i.e. "") to represent the disconnected state. There is no return value.