Advertisement
Guest User

sampel-gw-iso8583-dbx

a guest
Jun 2nd, 2018
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 18.16 KB | None | 0 0
  1. '''
  2. main library
  3. '''
  4. import sys
  5. import datetime
  6.  
  7. # signal osses
  8.  
  9. # argument parser
  10.  
  11. # lib for config file parser
  12.  
  13. # enumerate
  14.  
  15. # json
  16. import json
  17.  
  18. # datetime
  19.  
  20. # twisted
  21. # for web server part
  22. from enum import Enum
  23.  
  24. from twisted.enterprise import adbapi
  25. from twisted.internet import reactor, protocol
  26. from twisted.internet.defer import inlineCallbacks
  27. from twisted.internet.protocol import ServerFactory, ClientFactory, Protocol, connectionDone
  28. from twisted.web.resource import Resource
  29. from twisted.web.server import Site, NOT_DONE_YET
  30. from twisted.web.static import File
  31.  
  32. from twisted.python import log
  33.  
  34. # autobahn lib
  35.  
  36.  
  37. # ISO8583
  38. from ISO8583.ISO8583 import ISO8583
  39. from ISO8583.ISOErrors import *
  40.  
  41.  
  42. # enum request type
  43. class PdamTransactionType(Enum):
  44.     INQUIRY_CUSTOMER_INFO_REQUEST = 1
  45.     INQUIRY_BILL_PAYMENT_REQUEST = 2
  46.     INQUIRY_BILL_REVERSAL = 3
  47.     INQUIRY_INVALID = 255
  48.  
  49.  
  50. def log_and_broadcast_data(data, is_error=False, is_broadcasted=True):
  51.     """
  52.    log the data and broadcast to websocket client if enable
  53.    :param is_error: error info or not
  54.    :param data: data to log and broadcasted. will be cast to string
  55.    :param is_broadcasted: broadcast to websocket client
  56.    """
  57.     try:
  58.         if not is_error:
  59.             log.msg(data)
  60.         else:
  61.             log.err(data)
  62.  
  63.         # if is_broadcasted:
  64.         #     BroadcastServerFactory.broadcast_message(
  65.         #         {
  66.         #             'timestamp': time.time(),
  67.         #             'error': int(is_error),
  68.         #             'data': str(data)
  69.         #         })
  70.     except Exception as err:
  71.         pass
  72.         log.err(err)
  73.  
  74.  
  75. '''
  76. db connection class
  77. '''
  78.  
  79.  
  80. class DBConnection(object):
  81.  
  82.     def __init__(self, server=None, username=None, password=None, database_name=None, port=1433, timeout_query=45,
  83.                  timeout_login=10):
  84.         try:
  85.             # self._dbconnection = getattr(self, "_dbconnection", None)
  86.             # if self._dbconnection is None:
  87.             #     log.msg("Init new database connection")
  88.             #     self._dbconnection = adbapi.ConnectionPool("pymssql", user=username, password=password,
  89.             #                                                server=server, port=port, database=database_name,
  90.             #                                                timeout=timeout, tds_version='7.3')
  91.             # else:
  92.             #     log.msg("Database connection already established")
  93.             # log.msg(self._dbconnection)
  94.             # return self._dbconnection
  95.  
  96.             log.msg("Init new database connection")
  97.             self.dbconnection = adbapi.ConnectionPool("pymssql", cp_min=1, cp_max=2, user=username, password=password,
  98.                                                       server=server, port=port, database=database_name,
  99.                                                       timeout=timeout_query, login_timeout=timeout_login,
  100.                                                       tds_version='7.0')
  101.         except Exception as err:
  102.             pass
  103.             log.err(err)
  104.             self.dbconnection = None
  105.             return None
  106.  
  107.  
  108. '''
  109. iso8583 processor
  110. '''
  111.  
  112.  
  113. class PdamIso8583(ISO8583):
  114.  
  115.     def __init__(self, isoFromNetwork=None, isoStringContent=None, isBigEndian=True):
  116.         try:
  117.             super().__init__()
  118.  
  119.             if (isoFromNetwork is not None) and (isoStringContent is None):
  120.                 if isinstance(isoFromNetwork, bytes):
  121.                     self.setNetworkISO(isoFromNetwork, isBigEndian)
  122.                 else:
  123.                     self.setNetworkISO(isoFromNetwork.encode('latin1'), isBigEndian)
  124.  
  125.             if (isoFromNetwork is None) and (isoStringContent is not None):
  126.                 if isinstance(isoStringContent, bytes):
  127.                     self.setIsoContent(isoStringContent.decode('cp1252'))
  128.                 else:
  129.                     self.setIsoContent(isoStringContent)
  130.  
  131.             # log.msg(self.getBitsAndValues())
  132.             # log.msg(self.getNetworkISO(isBigEndian))
  133.             # return self
  134.  
  135.             self.isValid = True
  136.  
  137.         except Exception as err:
  138.             pass
  139.             log.err(err)
  140.             self.isValid = False
  141.             # return None
  142.  
  143.     '''
  144.    show debug iso content
  145.    '''
  146.  
  147.     def debug_iso(self):
  148.         try:
  149.             mtix = self.getMTI()
  150.             bitmapx = self.getBitmap()
  151.             vix = self.getBitsAndValues()
  152.  
  153.             result = "msgno[  0]<%d>\r\n" % (int(mtix),)
  154.             result += "bitmap: [%s]\r\n" % (bitmapx,)
  155.  
  156.             for v in vix:
  157.                 # print(self.getBit(int(v['bit'])))
  158.                 vx = v['value']
  159.                 nmx = self.getLargeBitName(int(v['bit']))
  160.                 # print(self.getLargeBitName(int(v['bit'])))
  161.                 if (v['type'] == 'LL') or (v['type'] == 'LLL') or (v['type'] == 'LLL'):
  162.                     lenx = len(v['type'])
  163.                     result += '%-48s out[ %3s: ] %4s <%s>\r\n' % (nmx, v['bit'], v['type'], vx[0:lenx])
  164.                     result += '%-48s out[ %3s: ] %4s <%s>\r\n' % (nmx, v['bit'], v['type'], vx[lenx:])
  165.                 else:
  166.                     result += '%-48s out[ %3s: ] %4s <%s>\r\n' % (nmx, v['bit'], v['type'], v['value'])
  167.  
  168.             return result
  169.  
  170.         except Exception as err:
  171.             pass
  172.             log.err(err)
  173.             return None
  174.  
  175.     def get_set_processing_code(self, proc_code=None):
  176.         try:
  177.             if proc_code is None:
  178.                 return self.getBit(3)
  179.             else:
  180.                 return self.setBit(3, proc_code)
  181.         except Exception as err:
  182.             pass
  183.             log.err(err)
  184.             return False
  185.  
  186.     def get_set_mti(self, mti=None):
  187.         try:
  188.             if mti is None:
  189.                 return self.getMTI()
  190.             else:
  191.                 return self.setMTI(mti)
  192.         except Exception as err:
  193.             pass
  194.             log.err(err)
  195.             return False
  196.  
  197.     def get_id_customer(self):
  198.         try:
  199.             return ((self.getBit(48))[3:]).strip()
  200.         except Exception as err:
  201.             pass
  202.             log.err(err)
  203.             return None
  204.  
  205.     def get_user_data_content(self):
  206.         try:
  207.             return ((self.getBit(48))[3:]).strip()
  208.         except Exception as err:
  209.             pass
  210.             log.err(err)
  211.             return None
  212.  
  213.     def get_trace_number(self):
  214.         try:
  215.             return self.getBit(11).strip()
  216.         except Exception as err:
  217.             pass
  218.             log.err(err)
  219.             return None
  220.  
  221.     def get_request_type(self):
  222.         try:
  223.             mtix = self.get_set_mti()
  224.             procx = self.get_set_processing_code()
  225.             if (mtix == "0200") and (procx[0:2] == "38") and (procx[-2:] == "98"):
  226.                 return PdamTransactionType.INQUIRY_CUSTOMER_INFO_REQUEST
  227.  
  228.             if (mtix == "0200") and (procx[0:2] == "17") and (procx[-2:] == "98"):
  229.                 return PdamTransactionType.INQUIRY_BILL_PAYMENT_REQUEST
  230.  
  231.             if (mtix == "0420") and (procx[0:2] == "17") and (procx[-2:] == "98"):
  232.                 return PdamTransactionType.INQUIRY_BILL_REVERSAL
  233.  
  234.             return PdamTransactionType.INQUIRY_INVALID
  235.         except Exception as err:
  236.             pass
  237.             log.err(err)
  238.             return PdamTransactionType.INQUIRY_INVALID
  239.  
  240.  
  241. class PDAMProcessor(object):
  242.  
  243.     # @staticmethod
  244.     @staticmethod
  245.     def get_database_connection_object(id_customer=None):
  246.         """
  247.        build db object
  248.        :param id_customer:
  249.        :return:
  250.        """
  251.         try:
  252.             # idx = (id_customer.strip())[0:3]
  253.             # idy = int(idx)
  254.             # if idy in range(100, 1000):
  255.             #     idy = (idy // 100) * 100
  256.             #     idx = str(idy)
  257.             #
  258.             # unit = read_config_file(CONFIG_FILE, section_name="db-router", option_name=idx)
  259.             # servername = read_config_file(CONFIG_FILE, section_name=unit, option_name="host")
  260.             # portnumber = int(read_config_file(CONFIG_FILE, section_name=unit, option_name="port"))
  261.             # db_username = read_config_file(CONFIG_FILE, section_name=unit, option_name="username")
  262.             # db_password = read_config_file(CONFIG_FILE, section_name=unit, option_name="password")
  263.             # db_name = read_config_file(CONFIG_FILE, section_name=unit, option_name="database")
  264.  
  265.             log_and_broadcast_data("Making connection to %s at %s:%d" % (unit, servername, portnumber))
  266.  
  267.             return DBConnection(server=servername, port=portnumber, username=db_username, password=db_password,
  268.                                 database_name=db_name)
  269.         except Exception as err:
  270.             pass
  271.             log.err(err)
  272.             return None
  273.  
  274.     @inlineCallbacks
  275.     def get_info_customer(self, id_customer=None, request=None, iso_obj=None):
  276.         """
  277.        Get info customer
  278.  
  279.        :param id_customer:
  280.        :param request:
  281.        """
  282.         try:
  283.             yield log_and_broadcast_data("Get customer info")
  284.  
  285.             # get db config
  286.             dbconnection_obj = self.get_database_connection_object(iso_obj.get_id_customer())
  287.  
  288.             # got any valid db connection?
  289.             if dbconnection_obj is not None:
  290.                 # run the query
  291.                 customer_info = yield dbconnection_obj.dbconnection.runQuery("exec spcektgh '%s'" % (id_customer,))
  292.  
  293.                 # format the return into dict
  294.                 fd = (
  295.                     'IDPEL', 'NAMA', 'ALAMAT', 'TARIP', 'DAYA', 'GARDU', 'GOLONGAN', 'FJN', 'F_METER', 'STAND1',
  296.                     'STAND2',
  297.                     'STAND3', 'BLN1', 'REK1', 'PPJ1', 'PPN1', 'SEWA1', 'DENDA1', 'MET1', 'TGH1', 'BLN2', 'REK2', 'PPJ2',
  298.                     'PPN2', 'SEWA2', 'DENDA2', 'MET2', 'TGH2', 'BLN3', 'REK3', 'PPJ3', 'PPN3', 'SEWA3', 'DENDA3',
  299.                     'MET3', 'TGH3', 'GRANDTOTAL', 'TOTALREC', 'RESPONSE CODE')
  300.                 dx = dict(zip(fd, customer_info[0]))
  301.  
  302.                 yield log_and_broadcast_data(dx)
  303.  
  304.                 # format the reply content
  305.                 number_of_bill = int(len(dx['BLN1']) > 0) + int(len(dx['BLN2']) > 0) + int(len(dx['BLN3']) > 0)
  306.                 bill_detail = ""
  307.                 for id_bill in range(1, (number_of_bill + 1)):
  308.                     bill_detail += "%-6s%8u%12u%12u%12u%12u%12u%12u%12u" % (
  309.                         dx['BLN' + str(id_bill)],
  310.                         int(dx['STAND' + str(id_bill)]) * 100,
  311.                         int(dx['REK' + str(id_bill)]) * 100,
  312.                         int(dx['PPJ' + str(id_bill)]) * 100,
  313.                         int(dx['PPN' + str(id_bill)]) * 100,
  314.                         int(dx['SEWA' + str(id_bill)]) * 100,
  315.                         int(dx['DENDA' + str(id_bill)]) * 100,
  316.                         int(dx['MET' + str(id_bill)]) * 100,
  317.                         int(dx['TGH' + str(id_bill)]) * 100)
  318.                 # log.msg(bill_detail)
  319.  
  320.                 reply_content_bit48 = "%-12s%-20s%-20s%2s%6s%20s%s%04d%08d%12u%u%8s%42s%s" % (
  321.                     dx['IDPEL'],
  322.                     dx['NAMA'],
  323.                     dx['ALAMAT'],
  324.                     " ",
  325.                     " ",
  326.                     dx['TARIP'],
  327.                     " ",
  328.                     0,
  329.                     0,
  330.                     dx['GRANDTOTAL'] * 100,
  331.                     number_of_bill,
  332.                     " ",
  333.                     " ",
  334.                     bill_detail)
  335.                 # reply_len = len(reply_content_bit48)
  336.                 # reply_content_bit48 = "%03u%s" % (reply_len, reply_content_bit48)
  337.  
  338.                 # log.msg(len(reply_content_bit48))
  339.                 # log.msg(reply_content_bit48)
  340.  
  341.                 # update the iso
  342.                 # log.msg(iso_obj)
  343.                 if iso_obj is not None:
  344.                     iso_obj.get_set_mti("0210")
  345.                     iso_obj.setBit(39, dx['RESPONSE CODE'])
  346.                     iso_obj.setBit(48, reply_content_bit48)
  347.  
  348.                     msgx = "ISO8583 reply content :\r\n%s" % (iso_obj.getNetworkISO(bigEndian=True),)
  349.                     yield log_and_broadcast_data(msgx)
  350.  
  351.                 # return the data and sent it to request, if it is not None
  352.                 try:
  353.                     if request is not None:
  354.                         # log.msg(request)
  355.                         request.write(iso_obj.getNetworkISO(bigEndian=True))
  356.                 except Exception as err:
  357.                     pass
  358.                     yield log_and_broadcast_data(err, True)
  359.  
  360.                 if request is not None:
  361.                     request.loseConnection()
  362.  
  363.                 yield dbconnection_obj.dbconnection.close()
  364.                 yield log_and_broadcast_data("Closing database connection")
  365.             else:
  366.                 yield log_and_broadcast_data("Invalid database connection", True)
  367.  
  368.             yield log_and_broadcast_data("Request info customer finished")
  369.  
  370.             if request is not None:
  371.                 request.loseConnection()
  372.  
  373.             # returnValue(dx)
  374.         except Exception as err:
  375.             pass
  376.             log.err(err)
  377.             yield log_and_broadcast_data(err, True)
  378.             # returnValue(None)
  379.  
  380.         # cleanup things
  381.         try:
  382.             if dbconnection_obj is not None:
  383.                 yield dbconnection_obj.dbconnection.close()
  384.  
  385.             if request is not None:
  386.                 request.loseConnection()
  387.         except Exception as err:
  388.             pass
  389.  
  390.  
  391. '''
  392. switching tcp server protocol
  393. '''
  394.  
  395.  
  396. class SwitchingServerProtocol(protocol.Protocol):
  397.     '''
  398.    init class
  399.    '''
  400.  
  401.     # def __init__(self, factory):
  402.     #     self.factory = factory
  403.     def connectionMade(self):
  404.         try:
  405.             ip, port = self.transport.client
  406.             self.connected += 1
  407.             # log.msg("Connection number #%d made from %s:%d" % (self.connected, ip, port))
  408.             log_and_broadcast_data("Connection number #%d made from %s:%d" % (self.connected, ip, port))
  409.         except Exception as err:
  410.             pass
  411.             log.err(err)
  412.  
  413.     def connectionLost(self, reason=connectionDone):
  414.         try:
  415.             ip, port = self.transport.client
  416.             self.connected -= 1
  417.             # log.msg("Connection lost from %s:%d with reason : %s" % (ip, port, reason))
  418.             log_and_broadcast_data("Connection lost from %s:%d with reason : %s" % (ip, port, reason))
  419.         except Exception as err:
  420.             pass
  421.             log.err(err)
  422.  
  423.     def dataReceived(self, data):
  424.         try:
  425.             ip, port = self.transport.client
  426.             msgx = "Got data from %s:%d = %s" % (ip, port, data)
  427.             log_and_broadcast_data(msgx)
  428.  
  429.             # parsing iso messages
  430.             isox = PdamIso8583(isoFromNetwork=data)
  431.             msgx = "Parsing =\r\n%s" % (isox.debug_iso(),)
  432.             log_and_broadcast_data(msgx)
  433.             #
  434.             # # process it if valid
  435.             # if isox.isValid:
  436.             #     msgx = isox.get_request_type()
  437.             #     log_and_broadcast_data(msgx)
  438.             #
  439.             #     # idx = (isox.get_id_customer().strip())[0:3]
  440.             #     # unit = read_config_file(section_name="db-router", option_name=idx)
  441.             #     # log_and_broadcast_data("Unit %s" % (unit,))
  442.             #     #
  443.             #     # # unit valid
  444.             #     # if unit is not None:
  445.             #     #     # process get info customer
  446.             #     #     if isox.get_request_type() == PdamTransactionType.INQUIRY_CUSTOMER_INFO_REQUEST:
  447.             #     #         # DB_CONNECTION_OBJ.get_info_customer(id_customer=isox.get_id_customer(), request=self.transport,
  448.             #     #         #                                     iso_obj=isox)
  449.             #     #         PDAMProcessor().get_info_customer(id_customer=isox.get_id_customer(), request=self.transport,
  450.             #     #                                           iso_obj=isox)
  451.             #     #
  452.             #     #     # process payment request
  453.             #     #     elif isox.get_request_type() == PdamTransactionType.INQUIRY_BILL_PAYMENT_REQUEST:
  454.             #     #         # DB_CONNECTION_OBJ.get_payment_request_for_customer(request=self.transport, iso_obj=isox)
  455.             #     #         PDAMProcessor().get_payment_request_for_customer(request=self.transport, iso_obj=isox)
  456.             #     #
  457.             #     #     # unknown request
  458.             #     #     else:
  459.             #     #         log_and_broadcast_data("Unknown request. Are you OK??? *_*")
  460.             #     # else:
  461.             #     #     log_and_broadcast_data("Unknown unit!!!")
  462.             #
  463.             #     # process get info customer
  464.             #     if isox.get_request_type() == PdamTransactionType.INQUIRY_CUSTOMER_INFO_REQUEST:
  465.             #         PDAMProcessor().get_info_customer(id_customer=isox.get_id_customer(), request=self.transport,
  466.             #                                           iso_obj=isox)
  467.             #
  468.             #     # process payment request
  469.             #     elif isox.get_request_type() == PdamTransactionType.INQUIRY_BILL_PAYMENT_REQUEST:
  470.             #         PDAMProcessor().get_payment_request_for_customer(request=self.transport, iso_obj=isox)
  471.             #
  472.             #     # process payment reversal
  473.             #     elif isox.get_request_type() == PdamTransactionType.INQUIRY_BILL_REVERSAL:
  474.             #         PDAMProcessor().get_reversal_request_for_customer(request=self.transport, iso_obj=isox)
  475.             #
  476.             #     # unknown request
  477.             #     else:
  478.             #         log_and_broadcast_data("Unknown request. Are you OK??? *_*", True)
  479.  
  480.         # self.transport.write(data)
  481.  
  482.         except Exception as err:
  483.             pass
  484.             log.err(err)
  485.  
  486.  
  487. '''
  488. switching tcp server factory
  489. '''
  490.  
  491.  
  492. class SwitchingServerFactory(protocol.ServerFactory):
  493.     protocol = SwitchingServerProtocol
  494.  
  495.  
  496. def main_loop():
  497.     """
  498.    Main loop program
  499.    """
  500.     log.startLogging(sys.stdout)
  501.     log.msg('Start your engines...')
  502.  
  503.     reactor.suggestThreadPoolSize(40)
  504.     reactor.listenTCP(7000, SwitchingServerFactory())
  505.     reactor.run()
  506.  
  507.  
  508. '''
  509. main program start here
  510. '''
  511. if __name__ == '__main__':
  512.     main_loop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement