Skip to content
This repository has been archived by the owner on Jul 26, 2022. It is now read-only.

Commit

Permalink
* remove hugly switch/case and replace it with nice Request builder
Browse files Browse the repository at this point in the history
* nicely integrate daemon operation results inside CLI
* Add an AlreadySyncingResponse ==> in order to get someting nice in the CLI
  • Loading branch information
vwiencek committed Sep 8, 2014
1 parent 61ceb56 commit 512a45a
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 89 deletions.
111 changes: 61 additions & 50 deletions syncany-cli/src/main/java/org/syncany/cli/CommandLineClient.java
Expand Up @@ -64,14 +64,16 @@
import org.syncany.config.UserConfig;
import org.syncany.config.to.PortTO;
import org.syncany.operations.daemon.DaemonOperation;
import org.syncany.operations.daemon.messages.StatusFolderRequest;
import org.syncany.operations.daemon.messages.StatusFolderResponse;
import org.syncany.operations.daemon.messages.AlreadySyncingResponse;
import org.syncany.operations.daemon.messages.BadRequestResponse;
import org.syncany.operations.daemon.messages.api.FolderRequest;
import org.syncany.operations.daemon.messages.api.FolderResponse;
import org.syncany.operations.daemon.messages.api.MessageFactory;
import org.syncany.operations.daemon.messages.api.Request;
import org.syncany.operations.daemon.messages.api.Response;
import org.syncany.operations.status.StatusOperationOptions;
import org.syncany.util.EnvironmentUtil;
import org.syncany.util.PidFileUtil;
import org.syncany.util.StringUtil;

/**
* The command line client implements a typical CLI. It represents the first entry
Expand Down Expand Up @@ -324,6 +326,8 @@ private int runCommand(Command command, String commandName, String[] commandArgs
boolean needsToRunInInitializedScope = command.getRequiredCommandScope() == CommandScope.INITIALIZED_LOCALDIR;
boolean sendToRest = daemonRunning & localDirHandledInDaemonScope && needsToRunInInitializedScope;

command.setOut(out);

if (sendToRest) {
return sendToRest(command, commandName, commandArgs, portFile);
}
Expand All @@ -334,7 +338,6 @@ private int runCommand(Command command, String commandName, String[] commandArgs

private int runLocally(Command command, String[] commandArgs) {
command.setClient(this);
command.setOut(out);
command.setLocalDir(localDir);

// Run!
Expand Down Expand Up @@ -382,50 +385,11 @@ private int sendToRest(Command command, String commandName, String[] commandArgs

// Create and send HTTP/REST request

switch (commandName.toLowerCase()) {
case "status":
request = new StatusFolderRequest();
request.setId(Math.abs(new Random().nextInt()));
StatusOperationOptions statusOption = ((StatusCommand)command).parseOptions(args);
((StatusFolderRequest)request).setOptions(statusOption);
((StatusFolderRequest)request).setRoot(config.getLocalDir().getAbsolutePath());

break;

case "debug":
// TODO
break;

case "down":
// TODO
break;

case "genlink":
// TODO
break;

case "ls":
// TODO
break;

case "ls-remote":
// TODO
break;

case "restore":
// TODO
break;

case "up":
// TODO
break;

case "watch":
// TODO
break;

default:
return 0;
if (command.getRequiredCommandScope() == CommandScope.INITIALIZED_LOCALDIR) {
request = buildFolderRequestFromCommand(command, commandName, config.getLocalDir().getAbsolutePath());
}
else {
request = buildManagementRequestFromCommand(command, commandName);
}

post.setEntity(new StringEntity(MessageFactory.toRequest(request)));
Expand All @@ -439,8 +403,16 @@ private int sendToRest(Command command, String commandName, String[] commandArgs

Response response = MessageFactory.createResponse(responseStr);

command.setOut(out);
command.printResults(((StatusFolderResponse)response).getResult());
if (response instanceof FolderResponse) {
FolderResponse folderResponse = (FolderResponse)response;
command.printResults(folderResponse.getResult());
}
else if (response instanceof AlreadySyncingResponse) {
out.println("Daemon is already syncing, please retry later");
}
else if (response instanceof BadRequestResponse) {
out.println("Invalid Request : " + response.getMessage());
}

return 0;
}
Expand All @@ -450,6 +422,45 @@ private int sendToRest(Command command, String commandName, String[] commandArgs
}
}

private Request buildManagementRequestFromCommand(Command command, String commandName) throws Exception {
String thisPackage = "org.syncany.operations.daemon.messages";
String camelCaseMessageType = StringUtil.toCamelCase(commandName) + "ManagementRequest";
String fqMessageClassName = thisPackage + "." + camelCaseMessageType;

// Try to load!
try {
Class<? extends FolderRequest> message = Class.forName(fqMessageClassName).asSubclass(FolderRequest.class);
FolderRequest request = message.newInstance();
request.setId(new Random().nextInt());
request.setOptions(command.parseOptions(args));
return request;
}
catch (Exception e) {
logger.log(Level.INFO, "Could not find FQCN " + fqMessageClassName, e);
throw new Exception("Cannot read request class from request type: " + commandName, e);
}
}

private Request buildFolderRequestFromCommand(Command command, String commandName, String root) throws Exception {
String thisPackage = "org.syncany.operations.daemon.messages";
String camelCaseMessageType = StringUtil.toCamelCase(commandName) + "FolderRequest";
String fqMessageClassName = thisPackage + "." + camelCaseMessageType;

// Try to load!
try {
Class<? extends FolderRequest> message = Class.forName(fqMessageClassName).asSubclass(FolderRequest.class);
FolderRequest request = message.newInstance();
request.setRoot(root);
request.setId(new Random().nextInt());
request.setOptions(command.parseOptions(args));
return request;
}
catch (Exception e) {
logger.log(Level.INFO, "Could not find FQCN " + fqMessageClassName, e);
throw new Exception("Cannot read request class from request type: " + commandName, e);
}
}

private PortTO readPortConfig(File portFile) {
try {
return new Persister().read(PortTO.class, portFile);
Expand Down
Expand Up @@ -42,6 +42,7 @@
import org.syncany.database.SqlDatabase;
import org.syncany.operations.Assembler;
import org.syncany.operations.Downloader;
import org.syncany.operations.daemon.messages.AlreadySyncingResponse;
import org.syncany.operations.daemon.messages.BadRequestResponse;
import org.syncany.operations.daemon.messages.GetDatabaseVersionHeadersFolderRequest;
import org.syncany.operations.daemon.messages.GetDatabaseVersionHeadersFolderResponse;
Expand Down Expand Up @@ -150,10 +151,15 @@ public void onRequestReceived(FolderRequest folderRequest) {
logger.log(Level.INFO, "Received " + folderRequest);

try {
FolderRequestHandler handler = FolderRequestHandler.createFolderRequestHandler(folderRequest, config);
Response response = handler.handleRequest(folderRequest);

eventBus.post(response);
if (!watchOperation.isSyncRunning() && !watchOperation.isSyncRequested()) {
FolderRequestHandler handler = FolderRequestHandler.createFolderRequestHandler(folderRequest, config);
Response response = handler.handleRequest(folderRequest);
eventBus.post(response);
}
else {
logger.log(Level.WARNING, "FolderRequest discarded : ", folderRequest);
eventBus.post(new AlreadySyncingResponse(folderRequest.getId(), "FolderRequest discarded."));
}
}
catch (Exception e) {
eventBus.post(new BadRequestResponse(folderRequest.getId(), "Invalid request."));
Expand Down
@@ -0,0 +1,34 @@
/*
* Syncany, www.syncany.org
* Copyright (C) 2011-2014 Philipp C. Heckel <philipp.heckel@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.syncany.operations.daemon.messages;

import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;
import org.syncany.operations.daemon.messages.api.Response;

@Root(strict = false)
@Namespace(reference = "http://syncany.org/ws/1")
public class AlreadySyncingResponse extends Response {
public AlreadySyncingResponse() {
super(400, -1, null); // Required
}

public AlreadySyncingResponse(int requestId, String message) {
super(400, requestId, message);
}
}
Expand Up @@ -37,5 +37,5 @@ public GetDatabaseVersionHeadersFolderResponse(int requestId, String root, List<

this.root = root;
this.databaseVersionHeaders = new ArrayList<DatabaseVersionHeader>(databaseVersionHeaders);
}
}
}
Expand Up @@ -17,6 +17,7 @@
*/
package org.syncany.operations.daemon.messages;

import org.syncany.operations.OperationOptions;
import org.syncany.operations.daemon.messages.api.FolderRequest;
import org.syncany.operations.status.StatusOperationOptions;

Expand All @@ -27,7 +28,7 @@ public StatusOperationOptions getOptions() {
return options;
}

public void setOptions(StatusOperationOptions options) {
this.options = options;
public void setOptions(OperationOptions options) {
this.options = (StatusOperationOptions)options;
}
}
Expand Up @@ -18,10 +18,10 @@
package org.syncany.operations.daemon.messages;

import org.simpleframework.xml.Element;
import org.syncany.operations.daemon.messages.api.Response;
import org.syncany.operations.daemon.messages.api.FolderResponse;
import org.syncany.operations.status.StatusOperationResult;

public class StatusFolderResponse extends Response {
public class StatusFolderResponse extends FolderResponse {
@Element(required = true)
private StatusOperationResult result;

Expand All @@ -34,6 +34,7 @@ public StatusFolderResponse(StatusOperationResult result, int requestId) {
this.result = result;
}

@Override
public StatusOperationResult getResult() {
return result;
}
Expand Down
Expand Up @@ -18,8 +18,9 @@
package org.syncany.operations.daemon.messages.api;

import org.simpleframework.xml.Element;
import org.syncany.operations.OperationOptions;

public class FolderRequest extends Request {
public abstract class FolderRequest extends Request {
@Element(required = true)
private String root;

Expand All @@ -30,4 +31,8 @@ public String getRoot() {
public void setRoot(String root) {
this.root = root;
}

public void setOptions(OperationOptions option) {
// Nothing here
}
}
Expand Up @@ -17,12 +17,19 @@
*/
package org.syncany.operations.daemon.messages.api;

public class FolderResponse extends Response {
import org.syncany.operations.OperationResult;

public abstract class FolderResponse extends Response {
public FolderResponse() {
// Required default constructor!
}

public FolderResponse(int code, Integer requestId, String message) {
super(code, requestId, message);
}

public OperationResult getResult() {
// Need to be overridden
return null;
}
}
Expand Up @@ -33,6 +33,7 @@
import org.syncany.database.FileVersion;
import org.syncany.operations.daemon.LocalEventBus;
import org.syncany.operations.daemon.WatchServer;
import org.syncany.operations.daemon.messages.AlreadySyncingResponse;
import org.syncany.operations.daemon.messages.GetFileFolderRequest;
import org.syncany.operations.daemon.messages.GetFileFolderResponseInternal;
import org.syncany.operations.daemon.messages.GetFileHistoryFolderRequest;
Expand All @@ -41,7 +42,10 @@
import org.syncany.operations.daemon.messages.GetFileTreeFolderResponse;
import org.syncany.operations.daemon.messages.RestoreFileFolderRequest;
import org.syncany.operations.daemon.messages.RestoreFileFolderResponse;
import org.syncany.operations.daemon.messages.StatusFolderRequest;
import org.syncany.operations.daemon.messages.StatusFolderResponse;
import org.syncany.operations.daemon.messages.api.Response;
import org.syncany.operations.status.StatusOperationOptions;
import org.syncany.plugins.transfer.TransferSettings;
import org.syncany.tests.util.TestClient;
import org.syncany.tests.util.TestConfigUtil;
Expand Down Expand Up @@ -187,31 +191,28 @@ public void testWatchServer() throws Exception {
clientA.copyFile("file-1", "file-1.bak");

// CLI request while running.
CliRequest cliRequest = new CliRequest();
cliRequest.setId(30);
cliRequest.setRoot(clientA.getConfig().getLocalDir().getAbsolutePath());
cliRequest.setCommand("status");
cliRequest.setCommandArgs(new ArrayList<String>());
StatusFolderRequest statusRequest = new StatusFolderRequest();
StatusOperationOptions statusOperationOption = new StatusOperationOptions();
statusOperationOption.setForceChecksum(true);

statusRequest.setId(30);
statusRequest.setRoot(clientA.getConfig().getLocalDir().getAbsolutePath());
statusRequest.setOptions(statusOperationOption);

// Create big file to trigger sync
clientA.createNewFile("bigfileforlongsync", 5000);

// ^^ Now sync should start and we send 'status' requests
CliResponse cliResponse = null;
StatusFolderResponse statusResponse = null;
boolean syncRunningMessageReceived = false;

for (i = 30; i < 50; i++) {
cliRequest.setId(i);
eventBus.post(cliRequest);
statusRequest.setId(i);
eventBus.post(statusRequest);

response = waitForResponse(i);

assertTrue(response instanceof CliResponse);
cliResponse = (CliResponse) response;

System.out.println(cliResponse.getOutput());

if ("Cannot run CLI commands while sync is running or requested.\n".equals(cliResponse.getOutput())) {
if (response instanceof AlreadySyncingResponse) {
syncRunningMessageReceived = true;
break;
}
Expand All @@ -222,23 +223,23 @@ public void testWatchServer() throws Exception {
assertTrue(syncRunningMessageReceived);

// Allow daemon to sync

Thread.sleep(10000);
for (i = 50; i < 60; i++) {
cliRequest.setId(i);
eventBus.post(cliRequest);
statusRequest.setId(i);
eventBus.post(statusRequest);

response = waitForResponse(i);
cliResponse = (CliResponse) response;

if (!"Cannot run CLI commands while sync is running or requested.\n".equals(cliResponse.getOutput())) {
if (response instanceof StatusFolderResponse) {
break;
}

Thread.sleep(1000);
}

assertNotNull(cliResponse);
assertEquals("No local changes.\n", cliResponse.getOutput());
assertNotNull(response);
//assertEquals("No local changes.\n", cliResponse.getOutput());

// Restore file test

Expand Down

0 comments on commit 512a45a

Please sign in to comment.