CFC-Servers / cfc_disconnect_interface

Custom interface to display when the server crashes or the client loses connection
GNU General Public License v3.0
2 stars 0 forks source link

[question] webserver #22

Open gmodmurderserver opened 2 years ago

gmodmurderserver commented 2 years ago

how does one run a webserver when the server runs, so that this could work properly?

brandonsturgeon commented 2 years ago

Great question!

I'm afraid it's a bit complicated. Our webserver setup is a proprietary system that lets us interact with our game servers from a web address.

If you wanted to mimic the web server portion for a specific server, ultimately you'll need a public endpoint that returns a json payload in the format of: { "server-is-up": true/false }.

One way of accomplishing this is using a language that has an rcon library available. You can use the rcon library to send a simple status command to your server, and if it replies, you can respond to the API caller with { "server-is-up": true }, if it times out or errors, you can respond with { "server-is-up": false }

Here's a simple (probably functional?) proof-of-concept:

# rcon_interface.py
# be sure to set the RCON_IP, RCON_PORT, and RCON_PASSWORD environment variables
import os
import valve.rcon

class RCONInterface:
    def __init__(self):
        self.set_rcon_credentials()

    def set_rcon_credentials(self):
        self.address = os.getenv("RCON_IP")
        self.port = os.getenv("RCON_PORT")
        self.password = os.getenv("RCON_PASSWORD")

    def issue_command(self, command):
        connection_address = (self.address, int(self.port))

        try:
            with valve.rcon.RCON(connection_address, self.password, timeout=5) as rcon:
                response = rcon(command)
                print("Rcon response:")
                print(response)

                if response:
                    return True, response

        except valve.rcon.RCONCommunicationError as socket_err:
            print(f"Hit a communication error when trying to issue: '{command}' to '{self.address}:{self.port}'")
            print(socket_err)

            return False, socket_err

        except valve.rcon.RCONTimeoutError as timeout_err:
            print(f"Hit a timeout error when trying to issue: '{command}' to '{self.address}:{self.port}'")
            print(timeout_err)

            return False, timeout_err

        except Exception as generic_err:
            print(f"Hit an unknown error when trying to issue: '{command}' to '{self.address}:{self.port}'")

            return False, generic_err

        print("No conditions met, assuming failure?")
        return False
# web.py
from rcon_interface.py import RCONInterface 
from flask import Flask
import time

app = Flask(__name__)
rcon = RCONInterface()

last_status = True
last_check = 0

@app.route("/ping")
def ping():
    # Cache the response for a few seconds so you're not sending tons of rcon requests
    if last_check > time.time() - 3:
        return { "server-is-up": last_status }

    is_up, err_message = rcon.issue_command("status")
    last_status = is_up
    last_check = time.time()

    return { "server-is-up": is_up }

You could deploy this script on the same host as the game server, or you could retrofit it to work in something like Amazon's AWS Lambda. If you know Javascript (or can be bothered to transpile to JS), you could use Cloudflare Workers, too.

Sorry this is a hassle. We had to make a generic solution for all of our game servers, and it's very specific to how we have things set up, so it wasn't made to be nicely shareable.

gmodmurderserver commented 2 years ago

hmmm, thanks, pretty much all i need it to do is run when the server itself does, and when its detected its up, it could run the restart command, etc

brandonsturgeon commented 2 years ago

Yeah I suppose you could do that with this web server too.

When you return a server-is-up: false response, you could also kick off the restart command (you'd have to be 100% sure it doesn't run multiple times though, that'd be a mess)

gmodmurderserver commented 2 years ago

i tried the python stuff, and it seems to do pretty much nothing when the server restarts or crashes

wrefgtzweve commented 2 years ago

i can recommend using https://github.com/Yepoleb/python-a2s instead of rcon

gmodmurderserver commented 2 years ago

im guessing i just replace "valve.rcon" with a2s?

wrefgtzweve commented 2 years ago

roughly, yeah. you'd only need the web.py part and just run a a2s.info to the server to see if its up, if it times out it isnt

gmodmurderserver commented 2 years ago

ah right i see, i am pretty new to python and all lol

wrefgtzweve commented 2 years ago

it can be done with any language has a a2s / rcon library, this is just a rough example

gmodmurderserver commented 2 years ago

https://files.catbox.moe/or4t5m.png does this look right? lol

wrefgtzweve commented 2 years ago

no, you'd have to call the a2s function whenever you want to do a info request, check their examples