Show More
@@ -109,6 +109,25 b' WS_PING_INTERVAL = 30000' | |||||
109 |
|
109 | |||
110 | class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler): |
|
110 | class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler): | |
111 | ping_callback = None |
|
111 | ping_callback = None | |
|
112 | last_pong = 0 | |||
|
113 | ||||
|
114 | @property | |||
|
115 | def ping_interval(self): | |||
|
116 | """The interval for websocket keep-alive pings. | |||
|
117 | ||||
|
118 | Set ws_ping_interval = 0 to disable pings. | |||
|
119 | """ | |||
|
120 | return self.settings.get('ws_ping_interval', WS_PING_INTERVAL) | |||
|
121 | ||||
|
122 | @property | |||
|
123 | def ping_timeout(self): | |||
|
124 | """If no ping is received in this many milliseconds, | |||
|
125 | close the websocket connection (VPNs, etc. can fail to cleanly close ws connections). | |||
|
126 | Default is max of 3 pings or 30 seconds. | |||
|
127 | """ | |||
|
128 | return self.settings.get('ws_ping_timeout', | |||
|
129 | max(3 * self.ping_interval, WS_PING_INTERVAL) | |||
|
130 | ) | |||
112 |
|
131 | |||
113 | def set_default_headers(self): |
|
132 | def set_default_headers(self): | |
114 | """Undo the set_default_headers in IPythonHandler |
|
133 | """Undo the set_default_headers in IPythonHandler | |
@@ -129,16 +148,30 b' class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):' | |||||
129 | self.session = Session(config=self.config) |
|
148 | self.session = Session(config=self.config) | |
130 | self.save_on_message = self.on_message |
|
149 | self.save_on_message = self.on_message | |
131 | self.on_message = self.on_first_message |
|
150 | self.on_message = self.on_first_message | |
132 | self.ping_callback = ioloop.PeriodicCallback(self.send_ping, WS_PING_INTERVAL) |
|
151 | ||
133 | self.ping_callback.start() |
|
152 | # start the pinging | |
|
153 | if self.ping_interval > 0: | |||
|
154 | self.last_pong = ioloop.IOLoop.instance().time() | |||
|
155 | self.ping_callback = ioloop.PeriodicCallback(self.send_ping, self.ping_interval) | |||
|
156 | self.ping_callback.start() | |||
134 |
|
157 | |||
135 | def send_ping(self): |
|
158 | def send_ping(self): | |
136 | """send a ping to keep the websocket alive""" |
|
159 | """send a ping to keep the websocket alive""" | |
137 | if self.stream.closed() and self.ping_callback is not None: |
|
160 | if self.stream.closed() and self.ping_callback is not None: | |
138 | self.ping_callback.stop() |
|
161 | self.ping_callback.stop() | |
139 | return |
|
162 | return | |
|
163 | ||||
|
164 | # check for timeout on pong | |||
|
165 | since_last_pong = 1e3 * (ioloop.IOLoop.instance().time() - self.last_pong) | |||
|
166 | if since_last_pong > self.ping_timeout: | |||
|
167 | self.log.warn("WebSocket ping timeout after %i ms.", since_last_pong) | |||
|
168 | self.close() | |||
|
169 | return | |||
140 |
|
170 | |||
141 | self.ping(b'') |
|
171 | self.ping(b'') | |
|
172 | ||||
|
173 | def on_pong(self, data): | |||
|
174 | self.last_pong = ioloop.IOLoop.instance().time() | |||
142 |
|
175 | |||
143 | def _inject_cookie_message(self, msg): |
|
176 | def _inject_cookie_message(self, msg): | |
144 | """Inject the first message, which is the document cookie, |
|
177 | """Inject the first message, which is the document cookie, |
General Comments 0
You need to be logged in to leave comments.
Login now