Skip to content

Commit

Permalink
Python3 (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
DomAmato committed Apr 11, 2020
1 parent 887e164 commit 8d7bd34
Show file tree
Hide file tree
Showing 19 changed files with 1,249 additions and 1,107 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/pythontest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Python Test

on:
push:
branches:
- '**'
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.5, 3.6, 3.7, 3.8]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e git+https://github.com/DomAmato/smpp.pdu.git@master#egg=smpp.pdu
pip install -r requirements.txt
pip install service_identity
- name: Lint
run: |
pip install pylint
pylint -rn --errors-only ./smpp
- name: Test
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
run: |
pip install coveralls mock
coverage run --source=smpp -m twisted.trial tests
coveralls
11 changes: 0 additions & 11 deletions .travis.yml

This file was deleted.

7 changes: 6 additions & 1 deletion README.markdown → README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# smpp.twisted

[![Test](https://github.com/DomAmato/smpp.twisted/workflows/Python%20Test/badge.svg)](https://github.com/DomAmato/smpp.twisted/actions)
[![Coverage Status](https://coveralls.io/repos/github/DomAmato/smpp.twisted/badge.svg?branch=master)](https://coveralls.io/github/DomAmato/smpp.twisted?branch=master)

SMPP 3.4 client built on Twisted

http://www.nowsms.com/discus/messages/1/24856.html
Expand All @@ -9,7 +14,7 @@ Example
from smpp.twisted.client import SMPPClientTransceiver, SMPPClientService
from smpp.twisted.config import SMPPClientConfig

class SMPP(object):
class SMPP:

def __init__(self, config=None):
if config is None:
Expand Down
1 change: 0 additions & 1 deletion dev_requirements.txt

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from smpp.twisted.client import SMPPClientTransceiver, SMPPClientService
from smpp.twisted.config import SMPPClientConfig

class SMPP(object):
class SMPP:

def __init__(self, config=None):
if config is None:
Expand Down
7 changes: 4 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
twisted
enum
pyOpenSSL
Twisted~=20.3.0
pyOpenSSL~=19.1.0
# cant install from other projects
# smpp.pdu @ git+https://github.com/DomAmato/smpp.pdu.git@master
smpp.pdu
25 changes: 14 additions & 11 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
import os
from setuptools import setup, find_packages

def parse_requirements(filename):
"""load requirements from a pip requirements file"""
lineiter = (line.strip() for line in open(filename))
return [line for line in lineiter if line and (not line.startswith("#") and not line.startswith('-'))]

def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()

from setuptools import setup, find_packages
setup(
name = "smpp.twisted",
version = "0.4",
author = "Roger Hoover",
author_email = "roger.hoover@gmail.com",
description = "SMPP 3.4 client built on Twisted",
license = 'Apache License 2.0',
packages = find_packages(),
long_description=read('README.markdown'),
packages = find_packages(exclude=["tests"]),
long_description=read('README.md'),
keywords = "smpp twisted",
url = "https://github.com/mozes/smpp.twisted",
py_modules=["smpp.twisted"],
include_package_data = True,
package_data={'smpp.twisted': ['README.markdown']},
package_data={'smpp.twisted': ['README.md']},
zip_safe = False,
install_requires = [
'twisted',
'enum',
'pyOpenSSL',
'smpp.pdu',
],
install_requires = parse_requirements('requirements.txt'),
tests_require = [
'mock',
],
test_suite = 'smpp.twisted.tests',
classifiers=[
"Development Status :: 5 - Production/Stable",
"Framework :: Twisted",
Expand All @@ -38,6 +36,11 @@ def read(fname):
"License :: OSI Approved :: Apache Software License",
"Intended Audience :: Developers",
"Programming Language :: Python",
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
"Topic :: Software Development :: Libraries :: Python Modules",
],
)
Expand Down
2 changes: 1 addition & 1 deletion smpp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
__import__('pkg_resources').declare_namespace(__name__)
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
49 changes: 26 additions & 23 deletions smpp/twisted/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from OpenSSL import SSL
from twisted.internet.protocol import ClientFactory
from twisted.internet import defer, reactor, ssl
from twisted.application import service
from twisted.application.service import Service
from smpp.twisted.protocol import SMPPClientProtocol, DataHandlerResponse

LOG_CATEGORY="smpp.twisted.client"
Expand All @@ -30,16 +30,17 @@ def __init__(self, config):
self.config = config
self.buildProtocolDeferred = defer.Deferred()
self.log = logging.getLogger(LOG_CATEGORY)

def getConfig(self):
return self.config

def buildProtocol(self, addr):
p = ClientFactory.buildProtocol(self, addr)
#This is a sneaky way of passing the protocol instance back to the caller
#pylint: disable=no-member
reactor.callLater(0, self.buildProtocolDeferred.callback, p)
return p

def clientConnectionFailed(self, connector, reason):
"""Connection failed
"""
Expand All @@ -50,17 +51,17 @@ class CtxFactory(ssl.ClientContextFactory):

def __init__(self, config):
self.smppConfig = config

def getContext(self):
self.method = SSL.SSLv23_METHOD
ctx = ssl.ClientContextFactory.getContext(self)
if self.smppConfig.SSLCertificateFile:
ctx.use_certificate_file(self.smppConfig.SSLCertificateFile)
return ctx

class SMPPClientBase(object):
class SMPPClientBase:
msgHandler = None

def __init__(self, config):
self.config = config
self.log = logging.getLogger(LOG_CATEGORY)
Expand All @@ -71,44 +72,46 @@ def connect(self):
factory = SMPPClientFactory(self.config)
if self.config.useSSL:
self.log.warning('Establishing SSL connection to %s:%d' % (self.config.host, self.config.port))
#pylint: disable=no-member
reactor.connectSSL(self.config.host, self.config.port, factory, CtxFactory(self.config))
else:
self.log.warning('Establishing TCP connection to %s:%d' % (self.config.host, self.config.port))
reactor.connectTCP(self.config.host, self.config.port, factory)
#pylint: disable=no-member
reactor.connectTCP(self.config.host, self.config.port, factory)
return factory.buildProtocolDeferred.addCallback(self.onConnect)

def onConnect(self, smpp):
self.smpp = smpp
if self.msgHandler is not None:
smpp.setDataRequestHandler(self.msgHandler)
return smpp

def connectAndBind(self):
self.bindDeferred = defer.Deferred()
self.connect().addCallback(self.doBind).addErrback(self.bindDeferred.errback)
return self.bindDeferred

def doBind(self, smpp):
self.bind(smpp).addCallback(self.bound).addErrback(self.bindFailed, smpp)
return smpp

def bind(self, smpp):
raise NotImplementedError()

#If bind fails, don't errback until we're disconnected
def bindFailed(self, error, smpp):
smpp.getDisconnectedDeferred().addCallback(lambda result: self.bindDeferred.errback(error))

def bound(self, result):
self.bindDeferred.callback(result.smpp)

class SMPPClientTransmitter(SMPPClientBase):

def bind(self, smpp):
return smpp.bindAsTransmitter()

class SMPPClientReceiver(SMPPClientBase):

def __init__(self, config, msgHandler):
SMPPClientBase.__init__(self, config)
self.msgHandler = msgHandler
Expand All @@ -123,31 +126,31 @@ def bind(self, smpp):

#TODO - move this to mozes code base since
# the service support in Twisted is so crappy
class SMPPClientService(service.Service):
class SMPPClientService(Service):

def __init__(self, smppClient):
self.client = smppClient
self.stopDeferred = defer.Deferred()
self.log = logging.getLogger(LOG_CATEGORY)

def getStopDeferred(self):
return self.stopDeferred

@defer.inlineCallbacks
def startService(self):
service.Service.startService(self)
Service.startService(self)
bindDeferred = self.client.connectAndBind()
bindDeferred.addErrback(self.handleStartError)
smpp = yield bindDeferred
smpp.getDisconnectedDeferred().chainDeferred(self.stopDeferred)
defer.returnValue(smpp)

def handleStartError(self, error):
self.stopDeferred.errback(error)
return error

def stopService(self):
service.Service.stopService(self)
Service.stopService(self)
if self.client.smpp:
self.log.info("Stopping SMPP Client")
return self.client.smpp.unbindAndDisconnect()
Expand Down
17 changes: 8 additions & 9 deletions smpp/twisted/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,33 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
class SMPPConfig(object):


class SMPPConfig:

def __init__(self, **kwargs):
self.sessionInitTimerSecs = kwargs.get('sessionInitTimerSecs', 30)
self.enquireLinkTimerSecs = kwargs.get('enquireLinkTimerSecs', 10)
self.inactivityTimerSecs = kwargs.get('inactivityTimerSecs', 120)
self.responseTimerSecs = kwargs.get('responseTimerSecs', 60)
self.pduReadTimerSecs = kwargs.get('pduReadTimerSecs', 10)


class SMPPClientConfig(SMPPConfig):

def __init__(self, **kwargs):
super(SMPPClientConfig, self).__init__(**kwargs)
self.port = kwargs['port']
self.host = kwargs['host']
self.port = kwargs['port']
self.username = kwargs['username']
self.password = kwargs['password']
self.systemType = kwargs.get('systemType', '')
self.useSSL = kwargs.get('useSSL', False)
self.SSLCertificateFile = kwargs.get('SSLCertificateFile', None)
self.addressRange = kwargs.get('addressRange', None)
self.addressTon = kwargs.get('addressTon', None)
self.addressNpi = kwargs.get('addressNpi', None)
self.addressNpi = kwargs.get('addressNpi', None)

class SMPPServerConfig(SMPPConfig):

def __init__(self, **kwargs):
"""
@param systems: A dict of data representing the available
Expand All @@ -50,5 +50,4 @@ def __init__(self, **kwargs):
"""
super(SMPPServerConfig, self).__init__(**kwargs)
self.systems = kwargs.get('systems', {})
self.msgHandler = kwargs['msgHandler']

self.msgHandler = kwargs['msgHandler']
Loading

0 comments on commit 8d7bd34

Please sign in to comment.