Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- '''
- main library
- '''
- import sys
- import datetime
- # signal osses
- # argument parser
- # lib for config file parser
- # enumerate
- # json
- import json
- # datetime
- # twisted
- # for web server part
- from enum import Enum
- from twisted.enterprise import adbapi
- from twisted.internet import reactor, protocol
- from twisted.internet.defer import inlineCallbacks
- from twisted.internet.protocol import ServerFactory, ClientFactory, Protocol, connectionDone
- from twisted.web.resource import Resource
- from twisted.web.server import Site, NOT_DONE_YET
- from twisted.web.static import File
- from twisted.python import log
- # autobahn lib
- # ISO8583
- from ISO8583.ISO8583 import ISO8583
- from ISO8583.ISOErrors import *
- # enum request type
- class PdamTransactionType(Enum):
- INQUIRY_CUSTOMER_INFO_REQUEST = 1
- INQUIRY_BILL_PAYMENT_REQUEST = 2
- INQUIRY_BILL_REVERSAL = 3
- INQUIRY_INVALID = 255
- def log_and_broadcast_data(data, is_error=False, is_broadcasted=True):
- """
- log the data and broadcast to websocket client if enable
- :param is_error: error info or not
- :param data: data to log and broadcasted. will be cast to string
- :param is_broadcasted: broadcast to websocket client
- """
- try:
- if not is_error:
- log.msg(data)
- else:
- log.err(data)
- # if is_broadcasted:
- # BroadcastServerFactory.broadcast_message(
- # {
- # 'timestamp': time.time(),
- # 'error': int(is_error),
- # 'data': str(data)
- # })
- except Exception as err:
- pass
- log.err(err)
- '''
- db connection class
- '''
- class DBConnection(object):
- def __init__(self, server=None, username=None, password=None, database_name=None, port=1433, timeout_query=45,
- timeout_login=10):
- try:
- # self._dbconnection = getattr(self, "_dbconnection", None)
- # if self._dbconnection is None:
- # log.msg("Init new database connection")
- # self._dbconnection = adbapi.ConnectionPool("pymssql", user=username, password=password,
- # server=server, port=port, database=database_name,
- # timeout=timeout, tds_version='7.3')
- # else:
- # log.msg("Database connection already established")
- # log.msg(self._dbconnection)
- # return self._dbconnection
- log.msg("Init new database connection")
- self.dbconnection = adbapi.ConnectionPool("pymssql", cp_min=1, cp_max=2, user=username, password=password,
- server=server, port=port, database=database_name,
- timeout=timeout_query, login_timeout=timeout_login,
- tds_version='7.0')
- except Exception as err:
- pass
- log.err(err)
- self.dbconnection = None
- return None
- '''
- iso8583 processor
- '''
- class PdamIso8583(ISO8583):
- def __init__(self, isoFromNetwork=None, isoStringContent=None, isBigEndian=True):
- try:
- super().__init__()
- if (isoFromNetwork is not None) and (isoStringContent is None):
- if isinstance(isoFromNetwork, bytes):
- self.setNetworkISO(isoFromNetwork, isBigEndian)
- else:
- self.setNetworkISO(isoFromNetwork.encode('latin1'), isBigEndian)
- if (isoFromNetwork is None) and (isoStringContent is not None):
- if isinstance(isoStringContent, bytes):
- self.setIsoContent(isoStringContent.decode('cp1252'))
- else:
- self.setIsoContent(isoStringContent)
- # log.msg(self.getBitsAndValues())
- # log.msg(self.getNetworkISO(isBigEndian))
- # return self
- self.isValid = True
- except Exception as err:
- pass
- log.err(err)
- self.isValid = False
- # return None
- '''
- show debug iso content
- '''
- def debug_iso(self):
- try:
- mtix = self.getMTI()
- bitmapx = self.getBitmap()
- vix = self.getBitsAndValues()
- result = "msgno[ 0]<%d>\r\n" % (int(mtix),)
- result += "bitmap: [%s]\r\n" % (bitmapx,)
- for v in vix:
- # print(self.getBit(int(v['bit'])))
- vx = v['value']
- nmx = self.getLargeBitName(int(v['bit']))
- # print(self.getLargeBitName(int(v['bit'])))
- if (v['type'] == 'LL') or (v['type'] == 'LLL') or (v['type'] == 'LLL'):
- lenx = len(v['type'])
- result += '%-48s out[ %3s: ] %4s <%s>\r\n' % (nmx, v['bit'], v['type'], vx[0:lenx])
- result += '%-48s out[ %3s: ] %4s <%s>\r\n' % (nmx, v['bit'], v['type'], vx[lenx:])
- else:
- result += '%-48s out[ %3s: ] %4s <%s>\r\n' % (nmx, v['bit'], v['type'], v['value'])
- return result
- except Exception as err:
- pass
- log.err(err)
- return None
- def get_set_processing_code(self, proc_code=None):
- try:
- if proc_code is None:
- return self.getBit(3)
- else:
- return self.setBit(3, proc_code)
- except Exception as err:
- pass
- log.err(err)
- return False
- def get_set_mti(self, mti=None):
- try:
- if mti is None:
- return self.getMTI()
- else:
- return self.setMTI(mti)
- except Exception as err:
- pass
- log.err(err)
- return False
- def get_id_customer(self):
- try:
- return ((self.getBit(48))[3:]).strip()
- except Exception as err:
- pass
- log.err(err)
- return None
- def get_user_data_content(self):
- try:
- return ((self.getBit(48))[3:]).strip()
- except Exception as err:
- pass
- log.err(err)
- return None
- def get_trace_number(self):
- try:
- return self.getBit(11).strip()
- except Exception as err:
- pass
- log.err(err)
- return None
- def get_request_type(self):
- try:
- mtix = self.get_set_mti()
- procx = self.get_set_processing_code()
- if (mtix == "0200") and (procx[0:2] == "38") and (procx[-2:] == "98"):
- return PdamTransactionType.INQUIRY_CUSTOMER_INFO_REQUEST
- if (mtix == "0200") and (procx[0:2] == "17") and (procx[-2:] == "98"):
- return PdamTransactionType.INQUIRY_BILL_PAYMENT_REQUEST
- if (mtix == "0420") and (procx[0:2] == "17") and (procx[-2:] == "98"):
- return PdamTransactionType.INQUIRY_BILL_REVERSAL
- return PdamTransactionType.INQUIRY_INVALID
- except Exception as err:
- pass
- log.err(err)
- return PdamTransactionType.INQUIRY_INVALID
- class PDAMProcessor(object):
- # @staticmethod
- @staticmethod
- def get_database_connection_object(id_customer=None):
- """
- build db object
- :param id_customer:
- :return:
- """
- try:
- # idx = (id_customer.strip())[0:3]
- # idy = int(idx)
- # if idy in range(100, 1000):
- # idy = (idy // 100) * 100
- # idx = str(idy)
- #
- # unit = read_config_file(CONFIG_FILE, section_name="db-router", option_name=idx)
- # servername = read_config_file(CONFIG_FILE, section_name=unit, option_name="host")
- # portnumber = int(read_config_file(CONFIG_FILE, section_name=unit, option_name="port"))
- # db_username = read_config_file(CONFIG_FILE, section_name=unit, option_name="username")
- # db_password = read_config_file(CONFIG_FILE, section_name=unit, option_name="password")
- # db_name = read_config_file(CONFIG_FILE, section_name=unit, option_name="database")
- log_and_broadcast_data("Making connection to %s at %s:%d" % (unit, servername, portnumber))
- return DBConnection(server=servername, port=portnumber, username=db_username, password=db_password,
- database_name=db_name)
- except Exception as err:
- pass
- log.err(err)
- return None
- @inlineCallbacks
- def get_info_customer(self, id_customer=None, request=None, iso_obj=None):
- """
- Get info customer
- :param id_customer:
- :param request:
- """
- try:
- yield log_and_broadcast_data("Get customer info")
- # get db config
- dbconnection_obj = self.get_database_connection_object(iso_obj.get_id_customer())
- # got any valid db connection?
- if dbconnection_obj is not None:
- # run the query
- customer_info = yield dbconnection_obj.dbconnection.runQuery("exec spcektgh '%s'" % (id_customer,))
- # format the return into dict
- fd = (
- 'IDPEL', 'NAMA', 'ALAMAT', 'TARIP', 'DAYA', 'GARDU', 'GOLONGAN', 'FJN', 'F_METER', 'STAND1',
- 'STAND2',
- 'STAND3', 'BLN1', 'REK1', 'PPJ1', 'PPN1', 'SEWA1', 'DENDA1', 'MET1', 'TGH1', 'BLN2', 'REK2', 'PPJ2',
- 'PPN2', 'SEWA2', 'DENDA2', 'MET2', 'TGH2', 'BLN3', 'REK3', 'PPJ3', 'PPN3', 'SEWA3', 'DENDA3',
- 'MET3', 'TGH3', 'GRANDTOTAL', 'TOTALREC', 'RESPONSE CODE')
- dx = dict(zip(fd, customer_info[0]))
- yield log_and_broadcast_data(dx)
- # format the reply content
- number_of_bill = int(len(dx['BLN1']) > 0) + int(len(dx['BLN2']) > 0) + int(len(dx['BLN3']) > 0)
- bill_detail = ""
- for id_bill in range(1, (number_of_bill + 1)):
- bill_detail += "%-6s%8u%12u%12u%12u%12u%12u%12u%12u" % (
- dx['BLN' + str(id_bill)],
- int(dx['STAND' + str(id_bill)]) * 100,
- int(dx['REK' + str(id_bill)]) * 100,
- int(dx['PPJ' + str(id_bill)]) * 100,
- int(dx['PPN' + str(id_bill)]) * 100,
- int(dx['SEWA' + str(id_bill)]) * 100,
- int(dx['DENDA' + str(id_bill)]) * 100,
- int(dx['MET' + str(id_bill)]) * 100,
- int(dx['TGH' + str(id_bill)]) * 100)
- # log.msg(bill_detail)
- reply_content_bit48 = "%-12s%-20s%-20s%2s%6s%20s%s%04d%08d%12u%u%8s%42s%s" % (
- dx['IDPEL'],
- dx['NAMA'],
- dx['ALAMAT'],
- " ",
- " ",
- dx['TARIP'],
- " ",
- 0,
- 0,
- dx['GRANDTOTAL'] * 100,
- number_of_bill,
- " ",
- " ",
- bill_detail)
- # reply_len = len(reply_content_bit48)
- # reply_content_bit48 = "%03u%s" % (reply_len, reply_content_bit48)
- # log.msg(len(reply_content_bit48))
- # log.msg(reply_content_bit48)
- # update the iso
- # log.msg(iso_obj)
- if iso_obj is not None:
- iso_obj.get_set_mti("0210")
- iso_obj.setBit(39, dx['RESPONSE CODE'])
- iso_obj.setBit(48, reply_content_bit48)
- msgx = "ISO8583 reply content :\r\n%s" % (iso_obj.getNetworkISO(bigEndian=True),)
- yield log_and_broadcast_data(msgx)
- # return the data and sent it to request, if it is not None
- try:
- if request is not None:
- # log.msg(request)
- request.write(iso_obj.getNetworkISO(bigEndian=True))
- except Exception as err:
- pass
- yield log_and_broadcast_data(err, True)
- if request is not None:
- request.loseConnection()
- yield dbconnection_obj.dbconnection.close()
- yield log_and_broadcast_data("Closing database connection")
- else:
- yield log_and_broadcast_data("Invalid database connection", True)
- yield log_and_broadcast_data("Request info customer finished")
- if request is not None:
- request.loseConnection()
- # returnValue(dx)
- except Exception as err:
- pass
- log.err(err)
- yield log_and_broadcast_data(err, True)
- # returnValue(None)
- # cleanup things
- try:
- if dbconnection_obj is not None:
- yield dbconnection_obj.dbconnection.close()
- if request is not None:
- request.loseConnection()
- except Exception as err:
- pass
- '''
- switching tcp server protocol
- '''
- class SwitchingServerProtocol(protocol.Protocol):
- '''
- init class
- '''
- # def __init__(self, factory):
- # self.factory = factory
- def connectionMade(self):
- try:
- ip, port = self.transport.client
- self.connected += 1
- # log.msg("Connection number #%d made from %s:%d" % (self.connected, ip, port))
- log_and_broadcast_data("Connection number #%d made from %s:%d" % (self.connected, ip, port))
- except Exception as err:
- pass
- log.err(err)
- def connectionLost(self, reason=connectionDone):
- try:
- ip, port = self.transport.client
- self.connected -= 1
- # log.msg("Connection lost from %s:%d with reason : %s" % (ip, port, reason))
- log_and_broadcast_data("Connection lost from %s:%d with reason : %s" % (ip, port, reason))
- except Exception as err:
- pass
- log.err(err)
- def dataReceived(self, data):
- try:
- ip, port = self.transport.client
- msgx = "Got data from %s:%d = %s" % (ip, port, data)
- log_and_broadcast_data(msgx)
- # parsing iso messages
- isox = PdamIso8583(isoFromNetwork=data)
- msgx = "Parsing =\r\n%s" % (isox.debug_iso(),)
- log_and_broadcast_data(msgx)
- #
- # # process it if valid
- # if isox.isValid:
- # msgx = isox.get_request_type()
- # log_and_broadcast_data(msgx)
- #
- # # idx = (isox.get_id_customer().strip())[0:3]
- # # unit = read_config_file(section_name="db-router", option_name=idx)
- # # log_and_broadcast_data("Unit %s" % (unit,))
- # #
- # # # unit valid
- # # if unit is not None:
- # # # process get info customer
- # # if isox.get_request_type() == PdamTransactionType.INQUIRY_CUSTOMER_INFO_REQUEST:
- # # # DB_CONNECTION_OBJ.get_info_customer(id_customer=isox.get_id_customer(), request=self.transport,
- # # # iso_obj=isox)
- # # PDAMProcessor().get_info_customer(id_customer=isox.get_id_customer(), request=self.transport,
- # # iso_obj=isox)
- # #
- # # # process payment request
- # # elif isox.get_request_type() == PdamTransactionType.INQUIRY_BILL_PAYMENT_REQUEST:
- # # # DB_CONNECTION_OBJ.get_payment_request_for_customer(request=self.transport, iso_obj=isox)
- # # PDAMProcessor().get_payment_request_for_customer(request=self.transport, iso_obj=isox)
- # #
- # # # unknown request
- # # else:
- # # log_and_broadcast_data("Unknown request. Are you OK??? *_*")
- # # else:
- # # log_and_broadcast_data("Unknown unit!!!")
- #
- # # process get info customer
- # if isox.get_request_type() == PdamTransactionType.INQUIRY_CUSTOMER_INFO_REQUEST:
- # PDAMProcessor().get_info_customer(id_customer=isox.get_id_customer(), request=self.transport,
- # iso_obj=isox)
- #
- # # process payment request
- # elif isox.get_request_type() == PdamTransactionType.INQUIRY_BILL_PAYMENT_REQUEST:
- # PDAMProcessor().get_payment_request_for_customer(request=self.transport, iso_obj=isox)
- #
- # # process payment reversal
- # elif isox.get_request_type() == PdamTransactionType.INQUIRY_BILL_REVERSAL:
- # PDAMProcessor().get_reversal_request_for_customer(request=self.transport, iso_obj=isox)
- #
- # # unknown request
- # else:
- # log_and_broadcast_data("Unknown request. Are you OK??? *_*", True)
- # self.transport.write(data)
- except Exception as err:
- pass
- log.err(err)
- '''
- switching tcp server factory
- '''
- class SwitchingServerFactory(protocol.ServerFactory):
- protocol = SwitchingServerProtocol
- def main_loop():
- """
- Main loop program
- """
- log.startLogging(sys.stdout)
- log.msg('Start your engines...')
- reactor.suggestThreadPoolSize(40)
- reactor.listenTCP(7000, SwitchingServerFactory())
- reactor.run()
- '''
- main program start here
- '''
- if __name__ == '__main__':
- main_loop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement