Periodically ping server to detect disconnection

In some cases, disconnection from the server can be unclean and won't be
noticed until the bot tries to send a message, which may never happen if
it did not disconnect during the game. To solve this problem, it will
now ping the server every 2 minutes by default, which will result in
a broken pipe error if the connection is dead. This won't be able to
detect netsplits where the server the bot is on stays online, because
those are impossible to correctly detect in every case.

This commit also adds a !latency command so that users can verify if the
bot is lagging.
This commit is contained in:
nyuszika7h 2017-01-06 15:52:26 +01:00
parent d78f0e5179
commit a6e3c0a720
4 changed files with 26 additions and 2 deletions

View File

@ -33,6 +33,7 @@
"Give me a ping, Vasily. One ping only, please.", "Give me a ping, Vasily. One ping only, please.",
"Would you people please leave me alone? Seriously." "Would you people please leave me alone? Seriously."
], ],
"latency": "{0:.3f} second{1}.",
"lynch_reveal": [ "lynch_reveal": [
"The villagers, after much debate, finally decide on lynching \u0002{0}\u0002, who turned out to be... a{1} \u0002{2}\u0002.", "The villagers, after much debate, finally decide on lynching \u0002{0}\u0002, who turned out to be... a{1} \u0002{2}\u0002.",
"After a prolonged struggle, \u0002{0}\u0002 is forced to the gallows, and is discovered after death to be a{1} \u0002{2}\u0002.", "After a prolonged struggle, \u0002{0}\u0002 is forced to the gallows, and is discovered after death to be a{1} \u0002{2}\u0002.",

View File

@ -3,6 +3,8 @@
import base64 import base64
import socket import socket
import sys import sys
import threading
import time
import traceback import traceback
import botconfig import botconfig
@ -44,6 +46,13 @@ def unhandled(cli, prefix, cmd, *args):
for fn in decorators.HOOKS.get(cmd, []): for fn in decorators.HOOKS.get(cmd, []):
fn.caller(cli, prefix, *args) fn.caller(cli, prefix, *args)
def ping_server(cli):
if var.SERVER_PING_INTERVAL > 0:
ts = time.time()
var.LAST_SERVER_PING = ts
cli.send("PING :{0}".format(ts))
threading.Timer(var.SERVER_PING_INTERVAL, ping_server, args=(cli,)).start()
def connect_callback(cli): def connect_callback(cli):
regaincount = 0 regaincount = 0
releasecount = 0 releasecount = 0
@ -81,6 +90,8 @@ def connect_callback(cli):
users.Bot.change_nick(botconfig.NICK) users.Bot.change_nick(botconfig.NICK)
ping_server(cli)
def mustregain(cli, server, bot_nick, nick, msg): def mustregain(cli, server, bot_nick, nick, msg):
nonlocal regaincount nonlocal regaincount

View File

@ -204,6 +204,9 @@ DEV_CHANNEL = ""
DEV_PREFIX = "" DEV_PREFIX = ""
PASTEBIN_ERRORS = False PASTEBIN_ERRORS = False
# How often to ping the server (in seconds) to detect unclean disconnection
SERVER_PING_INTERVAL = 120
LAST_SERVER_PING = None
# TODO: move this to a game mode called "fixed" once we implement a way to randomize roles (and have that game mode be called "random") # TODO: move this to a game mode called "fixed" once we implement a way to randomize roles (and have that game mode be called "random")
DEFAULT_ROLE = "villager" DEFAULT_ROLE = "villager"

View File

@ -46,7 +46,7 @@ import botconfig
import src import src
import src.settings as var import src.settings as var
from src.utilities import * from src.utilities import *
from src import db, events, channels, users, hooks, logger, proxy, debuglog, errlog, plog from src import db, events, channels, users, handler, hooks, logger, proxy, debuglog, errlog, plog
from src.decorators import command, cmd, hook, handle_error, event_listener, COMMANDS from src.decorators import command, cmd, hook, handle_error, event_listener, COMMANDS
from src.messages import messages from src.messages import messages
from src.warnings import * from src.warnings import *
@ -481,7 +481,6 @@ def restart_program(cli, nick, chan, rest): # XXX: sighandler (top of file) also
# handler now, but I'm keeping it for now just in case. # handler now, but I'm keeping it for now just in case.
var.RESTARTING = True var.RESTARTING = True
@cmd("ping", pm=True) @cmd("ping", pm=True)
def pinger(cli, nick, chan, rest): def pinger(cli, nick, chan, rest):
"""Check if you or the bot is still connected.""" """Check if you or the bot is still connected."""
@ -491,6 +490,16 @@ def pinger(cli, nick, chan, rest):
cmd_char=botconfig.CMD_CHAR, cmd_char=botconfig.CMD_CHAR,
goat_action=random.choice(messages["goat_actions"]))) goat_action=random.choice(messages["goat_actions"])))
@cmd("latency", pm=True)
def latency(cli, nick, chan, rest):
handler.ping_server(cli)
@hook("pong", hookid=300)
def latency_pong(cli, server, target, ts):
lat = round(time.time() - var.LAST_SERVER_PING, 3)
reply(cli, nick, chan, messages["latency"].format(lat, "" if lat == 1 else "s"))
hook.unhook(300)
@cmd("simple", raw_nick=True, pm=True) @cmd("simple", raw_nick=True, pm=True)
def mark_simple_notify(cli, nick, chan, rest): def mark_simple_notify(cli, nick, chan, rest):
"""Makes the bot give you simple role instructions, in case you are familiar with the roles.""" """Makes the bot give you simple role instructions, in case you are familiar with the roles."""