def post_delivery_issue(request):
    """
    Notify that a specific delivery has had an issue.
    :return:
    """

    initiated_routes = {k: v for k, v in routes.items() if v == "initiated"}
    if len(initiated_routes) > 0:
        issue_encountered = choice(list(initiated_routes))
        routes[issue_encountered] = "has_issue"
        # Build message
        message, request_id = make_kafka_message(
            action="DELIVERY_ISSUE",
            message={
                "delivery_uuid":
                deliveries[issue_encountered],
                "issue_type":
                "DELIVERY_MISSING"
                if randint(1, 2) > 1 else "DAMAGED_DELIVERY",
                "time":
                str(datetime.datetime.now().replace(
                    microsecond=0).isoformat()),
            },
        )

        # Send
        threads_mq["delivery"].put(message)

        # Response with callback url
        return json.dumps(dict(message))
    return "oupsy"
def post_delivery_route(request):
    """
    Create a new delivery
    :return:
    """
    created_routes = {k: v for k, v in routes.items() if v == "created"}
    # Build message
    if len(created_routes) > 0:
        to_init = choice(list(created_routes))
        delivery_id = str(uuid.uuid4())
        routes[to_init] = "initiated"
        deliveries[to_init] = delivery_id
        message, request_id = make_kafka_message(
            action="DELIVERY_INITIATED",
            message={
                "delivery_uuid":
                delivery_id,
                "city":
                cities[region][randint(0,
                                       len(cities[region]) - 1)],
                "time":
                str(datetime.datetime.now().replace(
                    microsecond=0).isoformat()),
                "route_uuid":
                to_init,
            },
        )

        # Send
        threads_mq["delivery"].put(message)

        # Response with callback url
        return json.dumps(dict(message))
    return "oupsy"
def post_delivery_checkpoint_route(request):
    """
    Notify that the delivery has reached a checkpoint
    :return:
    """
    # Build message
    is_final_destination = False
    if randint(0, 1) > 0:
        is_final_destination = True
    message, request_id = make_kafka_message(
        action="DELIVERY_CHECKPOINT",
        message={
            "delivery_id": randint(1, 9999),
            "city": cities[region][randint(0,
                                           len(cities[region]) - 1)],
            "time":
            str(datetime.datetime.now().replace(microsecond=0).isoformat()),
            "isFinalDestination": is_final_destination,
        },
    )

    # Send
    threads_mq["delivery"].put(message)

    # Response with callback url
    return json.dumps(dict(message))
def post_route(request):
    """
    Create a new route
    :return:
    """
    uuid_route = str(uuid.uuid4())
    # Build message
    message, request_id = make_kafka_message(
        action="ROUTE_CREATED",
        message={
            "route_uuid": uuid_route,
            "time":
            str(datetime.datetime.now().replace(microsecond=0).isoformat()),
            "initial_city": cities[region][randint(0,
                                                   len(cities[region]) - 1)],
            "end_city": cities[region][randint(0,
                                               len(cities[region]) - 1)],
        },
    )

    # Send
    threads_mq["delivery"].put(message)
    print("route created")
    # Store the route
    routes[uuid_route] = "created"
    print("Length : " + str(len(routes)))
    # Response with callback url
    return json.dumps(dict(message))
def post_route_cancellation(request):
    """
    Cancel a route
    :return:
    """
    created_routes = {k: v for k, v in routes.items() if v == "created"}
    if len(created_routes) > 0:
        to_cancel = choice(list(created_routes))
        routes.pop(to_cancel)
        # Build message
        message, request_id = make_kafka_message(
            action="ROUTE_CANCELED",
            message={
                "route_uuid":
                to_cancel,
                "time":
                str(datetime.datetime.now().replace(
                    microsecond=0).isoformat()),
            },
        )

        # Send
        threads_mq["delivery"].put(message)

        # Response with callback url
        return json.dumps(dict(message))
    return "oupsy"
def post_delivery_item(request):
    """
    Add an item to a delivery
    :return:
    """

    # Build message
    initiated_routes = {k: v for k, v in routes.items() if v == "initiated"}
    if len(initiated_routes) > 0:
        item_delivered = choice(list(initiated_routes))
        message, request_id = make_kafka_message(
            action="DELIVERY_ITEM",
            message={
                "delivery_uuid":
                deliveries[item_delivered],
                "item_type":
                items[randint(0,
                              len(items) - 1)],
                "time":
                str(datetime.datetime.now().replace(
                    microsecond=0).isoformat()),
            },
        )
        # Send
        threads_mq["delivery"].put(message)
        # Response with callback url
        return json.dumps(dict(message))
    return "oupsy"
def kafka_consumer_worker(t_stop_event: threading.Event,
                          bootstrap_servers: str, topic: str, region: str,
                          service_name: str, threads_mq: dict):
    """
    Kafka Generic Message Consumer, as thread worker
    Push back messages to shared Queue
    :param t_stop_event: threading.Event
    :param bootstrap_servers: str
    :param topic: str
    :param region:
    :param service_name: str
    :param threads_mq: dict
    :return:
    """

    # region
    if len(region) == 0:
        region = "world"

    # Client
    consumer = KafkaConsumer(
        topic,
        bootstrap_servers=bootstrap_servers,
        value_deserializer=lambda item: json.loads(item.decode('utf-8')))

    while not t_stop_event.is_set():
        try:
            # Message loop
            for message in consumer:
                print("READING MESSAGE %s:%d:%d: key=%s value=%s" %
                      (message.topic, message.partition, message.offset,
                       message.key, message.value))

                # simple sanitizer
                if 'action' not in message.value:
                    print("MALFORMED MESSAGE value=%s SKIPPING" %
                          (message.value, ))
                    continue

                # Action switch
                if str(message.value["action"]).upper(
                ) == 'HEARTBEAT_BROADCAST':
                    print("SENDING HEARTBEAT FOR " + service_name)
                    # Send
                    hb, request_id = make_kafka_message(
                        action='HEARTBEAT_REPLY',
                        message={
                            'service_name': str(service_name),
                            'region': str(region),
                            'timestamp':
                            int(datetime.datetime.now().timestamp())
                        })
                    threads_mq['heartbeat'].put(hb)
        except Exception as e:
            print(e)

    consumer.close()
    return
def get_kpi_city_top10_route():
    """
    Ask the system the most active cities by initiated deliveries
    :return:
    """
    # Build message
    message, request_id = make_kafka_message(action='KPI_CITY_TOP10_BROADCAST',
                                             message={})

    # Send
    threads_mq['kpi'].put(message)

    # Response with callback url
    return json.dumps(dict(message), )
def post_user_timeout_route(request):
    """
    The system has no more request from the previously signed in user for the last 30 minutes
    :return:
    """
    # Build message
    message, request_id = make_kafka_message(action='USER_TIMED_OUT',
                                             message={})

    # Send
    threads_mq['user'].put(message)

    # Response with callback url
    return json.dumps(dict(message), )
def post_user_register_route(request):
    """
    A new user has registered the system
    :return:
    """
    # Build message
    message, request_id = make_kafka_message(action='USER_REGISTERED',
                                             message={})

    # Send
    threads_mq['user'].put(message)

    # Response with callback url
    return json.dumps(dict(message), )
def post_user_logout_route(request):
    """
    A known user has signed off
    :return:
    """
    # Build message
    message, request_id = make_kafka_message(action='USER_LOGGED_OUT',
                                             message={})

    # Send
    threads_mq['user'].put(message)

    # Response with callback url
    return json.dumps(dict(message), )
def post_user_login_route(request):
    """
    A known user has signed in
    :return:
    """

    st = datetime.datetime.now().replace(microsecond=0).isoformat()
    # Build message
    message, request_id = make_kafka_message(action='USER_LOGGED_IN',
                                             message={
                                                 'time': st,
                                                 'uuid': str(uuid.uuid4())
                                             })

    # Send
    threads_mq['user'].put(message)

    # Response with callback url
    return json.dumps(dict(message), )