org.reaktivity.nukleus.http2.internal.Http2Controller Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nukleus-http Show documentation
Show all versions of nukleus-http Show documentation
HTTP Nukleus Implementation
/**
* Copyright 2016-2020 The Reaktivity Project
*
* The Reaktivity Project licenses this file to you 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 org.reaktivity.nukleus.http2.internal;
import static java.nio.ByteBuffer.allocateDirect;
import static java.nio.ByteOrder.nativeOrder;
import static java.util.Collections.singletonMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import org.agrona.MutableDirectBuffer;
import org.agrona.concurrent.UnsafeBuffer;
import org.reaktivity.nukleus.Controller;
import org.reaktivity.nukleus.ControllerSpi;
import org.reaktivity.nukleus.http.internal.types.Flyweight;
import org.reaktivity.nukleus.http.internal.types.OctetsFW;
import org.reaktivity.nukleus.http.internal.types.control.FreezeFW;
import org.reaktivity.nukleus.http.internal.types.control.HttpRouteExFW;
import org.reaktivity.nukleus.http.internal.types.control.Role;
import org.reaktivity.nukleus.http.internal.types.control.RouteFW;
import org.reaktivity.nukleus.http.internal.types.control.UnrouteFW;
import org.reaktivity.nukleus.route.RouteKind;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public final class Http2Controller implements Controller
{
private static final int MAX_SEND_LENGTH = 1024; // TODO: Configuration and Context
// TODO: thread-safe flyweights or command queue from public methods
private final RouteFW.Builder routeRW = new RouteFW.Builder();
private final UnrouteFW.Builder unrouteRW = new UnrouteFW.Builder();
private final FreezeFW.Builder freezeRW = new FreezeFW.Builder();
private final HttpRouteExFW.Builder routeExRW = new HttpRouteExFW.Builder();
private final OctetsFW extensionRO = new OctetsFW().wrap(new UnsafeBuffer(new byte[0]), 0, 0);
private final ControllerSpi controllerSpi;
private final MutableDirectBuffer commandBuffer;
private final MutableDirectBuffer extensionBuffer;
private final Gson gson;
public Http2Controller(ControllerSpi controllerSpi)
{
this.controllerSpi = controllerSpi;
this.commandBuffer = new UnsafeBuffer(allocateDirect(MAX_SEND_LENGTH).order(nativeOrder()));
this.extensionBuffer = new UnsafeBuffer(allocateDirect(MAX_SEND_LENGTH).order(nativeOrder()));
this.gson = new Gson();
}
@Override
public int process()
{
return controllerSpi.doProcess();
}
@Override
public void close() throws Exception
{
controllerSpi.doClose();
}
@Override
public Class kind()
{
return Http2Controller.class;
}
@Override
public String name()
{
return Http2Nukleus.NAME;
}
@Deprecated
public CompletableFuture routeServer(
String localAddress,
String remoteAddress,
Map headers)
{
return route(RouteKind.SERVER, localAddress, remoteAddress, gson.toJson(singletonMap("headers", headers)));
}
@Deprecated
public CompletableFuture routeClient(
String localAddress,
String remoteAddress,
Map headers)
{
return route(RouteKind.CLIENT, localAddress, remoteAddress, gson.toJson(singletonMap("headers", headers)));
}
public CompletableFuture route(
RouteKind kind,
String localAddress,
String remoteAddress)
{
return route(kind, localAddress, remoteAddress, null);
}
public CompletableFuture route(
RouteKind kind,
String localAddress,
String remoteAddress,
String extension)
{
Flyweight routeEx = extensionRO;
if (extension != null)
{
final JsonParser parser = new JsonParser();
final JsonElement element = parser.parse(extension);
if (element.isJsonObject())
{
final JsonObject object = (JsonObject) element;
final JsonObject headers = object.getAsJsonObject("headers");
final JsonObject overrides = object.getAsJsonObject("overrides");
routeEx = routeExRW.wrap(extensionBuffer, 0, extensionBuffer.capacity())
.headers(hs ->
{
if (headers != null)
{
headers.entrySet().forEach(e ->
{
String name = e.getKey();
String value = e.getValue().getAsString();
hs.item(h -> h.name(name).value(value));
});
}
})
.overrides(os ->
{
if (overrides != null)
{
overrides.entrySet().forEach(e ->
{
String name = e.getKey();
String value = e.getValue().getAsString();
os.item(h -> h.name(name).value(value));
});
}
})
.build();
}
}
return doRoute(kind, localAddress, remoteAddress, routeEx);
}
public CompletableFuture unroute(
long routeId)
{
long correlationId = controllerSpi.nextCorrelationId();
UnrouteFW unrouteRO = unrouteRW.wrap(commandBuffer, 0, commandBuffer.capacity())
.correlationId(correlationId)
.nukleus(name())
.routeId(routeId)
.build();
return controllerSpi.doUnroute(unrouteRO.typeId(), unrouteRO.buffer(), unrouteRO.offset(), unrouteRO.sizeof());
}
public CompletableFuture freeze()
{
long correlationId = controllerSpi.nextCorrelationId();
FreezeFW freeze = freezeRW.wrap(commandBuffer, 0, commandBuffer.capacity())
.correlationId(correlationId)
.nukleus(name())
.build();
return controllerSpi.doFreeze(freeze.typeId(), freeze.buffer(), freeze.offset(), freeze.sizeof());
}
private CompletableFuture doRoute(
RouteKind kind,
String localAddress,
String remoteAddress,
Flyweight extension)
{
final long correlationId = controllerSpi.nextCorrelationId();
final Role role = Role.valueOf(kind.ordinal());
final RouteFW routeRO = routeRW.wrap(commandBuffer, 0, commandBuffer.capacity())
.correlationId(correlationId)
.nukleus(name())
.role(b -> b.set(role))
.localAddress(localAddress)
.remoteAddress(remoteAddress)
.extension(extension.buffer(), extension.offset(), extension.sizeof())
.build();
return controllerSpi.doRoute(routeRO.typeId(), routeRO.buffer(), routeRO.offset(), routeRO.sizeof());
}
}