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

io.fabric8.kubernetes.client.jdkhttp.JdkWebSocketImpl Maven / Gradle / Ivy

/**
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.fabric8.kubernetes.client.jdkhttp;

import io.fabric8.kubernetes.client.http.WebSocket;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpRequest;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

class JdkWebSocketImpl implements WebSocket {

  static class BuilderImpl implements Builder {

    private JdkHttpClientImpl httpClientImpl;
    private java.net.http.HttpRequest.Builder builder;
    String subprotocol;

    public BuilderImpl(JdkHttpClientImpl jdkHttpClientImpl) {
      this(jdkHttpClientImpl, HttpRequest.newBuilder());
    }

    public BuilderImpl(JdkHttpClientImpl httpClientImpl, java.net.http.HttpRequest.Builder copy) {
      this.httpClientImpl = httpClientImpl;
      this.builder = copy;
    }

    @Override
    public CompletableFuture buildAsync(Listener listener) {
      return httpClientImpl.buildAsync(this, listener);
    }

    @Override
    public Builder header(String name, String value) {
      builder.header(name, value);
      return this;
    }

    @Override
    public Builder setHeader(String k, String v) {
      builder.setHeader(k, v);
      return this;
    }

    @Override
    public Builder uri(URI uri) {
      builder.uri(uri);
      return this;
    }

    @Override
    public BuilderImpl subprotocol(String protocol) {
      this.subprotocol = protocol;
      return this;
    }

    public HttpRequest asRequest() {
      return this.builder.build();
    }

    public BuilderImpl copy() {
      return new BuilderImpl(httpClientImpl, builder.copy()).subprotocol(subprotocol);
    }

  }

  static final class ListenerAdapter implements java.net.http.WebSocket.Listener {

    private final Listener listener;
    private final AtomicLong queueSize;
    private final StringBuilder stringBuilder = new StringBuilder();
    private final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    private final WritableByteChannel byteChannel = Channels.newChannel(byteArrayOutputStream);

    ListenerAdapter(Listener listener, AtomicLong queueSize) {
      this.listener = listener;
      this.queueSize = queueSize;
    }

    @Override
    public CompletionStage onBinary(java.net.http.WebSocket webSocket, ByteBuffer data, boolean last) {
      try {
        byteChannel.write(data);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
      if (last) {
        ByteBuffer value = ByteBuffer.wrap(byteArrayOutputStream.toByteArray());
        byteArrayOutputStream.reset();
        listener.onMessage(new JdkWebSocketImpl(queueSize, webSocket), value);
      } else {
        webSocket.request(1);
      }
      return null;
    }

    @Override
    public CompletionStage onText(java.net.http.WebSocket webSocket, CharSequence data, boolean last) {
      stringBuilder.append(data);
      if (last) {
        String value = stringBuilder.toString();
        stringBuilder.setLength(0);
        listener.onMessage(new JdkWebSocketImpl(queueSize, webSocket), value);
      } else {
        webSocket.request(1);
      }
      return null;
    }

    @Override
    public CompletionStage onClose(java.net.http.WebSocket webSocket, int statusCode, String reason) {
      listener.onClose(new JdkWebSocketImpl(queueSize, webSocket), statusCode, reason);
      return null;
    }

    @Override
    public void onError(java.net.http.WebSocket webSocket, Throwable error) {
      listener.onError(new JdkWebSocketImpl(queueSize, webSocket), error);
    }

    @Override
    public void onOpen(java.net.http.WebSocket webSocket) {
      webSocket.request(1);
      listener.onOpen(new JdkWebSocketImpl(queueSize, webSocket));
    }
  }

  private java.net.http.WebSocket webSocket;
  private AtomicLong queueSize;

  public JdkWebSocketImpl(AtomicLong queueSize, java.net.http.WebSocket webSocket) {
    this.queueSize = queueSize;
    this.webSocket = webSocket;
  }

  @Override
  public boolean send(ByteBuffer buffer) {
    final int size = buffer.remaining();
    queueSize.addAndGet(size);
    CompletableFuture cf = webSocket.sendBinary(buffer, true);
    cf.whenComplete((b, t) -> queueSize.addAndGet(-size));
    return asBoolean(cf);
  }

  /**
   * If there is an illegalstateexception or other immediate failure, return
   * false, otherwise it should have been enqueued
   */
  private boolean asBoolean(CompletableFuture cf) {
    try {
      cf.getNow(null);
      return true;
    } catch (Exception e) {
      return false;
    }
  }

  @Override
  public boolean sendClose(int code, String reason) {
    CompletableFuture cf = webSocket.sendClose(code, reason == null ? "Closing" : reason);
    // matches the behavior of the okhttp implementation and will ensure input closure after 1 minute 
    cf.thenRunAsync(() -> webSocket.abort(), CompletableFuture.delayedExecutor(1, TimeUnit.MINUTES));
    return asBoolean(cf);
  }

  @Override
  public long queueSize() {
    return queueSize.get();
  }

  @Override
  public void request() {
    this.webSocket.request(1);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy