svnserver.ext.gitlfs.storage.network.LfsHttpStorage.java Source code

Java tutorial

Introduction

Here is the source code for svnserver.ext.gitlfs.storage.network.LfsHttpStorage.java

Source

/**
 * This file is part of git-as-svn. It is subject to the license terms
 * in the LICENSE file found in the top-level directory of this distribution
 * and at http://www.gnu.org/licenses/gpl-2.0.html. No part of git-as-svn,
 * including this file, may be copied, modified, propagated, or distributed
 * except according to the terms contained in the LICENSE file.
 */
package svnserver.ext.gitlfs.storage.network;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.bozaro.gitlfs.client.Client;
import ru.bozaro.gitlfs.client.auth.AuthProvider;
import ru.bozaro.gitlfs.client.exceptions.RequestException;
import ru.bozaro.gitlfs.client.io.StreamProvider;
import ru.bozaro.gitlfs.common.data.Link;
import ru.bozaro.gitlfs.common.data.Links;
import ru.bozaro.gitlfs.common.data.ObjectRes;
import ru.bozaro.gitlfs.common.data.Operation;
import svnserver.TemporaryOutputStream;
import svnserver.auth.User;
import svnserver.ext.gitlfs.storage.LfsReader;
import svnserver.ext.gitlfs.storage.LfsStorage;
import svnserver.ext.gitlfs.storage.LfsWriter;
import svnserver.ext.web.server.WebServer;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

/**
 * Http remote storage for LFS files.
 *
 * @author Artem V. Navrotskiy <bozaro@users.noreply.github.com>
 */
public class LfsHttpStorage implements LfsStorage {
    private static final int MAX_CACHE = 1000;
    @NotNull
    private static final Logger log = LoggerFactory.getLogger(LfsHttpStorage.class);
    @NotNull
    private final URL authUrl;
    @NotNull
    private final String authToken;
    @NotNull
    private final ObjectMapper mapper;
    @NotNull
    private final LoadingCache<User, Link> tokens;
    @NotNull
    private final HttpClient httpClient = HttpClients.createDefault();

    public LfsHttpStorage(@NotNull URL authUrl, @NotNull String authToken) {
        this.authUrl = authUrl;
        this.authToken = authToken;
        this.mapper = WebServer.createJsonMapper();
        this.tokens = CacheBuilder.newBuilder().maximumSize(MAX_CACHE).build(new CacheLoader<User, Link>() {
            public Link load(@NotNull User user) throws IOException {
                return getTokenUncached(user);
            }
        });
    }

    private void addParameter(@NotNull List<NameValuePair> params, @NotNull String key, @Nullable String value) {
        if (value != null) {
            params.add(new BasicNameValuePair(key, value));
        }
    }

    @NotNull
    private Link getTokenUncached(@NotNull User user) throws IOException {
        final HttpPost post = new HttpPost(authUrl.toString());
        final List<NameValuePair> params = new ArrayList<>();
        addParameter(params, "token", authToken);
        if (!user.isAnonymous()) {
            addParameter(params, "username", user.getUserName());
            addParameter(params, "realname", user.getRealName());
            addParameter(params, "external", user.getExternalId());
            addParameter(params, "email", user.getEmail());
        } else {
            addParameter(params, "anonymous", "true");
        }
        post.setEntity(new UrlEncodedFormEntity(params));
        try {
            final HttpResponse response = httpClient.execute(post);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                return mapper.readValue(response.getEntity().getContent(), Link.class);
            }
            throw new RequestException(post, response);
        } finally {
            post.abort();
        }
    }

    @NotNull
    private Link getToken(@NotNull User user) throws IOException {
        try {
            return tokens.get(user);
        } catch (ExecutionException e) {
            if (e.getCause() instanceof IOException) {
                throw (IOException) e.getCause();
            }
            if (e.getCause() instanceof Error) {
                throw (Error) e.getCause();
            }
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
            }
            throw new RuntimeException(e);
        }
    }

    public void invalidate(@NotNull User user) {
        tokens.invalidate(user);
    }

    @Nullable
    public ObjectRes getMeta(@NotNull String hash) throws IOException {
        final Client lfsClient = new Client(new UserAuthProvider(User.getAnonymous()), httpClient);
        return lfsClient.getMeta(hash);
    }

    public boolean putObject(@NotNull User user, StreamProvider streamProvider, String sha, long size)
            throws IOException {
        final Client lfsClient = new Client(new UserAuthProvider(user), httpClient);
        return lfsClient.putObject(streamProvider, sha, size);
    }

    @NotNull
    public InputStream getObject(@NotNull Links links) throws IOException {
        final Client lfsClient = new Client(new UserAuthProvider(User.getAnonymous()), httpClient);
        return lfsClient.getObject(null, links, TemporaryOutputStream::new).toInputStream();
    }

    @Nullable
    @Override
    public LfsReader getReader(@NotNull String oid) throws IOException {
        try {
            if (!oid.startsWith(OID_PREFIX))
                return null;
            final String hash = oid.substring(OID_PREFIX.length());
            final Client lfsClient = new Client(new UserAuthProvider(User.getAnonymous()), httpClient);
            final ObjectRes meta = lfsClient.getMeta(hash);
            if (meta == null || meta.getMeta() == null) {
                return null;
            }
            return new LfsHttpReader(this, meta.getMeta(), meta);
        } catch (RequestException e) {
            log.error("HTTP request error:" + e.getMessage() + "\n" + e.getRequestInfo());
            throw e;
        }
    }

    @NotNull
    @Override
    public LfsWriter getWriter(@Nullable User user) throws IOException {
        return new LfsHttpWriter(this, user == null ? User.getAnonymous() : user);
    }

    private final class UserAuthProvider implements AuthProvider {
        @NotNull
        private final User user;

        public UserAuthProvider(@NotNull User user) {
            this.user = user;
        }

        @NotNull
        @Override
        public Link getAuth(@NotNull Operation mode) throws IOException {
            return getToken(user);
        }

        @Override
        public void invalidateAuth(@NotNull Operation mode, @NotNull Link auth) {
            tokens.invalidate(user);
        }
    }
}