#!/usr/bin/python

# ping_mon.py
#       --copyright--                   Copyright 2011 (C) Tranzoa, Co. All rights reserved.    Warranty: You're free and on your own here. This code is not necessarily up-to-date or of public quality.
#       --url--                         http://www.tranzoa.net/tzpython/
#       --email--                       pycode is the name to send to. tranzoa.com is the place to send to.
#       --bodstamps--
#       October 15, 2011        bar
#       October 16, 2011        bar     show how long down-time was
#       October 17, 2011        bar     try twice when it first fails
#                                       --wate
#       November 7, 2011        bar     keep checking a failure until it comes back on line
#       December 19, 2011       bar     allow 1-time run
#                                       return -1 on Control C
#       December 23, 2011       bar     set wate from cmd line, not rate again
#       February 8, 2012        bar     use tzlib for run_program
#                                       return the latest adr
#       April 23, 2012          bar     allow the adr to be a string
#       May 27, 2012            bar     doxygen namespace
#       November 7, 2017        bar     maxint->maxsize
#       February 27, 2023       bar     python3
#       --eodstamps--
##      \file
#       \namespace              tzpython.ping_mon
#
#
#       Ping forever and put out the results to a file.
#
#       The idea is that this program can monitor your net connectivity for flakiness.
#
#

from    __future__  import  print_function

import  os
import  random
import  sys
import  time

import  tz_simple_logger
import  tzlib


LOG_FILE_NAME       = os.path.splitext(os.path.basename(__file__))[0] + "_ping_history.log"
RATE                = 10.0
WATE                = 1


def do_it(wheres = [ '8.8.8.8', ], ofile_name = LOG_FILE_NAME, rate = RATE, wate = 1, how_many = 0, verbose = 0) :
    """ ^C - return ( ok_count, 0==no_pings_done None==latest_ping_ok time==When_first_bad_ping was """

    if  not tzlib.is_listish(wheres) :
        wheres  = [ wheres, ]
    wheres      = wheres    or [ '8.8.8.8', ]
    rate        = rate      or RATE
    wate        = wate      or WATE
    verbose     = verbose   or 0
    how_many    = how_many  or sys.maxsize

    cntopt      = 'c'
    if  sys.platform == 'win32' :
        wate   *= 1000
        cntopt  = 'n'

    ok_cnt      = 0
    bad_t       = 0

    logger      = None
    if  ofile_name :
        logger  = tz_simple_logger.a_logger(ofile_name)
        logger.log(";")
        logger.log("; Starting %s" % time.asctime())

    adr         = ""
    try         :
        failed  = None
        run_cnt = 0
        while True :
            run_cnt        += 1
            if  run_cnt     > how_many :
                break

            adr = failed or str(random.choice(wheres))
            cmd = 'ping -%s 1 -w %u "%s"' % ( cntopt, wate, adr )

            ( r, rs )       = tzlib.run_program(cmd)

            chg             = 0
            ds              = ""
            if  not r :
                failed      = None
                if  bad_t or (bad_t == 0) :
                    chg     = 1
                    if  bad_t :
                        dt  = time.time() - bad_t
                        ds  = time.strftime(" %H:%M:%S", time.gmtime(dt))
                    bad_t   = None
                ok_cnt     += 1
            elif not bad_t  :
                ( r, rs )   = tzlib.run_program(cmd)
                if  r       :
                    chg     = 1
                    bad_t   = time.time()
                    failed  = adr
                pass

            ps              = "%-3d %-15s %s%s" % ( r, adr, time.asctime(), ds )
            if  logger      :
                logger.log(ps, )
                logger.flush()
            if  verbose + chg >= 2 :
                print(ps)

            time.sleep(rate)
        pass

    except KeyboardInterrupt :
        ok_cnt  = -1

    if  logger :
        logger.log("; Ending %s" % time.asctime())
        logger.close()

    return(ok_cnt, bad_t, adr)




help_str    = """
%s  (options)   host_or_IP_address...

Options:

    --rate      seconds     How ofter to ping one of the given addresses. (default: %f)
    --wait      seconds     How long to wait for the ping to succeed.     (default: %u)
    --output    file_name   Output log file name.                         (default: %s)
    --count     how_many    Set how many times to ping                    (default: 0 - forever)
    --verbose               Be noisier.

"""

#
#
#
if  __name__ == '__main__' :
    import  TZCommandLineAtFile

    program_name    = sys.argv.pop(0)
    TZCommandLineAtFile.expand_at_sign_command_line_files(sys.argv)

    rate        = RATE
    wate        = WATE
    ofile_name  = LOG_FILE_NAME
    how_many    = 0
    verbose     = 0

    while True :
        oi  = tzlib.array_find(sys.argv, [ "--help", "-h", "-?", "/h", "/H", "/?" ] )
        if  oi < 0 :    break
        del sys.argv[oi]
        print(help_str % ( os.path.basename(program_name), rate, wate, ofile_name, ))
        sys.exit(254)


    while True :
        oi  = tzlib.array_find(sys.argv, [ "--output", "-o", ] )
        if  oi < 0 :    break
        del sys.argv[oi]
        ofile_name  = sys.argv.pop(oi)

    while True :
        oi  = tzlib.array_find(sys.argv, [ "--rate", "-r", ] )
        if  oi < 0 :    break
        del sys.argv[oi]
        rate        = float(sys.argv.pop(oi))

    while True :
        oi  = tzlib.array_find(sys.argv, [ "--wait", "--wate", "-w", ] )
        if  oi < 0 :    break
        del sys.argv[oi]
        wate        = float(sys.argv.pop(oi))

    while True :
        oi  = tzlib.array_find(sys.argv, [ "--how_many", "--how-many", "--howmany", "--count", "-c", ] )
        if  oi < 0 :    break
        del sys.argv[oi]
        how_many    = int(sys.argv.pop(oi))

    while True :
        oi  = tzlib.array_find(sys.argv, [ "--verbose", "-v", ] )
        if  oi < 0 :    break
        del sys.argv[oi]
        verbose    += 1


    wheres  = sys.argv

    ( ok_cnt, bad_t, adr )  = do_it(wheres, ofile_name = ofile_name, rate = rate, wate = wate, how_many = how_many, verbose = verbose)

    print('')
    print("OK count", ok_cnt)
    if  bad_t :
        print("Currently failing from %s" % time.asctime(time.localtime(bad_t)))

    sys.exit(not not bad_t)

#
#
#
# eof
