blob: 4280b2ff825e2857ebd76ad286654ffa9cf55114 [file] [log] [blame]
/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#ifndef LIBMINIFI_INCLUDE_SITETOSITE_SITETOSITECLIENT_H_
#define LIBMINIFI_INCLUDE_SITETOSITE_SITETOSITECLIENT_H_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "Peer.h"
#include "SiteToSite.h"
#include "core/ProcessSession.h"
#include "core/ProcessContext.h"
#include "core/Connectable.h"
namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace sitetosite {
/**
* Represents a piece of data that is to be sent to or that was received from a
* NiFi instance.
*/
class DataPacket {
public:
DataPacket(const std::shared_ptr<logging::Logger> &logger, const std::shared_ptr<Transaction> &transaction, std::map<std::string, std::string> attributes, const std::string &payload)
: payload_(payload),
logger_reference_(logger) {
_size = 0;
transaction_ = transaction;
_attributes = attributes;
}
std::map<std::string, std::string> _attributes;
uint64_t _size;
std::shared_ptr<Transaction> transaction_;
const std::string & payload_;
std::shared_ptr<logging::Logger> logger_reference_;
};
class SiteToSiteClient : public core::Connectable {
public:
SiteToSiteClient()
: core::Connectable("SitetoSiteClient"),
peer_state_(IDLE),
_batchSendNanos(5000000000),
ssl_context_service_(nullptr),
logger_(logging::LoggerFactory<SiteToSiteClient>::getLogger()) {
_supportedVersion[0] = 5;
_supportedVersion[1] = 4;
_supportedVersion[2] = 3;
_supportedVersion[3] = 2;
_supportedVersion[4] = 1;
_currentVersion = _supportedVersion[0];
_currentVersionIndex = 0;
_supportedCodecVersion[0] = 1;
_currentCodecVersion = _supportedCodecVersion[0];
_currentCodecVersionIndex = 0;
}
virtual ~SiteToSiteClient() = default;
void setSSLContextService(const std::shared_ptr<minifi::controllers::SSLContextService> &context_service) {
ssl_context_service_ = context_service;
}
/**
* Creates a transaction using the transaction ID and the direction
* @param transactionID transaction identifier
* @param direction direction of transfer
*/
virtual std::shared_ptr<Transaction> createTransaction(TransferDirection direction) = 0;
/**
* Transfers flow files
* @param direction transfer direction
* @param context process context
* @param session process session
* @returns true if the process succeeded, failure OR exception thrown otherwise
*/
virtual bool transfer(TransferDirection direction, const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSession> &session) {
#ifndef WIN32
if (__builtin_expect(direction == SEND, 1)) {
return transferFlowFiles(context, session);
} else {
return receiveFlowFiles(context, session);
}
#else
if (direction == SEND) {
return transferFlowFiles(context, session);
} else {
return receiveFlowFiles(context, session);
}
#endif
}
/**
* Transfers flow files to server
* @param context process context
* @param session process session
* @returns true if the process succeeded, failure OR exception thrown otherwise
*/
virtual bool transferFlowFiles(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSession> &session);
/**
* Receive flow files from server
* @param context process context
* @param session process session
* @returns true if the process succeeded, failure OR exception thrown otherwise
*/
// Confirm the data that was sent or received by comparing CRC32's of the data sent and the data received.
// Receive flow files for the process session
bool receiveFlowFiles(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSession> &session);
// Receive the data packet from the transaction
// Return false when any error occurs
bool receive(const utils::Identifier& transactionID, DataPacket *packet, bool &eof);
/**
* Transfers raw data and attributes to server
* @param context process context
* @param session process session
* @param payload data to transmit
* @param attributes
* @returns true if the process succeeded, failure OR exception thrown otherwise
*/
virtual bool transmitPayload(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSession> &session, const std::string &payload,
std::map<std::string, std::string> attributes) = 0;
void setPortId(utils::Identifier &id) {
port_id_ = id;
}
/**
* Sets the idle timeout.
*/
void setIdleTimeout(std::chrono::milliseconds timeout) {
idle_timeout_ = timeout;
}
/**
* Sets the base peer for this interface.
*/
virtual void setPeer(std::unique_ptr<SiteToSitePeer> peer) {
peer_ = std::move(peer);
}
/**
* Provides a reference to the port identifier
* @returns port identifier
*/
utils::Identifier getPortId() const {
return port_id_;
}
/**
* Obtains the peer list and places them into the provided vector
* @param peers peer vector.
* @return true if successful, false otherwise
*/
virtual bool getPeerList(std::vector<PeerStatus> &peers) = 0;
/**
* Establishes the interface.
* @return true if successful, false otherwise
*/
virtual bool establish() = 0;
const std::shared_ptr<logging::Logger> &getLogger() {
return logger_;
}
virtual void yield() {
}
/**
* Determines if we are connected and operating
*/
virtual bool isRunning() {
return running_;
}
/**
* Determines if work is available by this connectable
* @return boolean if work is available.
*/
virtual bool isWorkAvailable() {
return true;
}
virtual bool bootstrap() {
return true;
}
// Return -1 when any error occurs
virtual int16_t send(const utils::Identifier& transactionID, DataPacket *packet, const std::shared_ptr<core::FlowFile> &flowFile, const std::shared_ptr<core::ProcessSession> &session);
protected:
// Cancel the transaction
virtual void cancel(const utils::Identifier& transactionID);
// Complete the transaction
virtual bool complete(const utils::Identifier& transactionID);
// Error the transaction
virtual void error(const utils::Identifier& transactionID);
virtual bool confirm(const utils::Identifier& transactionID);
// deleteTransaction
virtual void deleteTransaction(const utils::Identifier& transactionID);
virtual void tearDown() = 0;
// read Respond
virtual int readResponse(const std::shared_ptr<Transaction> &transaction, RespondCode &code, std::string &message);
// write respond
virtual int writeResponse(const std::shared_ptr<Transaction> &transaction, RespondCode code, std::string message);
// getRespondCodeContext
virtual RespondCodeContext *getRespondCodeContext(RespondCode code) {
for (unsigned int i = 0; i < sizeof(SiteToSiteRequest::respondCodeContext) / sizeof(RespondCodeContext); i++) {
if (SiteToSiteRequest::respondCodeContext[i].code == code) {
return &SiteToSiteRequest::respondCodeContext[i];
}
}
return NULL;
}
// Peer State
PeerState peer_state_;
// portId
utils::Identifier port_id_;
// idleTimeout
std::chrono::milliseconds idle_timeout_{15000};
// Peer Connection
std::unique_ptr<SiteToSitePeer> peer_;
std::atomic<bool> running_;
// transaction map
std::map<utils::Identifier, std::shared_ptr<Transaction>> known_transactions_;
// BATCH_SEND_NANOS
uint64_t _batchSendNanos;
/***
* versioning
*/
uint32_t _supportedVersion[5];
uint32_t _currentVersion;
int _currentVersionIndex;
uint32_t _supportedCodecVersion[1];
uint32_t _currentCodecVersion;
int _currentCodecVersionIndex;
std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service_;
private:
std::shared_ptr<logging::Logger> logger_;
};
// Nest Callback Class for write stream
class WriteCallback : public OutputStreamCallback {
public:
WriteCallback(DataPacket *packet) // NOLINT
: _packet(packet) {
}
DataPacket *_packet;
// void process(std::ofstream *stream) {
int64_t process(const std::shared_ptr<io::BaseStream>& stream) {
uint8_t buffer[16384];
uint64_t len = _packet->_size;
uint64_t total = 0;
while (len > 0) {
int size = len < 16384 ? static_cast<int>(len) : 16384;
int ret = _packet->transaction_->getStream().read(buffer, size);
if (ret != size) {
logging::LOG_ERROR(_packet->logger_reference_) << "Site2Site Receive Flow Size " << size << " Failed " << ret << ", should have received " << len;
return -1;
}
stream->write(buffer, size);
len -= size;
total += size;
}
logging::LOG_INFO(_packet->logger_reference_) << "Received " << total << " from stream";
return len;
}
};
// Nest Callback Class for read stream
class ReadCallback : public InputStreamCallback {
public:
ReadCallback(DataPacket *packet) // NOLINT
: _packet(packet) {
}
DataPacket *_packet;
int64_t process(const std::shared_ptr<io::BaseStream>& stream) {
_packet->_size = 0;
uint8_t buffer[8192] = { 0 };
int readSize;
size_t size = 0;
do {
readSize = stream->read(buffer, 8192);
if (readSize == 0) {
break;
}
if (readSize < 0) {
return -1;
}
int ret = _packet->transaction_->getStream().write(buffer, readSize);
if (ret != readSize) {
logging::LOG_INFO(_packet->logger_reference_) << "Site2Site Send Flow Size " << readSize << " Failed " << ret;
return -1;
}
size += readSize;
} while (size < stream->size());
_packet->_size = size;
return size;
}
};
} // namespace sitetosite
} // namespace minifi
} // namespace nifi
} // namespace apache
} // namespace org
#endif // LIBMINIFI_INCLUDE_SITETOSITE_SITETOSITECLIENT_H_