001/*
002 * Syncany, www.syncany.org
003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com>
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package org.syncany.operations.daemon;
019
020import java.io.File;
021import java.util.logging.Level;
022import java.util.logging.Logger;
023
024import org.simpleframework.xml.core.Persister;
025import org.syncany.config.Config;
026import org.syncany.config.ConfigException;
027import org.syncany.config.LocalEventBus;
028import org.syncany.config.to.PortTO;
029import org.syncany.operations.daemon.messages.AlreadySyncingResponse;
030import org.syncany.operations.daemon.messages.BadRequestResponse;
031import org.syncany.operations.daemon.messages.api.FolderRequest;
032import org.syncany.operations.daemon.messages.api.FolderRequestHandler;
033import org.syncany.operations.daemon.messages.api.Response;
034import org.syncany.operations.watch.WatchOperation;
035import org.syncany.operations.watch.WatchOperationOptions;
036import org.syncany.operations.watch.WatchOperationResult;
037
038import com.google.common.eventbus.Subscribe;
039
040/**
041 * The watch operation thread runs a {@link WatchOperation} in a thread. The
042 * underlying thred can be started using the {@link #start()} method, and stopped
043 * gracefully using {@link #stop()}.
044 *
045 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
046 */
047public class WatchRunner {
048        private static final Logger logger = Logger.getLogger(WatchRunner.class.getSimpleName());
049
050        private Config config;
051        private PortTO portTO;
052        private Thread watchThread;
053        private WatchOperation watchOperation;
054        private WatchOperationResult watchOperationResult;
055        private LocalEventBus eventBus;
056
057        public WatchRunner(Config config, WatchOperationOptions watchOperationOptions, PortTO portTO) throws ConfigException {
058                this.config = config;
059                this.portTO = portTO;
060                this.watchOperation = new WatchOperation(config, watchOperationOptions);
061
062                this.eventBus = LocalEventBus.getInstance();
063                this.eventBus.register(this);
064        }
065
066        public void start() {
067                watchThread = new Thread(new Runnable() {
068                        @Override
069                        public void run() {
070                                try {
071                                        logger.log(Level.INFO, "STARTING watch at" + config.getLocalDir());
072                                        watchOperationResult = null;
073
074                                        // Write port to portFile
075                                        File portFile = config.getPortFile();
076
077                                        portFile.createNewFile();
078                                        portFile.deleteOnExit();
079
080                                        new Persister().write(portTO, portFile);
081
082                                        // Start operation (blocks!)
083                                        watchOperationResult = watchOperation.execute();
084
085                                        logger.log(Level.INFO, "STOPPED watch at " + config.getLocalDir());
086                                }
087                                catch (Exception e) {
088                                        logger.log(Level.SEVERE, "ERROR while running watch at " + config.getLocalDir(), e);
089                                }
090                        }
091                }, "WR/" + config.getLocalDir().getName());
092
093                watchThread.start();
094        }
095
096        public void stop() {
097                watchOperation.stop();
098                config.getPortFile().delete();
099
100                watchThread = null;
101        }
102
103        public boolean hasStopped() {
104                return watchOperationResult != null;
105        }
106
107        public boolean isSyncRunning() {
108                return watchOperation.isSyncRunning();
109        }
110
111        @Subscribe
112        public void onRequestReceived(FolderRequest folderRequest) {
113                File requestRootFolder = new File(folderRequest.getRoot());
114                boolean localDirMatches = requestRootFolder.equals(config.getLocalDir());
115
116                if (localDirMatches) {
117                        logger.log(Level.INFO, "Received " + folderRequest);
118
119                        try {
120                                if (!watchOperation.isSyncRunning() && !watchOperation.isSyncRequested()) {
121                                        watchOperation.pause();
122
123                                        FolderRequestHandler handler = FolderRequestHandler.createFolderRequestHandler(folderRequest, config);
124                                        Response response = handler.handleRequest(folderRequest);
125
126                                        if (response != null) {
127                                                eventBus.post(response);
128                                        }
129
130                                        watchOperation.resume();
131                                }
132                                else {
133                                        logger.log(Level.WARNING, "FolderRequest discarded : ", folderRequest);
134                                        eventBus.post(new AlreadySyncingResponse(folderRequest.getId(), "FolderRequest discarded."));
135                                }
136                        }
137                        catch (Exception e) {
138                                logger.log(Level.FINE, "Failed to process request", e);
139                                eventBus.post(new BadRequestResponse(folderRequest.getId(), "Invalid request."));
140                        }
141                }
142        }
143}