working on scanner API refactoring (doesn't compile yet)
parent
c7dd5bd663
commit
ceba09e65c
|
@ -1,20 +0,0 @@
|
||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package meerkat;
|
|
||||||
|
|
||||||
import "meerkat/voting.proto";
|
|
||||||
|
|
||||||
option java_package = "meerkat.protobuf";
|
|
||||||
|
|
||||||
// Container for scanned data
|
|
||||||
message ScannedData {
|
|
||||||
bytes channel = 1;
|
|
||||||
|
|
||||||
SignedEncryptedBallot signed_encrypted_ballot = 2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Container for error messages
|
|
||||||
message ErrorMsg {
|
|
||||||
string msg = 1;
|
|
||||||
}
|
|
|
@ -1,8 +1,11 @@
|
||||||
package meerkat.pollingstation;
|
package meerkat.pollingstation;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
import meerkat.pollingstation.controller.PollingStationControllerInterface;
|
import meerkat.pollingstation.controller.PollingStationControllerInterface;
|
||||||
|
import meerkat.pollingstation.controller.callbacks.ScanDataCallback;
|
||||||
import meerkat.pollingstation.controller.commands.PollingStationCommand;
|
import meerkat.pollingstation.controller.commands.PollingStationCommand;
|
||||||
import meerkat.pollingstation.controller.commands.ReceivedScanCommand;
|
import meerkat.pollingstation.controller.commands.ReceivedScanCommand;
|
||||||
|
import meerkat.protobuf.PollingStation;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -17,20 +20,31 @@ public class PollingStationMainController implements PollingStationControllerInt
|
||||||
private LinkedBlockingQueue<PollingStationCommand> queue;
|
private LinkedBlockingQueue<PollingStationCommand> queue;
|
||||||
private volatile boolean shutDownHasBeenCalled;
|
private volatile boolean shutDownHasBeenCalled;
|
||||||
|
|
||||||
private static ReceiverScanHandler server;
|
|
||||||
private static final String ADDRESS = "http://localhost";
|
|
||||||
private static final String SUB_ADDRESS = "";
|
|
||||||
private static final int PORT = 8080;
|
|
||||||
|
|
||||||
|
|
||||||
public PollingStationMainController() {
|
public PollingStationMainController() {
|
||||||
queue = new LinkedBlockingQueue<PollingStationCommand>();
|
queue = new LinkedBlockingQueue<PollingStationCommand>();
|
||||||
shutDownHasBeenCalled = false;
|
shutDownHasBeenCalled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(ReceiverScanHandler server) {
|
public void init(PollingStationScanner.Consumer server) {
|
||||||
server.setControllerQueue(queue);
|
server.subscribe(new FutureCallback<PollingStation.ScannedData>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(PollingStation.ScannedData result) {
|
||||||
|
if (result.getDataCase().equals(PollingStation.ScannedData.DataCase.BALLOT)) {
|
||||||
|
// TODO: Set request ID correctly?
|
||||||
|
int requestID = 1;
|
||||||
|
long serialNumber = result.getBallot().getSignedEncryptedBallot().getEncryptedBallot().getSerialNumber();
|
||||||
|
queue.add(new ReceivedScanCommand(requestID, serialNumber));
|
||||||
|
} else if (result.getDataCase().equals(PollingStation.ScannedData.DataCase.ERROR)) {
|
||||||
|
// TODO: Deal with scan errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
// TODO: deal with this? When is this called?
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
|
@ -6,6 +6,7 @@ package meerkat.pollingstation;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.protobuf.BoolValue;
|
import com.google.protobuf.BoolValue;
|
||||||
|
import meerkat.protobuf.Crypto;
|
||||||
import meerkat.protobuf.PollingStation;
|
import meerkat.protobuf.PollingStation;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
@ -17,6 +18,7 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_CONNECT_PATH;
|
||||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH;
|
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH;
|
||||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH;
|
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH;
|
||||||
import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF;
|
import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF;
|
||||||
|
@ -49,6 +51,15 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path(POLLING_STATION_WEB_SCANNER_CONNECT_PATH)
|
||||||
|
@Consumes(MEDIATYPE_PROTOBUF)
|
||||||
|
@Produces(MEDIATYPE_PROTOBUF)
|
||||||
|
@Override
|
||||||
|
public BoolValue connect(PollingStation.ConnectionClientData clientData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path(POLLING_STATION_WEB_SCANNER_SCAN_PATH)
|
@Path(POLLING_STATION_WEB_SCANNER_SCAN_PATH)
|
||||||
@Consumes(MEDIATYPE_PROTOBUF)
|
@Consumes(MEDIATYPE_PROTOBUF)
|
||||||
|
@ -58,6 +69,7 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc
|
||||||
|
|
||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
for (FutureCallback<PollingStation.ScannedData> callback : callbacks){
|
for (FutureCallback<PollingStation.ScannedData> callback : callbacks){
|
||||||
|
|
||||||
callback.onSuccess(scannedData);
|
callback.onSuccess(scannedData);
|
||||||
|
@ -71,26 +83,4 @@ public class PollingStationScannerWebApp implements PollingStationScanner.Produc
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
|
||||||
@Path(POLLING_STATION_WEB_SCANNER_ERROR_PATH)
|
|
||||||
@Consumes(MEDIATYPE_PROTOBUF)
|
|
||||||
@Produces(MEDIATYPE_PROTOBUF)
|
|
||||||
@Override
|
|
||||||
public BoolValue reportScanError(PollingStation.ErrorMsg errorMsg) {
|
|
||||||
|
|
||||||
boolean handled = false;
|
|
||||||
|
|
||||||
for (FutureCallback<PollingStation.ScannedData> callback : callbacks){
|
|
||||||
|
|
||||||
callback.onFailure(new IOException(errorMsg.getMsg()));
|
|
||||||
handled = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return BoolValue.newBuilder()
|
|
||||||
.setValue(handled)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
package meerkat.pollingstation;
|
package meerkat.pollingstation;
|
||||||
|
|
||||||
|
import meerkat.protobuf.PollingStation;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Laura on 3/20/2017.
|
* Created by Laura on 3/20/2017.
|
||||||
*/
|
*/
|
||||||
public class PollingStationToyRun {
|
public class PollingStationToyRun {
|
||||||
|
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private static PollingStationScanner.Consumer scanner;
|
private static PollingStationScanner.Consumer scanner;
|
||||||
private static final String ADDRESS = "http://localhost";
|
private static final String CONTEXT_PATH = "/scan";
|
||||||
private static final String SUB_ADDRESS = "";
|
|
||||||
private static final int PORT = 8080;
|
private static final int PORT = 8080;
|
||||||
|
|
||||||
public static void main(String [] args) {
|
public static void main(String [] args) throws Exception {
|
||||||
System.err.println("Setting up Scanner WebApp!");
|
System.err.println("Setting up Scanner WebApp!");
|
||||||
|
|
||||||
// scanner = new ReceiverScanHandler(PORT, SUB_ADDRESS);
|
// scanner = new ReceiverScanHandler(PORT, SUB_ADDRESS);
|
||||||
|
@ -22,14 +26,17 @@ public class PollingStationToyRun {
|
||||||
// System.err.println("Could not start server: " + e.getMessage());
|
// System.err.println("Could not start server: " + e.getMessage());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
ReceiverScanHandler serverController = new ReceiverScanHandler(PORT, SUB_ADDRESS);
|
scanner = new PollingStationWebScanner(0, CONTEXT_PATH);
|
||||||
|
PollingStation.ConnectionServerData serverData = scanner.start(false);
|
||||||
|
|
||||||
|
|
||||||
PollingStationMainController controller = new PollingStationMainController();
|
PollingStationMainController controller = new PollingStationMainController();
|
||||||
controller.init(serverController);
|
controller.init(scanner);
|
||||||
|
|
||||||
Thread controllerThread = new Thread(controller);
|
Thread controllerThread = new Thread(controller);
|
||||||
controllerThread.setName("Meerkat PS-Controller Thread");
|
controllerThread.setName("Meerkat PS-Controller Thread");
|
||||||
Thread serverThread = new Thread(serverController);
|
// Thread serverThread = new Thread(serverController);
|
||||||
serverThread.setName("Meerkat PS-ServerScanner Thread");
|
// serverThread.setName("Meerkat PS-ServerScanner Thread");
|
||||||
|
|
||||||
controllerThread.start();
|
controllerThread.start();
|
||||||
serverThread.start();
|
serverThread.start();
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package meerkat.pollingstation;
|
package meerkat.pollingstation;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
import meerkat.protobuf.PollingStation;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.servlet.*;
|
import org.eclipse.jetty.servlet.*;
|
||||||
|
|
||||||
|
@ -17,20 +19,22 @@ import meerkat.rest.*;
|
||||||
* Created by Arbel on 05/05/2016.
|
* Created by Arbel on 05/05/2016.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class PollingStationWebScanner implements PollingStationScanner.Consumer{
|
public class PollingStationWebScanner implements PollingStationScanner.Consumer {
|
||||||
|
|
||||||
public final static String CALLBACKS_ATTRIBUTE_NAME = "controller";
|
public final static String CALLBACKS_ATTRIBUTE_NAME = "controller";
|
||||||
|
|
||||||
private final Server server;
|
private final Server server;
|
||||||
private final List<FutureCallback<ScannedData>> callbacks;
|
private final List<FutureCallback<ScannedData>> callbacks;
|
||||||
|
boolean verifyScanner;
|
||||||
|
byte nonce[];
|
||||||
|
|
||||||
public PollingStationWebScanner(int port, String subAddress) {
|
public PollingStationWebScanner(int port, String contextPath) {
|
||||||
|
|
||||||
callbacks = new LinkedList<>();
|
callbacks = new LinkedList<>();
|
||||||
|
|
||||||
server = new Server(port);
|
server = new Server(port);
|
||||||
|
|
||||||
ServletContextHandler servletContextHandler = new ServletContextHandler(server, subAddress);
|
ServletContextHandler servletContextHandler = new ServletContextHandler(server, contextPath);
|
||||||
servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, (Iterable<FutureCallback<ScannedData>>) callbacks);
|
servletContextHandler.setAttribute(CALLBACKS_ATTRIBUTE_NAME, (Iterable<FutureCallback<ScannedData>>) callbacks);
|
||||||
|
|
||||||
ResourceConfig resourceConfig = new ResourceConfig(PollingStationScannerWebApp.class);
|
ResourceConfig resourceConfig = new ResourceConfig(PollingStationScannerWebApp.class);
|
||||||
|
@ -42,9 +46,17 @@ public class PollingStationWebScanner implements PollingStationScanner.Consumer{
|
||||||
servletContextHandler.addServlet(servletHolder, "/*");
|
servletContextHandler.addServlet(servletHolder, "/*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() throws Exception {
|
public PollingStation.ConnectionServerData start(boolean verifyScanner) throws Exception {
|
||||||
|
this.verifyScanner = verifyScanner;
|
||||||
|
nonce = new byte[32];
|
||||||
|
new SecureRandom().nextBytes(nonce);
|
||||||
|
|
||||||
|
|
||||||
server.start();
|
server.start();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||||
/**
|
/**
|
||||||
* Created by Laura on 3/20/2017.
|
* Created by Laura on 3/20/2017.
|
||||||
*/
|
*/
|
||||||
public class ReceiverScanHandler implements PollingStationScanner.Consumer, Runnable{
|
public class ReceiverScanHandler implements PollingStationScanner.Consumer, Runnable {
|
||||||
|
|
||||||
public final static String CALLBACKS_ATTRIBUTE_NAME = "controller";
|
public final static String CALLBACKS_ATTRIBUTE_NAME = "controller";
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ public class ReceiverScanHandler implements PollingStationScanner.Consumer, Runn
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() throws Exception {
|
public PollingStation.ConnectionServerData start(boolean verifyScanner) throws Exception {
|
||||||
server.start();
|
server.start();
|
||||||
while (! wasShutDownCalled()) {
|
while (! wasShutDownCalled()) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import com.google.protobuf.BoolValue;
|
||||||
import meerkat.pollingstation.controller.callbacks.ScanCallback;
|
import meerkat.pollingstation.controller.callbacks.ScanCallback;
|
||||||
import meerkat.pollingstation.controller.callbacks.ScanDataCallback;
|
import meerkat.pollingstation.controller.callbacks.ScanDataCallback;
|
||||||
import meerkat.pollingstation.controller.callbacks.ScanErrorCallback;
|
import meerkat.pollingstation.controller.callbacks.ScanErrorCallback;
|
||||||
|
import meerkat.protobuf.Crypto;
|
||||||
import meerkat.protobuf.PollingStation;
|
import meerkat.protobuf.PollingStation;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
@ -16,6 +17,7 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_CONNECT_PATH;
|
||||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH;
|
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH;
|
||||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH;
|
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH;
|
||||||
import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF;
|
import static meerkat.rest.Constants.MEDIATYPE_PROTOBUF;
|
||||||
|
@ -48,12 +50,37 @@ public class ReceiverWebAPI implements PollingStationScanner.Producer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path(POLLING_STATION_WEB_SCANNER_CONNECT_PATH)
|
||||||
|
@Consumes(MEDIATYPE_PROTOBUF)
|
||||||
|
@Produces(MEDIATYPE_PROTOBUF)
|
||||||
|
@Override
|
||||||
|
public BoolValue connect(PollingStation.ConnectionClientData clientData) {
|
||||||
|
|
||||||
|
boolean sent = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ScanDataCallback callback = new ScanDataCallback(scannedData);
|
||||||
|
|
||||||
|
callbacks.add(callback);
|
||||||
|
sent = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return BoolValue.newBuilder()
|
||||||
|
.setValue(sent)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path(POLLING_STATION_WEB_SCANNER_SCAN_PATH)
|
@Path(POLLING_STATION_WEB_SCANNER_SCAN_PATH)
|
||||||
@Consumes(MEDIATYPE_PROTOBUF)
|
@Consumes(MEDIATYPE_PROTOBUF)
|
||||||
@Produces(MEDIATYPE_PROTOBUF)
|
@Produces(MEDIATYPE_PROTOBUF)
|
||||||
@Override
|
@Override
|
||||||
public BoolValue newScan(PollingStation.ScannedData scannedData) {
|
public BoolValue newScan(PollingStation.ScannedData scannedData, Crypto.Signature scannedDataSignature) {
|
||||||
|
|
||||||
boolean sent = false;
|
boolean sent = false;
|
||||||
|
|
||||||
|
@ -83,7 +110,7 @@ public class ReceiverWebAPI implements PollingStationScanner.Producer {
|
||||||
@Consumes(MEDIATYPE_PROTOBUF)
|
@Consumes(MEDIATYPE_PROTOBUF)
|
||||||
@Produces(MEDIATYPE_PROTOBUF)
|
@Produces(MEDIATYPE_PROTOBUF)
|
||||||
@Override
|
@Override
|
||||||
public BoolValue reportScanError(PollingStation.ErrorMsg errorMsg) {
|
public BoolValue reportScanError(PollingStation.ErrorMsg errorMsg, Crypto.Signature errorMsgSignature) {
|
||||||
|
|
||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
|
|
||||||
|
@ -104,4 +131,5 @@ public class ReceiverWebAPI implements PollingStationScanner.Producer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package meerkat.pollingstation.controller;
|
package meerkat.pollingstation.controller;
|
||||||
|
|
||||||
import meerkat.pollingstation.ReceiverScanHandler;
|
import meerkat.pollingstation.PollingStationScanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for the controller component of the polling station
|
* An interface for the controller component of the polling station
|
||||||
|
@ -11,12 +11,10 @@ public interface PollingStationControllerInterface extends Runnable {
|
||||||
* (see VotingBoothController)
|
* (see VotingBoothController)
|
||||||
*/
|
*/
|
||||||
// TODO: 4/16/2017 complete with proper arguments and exceptions
|
// TODO: 4/16/2017 complete with proper arguments and exceptions
|
||||||
public void init(ReceiverScanHandler server);
|
public void init(PollingStationScanner.Consumer server);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* an asynchronous call from Admin Console (If there is such one implemented) to shut down the system
|
* an asynchronous call from Admin Console (If there is such one implemented) to shut down the system
|
||||||
*/
|
*/
|
||||||
public void callShutDown();
|
public void callShutDown();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,6 @@ package meerkat.pollingstation.controller.callbacks;
|
||||||
/**
|
/**
|
||||||
* Created by Laura on 3/20/2017.
|
* Created by Laura on 3/20/2017.
|
||||||
*/
|
*/
|
||||||
public abstract class ScanCallback {
|
public interface ScanCallback {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import meerkat.protobuf.PollingStation;
|
||||||
/**
|
/**
|
||||||
* Created by Laura on 3/20/2017.
|
* Created by Laura on 3/20/2017.
|
||||||
*/
|
*/
|
||||||
public class ScanDataCallback extends ScanCallback implements FutureCallback<PollingStation.ScannedData> {
|
public class ScanDataCallback implements ScanCallback, FutureCallback<PollingStation.ScannedData> {
|
||||||
|
|
||||||
private final PollingStation.ScannedData expectedData;
|
private final PollingStation.ScannedData expectedData;
|
||||||
private boolean dataIsAsExpected;
|
private boolean dataIsAsExpected;
|
||||||
|
@ -22,7 +22,8 @@ public class ScanDataCallback extends ScanCallback implements FutureCallback<Pol
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(PollingStation.ScannedData result) {
|
public void onSuccess(PollingStation.ScannedData result) {
|
||||||
dataIsAsExpected = result.getChannel().equals(expectedData.getChannel());
|
|
||||||
|
dataIsAsExpected = result.getBallot().getChannel().equals(expectedData.getBallot().getChannel());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,6 +2,7 @@ package meerkat.pollingstation;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
import meerkat.protobuf.PollingStation;
|
||||||
import meerkat.protobuf.PollingStation.ErrorMsg;
|
import meerkat.protobuf.PollingStation.ErrorMsg;
|
||||||
import meerkat.protobuf.PollingStation.ScannedData;
|
import meerkat.protobuf.PollingStation.ScannedData;
|
||||||
import meerkat.rest.Constants;
|
import meerkat.rest.Constants;
|
||||||
|
@ -10,6 +11,8 @@ import meerkat.rest.ProtobufMessageBodyWriter;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.ws.rs.client.Client;
|
import javax.ws.rs.client.Client;
|
||||||
import javax.ws.rs.client.ClientBuilder;
|
import javax.ws.rs.client.ClientBuilder;
|
||||||
|
@ -24,18 +27,16 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
|
||||||
public class Receiver_ClientTest {
|
public class Receiver_ClientTest {
|
||||||
|
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
private PollingStationScanner.Consumer scanner;
|
private PollingStationScanner.Consumer scanner;
|
||||||
private static final int PSC_PORT = 8880;
|
private static final String CONTEXT_PATH = "/scan";
|
||||||
private static final String PSC_HOST = "localhost";
|
|
||||||
private static final String PSC_SCANNER_PATH = "";
|
|
||||||
|
|
||||||
private static final String PSC_URL = "http://" + PSC_HOST + ":" + PSC_PORT + PSC_SCANNER_PATH;
|
|
||||||
|
|
||||||
private Semaphore semaphore;
|
private Semaphore semaphore;
|
||||||
private Throwable thrown;
|
private Throwable thrown;
|
||||||
private boolean dataIsAsExpected;
|
private boolean dataIsAsExpected;
|
||||||
|
|
||||||
|
PollingStation.ConnectionServerData serverData = null;
|
||||||
|
|
||||||
private class ScanHandler implements FutureCallback<ScannedData> {
|
private class ScanHandler implements FutureCallback<ScannedData> {
|
||||||
|
|
||||||
private final ScannedData expectedData;
|
private final ScannedData expectedData;
|
||||||
|
@ -58,43 +59,26 @@ public class Receiver_ClientTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ErrorHandler implements FutureCallback<ScannedData> {
|
|
||||||
|
|
||||||
private final String expectedErrorMessage;
|
|
||||||
|
|
||||||
public ErrorHandler(String expectedErrorMessage) {
|
|
||||||
this.expectedErrorMessage = expectedErrorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSuccess(ScannedData result) {
|
|
||||||
dataIsAsExpected = false;
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable t) {
|
|
||||||
dataIsAsExpected = t.getMessage().equals(expectedErrorMessage);
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
||||||
System.err.println("Setting up Scanner WebApp!");
|
System.err.println("Setting up Scanner WebApp!");
|
||||||
|
|
||||||
scanner = new ReceiverScanHandler(PSC_PORT, PSC_SCANNER_PATH);
|
scanner = new PollingStationWebScanner(0, CONTEXT_PATH);
|
||||||
|
|
||||||
semaphore = new Semaphore(0);
|
semaphore = new Semaphore(0);
|
||||||
thrown = null;
|
thrown = null;
|
||||||
|
|
||||||
|
PollingStation.ConnectionServerData serverData = null;
|
||||||
try {
|
try {
|
||||||
scanner.start();
|
serverData = scanner.start(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertThat("Could not start server: " + e.getMessage(), false);
|
assertThat("Could not start server: " + e.getMessage(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Started scanner web service. API endpoint: {}", serverData.getServerUrl());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -103,13 +87,17 @@ public class Receiver_ClientTest {
|
||||||
byte[] data = {(byte) 1, (byte) 2};
|
byte[] data = {(byte) 1, (byte) 2};
|
||||||
|
|
||||||
ScannedData scannedData = ScannedData.newBuilder()
|
ScannedData scannedData = ScannedData.newBuilder()
|
||||||
.setChannel(ByteString.copyFrom(data))
|
.setBallot(PollingStation.ScannedBallot.newBuilder()
|
||||||
|
.setChannel(ByteString.copyFrom(data))
|
||||||
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
scanner.subscribe(new ScanHandler(scannedData));
|
scanner.subscribe(new ScanHandler(scannedData));
|
||||||
|
|
||||||
ScannerClientAPI scannerClient = new ScannerClientAPI(PSC_URL + POLLING_STATION_WEB_SCANNER_SCAN_PATH);
|
PollingStationScanner.Producer scannerClient = new ScannerClientAPI()
|
||||||
scannerClient.sendScan(scannedData);
|
|
||||||
|
ScannerClientAPI(PSC_URL + POLLING_STATION_WEB_SCANNER_SCAN_PATH);
|
||||||
|
scannerClient.newScan(scannedData, null);
|
||||||
|
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
assertThat("Scanner has thrown an error", thrown == null);
|
assertThat("Scanner has thrown an error", thrown == null);
|
||||||
|
@ -126,7 +114,10 @@ public class Receiver_ClientTest {
|
||||||
|
|
||||||
scanner.subscribe(new ErrorHandler(errorMsg.getMsg()));
|
scanner.subscribe(new ErrorHandler(errorMsg.getMsg()));
|
||||||
|
|
||||||
ScannerClientAPI scannerClient = new ScannerClientAPI(PSC_URL + POLLING_STATION_WEB_SCANNER_ERROR_PATH);
|
ScannerClientAPI scannerClient = new ScannerClientAPI();
|
||||||
|
|
||||||
|
|
||||||
|
PSC_URL + POLLING_STATION_WEB_SCANNER_ERROR_PATH);
|
||||||
scannerClient.sendError(errorMsg);
|
scannerClient.sendError(errorMsg);
|
||||||
|
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
|
|
|
@ -106,7 +106,6 @@ idea {
|
||||||
|
|
||||||
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
|
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
|
||||||
|
|
||||||
println "Adding $srcDir"
|
|
||||||
// add protobuf generated sources to generated source dir.
|
// add protobuf generated sources to generated source dir.
|
||||||
if ("test".equals(sourceSet.name)) {
|
if ("test".equals(sourceSet.name)) {
|
||||||
testSourceDirs += file(srcDir)
|
testSourceDirs += file(srcDir)
|
||||||
|
|
|
@ -9,5 +9,6 @@ public interface PollingStationConstants {
|
||||||
|
|
||||||
public static final String POLLING_STATION_WEB_SCANNER_SCAN_PATH = "/scan";
|
public static final String POLLING_STATION_WEB_SCANNER_SCAN_PATH = "/scan";
|
||||||
public static final String POLLING_STATION_WEB_SCANNER_ERROR_PATH = "/error";
|
public static final String POLLING_STATION_WEB_SCANNER_ERROR_PATH = "/error";
|
||||||
|
public static final String POLLING_STATION_WEB_SCANNER_CONNECT_PATH = "/connect";
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ package meerkat.pollingstation;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.protobuf.BoolValue;
|
import com.google.protobuf.BoolValue;
|
||||||
|
import meerkat.protobuf.Crypto;
|
||||||
import meerkat.protobuf.PollingStation.*;
|
import meerkat.protobuf.PollingStation.*;
|
||||||
/**
|
/**
|
||||||
* Created by Arbel on 05/05/2016.
|
* Created by Arbel on 05/05/2016.
|
||||||
|
@ -17,10 +18,13 @@ public interface PollingStationScanner {
|
||||||
public interface Consumer {
|
public interface Consumer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the connection to the scanner and begins receiving scans
|
* Sets up the connection to the scanner and begins receiving scans.
|
||||||
|
* Returns the data the scanner client will need to connect
|
||||||
|
* If verifyScanner is true, will verify that scanner has the correct nonce before
|
||||||
|
* allowing connection, and verify signatures on scanned data.
|
||||||
* @throws Exception when the operation fails
|
* @throws Exception when the operation fails
|
||||||
*/
|
*/
|
||||||
public void start() throws Exception;
|
public ConnectionServerData start(boolean verifyScanner) throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the connection to the scanner
|
* Closes the connection to the scanner
|
||||||
|
@ -34,7 +38,6 @@ public interface PollingStationScanner {
|
||||||
* @param scanCallback is the handler for scanned data
|
* @param scanCallback is the handler for scanned data
|
||||||
*/
|
*/
|
||||||
public void subscribe(FutureCallback<ScannedData> scanCallback);
|
public void subscribe(FutureCallback<ScannedData> scanCallback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,6 +45,13 @@ public interface PollingStationScanner {
|
||||||
*/
|
*/
|
||||||
public interface Producer {
|
public interface Producer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to the polling station server.
|
||||||
|
* The client data contains the scanner ID and optional verification data.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public BoolValue connect(ConnectionClientData clientData);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a scan to all subscribers
|
* Sends a scan to all subscribers
|
||||||
* @param scannedData contains the scanned data
|
* @param scannedData contains the scanned data
|
||||||
|
@ -49,13 +59,6 @@ public interface PollingStationScanner {
|
||||||
*/
|
*/
|
||||||
public BoolValue newScan(ScannedData scannedData);
|
public BoolValue newScan(ScannedData scannedData);
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies subscribers about an error that occurred during scan
|
|
||||||
* @param errorMsg is the error that occurred
|
|
||||||
* @return a BoolValue containing TRUE iff the error has been sent to at least one subscriber
|
|
||||||
*/
|
|
||||||
public BoolValue reportScanError(ErrorMsg errorMsg);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package meerkat.pollingstation;
|
package meerkat.pollingstation;
|
||||||
|
|
||||||
import com.google.protobuf.BoolValue;
|
import com.google.protobuf.BoolValue;
|
||||||
import meerkat.protobuf.BulletinBoardAPI;
|
import meerkat.protobuf.Crypto;
|
||||||
import meerkat.protobuf.PollingStation;
|
import meerkat.protobuf.PollingStation;
|
||||||
import meerkat.rest.Constants;
|
import meerkat.rest.Constants;
|
||||||
import meerkat.rest.ProtobufMessageBodyReader;
|
import meerkat.rest.ProtobufMessageBodyReader;
|
||||||
|
@ -13,13 +13,10 @@ import javax.ws.rs.client.Entity;
|
||||||
import javax.ws.rs.client.WebTarget;
|
import javax.ws.rs.client.WebTarget;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_ERROR_PATH;
|
|
||||||
import static meerkat.pollingstation.PollingStationConstants.POLLING_STATION_WEB_SCANNER_SCAN_PATH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Laura on 3/20/2017.
|
* Created by Laura on 3/20/2017.
|
||||||
*/
|
*/
|
||||||
public class ScannerClientAPI {
|
public class ScannerClientAPI implements PollingStationScanner.Producer {
|
||||||
private Client client;
|
private Client client;
|
||||||
private WebTarget webTarget;
|
private WebTarget webTarget;
|
||||||
|
|
||||||
|
@ -30,27 +27,38 @@ public class ScannerClientAPI {
|
||||||
webTarget = client.target(url);
|
webTarget = client.target(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the scanned data to the polling station server
|
* Sends the scanned data to the polling station server
|
||||||
* @param scannedData
|
* @param scannedData
|
||||||
* @return boolean value: true if the data was sent successfully, false otherwise
|
* @return boolean value: true if the data was sent successfully, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean sendScan(PollingStation.ScannedData scannedData) {
|
@Override
|
||||||
Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF));
|
public BoolValue newScan(PollingStation.ScannedData scannedData) {
|
||||||
|
|
||||||
|
Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(scannedData, Constants.MEDIATYPE_PROTOBUF),
|
||||||
|
);
|
||||||
BoolValue res = response.readEntity(BoolValue.class);
|
BoolValue res = response.readEntity(BoolValue.class);
|
||||||
response.close();
|
response.close();
|
||||||
return res.getValue();
|
return res.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the error message to the polling station server
|
public void close() {
|
||||||
* @param errorMsg
|
client.close();
|
||||||
* @return boolean value: true if the error message was sent successfully, false otherwise
|
|
||||||
*/
|
}
|
||||||
public boolean sendError(PollingStation.ErrorMsg errorMsg) {
|
|
||||||
Response response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(errorMsg, Constants.MEDIATYPE_PROTOBUF));
|
@Override
|
||||||
BoolValue res = response.readEntity(BoolValue.class);
|
public BoolValue connect(PollingStation.ConnectionClientData clientData) {
|
||||||
response.close();
|
return null;
|
||||||
return res.getValue();
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BoolValue reportScanError(PollingStation.ErrorMsg errorMsg, Crypto.Signature errorMsgSignature) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package meerkat;
|
||||||
|
|
||||||
|
option java_package = "meerkat.protobuf";
|
||||||
|
|
||||||
|
import "meerkat/crypto.proto";
|
||||||
|
import "meerkat/voting.proto";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Data sent (out-of-band) by the server that the client will require to set up a connection
|
||||||
|
message ConnectionServerData {
|
||||||
|
// Web-API URL for the server
|
||||||
|
string server_url = 1;
|
||||||
|
|
||||||
|
// random nonce used for verification of the client.
|
||||||
|
bytes nonce = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data sent by the client in order to set up a connection
|
||||||
|
message ConnectionClientData {
|
||||||
|
// Key used to identify the client
|
||||||
|
SignatureVerificationKey scannerPK = 1;
|
||||||
|
|
||||||
|
// Nonce sent by connection-server
|
||||||
|
bytes nonce = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message ScannedBallot {
|
||||||
|
bytes channel = 1;
|
||||||
|
|
||||||
|
SignedEncryptedBallot signed_encrypted_ballot = 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container for error messages
|
||||||
|
message ScanError {
|
||||||
|
string msg = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container for scanned data
|
||||||
|
message ScannedData {
|
||||||
|
oneof data {
|
||||||
|
ScannedBallot ballot = 2;
|
||||||
|
ScanError error = 3;
|
||||||
|
}
|
||||||
|
uint64 serial = 4; // Serial number of the message
|
||||||
|
bytes scannerId = 5; // hash of the scannerPK
|
||||||
|
Signature scannerSig = 6; // signature on the serialzed form of data.
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue