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

com.aitusoftware.aether.net.Server Maven / Gradle / Ivy

/*
 * Copyright 2019 Aitu Software Limited.
 *
 * https://aitusoftware.com
 *
 * 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 com.aitusoftware.aether.net;

import com.aitusoftware.aether.Aether;
import com.aitusoftware.aether.event.StreamKey;
import com.aitusoftware.aether.event.SystemSnapshot;
import com.aitusoftware.aether.model.ChannelSessionKey;
import com.aitusoftware.aether.model.SubscriberCounterSet;
import com.aitusoftware.aether.net.model.PublisherData;
import com.aitusoftware.aether.net.model.SubscriberData;
import com.aitusoftware.aether.transport.CounterSnapshotSubscriber;
import com.google.gson.Gson;
import io.aeron.driver.MediaDriver;
import io.aeron.driver.ThreadingMode;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpServer;
import org.agrona.CloseHelper;
import org.agrona.SystemUtil;
import org.agrona.concurrent.SleepingMillisIdleStrategy;

import java.io.Closeable;
import java.util.*;

public final class Server extends AbstractVerticle
{
    public static final int HTTP_PORT = Integer.getInteger("aether.net.http.port", 8080);
    private final Context context;
    private MediaDriver mediaDriver;
    private CounterSnapshotSubscriber counterSnapshotSubscriber;
    private Aether aether;

    public Server(final Context context)
    {
        this.context = context;
    }

    public static void main(final String[] args)
    {
        SystemUtil.loadPropertiesFiles(args);
        launchServer(new Context());
    }

    public static Closeable launchServer(final Context context)
    {
        final VertxOptions vertxOptions = new VertxOptions();
        final Vertx vertx = Vertx.vertx(vertxOptions);
        final Closeable closeable = vertx::close;
        final DeploymentOptions deploymentOptions = new DeploymentOptions();
        vertx.deployVerticle(new Server(context), deploymentOptions);
        return closeable;
    }

    @Override
    public void start()
    {
        final SystemSnapshot systemSnapshot = new SystemSnapshot();
        final HttpServer httpServer = vertx.createHttpServer();
        final Gson gson = new Gson();
        final Mode mode = context.mode();
        if (mode == Mode.LOCAL)
        {
            aether = Aether.launch(new Aether.Context()
                .counterSnapshotListener(systemSnapshot)
                .mode(Aether.Mode.LOCAL)
                .transport(Aether.Transport.LOCAL));
        }
        else
        {
            mediaDriver = MediaDriver.launchEmbedded(new MediaDriver.Context()
                .threadingMode(ThreadingMode.SHARED)
                .sharedIdleStrategy(new SleepingMillisIdleStrategy(1L)));
            counterSnapshotSubscriber = new CounterSnapshotSubscriber(new CounterSnapshotSubscriber.Context()
                .aeronDirectoryName(mediaDriver.aeronDirectoryName())
                .counterSnapshotListener(systemSnapshot));
        }
        vertx.periodicStream(100).handler(i ->
        {
            if (counterSnapshotSubscriber != null)
            {
                counterSnapshotSubscriber.doWork();
            }
            else if (aether != null)
            {
                aether.doWork();
            }
        });
        httpServer.requestHandler(req ->
        {
            if (req.uri().endsWith(".js"))
            {
                req.response().putHeader("content-type", "text/javascript").sendFile("monitor.js");
            }
            else if (req.uri().endsWith(".json"))
            {
                final StringBuilder data = new StringBuilder();

                serialiseModel(systemSnapshot, gson, data);
                req.response().putHeader("content-type", "application/json").end(data.toString());
            }
            else
            {
                req.response().putHeader("content-type", "text/html").sendFile("monitor.html");
            }
        });
        httpServer
            .websocketHandler(ws -> ws.handler(buffer ->
            {
                final StringBuilder data = new StringBuilder();

                serialiseModel(systemSnapshot, gson, data);

                ws.writeTextMessage(data.toString());
            }))
            .listen(HTTP_PORT);
    }

    private void serialiseModel(final SystemSnapshot systemSnapshot, final Gson gson, final StringBuilder data)
    {
        final Map>> connectionsByStream =
            systemSnapshot.getConnectionsByStream();
        final Map>> treeView = new TreeMap<>();

        for (final Map.Entry>> streamKeyMapEntry :
            connectionsByStream.entrySet())
        {
            for (final ChannelSessionKey pubChannelSessionKey : streamKeyMapEntry.getValue().keySet())
            {
                final Set subscriberList = new TreeSet<>();
                final Set subChannelSessionKeys =
                    streamKeyMapEntry.getValue().get(pubChannelSessionKey);
                for (final ChannelSessionKey subChannelSessionKey : subChannelSessionKeys)
                {
                    final SubscriberCounterSet subscriberCounterSet =
                        systemSnapshot.getSubscriberCounterSet(subChannelSessionKey);
                    subscriberList.add(new SubscriberData(subChannelSessionKey.getLabel(), subscriberCounterSet));
                }

                final Set streamMap =
                    treeView.computeIfAbsent(streamKeyMapEntry.getKey().getChannel(), key -> new TreeMap<>())
                    .computeIfAbsent(streamKeyMapEntry.getKey().getStreamId(), key -> new TreeSet<>());

                final PublisherData publisherData =
                    new PublisherData(pubChannelSessionKey.getLabel(),
                    systemSnapshot.getPublisherCounterSet(pubChannelSessionKey));
                subscriberList.forEach(publisherData::addSubscriberData);
                streamMap.add(publisherData);
            }
        }

        final Map allData = new HashMap<>();
        allData.put("streams", treeView);
        allData.put("systemCounters", systemSnapshot.getSystemCounters());

        gson.toJson(allData, data);
    }

    @Override
    public void stop() throws Exception
    {
        super.stop();
        CloseHelper.quietClose(aether);
        CloseHelper.quietClose(counterSnapshotSubscriber);
        CloseHelper.quietClose(mediaDriver);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy