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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
## Hrishi Hiraskar
## 23 October 2016
import gevent
import time
import subprocess
from gevent import monkey
from gevent.pywsgi import WSGIServer
from flask import Flask, request, Response, render_template, send_from_directory
monkey.patch_all()
app = Flask(__name__, static_folder='')
# Delay time to look for new line (in s)
LOOK_DELAY = 0.1
# States of the line
INITIALIZATION = 0
ENDING = 1
DATA = 2
NOLINE = -1
# List to store figure IDs
figure_list = []
class line_and_state:
# Class to store the line and its state
line = None
state = NOLINE
def __init__(self, line, state):
self.line = line
self.state = state
def set(self, line_state):
self.line = line_state[0]
self.state = line_state[1]
return False
def get_line(self):
return self.line
def get_state(self):
return self.state
def parse_line(line):
# Function to parse the line
# Returns tuple of figure ID and state
# state = INITIALIZATION if new figure is created
# ENDING if current fig end
# DATA otherwise
line_words = line.split(' ')
if line_words[2] == "Initialization":
# New figure created
# Get fig id
figure_id = int(line_words[-1])
return (figure_id, INITIALIZATION)
elif line_words[2] == "Ending":
# Current figure end
# Get fig id
figure_id = int(line_words[-1])
return (figure_id, ENDING)
else:
# Current figure coordinates
figure_id = int(line_words[2])
return (figure_id, DATA)
def get_line_and_state(file):
# Function to get a new line from file
# This also parses the line and appends new figures to figure List
global figure_list
line = file.readline()
if not line:
return (None, NOLINE)
parse_result = parse_line(line)
figure_id = parse_result[0]
state = parse_result[1]
if state == INITIALIZATION:
# New figure created
# Add figure ID to list
figure_list.append(figure_id)
return (None, INITIALIZATION)
elif state == ENDING:
# End of figure
# Remove figure ID from list
figure_list.remove(figure_id)
return (None, ENDING)
return (line, DATA)
def event_stream():
global figure_list
# Get previously running scilab process IDs
proc = subprocess.Popen("pgrep scilab", stdout=subprocess.PIPE, shell=True)
# out will contain output of command, the list of process IDs of scilab
(out, err) = proc.communicate()
_l = len(out)
# Run xcos
subprocess.Popen("./../../bin/xcos")
# Wait till xcos is launched
while len(out) == _l:
# If length of out equals _l,
# it means scilab hasn't launched yet
# Wait
gevent.sleep(LOOK_DELAY)
# Get process IDs of scilab instances
proc = subprocess.Popen("pgrep scilab", stdout=subprocess.PIPE, shell=True)
# out will contain output of command, the list of process IDs of scilab
(out, err) = proc.communicate()
# out will contain output of command, the list of process IDs of scilab
# Get the latest process ID of scilab
pid = out.split()[-1]
# Log file directory
# As the scilab process is spawned by this script
# the log directory is same as that of this script
log_dir = ""
# Log file name
log_name = "scilab-log-"+pid+".txt"
# Open the log file
log_file = open(log_dir + log_name, "a+")
# Seek the file pointer to the end of file
# 0 signifies the displacement index relative to given position and
# 2 signifies the position (here, end of file; 0 is for start of file and 1 is for current position)
# Refer https://www.tutorialspoint.com/python/file_seek.htm for more
log_file.seek(0,2)
# Start sending log
line = line_and_state(None, NOLINE)
while line.set(get_line_and_state(log_file)) or (line.get_state() != ENDING or len(figure_list) > 0):
# Get the line and loop until the state is ENDING and figure_list empty
if line.get_state() != DATA:
gevent.sleep(LOOK_DELAY)
else:
yield "event: log\ndata: "+line.get_line()+"\n\n";
# Reset line
line = line_and_state(None, NOLINE)
# Finished Sending Log
# Exit xcos
subprocess.Popen(["kill","-9",pid])
# Remove log file, so server won't send same line twice
subprocess.Popen(["rm",log_dir+log_name])
# Notify Client
yield "event: DONE\ndata: None\n\n";
@app.route('/SendLog')
def sse_request():
# Set response method to event-stream
return Response(event_stream(), mimetype='text/event-stream')
@app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
@app.route('/')
def page():
return app.send_static_file('index.html')
if __name__ == '__main__':
# Set server address 127.0.0.1:8001/
http_server = WSGIServer(('127.0.0.1', 8001), app)
http_server.serve_forever()
|