prototyped
parent
0b0d001a2f
commit
52e9df34d3
|
|
@ -0,0 +1,133 @@
|
|||
import random
|
||||
import time
|
||||
import threading
|
||||
import queue
|
||||
from sys import argv
|
||||
|
||||
def main():
|
||||
def __input__():
|
||||
return input()
|
||||
if argv[1:]:
|
||||
f = open(argv[1])
|
||||
def __input__():
|
||||
return f.readline()
|
||||
input_buffer = InputBuffer()
|
||||
input_buffer.start()
|
||||
print("accepting input")
|
||||
while True:
|
||||
try:
|
||||
got = __input__()
|
||||
input_buffer.enqueue(got.strip())
|
||||
except KeyboardInterrupt:
|
||||
print("stopping")
|
||||
input_buffer.stop()
|
||||
break
|
||||
input_buffer.join()
|
||||
print("stopped")
|
||||
|
||||
class InputBuffer(threading.Thread):
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
self.pages = {}
|
||||
self.q = queue.Queue()
|
||||
self.done = False
|
||||
|
||||
def now():
|
||||
return time.time()
|
||||
|
||||
def interval():
|
||||
return .1
|
||||
|
||||
def stop(self):
|
||||
self.done = True
|
||||
self.q.put(None)
|
||||
|
||||
def bucket(self, t):
|
||||
t *= 1000
|
||||
i = InputBuffer.interval() * 1000
|
||||
tp = int(t // i) * int(i)
|
||||
return tp / 1000
|
||||
|
||||
def run(self):
|
||||
state = InputBuffer.State(0, None)
|
||||
previous = None
|
||||
while not self.done:
|
||||
try:
|
||||
state = InputBuffer.State.choose(state, self._run())
|
||||
latest = state.v
|
||||
if latest != previous:
|
||||
print(InputBuffer.now(), latest)
|
||||
previous = latest
|
||||
except Exception as e:
|
||||
print(e)
|
||||
time.sleep(InputBuffer.interval())
|
||||
|
||||
def _run(self):
|
||||
now = InputBuffer.now()
|
||||
deadline = now + InputBuffer.interval()
|
||||
while InputBuffer.now() < deadline:
|
||||
if self.dequeue(deadline - InputBuffer.now()) == None:
|
||||
self.done = True
|
||||
return
|
||||
return InputBuffer.State(now, self.pick(now))
|
||||
|
||||
def enqueue(self, k):
|
||||
self.q.put([ InputBuffer.now(), k.lower() ])
|
||||
|
||||
def dequeue(self, timeout):
|
||||
try:
|
||||
if timeout <= 0:
|
||||
return False
|
||||
got = self.q.get(timeout=timeout)
|
||||
except queue.Empty:
|
||||
return False
|
||||
if got:
|
||||
t = self.bucket(got[0])
|
||||
k = got[1]
|
||||
if not t in self.pages:
|
||||
self.pages[t] = InputBuffer.Page()
|
||||
self.pages[t].push(k)
|
||||
return got
|
||||
|
||||
def pick(self, t):
|
||||
return self.pages.get(self.bucket(t), InputBuffer.Page()).pick()
|
||||
|
||||
class Page:
|
||||
def __init__(self):
|
||||
self.inputs = {}
|
||||
|
||||
def push(self, k):
|
||||
self.inputs[k] = self.inputs.get(k, 0) + 1
|
||||
|
||||
def pick(self):
|
||||
if not self.inputs:
|
||||
return None
|
||||
options = []
|
||||
for k,v in self.inputs.items():
|
||||
for i in range(0, v):
|
||||
options.append(k)
|
||||
return options[random.randint(0, len(options)-1)]
|
||||
|
||||
class State:
|
||||
def __init__(self, t, v):
|
||||
self.t = t
|
||||
self.v = v
|
||||
|
||||
def choose(a, b):
|
||||
if not a:
|
||||
return b
|
||||
if not b:
|
||||
return a
|
||||
latest = a
|
||||
oldest = b
|
||||
if b.t > a.t:
|
||||
latest = b
|
||||
oldest = a
|
||||
if latest.v == None:
|
||||
t_a_few_intervals_ago = InputBuffer.now() - InputBuffer.interval() * 10
|
||||
if oldest.t > t_a_few_intervals_ago:
|
||||
return oldest
|
||||
return latest
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#! /bin/bash
|
||||
|
||||
main() {
|
||||
cleanup() {
|
||||
jobs="$(jobs -p)"
|
||||
test -n "$jobs" && kill -9 $jobs
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
local pipe=/tmp/breel.pipe
|
||||
test -e "$pipe" || mkfifo $pipe
|
||||
while true; do
|
||||
read -s v
|
||||
echo "$v"
|
||||
done | python3 ./main.py
|
||||
}
|
||||
|
||||
if [ "$0" == "$BASH_SOURCE" ]; then
|
||||
main "$@"
|
||||
fi
|
||||
Loading…
Reference in New Issue