def lambda_handler()

in BackendServices/functions/updateredis.py [0:0]


def lambda_handler(event, context):

    # The TTL in Redis for game server data. We expect updates every 15 seconds from game servers so leave 5 seconds headroom
    gameserverdata_ttl = 20.0

    # Get redis endpoint and set up
    redis_endpoint = os.environ['REDIS_ENDPOINT']
    # Setup Redis client
    redis_client = redis.Redis(host=redis_endpoint, port=6379, db=0)

    # Get the parameters from the server
    server_in_use = event["serverInUse"]
    taskArn = event["taskArn"] # This includes the container (taskarn-containerX)
    current_players = event["currentPlayers"]
    max_players = event["maxPlayers"]
    ready = event["ready"]
    publicIP = event["publicIP"]
    port = event["port"]
    serverTerminated = event["serverTerminated"]

    # Get only the Task arn (as taskArn also includes the game server container)
    onlyTaskArn = taskArn.split("-container")[0]

    print("server_in_use: " + str(server_in_use))
    print("taskArn with container: " + str(taskArn))
    print("Only TaskArn: " + str(onlyTaskArn))
    print("current_players: " + str(current_players))
    print("max_players: " + str(max_players))
    print("ready: " + str(ready))
    print("publicIP: " + str(publicIP))
    print("port: " + str(port))
    print("serverTerminated: " + str(serverTerminated))

    # Check for outdated player session reservations
    # Get the last reservation time and check against current time. It could be active, available or available_priority
    game_server_key = "available-gameserver-"+taskArn
    last_reservation_time = redis_client.hget(game_server_key, "last-reservation-time")
    current_reservations = None
    # No reservation time in available, try priority
    if last_reservation_time == None:
        game_server_key = "available-priority-gameserver-"+taskArn
        last_reservation_time = redis_client.hget(game_server_key, "last-reservation-time")
    # No reservation time in available or priority, try active
    if last_reservation_time == None:
        game_server_key = "active-gameserver-"+taskArn
        last_reservation_time = redis_client.hget(game_server_key, "last-reservation-time")
    if last_reservation_time != None:
        print("Found last reservation time: " + str(last_reservation_time))
        timedifference = time.time() - float(last_reservation_time)
        print("time since last reservation: " + str(timedifference))
        current_reservations = redis_client.hget(game_server_key, "reserved-player-slots")
        # If 30s passed, clamp reservations to currentplayers --> update with hset
        if timedifference > 30.0:
            print("Clear outdated reservations")
            if current_reservations != None:
                print("Found current reservations: " + str(current_reservations))
                if int(current_reservations) > current_players:
                    current_reservations = current_players
                    print("Limiting current reservations to current players")
                    redis_client.hset(game_server_key, "reserved-player-slots", current_reservations)

    if current_reservations == None:
        current_reservations = 0

    # Convert booleans to int for Redis
    server_in_use = int(server_in_use == True)
    ready = int(ready == True)

    if serverTerminated:
        print("Server terminated, delete entry and quit")
        # Delete all the possible gameserver keys
        redis_client.delete("available-gameserver-"+taskArn)
        redis_client.delete("active-gameserver-"+taskArn)
        redis_client.delete("full-gameserver-"+taskArn)
        return

    if publicIP == None:
        print("Public IP not set, can't update server in Redis")
        return

    # OPTION 1. If server is in use (full), delete from available servers and update to in use servers
    if server_in_use == 1:
        print("marking server as in use")
        # Delete the possible other gameserver key
        redis_client.delete("available-gameserver-"+taskArn)
        redis_client.delete("available-priority-gameserver-"+taskArn)
        redis_client.delete("active-gameserver-"+taskArn)
        # Update the full game server info
        redis_client.hset("full-gameserver-"+taskArn, "server-id", taskArn)
        redis_client.hset("full-gameserver-"+taskArn, "current-players", current_players)
        redis_client.hset("full-gameserver-"+taskArn, "max-players", max_players)
        redis_client.hset("full-gameserver-"+taskArn, "ready", ready) #Server will define itself ready when it's started
        redis_client.hset("full-gameserver-"+taskArn, "publicIP", publicIP)
        redis_client.hset("full-gameserver-"+taskArn, "port", port)
        # Expire in gameserverdata_ttl seconds
        redis_client.expire("full-gameserver-"+taskArn, timedelta(seconds=gameserverdata_ttl))
        
        # Mark the whole Task this server is running on as priority
        # (to make sure we prioritize servers that have already hosted sessions for good rotation)
        redis_client.set("prioritize-"+onlyTaskArn, "yes")
        redis_client.expire("prioritize-"+onlyTaskArn, timedelta(seconds=gameserverdata_ttl))

    # OPTION 2. If there's someone playing already, add to the active servers (these are used when searching for games)
    elif current_players > 0:
        print("marking server as active (at least one player connected)")
        # Delete the possible other gameserver keys
        redis_client.delete("available-gameserver-"+taskArn)
        redis_client.delete("available-priority-gameserver-"+taskArn)
        redis_client.delete("full-gameserver-"+taskArn)
        # Update the full game server info
        redis_client.hset("active-gameserver-"+taskArn, "server-id", taskArn)
        redis_client.hset("active-gameserver-"+taskArn, "current-players", current_players)
        redis_client.hset("active-gameserver-"+taskArn, "max-players", max_players)
        redis_client.hset("active-gameserver-"+taskArn, "ready", ready) #Server will define itself ready when it's started
        redis_client.hset("active-gameserver-"+taskArn, "publicIP", publicIP)
        redis_client.hset("active-gameserver-"+taskArn, "port", port)
        # Update last reservation time and reservations as well if we found one as it might be we moved from available to active
        if last_reservation_time != None:
            redis_client.hset("active-gameserver-"+taskArn, "last-reservation-time", last_reservation_time)
            redis_client.hset("active-gameserver-"+taskArn, "reserved-player-slots", current_reservations)
        # Expire in gameserverdata_ttlseconds
        redis_client.expire("active-gameserver-"+taskArn, timedelta(seconds=gameserverdata_ttl))

        # Mark the whole Task this server is running on as priority
        # (to make sure we prioritize servers that have already hosted sessions for good rotation)
        redis_client.set("prioritize-"+onlyTaskArn, "yes")
        redis_client.expire("prioritize-"+onlyTaskArn, timedelta(seconds=gameserverdata_ttl))

    # OPTION 3. if server is available and no players, delete from full and active servers and set current status based on parameters
    else:
        print("marking server available")

        available_prefix = "available-gameserver-"

        # Check if we should mark this priority (Task already hosted other game sessions)
        priority = redis_client.get("prioritize-"+onlyTaskArn)
        print("priority " + str(priority))
        if redis_client.get("prioritize-"+onlyTaskArn) != None:
            print("This server should be marked priority")
            # Delete the possible other available key as it will never be used again once the Task is priority
            redis_client.delete("available-gameserver-"+taskArn)
            # Use the priority prefix
            available_prefix = "available-priority-gameserver-"
            # Update priority key so it doesn't expire
            redis_client.set("prioritize-"+onlyTaskArn, "yes")
            redis_client.expire("prioritize-"+onlyTaskArn, timedelta(seconds=gameserverdata_ttl))

        # Delete the possible other gameserver keys
        redis_client.delete("full-gameserver-"+taskArn)
        redis_client.delete("active-gameserver-"+taskArn)
        # Update the available game server info
        redis_client.hset(available_prefix+taskArn, "server-id", taskArn)
        redis_client.hset(available_prefix+taskArn, "current-players", current_players)
        redis_client.hset(available_prefix+taskArn, "max-players", max_players)
        redis_client.hset(available_prefix+taskArn, "ready", ready) #Server will define itself ready when it's started
        redis_client.hset(available_prefix+taskArn, "publicIP", publicIP)
        redis_client.hset(available_prefix+taskArn, "port", port)
        # Update last reservation time and reservations as well if we found one to move this information to the priority entry
        if last_reservation_time != None:
            redis_client.hset(available_prefix+taskArn, "last-reservation-time", last_reservation_time)
            redis_client.hset(available_prefix+taskArn, "reserved-player-slots", current_reservations)
        # Expire in gameserverdata_ttl seconds
        redis_client.expire(available_prefix+taskArn, timedelta(seconds=gameserverdata_ttl))