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

io.proximax.xpx.facade.upload.Upload Maven / Gradle / Ivy

There is a newer version: 0.1.0-beta.10
Show newest version
/*
 * Copyright 2018 ProximaX Limited
 *
 * 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 io.proximax.xpx.facade.upload;

import io.proximax.xpx.exceptions.PeerConnectionNotFoundException;
import io.proximax.xpx.facade.AbstractFacadeService;
import io.proximax.xpx.facade.connection.PeerConnection;
import io.proximax.xpx.facade.upload.MultiFileUploadResult.FileUploadResult;
import io.proximax.xpx.service.IpfsGatewaySyncService;
import io.proximax.xpx.service.TransactionAnnouncer;
import io.proximax.xpx.service.UploadDelegate;
import io.proximax.xpx.service.UploadDelegate.ResourceHashMessageWrapper;
import io.proximax.xpx.service.intf.UploadApi;
import io.proximax.xpx.strategy.privacy.PrivacyStrategy;
import io.proximax.xpx.utils.ContentTypeUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.nem.core.model.Message;
import org.nem.core.model.mosaic.Mosaic;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static java.lang.String.format;



/**
 * The Class Upload.
 */
public class Upload extends AbstractFacadeService {

	/** The peer connection. */
	private final PeerConnection peerConnection;

	/** The upload api. */
	private final UploadApi uploadApi;

	/** The transaction announcer. */
	private final TransactionAnnouncer transactionAnnouncer;

	private final UploadDelegate uploadDelegate;


	private final IpfsGatewaySyncService ipfsGatewaySyncService;

	/**
	 * Instantiates a new upload.
	 *
	 * @param peerConnection
	 *            the peer connection
	 * @throws PeerConnectionNotFoundException
	 *             the peer connection not found exception
	 */
	public Upload(PeerConnection peerConnection) {
		if (peerConnection == null) {
			throw new PeerConnectionNotFoundException("PeerConnection can't be null");
		}

		this.uploadApi = peerConnection.getUploadApi();
		this.transactionAnnouncer = peerConnection.getTransactionAnnouncer();
		this.peerConnection = peerConnection;
		this.uploadDelegate = new UploadDelegate(peerConnection.getUploadApi());
		this.ipfsGatewaySyncService = new IpfsGatewaySyncService(peerConnection.getSyncGateways());
	}

	/**
	 * Upload file.
	 *
	 * @param param
	 *            the upload parameter
	 * @return the upload data
	 * @throws UploadException
	 *             the upload exception
	 */
	public UploadResult uploadFile(UploadFileParameter param)
			throws UploadException {

		try {
			byte[] binaryContent = FileUtils.readFileToByteArray(param.getFile());
			return handleBinaryUpload(param.getPrivacyStrategy(), param.getSenderPrivateKey(), param.getReceiverPublicKey(),
					param.getContentType(), param.getKeywords(), param.getMetaDataAsString(), param.getName(), param.getMosaics(), binaryContent);
		} catch (UploadException e) {
			throw e;
		} catch (Exception e) {
			throw new UploadException(format("Error on uploading file data: %s", param.getFile().getAbsolutePath()), e);
		}
	}

	/**
	 * Upload data.
	 *
	 * @param param
	 *            the upload parameter
	 * @return the upload data
	 * @throws UploadException
	 *             the upload exception
	 */
	public UploadResult uploadTextData(UploadTextDataParameter param) throws UploadException {
		return handleTextDataUpload(param.getPrivacyStrategy(), param.getSenderPrivateKey(),
				param.getReceiverPublicKey(), param.getContentType(), param.getKeywords(),
				param.getMetaDataAsString(), param.getName(), param.getMosaics(),
				param.getData(), param.getEncoding());
	}

	/**
	 * Upload a binary file.
	 *
	 * @param param the upload parameter
	 * @return the upload data
	 * @throws UploadException the upload exception
	 */
	public UploadResult uploadBinary(UploadBinaryParameter param) throws UploadException {
		try {
			return handleBinaryUpload(param.getPrivacyStrategy(), param.getSenderPrivateKey(), param.getReceiverPublicKey(),
					param.getContentType(), param.getKeywords(), param.getMetaDataAsString(), param.getName(), param.getMosaics(), param.getData());
		} catch (UploadException e) {
			throw e;
		} catch (Exception e) {
			throw new UploadException("Error on uploading binary data", e);
		}
	}

	/**
	 * Upload path.
	 *
	 * @param param            the upload parameter
	 * @return the upload data
	 * @throws UploadException             the upload exception
	 */
	public UploadResult uploadPath(UploadPathParameter param)
			throws UploadException {
		try {
			final ResourceHashMessageWrapper resourceHashMessageWrapper = uploadDelegate.uploadPathToIpfs(
					param.getPath(), param.getName(), param.getKeywords(), param.getMetaDataAsString());

			return handlePostUpload(param.getPrivacyStrategy(), param.getSenderPrivateKey(),
					param.getReceiverPublicKey(), param.getMosaics(), resourceHashMessageWrapper);
		} catch (UploadException e) {
			throw e;
		} catch (Exception e) {
			throw new UploadException(format("Error on uploading path: %s", param.getPath()), e);
		}
	}

	/**
	 * Upload files as zip.
	 *
	 * @param param the param
	 * @return the upload result
	 * @throws UploadException the upload exception
	 */
	public UploadResult uploadFilesAsZip(UploadFilesAsZipParameter param) throws UploadException {

		try {
			byte[] binaryContent = zipFiles(param.getFiles());
			return handleBinaryUpload(param.getPrivacyStrategy(), param.getSenderPrivateKey(), param.getReceiverPublicKey(),
					param.getContentType(), param.getKeywords(), param.getMetaDataAsString(), param.getName(), param.getMosaics(), binaryContent);
		} catch (UploadException e) {
			throw e;
		} catch (Exception e) {
			throw new UploadException("Error on uploading files as zip", e);
		}
	}

	/**
	 * Upload multiple files.
	 *
	 * @param param the param
	 * @return the multi file upload result
	 * @throws UploadException the upload exception
	 */
	public MultiFileUploadResult uploadMultipleFiles(UploadMultipleFilesParameter param) throws UploadException {

        if (param.getFiles().size() == 0)
            throw new UploadException("No file to upload");

        List fileUploadResults = param.getFiles()
                .parallelStream()
                .map(file -> {
                    try {
                        byte[] binaryContent = FileUtils.readFileToByteArray(file);
                        return new FileUploadResult(file,
								handleBinaryUpload(param.getPrivacyStrategy(), param.getSenderPrivateKey(),
										param.getReceiverPublicKey(), ContentTypeUtils.detectContentType(binaryContent),
										param.getKeywords(), param.getMetaDataAsString(), file.getName(), param.getMosaics(), binaryContent));
                    } catch (Exception e) {
                        return new FileUploadResult(file, new UploadException(format("Error on uploading file data: %s", file.getAbsolutePath()), e));
                    }
                }).collect(Collectors.toList());
        return new MultiFileUploadResult(fileUploadResults);
	}

	/**
	 * Upload from URL.
	 *
	 * @param param
	 *            the upload parameter
	 * @return the upload data
	 * @throws UploadException
	 *             the upload exception
	 */
	public UploadResult uploadFromUrl(UploadFromUrlParameter param)
			throws UploadException {

		try {
			final byte[] downloadedBinary = IOUtils.toByteArray(param.getUrl());
			final String contentTypeOrDetected = param.getContentType() != null ? param.getContentType() :
					ContentTypeUtils.detectContentType(downloadedBinary);
			return handleBinaryUpload(param.getPrivacyStrategy(), param.getSenderPrivateKey(), param.getReceiverPublicKey(),
					contentTypeOrDetected, param.getKeywords(), param.getMetaDataAsString(), param.getName(), param.getMosaics(), downloadedBinary);
		} catch (UploadException e) {
			throw e;
		} catch (Exception e) {
			throw new UploadException(format("Error on uploading from URL: %s", param.getUrl().toString()), e);
		}
	}

	/**
	 * Handle text data upload.
	 *
	 * @param privacyStrategy the privacy strategy
	 * @param senderPrivateKey the sender private key
	 * @param receiverPublicKey the receiver public key
	 * @param contentType the content type
	 * @param keywords the keywords
	 * @param metadata the metadata
	 * @param name the name
	 * @param mosaics the mosaics
	 * @param textData the text data
	 * @param encoding the encoding
	 * @return the upload result
	 * @throws UploadException the upload exception
	 */
	private UploadResult handleTextDataUpload(PrivacyStrategy privacyStrategy, String senderPrivateKey, String receiverPublicKey,
											String contentType, String keywords, String metadata, String name, Mosaic[] mosaics,
											String textData, String encoding) throws UploadException {
		try {
			final byte[] textInBytes = textData.getBytes(encoding);

			final byte[] encryptedTextInBytes = privacyStrategy.encrypt(textInBytes);
			final ResourceHashMessageWrapper hashMessageWrapper = uploadDelegate.uploadTextToIpfs(
					encryptedTextInBytes, name, contentType, encoding, keywords, metadata);

			return handlePostUpload(privacyStrategy, senderPrivateKey,
					receiverPublicKey, mosaics, hashMessageWrapper);
		} catch (UploadException e) {
			throw e;
		} catch (Exception e) {
			throw new UploadException("Error on uploading text data", e);
		}
	}

	/**
	 * Handle binary upload.
	 *
	 * @param privacyStrategy the privacy strategy
	 * @param senderPrivateKey the sender private key
	 * @param receiverPublicKey the receiver public key
	 * @param contentType the content type
	 * @param keywords the keywords
	 * @param metadata the metadata
	 * @param name the name
	 * @param mosaics the mosaics
	 * @param binaryContent the binary content
	 * @return the upload result
	 * @throws UploadException the upload exception
	 */
	private UploadResult handleBinaryUpload(PrivacyStrategy privacyStrategy, String senderPrivateKey, String receiverPublicKey,
											String contentType, String keywords, String metadata, String name, Mosaic[] mosaics,
											byte[] binaryContent) throws UploadException {
		try {
			byte[] encryptedContent = privacyStrategy.encrypt(binaryContent);
			final ResourceHashMessageWrapper hashMessageWrapper =
					uploadDelegate.uploadBinaryToIpfs(encryptedContent, name, contentType, keywords, metadata);
			return handlePostUpload(privacyStrategy, senderPrivateKey, receiverPublicKey, mosaics, hashMessageWrapper);

		} catch (UploadException e) {
			throw e;
		} catch (Exception e) {
			throw new UploadException("Error on uploading binary data", e);

		}
	}


	/**
	 * Zip files.
	 *
	 * @param files the files
	 * @return the byte[]
	 * @throws UploadException the upload exception
	 */
	private byte[] zipFiles(List files) throws UploadException {

		validateZipFilesArguments(files);

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try (ZipOutputStream zos = new ZipOutputStream(baos)) {

			for (File file : files) {
				ZipEntry entry = new ZipEntry(file.getName());

				zos.putNextEntry(entry);
				zos.write(FileUtils.readFileToByteArray(file));
				zos.closeEntry();
			};

		} catch (IOException e) {
			throw new UploadException(format("Unable to zip files together: %s", String.join(",",
					files.stream().map(file -> file.getAbsolutePath()).collect(Collectors.toList()))), e);
		}
		return baos.toByteArray();
	}

	/**
	 * Validate zip files arguments.
	 *
	 * @param files the files
	 * @throws UploadException the upload exception
	 */
	private void validateZipFilesArguments(List files) throws UploadException {
		if (files.size() == 0)
			throw new UploadException("No file to upload");

		long uniqueFileNameCount = files.stream().map(file -> file.getName()).distinct().count();
		if (uniqueFileNameCount < files.size())
			throw new UploadException(format("File names should be unique to zip files together: %s",
					String.join(",", files.stream().map(file -> file.getName()).collect(Collectors.toList()))));
	}

	/**
	 * Handle post upload.
	 *
	 * @param privacyStrategy the privacy strategy
	 * @param senderPrivateKey the sender private key
	 * @param receiverPublicKey the receiver public key
	 * @param mosaics the mosaics
	 * @return the upload result
	 * @throws Exception the exception
	 */
	private UploadResult handlePostUpload(PrivacyStrategy privacyStrategy, String senderPrivateKey, String receiverPublicKey,
										  Mosaic[] mosaics, ResourceHashMessageWrapper hashMessageWrapper) throws Exception {
		try {
			final String nemHash = createNemTransaction(privacyStrategy, senderPrivateKey, receiverPublicKey, mosaics,
					hashMessageWrapper.getData());

			ipfsGatewaySyncService.syncToGatewaysAsynchronously(hashMessageWrapper.getResourceHashMessage().hash());

			return new UploadResult(hashMessageWrapper.getResourceHashMessage(), nemHash);
		} catch (Exception e) {
			Executors.newSingleThreadExecutor().submit(() ->
					uploadDelegate.deletePinnedContent(hashMessageWrapper.getResourceHashMessage().hash()));
			throw e;
		}
	}

	/**
	 * Creates the proximax transaction.
	 *
	 * @param privacyStrategy the privacy strategy
	 * @param senderPrivateKey the sender private key
	 * @param receiverPublicKey the receiver public key
	 * @param mosaics the mosaics
	 * @param response the response
	 * @return the string
	 * @throws Exception the exception
	 */
	private String createNemTransaction(PrivacyStrategy privacyStrategy, String senderPrivateKey,
										String receiverPublicKey, Mosaic[] mosaics, byte[] response) throws Exception {
		final Message nemMessage = privacyStrategy.encodeToMessage(response);
		return transactionAnnouncer.announceTransactionForUploadedContent(nemMessage, senderPrivateKey, receiverPublicKey, mosaics);
	}
}






© 2015 - 2024 Weber Informatics LLC | Privacy Policy