com.simiacryptus.util.StreamNanoHTTPD Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-util Show documentation
Show all versions of java-util Show documentation
Miscellaneous Utilities (Pure Java)
/*
* Copyright (c) 2018 by Andrew Charneski.
*
* The author 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 com.simiacryptus.util;
import com.simiacryptus.util.io.AsyncOutputStream;
import com.simiacryptus.util.io.TeeOutputStream;
import fi.iki.elonen.NanoHTTPD;
import java.awt.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Semaphore;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* The type Stream nano httpd.
*/
public class StreamNanoHTTPD extends FileNanoHTTPD {
/**
* The Data reciever.
*/
@javax.annotation.Nonnull
public final TeeOutputStream dataReciever;
/**
* The Gateway uri.
*/
@javax.annotation.Nonnull
protected final URI gatewayUri;
@javax.annotation.Nonnull
private final File primaryFile;
private final String mimeType;
private boolean autobrowse = true;
/**
* Instantiates a new Stream nano httpd.
*
* @param port the port
* @param mimeType the mime type
* @param primaryFile the file
* @throws IOException the io exception
*/
public StreamNanoHTTPD(final int port, final String mimeType, final File primaryFile) throws IOException {
super(primaryFile.getParentFile(), port);
try {
gatewayUri = null == primaryFile ? null : new URI(String.format("http://localhost:%s/%s", port, primaryFile.getName()));
} catch (@javax.annotation.Nonnull final URISyntaxException e) {
throw new RuntimeException(e);
}
this.primaryFile = primaryFile;
this.mimeType = mimeType;
dataReciever = null == primaryFile ? null : new TeeOutputStream(new FileOutputStream(primaryFile), true) {
@Override
public void close() {
try {
Thread.sleep(100);
com.simiacryptus.util.StreamNanoHTTPD.this.stop();
} catch (@javax.annotation.Nonnull final Exception e) {
e.printStackTrace();
}
}
};
}
@Override
@javax.annotation.Nonnull
public StreamNanoHTTPD init() throws IOException {
super.init();
if (!GraphicsEnvironment.isHeadless() && Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE))
new Thread(() -> {
try {
Thread.sleep(100);
if (null != gatewayUri && isAutobrowse()) Desktop.getDesktop().browse(gatewayUri);
} catch (@javax.annotation.Nonnull final Exception e) {
e.printStackTrace();
}
}).start();
return this;
}
/**
* Instantiates a new Stream nano httpd.
*
* @param port the port
* @throws IOException the io exception
*/
public StreamNanoHTTPD(final int port) throws IOException {
this(port, null, null);
}
/**
* Async handler function.
*
* @param pool the pool
* @param mimeType the mime type
* @param logic the logic
* @param async the async
* @return the function
*/
public static Function asyncHandler(@javax.annotation.Nonnull final ExecutorService pool, final String mimeType, @javax.annotation.Nonnull final Consumer logic, final boolean async) {
return session -> {
@javax.annotation.Nonnull final PipedInputStream snk = new PipedInputStream();
@javax.annotation.Nonnull final Semaphore onComplete = new Semaphore(0);
pool.submit(() -> {
try (@javax.annotation.Nonnull OutputStream out = new BufferedOutputStream(new AsyncOutputStream(new PipedOutputStream(snk)))) {
try {
logic.accept(out);
} finally {
onComplete.release();
}
} catch (@javax.annotation.Nonnull final IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
if (!async) {
try {
onComplete.acquire();
} catch (@javax.annotation.Nonnull final InterruptedException e) {
throw new RuntimeException(e);
}
}
return NanoHTTPD.newChunkedResponse(Response.Status.OK, mimeType, new BufferedInputStream(snk));
};
}
/**
* Add async handler.
*
* @param path the path
* @param mimeType the mime type
* @param logic the logic
* @param async the async
*/
public void addAsyncHandler(final CharSequence path, final String mimeType, @javax.annotation.Nonnull final Consumer logic, final boolean async) {
addSessionHandler(path, com.simiacryptus.util.StreamNanoHTTPD.asyncHandler(pool, mimeType, logic, async));
}
@Override
public Response serve(final IHTTPSession session) {
String requestPath = session.getUri();
while (requestPath.startsWith("/")) {
requestPath = requestPath.substring(1);
}
if (null != primaryFile && requestPath.equals(primaryFile.getName())) {
try {
@javax.annotation.Nonnull final Response response = NanoHTTPD.newChunkedResponse(Response.Status.OK, mimeType, new BufferedInputStream(dataReciever.newInputStream()));
response.setGzipEncoding(false);
return response;
} catch (@javax.annotation.Nonnull final IOException e) {
throw new RuntimeException(e);
}
}
else {
return super.serve(session);
}
}
@Override
protected boolean useGzipWhenAccepted(final Response r) {
return false;
}
public boolean isAutobrowse() {
return autobrowse;
}
public StreamNanoHTTPD setAutobrowse(boolean autobrowse) {
this.autobrowse = autobrowse;
return this;
}
}