Skip to content

Commit

Permalink
feat(apiclient): support the High Performance Proxy Setup. see READ…
Browse files Browse the repository at this point in the history
…ME.md
  • Loading branch information
KaiSchwarz-cnic committed Apr 29, 2020
1 parent 3579796 commit d66d495
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 11 deletions.
70 changes: 66 additions & 4 deletions README.md
Expand Up @@ -21,13 +21,75 @@ This module is a connector library for the insanely fast HEXONET Backend API. Fo
## Features

* Automatic IDN Domain name conversion to punycode (our API accepts only punycode format in commands)
* Allow nested associative arrays in API commands to improve for bulk parameters
* Allows nested associative arrays in API commands to improve for bulk parameters
* Connecting and communication with our API
* Several ways to access and deal with response data
* Getting the command again returned together with the response
* sessionless communication
* session-based communication
* possibility to save API session identifier in PHP session
* Sessionless communication
* Session based communication
* Possibility to save API session identifier in PHP session
* Configure a Proxy for API communication
* Configure a Referer for API communication
* High Performance Proxy Setup

### High Performance Proxy Setup

Long distances to our main data center in Germany may result in high network latencies. If you encounter such problems, we highly recommend to use this setup, as it uses persistent connections to our API server and the overhead for connection establishments is omitted.

#### Step 1: Required Apache2 packages / modules

*At least Apache version 2.2.9* is required.

The following Apache2 modules must be installed and activated:

```bash
proxy.conf
proxy.load
proxy_http.load
ssl.conf # for HTTPs connection to our API server
ssl.load # for HTTPs connection to our API server
```

#### Step 2: Apache configuration

An example Apache configuration with binding to localhost:

```bash
<VirtualHost 127.0.0.1:80>
ServerAdmin webmaster@localhost
ServerSignature Off
SSLProxyEngine on
ProxyPass /api/call.cgi https://api.ispapi.net/api/call.cgi min=1 max=2
<Proxy *>
Order Deny,Allow
Deny from none
Allow from all
</Proxy>
</VirtualHost>
```

After saving your configuration changes please restart the Apache webserver.

#### Step 3: Using this setup

```python
from hexonet.apiconnector.apiclient import APIClient as AC

cl = AC()
cl.useOTESystem()
cl.useHighPerformanceConnectionSetup() # Default Connection Setup would be used otherwise by default
cl.setCredentials('test.user', 'test.passw0rd')
r = cl.request({"COMMAND" => "StatusAccount"})
```

So, what happens in code behind the scenes? We communicate with localhost (so our proxy setup) that passes the requests to the HEXONET API.
Of course we can't activate this setup by default as it is based on Steps 1 and 2. Otherwise connecting to our API wouldn't work.

Just in case the above port or ip address can't be used, use function setURL instead to set a different URL / Port.
`http://127.0.0.1/api/call.cgi` is the default URL for the High Performance Proxy Setup.
e.g. `$cl->setURL("http://127.0.0.1:8765/api/call.cgi");` would change the port. Configure that port also in the Apache Configuration (-> Step 2)!

Don't use `https` for that setup as it leads to slowing things down as of the https `overhead` of securing the connection. In this setup we just connect to localhost, so no direct outgoing network traffic using `http`. The apache configuration finally takes care passing it to `https` for the final communication to the HEXONET API.

## How to use this module in your project

Expand Down
67 changes: 64 additions & 3 deletions hexonet/apiconnector/apiclient.py
Expand Up @@ -19,12 +19,15 @@

rtm = RTM()

ISPAPI_CONNECTION_URL_PROXY = "http://127.0.0.1/api/call.cgi"
ISPAPI_CONNECTION_URL = "https://api.ispapi.net/api/call.cgi"


class APIClient(object):

def __init__(self):
# API connection url
self.setURL("https://api.ispapi.net/api/call.cgi")
self.setURL(ISPAPI_CONNECTION_URL)
# Object covering API connection data
self.__socketConfig = SocketConfig()
# activity flag for debug mode
Expand All @@ -34,6 +37,44 @@ def __init__(self):
self.useLIVESystem()
# user agent setting
self.__ua = ""
# additional connection settings
self.__curlopts = {}

def setProxy(self, proxy):
"""
Set Proxy to use for API communication
"""
if proxy == '':
self.__curlopts.pop('PROXY', None)
else:
self.__curlopts["PROXY"] = proxy
return self

def getProxy(self):
"""
Get Proxy configuration value for API communication
"""
if "PROXY" in self.__curlopts:
return self.__curlopts["PROXY"]
return None

def setReferer(self, referer):
"""
Set the Referer Header to use for API communication
"""
if referer == '':
self.__curlopts.pop('REFERER', None)
else:
self.__curlopts["REFERER"] = referer
return self

def getReferer(self):
"""
Get the Referer Header configuration value
"""
if "REFERER" in self.__curlopts:
return self.__curlopts["REFERER"]
return None

def enableDebugMode(self):
"""
Expand Down Expand Up @@ -216,9 +257,15 @@ def request(self, cmd):
data = self.getPOSTData(newcmd).encode('UTF-8')
# TODO: 300s (to be sure to get an API response)
try:
req = Request(self.__socketURL, data, {
headers = {
'User-Agent': self.getUserAgent()
})
}
if "REFERER" in self.__curlopts:
headers['Referer'] = self.__curlopts["REFERER"]
req = Request(self.__socketURL, data, headers)
if "PROXY" in self.__curlopts:
proxyurl = urlparse(self.__curlopts["PROXY"])
req.set_proxy(proxyurl.netloc, proxyurl.scheme)
body = urlopen(req, timeout=self.__socketTimeout).read()
if (self.__debugMode):
print((self.__socketURL, data, body, '\n', '\n'))
Expand Down Expand Up @@ -279,6 +326,20 @@ def resetUserView(self):
self.__socketConfig.setUser(None)
return self

def useHighPerformanceConnectionSetup(self):
"""
Activate High Performance Setup
"""
self.setURL(ISPAPI_CONNECTION_URL_PROXY)
return self

def useDefaultConnectionSetup(self):
"""
Activate Default Connection Setup (which is the default anyways)
"""
self.setURL(ISPAPI_CONNECTION_URL)
return self

def useOTESystem(self):
"""
Set OT&E System for API communication
Expand Down
26 changes: 22 additions & 4 deletions tests/test_apiclient.py
@@ -1,4 +1,4 @@
from hexonet.apiconnector.apiclient import APIClient as AC
from hexonet.apiconnector.apiclient import APIClient as AC, ISPAPI_CONNECTION_URL, ISPAPI_CONNECTION_URL_PROXY
from hexonet.apiconnector.response import Response as R
from hexonet.apiconnector.responsetemplatemanager import ResponseTemplateManager as RTM
import pytest
Expand Down Expand Up @@ -104,7 +104,7 @@ def test_apiclientmethods():
cl.setSession('')

# #.getURL()
assert cl.getURL() == 'https://api.ispapi.net/api/call.cgi'
assert cl.getURL() == ISPAPI_CONNECTION_URL

# #.getUserAgent()
pid = "PYTHON-SDK"
Expand All @@ -127,10 +127,10 @@ def test_apiclientmethods():
assert cl.getUserAgent() == ua

# #.setURL()
tmp = 'http://api.ispapi.net/api/call.cgi'
tmp = ISPAPI_CONNECTION_URL_PROXY
url = cl.setURL(tmp).getURL()
assert url is tmp
cl.setURL('https://api.ispapi.net/api/call.cgi')
cl.setURL(ISPAPI_CONNECTION_URL)

# #.setOTP()
# [otp set]
Expand Down Expand Up @@ -443,3 +443,21 @@ def test_apiclientmethods():
r = cl.request({'COMMAND': 'GetUserIndex'})
assert isinstance(r, R) is True
assert r.isSuccess() is True

# #.setProxy
cl.setProxy('https://127.0.0.1:8080')
assert cl.getProxy() == 'https://127.0.0.1:8080'
cl.setProxy('')

# #.setReferer
cl.setReferer('https://www.hexonet.net/')
assert cl.getReferer() == 'https://www.hexonet.net/'
cl.setReferer('')

# #.useHighPerformanceConnectionSetup
cl.useHighPerformanceConnectionSetup()
assert cl.getURL() == ISPAPI_CONNECTION_URL_PROXY

# #.useDefaultConnectionSetup
cl.useDefaultConnectionSetup()
assert cl.getURL() == ISPAPI_CONNECTION_URL

0 comments on commit d66d495

Please sign in to comment.