web_client.py 5.01 KB
import sys
import requests
import json
from datetime import datetime
from time import (
    sleep,
    time,
    )
from threading import Thread
from argparse import ArgumentParser


headers = {'content-type': 'application/json'}
threads = {}
end_threads = []
durations = {}
json_responses = {}

default_url = 'http://localhost:7000/rpc'
default_host = 'pemda'
default_count = 1

help_url = 'default ' + default_url
help_host = 'default ' + default_host
help_count = 'default {}'.format(default_count)
help_invoice_id = 'wajib saat --payment dan --reversal'
help_amount = 'wajib saat --payment dan --reversal'
help_ntb = 'opsional saat --payment, wajib saat --reversal'
help_stan = 'opsional saat --payment, wajib saat --reversal'
help_bit = 'bit tambahan, contoh: --bit=42:TOKOPEDIA'
help_conf = 'konfigurasi tambahan, contoh untuk multi: --conf=pajak:bphtb'


def error(s):
    print('ERROR: {}'.format(s))
    sys.exit()


def required(name, default=None):
    value = getattr(option, name)
    if not value and not default:
        error('--{} harus diisi'.format(name))
    p[name] = value or default


def log_info(s):
    t = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
    t = t[:-3]
    msg = '{} {}'.format(t, s)
    print(msg)


def get_option(argv):
    parser = ArgumentParser()
    parser.add_argument('--url', default=default_url, help=help_url)
    parser.add_argument('--host', default=default_host, help=help_host)
    parser.add_argument(
        '--count', type=int, default=default_count, help=help_count)
    parser.add_argument('--invoice-id', help=help_invoice_id)
    parser.add_argument('--payment', action='store_true')
    parser.add_argument('--reversal', action='store_true')
    parser.add_argument('--amount', type=int, help=help_amount)
    parser.add_argument('--ntb', help=help_ntb)
    parser.add_argument('--stan', help=help_stan)
    parser.add_argument('--bit', help=help_bit)
    parser.add_argument('--conf', help=help_conf)
    return parser.parse_args(argv)


class App:
    def __init__(self, argv):
        self.option = get_option(argv)

    def set_transaction(self, p):
        p['invoice_id'] = self.option.invoice_id
        if self.option.payment or self.option.reversal:
            required('amount')
            if self.option.method == 'payment':
                required('ntb', datetime.now().strftime('%m%d%H%m%s'))
                required('stan', datetime.now().strftime('%H%M%S'))
            else:
                required('ntb')
                required('stan')
        if self.option.bit:
            bits = dict()
            for t in self.option.bit.split(','):
                bit, value = t.split(':')
                bits[bit] = value
            p['bits'] = bits
        if self.option.conf:
            conf = dict()
            for t in self.option.conf.split(','):
                key, val = t.split(':')
                conf[key] = val
            p['conf'] = conf

    def send(self, p):
        key = p['id']
        log_info('Request: {}'.format(p))
        start = time()
        try:
            resp = requests.post(
                    self.option.url, data=json.dumps(p), headers=headers)
            durations[key] = time() - start
            json_resp = resp.json()
            log_info('Response: {}'.format(json_resp))
            json_responses[key] = json_resp
        finally:
            end_threads.append(key)

    def create_thread(self, args=[]):
        thread = Thread(target=self.send, args=args)
        # Exit the server thread when the main thread terminates
        thread.daemon = True
        return thread

    def run(self):
        p = dict(host=self.option.host)
        if self.option.invoice_id:
            self.set_transaction(p)
            if self.option.payment:
                method = 'payment'
            elif self.option.reversal:
                method = 'reversal'
            else:
                method = 'inquiry'
        else:
            method = 'echo'
        data = dict(method=method, params=[p], jsonrpc='2.0')
        for i in range(self.option.count):
            data['id'] = i
            thread = self.create_thread([dict(data)])
            threads[i] = thread
        for key in threads:
            thread = threads[key]
            thread.start()
            sleep(0.2)
        while threads:
            sleep(1)
            if not end_threads:
                continue
            i = end_threads[0]
            if i in threads:
                thread = threads[i]
                thread.join()
                del threads[i]
            index = end_threads.index(i)
            del end_threads[index]
        for key in durations:
            val = durations[key]
            resp = json_responses[key]
            if 'error' in resp:
                break
            result = resp['result']
            if result['code'] == 0:
                stan = result['data']['11']
            else:
                stan = '-'
            msg = 'thread {} stan {} {} detik'.format(key, stan, val)
            log_info(msg)


def main(argv=sys.argv[1:]):
    app = App(argv)
    app.run()