// Copyright (C) 2018 The Android Open Source Project // // 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 com.googlesource.gerrit.plugins.replication; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.common.hash.Hashing; import com.google.gson.Gson; import com.google.inject.Inject; import com.google.inject.ProvisionException; import com.google.inject.Singleton; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import org.eclipse.jgit.lib.ObjectId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class EventsStorage { private static final Logger log = LoggerFactory.getLogger(EventsStorage.class); public static class ReplicateRefUpdate { public String project; public String ref; } private static Gson GSON = new Gson(); private final Path refUpdates; @Inject EventsStorage(ReplicationConfig config) { refUpdates = config.getEventsDirectory().resolve("ref-updates"); } public String persist(String project, String ref) { ReplicateRefUpdate r = new ReplicateRefUpdate(); r.project = project; r.ref = ref; String json = GSON.toJson(r) + "\n"; String eventKey = sha1(json).name(); Path file = refUpdates().resolve(eventKey); if (Files.exists(file)) { return eventKey; } try { Files.write(file, json.getBytes(UTF_8)); } catch (IOException e) { log.warn("Couldn't persist event {}", json); } return eventKey; } public void delete(String eventKey) { if (eventKey != null) { try { Files.delete(refUpdates().resolve(eventKey)); } catch (IOException e) { log.error("Error while deleting event {}", eventKey, e); } } } public List list() { ArrayList result = new ArrayList<>(); try (DirectoryStream events = Files.newDirectoryStream(refUpdates())) { for (Path e : events) { if (Files.isRegularFile(e)) { String json = new String(Files.readAllBytes(e), UTF_8); result.add(GSON.fromJson(json, ReplicateRefUpdate.class)); Files.delete(e); } } } catch (IOException e) { log.error("Error when firing pending events", e); } return result; } private ObjectId sha1(String s) { return ObjectId.fromRaw(Hashing.sha1().hashString(s, UTF_8).asBytes()); } private Path refUpdates() { try { return Files.createDirectories(refUpdates); } catch (IOException e) { throw new ProvisionException(String.format("Couldn't create %s", refUpdates), e); } } }