#ifndef INC_SRT_APPCOMMON_H
#define INC_SRT_APPCOMMON_H
#include <string>
#include <map>
#include <set>
#include <vector>
#include <memory>
#include "netinet_any.h"
#if _WIN32
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#ifdef __MINGW32__
#include <unistd.h>
#else
extern "C" inline int sleep(int seconds) { Sleep(seconds * 1000); return 0; }
#endif
inline bool SysInitializeNetwork()
{
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
return WSAStartup(wVersionRequested, &wsaData) == 0;
}
inline void SysCleanupNetwork()
{
WSACleanup();
}
#else
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
inline bool SysInitializeNetwork() {return true;}
inline void SysCleanupNetwork() {}
#endif
#include "srt.h"
#ifdef _WIN32
inline int SysError() { return ::GetLastError(); }
#else
inline int SysError() { return errno; }
#endif
sockaddr_any CreateAddr(const std::string& name, unsigned short port = 0, int pref_family = AF_UNSPEC);
std::string Join(const std::vector<std::string>& in, std::string sep);
inline bool CheckTrue(const std::vector<std::string>& in)
{
if (in.empty())
return true;
const std::set<std::string> false_vals = { "0", "no", "off", "false" };
if (false_vals.count(in[0]))
return false;
return true;
}
template<class Number>
static inline Number StrToNumber(const std::string& )
{
typename Number::incorrect_version wrong = Number::incorrect_version;
return Number();
}
#define STON(type, function) \
template<> inline type StrToNumber(const std::string& s) { return function (s, 0, 0); }
STON(int, stoi);
STON(unsigned long, stoul);
STON(unsigned int, stoul);
STON(long long, stoll);
STON(unsigned long long, stoull);
#undef STON
typedef std::map<std::string, std::vector<std::string>> options_t;
struct OutList
{
typedef std::vector<std::string> type;
static type process(const options_t::mapped_type& i) { return i; }
};
struct OutString
{
typedef std::string type;
static type process(const options_t::mapped_type& i) { return Join(i, " "); }
};
struct NumberAutoConvert
{
std::string value;
NumberAutoConvert(): NumberAutoConvert("") {}
NumberAutoConvert(const std::string& arg): NumberAutoConvert(arg.c_str()) {}
NumberAutoConvert(const char* arg): value(arg)
{
if (value.empty())
value = "0"; }
template<class Number>
operator Number()
{
return StrToNumber<Number>(value);
}
};
struct OutNumber
{
typedef NumberAutoConvert type;
static type process(const options_t::mapped_type& i)
{
if (i.empty())
return {"0"};
return type { i.back() };
}
};
template <class Number>
struct OutNumberAs
{
typedef Number type;
static type process(const options_t::mapped_type& i)
{
return OutNumber::process(i);
}
};
struct OutBool
{
typedef bool type;
static type process(const options_t::mapped_type& i) { return CheckTrue(i); }
};
struct OptionName;
struct OptionScheme
{
const OptionName* pid;
enum Args { ARG_NONE, ARG_ONE, ARG_VAR } type;
OptionScheme(const OptionScheme&) = default;
OptionScheme(OptionScheme&& src)
: pid(src.pid)
, type(src.type)
{
}
OptionScheme(const OptionName& id, Args tp);
const std::set<std::string>& names();
};
struct OptionName
{
std::string helptext;
std::string main_name;
std::set<std::string> names;
template <class... Args>
OptionName(std::string ht, std::string first, Args... rest)
: helptext(ht), main_name(first),
names {first, rest...}
{
}
template <class... Args>
OptionName(std::vector<OptionScheme>& sc, OptionScheme::Args type,
std::string ht, std::string first, Args... rest)
: helptext(ht), main_name(first),
names {first, rest...}
{
sc.push_back(OptionScheme(*this, type));
}
template <class... Args>
OptionName(std::vector<OptionScheme>& sc,
std::string ht, std::string first, Args... rest)
: helptext(ht), main_name(first),
names {first, rest...}
{
OptionScheme::Args type = DetermineTypeFromHelpText(ht);
sc.push_back(OptionScheme(*this, type));
}
OptionName(std::initializer_list<std::string> args): main_name(*args.begin()), names(args) {}
operator std::set<std::string>() { return names; }
operator const std::set<std::string>() const { return names; }
private:
static OptionScheme::Args DetermineTypeFromHelpText(const std::string& helptext);
};
inline OptionScheme::OptionScheme(const OptionName& id, Args tp): pid(&id), type(tp) {}
inline const std::set<std::string>& OptionScheme::names() { return pid->names; }
template <class OutType, class OutValue> inline
typename OutType::type Option(const options_t&, OutValue deflt=OutValue()) { return deflt; }
template <class OutType, class OutValue, class... Args> inline
typename OutType::type Option(const options_t& options, OutValue deflt, std::string key, Args... further_keys)
{
auto i = options.find(key);
if ( i == options.end() )
return Option<OutType>(options, deflt, further_keys...);
return OutType::process(i->second);
}
template<typename TrapType>
struct OptionTrapType
{
static TrapType pass(TrapType v) { return v; }
};
template<>
struct OptionTrapType<const char*>
{
static std::string pass(const char* v) { return v; }
};
template <class OutType, class OutValue> inline
typename OutType::type Option(const options_t& options, OutValue deflt, const OptionName& oname)
{
(void)OptionTrapType<OutValue>::pass(deflt);
for (auto key: oname.names)
{
auto i = options.find(key);
if ( i != options.end() )
{
return OutType::process(i->second);
}
}
return deflt;
}
template <class OutType> inline
typename OutType::type Option(const options_t& options, const OptionName& oname)
{
typedef typename OutType::type out_t;
for (auto key: oname.names)
{
auto i = options.find(key);
if ( i != options.end() )
{
return OutType::process(i->second);
}
}
return out_t();
}
inline bool OptionPresent(const options_t& options, const std::set<std::string>& keys)
{
for (auto key: keys)
{
auto i = options.find(key);
if ( i != options.end() )
return true;
}
return false;
}
options_t ProcessOptions(char* const* argv, int argc, std::vector<OptionScheme> scheme);
std::string OptionHelpItem(const OptionName& o);
enum SrtStatsPrintFormat
{
SRTSTATS_PROFMAT_INVALID = -1,
SRTSTATS_PROFMAT_2COLS = 0,
SRTSTATS_PROFMAT_JSON,
SRTSTATS_PROFMAT_CSV
};
SrtStatsPrintFormat ParsePrintFormat(std::string pf);
class SrtStatsWriter
{
public:
virtual std::string WriteStats(int sid, const CBytePerfMon& mon) = 0;
virtual std::string WriteBandwidth(double mbpsBandwidth) = 0;
virtual ~SrtStatsWriter() { };
};
std::shared_ptr<SrtStatsWriter> SrtStatsWriterFactory(SrtStatsPrintFormat printformat);
#endif