package org.cloudname.samples.service;
import static spark.Spark.init;
import static spark.Spark.port;
import static spark.Spark.staticFileLocation;
import static spark.Spark.webSocket;
import org.cloudname.core.BackendManager;
import org.cloudname.flags.Flag;
import org.cloudname.flags.Flags;
import org.cloudname.service.CloudnameService;
import org.cloudname.service.Endpoint;
import org.cloudname.service.InstanceCoordinate;
import org.cloudname.service.ServiceCoordinate;
import org.cloudname.service.ServiceData;
import org.cloudname.service.ServiceHandle;
import org.cloudname.service.ServiceListener;
import org.json.JSONObject;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
/**
* The server hosting the web page. Static pages (on the root) are served out of the resources,
* web socket is served through /messages.
*/
public class PacServer {
private static final Logger LOG = Logger.getLogger(PacServer.class.getName());
private final int httpPort = 4567;
@Flag (name = "cloudname-url", description = "Cloudname URL", required = true)
private static String cloudnameUrl = null;
@Flag (name = "coordinate", description = "Service coordinate", required = false)
private static String myCoordinate = "pacman.test.local";
private final CloudnameService service;
public static final NotificationPublisher publisher = new NotificationPublisher();
private PacServer() {
service = new CloudnameService(BackendManager.getBackend(cloudnameUrl));
}
private String getCreateNotification(
final InstanceCoordinate coordinate, final ServiceData serviceData) {
final Endpoint ep = serviceData.getEndpoint("http");
return new JSONObject()
.put("coordinate", coordinate.toCanonicalString())
.put("action", "created")
.put("host", ep != null ? ep.getHost() : null)
.put("port", ep != null ? ep.getPort() : null)
.toString();
}
private String getRemoveNotification(final InstanceCoordinate coordinate) {
return new JSONObject()
.put("coordinate", coordinate.toCanonicalString())
.put("action", "removed")
.toString();
}
private void connectToCloudname() {
final ServiceData myServiceData = new ServiceData();
myServiceData.addEndpoint(new Endpoint("http", "0.0.0.0", httpPort));
try (final ServiceHandle handle = service.registerService(
ServiceCoordinate.parse(myCoordinate), myServiceData)) {
final String[] ghostNames = new String[]{"pinky", "blinky", "inky", "clyde"};
for (final String name : ghostNames) {
final ServiceCoordinate ghostCoordinate = new ServiceCoordinate.Builder()
.fromCoordinate(ServiceCoordinate.parse(myCoordinate))
.setService(name)
.build();
LOG.info("Listening for " + ghostCoordinate);
service.addServiceListener(ghostCoordinate, new ServiceListener() {
@Override
public void onServiceCreated(
final InstanceCoordinate coordinate, final ServiceData serviceData) {
LOG.info("Service " + coordinate.toCanonicalString()
+ " with serviceData " + serviceData + " is created");
publisher.publish(getCreateNotification(coordinate, serviceData));
}
@Override
public void onServiceDataChanged(
final InstanceCoordinate coordinate, final ServiceData data) {
LOG.info("Service data changed for: " + coordinate.toCanonicalString()
+ " to: " + data.toString());
}
@Override
public void onServiceRemoved(final InstanceCoordinate coordinate) {
LOG.info("Service " + coordinate.toCanonicalString() + " was removed");
publisher.publish(getRemoveNotification(coordinate));
}
});
}
LOG.info("Connected, using coordinate " + handle.getCoordinate().toCanonicalString());
}
}
private void startServer() {
port(httpPort);
staticFileLocation("/demoServerHtml");
webSocket("/messages", NotificationsWebSocket.class);
LOG.info("Starting server on port " + httpPort + "....");
init();
}
/**
* Start the server. Registers in Cloudname, starts a heartbeat thread for the clients connected
* via web sockets and starts monitoring for services.
*/
public static void main(final String[] args) {
new Flags().loadOpts(PacServer.class).parse(args);
final PacServer demoServer = new PacServer();
demoServer.connectToCloudname();
// Start publishing a heartbeat
Executors.newSingleThreadExecutor().execute(() -> {
while (true) {
try {
Thread.sleep(10000L);
publisher.publish(new JSONObject()
.put("action", "heartbeat")
.put("time", System.currentTimeMillis())
.toString());
} catch (final InterruptedException ie) {
throw new RuntimeException(ie);
}
}
});
demoServer.startServer();
}
}