Skip to content

Commit

Permalink
Merge pull request #12 from mujin/unixSocket
Browse files Browse the repository at this point in the history
Support HTTP over Unix domain socket
  • Loading branch information
rdiankov authored May 17, 2023
2 parents a75ea47 + b91c099 commit e99b400
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.5.0 (2023-04-18)

- Support HTTP over Unix domain socket via optional `unixEndpoint` argument.


# 0.4.1 (2023-03-13)

- Regenerate graph client for new module library APIs.
Expand Down
13 changes: 9 additions & 4 deletions python/mujinwebstackclient/controllerwebclientraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from . import _
from . import json
from . import APIServerError, WebstackClientError, ControllerGraphClientException
from .unixsocketadapter import UnixSocketAdapter

import logging
log = logging.getLogger(__name__)
Expand All @@ -35,7 +36,7 @@ class ControllerWebClientRaw(object):
_isok = False # Flag to stop
_session = None # Requests session object

def __init__(self, baseurl, username, password, locale=None, author=None, userAgent=None, additionalHeaders=None):
def __init__(self, baseurl, username, password, locale=None, author=None, userAgent=None, additionalHeaders=None, unixEndpoint=None):
self._baseurl = baseurl
self._username = username
self._password = password
Expand All @@ -59,9 +60,13 @@ def __init__(self, baseurl, username, password, locale=None, author=None, userAg
self._headers['X-CSRFToken'] = 'csrftoken'
self._session.cookies.set('csrftoken', self._headers['X-CSRFToken'], path='/')

# Add retry to deal with closed keep alive connections
self._session.mount('https://', requests_adapters.HTTPAdapter(max_retries=3))
self._session.mount('http://', requests_adapters.HTTPAdapter(max_retries=3))
if unixEndpoint is None:
# Add retry to deal with closed keep alive connections
self._session.mount('https://', requests_adapters.HTTPAdapter(max_retries=3))
self._session.mount('http://', requests_adapters.HTTPAdapter(max_retries=3))
else:
self._session.adapters.pop('https://', None) # we don't use https with unix sockets
self._session.mount('http://', UnixSocketAdapter(unixEndpoint, max_retries=3))

# Set locale headers
self.SetLocale(locale)
Expand Down
66 changes: 66 additions & 0 deletions python/mujinwebstackclient/unixsocketadapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# Copyright (C) MUJIN Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import functools
import socket

from requests.adapters import HTTPAdapter
from urllib3 import HTTPConnectionPool
from urllib3.connection import HTTPConnection


class UnixSocketHTTPConnection(HTTPConnection):

_unixEndpoint = None # unix socket endpoint

def __init__(self, unixEndpoint, **kwargs):
super(UnixSocketHTTPConnection, self).__init__(**kwargs)
self._unixEndpoint = unixEndpoint

def _new_conn(self):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
sock.settimeout(self.timeout)
sock.connect(self._unixEndpoint)
return sock


class UnixSocketConnectionPool(HTTPConnectionPool):

_unixEndpoint = None # unix socket endpoint

def __init__(self, unixEndpoint):
super(UnixSocketConnectionPool, self).__init__('127.0.0.1')
UnixSocketConnectionPool.ConnectionCls = functools.partial(UnixSocketHTTPConnection, unixEndpoint=unixEndpoint)
self._unixEndpoint = unixEndpoint

def __str__(self):
return '%s(unixEndpoint=%s)' % (type(self).__name__, self._unixEndpoint)


class UnixSocketAdapter(HTTPAdapter):

_connectionPool = None # an instance of UnixSocketConnectionPool

def __init__(self, unixEndpoint, **kwargs):
super(UnixSocketAdapter, self).__init__(**kwargs)
self._connectionPool = UnixSocketConnectionPool(unixEndpoint)

def close(self):
self._connectionPool.close()
super(UnixSocketAdapter, self).close()

def get_connection(self, url, proxies=None):
assert not proxies, 'proxies not supported for unix socket'
return self._connectionPool
2 changes: 1 addition & 1 deletion python/mujinwebstackclient/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '0.4.1'
__version__ = '0.5.0'

# Do not forget to update CHANGELOG.md

7 changes: 4 additions & 3 deletions python/mujinwebstackclient/webstackclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,16 @@ def offset(self):
controllerIp = '' # Hostname of the controller web server
controllerPort = 80 # Port of the controller web server

def __init__(self, controllerurl='http://127.0.0.1', controllerusername='', controllerpassword='', author=None, userAgent=None, additionalHeaders=None):
def __init__(self, controllerurl='http://127.0.0.1', controllerusername='', controllerpassword='', author=None, userAgent=None, additionalHeaders=None, unixEndpoint=None):
"""Logs into the Mujin controller.
Args:
controllerurl (str): URL of the mujin controller, e.g. http://controller14
controllerusername (str): Username of the mujin controller, e.g. testuser
controllerpassword (str): Password of the mujin controller
userAgent (str): User agent to be sent on each request
additionalHeaders: Additional HTTP headers to be included in requests
additionalHeaders (dict): Additional HTTP headers to be included in requests
unixEndpoint (str): Unix socket endpoint for communicating with HTTP server over unix socket
"""

# Parse controllerurl
Expand All @@ -149,7 +150,7 @@ def __init__(self, controllerurl='http://127.0.0.1', controllerusername='', cont
'username': self.controllerusername,
'locale': os.environ.get('LANG', ''),
}
self._webclient = controllerwebclientraw.ControllerWebClientRaw(self.controllerurl, self.controllerusername, self.controllerpassword, author=author, userAgent=userAgent, additionalHeaders=additionalHeaders)
self._webclient = controllerwebclientraw.ControllerWebClientRaw(self.controllerurl, self.controllerusername, self.controllerpassword, author=author, userAgent=userAgent, additionalHeaders=additionalHeaders, unixEndpoint=unixEndpoint)

def __del__(self):
self.Destroy()
Expand Down

0 comments on commit e99b400

Please sign in to comment.