package spimedb.server; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.util.concurrent.RateLimiter; import io.undertow.server.HttpHandler; import io.undertow.websockets.WebSocketConnectionCallback; import io.undertow.websockets.core.*; import io.undertow.websockets.extensions.PerMessageDeflateHandshake; import io.undertow.websockets.spi.WebSocketHttpExchange; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import spimedb.util.JSON; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicLong; import static io.undertow.Handlers.websocket; /** * Manages websocket i/o to a channel */ abstract public class AbstractServerWebSocket extends AbstractReceiveListener implements WebSocketCallback<Void>, WebSocketConnectionCallback { static final Logger logger = LoggerFactory.getLogger(AbstractServerWebSocket.class); @Override public void onConnect(WebSocketHttpExchange exchange, WebSocketChannel socket) { logger.info("{} connect {}", socket.getPeerAddress(), socket.getUrl() ); socket.getReceiveSetter().set(this); socket.resumeReceives(); } @Override protected void onClose(WebSocketChannel socket, StreamSourceFrameChannel channel) throws IOException { logger.info("{} disconnect", socket.getPeerAddress()); } public static void sendJSONText(WebSocketChannel socket, Object object) { sendJSON(socket, object, JSON.jsonSafe, null, null); } public static void sendJSONBinary(WebSocketChannel socket, Object object) { sendJSON(socket, object, JSON.msgPackMapper,null, null); } public static void sendJSONBinary(WebSocketChannel socket, Object object, @Nullable RateLimiter r, @Nullable AtomicLong outBytes) { sendJSON(socket, object, JSON.msgPackMapper, r, outBytes); } public static void sendJSON(WebSocketChannel socket, Object object, ObjectMapper encoder, @Nullable RateLimiter r, @Nullable AtomicLong outBytes) { byte[] s; if (object instanceof byte[]) { s = (byte[])object; } else { try { s = encoder.writeValueAsBytes(object); } catch (JsonProcessingException t) { try { s = encoder.writeValueAsBytes(object.toString()); //could not make json so just use toString() } catch (JsonProcessingException e) { e.printStackTrace(); s = object.toString().getBytes(); } } } int size = s.length; if (r!=null) { r.acquire(size); } WebSockets.sendBinary(ByteBuffer.wrap(s), socket, null); //WebSockets.sendBinaryBlocking(ByteBuffer.wrap(s), socket); if (outBytes!=null) outBytes.addAndGet(size); } @Override public void onError(WebSocketChannel wsc, Void t, Throwable thrwbl) { logger.error("err: {} {}", wsc, thrwbl.toString()); } @Override public void complete(WebSocketChannel channel, Void context) { } public HttpHandler get() { return websocket(this).addExtension(new PerMessageDeflateHandshake()); } } // protected void onJSONMessage(WebSocketChannel socket, JsonNode j) { // // } // public final EventObserver channelObserver = new EventObserver() { // // @Override // public void event(Class event, Object[] args) { // if (event == ChannelChange.class) { // Channel c = (Channel)args[0]; // JsonNode patch = null; // if (args.length > 1) // patch = (JsonNode)args[1]; // // if (patch == null) { // //send entire object // sendChannel(c); // } // else { // sendPatch(c.id, patch); // } // } // } // // }; // // protected void sendChannel(Channel c) { // ArrayNode a = Core.newJson.arrayNode(); // a.add("="); // a.add(c.get()); // send(socket, a); // } // protected void sendPatch(String channelID, JsonNode patch) { // ArrayNode a = Core.newJson.arrayNode(); // a.add("+"); // a.add(channelID); // a.add(patch); // send(socket, a); // } //