1# -*- coding: UTF-8 -*- 2 3import re 4import sys 5import shutil 6 7from gi.repository import GObject 8 9from pychess.compat import create_task 10from pychess.System.Log import log 11from pychess.System.SubProcess import SubProcess 12 13 14class Pinger(GObject.GObject): 15 """ The received signal contains the time it took to get response from the 16 server in millisecconds. -1 means that some error occurred """ 17 18 __gsignals__ = { 19 "received": (GObject.SignalFlags.RUN_FIRST, None, (float, )), 20 "error": (GObject.SignalFlags.RUN_FIRST, None, (str, )) 21 } 22 23 def __init__(self, host): 24 GObject.GObject.__init__(self) 25 self.host = host 26 self.subproc = None 27 28 self.expression = re.compile(r"=([\d\.]+) (m?s)") 29 30 # We need untranslated error messages in regexp search 31 # below, so have to use deferred translation here 32 def _(msg): 33 return msg 34 35 error = _("Destination Host Unreachable") 36 self.errorExprs = (re.compile("(%s)" % error), ) 37 del _ 38 39 self.restartsOnDead = 3 40 self.deadCount = 0 41 42 def start(self): 43 assert not self.subproc 44 if sys.platform == "win32": 45 args = ["-t", self.host] 46 else: 47 args = ["-i10", self.host] 48 self.subproc = SubProcess(shutil.which("ping"), args, env={"LANG": "en"}) 49 create_task(self.subproc.start()) 50 self.conid1 = self.subproc.connect("line", self.__handleLines) 51 self.conid2 = self.subproc.connect("died", self.__handleDead) 52 53 def __handleLines(self, subprocess, line): 54 match = self.expression.search(line) 55 if match: 56 time, unit = match.groups() 57 time = float(time) 58 if unit == "s": 59 time *= 1000 60 self.emit("received", time) 61 else: 62 for expr in self.errorExprs: 63 match = expr.search(line) 64 if match: 65 msg = match.groups()[0] 66 self.emit("error", _(msg)) 67 68 def __handleDead(self, subprocess): 69 if self.deadCount < self.restartsOnDead: 70 log.warning("Pinger died and restarted (%d/%d)" % 71 (self.deadCount + 1, self.restartsOnDead), 72 extra={"task": self.subproc.defname}) 73 self.stop() 74 self.start() 75 self.deadCount += 1 76 else: 77 self.emit("error", _("Died")) 78 self.stop() 79 80 def stop(self): 81 if not self.subproc: 82 return 83 # exitCode = self.subproc.gentleKill() 84 self.subproc.disconnect(self.conid1) 85 self.subproc.disconnect(self.conid2) 86 self.subproc.terminate() 87 self.subproc = None 88 89 90if __name__ == "__main__": 91 pinger = Pinger("google.com") 92 93 def callback(pinger, time): 94 print(time) 95 96 pinger.connect("received", callback) 97 pinger.start() 98 import time 99 time.sleep(5) 100 pinger.stop() 101 time.sleep(3) 102