import re from gql.client import SyncClientSession from speckle.logging.exceptions import SpeckleException from typing import Dict from speckle.api import resources from speckle.api.resources import commit, stream, object, server, user, subscriptions from gql import Client, gql from gql.transport.requests import RequestsHTTPTransport from gql.transport.aiohttp import AIOHTTPTransport from gql.transport.websockets import WebsocketsTransport class SpeckleClient: DEFAULT_HOST = "staging.speckle.dev" USE_SSL = True def __init__(self, host: str = DEFAULT_HOST, use_ssl: bool = USE_SSL) -> None: ws_protocol = "ws" http_protocol = "http" if use_ssl: ws_protocol = "wss" http_protocol = "https" # sanitise host input by removing protocol and trailing slash host = re.sub(r"((^\w+:|^)\/\/)|(\/$)", "", host) self.url = f"{http_protocol}://{host}" self.graphql = self.url + "/graphql" self.ws_url = f"{ws_protocol}://{host}/graphql" self.me = None self.httpclient = Client( transport=RequestsHTTPTransport(url=self.graphql, verify=True, retries=3) ) self.wsclient = None self._init_resources() def authenticate(self, token: str) -> None: """Authenticate the client using a personal access token The token is saved in the client object and a synchronous GraphQL entrypoint is created Arguments: token {str} -- an api token """ self.me = {"token": token} headers = { "Authorization": f"Bearer {self.me['token']}", "Content-Type": "application/json", } httptransport = RequestsHTTPTransport( url=self.graphql, headers=headers, verify=True, retries=3 ) wstransport = WebsocketsTransport( url=self.ws_url, init_payload={"Authorization": f"Bearer {self.me['token']}"}, ) self.httpclient = Client(transport=httptransport) self.wsclient = Client(transport=wstransport) self._init_resources() def execute_query(self, query: str) -> Dict: return self.httpclient.execute(query) def _init_resources(self) -> None: self.stream = stream.Resource( me=self.me, basepath=self.url, client=self.httpclient ) self.commit = commit.Resource( me=self.me, basepath=self.url, client=self.httpclient ) self.object = object.Resource( me=self.me, basepath=self.url, client=self.httpclient ) self.server = server.Resource( me=self.me, basepath=self.url, client=self.httpclient ) self.user = user.Resource(me=self.me, basepath=self.url, client=self.httpclient) self.subscribe = subscriptions.Resource( me=self.me, basepath=self.ws_url, client=self.wsclient, ) def __getattr__(self, name): try: attr = getattr(resources, name) return attr.Resource(me=self.me, basepath=self.url, client=self.httpclient) except: raise SpeckleException( f"Method {name} is not supported by the SpeckleClient class" )