/* * Copyright 2016 The Simple File Server Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sfs.filesystem.temp; import io.vertx.core.Context; import io.vertx.core.logging.Logger; import org.sfs.Server; import org.sfs.VertxContext; import org.sfs.rx.ObservableFuture; import org.sfs.rx.RxHelper; import rx.Observable; import java.io.File; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; import static io.vertx.core.logging.LoggerFactory.getLogger; import static java.lang.System.currentTimeMillis; import static java.nio.file.Files.deleteIfExists; import static java.util.concurrent.TimeUnit.SECONDS; import static org.sfs.rx.Defer.aVoid; import static rx.Observable.defer; public class TempDirectoryCleaner { private static final Logger LOGGER = getLogger(TempDirectoryCleaner.class); private Set<Long> periodics = new HashSet<>(); private Long ttl; private VertxContext<Server> vertxContext; private ExecutorService ioPool; public TempDirectoryCleaner() { } public Observable<Void> start(VertxContext<Server> vertxContext, long ttl) { this.ttl = ttl; this.vertxContext = vertxContext; this.ioPool = vertxContext.getIoPool(); Context context = vertxContext.vertx().getOrCreateContext(); return defer(() -> { ObservableFuture<Void> handler = RxHelper.observableFuture(); vertxContext.vertx() .fileSystem() .mkdirs(vertxContext.verticle().sfsFileSystem().tmpDirectory().toString(), null, handler.toHandler()); long id = vertxContext.vertx() .setPeriodic(SECONDS.toMillis(1), event -> RxHelper.executeBlocking(context, ioPool, () -> { deleteExpired(); return (Void) null; }) .single() .subscribe( aVoid -> { }, throwable -> LOGGER.warn("Unhandled Exception", throwable), () -> { })); periodics.add(id); return handler; }); } public Observable<Void> stop() { return defer(() -> { for (Long periodic : periodics) { vertxContext.vertx() .cancelTimer(periodic); } periodics.clear(); return aVoid(); }); } public Long getTtl() { return ttl; } protected void deleteExpired() { for (File expired : listExpired()) { try { deleteIfExists(expired.toPath()); } catch (Throwable e) { LOGGER.warn("Failed to delete " + expired.toPath().toString(), e); } } } protected File[] listExpired() { long now = currentTimeMillis(); File tmpFolder = vertxContext.verticle().sfsFileSystem().tmpDirectory().toFile(); File[] expired = tmpFolder.listFiles(pathname -> now - pathname.lastModified() >= ttl); return expired; } }