Commit c33d0640 authored by Felix Morgner's avatar Felix Morgner
Browse files

week10: add solution for asynchronous JuliaClient

parent b1cfeede
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>w10_solution_02_AsyncJuliaClient</name>
<comment></comment>
<projects>
<project>simple_http</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>
#include "JuliaClient.h"
#include "asio.hpp"
#include <iostream>
int main() {
auto context = asio::io_context { };
auto client = JuliaClient { context, "127.0.0.1", 8080 };
client.download_image();
context.run();
}
#include "JuliaClient.h"
#include "simple_http.h"
#include "asio.hpp"
#include <algorithm>
#include <fstream>
#include <istream>
#include <iterator>
#include <string>
#include <utility>
JuliaClient::JuliaClient(asio::io_context &context, std::string ip, unsigned short port) :
m_context { context }, m_remote { asio::ip::make_address(ip), port } {
}
void JuliaClient::download_image() {
connect();
}
void JuliaClient::connect() {
m_socket.async_connect(m_remote, [&](auto error) {
if (!error) {
send_request();
}
});
}
void JuliaClient::send_request() {
auto request = http::request { http::method::get };
auto request_stream = std::ostream { &m_transfer_buffer };
request_stream << request;
asio::async_write(m_socket, m_transfer_buffer, [this](auto error, auto) {
if (!error) {
read_response_headers();
}
});
}
void JuliaClient::read_response_headers() {
asio::async_read_until(m_socket, m_transfer_buffer, "\r\n\r\n", [this](auto error, auto) {
if (error) {
return;
}
auto response_stream = std::istream { &m_transfer_buffer };
auto response = http::response { response_stream };
if (response.complete()) {
handle_response(std::move(response));
} else {
read_response_body(std::move(response));
}
});
}
void JuliaClient::read_response_body(http::response response) {
auto remainder = response.get<http::header::content_length>() - m_transfer_buffer.size();
asio::async_read(m_socket, m_transfer_buffer, asio::transfer_exactly(remainder), [response, this](auto error, auto) mutable {
auto body_stream = std::istream(&m_transfer_buffer);
response.body(body_stream);
handle_response(std::move(response));
});
}
void JuliaClient::handle_response(http::response response) {
if (response.status() == http::status_code::ok) {
auto file = std::ofstream { "julia.bmp", std::ios::trunc | std::ios::binary };
auto image_data = response.body();
copy(cbegin(image_data), cend(image_data), std::ostream_iterator<char> { file, "" });
}
}
#ifndef JULIACLIENT_H_
#define JULIACLIENT_H_
#include "simple_http.h"
#include "asio.hpp"
#include <string>
struct JuliaClient {
JuliaClient(asio::io_context &context, std::string ip, unsigned short port);
void download_image();
private:
void connect();
void send_request();
void read_response_headers();
void read_response_body(http::response response);
void handle_response(http::response response);
asio::io_context &m_context;
asio::ip::tcp::endpoint m_remote;
asio::ip::tcp::socket m_socket { m_context };
asio::streambuf m_transfer_buffer { };
};
#endif /* JULIACLIENT_H_ */
//
// asio.hpp
// ~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_HPP
#define ASIO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "../../../third_party/asio/include/asio/associated_allocator.hpp"
#include "../../../third_party/asio/include/asio/associated_executor.hpp"
#include "../../../third_party/asio/include/asio/async_result.hpp"
#include "../../../third_party/asio/include/asio/awaitable.hpp"
#include "../../../third_party/asio/include/asio/basic_datagram_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_deadline_timer.hpp"
#include "../../../third_party/asio/include/asio/basic_io_object.hpp"
#include "../../../third_party/asio/include/asio/basic_raw_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_seq_packet_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_serial_port.hpp"
#include "../../../third_party/asio/include/asio/basic_signal_set.hpp"
#include "../../../third_party/asio/include/asio/basic_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_socket_acceptor.hpp"
#include "../../../third_party/asio/include/asio/basic_socket_iostream.hpp"
#include "../../../third_party/asio/include/asio/basic_socket_streambuf.hpp"
#include "../../../third_party/asio/include/asio/basic_stream_socket.hpp"
#include "../../../third_party/asio/include/asio/basic_streambuf.hpp"
#include "../../../third_party/asio/include/asio/basic_waitable_timer.hpp"
#include "../../../third_party/asio/include/asio/bind_executor.hpp"
#include "../../../third_party/asio/include/asio/buffer.hpp"
#include "../../../third_party/asio/include/asio/buffered_read_stream_fwd.hpp"
#include "../../../third_party/asio/include/asio/buffered_read_stream.hpp"
#include "../../../third_party/asio/include/asio/buffered_stream_fwd.hpp"
#include "../../../third_party/asio/include/asio/buffered_stream.hpp"
#include "../../../third_party/asio/include/asio/buffered_write_stream_fwd.hpp"
#include "../../../third_party/asio/include/asio/buffered_write_stream.hpp"
#include "../../../third_party/asio/include/asio/buffers_iterator.hpp"
#include "../../../third_party/asio/include/asio/co_spawn.hpp"
#include "../../../third_party/asio/include/asio/completion_condition.hpp"
#include "../../../third_party/asio/include/asio/compose.hpp"
#include "../../../third_party/asio/include/asio/connect.hpp"
#include "../../../third_party/asio/include/asio/coroutine.hpp"
#include "../../../third_party/asio/include/asio/deadline_timer.hpp"
#include "../../../third_party/asio/include/asio/defer.hpp"
#include "../../../third_party/asio/include/asio/detached.hpp"
#include "../../../third_party/asio/include/asio/dispatch.hpp"
#include "../../../third_party/asio/include/asio/error.hpp"
#include "../../../third_party/asio/include/asio/error_code.hpp"
#include "../../../third_party/asio/include/asio/execution_context.hpp"
#include "../../../third_party/asio/include/asio/executor.hpp"
#include "../../../third_party/asio/include/asio/executor_work_guard.hpp"
#include "../../../third_party/asio/include/asio/generic/basic_endpoint.hpp"
#include "../../../third_party/asio/include/asio/generic/datagram_protocol.hpp"
#include "../../../third_party/asio/include/asio/generic/raw_protocol.hpp"
#include "../../../third_party/asio/include/asio/generic/seq_packet_protocol.hpp"
#include "../../../third_party/asio/include/asio/generic/stream_protocol.hpp"
#include "../../../third_party/asio/include/asio/handler_alloc_hook.hpp"
#include "../../../third_party/asio/include/asio/handler_continuation_hook.hpp"
#include "../../../third_party/asio/include/asio/handler_invoke_hook.hpp"
#include "../../../third_party/asio/include/asio/high_resolution_timer.hpp"
#include "../../../third_party/asio/include/asio/io_context.hpp"
#include "../../../third_party/asio/include/asio/io_context_strand.hpp"
#include "../../../third_party/asio/include/asio/io_service.hpp"
#include "../../../third_party/asio/include/asio/io_service_strand.hpp"
#include "../../../third_party/asio/include/asio/ip/address.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v4.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v4_iterator.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v4_range.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v6.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v6_iterator.hpp"
#include "../../../third_party/asio/include/asio/ip/address_v6_range.hpp"
#include "../../../third_party/asio/include/asio/ip/network_v4.hpp"
#include "../../../third_party/asio/include/asio/ip/network_v6.hpp"
#include "../../../third_party/asio/include/asio/ip/bad_address_cast.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_endpoint.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_resolver.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_resolver_entry.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_resolver_iterator.hpp"
#include "../../../third_party/asio/include/asio/ip/basic_resolver_query.hpp"
#include "../../../third_party/asio/include/asio/ip/host_name.hpp"
#include "../../../third_party/asio/include/asio/ip/icmp.hpp"
#include "../../../third_party/asio/include/asio/ip/multicast.hpp"
#include "../../../third_party/asio/include/asio/ip/resolver_base.hpp"
#include "../../../third_party/asio/include/asio/ip/resolver_query_base.hpp"
#include "../../../third_party/asio/include/asio/ip/tcp.hpp"
#include "../../../third_party/asio/include/asio/ip/udp.hpp"
#include "../../../third_party/asio/include/asio/ip/unicast.hpp"
#include "../../../third_party/asio/include/asio/ip/v6_only.hpp"
#include "../../../third_party/asio/include/asio/is_executor.hpp"
#include "../../../third_party/asio/include/asio/is_read_buffered.hpp"
#include "../../../third_party/asio/include/asio/is_write_buffered.hpp"
#include "../../../third_party/asio/include/asio/local/basic_endpoint.hpp"
#include "../../../third_party/asio/include/asio/local/connect_pair.hpp"
#include "../../../third_party/asio/include/asio/local/datagram_protocol.hpp"
#include "../../../third_party/asio/include/asio/local/stream_protocol.hpp"
#include "../../../third_party/asio/include/asio/packaged_task.hpp"
#include "../../../third_party/asio/include/asio/placeholders.hpp"
#include "../../../third_party/asio/include/asio/posix/basic_descriptor.hpp"
#include "../../../third_party/asio/include/asio/posix/basic_stream_descriptor.hpp"
#include "../../../third_party/asio/include/asio/posix/descriptor.hpp"
#include "../../../third_party/asio/include/asio/posix/descriptor_base.hpp"
#include "../../../third_party/asio/include/asio/posix/stream_descriptor.hpp"
#include "../../../third_party/asio/include/asio/post.hpp"
#include "../../../third_party/asio/include/asio/read.hpp"
#include "../../../third_party/asio/include/asio/read_at.hpp"
#include "../../../third_party/asio/include/asio/read_until.hpp"
#include "../../../third_party/asio/include/asio/redirect_error.hpp"
#include "../../../third_party/asio/include/asio/serial_port.hpp"
#include "../../../third_party/asio/include/asio/serial_port_base.hpp"
#include "../../../third_party/asio/include/asio/signal_set.hpp"
#include "../../../third_party/asio/include/asio/socket_base.hpp"
#include "../../../third_party/asio/include/asio/steady_timer.hpp"
#include "../../../third_party/asio/include/asio/strand.hpp"
#include "../../../third_party/asio/include/asio/streambuf.hpp"
#include "../../../third_party/asio/include/asio/system_context.hpp"
#include "../../../third_party/asio/include/asio/system_error.hpp"
#include "../../../third_party/asio/include/asio/system_executor.hpp"
#include "../../../third_party/asio/include/asio/system_timer.hpp"
#include "../../../third_party/asio/include/asio/this_coro.hpp"
#include "../../../third_party/asio/include/asio/thread.hpp"
#include "../../../third_party/asio/include/asio/thread_pool.hpp"
#include "../../../third_party/asio/include/asio/time_traits.hpp"
#include "../../../third_party/asio/include/asio/use_awaitable.hpp"
#include "../../../third_party/asio/include/asio/use_future.hpp"
#include "../../../third_party/asio/include/asio/uses_executor.hpp"
#include "../../../third_party/asio/include/asio/version.hpp"
#include "../../../third_party/asio/include/asio/wait_traits.hpp"
#include "../../../third_party/asio/include/asio/windows/basic_object_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/basic_overlapped_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/basic_random_access_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/basic_stream_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/object_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/overlapped_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/overlapped_ptr.hpp"
#include "../../../third_party/asio/include/asio/windows/random_access_handle.hpp"
#include "../../../third_party/asio/include/asio/windows/stream_handle.hpp"
#include "../../../third_party/asio/include/asio/write.hpp"
#include "../../../third_party/asio/include/asio/write_at.hpp"
#endif // ASIO_HPP
//
// associated_allocator.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_ASSOCIATED_ALLOCATOR_HPP
#define ASIO_ASSOCIATED_ALLOCATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "../../../../third_party/asio/include/asio/detail/config.hpp"
#include <memory>
#include "../../../../third_party/asio/include/asio/detail/type_traits.hpp"
#include "../../../../third_party/asio/include/asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename>
struct associated_allocator_check
{
typedef void type;
};
template <typename T, typename E, typename = void>
struct associated_allocator_impl
{
typedef E type;
static type get(const T&, const E& e) ASIO_NOEXCEPT
{
return e;
}
};
template <typename T, typename E>
struct associated_allocator_impl<T, E,
typename associated_allocator_check<typename T::allocator_type>::type>
{
typedef typename T::allocator_type type;
static type get(const T& t, const E&) ASIO_NOEXCEPT
{
return t.get_allocator();
}
};
} // namespace detail
/// Traits type used to obtain the allocator associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Allocator shall be a type meeting the Allocator requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c a is an object of type @c
* Allocator.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Allocator requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,a) and with return type @c type.
*/
template <typename T, typename Allocator = std::allocator<void> >
struct associated_allocator
{
/// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>.
/// Otherwise @c Allocator.
#if defined(GENERATING_DOCUMENTATION)
typedef see_below type;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::associated_allocator_impl<T, Allocator>::type type;
#endif // defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c allocator_type, returns
/// <tt>t.get_allocator()</tt>. Otherwise returns @c a.
static type get(const T& t,
const Allocator& a = Allocator()) ASIO_NOEXCEPT
{
return detail::associated_allocator_impl<T, Allocator>::get(t, a);
}
};
/// Helper function to obtain an object's associated allocator.
/**
* @returns <tt>associated_allocator<T>::get(t)</tt>
*/
template <typename T>
inline typename associated_allocator<T>::type
get_associated_allocator(const T& t) ASIO_NOEXCEPT
{
return associated_allocator<T>::get(t);
}
/// Helper function to obtain an object's associated allocator.
/**
* @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt>
*/
template <typename T, typename Allocator>
inline typename associated_allocator<T, Allocator>::type
get_associated_allocator(const T& t, const Allocator& a) ASIO_NOEXCEPT
{
return associated_allocator<T, Allocator>::get(t, a);
}
#if defined(ASIO_HAS_ALIAS_TEMPLATES)
template <typename T, typename Allocator = std::allocator<void> >
using associated_allocator_t
= typename associated_allocator<T, Allocator>::type;
#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
} // namespace asio
#include "../../../../third_party/asio/include/asio/detail/pop_options.hpp"
#endif // ASIO_ASSOCIATED_ALLOCATOR_HPP
//
// associated_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_ASSOCIATED_EXECUTOR_HPP
#define ASIO_ASSOCIATED_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "../../../../third_party/asio/include/asio/detail/config.hpp"
#include "../../../../third_party/asio/include/asio/detail/type_traits.hpp"
#include "../../../../third_party/asio/include/asio/is_executor.hpp"
#include "../../../../third_party/asio/include/asio/system_executor.hpp"
#include "../../../../third_party/asio/include/asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename>
struct associated_executor_check
{
typedef void type;
};
template <typename T, typename E, typename = void>
struct associated_executor_impl
{
typedef E type;
static type get(const T&, const E& e) ASIO_NOEXCEPT
{
return e;
}
};
template <typename T, typename E>
struct associated_executor_impl<T, E,
typename associated_executor_check<typename T::executor_type>::type>
{
typedef typename T::executor_type type;
static type get(const T& t, const E&) ASIO_NOEXCEPT
{
return t.get_executor();
}
};
} // namespace detail
/// Traits type used to obtain the executor associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Executor shall be a type meeting the Executor requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c e is an object of type @c
* Executor.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Executor requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,e) and with return type @c type.
*/
template <typename T, typename Executor = system_executor>
struct associated_executor
{
/// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>.
/// Otherwise @c Executor.
#if defined(GENERATING_DOCUMENTATION)
typedef see_below type;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::associated_executor_impl<T, Executor>::type type;
#endif // defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c executor_type, returns
/// <tt>t.get_executor()</tt>. Otherwise returns @c ex.
static type get(const T& t,
const Executor& ex = Executor()) ASIO_NOEXCEPT
{
return detail::associated_executor_impl<T, Executor>::get(t, ex);
}
};
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T>::get(t)</tt>
*/
template <typename T>
inline typename associated_executor<T>::type
get_associated_executor(const T& t) ASIO_NOEXCEPT
{
return associated_executor<T>::get(t);
}
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt>
*/
template <typename T, typename Executor>
inline typename associated_executor<T, Executor>::type
get_associated_executor(const T& t, const Executor& ex,
typename enable_if<is_executor<
Executor>::value>::type* = 0) ASIO_NOEXCEPT
{
return associated_executor<T, Executor>::get(t, ex);
}
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T, typename
* ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt>
*/
template <typename T, typename ExecutionContext>
inline typename associated_executor<T,
typename ExecutionContext::executor_type>::type
get_associated_executor(const T& t, ExecutionContext& ctx,
typename enable_if<is_convertible<ExecutionContext&,
execution_context&>::value>::type* = 0) ASIO_NOEXCEPT
{
return associated_executor<T,
typename ExecutionContext::executor_type>::get(t, ctx.get_executor());
}
#if defined(ASIO_HAS_ALIAS_TEMPLATES)
template <typename T, typename Executor = system_executor>
using associated_executor_t = typename associated_executor<T, Executor>::type;