package test_streamer.client;
import com.sun.corba.se.spi.activation.Server;
import io.undertow.websockets.WebSocketExtension;
import io.undertow.websockets.client.WebSocketClient;
import io.undertow.websockets.client.WebSocketClientNegotiation;
import io.undertow.websockets.jsr.ServerWebSocketContainer;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import test_streamer.client.dto.ReadyCommand;
import test_streamer.client.event.ConnectEvent;
import test_streamer.client.handler.ClassProviderPortHandler;
import test_streamer.client.handler.DoTestHandler;
import test_streamer.client.ui.PanelNotification;
import test_streamer.client.ui.TrayNotification;
import us.bpsm.edn.Keyword;
import us.bpsm.edn.parser.Parseable;
import us.bpsm.edn.parser.Parser;
import us.bpsm.edn.parser.Parsers;
import javax.websocket.*;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.*;
import java.util.*;
import java.util.List;
import static test_streamer.client.ClientConfig.ClientConfigKey.CLASS_PROVIDER_URL;
import static test_streamer.client.ClientConfig.ClientConfigKey.SERVER_HOST;
/**
* Starts a client application.
*
* @author kawasima
*/
public class Main extends Application {
private static final Logger LOG = LoggerFactory.getLogger(Main.class);
private Session session;
private Parser ednParser = Parsers.newParser(Parsers.defaultConfiguration());
private final HandlerLookup handlerLookup = new HandlerLookup();
private List<ClientUI> uiList;
private ClientConfig config;
private boolean isTerminate = false;
@Override
public void init() {
uiList = new ArrayList<>();
this.config = new ClientConfig();
handlerLookup.registerHandler(
Keyword.newKeyword("do-test"),
new DoTestHandler(config, uiList));
handlerLookup.registerHandler(
Keyword.newKeyword("class-provider-port"),
new ClassProviderPortHandler(config));
}
private static List<WebSocketExtension> toExtensionList(final List<Extension> extensions) {
List<WebSocketExtension> ret = new ArrayList<>();
for (Extension e : extensions) {
final List<WebSocketExtension.Parameter> parameters = new ArrayList<>();
for (Extension.Parameter p : e.getParameters()) {
parameters.add(new WebSocketExtension.Parameter(p.getName(), p.getValue()));
}
ret.add(new WebSocketExtension(e.getName(), parameters));
}
return ret;
}
private WebSocketClient.ConnectionBuilder setProxy(WebSocketClient.ConnectionBuilder builder) {
String proxy = System.getenv("http_proxy");
if (proxy == null) {
proxy = System.getenv("HTTP_PROXY");
}
LOG.info("http_proxy = {}", proxy);
return (proxy != null) ? builder.setProxyUri(URI.create(proxy)) : builder;
}
public Session connect(final String testServerUrl) throws IOException, DeploymentException {
URI uri = URI.create(testServerUrl);
ServerWebSocketContainer wsContainer = (ServerWebSocketContainer) ContainerProvider.getWebSocketContainer();
WebSocketClient.ConnectionBuilder builder = new WebSocketClient.ConnectionBuilder(wsContainer.getXnioWorker(), wsContainer.getBufferPool(), uri);
builder = setProxy(builder);
ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();
WebSocketClientNegotiation clientNegotiation = new ClientNegotiation(cec.getPreferredSubprotocols(), toExtensionList(cec.getExtensions()), cec);
builder = builder.setClientNegotiation(clientNegotiation);
session = wsContainer.connectToServer(new Endpoint() {
@Override
public void onOpen(final Session session, EndpointConfig endpointConfig) {
session.addMessageHandler(String.class, message -> {
Parseable psb = Parsers.newParseable(new String(message));
Map<Keyword, Object> command = (Map)ednParser.nextValue (psb);
Handler handler = handlerLookup.getHandler((Keyword)command.get(Keyword.newKeyword("command")));
handler.handle(command, session);
});
uiList.forEach(ClientUI::standby);
String serverHost = config.getString(SERVER_HOST);
config.setObject(CLASS_PROVIDER_URL,
"ws://" + serverHost + "/wscl");
WebSocketUtil.send(session, new ReadyCommand());
}
@Override
public void onClose(final Session session, CloseReason closeReason) {
uiList.forEach(ClientUI::disconnect);
}
}, cec, builder);
return session;
}
public void start(Stage stage, String testServerUrl) throws IOException, DeploymentException {
try {
if (SystemTray.isSupported()) {
uiList.add(new TrayNotification());
}
PanelNotification panelUi = new PanelNotification();
uiList.add(panelUi);
Scene scene = new Scene(panelUi);
scene.getStylesheets().add("css/client.css");
stage.setOnCloseRequest(event -> {
Platform.runLater(() -> destroy());
stage.close();
Platform.exit();
});
stage.setScene(scene);
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
URI serverUri = URI.create(testServerUrl);
int port = serverUri.getPort();
config.setString(SERVER_HOST, serverUri.getHost() + (port > 0 ? ":" + port : "")
+ Optional.ofNullable(serverUri.getPath()).orElse(""));
String joinUrl = testServerUrl + (testServerUrl.endsWith("/")? "" : "/") + "join";
uiList.forEach(ui -> ui.addEventHandler(ConnectEvent.CONNECT_SERVER, e -> {
try {
connect(joinUrl);
} catch (Exception ex) {
ui.disconnect();
}
}));
try {
connect(joinUrl);
} catch (Exception ex) {
uiList.forEach(ClientUI::disconnect);
}
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
Platform.runLater(() -> {
destroy();
stage.close();
});
}));
}
public void destroy() {
isTerminate = true;
if (session != null && session.isOpen()) {
try {
session.close();
} catch (IOException ignore) {
}
}
handlerLookup.dispose();
}
protected String getTestStreamerUrl() {
Properties props = new Properties();
InputStream is = getClass().getResourceAsStream("/app.properties");
if (is == null) return null;
try {
props.load(is);
return props.getProperty("teststreamer.url");
} catch (IOException ex) {
return null;
}
}
@Override
public void start(Stage stage) throws Exception {
Policy.setPolicy(new Policy() {
@Override
public PermissionCollection getPermissions(CodeSource codesource) {
Permissions p = new Permissions();
p.add(new AllPermission());
return p;
}
});
Platform.setImplicitExit(false);
String testStreamerUrl = Optional.ofNullable(getTestStreamerUrl())
.orElse("ws://localhost:5000");
LOG.info("teststreamer url = {}", testStreamerUrl);
start(stage, testStreamerUrl);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) throws IOException, DeploymentException {
launch(args);
}
}