-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.py
executable file
·131 lines (109 loc) · 4.31 KB
/
client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python3
"""Online Text Flow Client"""
__copyright__ = "2021"
__homepage__ = "http://github.com/ELITR/online-text-flow"
__license__ = "GPL"
__author__ = "Otakar Smrz"
__email__ = "otakar-smrz users.sf.net"
import websocket
import requests
import json
import re
import sys
import click
from . import textflow_protocol
webs = websocket.WebSocket()
code = {100: "complete", 10: "expected", 1: "incoming"}
opts = {}
def empty(kind='', uniq=1):
event = {'data': {'text': {"complete": [],
"expected": [],
"incoming": []}}}
if kind:
event['event'] = kind
event['id'] = uniq
return event
def post(event, url):
kind = event['event'] if 'event' in event else ''
uniq = event['id']
event['id'] = 'event%s-%d' % ('-' + kind if kind else '', uniq)
if any(event['data']['text'].values()):
if opts['websocket']:
webs.send(json.dumps(event))
event['code'] = None
else:
resp = requests.post(url + '/post', json=event)
event['code'] = resp.status_code
if opts['verbose']:
print(json.dumps(event), flush=True)
return empty(kind, uniq + 1)
else:
return empty(kind, uniq)
def wrapped_input_stream(in_stream):
if opts['brief']:
for line in textflow_protocol.brief_to_original(in_stream):
yield line
else:
for line in in_stream:
yield line
def client(kind, url):
if opts['websocket']:
try:
webs.connect(url + '/send')
except:
url = re.sub('^ws', 'http', url)
opts['websocket'] = False
kind = re.sub('\W', '-', " ".join(kind.split()))
event = empty(kind)
for line in wrapped_input_stream(sys.stdin):
if line[:1] == "{":
event = post(event, url)
event['data'] = json.loads(line)
event = post(event, url)
else:
data = line.split()
data = [int(data[0]), int(data[1]), " ".join(data[2:])]
text = event['data']['text']
text = text["complete"] + text["expected"] + text["incoming"]
if text and not text[-1][0] < data[0]:
event = post(event, url)
event['data']['text'][code[data[1] - data[0]]].append(data)
post(event, url)
if opts['websocket']:
webs.close()
print(flush=True)
@click.command(context_settings={'help_option_names': ['-h', '--help']})
@click.argument('kind', default='')
@click.argument('url', default='ws://127.0.0.1:5000')
@click.option('-v', '--verbose', is_flag=True, default=False, show_default=True,
help='Print the JSON event and the response code from the server.')
@click.option('-b', '--brief', is_flag=True, default=False, show_default=True,
help='Input is converted from the "brief" text flow to the '
'original "verbose" protocol with repeated sentences.')
def main(kind, url, verbose, brief):
"""
Emit data as the KIND of events to the URL/send websocket or the URL/post
endpoint, depending on the scheme of the URL. Consider websockets over
recurring requests. KIND is '' and URL is ws://127.0.0.1:5000 by default.
If an input line contains two integers as artificial timestamps and then
some text, an event is being built from the consecutive lines while the
timestamps increase. The specific difference of timestamps on one line
classifies the text as "complete", "expected", "incoming", or ignored.
If the data on a line is a JSON object, the event being built is posted,
then the data object is decorated and posted as an event of its own.
Lines that do not fit the logic are ignored. They do not emit the event in
progress and are printed to the standard error. Use the --verbose option
to observe the implementation details and the semantics of the events.
"""
opts['websocket'] = url.split(':')[0] in ['ws', 'wss']
if not opts['websocket']:
print('Consider using %s/send websockets instead of %s/post requests :)'
% (url.replace('http', 'ws', 1), url), file=sys.stderr)
opts['verbose'] = verbose
opts['brief'] = brief
try:
client(kind, url)
except KeyboardInterrupt:
sys.stderr.close()
if __name__ == '__main__':
main()