All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.v5.websocket.client.WebSocketClientBaratine Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
 *
 * This file is part of Baratine(TM)
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Baratine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Baratine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Baratine; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.v5.websocket.client;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Logger;

import com.caucho.v5.amp.thread.ThreadPool;
import com.caucho.v5.http.websocket.WebSocketBase;
import com.caucho.v5.http.websocket.WebSocketManager;
import com.caucho.v5.inject.type.TypeRef;
import com.caucho.v5.io.ReadBuffer;
import com.caucho.v5.io.SocketBar;
import com.caucho.v5.io.TempBuffer;
import com.caucho.v5.io.WriteBuffer;
import com.caucho.v5.tcp.TcpConnection;
import com.caucho.v5.util.Base64Util;
import com.caucho.v5.util.L10N;
import com.caucho.v5.websocket.WebSocketClient;
import com.caucho.v5.websocket.io.FrameInputStream;
import com.caucho.v5.websocket.io.WebSocketConstants;
import com.caucho.v5.websocket.io.WebSocketProtocolException;

import io.baratine.io.Buffer;
import io.baratine.pipe.Pipe;
import io.baratine.web.ServiceWebSocket;

/**
 * WebSocketClient
 */
public class WebSocketClientBaratine extends WebSocketBase 
  implements WebSocketConstants, WebSocketClient
{
  private static final Logger log
    = Logger.getLogger(WebSocketClientBaratine.class.getName());
  private static final L10N L = new L10N(WebSocketClientBaratine.class);

  private String _url;
  private URI _uri;

  private String _scheme;
  private String _host;
  private int _port;
  private String _path;

  private long _connectTimeout;

  private String _virtualHost;
  private boolean _isMasked = true;

  private boolean _isClosed;

  private ThreadClientTask _threadTask;
  private ConnectionWebSocketJni _jniTask;

  private FrameInputStream _frameIs;

  private HashMap _headers = new HashMap();
  
  private List _preferredSubprotocols = new ArrayList<>();
  
  private String _origin;

  private Pipe _onRead;
  private SocketBar _socket;
  private TcpConnection _conn;
  private WriteBuffer _os;
  private ServiceWebSocket _service;

  /*
  public WebSocketClient(String url, WebSocketListener listener)
  {
    this(url, createAdapter(listener), createConfigAdapter(url));
  }
  */

  public WebSocketClientBaratine(String address,
                                 ServiceWebSocket service)
  {
    super(new WebSocketManager());
    
    //Objects.requireNonNull(container);
    Objects.requireNonNull(address);
    Objects.requireNonNull(service);
    //_container = container;
    //_endpoint = endpoint;
    //_config = config;
    
    try {
      _uri = new URI(address);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    /*
    if (config != null) {
      if (config.getPreferredSubprotocols() != null) {
        _preferredSubprotocols.addAll(config.getPreferredSubprotocols());
      }
    }
    */
    
    //_configurator = config.getConfigurator();
        
    /*
    if (config != null) {
      _origin = config.getOrigin();
    }
    */

    _scheme = _uri.getScheme();
    _host = _uri.getHost();
    _port = _uri.getPort();
    _path = _uri.getPath();

    if (_path == null) {
      _path = "/";
    }
    
    _service = service;
    
    open();
    TypeRef typeRef = TypeRef.of(service.getClass());
    TypeRef typeRefService = typeRef.to(ServiceWebSocket.class);
    TypeRef type = typeRefService.param(0);
    
    Class valueType;
    
    if (type != null) {
      valueType = type.rawClass(); 
    }
    else {
      valueType = String.class;
    }
    
    if (Frame.class.equals(valueType)) {
      readFrame((ServiceWebSocket) _service);
    }
    else if (String.class.equals(valueType)) {
      readString((ServiceWebSocket) _service);
    }
    else if (Buffer.class.equals(valueType)) {
      read((ServiceWebSocket) _service);
    }
    else {
      throw new UnsupportedOperationException(valueType.toString());
    }

  }

  public String getHost()
  {
    return _host;
  }

  public int getPort()
  {
    return _port;
  }

  public String getPath()
  {
    return _path;
  }

  public void setVirtualHost(String virtualHost)
  {
    _virtualHost = virtualHost;
  }

  public void setConnectTimeout(long timeout)
  {
    _connectTimeout = timeout;
  }

  public void setMasked(boolean isMasked)
  {
    _isMasked = isMasked;
  }
  
  /*
  public WebSocketClientBaratine onOpen(ServiceWebSocket service)
  {
    Objects.requireNonNull(service);
    
    _onOpen = service;
    
    return this;
  }
  */

  /*
  public WebSocketClientBaratine onRead(OutPipe onRead)
  {
    Objects.requireNonNull(onRead);
    
    _onRead = onRead;
    
    return this;
  }
  */

  /**
   * @param preferredSubprotocols
   */
  public void setPreferredSubprotocols(List preferredSubprotocols)
  {
    _preferredSubprotocols = preferredSubprotocols;
  }

  public void setOrigin(String origin)
  {
    _origin = origin;
  }


  public void connect()
    throws IOException
  {
    connect(null, null);
  }

  public void connect(String userName, String password)
    throws IOException
  {
    connectImpl(userName, password);
  }

  public String getProtocolVersion()
  {
    return WebSocketConstants.VERSION;
  }

  public String getHeader(String key)
  {
    return _headers.get(key);
  }

  protected void connectImpl(String userName, String password)
    throws IOException
  {
    int connectTimeout = (int) _connectTimeout;

    /*
    InetSocketAddress addr = new InetSocketAddress(_host, _port);

    SocketSystem network = SocketSystem.current();

    QSocket s = network.connect(addr.getAddress(), addr.getPort(), connectTimeout);
    */
    
    _conn = TcpConnection.open(_host, _port);

    /*
    Socket s = new Socket();

    if (connectTimeout > 0) {
      s.connect(new InetSocketAddress(_host, _port), connectTimeout);
    }
    else {
      s.connect(new InetSocketAddress(_host, _port));
    }
    */

    /*
    SocketChannel chan = SocketChannel.open();

    chan.connect(new InetSocketAddress(_host, _port));

    Socket s = chan.socket();
    */

    //s.setTcpNoDelay(true);

    /*
    if ("https".equals(_scheme)) {
      s = openSsl(s);
    }
    */

    //_socket = s;
    //_socketConn = new EndpointConnectionQSocket(s);
    //_socketConn.setIdleReadTimeout(600000);

    ReadBuffer is = _conn.inputStream();
    WriteBuffer os = _conn.outputStream();
    _os = os;

    String path = _path;

    if (_uri.getQuery() != null) {
      path = path + "?" + _uri.getQuery();
    }

    os.print("GET " + path + " HTTP/1.1\r\n");

    if (_virtualHost != null) {
      os.print("Host: " + _virtualHost + "\r\n");
    }
    else if (_host != null) {
      os.print("Host: " + _host + "\r\n");
    }
    else {
      os.print("Host: localhost\r\n");
    }

    byte []clientNonce = new byte[16];

    String key = Base64Util.encode(clientNonce);

    os.print("Sec-WebSocket-Key: " + key + "\r\n");

    String version = WebSocketConstants.VERSION;

    os.print("Sec-WebSocket-Version: " + version + "\r\n");

    if (_origin != null) {
      os.print("Origin: " + _origin + "\r\n");
    }

    StringBuilder ext = new StringBuilder();

    if (! _isMasked) {
      if (ext.length() > 0)
        ext.append(", ");

      ext.append("x-unmasked");
    }

    /*
    if (ext.length() > 0) {
      os.print("Sec-WebSocket-Extensions: " + ext + "\r\n");
    }
    */
    
    if (_preferredSubprotocols != null && _preferredSubprotocols.size() > 0) {
      StringBuilder sb = new StringBuilder();

      for (int i = 0; i < _preferredSubprotocols.size(); i++) {
        if (i > 0) {
          sb.append(", ");
        }

        sb.append(_preferredSubprotocols.get(i));
      }

      os.print("Sec-WebSocket-Protocol: " + sb + "\r\n");
    }
    
    HashMap> headers = new HashMap<>();

    //_configurator.beforeRequest(headers);
    
    for (Map.Entry> entry : headers.entrySet()) {
      List values = entry.getValue();

      os.print(entry.getKey());
      os.print(": ");
      
      for (int i = 0; i < values.size(); i++) {
        if (i != 0) {
          os.print(", ");
        }
        
        os.print(values.get(i));
      }
      
      os.print("\r\n");
    }

    if (_origin != null) {
      os.print("Origin: " + _origin + "\r\n");
    }

    os.print("Upgrade: websocket\r\n");
    os.print("Connection: Upgrade\r\n");

    os.print("\r\n");
    os.flush();

    parseHeaders(is);

    //_frameIs = new FrameInputStream();
    
    os.flush();

    String []names = new String[0];
    
    String subprotocol = _headers.get("Sec-WebSocket-Protocol");
    
    //_webSocket = new WebSocketImplClient(_uri.getPath(), os);
    

    FrameInputStream fIs = new FrameInputStream();
    fIs.init(null, is);
    
    //Objects.requireNonNull(_frameIs);
    frameInput(fIs);
    
    _threadTask = new ThreadClientTask(this, is);
    
    // static callbacks must be before the open
    /*
    if (_onRead != null) {
      read(_onRead);
    }
    */

    // open before the reader in case the on open registers message handlers
    /*
    if (_onOpen != null) {
      _onOpen.open(this); // _webSocket);
    }
    */
    
    _service.open(this);
    
    // now can start the reader
    if (_threadTask != null) {
      ThreadPool.current().execute(_threadTask);
    }
  }

  private void parseHeaders(ReadBuffer in)
    throws IOException
  {
    String status = readln(in);

    if (status == null) {
      throw new WebSocketProtocolException(L.l("Unexpected connection close"));
    }
    else if (status == null || ! status.startsWith("HTTP")) {
      throw new WebSocketProtocolException(L.l("Unexpected response {0}", status));
    }

    String line;
    while ((line = readln(in)) != null && line.length() != 0) {
      int p = line.indexOf(':');

      if (p > 0) {
        String header = line.substring(0, p).trim();
        String value = line.substring(p + 1).trim();

        _headers.put(header, value);
      }
    }

    if (! status.startsWith("HTTP/1.1 101")) {
      StringBuilder sb = new StringBuilder();

      int ch;

      while (in.available() > 0 && (ch = in.read()) >= 0) {
        sb.append((char) ch);
      }

      throw new WebSocketProtocolException(L.l("Unexpected response {0}\n\n{1}",
                                               status, sb));

    }
  }
  
  private String readln(ReadBuffer in)
    throws IOException
  {
    StringBuilder sb = new StringBuilder();
    int ch;
    
    while ((ch = in.read()) >= 0 && ch != '\n') {
      if (ch != '\r') {
        sb.append((char) ch);
      }
    }
    
    return sb.toString();
  }

  @Override
  protected  Pipe wrap(Pipe handler)
  {
    return handler;
  }

  @Override
  protected boolean readFrame()
  {
    return super.readFrame();
  }

  public void disconnect()
  {
  }

  public boolean isClosed()
  {
    return _isClosed;
  }

  public void close()
  {
    disconnect();
  }

  @Override
  public String toString()
  {
    return getClass().getSimpleName() + "[" + _uri + "]";
  }

  @Override
  protected void send(TempBuffer tBuf)
  {
    try {
      _os.write(tBuf.buffer(), 0, tBuf.length());
      _os.flush();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy