import signal from os import getpid, kill import time import argparse def main(): args = get_args() with_( N=args.n, R=args.r, T=args.t, p=args.p, ) def get_args(): ap = argparse.ArgumentParser() ap.add_argument("-n", type=int, help="queue capacity", default=3) ap.add_argument("-r", type=int, help="drain rate per second", default=2) ap.add_argument("-t", type=int, help="threshold for state", default=2) ap.add_argument("-p", type=str, help="path to write out to", default="/tmp/cbappend.both.txt") return ap.parse_args() def with_(N, R, T, p): triggered = CBAppend(p) released = CBAppend(p) cb = CBFork(triggered, released) bucket = Bucket(N, R, T, cb.cb()) while readline(): bucket.push() def readline(): try: line = input() return True except EOFError: return False class Bucket: def __init__(self, N, R, T, CB): self.q = 0.0 self.N = N self.R = R self.T = T self.CB = CB self.__last_pop = 0 self.__last_state = False def push(self): result = self.__push_c(1) self.__cb() return result def pop(self): result = self.__pop() self.__cb() return result def __cb(self): new_state = self.q > self.T if new_state == self.__last_state: return self.__last_state = new_state self.CB(new_state) def state(self): return self.__last_state def __push_c(self, c): self.__pop() if self.q+c > self.N: return False self.q += c return True def __pop(self): now = self.__now() remove_up_to = (now - self.__last_pop) / self.R if remove_up_to > self.q: remove_up_to = self.q self.q -= remove_up_to self.__last_pop = now def __now(self): return time.time() class CBSignals(): def __init__(self, pid, signal_triggered, signal_released): self.__pid = pid self.__signal_triggered = signal_triggered self.__signal_released = signal_released def cb(self): def cb(state): print(f"state is now {state}") kill( self.__pid, self.__signal_triggered if state else self.__signal_released, ) handler = lambda s, f: print("SIGNAL:", s) signal.signal(self.__signal_triggered, handler) signal.signal(self.__signal_released, handler) return cb class CBAppend(): def __init__(self, path): self.__path = path def cb(self): def cb(state): with open(self.__path, "a") as f: f.write(f"{state}\n") return cb class CBFork(): def __init__(self, triggered, released): self.__triggered = triggered self.__released = released def cb(self): cb_triggered = self.__triggered.cb() cb_released = self.__released.cb() def cb(state): if state: return cb_triggered(state) return cb_released(state) return cb if __name__ == "__main__": main()