[59] | 1 | import json
|
---|
| 2 | import sys
|
---|
| 3 | from typing import Optional
|
---|
| 4 |
|
---|
| 5 | from pyson.ObjectMapper import ObjectMapper
|
---|
| 6 | from tudelft.utilities.listener.DefaultListenable import DefaultListenable
|
---|
| 7 | from tudelft.utilities.listener.Listener import Listener
|
---|
| 8 |
|
---|
| 9 | from geniusweb.actions.Action import Action
|
---|
| 10 | from geniusweb.connection.ConnectionEnd import ConnectionEnd
|
---|
| 11 | from geniusweb.inform.Inform import Inform
|
---|
| 12 |
|
---|
| 13 |
|
---|
| 14 | class StdInOutConnectionEnd(DefaultListenable[Inform],ConnectionEnd[Inform, Action]):
|
---|
| 15 | '''
|
---|
| 16 | A connectionend for a party that forwards stdin to the party,
|
---|
| 17 | and pushes outdata from the party back into the stream.
|
---|
| 18 | '''
|
---|
| 19 | def __init__(self):
|
---|
| 20 | super().__init__()
|
---|
| 21 | self._pyson = ObjectMapper()
|
---|
| 22 |
|
---|
| 23 |
|
---|
| 24 | def send(self,act:Action ):
|
---|
| 25 | data=json.dumps(self._pyson.toJson(act))
|
---|
| 26 | sys.stdout.buffer.write(len(data).to_bytes(4,'little'))
|
---|
| 27 | sys.stdout.buffer.write(bytes(data, 'utf-8'))
|
---|
| 28 | sys.stdout.buffer.flush()
|
---|
| 29 |
|
---|
| 30 | def run(self, receiver: Listener[Inform]):
|
---|
| 31 | '''
|
---|
| 32 | @param receiver the listener for the information
|
---|
| 33 | runs until the input breaks.
|
---|
| 34 | returns only after termination
|
---|
| 35 | @raise exception if the read or the receiver throws:
|
---|
| 36 | '''
|
---|
| 37 | # blocking read
|
---|
| 38 | while True:
|
---|
| 39 | data=self.readblock()
|
---|
| 40 | if not data:
|
---|
| 41 | break
|
---|
| 42 |
|
---|
| 43 | obj=self._pyson.parse(json.loads(data.decode("utf-8")),Inform)
|
---|
| 44 | receiver.notifyChange(obj)
|
---|
| 45 | # FIXME receiver.terminate?
|
---|
| 46 |
|
---|
| 47 | def readblock(self)->Optional[bytearray]:
|
---|
| 48 | '''
|
---|
| 49 | @return next block of data from stdin, or None if stream closed.
|
---|
| 50 | '''
|
---|
| 51 | sizedata=sys.stdin.buffer.raw.read(4) #type:ignore
|
---|
| 52 | if len(sizedata)<4:
|
---|
| 53 | return None
|
---|
| 54 | remaining=int.from_bytes(sizedata, byteorder='little',signed=True)
|
---|
| 55 | if remaining>20000000:
|
---|
| 56 | raise ValueError("Received bad block:"+str(remaining))
|
---|
| 57 | #sys.stderr.write("remaining: "+str(remaining))
|
---|
| 58 |
|
---|
| 59 | data=bytearray()
|
---|
| 60 | while remaining>0:
|
---|
| 61 | newdata=sys.stdin.buffer.raw.read(remaining) #type:ignore
|
---|
| 62 | if len(newdata)==0:
|
---|
| 63 | # FIXME receiver.terminate ?
|
---|
| 64 | return None
|
---|
| 65 | data.extend(bytearray(newdata))
|
---|
| 66 | remaining=remaining-len(newdata)
|
---|
| 67 | return data
|
---|
| 68 | |
---|