561 lines
18 KiB
C++
561 lines
18 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2013 by gempa GmbH *
|
|
* *
|
|
* All Rights Reserved. *
|
|
* *
|
|
* NOTICE: All information contained herein is, and remains *
|
|
* the property of gempa GmbH and its suppliers, if any. The intellectual *
|
|
* and technical concepts contained herein are proprietary to gempa GmbH *
|
|
* and its suppliers. *
|
|
* Dissemination of this information or reproduction of this material *
|
|
* is strictly forbidden unless prior written permission is obtained *
|
|
* from gempa GmbH. *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef GEMPA_CAPS_PLUGIN_H
|
|
#define GEMPA_CAPS_PLUGIN_H
|
|
|
|
|
|
/*
|
|
// Enable/disable journal
|
|
#define CAPS_FEATURES_JOURNAL 1
|
|
// Enable/disable backfilling of packets
|
|
#define CAPS_FEATURES_BACKFILLING 1
|
|
#define CAPS_FEATURES_SSL 1
|
|
|
|
// Supportted CAPS packets
|
|
#define CAPS_FEATURES_ANY 1
|
|
#define CAPS_FEATURES_MSEED 1
|
|
#define CAPS_FEATURES_RAW 1
|
|
#define CAPS_FEATURES_RTCM2 1
|
|
*/
|
|
|
|
#include "encoderfactory.h"
|
|
|
|
#include <gempa/caps/packet.h>
|
|
#include <gempa/caps/socket.h>
|
|
#include <gempa/caps/url.h>
|
|
#include <gempa/caps/version.h>
|
|
#include <gempa/caps/pluginpacket.h>
|
|
|
|
#include <boost/function.hpp>
|
|
#include <boost/shared_ptr.hpp>
|
|
|
|
#include <deque>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <list>
|
|
|
|
|
|
namespace Gempa {
|
|
namespace CAPS {
|
|
|
|
|
|
class SC_GEMPA_CAPS_API Plugin {
|
|
public:
|
|
enum Status {
|
|
Success,
|
|
PacketSize, /* Packet is bigger than the buffer size */
|
|
PacketLoss, /* The other end didn't acknowledge
|
|
transmitted data after some time */
|
|
PacketNotValid, /* Read meta data failed*/
|
|
PacketNotSupported,
|
|
MaxFutureEndTimeExceeded
|
|
};
|
|
|
|
struct Stats {
|
|
Stats() : maxBytesBuffered(0) {}
|
|
size_t maxBytesBuffered;
|
|
};
|
|
|
|
struct HostInfo {
|
|
std::string agent;
|
|
std::string agentVersion;
|
|
std::string os;
|
|
int64_t totalMem{-1};
|
|
int64_t totalDisc{-1};
|
|
};
|
|
|
|
struct RuntimeInfo {
|
|
int64_t availableMem{-1};
|
|
int64_t procUsedMem{-1};
|
|
int64_t availableDisc{-1};
|
|
int cpuUsage{-1};
|
|
double systemLoad{-1};
|
|
};
|
|
|
|
typedef std::vector<char> Buffer;
|
|
typedef boost::shared_ptr<Buffer> BufferPtr;
|
|
typedef std::deque<PacketPtr> PacketBuffer;
|
|
|
|
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
|
|
typedef std::list<PacketPtr> BackfillingBuffer;
|
|
|
|
#endif
|
|
struct StreamState {
|
|
Time lastEndTime;
|
|
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
|
|
Time lastCommitEndTime;
|
|
BackfillingBuffer backfillingBuffer;
|
|
#endif
|
|
};
|
|
|
|
typedef std::map<std::string, StreamState> StreamStates;
|
|
|
|
typedef boost::function<void (const std::string &, const CAPS::Time &,
|
|
const CAPS::Time &, void *context)> PacketAckFunc;
|
|
typedef boost::function<void ()> ConnectedCallback;
|
|
typedef boost::function<void ()> DisconnectedCallback;
|
|
|
|
|
|
public:
|
|
Plugin(const std::string &name, const std::string &options = "",
|
|
const std::string &description = "");
|
|
virtual ~Plugin();
|
|
|
|
void close();
|
|
void quit();
|
|
|
|
void enableLogging();
|
|
|
|
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
|
|
void setBackfillingBufferSize(int secs) { _backfillingBufferSize = secs; }
|
|
int backfillingBufferSize() const { return _backfillingBufferSize; }
|
|
|
|
#endif
|
|
|
|
/**
|
|
* @brief Returns whether the plugin has been
|
|
* requested to quit or not.
|
|
* @return True, if the plugin has been requested to quit.
|
|
*/
|
|
bool isExitRequested() {
|
|
return _isExitRequested;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the stat object
|
|
* @return The stat object
|
|
*/
|
|
const Stats& stats() const {
|
|
return _stats;
|
|
}
|
|
|
|
/**
|
|
* @brief Resets the max bytes buffered counter
|
|
*/
|
|
void resetMaxBytesBuffered() {
|
|
_stats.maxBytesBuffered = 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Sets the encoder factory used to created encoders for packet
|
|
* encoding, e.g. miniSEED.
|
|
* @param factory The ownership of the factory goes to the plugin and
|
|
* will be deleted if necessary.
|
|
*/
|
|
void setEncoderFactory(EncoderFactory *factory);
|
|
|
|
/**
|
|
* @brief Parses connection parameters from address string. Format
|
|
* is [[caps|capss]://][user:pass@]host[:port]
|
|
* @param addr The address of the caps server as string
|
|
* @param defaultPort The default port used when the port is omitted
|
|
*/
|
|
bool setAddress(const std::string &addr, uint16_t defaultPort = 18003);
|
|
|
|
void setHost(const std::string &host) { _url.host = host; }
|
|
const std::string &host() const { return _url.host; }
|
|
|
|
void setPort(unsigned short port) { _url.port = port; }
|
|
unsigned short port() const { return _url.port; }
|
|
|
|
void setBufferSize(size_t bufferSize) { _bufferSize = bufferSize; }
|
|
size_t bufferSize() const { return _bufferSize; }
|
|
|
|
//! Enables SSL feature
|
|
#if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL
|
|
void setSSLEnabled(bool enable) { _useSSL = enable; }
|
|
#endif
|
|
|
|
/**
|
|
* @brief Sets username and password
|
|
* @param user The username
|
|
* @param password The password
|
|
*/
|
|
void setCredentials(const std::string &user, const std::string &password) {
|
|
_url.user = user;
|
|
_url.password = password;
|
|
}
|
|
|
|
/**
|
|
* @brief Sets the maximum allowed relative end time for packets. If
|
|
* the packet end time is greater than the current time plus this
|
|
* value the packet will be discarded. By default this value is
|
|
* set to 120 seconds.
|
|
* @param time The time span
|
|
*/
|
|
void setMaxFutureEndTime(const TimeSpan &span) {
|
|
_maxFutureEndTime = span;
|
|
}
|
|
|
|
void setPacketAckFunc(const PacketAckFunc &func) { _packetAckFunc = func; }
|
|
|
|
/**
|
|
* @brief Sets the connection timout used when the plugin
|
|
* tries to establish a connection to CAPS
|
|
* @param sec The seconds
|
|
*/
|
|
void setConnectionTimeout(int sec) {
|
|
_connectionTimeout = sec;
|
|
}
|
|
|
|
/**
|
|
* @brief Sets the maximum number of seconds to wait until
|
|
* the file descriptor is ready for writing.
|
|
* @param sec The seconds
|
|
*/
|
|
void setSendTimeout(int sec) {
|
|
_sendTimeout = sec;
|
|
}
|
|
|
|
/**
|
|
* @brief Sets timeout values
|
|
* @param ack The acknowledgement message value
|
|
* @param lastAck The last acknowledgement message value
|
|
* @param send See setSendTimeout
|
|
* @
|
|
*/
|
|
void setTimeouts(int ack, int lastAck, int send) {
|
|
_ackTimeout = ack;
|
|
_lastAckTimeout = lastAck;
|
|
_sendTimeout = send;
|
|
}
|
|
|
|
#if !defined(CAPS_FEATURES_JOURNAL) || CAPS_FEATURES_JOURNAL
|
|
bool readJournal();
|
|
void setJournal(const std::string &filename) { _journalFile = filename; }
|
|
void setFlushInterval(int interval) { _flushInterval = interval; }
|
|
|
|
const StreamStates &streamStates() const { return _states; }
|
|
bool writeJournal();
|
|
bool writeJournal(std::ostream &ostream);
|
|
|
|
/**
|
|
* @brief Gets end time of the last acknowledged packet
|
|
* @param id The stream ID, e.g., GE.APE..BHZ
|
|
* @return The last end time or an invalid time
|
|
*/
|
|
Gempa::CAPS::Time lastEndTime(const std::string &id);
|
|
#endif
|
|
Status push(const std::string &net, const std::string &sta,
|
|
const std::string &loc, const std::string &cha,
|
|
DataRecordPtr rec, const std::string &uom,
|
|
int timingQuality = -1, void *context = nullptr);
|
|
|
|
Status push(const std::string &net, const std::string &sta,
|
|
const std::string &loc, const std::string &cha,
|
|
const Time &stime,
|
|
uint16_t numerator, uint16_t denominator,
|
|
const std::string &uom,
|
|
void *data, size_t count,
|
|
DataType dt, int timingQuality = -1,
|
|
void *context = nullptr);
|
|
|
|
/**
|
|
* @brief Sends CAPS data record to CAPS
|
|
* @param net Network code
|
|
* @param sta Station code
|
|
* @param loc Location code
|
|
* @param cha Channel code
|
|
* @param rec CAPS data record
|
|
* @param uom Unit of measurement
|
|
* @param timingQuality Data timing quality. Ususally between 0 and 100 or -1
|
|
* if unset
|
|
* @param context Pointer to user-defined context data
|
|
* @return Status Packet status
|
|
*/
|
|
Status pushRecord(const std::string &net, const std::string &sta,
|
|
const std::string &loc, const std::string &cha,
|
|
DataRecordPtr rec, const std::string &uom,
|
|
int timingQuality = -1, void *context = nullptr);
|
|
|
|
/**
|
|
* @brief Sends C array data as RAW record to CAPS
|
|
* @param net Network code
|
|
* @param sta Station code
|
|
* @param loc Location code
|
|
* @param cha Channel code
|
|
* @param stime Packet start time
|
|
* @param numerator Sampling frequency numerator
|
|
* @param denominator Sampling frequency denominator
|
|
* @param uom Unit of measurement
|
|
* @param data Pointer to data array
|
|
* @param count Number of samples
|
|
* @param dt Data type, e.g., DT_DOUBLE
|
|
* @param timingQuality Data timing quality. Ususally between 0 and 100 or -1
|
|
* if unset
|
|
* @param context Pointer to user-defined context data
|
|
* @return Status Packet status
|
|
*/
|
|
Status pushRaw(const std::string &net, const std::string &sta,
|
|
const std::string &loc, const std::string &cha,
|
|
const Time &stime,
|
|
uint16_t numerator, uint16_t denominator,
|
|
const std::string &uom,
|
|
void *data, size_t count,
|
|
DataType dt, int timingQuality = -1,
|
|
void *context = nullptr);
|
|
|
|
/*
|
|
* Sends given data as any packet. Before sending the data will be
|
|
* copied into an internal buffer. We introduced this method
|
|
* to simplify the creation of the python wrappers.
|
|
*/
|
|
#if !defined(CAPS_FEATURES_ANY) || CAPS_FEATURES_ANY
|
|
Status push(const std::string &net, const std::string &sta,
|
|
const std::string &loc, const std::string &cha,
|
|
const Time &stime, uint16_t numerator,
|
|
uint16_t denominator, const std::string &format,
|
|
char *data, size_t count, void *context = nullptr);
|
|
|
|
Status push(const std::string &net, const std::string &sta,
|
|
const std::string &loc, const std::string &cha,
|
|
const Time &stime, uint16_t numerator,
|
|
uint16_t denominator, const std::string &format,
|
|
const std::string &data, void *context = nullptr);
|
|
|
|
/**
|
|
* @brief Sends C array data as any record to CAPS
|
|
* @param net Network code
|
|
* @param sta Station code
|
|
* @param loc Location code
|
|
* @param cha Channel code
|
|
* @param stime Packet start time
|
|
* @param etime Packet end time
|
|
* @param numerator Sampling frequency numerator. Use 1 / 0
|
|
* for packets without sampling frequency.
|
|
* @param denominator Sampling frequency denominator
|
|
* @param format Data format of the provided data
|
|
* @param uom Unit of measurement, e.g., px
|
|
* @param data Pointer to data array
|
|
* @param count Number of data elements
|
|
* @param context Pointer to user-defined context data
|
|
* @return Status Packet status
|
|
*/
|
|
Status pushAny(const std::string &net, const std::string &sta,
|
|
const std::string &loc, const std::string &cha,
|
|
const Time &stime, const Time &etime,
|
|
uint16_t numerator, uint16_t denominator,
|
|
const std::string &format, const std::string &uom,
|
|
char *data, size_t count, void *context = nullptr);
|
|
|
|
/**
|
|
* @brief Sends STL string as any record to CAPS
|
|
* @param net Network code
|
|
* @param sta Station code
|
|
* @param loc Location code
|
|
* @param cha Channel code
|
|
* @param stime Packet start time
|
|
* @param etime Packet end time
|
|
* @param numerator Sampling frequency numerator. Use 1 / 0
|
|
* for packets without sampling frequency.
|
|
* @param denominator Sampling frequency denominator
|
|
* @param format Data format of the provided data
|
|
* @param uom Unit of measurement, e.g., px
|
|
* @param data Data as string
|
|
* @param context Pointer to user-defined context data
|
|
* @return Status Packet status
|
|
*/
|
|
Status pushAny(const std::string &net, const std::string &sta,
|
|
const std::string &loc, const std::string &cha,
|
|
const Time &stime, const Time &etime,
|
|
uint16_t numerator, uint16_t denominator,
|
|
const std::string &format, const std::string &uom,
|
|
const std::string &data, void *context = nullptr);
|
|
#endif
|
|
|
|
void flushEncoders();
|
|
|
|
void dumpPackets(bool enable);
|
|
|
|
/**
|
|
* @brief Returns the internal packet buffer that
|
|
* keeps packets until they have been acknowledged
|
|
* by CAPS
|
|
* @return The interal packet buffer
|
|
*/
|
|
const PacketBuffer &packetBuffer() const {
|
|
return _packetBuffer;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Set host information like agent or total mem
|
|
* @param info The host info struct
|
|
*/
|
|
void setHostInfo(const HostInfo &info);
|
|
|
|
/**
|
|
* @brief Set runtime information like CPU load or process memory usage.
|
|
* This methods blocks until sent.
|
|
* @param info The runtime info struct
|
|
*/
|
|
void setRuntimeInfo(const RuntimeInfo &info);
|
|
|
|
/**
|
|
* @brief Sets the connection ID. If not set, the server generates an ID
|
|
* during the first connection attempt.
|
|
* @param id The connection ID string
|
|
*/
|
|
void setConnectionID(const std::string &id);
|
|
|
|
/**
|
|
* @brief Set the connection ID file to read the connection ID from
|
|
* @param filename The filename
|
|
* @return True if the connection could be read from the given file
|
|
*/
|
|
bool setConnectionIDFile(const std::string &filename);
|
|
|
|
/**
|
|
* @brief Returns the connection ID
|
|
* @return Returns the connection ID
|
|
*/
|
|
const std::string &connectionID() const;
|
|
|
|
/**
|
|
* @brief Set function that gets called if the connection to the server
|
|
* has been established.
|
|
*/
|
|
void setConnectedCallback(ConnectedCallback f);
|
|
|
|
/**
|
|
* @brief Set function that gets called if the connection to the server
|
|
* was disconnected.
|
|
*/
|
|
void setDisconnectedCallback(DisconnectedCallback f);
|
|
|
|
const char *version() {
|
|
return LIB_CAPS_VERSION_NAME;
|
|
}
|
|
|
|
protected:
|
|
/**
|
|
* @brief Sends HELLO request and parses API version
|
|
* from server response. If the server does not support
|
|
* the API feature the method sets the version to 0.
|
|
* @param version The CAPS API version, e.g., 5
|
|
* @return True on success
|
|
*/
|
|
bool getAPIVersion(int &version);
|
|
|
|
/**
|
|
* @brief Get connection ID from server. If the plugin sends no
|
|
* connection ID the server generates one.
|
|
* @return True on success
|
|
*/
|
|
bool getConnectionID();
|
|
|
|
/**
|
|
* brief Send runtime information
|
|
*/
|
|
void sendRuntimeInfo();
|
|
|
|
private:
|
|
typedef boost::shared_ptr<Encoder> EncoderPtr;
|
|
|
|
struct EncoderItem {
|
|
EncoderItem() : dataType(DT_Unknown) {}
|
|
EncoderPtr encoder;
|
|
DataType dataType;
|
|
};
|
|
typedef std::map<std::string, EncoderItem> EncoderItems;
|
|
|
|
private:
|
|
bool connect();
|
|
void disconnect();
|
|
void dumpPacket(Packet *packet);
|
|
bool isConnected() const;
|
|
Encoder* getEncoder(PacketPtr packet);
|
|
bool readResponse(unsigned int sec = 0);
|
|
#if !defined(CAPS_FEATURES_JOURNAL) || CAPS_FEATURES_JOURNAL
|
|
bool readJournal(std::istream &istream);
|
|
void updateJournal();
|
|
#endif
|
|
void sendBye();
|
|
bool commitPacket(PacketPtr packet);
|
|
bool encodePacket(PacketPtr packet);
|
|
bool sendPacket(Packet *packet);
|
|
void serializePacket(Packet *packet);
|
|
void tryFlushBackfillingBuffer(StreamState &state);
|
|
void trimBackfillingBuffer(StreamState &state);
|
|
bool flush();
|
|
bool send(char *data, int len, int timeout = 60);
|
|
void wait();
|
|
|
|
private:
|
|
SocketPtr _socket;
|
|
std::string _name;
|
|
std::string _options;
|
|
std::string _description;
|
|
size_t _bufferSize;
|
|
StreamStates _states;
|
|
PacketBuffer _packetBuffer;
|
|
bool _packetBufferDirty;
|
|
size_t _bytesBuffered;
|
|
char _responseBuf[512];
|
|
int _responseBufIdx;
|
|
fd_set _readFDs;
|
|
fd_set _writeFDs;
|
|
int _sendTimeout;
|
|
int _readTimeout;
|
|
int _connectionTimeout;
|
|
#if !defined(CAPS_FEATURES_JOURNAL) || CAPS_FEATURES_JOURNAL
|
|
std::string _journalFile;
|
|
bool _journalDirty;
|
|
Time _lastWrite;
|
|
int _flushInterval;
|
|
#endif
|
|
bool _isExitRequested;
|
|
bool _closed;
|
|
bool _wasConnected;
|
|
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
|
|
int _backfillingBufferSize;
|
|
#endif
|
|
int _ackTimeout;
|
|
int _lastAckTimeout;
|
|
|
|
EncoderFactory *_encoderFactory;
|
|
EncoderItems _encoderItems;
|
|
|
|
PacketAckFunc _packetAckFunc;
|
|
|
|
Url _url;
|
|
#if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL
|
|
bool _useSSL;
|
|
#endif
|
|
Stats _stats;
|
|
TimeSpan _maxFutureEndTime;
|
|
|
|
bool _dumpPackets;
|
|
HostInfo _hostInfo;
|
|
RuntimeInfo _runtimeInfo;
|
|
std::string _connectionID;
|
|
std::string _connectionIDFile;
|
|
ConnectedCallback _connectedCallback;
|
|
DisconnectedCallback _disconnectedCallback;
|
|
};
|
|
|
|
|
|
using PluginPtr = boost::shared_ptr<Plugin>;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|