<commit_before>import struct

from twisted.application.service import Service
from twisted.internet import task, reactor
from twisted.internet.protocol import Protocol, ClientFactory

from events import StatPlayerCount, ServerOutputConsumer, ACCEPTED


class PingProtocol(Protocol):
    def connectionMade(self):
        self.buff = ""
        self.transport.write('\xFE\x01')
    
    def dataReceived(self, data):
        self.buff += data
        if len(self.buff) >= 3:
            l = struct.unpack('>h', self.buff[1:3])[0]
            
            if len(self.buff) >= 3 + l * 2:
                data = self.buff[9:].decode('utf-16be').split('\x00')
                self.dispatch(StatPlayerCount(source="ping", players_current=data[3], players_max=data[4]))
                self.transport.loseConnection()


class PingFactory(ClientFactory):
    noisy = False
    
    def __init__(self, interval, host, port, dispatch):
        self.host = host
        self.port = port
        self.dispatch = dispatch
        t = task.LoopingCall(self.loop)
        t.start(interval, now=False)
    
    def loop(self):
        reactor.connectTCP(self.host, self.port, self)
    
    def buildProtocol(self, addr):
        pr = PingProtocol()
        pr.dispatch = self.dispatch
        return pr


class Ping(Service):
    name = "ping"
    
    def __init__(self, parent, host, port, interval):
        parent.events.register(self.whine, ServerOutputConsumer, pattern='\/127\.0\.0\.1\:\d+ lost connection')
        
        self.factory = PingFactory(interval, host, port, parent.events.dispatch)
    
    def whine(self, event):
        return ACCEPTED

    def stopService(self):
        self.factory.stopFactory()
        Service.stopService(self)<commit_msg>ping: fix "connection lost" spam when server-ip isn't blank.<commit_after>import re
import struct

from twisted.application.service import Service
from twisted.internet import task, reactor
from twisted.internet.protocol import Protocol, ClientFactory

from events import StatPlayerCount, ServerOutputConsumer, ACCEPTED


class PingProtocol(Protocol):
    def connectionMade(self):
        self.buff = ""
        self.transport.write('\xFE\x01')
    
    def dataReceived(self, data):
        self.buff += data
        if len(self.buff) >= 3:
            l = struct.unpack('>h', self.buff[1:3])[0]
            
            if len(self.buff) >= 3 + l * 2:
                data = self.buff[9:].decode('utf-16be').split('\x00')
                self.dispatch(StatPlayerCount(source="ping", players_current=data[3], players_max=data[4]))
                self.transport.loseConnection()


class PingFactory(ClientFactory):
    noisy = False
    
    def __init__(self, interval, host, port, dispatch):
        self.host = host
        self.port = port
        self.dispatch = dispatch
        t = task.LoopingCall(self.loop)
        t.start(interval, now=False)
    
    def loop(self):
        reactor.connectTCP(self.host, self.port, self)
    
    def buildProtocol(self, addr):
        pr = PingProtocol()
        pr.dispatch = self.dispatch
        return pr


class Ping(Service):
    name = "ping"
    
    def __init__(self, parent, host, port, interval):
        h = host if host else '127.0.0.1'
        parent.events.register(self.whine, ServerOutputConsumer, pattern='\/%s\:\d+ lost connection' % re.escape(h))
        
        self.factory = PingFactory(interval, host, port, parent.events.dispatch)
    
    def whine(self, event):
        return ACCEPTED

    def stopService(self):
        self.factory.stopFactory()
        Service.stopService(self)
{'fraction_non_alphanumeric': 0.11753318584070796, 'fraction_numerical': 0.011615044247787611, 'mean_word_length': 2.5184824902723735, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 1, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2047467', 'n_tokens_mistral': 1090, 'n_tokens_neox': 1059, 'n_words': 242}