aboutsummaryrefslogtreecommitdiffstats
path: root/include/jau
diff options
context:
space:
mode:
Diffstat (limited to 'include/jau')
-rw-r--r--include/jau/byte_stream.hpp36
-rw-r--r--include/jau/io_util.hpp72
-rw-r--r--include/jau/string_util.hpp48
3 files changed, 141 insertions, 15 deletions
diff --git a/include/jau/byte_stream.hpp b/include/jau/byte_stream.hpp
index e68c431..f15c292 100644
--- a/include/jau/byte_stream.hpp
+++ b/include/jau/byte_stream.hpp
@@ -42,6 +42,8 @@
// Include Botan header files before this one to be integrated w/ Botan!
// #include <botan_all.h>
+using namespace jau::fractions_i64_literals;
+
namespace jau::io {
/** \addtogroup IOUtils
@@ -365,15 +367,19 @@ namespace jau::io {
size_t peek(uint8_t[], size_t, size_t) const NOEXCEPT_BOTAN override;
bool check_available(size_t n) NOEXCEPT_BOTAN override;
bool end_of_data() const NOEXCEPT_BOTAN override;
- bool error() const noexcept override { return m_source.bad(); }
+ bool error() const noexcept override { return nullptr == m_source || m_source->bad(); }
std::string id() const NOEXCEPT_BOTAN override;
/**
* Construct a Stream-Based byte input stream from filesystem path
- * @param file the path to the file
+ *
+ * In case the given path is a local file URI starting with `file://`, see jau::io::uri::is_local_file_protocol(),
+ * the leading `file://` is cut off and the remainder being used.
+ *
+ * @param path the path to the file, maybe a local file URI
* @param use_binary whether to treat the file as binary (default) or use platform character conversion
*/
- ByteInStream_File(const std::string& file, bool use_binary = true) noexcept;
+ ByteInStream_File(const std::string& path, bool use_binary = true) noexcept;
ByteInStream_File(const ByteInStream_File&) = delete;
@@ -395,7 +401,7 @@ namespace jau::io {
private:
const std::string m_identifier;
- mutable std::ifstream m_source;
+ mutable std::unique_ptr<std::ifstream> m_source;
uint64_t m_content_size;
uint64_t m_bytes_consumed;
};
@@ -403,7 +409,9 @@ namespace jau::io {
/**
* This class represents a Ringbuffer-Based byte input stream with a URL connection provisioned data feed.
*
- * Standard implementation uses curl, hence all protocols supported by curl are supported.
+ * Standard implementation uses [curl](https://curl.se/),
+ * hence all [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) are supported,
+ * jau::io::uri::supported_protocols().
*/
class ByteInStream_URL final : public ByteInStream {
public:
@@ -450,7 +458,7 @@ namespace jau::io {
/**
* Construct a ringbuffer backed Http byte input stream
* @param url the URL of the data to read
- * @param timeout maximum duration in fractions of seconds to wait @ check_available(), where fractions_i64::zero waits infinitely
+ * @param timeout maximum duration in fractions of seconds to wait @ check_available() for next bytes, where fractions_i64::zero waits infinitely
*/
ByteInStream_URL(const std::string& url, const jau::fraction_i64& timeout) noexcept;
@@ -483,11 +491,25 @@ namespace jau::io {
jau::relaxed_atomic_uint64 m_content_size;
jau::relaxed_atomic_uint64 m_total_xfered;
relaxed_atomic_async_io_result_t m_result;
- std::thread m_url_thread;
+ std::unique_ptr<std::thread> m_url_thread;
uint64_t m_bytes_consumed;
};
/**
+ * Parses the given path_or_uri, if it matches a supported protocol, see jau::io::uri::protocol_supported(),
+ * but is not a local file, see jau::io::uri::is_local_file_protocol(), ByteInStream_URL is being attempted.
+ *
+ * If the above fails, ByteInStream_File is attempted.
+ *
+ * If non of the above leads to a ByteInStream without ByteInStream::error(), nullptr is returned.
+ *
+ * @param path_or_uri given path or uri for with a ByteInStream instance shall be established.
+ * @param timeout a timeout in case ByteInStream_URL is being used as maximum dureation to wait for next bytes at ByteInStream_URL::check_available(), defaults to 20_s
+ * @return a working ByteInStream w/o ByteInStream::error() or nullptr
+ */
+ std::unique_ptr<ByteInStream> to_ByteInStream(const std::string& path_or_uri, jau::fraction_i64 timeout=20_s) noexcept;
+
+ /**
* This class represents a Ringbuffer-Based byte input stream with an externally provisioned data feed.
*/
class ByteInStream_Feed final : public ByteInStream {
diff --git a/include/jau/io_util.hpp b/include/jau/io_util.hpp
index c74a875..2ca8475 100644
--- a/include/jau/io_util.hpp
+++ b/include/jau/io_util.hpp
@@ -84,14 +84,63 @@ namespace jau::io {
StreamConsumerFunc consumer_fn) noexcept;
/**
+ * Limited URI scheme functionality to query whether implementation may handle the protocol.
+ *
+ * The URI scheme functionality exposed here is limited and only provided to decide whether the used implementation
+ * is able to handle the protocol. This is not a replacement for a proper URI class.
+ */
+ namespace uri {
+ /**
+ * Returns a list of supported protocol supported by [*libcurl* network protocols](https://curl.se/docs/url-syntax.html),
+ * queried at runtime.
+ * @see protocol_supported()
+ */
+ std::vector<std::string_view> supported_protocols() noexcept;
+
+ /**
+ * Returns the valid uri-scheme-view from given uri-view,
+ * which is empty if no valid scheme is included.
+ *
+ * @param uri an uri-view
+ * @return valid uri-scheme-view, empty if non found
+ */
+ std::string_view get_scheme(const std::string_view& uri) noexcept;
+
+ /**
+ * Returns true if the uri-scheme of given uri-view matches a supported by [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) otherwise false.
+ *
+ * The *libcurl* supported protocols is queried at runtime, see supported_protocols().
+ *
+ * @param uri an uri-view to test
+ * @return true if the uri-scheme of given uri is supported, otherwise false.
+ * @see supported_protocols()
+ * @see get_scheme()
+ */
+ bool protocol_supported(const std::string_view& uri) noexcept;
+
+ /**
+ * Returns true if the uri-scheme of given uri-view matches the local `file` protocol, i.e. starts with `file://`.
+ * @param uri an uri-view to test
+ */
+ bool is_local_file_protocol(const std::string_view& uri) noexcept;
+ }
+
+ /**
* Synchronous URL stream reader using the given StreamConsumerFunc consumer_fn.
*
* To abort streaming, user may return `false` from the given `consumer_func`.
*
+ * Standard implementation uses [curl](https://curl.se/),
+ * hence all [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) are supported,
+ * see jau::io::uri::supported_protocols().
+ *
+ * If the uri-sheme doesn't match a supported protocol, see jau::io::uri::protocol_supported(),
+ * function returns immediately with zero bytes.
+ *
* @param url the URL to open a connection to and stream bytes from
* @param buffer secure std::vector buffer, passed down to consumer_fn
* @param consumer_fn StreamConsumerFunc consumer for each received heap of bytes, returning true to continue stream of false to abort.
- * @return total bytes read or 0 if error
+ * @return total bytes read or 0 if transmission error or protocol of given url is not supported
*/
uint64_t read_url_stream(const std::string& url,
secure_vector<uint8_t>& buffer,
@@ -102,20 +151,27 @@ namespace jau::io {
*
* To abort streaming, user may set given reference `results` to a value other than async_io_result_t::NONE.
*
+ * Standard implementation uses [curl](https://curl.se/),
+ * hence all [*libcurl* network protocols](https://curl.se/docs/url-syntax.html) are supported,
+ * see jau::io::uri::supported_protocols().
+ *
+ * If the uri-sheme doesn't match a supported protocol, see jau::io::uri::protocol_supported(),
+ * function returns with nullptr.
+ *
* @param url the URL to open a connection to and stream bytes from
* @param buffer the ringbuffer destination to write into
* @param has_content_length indicating whether content_length is known from server
* @param content_length tracking the content_length
* @param total_read tracking the total_read
* @param result reference to tracking async_io_result_t. If set to other than async_io_result_t::NONE while streaming, streaming is aborted.
- * @return the url background reading thread
+ * @return the url background reading thread unique-pointer or nullptr if protocol of given url is not supported
*/
- std::thread read_url_stream(const std::string& url,
- ByteRingbuffer& buffer,
- jau::relaxed_atomic_bool& has_content_length,
- jau::relaxed_atomic_uint64& content_length,
- jau::relaxed_atomic_uint64& total_read,
- relaxed_atomic_async_io_result_t& result) noexcept;
+ std::unique_ptr<std::thread> read_url_stream(const std::string& url,
+ ByteRingbuffer& buffer,
+ jau::relaxed_atomic_bool& has_content_length,
+ jau::relaxed_atomic_uint64& content_length,
+ jau::relaxed_atomic_uint64& total_read,
+ relaxed_atomic_async_io_result_t& result) noexcept;
void print_stats(const std::string& prefix, const uint64_t& out_bytes_total, const jau::fraction_i64& td) noexcept;
diff --git a/include/jau/string_util.hpp b/include/jau/string_util.hpp
index 6673171..8a6a37f 100644
--- a/include/jau/string_util.hpp
+++ b/include/jau/string_util.hpp
@@ -201,9 +201,31 @@ namespace jau {
{
return std::to_string(ref);
}
+
+ template< class value_type,
+ std::enable_if_t<!std::is_integral_v<value_type> &&
+ !std::is_floating_point_v<value_type> &&
+ std::is_base_of_v<std::string, value_type>,
+ bool> = true>
+ inline std::string to_string(const value_type & ref) {
+ return ref;
+ }
+
+ template< class value_type,
+ std::enable_if_t<!std::is_integral_v<value_type> &&
+ !std::is_floating_point_v<value_type> &&
+ !std::is_base_of_v<std::string, value_type> &&
+ std::is_base_of_v<std::string_view, value_type>,
+ bool> = true>
+ inline std::string to_string(const value_type & ref) {
+ return std::string(ref);
+ }
+
template< class value_type,
std::enable_if_t<!std::is_integral_v<value_type> &&
!std::is_floating_point_v<value_type> &&
+ !std::is_base_of_v<std::string, value_type> &&
+ !std::is_base_of_v<std::string_view, value_type> &&
std::is_pointer_v<value_type>,
bool> = true>
inline std::string to_string(const value_type & ref)
@@ -214,6 +236,8 @@ namespace jau {
template< class value_type,
std::enable_if_t<!std::is_integral_v<value_type> &&
!std::is_floating_point_v<value_type> &&
+ !std::is_base_of_v<std::string, value_type> &&
+ !std::is_base_of_v<std::string_view, value_type> &&
!std::is_pointer_v<value_type> &&
jau::has_toString_v<value_type>,
bool> = true>
@@ -224,6 +248,8 @@ namespace jau {
template< class value_type,
std::enable_if_t<!std::is_integral_v<value_type> &&
!std::is_floating_point_v<value_type> &&
+ !std::is_base_of_v<std::string, value_type> &&
+ !std::is_base_of_v<std::string_view, value_type> &&
!std::is_pointer_v<value_type> &&
!jau::has_toString_v<value_type> &&
jau::has_to_string_v<value_type>,
@@ -235,6 +261,8 @@ namespace jau {
template< class value_type,
std::enable_if_t<!std::is_integral_v<value_type> &&
!std::is_floating_point_v<value_type> &&
+ !std::is_base_of_v<std::string, value_type> &&
+ !std::is_base_of_v<std::string_view, value_type> &&
!std::is_pointer_v<value_type> &&
!jau::has_toString_v<value_type> &&
!jau::has_to_string_v<value_type> &&
@@ -247,6 +275,8 @@ namespace jau {
template< class value_type,
std::enable_if_t<!std::is_integral_v<value_type> &&
!std::is_floating_point_v<value_type> &&
+ !std::is_base_of_v<std::string, value_type> &&
+ !std::is_base_of_v<std::string_view, value_type> &&
!std::is_pointer_v<value_type> &&
!jau::has_toString_v<value_type> &&
!jau::has_to_string_v<value_type> &&
@@ -257,6 +287,24 @@ namespace jau {
return "jau::to_string<T> not available for "+type_cue<value_type>::print("unknown", TypeTraitGroup::ALL);
}
+ template<typename T>
+ std::string to_string(std::vector<T> const &list, const std::string& delim)
+ {
+ if ( list.empty() ) {
+ return std::string();
+ }
+ bool need_delim = false;
+ std::string res;
+ for(const T& e : list) {
+ if( need_delim ) {
+ res.append( delim ).append( " " );
+ }
+ res.append( to_string( e ) );
+ need_delim = true;
+ }
+ return res;
+ }
+
/**@}*/
} // namespace jau