blob: b6d14b0e900ed89dfd93ff4de4365a7642035575 [file] [log] [blame]
Thomas Vachuska750ab042015-06-17 10:42:15 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska750ab042015-06-17 10:42:15 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onlab.stc;
17
18import com.fasterxml.jackson.databind.ObjectMapper;
19import com.fasterxml.jackson.databind.node.ObjectNode;
20import org.eclipse.jetty.websocket.WebSocket;
Thomas Vachuska750ab042015-06-17 10:42:15 -070021
22import java.io.IOException;
23
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070024import static org.onlab.stc.Coordinator.print;
25
Thomas Vachuska750ab042015-06-17 10:42:15 -070026/**
27 * Web socket capable of interacting with the STC monitor GUI.
28 */
29public class MonitorWebSocket implements WebSocket.OnTextMessage, WebSocket.OnControl {
30
Thomas Vachuska750ab042015-06-17 10:42:15 -070031 private static final long MAX_AGE_MS = 30_000;
32
33 private static final byte PING = 0x9;
34 private static final byte PONG = 0xA;
35 private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad};
36
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070037 private final Monitor monitor;
38
Thomas Vachuska750ab042015-06-17 10:42:15 -070039 private Connection connection;
40 private FrameConnection control;
41
42 private final ObjectMapper mapper = new ObjectMapper();
43
44 private long lastActive = System.currentTimeMillis();
45
46 /**
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070047 * Creates a new monitor client GUI web-socket.
48 *
49 * @param monitor shared process flow monitor
50 */
51 MonitorWebSocket(Monitor monitor) {
52 this.monitor = monitor;
53 }
54
55 /**
Thomas Vachuska750ab042015-06-17 10:42:15 -070056 * Issues a close on the connection.
57 */
58 synchronized void close() {
59 destroyHandlers();
60 if (connection.isOpen()) {
61 connection.close();
62 }
63 }
64
65 /**
66 * Indicates if this connection is idle.
67 *
68 * @return true if idle or closed
69 */
70 synchronized boolean isIdle() {
71 long quietFor = System.currentTimeMillis() - lastActive;
72 boolean idle = quietFor > MAX_AGE_MS;
73 if (idle || (connection != null && !connection.isOpen())) {
Thomas Vachuska750ab042015-06-17 10:42:15 -070074 return true;
75 } else if (connection != null) {
76 try {
77 control.sendControl(PING, PING_DATA, 0, PING_DATA.length);
78 } catch (IOException e) {
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070079 print("Unable to send ping message due to: %s", e);
Thomas Vachuska750ab042015-06-17 10:42:15 -070080 }
81 }
82 return false;
83 }
84
85 @Override
86 public void onOpen(Connection connection) {
87 this.connection = connection;
88 this.control = (FrameConnection) connection;
89 try {
90 createHandlers();
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070091 sendMessage(message("flow", monitor.scenarioData()));
Thomas Vachuska750ab042015-06-17 10:42:15 -070092
93 } catch (Exception e) {
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -070094 print("Unable to open monitor connection: %s", e);
Thomas Vachuska750ab042015-06-17 10:42:15 -070095 this.connection.close();
96 this.connection = null;
97 this.control = null;
98 }
99 }
100
101 @Override
102 public synchronized void onClose(int closeCode, String message) {
103 destroyHandlers();
Thomas Vachuska750ab042015-06-17 10:42:15 -0700104 }
105
106 @Override
107 public boolean onControl(byte controlCode, byte[] data, int offset, int length) {
108 lastActive = System.currentTimeMillis();
109 return true;
110 }
111
112 @Override
113 public void onMessage(String data) {
114 lastActive = System.currentTimeMillis();
115 try {
116 ObjectNode message = (ObjectNode) mapper.reader().readTree(data);
117 // TODO:
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -0700118 print("Got message: %s", message);
Thomas Vachuska750ab042015-06-17 10:42:15 -0700119 } catch (Exception e) {
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -0700120 print("Unable to parse GUI message %s due to %s", data, e);
Thomas Vachuska750ab042015-06-17 10:42:15 -0700121 }
122 }
123
124 public synchronized void sendMessage(ObjectNode message) {
125 try {
126 if (connection.isOpen()) {
127 connection.sendMessage(message.toString());
128 }
129 } catch (IOException e) {
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -0700130 print("Unable to send message %s to GUI due to %s", message, e);
Thomas Vachuska750ab042015-06-17 10:42:15 -0700131 }
132 }
133
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -0700134 public ObjectNode message(String type, ObjectNode payload) {
135 ObjectNode message = mapper.createObjectNode().put("event", type);
Thomas Vachuska750ab042015-06-17 10:42:15 -0700136 message.set("payload", payload);
Thomas Vachuskab51b8bc2015-07-27 08:37:12 -0700137 return message;
Thomas Vachuska750ab042015-06-17 10:42:15 -0700138 }
139
140 // Creates new message handlers.
141 private synchronized void createHandlers() {
142 }
143
144 // Destroys message handlers.
145 private synchronized void destroyHandlers() {
146 }
147
148}
149