#
#   logactio  -  simple framework for doing configured action on certain
#                log file events
#
# SPDX-FileCopyrightText: Copyright 2012-  David Sommerseth <dazo@eurephia.org>
# SPDX-License-Identifier: GPL-2.0-only
#

import json
import sys
import urllib.parse
import urllib.request
from LogActio import Message, ReporterQueue


class HTTPreporter(ReporterQueue.ReporterQueue):
    """Simple LogActio reporter module, sending alerts via HTTP/HTTPS

    Example configuration to be used in /etc/logactio.cfg

        [Reporter:HTTP]
        module: HTTPreporter
        method: POST
        url: http://alerts.example.com/logactio/alerts.php
        format: plain

    This will send reports to the given URL using POST.  If you want
    to use GET instead of POST, modify or remove the 'method' variable.

    The 'format' setting controls the request body encoding:
      plain  (default) - application/x-www-form-urlencoded, works with GET and POST
      json             - application/json with a JSON body, requires method POST
    """

    def __init__(self, config, logger=None):
        if "url" not in config:
            raise Exception("HTTPreporter is not configured with a URL")

        self.__method = config.get("method", "GET")
        self.__url = config["url"]
        self.__format = config.get("format", "plain")
        self.__log = logger if logger is not None else self.__logfnc

        if self.__method not in ("GET", "POST"):
            raise Exception(f"HTTPreporter is configured with an invalid submission method: "
                            f"'{self.__method}'")

        if self.__format not in ("plain", "json"):
            raise Exception(f"HTTPreporter is configured with an invalid format: "
                            f"'{self.__format}'")

        if self.__format == "json" and self.__method != "POST":
            raise Exception("HTTPreporter: format 'json' requires method POST")

        super().__init__("HTTPreporter", "HTTP Reporter", self.__processqueue)

    def __logfnc(self, lvl, msg):
        print(msg)
        sys.stdout.flush()


    def __processqueue(self):
        done = False

        # Process the message queue
        while not done:
            msg = self._QueueGet()

            if msg.MessageType() == Message.MSG_SHUTDOWN:
                done = True

            elif msg.MessageType() == Message.MSG_SEND:
                m = msg.Message()
                m["priority"] = msg.Priority()

                if self.__method == "GET":
                    m["message"] = "|".join(m.pop("matches"))
                    data = urllib.parse.urlencode(m)
                    req = urllib.request.Request(f"{self.__url}?{data}")
                    self.__log(1, f"[HTTPreporter] GET {self.__url}?{data}")
                elif self.__method == "POST":
                    if self.__format == "json":
                        body = json.dumps(m).encode()
                        req = urllib.request.Request(
                            self.__url, data=body,
                            headers={"Content-Type": "application/json"})
                        self.__log(1, f"[HTTPreporter] POST {self.__url} {{{body.decode()}}}")
                    else:
                        m["message"] = "|".join(m.pop("matches"))
                        data = urllib.parse.urlencode(m)
                        req = urllib.request.Request(self.__url, data.encode())
                        self.__log(1, f"[HTTPreporter] POST {self.__url} {{{data}}}")
                else:
                    self.__log(0, f"[HTTPreporter] Unknown method '{self.__method}'")
                    continue
                res = urllib.request.urlopen(req)
                self.__log(4, f"[HTTPreporter] Response: {res.read()}")


    def ProcessEvent(self, logfile, prefix, msg, count, threshold):
        # Queue the raw regex matches as a list; __processqueue shapes them per format
        msg = {"prefix": prefix, "count": count, "threshold": threshold,
               "matches": list(msg), "logfile": logfile}

        # Queue the message for sending
        self._QueueMsg(0, msg)


def InitReporter(config, logger=None):
    return HTTPreporter(config, logger)
