#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
from __future__ import print_function

import hashlib
import socket
import struct
import sys

HOST = '203.73.22.167'
PORT = 12202
CHANNEL_ID = 6
CHANNEL_KEY = '45678'
SEQ_NUM = 0
TIMEOUT_SEC = 3

CMD_ID = 0x0301
PROTO_HEADER_FMT = '<IIHII'
VERIFY_HEADER_FMT = '<H32s'
REQ_BODY_FMT = '<III64s'
ACK_BODY_FMT = '<Q'
PROTO_HEADER_SIZE = struct.calcsize(PROTO_HEADER_FMT)
ACK_BODY_SIZE = struct.calcsize(ACK_BODY_FMT)


def recv_all(sock, size):
    chunks = []
    received = 0
    while received < size:
        chunk = sock.recv(size - received)
        if not chunk:
            raise RuntimeError('socket closed')
        chunks.append(chunk)
        received += len(chunk)
    return b''.join(chunks)


def build_verify_header(channel_id, body):
    prefix = ('channelId=%d&securityCode=%s&data=' % (channel_id, CHANNEL_KEY)).encode('ascii')
    digest = hashlib.md5(prefix + body).hexdigest().encode('ascii')
    return struct.pack(VERIFY_HEADER_FMT, channel_id, digest)


def send_request(user_id, mb_num):
    body_without_verify = struct.pack(
        REQ_BODY_FMT,
        mb_num,
        0,
        0,
        b'\x00' * 64)
    body = build_verify_header(CHANNEL_ID, body_without_verify) + body_without_verify
    packet = struct.pack(
        PROTO_HEADER_FMT,
        PROTO_HEADER_SIZE + len(body),
        SEQ_NUM,
        CMD_ID,
        0,
        user_id) + body

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(TIMEOUT_SEC)
    try:
        sock.connect((HOST, PORT))
        sock.sendall(packet)
        header_prefix = recv_all(sock, 4)
        pkg_len = struct.unpack('<I', header_prefix)[0]
        if pkg_len < PROTO_HEADER_SIZE:
            raise RuntimeError('invalid pkg_len=%u' % pkg_len)
        payload = recv_all(sock, pkg_len - 4)
        return header_prefix + payload
    finally:
        sock.close()


def main():
    if len(sys.argv) != 3:
        print('usage: python2.7 add_mb.py userid mb_num')
        return 1

    user_id = int(sys.argv[1])
    mb_num = int(sys.argv[2])

    try:
        response = send_request(user_id, mb_num)
    except Exception as err:
        print('cmd_id=%u' % CMD_ID)
        print('userid=%u' % user_id)
        print('mb_num=%u' % mb_num)
        print('error=%s' % err)
        return 1

    pkg_len, seq_num, cmd_id, status_code, ack_user_id = struct.unpack(
        PROTO_HEADER_FMT, response[:PROTO_HEADER_SIZE])

    print('pkg_len=%u' % pkg_len)
    print('seq_num=%u' % seq_num)
    print('cmd_id=%u' % cmd_id)
    print('status_code=%u' % status_code)
    print('userid=%u' % ack_user_id)

    body_len = len(response) - PROTO_HEADER_SIZE
    print('body_len=%u' % body_len)
    if body_len >= ACK_BODY_SIZE:
        transaction_id, = struct.unpack(
            ACK_BODY_FMT,
            response[PROTO_HEADER_SIZE:PROTO_HEADER_SIZE + ACK_BODY_SIZE])
        print('transaction_id=%u' % transaction_id)

    return 0 if status_code == 0 else 1


if __name__ == '__main__':
    sys.exit(main())

