From f998a6bca5ab48ee2d5ce5f52f6a93cff2485c9e Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Wed, 22 Feb 2017 22:44:36 +0200 Subject: Initial commit --- .gitignore | 1 + README.md | 22 +++++++++++ bimclient/__init__.py | 0 bimclient/bimclient.py | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ requirements.pip | 1 + tests.py | 26 ++++++++++++ 6 files changed, 155 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 bimclient/__init__.py create mode 100644 bimclient/bimclient.py create mode 100644 requirements.pip create mode 100644 tests.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/README.md b/README.md new file mode 100644 index 0000000..c5b9bcb --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +### Introduction + +This is an ArchiCAD BIMServer/Cloud client library for Python. + + +### System Requirements + +- pip install -r requirements.pip +- ArchiCAD BIMServer or BIMCloud + + +### Usage + +Example 1 - get the version number of your BIM server: + +```python +import bimclient +s = bimclient.connect('http://bim.example.com:19000') +s.version +``` + +Check `tests.py` for more examples. diff --git a/bimclient/__init__.py b/bimclient/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bimclient/bimclient.py b/bimclient/bimclient.py new file mode 100644 index 0000000..0f0873c --- /dev/null +++ b/bimclient/bimclient.py @@ -0,0 +1,105 @@ +import json +import logging +import base64 +import tempfile +import subprocess + +import requests + + +class Session(object): + def __init__(self, url): + self.session_id = None + self.url = url.rstrip('/') + '/' + + def __enter__(self): + return self + + def __exit__(self, *args): + pass + + def __dict__(self): + return self.response + + def request(self, method, data=None): + """ + Sends a request to the BIM server. + """ + url = self.url + method + params = {} + + if self.session_id: + params['session-id'] = self.session_id + + if data: + self._request = requests.post(url, json=data) + else: + self._request = requests.get(url, params=params) + + self._text = self._request.text + + if method.endswith('get-server-public-key'): + logging.debug('Got public key: %s' % self._text) + self.key = self._text + return self + + try: + self.response = self._request.json() + except ValueError: + raise Exception(self._text) + + if method.endswith('get-server-info'): + self.server = self.response + self.id = self.response.get('serverId') + self.version = self.response.get('versionString') + self.name = self.response.get('friendlyName') + self.license = self.response.get('license') + self.platform = self.response.get('platform') + + return self + + def encrypt_password(self, password): + """ + Encrypts the supplied password with the server's public key + and returns the encrypted password + """ + with tempfile.NamedTemporaryFile() as f: + f.write(self.key) + logging.debug('Wrote public key to %s' % f.name) + f.seek(0) + p = subprocess.Popen(['openssl', 'rsautl', '-encrypt', + '-inkey', f.name, '-pubin'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + o, e = p.communicate(password + '00000000') + password = base64.b64encode(o) + + return password + + def login(self, username, password): + """ + Authenticates with the BIM server. + """ + self.request('management/latest/get-server-public-key') + password = self.encrypt_password(password) + d = {'username': username, 'password': password} + logging.debug('Auth request: %s' % d) + self.request('management/latest/create-session', data=d) + logging.debug(self.response) + self.user_id = self.response.get('user-id') + self.session_id = self.response.get('session-id') + self.session_timeout = self.response.get('expire-timeout') + + if not self.user_id: + raise Exception('Authentication failed') + + return self + + def projects(self): + self.request('management/latest/get-projects-by-criterion') + return self.response + + +def connect(url): + with Session(url) as session: + return session.request('get-server-info') diff --git a/requirements.pip b/requirements.pip new file mode 100644 index 0000000..f229360 --- /dev/null +++ b/requirements.pip @@ -0,0 +1 @@ +requests diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..136b7fd --- /dev/null +++ b/tests.py @@ -0,0 +1,26 @@ +import os +import logging +import unittest + +from bimclient import bimclient + + +class TestServerMethods(unittest.TestCase): + def setUp(self): + self.server = bimclient.connect(os.getenv('BIMCLIENT_URL')) + + def test_connect(self): + self.assertEquals(len(self.server.version), 6) + + def test_login(self): + self.server.login(os.getenv('BIMCLIENT_USER'), + os.getenv('BIMCLIENT_PW')) + + def test_projects(self): + projects = self.server.projects() + self.assertGreater(len(projects), 0) + + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG) + unittest.main() -- cgit v1.2.3