package com.github.nkzawa.engineio.client.transports; import java.net.URI; import java.net.URISyntaxException; import java.nio.ByteBuffer; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import org.java_websocket.client.WebSocketClient; import org.java_websocket.drafts.Draft_17; import org.java_websocket.handshake.ServerHandshake; import com.github.nkzawa.engineio.client.Transport; import com.github.nkzawa.engineio.parser.Packet; import com.github.nkzawa.engineio.parser.Parser; import com.github.nkzawa.parseqs.ParseQS; import com.github.nkzawa.thread.EventThread; public class WebSocket extends Transport { public static final String NAME = "websocket"; private WebSocketClient ws; public WebSocket(Options opts) { super(opts); this.name = NAME; } protected void doOpen() { if (!this.check()) { return; } Map<String, String> headers = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER); this.emit(EVENT_REQUEST_HEADERS, headers); final WebSocket self = this; try { this.ws = new WebSocketClient(new URI(this.uri()), new Draft_17(), headers, 0) { @Override public void onOpen(final ServerHandshake serverHandshake) { EventThread.exec(new Runnable() { @Override public void run() { Map<String, String> headers = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER); Iterator<String> it = serverHandshake.iterateHttpFields(); while (it.hasNext()) { String field = it.next(); if (field == null) continue; headers.put(field, serverHandshake.getFieldValue(field)); } self.emit(EVENT_RESPONSE_HEADERS, headers); self.onOpen(); } }); } @Override public void onClose(int i, String s, boolean b) { EventThread.exec(new Runnable() { @Override public void run() { self.onClose(); } }); } @Override public void onMessage(final String s) { EventThread.exec(new Runnable() { @Override public void run() { self.onData(s); } }); } @Override public void onMessage(final ByteBuffer s) { EventThread.exec(new Runnable() { @Override public void run() { self.onData(s.array()); } }); } @Override public void onError(final Exception e) { EventThread.exec(new Runnable() { @Override public void run() { self.onError("websocket error", e); } }); } }; //if (this.sslContext != null) { // this.ws.setWebSocketFactory(new DefaultSSLWebSocketClientFactory(this.sslContext)); //} this.ws.connect(); } catch (URISyntaxException e) { throw new RuntimeException(e); } } protected void write(Packet[] packets) { final WebSocket self = this; this.writable = false; for (Packet packet : packets) { Parser.encodePacket(packet, new Parser.EncodeCallback() { @Override public void call(Object packet) { if (packet instanceof String) { self.ws.send((String) packet); } else if (packet instanceof byte[]) { self.ws.send((byte[]) packet); } } }); } final Runnable ondrain = new Runnable() { @Override public void run() { self.writable = true; self.emit(EVENT_DRAIN); } }; // fake drain // defer to next tick to allow Socket to clear writeBuffer EventThread.nextTick(ondrain); } @Override protected void onClose() { super.onClose(); } protected void doClose() { if (this.ws != null) { this.ws.close(); } } protected String uri() { Map<String, String> query = this.query; if (query == null) { query = new HashMap<String, String>(); } String schema = this.secure ? "wss" : "ws"; String port = ""; if (this.port > 0 && (("wss".equals(schema) && this.port != 443) || ("ws".equals(schema) && this.port != 80))) { port = ":" + this.port; } if (this.timestampRequests) { query.put(this.timestampParam, String.valueOf(new Date().getTime())); } String _query = ParseQS.encode(query); if (_query.length() > 0) { _query = "?" + _query; } return schema + "://" + this.hostname + port + this.path + _query; } private boolean check() { // for checking if the websocket is available. Should we remove? return true; } }