#!/usr/bin/python3
# dopd stores the state of devices being provisioned by the remote-dop container.
# The information gathered is aggregated from several log sources via the redis
# dop channel, and stored in redis.
import sys
import os
import json
import redis
import signal
from remote_dop.target_device import TargetDevice, from_mac, from_ip
from remote_dop.util import normalise_host_addr

# Global handle for the redis connection.
redis_port = 6379
if 'REDIS_PORT' in os.environ:
    redis_port = os.environ['REDIS_PORT']

redis_handle = redis.StrictRedis(host="localhost", port=redis_port, db=0)
redis_channel = "dop"

# handle_message parses the json message from redis and actions it.
def handle_message(msg):
    # Strip any hangover quotes.
    msg = msg.decode("utf-8", "ignore").replace("\'", "")
    try:
        msg = json.loads(msg)
    except ValueError:
        print("json error parsing message")
        return

    normalised_host_addr = normalise_host_addr(msg.get('host_addr', None))

    # Find the stored device (if it exists), and update it with the new data.
    td = TargetDevice(redis_handle)
    if 'mac_addr' in msg:
        td = from_mac(td, msg['mac_addr'])
    elif normalised_host_addr:
        td = from_ip(td, normalised_host_addr)

    # Fill in the data that's there, performing some minor transforms.
    if 'mac_addr' in msg and msg['mac_addr'] is not None:
        td.mac = msg['mac_addr'].lower()
    if normalised_host_addr:
        td.ip = normalised_host_addr
    if 'class_name' in msg and msg['class_name'] is not None:
        td.add_bundle(msg['class_name'])
    if 'host_name' in msg and msg['host_name'] is not None:
        if msg['host_name'] != 'via':
            td.hostname = msg['host_name'].replace("(","").replace(")","")
    if 'ident' in msg and msg['ident'] is not None:
        td.vendor = msg['ident']
    if 'filename' in msg and msg['filename'] is not None:
        td.add_file_downloaded(os.path.basename(msg['filename']))
        # If the device is requesting a file, set provisioned to False in case
        # this is a re-provisioning
        td.provisioned = False
        td.post_provision_scripts_run = []

    td.save()

    return


def sigterm_handler(signum, frame):
    print("closing redis connection")
    redis_handle.connection_pool.disconnect()
    print("done")
    sys.exit(0)


signal.signal(signal.SIGTERM, sigterm_handler)
signal.signal(signal.SIGINT, sigterm_handler)


def main():
    print("connecting to redis")
    p = redis_handle.pubsub(ignore_subscribe_messages=True)
    p.subscribe(redis_channel)
    print(("subscribed to {}, waiting for messages...".format(redis_channel)))
    for message in p.listen():
        handle_message(message['data'])


if __name__ == "__main__":
    main()
