All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.nscuro.wdm.binary.github.GitHubReleasesServiceImpl Maven / Gradle / Ivy

There is a newer version: 0.3.0
Show newest version
package com.github.nscuro.wdm.binary.github;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.nscuro.wdm.Platform;
import com.github.nscuro.wdm.binary.util.FileUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Optional;

import static com.github.nscuro.wdm.binary.util.HttpUtils.verifyContentTypeIsAnyOf;
import static com.github.nscuro.wdm.binary.util.HttpUtils.verifyStatusCodeIsAnyOf;
import static com.github.nscuro.wdm.binary.util.MimeType.APPLICATION_GZIP;
import static com.github.nscuro.wdm.binary.util.MimeType.APPLICATION_OCTET_STREAM;
import static com.github.nscuro.wdm.binary.util.MimeType.APPLICATION_ZIP;
import static java.lang.String.format;

final class GitHubReleasesServiceImpl implements GitHubReleasesService {

    private static final Logger LOGGER = LoggerFactory.getLogger(GitHubReleasesServiceImpl.class);

    private final HttpClient httpClient;

    private final ObjectMapper objectMapper;

    private final String gitHubUserName;

    private final String oAuthToken;

    GitHubReleasesServiceImpl(final HttpClient httpClient,
                              final ObjectMapper objectMapper,
                              @Nullable final String gitHubUserName,
                              @Nullable final String oAuthToken) {
        this.httpClient = httpClient;
        this.objectMapper = objectMapper;
        this.gitHubUserName = gitHubUserName;
        this.oAuthToken = oAuthToken;
    }

    /**
     * {@inheritDoc}
     */
    @Nonnull
    @Override
    public Optional getLatestRelease(final String repoOwner, final String repoName) throws IOException {
        return getGitHubReleaseFromPath("/releases/latest", repoOwner, repoName);
    }

    /**
     * {@inheritDoc}
     */
    @Nonnull
    @Override
    public Optional getReleaseByTagName(final String repoOwner, final String repoName, final String tagName) throws IOException {
        return getGitHubReleaseFromPath("/releases/tags/" + tagName, repoOwner, repoName);
    }

    /**
     * {@inheritDoc}
     */
    @Nonnull
    @Override
    public Optional getReleaseAssetForPlatform(final GitHubRelease release, final Platform platform) {
        return release.getAssets().stream()
                .filter(asset -> asset.getName().toLowerCase().contains(platform.getName().toLowerCase()))
                .findAny();
    }

    @Nonnull
    @Override
    public File downloadAsset(final GitHubReleaseAsset asset) throws IOException {
        final HttpGet request = new HttpGet(asset.getBrowserDownloadUrl());
        request.setHeader(HttpHeaders.ACCEPT, asset.getContentType());

        final File targetFile = FileUtils.getTempDirPath().resolve(asset.getName()).toFile();

        LOGGER.debug("Downloading archived binary to {}", targetFile);

        return httpClient.execute(request, httpResponse -> {
            verifyStatusCodeIsAnyOf(httpResponse, HttpStatus.SC_OK);
            verifyContentTypeIsAnyOf(httpResponse, APPLICATION_ZIP, APPLICATION_GZIP, APPLICATION_OCTET_STREAM);

            try (final FileOutputStream fileOutputStream = new FileOutputStream(targetFile)) {
                Optional.ofNullable(httpResponse.getEntity())
                        .orElseThrow(() -> new IllegalStateException("Response body was empty"))
                        .writeTo(fileOutputStream);
            }

            return targetFile;
        });
    }

    @Nonnull
    private Optional getGitHubReleaseFromPath(final String path, final String repoOwner, final String repoName) throws IOException {
        final HttpGet request = new HttpGet(buildRepositoryUrl(repoOwner, repoName) + path);
        request.setHeader(HttpHeaders.ACCEPT, "application/json; charset=utf-8");

        getApiCredentials().ifPresent(credentials -> {
                    try {
                        request.addHeader(new BasicScheme().authenticate(credentials, request, null));
                        LOGGER.debug("Basic auth credentials attached to request");
                    } catch (AuthenticationException e) {
                        LOGGER.error("Basic auth credentials could not be attached to request");
                    }
                }
        );

        final String jsonResponse = httpClient.execute(request, httpResponse -> {
            switch (httpResponse.getStatusLine().getStatusCode()) {
                case HttpStatus.SC_OK:
                    if (httpResponse.getEntity() == null) {
                        throw new IllegalStateException("Response body is empty");
                    } else {
                        return EntityUtils.toString(httpResponse.getEntity());
                    }
                case HttpStatus.SC_NOT_FOUND:
                    return null;
                default:
                    throw new IllegalStateException("Unexpected HTTP status");
            }
        });

        if (jsonResponse != null) {
            return Optional.of(objectMapper.readValue(jsonResponse, GitHubRelease.class));
        } else {
            return Optional.empty();
        }
    }

    @Nonnull
    Optional getApiCredentials() {
        if (gitHubUserName != null && oAuthToken != null) {
            return Optional.of(new UsernamePasswordCredentials(gitHubUserName, oAuthToken));
        } else {
            return Optional.empty();
        }
    }

    @Nonnull
    static String buildRepositoryUrl(final String repoOwner, final String repoName) {
        return format("https://api.github.com/repos/%s/%s", repoOwner, repoName);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy