#!/usr/bin/env python3

import sys
import time
import subprocess
import select
import re
import argparse

update_every = 0.001
log_path = '/var/log/'
log_file = 'slapd'
log_file_path = log_path + log_file
rgx = dict()
connections = dict()
rgx['conn'] = re.compile(r'conn=(?P<conn>[0-9]+) .*?=.*? (?P<closed>closed)?')


def sleep(start_time):
    """After hard work, take a nap"""
    current_time = time.perf_counter()
    elapsed_time = current_time - start_time
    sleep_time = update_every - elapsed_time

    if sleep_time > 0:
        time.sleep(sleep_time)


def parse(line):
    """Parse line and print"""
    connect = rgx['connect'].search(line)

    if(connect):
        ip = connect.group('ip')
        port = connect.group('port')
        connection_id = connect.group('conn')

        if connection_id not in connections:
            connections[connection_id] = ip, port

        print(len(connections), ip, port, line, end='')

    else:
        conn = rgx['conn'].search(line)

        if(conn):
            connection_id = conn.group('conn')

            if connection_id in connections:
                ip, port = connections[connection_id]

                print(len(connections), ip, port, line, end='')

                if conn.group('closed'):
                    del connections[connection_id]


def tail_input(fin):
    """Open input file in tail mode"""
    poll = select.poll()
    poll.register(fin.stdout)

    try:
        while True:
            start_time = time.perf_counter()

            if poll.poll(1):
                line = fin.stdout.readline().decode('utf-8')

                parse(line)

            sleep(start_time)

    except KeyboardInterrupt:
        sys.stdout.flush()
        pass


def read_input(fin):
    """Read from input file"""
    try:
        for line in fin:
            parse(line)
    except KeyboardInterrupt:
        sys.stdout.flush()
        pass


def main():
    """Open file in non blocking mode and parse it"""
    parser = argparse.ArgumentParser(
        add_help=False,
        description='Parse from file or stdin'
    )
    parser.add_argument(
        '-f', '--follow',
        dest='follow', action='store_const', const=True,
        help='Output appended data as the file grows'
    )
    parser.add_argument(
        'pattern',
        type=str,
        help='Regex pattern'
    )
    parser.add_argument(
        'file',
        nargs='?', type=str,
        help='File to open'
    )
    parser.add_argument(
        '-h', '--help',
        action='help',
        help='Show this help message and exit'
    )
    arg = vars(parser.parse_args())

    rgx['connect'] = re.compile(''.join([r'conn=(?P<conn>[0-9]+).+?ACCEPT from IP=(?P<ip>',
                                arg['pattern'], r'):[0-9]+ \(IP=0\.0\.0\.0:(?P<port>[0-9]+)\)']))

    if arg['follow']:
        if arg['file']:
            path = arg['file']
        else:
            path = log_file_path

        fin = subprocess.Popen(['tail', '-F', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        tail_input(fin)

    else:
        if arg['file']:
            with open(arg['file'], 'r') as fin:
                read_input(fin)
        else:
            fin = sys.stdin
            read_input(fin)

    sys.exit(0)


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