Merge pull request #77 from falk-werner/adapter_client
Provides client mode for webfuse_adapterpull/78/head
commit
56749c113b
@ -0,0 +1,159 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file adapter/client.h
|
||||
/// \brief Adapter client.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef WF_ADAPTER_CLIENT_H
|
||||
#define WF_ADAPTER_CLIENT_H
|
||||
|
||||
#include <webfuse/adapter/api.h>
|
||||
#include <webfuse/adapter/client_callback.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \struct wf_client
|
||||
/// \brief Adapter client
|
||||
///
|
||||
/// An adapter client is used to connect to a remote provider server, e.g. a
|
||||
/// cloud service, an request a filesystem to inject.
|
||||
//------------------------------------------------------------------------------
|
||||
struct wf_client;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Created a new instance of an adapter client.
|
||||
///
|
||||
/// During creation, the client is initialized in the following order:
|
||||
/// - WF_CLIENT_INIT is triggered to initialize custom data
|
||||
/// - WF_CLIENT_GET_TLS_CONFIG is triggered to query TLS configuration
|
||||
/// - internal initialization is performed
|
||||
/// - WF_CLIENT_CREATED is triggered
|
||||
///
|
||||
/// Therefore, the client should not be used, unless WF_CLIENT_CREATED is
|
||||
/// triggered.
|
||||
///
|
||||
/// When TLS configuration is queried, a pointer to an instance if
|
||||
/// \see wf_client_tlsconfig is provided to be set by the user.
|
||||
///
|
||||
/// \param callback Pointer to the callback function.
|
||||
/// \param user_data Pointer to user data.
|
||||
///
|
||||
/// \return Newly created instance of an adapter client.
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API struct wf_client *
|
||||
wf_client_create(
|
||||
wf_client_callback_fn * callback,
|
||||
void * user_data);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Disposes an adapter client.
|
||||
///
|
||||
/// \param client Pointer to the client.
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_dispose(
|
||||
struct wf_client * client);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Get user data.
|
||||
///
|
||||
/// \param client Pointer to the client.
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void *
|
||||
wf_client_get_userdata(
|
||||
struct wf_client * client);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Triggers the client.
|
||||
///
|
||||
/// \param client Pointer to the client.
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_service(
|
||||
struct wf_client * client);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Interrupts a service call.
|
||||
///
|
||||
/// Wakes up the client.
|
||||
///
|
||||
/// \note This is the only function that can be used safely from another
|
||||
// thread.
|
||||
///
|
||||
/// \param client Pointer to the client.
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_interrupt(
|
||||
struct wf_client * client);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Connects to a foreign server.
|
||||
///
|
||||
/// Starts to connect. The callback is triggered, when connect is finised:
|
||||
/// - WF_CLIENT_CONNECTED on success
|
||||
/// - WF_CLIENT_DISCONNECTED on connect error
|
||||
///
|
||||
/// \param client Pointer to the client.
|
||||
/// \param url URL of the remote ppovider.
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_connect(
|
||||
struct wf_client * client,
|
||||
char const * url);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Disconnects from the foreign server.
|
||||
///
|
||||
/// The event WF_CLIENT_DISCONNECTED is triggered, when disconnected.
|
||||
///
|
||||
/// \param client Pointer to the client.
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_disconnect(
|
||||
struct wf_client * client);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Authenticated the client.
|
||||
///
|
||||
/// During authentication, credentials are queries via
|
||||
/// WF_CLIENT_AUTHENTICATE_GET_CREDENTIALS event. In that case a pointer to an
|
||||
/// instance of wf_client_tlsconfig is provided to set credentials.
|
||||
///
|
||||
/// When authentications finishes, an event is triggered:
|
||||
/// - WF_CLIENT_AUTHENTICATED on success
|
||||
/// - WF_CLIENT_AUTHENTICATION_FAILED on failure
|
||||
///
|
||||
/// \param client Pointer to the client.
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_authenticate(
|
||||
struct wf_client * client);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Add a filesystem.
|
||||
///
|
||||
/// After add filesystem finished, an event is triggered:
|
||||
/// - WF_CLIENT_FILESYSTEM_ADDED on success
|
||||
/// - WF_CLIENT_FILESYSTEM_ADD_FAILED on failure
|
||||
///
|
||||
/// \note Currently, only one file system is supported by the client.
|
||||
///
|
||||
/// \param client Pointer to the client.
|
||||
/// \param local_path Local path where the filesystem should be places
|
||||
/// (must be an exististing and empty directory).
|
||||
/// \param name Name of the filesystem (identifier sent to the provider).
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_add_filesystem(
|
||||
struct wf_client * client,
|
||||
char const * local_path,
|
||||
char const * name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,53 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file adapter/client_callbak.h
|
||||
/// \brief Callback of adapter clients.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef WF_ADAPTER_CLIENT_CALLBACK_H
|
||||
#define WF_ADAPTER_CLIENT_CALLBACK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
#define WF_CLIENT_INIT 0x0001 ///< Out-most initialization of a client
|
||||
#define WF_CLIENT_CLEANUP 0x0002 ///< Out-most cleanup of a client
|
||||
#define WF_CLIENT_CREATED 0x0003 ///< Client is fully initialized an can be used
|
||||
|
||||
#define WF_CLIENT_CONNECTED 0x0011 ///< Connection to a foreign provider established
|
||||
#define WF_CLIENT_DISCONNECTED 0x0012 ///< Connection closed or connect failed
|
||||
|
||||
#define WF_CLIENT_AUTHENTICATED 0x0021 ///< Authentication succeeded
|
||||
#define WF_CLIENT_AUTHENTICATION_FAILED 0x0022 ///< Authentication failed
|
||||
#define WF_CLIENT_AUTHENTICATE_GET_CREDENTIALS 0x0023 ///< Query credentials (\see wf_client_authenticate)
|
||||
|
||||
#define WF_CLIENT_FILESYSTEM_ADDED 0x0031 ///< File system added successfully
|
||||
#define WF_CLIENT_FILESYSTEM_ADD_FAILED 0x0032 ///< Failed to add file system
|
||||
|
||||
#define WF_CLIENT_GET_TLS_CONFIG 0x0041 ///< Query TLS config (\see wf_client_create)
|
||||
|
||||
struct wf_client;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Client callback function
|
||||
///
|
||||
/// This function is triggered whenever an event occurs the client should
|
||||
/// be aware of.
|
||||
///
|
||||
/// \param client Pointer to the client
|
||||
/// \param reason Event, that triggered the callback
|
||||
/// \param args Event-specific arguments
|
||||
//------------------------------------------------------------------------------
|
||||
typedef void wf_client_callback_fn(
|
||||
struct wf_client * client,
|
||||
int reason,
|
||||
void * args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,69 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file adapter/client_tslconfig.h
|
||||
/// \brief Configuration of TLS (Transport Layer Security) for adapter clients.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef WF_ADAPTER_CLIENT_TLSCONFIG_H
|
||||
#define WF_ADAPTER_CLIENT_TLSCONFIG_H
|
||||
|
||||
#include <webfuse/adapter/api.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \struct wf_client_tlsconfig
|
||||
/// \brief TLS configuration of the client.
|
||||
///
|
||||
/// TLS configuration is queried during initialization of a client via
|
||||
/// WF_CLIENT_GET_TLS_CONFIG event.
|
||||
///
|
||||
/// \see WF_CLIENT_GET_TLS_CONFIG
|
||||
/// \see wf_client_create
|
||||
//------------------------------------------------------------------------------
|
||||
struct wf_client_tlsconfig;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Sets the path to the private key.
|
||||
///
|
||||
/// \note To enable TLS both, key_path and cert_path, must be specified.
|
||||
///
|
||||
/// \param config Pointer to config.
|
||||
/// \param key_path Path to private key file (in PEM format).
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_tlsconfig_set_keypath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * key_path);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Sets the path to the clients certificate.
|
||||
///
|
||||
/// \note To enable TLS both, key_path and cert_path, must be specified.
|
||||
///
|
||||
/// \param config Pointer to the config.
|
||||
/// \param cert_path Path the the clients certificate (in PEM format).
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_tlsconfig_set_certpath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * cert_path);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \brief Sets the path the CA file.
|
||||
///
|
||||
/// \param config Pointer to the config.
|
||||
/// \param cafile_path Path to CA file (in PEM format).
|
||||
//------------------------------------------------------------------------------
|
||||
extern WF_API void
|
||||
wf_client_tlsconfig_set_cafilepath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * cafile_path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,127 @@
|
||||
#include "webfuse/adapter/impl/client.h"
|
||||
#include "webfuse/adapter/impl/client_protocol.h"
|
||||
#include "webfuse/adapter/impl/client_tlsconfig.h"
|
||||
#include "webfuse/core/lws_log.h"
|
||||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WF_CLIENT_PROTOCOL_COUNT 2
|
||||
|
||||
struct wf_client
|
||||
{
|
||||
struct wf_client_protocol protocol;
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_protocols protocols[WF_CLIENT_PROTOCOL_COUNT];
|
||||
struct wf_client_tlsconfig tls;
|
||||
struct lws_context * context;
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
struct wf_client *
|
||||
wf_impl_client_create(
|
||||
wf_client_callback_fn * callback,
|
||||
void * user_data)
|
||||
{
|
||||
wf_lwslog_disable();
|
||||
|
||||
struct wf_client * client = malloc(sizeof(struct wf_client));
|
||||
wf_impl_client_tlsconfig_init(&client->tls);
|
||||
client->user_data = user_data;
|
||||
wf_impl_client_protocol_init(&client->protocol,
|
||||
(wf_client_protocol_callback_fn*) callback, (void*) client);
|
||||
|
||||
memset(client->protocols, 0, sizeof(struct lws_protocols) * WF_CLIENT_PROTOCOL_COUNT);
|
||||
wf_impl_client_protocol_init_lws(&client->protocol, &client->protocols[0]);
|
||||
|
||||
memset(&client->info, 0, sizeof(struct lws_context_creation_info));
|
||||
client->info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
client->info.protocols = client->protocols;
|
||||
client->info.uid = -1;
|
||||
client->info.gid = -1;
|
||||
|
||||
wf_impl_client_protocol_callback(&client->protocol, WF_CLIENT_GET_TLS_CONFIG, &client->tls);
|
||||
if (wf_impl_client_tlsconfig_isset(&client->tls))
|
||||
{
|
||||
client->info.options |= LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
||||
}
|
||||
|
||||
client->context = lws_create_context(&client->info);
|
||||
|
||||
if (wf_impl_client_tlsconfig_isset(&client->tls))
|
||||
{
|
||||
struct lws_vhost * vhost = lws_create_vhost(client->context, &client->info);
|
||||
client->info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
client->info.client_ssl_cert_filepath = client->tls.cert_path;
|
||||
client->info.client_ssl_private_key_filepath = client->tls.key_path;
|
||||
client->info.client_ssl_ca_filepath = client->tls.cafile_path;
|
||||
lws_init_vhost_client_ssl(&client->info, vhost);
|
||||
}
|
||||
|
||||
wf_impl_client_protocol_callback(&client->protocol, WF_CLIENT_CREATED ,NULL);
|
||||
return client;
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_dispose(
|
||||
struct wf_client * client)
|
||||
{
|
||||
lws_context_destroy(client->context);
|
||||
wf_impl_client_protocol_cleanup(&client->protocol);
|
||||
wf_impl_client_tlsconfig_cleanup(&client->tls);
|
||||
free(client);
|
||||
}
|
||||
|
||||
void *
|
||||
wf_impl_client_get_userdata(
|
||||
struct wf_client * client)
|
||||
{
|
||||
return client->user_data;
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_service(
|
||||
struct wf_client * client)
|
||||
{
|
||||
lws_service(client->context, 0);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_interrupt(
|
||||
struct wf_client * client)
|
||||
{
|
||||
lws_cancel_service(client->context);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_connect(
|
||||
struct wf_client * client,
|
||||
char const * url)
|
||||
{
|
||||
wf_impl_client_protocol_connect(&client->protocol, client->context, url);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_disconnect(
|
||||
struct wf_client * client)
|
||||
{
|
||||
wf_impl_client_protocol_disconnect(&client->protocol);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_authenticate(
|
||||
struct wf_client * client)
|
||||
{
|
||||
wf_impl_client_protocol_authenticate(&client->protocol);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_add_filesystem(
|
||||
struct wf_client * client,
|
||||
char const * local_path,
|
||||
char const * name)
|
||||
{
|
||||
wf_impl_client_protocol_add_filesystem(&client->protocol, local_path, name);
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
#ifndef WF_ADAPTER_IMPL_CLIENT_H
|
||||
#define WF_ADAPTER_IMPL_CLIENT_H
|
||||
|
||||
|
||||
#include "webfuse/adapter/client_callback.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern struct wf_client *
|
||||
wf_impl_client_create(
|
||||
wf_client_callback_fn * callback,
|
||||
void * user_data);
|
||||
|
||||
extern void
|
||||
wf_impl_client_dispose(
|
||||
struct wf_client * client);
|
||||
|
||||
extern void *
|
||||
wf_impl_client_get_userdata(
|
||||
struct wf_client * client);
|
||||
|
||||
extern void
|
||||
wf_impl_client_service(
|
||||
struct wf_client * client);
|
||||
|
||||
extern void
|
||||
wf_impl_client_interrupt(
|
||||
struct wf_client * client);
|
||||
|
||||
extern void
|
||||
wf_impl_client_connect(
|
||||
struct wf_client * client,
|
||||
char const * url);
|
||||
|
||||
extern void
|
||||
wf_impl_client_disconnect(
|
||||
struct wf_client * client);
|
||||
|
||||
extern void
|
||||
wf_impl_client_authenticate(
|
||||
struct wf_client * client);
|
||||
|
||||
extern void
|
||||
wf_impl_client_add_filesystem(
|
||||
struct wf_client * client,
|
||||
char const * local_path,
|
||||
char const * name);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,336 @@
|
||||
#include "webfuse/adapter/impl/client_protocol.h"
|
||||
#include "webfuse/adapter/client_callback.h"
|
||||
#include "webfuse/adapter/impl/credentials.h"
|
||||
#include "webfuse/adapter/impl/filesystem.h"
|
||||
#include "webfuse/adapter/impl/mountpoint.h"
|
||||
#include "webfuse/core/protocol_names.h"
|
||||
#include "webfuse/core/url.h"
|
||||
#include "webfuse/core/util.h"
|
||||
#include "webfuse/core/timer/manager.h"
|
||||
#include "webfuse/core/jsonrpc/response.h"
|
||||
#include "webfuse/core/jsonrpc/proxy.h"
|
||||
|
||||
#include "webfuse/core/message.h"
|
||||
#include "webfuse/core/message_queue.h"
|
||||
#include "webfuse/core/container_of.h"
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#define WF_DEFAULT_TIMEOUT (10 * 1000)
|
||||
|
||||
struct wf_impl_client_protocol_add_filesystem_context
|
||||
{
|
||||
struct wf_client_protocol * protocol;
|
||||
char * local_path;
|
||||
};
|
||||
|
||||
static void
|
||||
wf_impl_client_protocol_process(
|
||||
struct wf_client_protocol * protocol,
|
||||
char const * data,
|
||||
size_t length)
|
||||
{
|
||||
json_t * message = json_loadb(data, length, 0, NULL);
|
||||
if (NULL != message)
|
||||
{
|
||||
if (wf_jsonrpc_is_response(message))
|
||||
{
|
||||
wf_jsonrpc_proxy_onresult(protocol->proxy, message);
|
||||
}
|
||||
|
||||
json_decref(message);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
wf_impl_client_protocol_send(
|
||||
json_t * request,
|
||||
void * user_data)
|
||||
{
|
||||
bool result = false;
|
||||
struct wf_client_protocol * protocol = user_data;
|
||||
|
||||
if (NULL != protocol->wsi)
|
||||
{
|
||||
struct wf_message * message = wf_message_create(request);
|
||||
if (NULL != message)
|
||||
{
|
||||
wf_slist_append(&protocol->messages, &message->item);
|
||||
lws_callback_on_writable(protocol->wsi);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
wf_impl_client_protocol_on_authenticate_finished(
|
||||
void * user_data,
|
||||
json_t const * result,
|
||||
json_t const * WF_UNUSED_PARAM(error))
|
||||
{
|
||||
struct wf_client_protocol * protocol = user_data;
|
||||
int const reason = (NULL != result) ? WF_CLIENT_AUTHENTICATED : WF_CLIENT_AUTHENTICATION_FAILED;
|
||||
|
||||
protocol->callback(protocol->user_data, reason, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
wf_impl_client_protocol_on_add_filesystem_finished(
|
||||
void * user_data,
|
||||
json_t const * result,
|
||||
json_t const * WF_UNUSED_PARAM(error))
|
||||
{
|
||||
struct wf_impl_client_protocol_add_filesystem_context * context = user_data;
|
||||
struct wf_client_protocol * protocol = context->protocol;
|
||||
|
||||
int reason = WF_CLIENT_FILESYSTEM_ADD_FAILED;
|
||||
if (NULL == protocol->filesystem)
|
||||
{
|
||||
json_t * id = json_object_get(result, "id");
|
||||
if (json_is_string(id))
|
||||
{
|
||||
char const * name = json_string_value(id);
|
||||
struct wf_mountpoint * mountpoint = wf_mountpoint_create(context->local_path);
|
||||
protocol->filesystem = wf_impl_filesystem_create(protocol->wsi,protocol->proxy, name, mountpoint);
|
||||
if (NULL != protocol->filesystem)
|
||||
{
|
||||
reason = WF_CLIENT_FILESYSTEM_ADDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
wf_mountpoint_dispose(mountpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(context->local_path);
|
||||
free(context);
|
||||
protocol->callback(protocol->user_data, reason, NULL);
|
||||
}
|
||||
|
||||
static int wf_impl_client_protocol_lws_callback(
|
||||
struct lws * wsi,
|
||||
enum lws_callback_reasons reason,
|
||||
void * WF_UNUSED_PARAM(user),
|
||||
void * in,
|
||||
size_t WF_UNUSED_PARAM(len))
|
||||
{
|
||||
int result = 0;
|
||||
struct lws_protocols const * ws_protocol = lws_get_protocol(wsi);
|
||||
struct wf_client_protocol * protocol = (NULL != ws_protocol) ? ws_protocol->user : NULL;
|
||||
|
||||
if (NULL != protocol)
|
||||
{
|
||||
wf_timer_manager_check(protocol->timer_manager);
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
protocol->is_connected = true;
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_CONNECTED, NULL);
|
||||
break;
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
protocol->is_connected = false;
|
||||
protocol->wsi = NULL;
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_DISCONNECTED, NULL);
|
||||
break;
|
||||
case LWS_CALLBACK_CLIENT_CLOSED:
|
||||
protocol->is_connected = false;
|
||||
protocol->wsi = NULL;
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_DISCONNECTED, NULL);
|
||||
break;
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
wf_impl_client_protocol_process(protocol, in, len);
|
||||
break;
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
// fall-through
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
if (wsi == protocol->wsi)
|
||||
{
|
||||
if (protocol->is_shutdown_requested)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else if (!wf_slist_empty(&protocol->messages))
|
||||
{
|
||||
struct wf_slist_item * item = wf_slist_remove_first(&protocol->messages);
|
||||
struct wf_message * message = wf_container_of(item, struct wf_message, item);
|
||||
lws_write(wsi, (unsigned char*) message->data, message->length, LWS_WRITE_TEXT);
|
||||
wf_message_dispose(message);
|
||||
|
||||
if (!wf_slist_empty(&protocol->messages))
|
||||
{
|
||||
lws_callback_on_writable(wsi);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LWS_CALLBACK_RAW_RX_FILE:
|
||||
if ((NULL != protocol->filesystem) && (wsi == protocol->filesystem->wsi))
|
||||
{
|
||||
wf_impl_filesystem_process_request(protocol->filesystem);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_protocol_init(
|
||||
struct wf_client_protocol * protocol,
|
||||
wf_client_protocol_callback_fn * callback,
|
||||
void * user_data)
|
||||
{
|
||||
protocol->is_connected = false,
|
||||
protocol->is_shutdown_requested = false;
|
||||
protocol->wsi = NULL;
|
||||
protocol->callback = callback;
|
||||
protocol->user_data = user_data;
|
||||
protocol->filesystem = NULL;
|
||||
|
||||
wf_slist_init(&protocol->messages);
|
||||
protocol->timer_manager = wf_timer_manager_create();
|
||||
protocol->proxy = wf_jsonrpc_proxy_create(protocol->timer_manager, WF_DEFAULT_TIMEOUT, &wf_impl_client_protocol_send, protocol);
|
||||
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_INIT, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_protocol_cleanup(
|
||||
struct wf_client_protocol * protocol)
|
||||
{
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_CLEANUP, NULL);
|
||||
|
||||
wf_jsonrpc_proxy_dispose(protocol->proxy);
|
||||
wf_timer_manager_dispose(protocol->timer_manager);
|
||||
wf_message_queue_cleanup(&protocol->messages);
|
||||
|
||||
if (NULL != protocol->filesystem)
|
||||
{
|
||||
wf_impl_filesystem_dispose(protocol->filesystem);
|
||||
protocol->filesystem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_protocol_callback(
|
||||
struct wf_client_protocol * protocol,
|
||||
int reason,
|
||||
void * arg)
|
||||
{
|
||||
protocol->callback(protocol->user_data, reason, arg);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_protocol_init_lws(
|
||||
struct wf_client_protocol * protocol,
|
||||
struct lws_protocols * lws_protocol)
|
||||
{
|
||||
lws_protocol->name = WF_PROTOCOL_NAME_ADAPTER_CLIENT;
|
||||
lws_protocol->callback = &wf_impl_client_protocol_lws_callback;
|
||||
lws_protocol->per_session_data_size = 0;
|
||||
lws_protocol->user = protocol;
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_protocol_connect(
|
||||
struct wf_client_protocol * protocol,
|
||||
struct lws_context * context,
|
||||
char const * url)
|
||||
{
|
||||
struct wf_url url_data;
|
||||
bool const success = wf_url_init(&url_data, url);
|
||||
if (success)
|
||||
{
|
||||
struct lws_client_connect_info info;
|
||||
memset(&info, 0 ,sizeof(struct lws_client_connect_info));
|
||||
info.context = context;
|
||||
info.port = url_data.port;
|
||||
info.address = url_data.host;
|
||||
info.path = url_data.path;
|
||||
info.host = info.address;
|
||||
info.origin = info.address;
|
||||
info.ssl_connection = (url_data.use_tls) ? LCCSCF_USE_SSL : 0;
|
||||
info.protocol = WF_PROTOCOL_NAME_PROVIDER_SERVER;
|
||||
info.local_protocol_name = WF_PROTOCOL_NAME_ADAPTER_CLIENT;
|
||||
info.pwsi = &protocol->wsi;
|
||||
|
||||
lws_client_connect_via_info(&info);
|
||||
wf_url_cleanup(&url_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_DISCONNECTED, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_protocol_disconnect(
|
||||
struct wf_client_protocol * protocol)
|
||||
{
|
||||
if (protocol->is_connected)
|
||||
{
|
||||
protocol->is_shutdown_requested = true;
|
||||
lws_callback_on_writable(protocol->wsi);
|
||||
}
|
||||
else
|
||||
{
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_DISCONNECTED, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_protocol_authenticate(
|
||||
struct wf_client_protocol * protocol)
|
||||
{
|
||||
struct wf_credentials creds;
|
||||
wf_impl_credentials_init_default(&creds);
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_AUTHENTICATE_GET_CREDENTIALS, &creds);
|
||||
|
||||
json_incref(creds.data);
|
||||
wf_jsonrpc_proxy_invoke(
|
||||
protocol->proxy,
|
||||
&wf_impl_client_protocol_on_authenticate_finished,
|
||||
protocol,
|
||||
"authenticate",
|
||||
"sj",
|
||||
creds.type, creds.data);
|
||||
|
||||
wf_impl_credentials_cleanup(&creds);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_protocol_add_filesystem(
|
||||
struct wf_client_protocol * protocol,
|
||||
char const * local_path,
|
||||
char const * name)
|
||||
{
|
||||
if (NULL == protocol->filesystem)
|
||||
{
|
||||
struct wf_impl_client_protocol_add_filesystem_context * context = malloc(sizeof(struct wf_impl_client_protocol_add_filesystem_context));
|
||||
context->protocol = protocol;
|
||||
context->local_path = strdup(local_path);
|
||||
|
||||
wf_jsonrpc_proxy_invoke(
|
||||
protocol->proxy,
|
||||
&wf_impl_client_protocol_on_add_filesystem_finished,
|
||||
context,
|
||||
"add_filesystem",
|
||||
"s",
|
||||
name);
|
||||
}
|
||||
else
|
||||
{
|
||||
protocol->callback(protocol->user_data, WF_CLIENT_FILESYSTEM_ADD_FAILED, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
#ifndef WF_ADAPTER_IMPL_CLIENT_PROTOCOL_H
|
||||
#define WF_ADAPTER_IMPL_CLIENT_PROTOCOL_H
|
||||
|
||||
#include "webfuse/adapter/client_callback.h"
|
||||
#include "webfuse/core/slist.h"
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct lws_protocols;
|
||||
struct lws_context;
|
||||
|
||||
struct wf_impl_filesystem;
|
||||
struct wf_jsonrpc_proxy;
|
||||
struct wf_timer_manager;
|
||||
|
||||
typedef void
|
||||
wf_client_protocol_callback_fn(
|
||||
void * user_data,
|
||||
int reason,
|
||||
void * arg);
|
||||
|
||||
struct wf_client_protocol
|
||||
{
|
||||
bool is_connected;
|
||||
bool is_shutdown_requested;
|
||||
struct lws * wsi;
|
||||
wf_client_protocol_callback_fn * callback;
|
||||
struct wf_impl_filesystem * filesystem;
|
||||
void * user_data;
|
||||
struct wf_timer_manager * timer_manager;
|
||||
struct wf_jsonrpc_proxy * proxy;
|
||||
struct wf_slist messages;
|
||||
};
|
||||
|
||||
extern void
|
||||
wf_impl_client_protocol_init(
|
||||
struct wf_client_protocol * protocol,
|
||||
wf_client_protocol_callback_fn * callback,
|
||||
void * user_data);
|
||||
|
||||
extern void
|
||||
wf_impl_client_protocol_cleanup(
|
||||
struct wf_client_protocol * protocol);
|
||||
|
||||
extern void
|
||||
wf_impl_client_protocol_callback(
|
||||
struct wf_client_protocol * protocol,
|
||||
int reason,
|
||||
void * arg);
|
||||
|
||||
extern void
|
||||
wf_impl_client_protocol_init_lws(
|
||||
struct wf_client_protocol * protocol,
|
||||
struct lws_protocols * lws_protocol);
|
||||
|
||||
extern void
|
||||
wf_impl_client_protocol_connect(
|
||||
struct wf_client_protocol * protocol,
|
||||
struct lws_context * conext,
|
||||
char const * url);
|
||||
|
||||
extern void
|
||||
wf_impl_client_protocol_disconnect(
|
||||
struct wf_client_protocol * protocol);
|
||||
|
||||
extern void
|
||||
wf_impl_client_protocol_authenticate(
|
||||
struct wf_client_protocol * protocol);
|
||||
|
||||
extern void
|
||||
wf_impl_client_protocol_add_filesystem(
|
||||
struct wf_client_protocol * protocol,
|
||||
char const * local_path,
|
||||
char const * name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,56 @@
|
||||
#include "webfuse/adapter/impl/client_tlsconfig.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
wf_impl_client_tlsconfig_init(
|
||||
struct wf_client_tlsconfig * config)
|
||||
{
|
||||
config->key_path = NULL;
|
||||
config->cert_path = NULL;
|
||||
config->cafile_path = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_tlsconfig_cleanup(
|
||||
struct wf_client_tlsconfig * config)
|
||||
{
|
||||
free(config->key_path);
|
||||
free(config->cert_path);
|
||||
free(config->cafile_path);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_tlsconfig_set_keypath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * key_path)
|
||||
{
|
||||
free(config->key_path);
|
||||
config->key_path = strdup(key_path);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_tlsconfig_set_certpath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * cert_path)
|
||||
{
|
||||
free(config->cert_path);
|
||||
config->cert_path = strdup(cert_path);
|
||||
}
|
||||
|
||||
void
|
||||
wf_impl_client_tlsconfig_set_cafilepath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * cafile_path)
|
||||
{
|
||||
free(config->cafile_path);
|
||||
config->cafile_path = strdup(cafile_path);
|
||||
}
|
||||
|
||||
bool
|
||||
wf_impl_client_tlsconfig_isset(
|
||||
struct wf_client_tlsconfig const * config)
|
||||
{
|
||||
return (NULL != config->cert_path) && (NULL != config->key_path);
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
#ifndef WF_ADAPTER_IMPL_CLIENT_TLSCONFIG_H
|
||||
#define WF_ADAPTER_IMPL_CLIENT_TLSCONFIG_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct wf_client_tlsconfig
|
||||
{
|
||||
char * key_path;
|
||||
char * cert_path;
|
||||
char * cafile_path;
|
||||
};
|
||||
|
||||
extern void
|
||||
wf_impl_client_tlsconfig_init(
|
||||
struct wf_client_tlsconfig * config);
|
||||
|
||||
extern void
|
||||
wf_impl_client_tlsconfig_cleanup(
|
||||
struct wf_client_tlsconfig * config);
|
||||
|
||||
extern void
|
||||
wf_impl_client_tlsconfig_set_keypath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * key_path);
|
||||
|
||||
extern void
|
||||
wf_impl_client_tlsconfig_set_certpath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * cert_path);
|
||||
|
||||
extern void
|
||||
wf_impl_client_tlsconfig_set_cafilepath(
|
||||
struct wf_client_tlsconfig * config,
|
||||
char const * cafile_path);
|
||||
|
||||
extern bool
|
||||
wf_impl_client_tlsconfig_isset(
|
||||
struct wf_client_tlsconfig const * config);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,32 +0,0 @@
|
||||
#include "webfuse/core/string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char * wf_create_string(char const * format, ...)
|
||||
{
|
||||
char * result = NULL;
|
||||
|
||||
va_list measure_args;
|
||||
va_start(measure_args, format);
|
||||
char buffer;
|
||||
int needed = vsnprintf(&buffer, 1, format, measure_args);
|
||||
va_end(measure_args);
|
||||
|
||||
if (0 <= needed)
|
||||
{
|
||||
result = malloc(needed + 1);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int count = vsnprintf(result, needed + 1, format, args);
|
||||
va_end(args);
|
||||
|
||||
if ((count < 0) || (needed < count))
|
||||
{
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
#ifndef WF_CORE_STRING_H
|
||||
#define WF_CORE_STRING_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <cstdarg>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern char * wf_create_string(char const * format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,50 @@
|
||||
#ifndef WF_LOOKUP_MATCHER_HPP
|
||||
#define WF_LOOKUP_MATCHER_HPP
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <jansson.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
MATCHER_P2(Lookup, parent, name, "")
|
||||
{
|
||||
if (!json_is_array(arg))
|
||||
{
|
||||
*result_listener << "json array expected";
|
||||
return false;
|
||||
}
|
||||
|
||||
json_t * parent_ = json_array_get(arg, 1);
|
||||
if (!json_is_integer(parent_))
|
||||
{
|
||||
*result_listener << "parent is expected to be an integer";
|
||||
return false;
|
||||
}
|
||||
if (parent != json_integer_value(parent_))
|
||||
{
|
||||
*result_listener << "parent mismatch: expected " << parent
|
||||
<< " but was " << json_integer_value(parent_);
|
||||
return false;
|
||||
}
|
||||
|
||||
json_t * name_ = json_array_get(arg, 2);
|
||||
if (!json_is_string(name_))
|
||||
{
|
||||
*result_listener << "name is expected to be a string";
|
||||
return false;
|
||||
}
|
||||
if (0 != strcmp(name, json_string_value(name_)))
|
||||
{
|
||||
*result_listener << "name mismatch: expected \"" << name
|
||||
<< "\" but was \"" << json_string_value(name_) << "\"";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,44 @@
|
||||
#include "webfuse/mocks/mock_adapter_client_callback.hpp"
|
||||
#include "webfuse/adapter/client.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static void
|
||||
webfuse_test_MockAdapterClientCallback_callback(
|
||||
wf_client * client,
|
||||
int reason,
|
||||
void * args)
|
||||
{
|
||||
void * user_data = wf_client_get_userdata(client);
|
||||
auto * callback = reinterpret_cast<webfuse_test::MockAdapterClientCallback*>(user_data);
|
||||
|
||||
callback->Invoke(client, reason, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
MockAdapterClientCallback::MockAdapterClientCallback()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MockAdapterClientCallback::~MockAdapterClientCallback()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void * MockAdapterClientCallback::GetUserData()
|
||||
{
|
||||
return reinterpret_cast<void*>(this);
|
||||
}
|
||||
|
||||
wf_client_callback_fn * MockAdapterClientCallback::GetCallbackFn()
|
||||
{
|
||||
return &webfuse_test_MockAdapterClientCallback_callback;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
#ifndef WF_MOCK_ADAPTER_CLIENT_CALLBACK_HPP
|
||||
#define WF_MOCK_ADAPTER_CLIENT_CALLBACK_HPP
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "webfuse/adapter/client_callback.h"
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class MockAdapterClientCallback
|
||||
{
|
||||
public:
|
||||
MockAdapterClientCallback();
|
||||
virtual ~MockAdapterClientCallback();
|
||||
MOCK_METHOD3(Invoke, void (wf_client *, int, void *));
|
||||
void * GetUserData();
|
||||
wf_client_callback_fn * GetCallbackFn();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,18 @@
|
||||
#ifndef WF_MOCK_INVOKATION_HANDLER_HPP
|
||||
#define WF_MOCK_INVOKATION_HANDLER_HPP
|
||||
|
||||
#include "webfuse/utils/ws_server2.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class MockInvokationHander: public IIvokationHandler
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD2(Invoke, std::string(char const * method, json_t * params));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,579 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "webfuse/utils/adapter_client.hpp"
|
||||
#include "webfuse/adapter/client_tlsconfig.h"
|
||||
#include "webfuse/adapter/credentials.h"
|
||||
#include "webfuse/core/protocol_names.h"
|
||||
#include "webfuse/utils/ws_server2.hpp"
|
||||
#include "webfuse/mocks/mock_adapter_client_callback.hpp"
|
||||
#include "webfuse/mocks/mock_invokation_handler.hpp"
|
||||
#include "webfuse/utils/timeout_watcher.hpp"
|
||||
#include "webfuse/tests/integration/file.hpp"
|
||||
#include "webfuse/mocks/lookup_matcher.hpp"
|
||||
|
||||
using webfuse_test::AdapterClient;
|
||||
using webfuse_test::WsServer2;
|
||||
using webfuse_test::MockInvokationHander;
|
||||
using webfuse_test::MockAdapterClientCallback;
|
||||
using webfuse_test::TimeoutWatcher;
|
||||
using webfuse_test::File;
|
||||
using webfuse_test::Lookup;
|
||||
using testing::_;
|
||||
using testing::Invoke;
|
||||
using testing::AnyNumber;
|
||||
using testing::Return;
|
||||
using testing::Throw;
|
||||
using testing::StrEq;
|
||||
|
||||
#define TIMEOUT (std::chrono::milliseconds(30 * 1000))
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void GetCredentials(wf_client *, int, void * arg)
|
||||
{
|
||||
auto * creds = reinterpret_cast<wf_credentials*>(arg);
|
||||
wf_credentials_set_type(creds, "username");
|
||||
wf_credentials_add(creds, "username", "Bob");
|
||||
wf_credentials_add(creds, "password", "secret");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST(AdapterClient, CreateAndDispose)
|
||||
{
|
||||
MockAdapterClientCallback callback;
|
||||
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_INIT, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CREATED, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_GET_TLS_CONFIG, _)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CLEANUP, nullptr)).Times(1);
|
||||
|
||||
wf_client * client = wf_client_create(
|
||||
callback.GetCallbackFn(), callback.GetUserData());
|
||||
|
||||
wf_client_dispose(client);
|
||||
}
|
||||
|
||||
TEST(AdapterClient, Connect)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(_,_)).Times(0);
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_INIT, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CREATED, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_GET_TLS_CONFIG, _)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CLEANUP, nullptr)).Times(1);
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, IgnoreNonJsonMessage)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(_,_)).Times(0);
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_INIT, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CREATED, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_GET_TLS_CONFIG, _)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CLEANUP, nullptr)).Times(1);
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
server.SendMessage("brummni");
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
|
||||
TEST(AdapterClient, IgnoreInvalidJsonMessage)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(_,_)).Times(0);
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_INIT, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CREATED, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_GET_TLS_CONFIG, _)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CLEANUP, nullptr)).Times(1);
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
json_t * invalid_request = json_object();
|
||||
server.SendMessage(invalid_request);
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, ConnectWithTls)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER, 0, true);
|
||||
EXPECT_CALL(handler, Invoke(_,_)).Times(0);
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_INIT, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CREATED, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_GET_TLS_CONFIG, _)).Times(1)
|
||||
.WillOnce(Invoke([](wf_client *, int, void * arg) {
|
||||
auto * tls = reinterpret_cast<wf_client_tlsconfig*>(arg);
|
||||
wf_client_tlsconfig_set_keypath (tls, "client-key.pem");
|
||||
wf_client_tlsconfig_set_certpath(tls, "client-cert.pem");
|
||||
wf_client_tlsconfig_set_cafilepath(tls, "server-cert.pem");
|
||||
}));
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CLEANUP, nullptr)).Times(1);
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, FailedToConnectInvalidPort)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_INIT, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CREATED, nullptr)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_GET_TLS_CONFIG, _)).Times(1);
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CLEANUP, nullptr)).Times(1);
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), "ws://localhost:4/");
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
|
||||
TEST(AdapterClient, Authenticate)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(StrEq("authenticate"),_)).Times(1)
|
||||
.WillOnce(Return("{}"));
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_AUTHENTICATE_GET_CREDENTIALS, _)).Times(1)
|
||||
.WillOnce(Invoke(GetCredentials));
|
||||
|
||||
bool authenticated = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_AUTHENTICATED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { authenticated = true; }));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.Authenticate();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return authenticated; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, AuthenticateFailedWithoutConnect)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_AUTHENTICATE_GET_CREDENTIALS, _)).Times(1)
|
||||
.WillOnce(Invoke(GetCredentials));
|
||||
bool called = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_AUTHENTICATION_FAILED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&called] (wf_client *, int, void *) mutable {
|
||||
called = true;
|
||||
}));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), "");
|
||||
|
||||
client.Authenticate();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return called; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, AuthenticationFailed)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(StrEq("authenticate"),_)).Times(1)
|
||||
.WillOnce(Throw(std::runtime_error("authentication failed")));
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_AUTHENTICATE_GET_CREDENTIALS, _)).Times(1)
|
||||
.WillOnce(Invoke(GetCredentials));
|
||||
|
||||
bool called = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_AUTHENTICATION_FAILED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&called] (wf_client *, int, void *) mutable {
|
||||
called = true;
|
||||
}));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.Authenticate();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return called; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, AddFileSystem)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(StrEq("add_filesystem"),_)).Times(1)
|
||||
.WillOnce(Return("{\"id\": \"test\"}"));
|
||||
EXPECT_CALL(handler, Invoke(StrEq("lookup"), _)).Times(AnyNumber())
|
||||
.WillRepeatedly(Throw(std::runtime_error("unknown")));
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
bool called = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_FILESYSTEM_ADDED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&called] (wf_client *, int, void *) mutable {
|
||||
called = true;
|
||||
}));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.AddFileSystem();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return called; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, FailToAddFileSystemTwice)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(StrEq("add_filesystem"),_)).Times(1)
|
||||
.WillOnce(Return("{\"id\": \"test\"}"));
|
||||
EXPECT_CALL(handler, Invoke(StrEq("lookup"), _)).Times(AnyNumber())
|
||||
.WillRepeatedly(Throw(std::runtime_error("unknown")));
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
bool filesystem_added = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_FILESYSTEM_ADDED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable {
|
||||
filesystem_added = true;
|
||||
}));
|
||||
|
||||
bool filesystem_add_failed = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_FILESYSTEM_ADD_FAILED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable {
|
||||
filesystem_add_failed = true;
|
||||
}));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.AddFileSystem();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return filesystem_added; }));
|
||||
|
||||
client.AddFileSystem();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return filesystem_add_failed; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, FailToAddFileSystemMissingId)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(StrEq("add_filesystem"),_)).Times(1)
|
||||
.WillOnce(Return("{}"));
|
||||
EXPECT_CALL(handler, Invoke(StrEq("lookup"), _)).Times(AnyNumber())
|
||||
.WillRepeatedly(Throw(std::runtime_error("unknown")));
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
bool filesystem_add_failed = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_FILESYSTEM_ADD_FAILED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable {
|
||||
filesystem_add_failed = true;
|
||||
}));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.AddFileSystem();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return filesystem_add_failed; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, FailToAddFileSystemIdNotString)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(StrEq("add_filesystem"),_)).Times(1)
|
||||
.WillOnce(Return("{\"id\": 42}"));
|
||||
EXPECT_CALL(handler, Invoke(StrEq("lookup"), _)).Times(AnyNumber())
|
||||
.WillRepeatedly(Throw(std::runtime_error("unknown")));
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
bool filesystem_add_failed = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_FILESYSTEM_ADD_FAILED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable {
|
||||
filesystem_add_failed = true;
|
||||
}));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.AddFileSystem();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return filesystem_add_failed; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
|
||||
TEST(AdapterClient, AddFileSystemFailed)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(StrEq("add_filesystem"),_)).Times(1)
|
||||
.WillOnce(Throw(std::runtime_error("failed")));
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
bool called = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_FILESYSTEM_ADD_FAILED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&called] (wf_client *, int, void *) mutable {
|
||||
called = true;
|
||||
}));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.AddFileSystem();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return called; }));
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
||||
|
||||
TEST(AdapterClient, LookupFile)
|
||||
{
|
||||
TimeoutWatcher watcher(TIMEOUT);
|
||||
|
||||
MockInvokationHander handler;
|
||||
WsServer2 server(handler, WF_PROTOCOL_NAME_PROVIDER_SERVER);
|
||||
EXPECT_CALL(handler, Invoke(StrEq("add_filesystem"),_)).Times(1)
|
||||
.WillOnce(Return("{\"id\": \"test\"}"));
|
||||
EXPECT_CALL(handler, Invoke(StrEq("lookup"), _)).Times(AnyNumber())
|
||||
.WillRepeatedly(Throw(std::runtime_error("unknown")));
|
||||
EXPECT_CALL(handler, Invoke(StrEq("lookup"), Lookup(1, "Hello.txt"))).Times(AnyNumber())
|
||||
.WillRepeatedly(Return(
|
||||
"{"
|
||||
"\"inode\": 2,"
|
||||
"\"mode\": 420," //0644
|
||||
"\"type\": \"file\","
|
||||
"\"size\": 42,"
|
||||
"\"atime\": 0,"
|
||||
"\"mtime\": 0,"
|
||||
"\"ctime\": 0"
|
||||
"}"
|
||||
));
|
||||
|
||||
MockAdapterClientCallback callback;
|
||||
EXPECT_CALL(callback, Invoke(_, _, _)).Times(AnyNumber());
|
||||
|
||||
bool connected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_CONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { connected = true; }));
|
||||
|
||||
bool disconnected = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_DISCONNECTED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&] (wf_client *, int, void *) mutable { disconnected = true; }));
|
||||
|
||||
bool called = false;
|
||||
EXPECT_CALL(callback, Invoke(_, WF_CLIENT_FILESYSTEM_ADDED, nullptr)).Times(1)
|
||||
.WillOnce(Invoke([&called] (wf_client *, int, void *) mutable {
|
||||
called = true;
|
||||
}));
|
||||
|
||||
AdapterClient client(callback.GetCallbackFn(), callback.GetUserData(), server.GetUrl());
|
||||
|
||||
client.Connect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return connected; }));
|
||||
|
||||
client.AddFileSystem();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return called; }));
|
||||
|
||||
std::string file_name = client.GetDir() + "/Hello.txt";
|
||||
File file(file_name);
|
||||
ASSERT_TRUE(file.isFile());
|
||||
|
||||
client.Disconnect();
|
||||
ASSERT_TRUE(watcher.waitUntil([&]() mutable { return disconnected; }));
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "webfuse/adapter/client_tlsconfig.h"
|
||||
#include "webfuse/adapter/impl/client_tlsconfig.h"
|
||||
|
||||
TEST(ClientTlsConfig, InitAndCleanup)
|
||||
{
|
||||
wf_client_tlsconfig config;
|
||||
|
||||
wf_impl_client_tlsconfig_init(&config);
|
||||
wf_impl_client_tlsconfig_cleanup(&config);
|
||||
}
|
||||
|
||||
TEST(ClientTlsConfig, SetKeyPath)
|
||||
{
|
||||
wf_client_tlsconfig config;
|
||||
wf_impl_client_tlsconfig_init(&config);
|
||||
|
||||
wf_client_tlsconfig_set_keypath(&config, "/path/to/key.pem");
|
||||
ASSERT_STREQ("/path/to/key.pem", config.key_path);
|
||||
|
||||
wf_impl_client_tlsconfig_cleanup(&config);
|
||||
}
|
||||
|
||||
TEST(ClientTlsConfig, SetCertPath)
|
||||
{
|
||||
wf_client_tlsconfig config;
|
||||
wf_impl_client_tlsconfig_init(&config);
|
||||
|
||||
wf_client_tlsconfig_set_certpath(&config, "/path/to/cert.pem");
|
||||
ASSERT_STREQ("/path/to/cert.pem", config.cert_path);
|
||||
|
||||
wf_impl_client_tlsconfig_cleanup(&config);
|
||||
}
|
||||
|
||||
TEST(ClientTlsConfig, SetCafilePath)
|
||||
{
|
||||
wf_client_tlsconfig config;
|
||||
wf_impl_client_tlsconfig_init(&config);
|
||||
|
||||
wf_client_tlsconfig_set_cafilepath(&config, "/path/to/cafile.pem");
|
||||
ASSERT_STREQ("/path/to/cafile.pem", config.cafile_path);
|
||||
|
||||
wf_impl_client_tlsconfig_cleanup(&config);
|
||||
}
|
||||
|
||||
TEST(ClientTslConfig, IsSet)
|
||||
{
|
||||
wf_client_tlsconfig config;
|
||||
|
||||
wf_impl_client_tlsconfig_init(&config);
|
||||
ASSERT_FALSE(wf_impl_client_tlsconfig_isset(&config));
|
||||
wf_impl_client_tlsconfig_cleanup(&config);
|
||||
|
||||
wf_impl_client_tlsconfig_init(&config);
|
||||
wf_client_tlsconfig_set_keypath(&config, "/path/to/key.pem");
|
||||
ASSERT_FALSE(wf_impl_client_tlsconfig_isset(&config));
|
||||
wf_impl_client_tlsconfig_cleanup(&config);
|
||||
|
||||
wf_impl_client_tlsconfig_init(&config);
|
||||
wf_client_tlsconfig_set_certpath(&config, "/path/to/cert.pem");
|
||||
ASSERT_FALSE(wf_impl_client_tlsconfig_isset(&config));
|
||||
wf_impl_client_tlsconfig_cleanup(&config);
|
||||
|
||||
wf_impl_client_tlsconfig_init(&config);
|
||||
wf_client_tlsconfig_set_keypath(&config, "/path/to/key.pem");
|
||||
wf_client_tlsconfig_set_certpath(&config, "/path/to/cert.pem");
|
||||
ASSERT_TRUE(wf_impl_client_tlsconfig_isset(&config));
|
||||
wf_impl_client_tlsconfig_cleanup(&config);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "webfuse/core/string.h"
|
||||
|
||||
TEST(wf_string_create, Default)
|
||||
{
|
||||
char * value = wf_create_string("test %s/%d", "hello", 42);
|
||||
ASSERT_STREQ("test hello/42", value);
|
||||
free(value);
|
||||
}
|
||||
|
||||
TEST(wf_string_create, EmptyString)
|
||||
{
|
||||
char * value = wf_create_string("");
|
||||
ASSERT_STREQ("", value);
|
||||
free(value);
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
#include "webfuse/provider/impl/dirbuffer.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(DirBuffer, CreateDispose)
|
||||
{
|
||||
wfp_dirbuffer * buffer = wfp_impl_dirbuffer_create();
|
||||
wfp_impl_dirbuffer_dispose(buffer);
|
||||
}
|
||||
|
||||
TEST(DirBuffer, Add)
|
||||
{
|
||||
wfp_dirbuffer * buffer = wfp_impl_dirbuffer_create();
|
||||
wfp_impl_dirbuffer_add(buffer, "answer", 42);
|
||||
|
||||
ASSERT_EQ(1, json_array_size(buffer->entries));
|
||||
|
||||
json_t * entry = json_array_get(buffer->entries, 0);
|
||||
ASSERT_STREQ("answer", json_string_value(json_object_get(entry, "name")));
|
||||
ASSERT_EQ(42, json_integer_value(json_object_get(entry, "inode")));
|
||||
|
||||
wfp_impl_dirbuffer_dispose(buffer);
|
||||
}
|
||||
|
||||
TEST(DirBuffer, Take)
|
||||
{
|
||||
wfp_dirbuffer * buffer = wfp_impl_dirbuffer_create();
|
||||
json_t * entries = wfp_impl_dirbuffer_take(buffer);
|
||||
wfp_impl_dirbuffer_dispose(buffer);
|
||||
|
||||
ASSERT_TRUE(json_is_array(entries));
|
||||
json_decref(entries);
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
#include "webfuse/utils/adapter_client.hpp"
|
||||
#include "webfuse/utils/tempdir.hpp"
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
enum class Command
|
||||
{
|
||||
run,
|
||||
shutdown,
|
||||
connect,
|
||||
disconnect,
|
||||
authenticate,
|
||||
add_filesystem
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class AdapterClient::Private
|
||||
{
|
||||
public:
|
||||
Private(
|
||||
wf_client_callback_fn * callback,
|
||||
void * user_data,
|
||||
std::string const & url)
|
||||
: client(wf_client_create(callback, user_data))
|
||||
, url_(url)
|
||||
, command(Command::run)
|
||||
, tempdir("webfuse_adpter_client")
|
||||
{
|
||||
thread = std::thread(&Run, this);
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
ApplyCommand(Command::shutdown);
|
||||
thread.join();
|
||||
wf_client_dispose(client);
|
||||
}
|
||||
|
||||
void ApplyCommand(Command actual_command)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
command = actual_command;
|
||||
}
|
||||
|
||||
wf_client_interrupt(client);
|
||||
}
|
||||
|
||||
std::string GetDir()
|
||||
{
|
||||
return tempdir.path();
|
||||
}
|
||||
|
||||
private:
|
||||
static void Run(Private * self)
|
||||
{
|
||||
bool is_running = true;
|
||||
while (is_running)
|
||||
{
|
||||
Command actual_command;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(self->mutex);
|
||||
actual_command = self->command;
|
||||
self->command = Command::run;
|
||||
}
|
||||
|
||||
switch (actual_command)
|
||||
{
|
||||
case Command::run:
|
||||
wf_client_service(self->client);
|
||||
break;
|
||||
case Command::connect:
|
||||
wf_client_connect(self->client, self->url_.c_str());
|
||||
break;
|
||||
case Command::disconnect:
|
||||
wf_client_disconnect(self->client);
|
||||
break;
|
||||
case Command::authenticate:
|
||||
wf_client_authenticate(self->client);
|
||||
break;
|
||||
case Command::add_filesystem:
|
||||
wf_client_add_filesystem(self->client, self->tempdir.path(), "test");
|
||||
break;
|
||||
case Command::shutdown:
|
||||
// fall-through
|
||||
default:
|
||||
is_running = false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
wf_client * client;
|
||||
std::string url_;
|
||||
Command command;
|
||||
TempDir tempdir;
|
||||
std::thread thread;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
AdapterClient::AdapterClient(
|
||||
wf_client_callback_fn * callback,
|
||||
void * user_data,
|
||||
std::string const & url)
|
||||
: d(new Private(callback, user_data, url))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AdapterClient::~AdapterClient()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void AdapterClient::Connect()
|
||||
{
|
||||
d->ApplyCommand(Command::connect);
|
||||
}
|
||||
|
||||
void AdapterClient::Disconnect()
|
||||
{
|
||||
d->ApplyCommand(Command::disconnect);
|
||||
}
|
||||
|
||||
void AdapterClient::Authenticate()
|
||||
{
|
||||
d->ApplyCommand(Command::authenticate);
|
||||
}
|
||||
|
||||
void AdapterClient::AddFileSystem()
|
||||
{
|
||||
d->ApplyCommand(Command::add_filesystem);
|
||||
}
|
||||
|
||||
std::string AdapterClient::GetDir() const
|
||||
{
|
||||
return d->GetDir();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
#ifndef WF_UTILS_ADAPTER_CLIENT_HPP
|
||||
#define WF_UTILS_APAPTER_CLIENT_HPP
|
||||
|
||||
#include "webfuse/adapter/client.h"
|
||||
#include <string>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class AdapterClient
|
||||
{
|
||||
AdapterClient(AdapterClient const &) = delete;
|
||||
AdapterClient& operator=(AdapterClient const &) = delete;
|
||||
public:
|
||||
AdapterClient(
|
||||
wf_client_callback_fn * callback,
|
||||
void * user_data,
|
||||
std::string const & url);
|
||||
~AdapterClient();
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
void Authenticate();
|
||||
void AddFileSystem();
|
||||
std::string GetDir() const;
|
||||
private:
|
||||
class Private;
|
||||
Private * d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,16 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <jansson.h>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class JanssonTestEnvironment: public ::testing::Environment
|
||||
{
|
||||
public:
|
||||
void SetUp()
|
||||
{
|
||||
json_object_seed(0);
|
||||
}
|
||||
};
|
||||
#
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef WF_TEST_UTILS_WS_SERVER_HPP
|
||||
#define WF_TEST_UTILS_WS_SERVER_HPP
|
||||
|
||||
#include <jansson.h>
|
||||
#include <string>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class WsServer
|
||||
{
|
||||
WsServer(WsServer const &) = delete;
|
||||
WsServer & operator=(WsServer const &) = delete;
|
||||
public:
|
||||
WsServer(std::string const & protocol, int port = 0);
|
||||
~WsServer();
|
||||
bool IsConnected();
|
||||
std::string GetUrl() const;
|
||||
void SendMessage(json_t * message);
|
||||
json_t * ReceiveMessage();
|
||||
private:
|
||||
class Private;
|
||||
Private * d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@ -1,29 +0,0 @@
|
||||
#ifndef WF_TEST_UTILS_WS_SERVER_HPP
|
||||
#define WF_TEST_UTILS_WS_SERVER_HPP
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <jansson.h>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class WebsocketServer
|
||||
{
|
||||
WebsocketServer(WebsocketServer const &) = delete;
|
||||
WebsocketServer & operator=(WebsocketServer const &) = delete;
|
||||
public:
|
||||
explicit WebsocketServer(int port);
|
||||
WebsocketServer(int port, struct lws_protocols * additionalProtocols, std::size_t additionalProtocolsCount);
|
||||
~WebsocketServer();
|
||||
struct lws_context * getContext();
|
||||
void waitForConnection();
|
||||
void sendMessage(json_t * message);
|
||||
json_t * receiveMessage();
|
||||
private:
|
||||
class Private;
|
||||
Private * d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,331 @@
|
||||
#include "webfuse/utils/ws_server2.hpp"
|
||||
#include "webfuse/core/lws_log.h"
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <queue>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class IServer
|
||||
{
|
||||
public:
|
||||
virtual ~IServer() = default;
|
||||
virtual void OnConnected(lws * wsi) = 0;
|
||||
virtual void OnConnectionClosed(lws * wsi) = 0;
|
||||
virtual void OnMessageReceived(struct lws * wsi, char const * data, size_t length) = 0;
|
||||
virtual void OnWritable(struct lws * wsi) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static int wf_test_utils_ws_server_callback(
|
||||
struct lws * wsi,
|
||||
enum lws_callback_reasons reason,
|
||||
void * user,
|
||||
void * in,
|
||||
size_t len)
|
||||
{
|
||||
int result = 0;
|
||||
struct lws_protocols const * ws_protocol = lws_get_protocol(wsi);
|
||||
auto * server = reinterpret_cast<IServer*>(nullptr != ws_protocol ? ws_protocol->user : nullptr);
|
||||
|
||||
if (nullptr != server)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
server->OnConnected(wsi);
|
||||
break;
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
server->OnConnectionClosed(wsi);
|
||||
break;
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
{
|
||||
auto * data = reinterpret_cast<char const *>(in);
|
||||
server->OnMessageReceived(wsi, data, len);
|
||||
}
|
||||
break;
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
server->OnWritable(wsi);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class WsServer2::Private : public IServer
|
||||
{
|
||||
Private(Private const &) = delete;
|
||||
Private & operator=(Private const &) = delete;
|
||||
public:
|
||||
Private(IIvokationHandler & handler, std::string const & protocol, int port, bool enable_tls);
|
||||
~Private();
|
||||
bool IsConnected();
|
||||
std::string const & GetUrl() const;
|
||||
void OnConnected(lws * wsi) override;
|
||||
void OnConnectionClosed(lws * wsi) override;
|
||||
void OnMessageReceived(struct lws * wsi, char const * data, size_t length) override;
|
||||
void OnWritable(struct lws * wsi) override;
|
||||
|
||||
void SendMessage(char const * message);
|
||||
void SendMessage(json_t * message);
|
||||
private:
|
||||
static void Run(Private * self);
|
||||
|
||||
IIvokationHandler & handler_;
|
||||
std::string protocol_;
|
||||
bool is_connected;
|
||||
bool is_shutdown_requested;
|
||||
lws * wsi_;
|
||||
lws_context * ws_context;
|
||||
lws_protocols ws_protocols[2];
|
||||
lws_context_creation_info info;
|
||||
std::string url;
|
||||
std::thread context;
|
||||
std::mutex mutex;
|
||||
std::queue<std::string> writeQueue;
|
||||
};
|
||||
|
||||
WsServer2::WsServer2(
|
||||
IIvokationHandler& handler,
|
||||
std::string const & protocol,
|
||||
int port,
|
||||
bool enable_tls)
|
||||
: d(new WsServer2::Private(handler, protocol, port, enable_tls))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WsServer2::~WsServer2()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool WsServer2::IsConnected()
|
||||
{
|
||||
return d->IsConnected();
|
||||
}
|
||||
|
||||
std::string const & WsServer2::GetUrl() const
|
||||
{
|
||||
return d->GetUrl();
|
||||
}
|
||||
|
||||
void WsServer2::SendMessage(char const * message)
|
||||
{
|
||||
d->SendMessage(message);
|
||||
}
|
||||
|
||||
void WsServer2::SendMessage(json_t * message)
|
||||
{
|
||||
d->SendMessage(message);
|
||||
}
|
||||
|
||||
|
||||
WsServer2::Private::Private(
|
||||
IIvokationHandler & handler,
|
||||
std::string const & protocol,
|
||||
int port,
|
||||
bool enable_tls)
|
||||
: handler_(handler)
|
||||
, protocol_(protocol)
|
||||
, is_connected(false)
|
||||
, is_shutdown_requested(false)
|
||||
, wsi_(nullptr)
|
||||
{
|
||||
wf_lwslog_disable();
|
||||
IServer * server = this;
|
||||
memset(ws_protocols, 0, sizeof(struct lws_protocols) * 2 );
|
||||
|
||||
ws_protocols[0].name = protocol_.c_str();
|
||||
ws_protocols[0].callback = &wf_test_utils_ws_server_callback;
|
||||
ws_protocols[0].per_session_data_size = 0;
|
||||
ws_protocols[0].user = reinterpret_cast<void*>(server);
|
||||
|
||||
memset(&info, 0, sizeof(struct lws_context_creation_info));
|
||||
info.port = port;
|
||||
info.mounts = NULL;
|
||||
info.protocols =ws_protocols;
|
||||
info.vhost_name = "localhost";
|
||||
info.ws_ping_pong_interval = 10;
|
||||
info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
|
||||
info.options |= LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
||||
|
||||
if (enable_tls)
|
||||
{
|
||||
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
info.ssl_cert_filepath = "server-cert.pem";
|
||||
info.ssl_private_key_filepath = "server-key.pem";
|
||||
}
|
||||
|
||||
ws_context = lws_create_context(&info);
|
||||
|
||||
std::ostringstream stream;
|
||||
struct lws_vhost * vhost = lws_create_vhost(ws_context, &info);
|
||||
stream << (enable_tls ? "wss://" : "ws://")
|
||||
<< "localhost:" << lws_get_vhost_port(vhost) << "/";
|
||||
url = stream.str();
|
||||
|
||||
context = std::thread(&Run, this);
|
||||
}
|
||||
|
||||
WsServer2::Private::~Private()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
is_shutdown_requested = true;
|
||||
}
|
||||
|
||||
lws_cancel_service(ws_context);
|
||||
context.join();
|
||||
lws_context_destroy(ws_context);
|
||||
}
|
||||
|
||||
void WsServer2::Private::Run(Private * self)
|
||||
{
|
||||
bool is_running = true;
|
||||
while (is_running)
|
||||
{
|
||||
lws_service(self->ws_context, 0);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(self->mutex);
|
||||
is_running = !self->is_shutdown_requested;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WsServer2::Private::IsConnected()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
return is_connected;
|
||||
}
|
||||
|
||||
void WsServer2::Private::OnConnected(lws * wsi)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
is_connected = true;
|
||||
wsi_ = wsi;
|
||||
}
|
||||
|
||||
void WsServer2::Private::OnConnectionClosed(lws * wsi)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
if (wsi == wsi_)
|
||||
{
|
||||
is_connected = false;
|
||||
wsi_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void WsServer2::Private::OnWritable(struct lws * wsi)
|
||||
{
|
||||
bool notify = false;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
|
||||
if (!writeQueue.empty())
|
||||
{
|
||||
std::string const & message = writeQueue.front();
|
||||
|
||||
unsigned char * data = new unsigned char[LWS_PRE + message.size()];
|
||||
memcpy(&data[LWS_PRE], message.c_str(), message.size());
|
||||
lws_write(wsi, &data[LWS_PRE], message.size(), LWS_WRITE_TEXT);
|
||||
delete[] data;
|
||||
|
||||
writeQueue.pop();
|
||||
notify = !writeQueue.empty();
|
||||
}
|
||||
}
|
||||
|
||||
if (notify)
|
||||
{
|
||||
lws_callback_on_writable(wsi);
|
||||
}
|
||||
}
|
||||
|
||||
void WsServer2::Private::SendMessage(char const * message)
|
||||
{
|
||||
lws * wsi = nullptr;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
|
||||
if (nullptr != wsi_)
|
||||
{
|
||||
writeQueue.push(message);
|
||||
wsi = wsi_;
|
||||
}
|
||||
}
|
||||
|
||||
if (nullptr != wsi)
|
||||
{
|
||||
lws_callback_on_writable(wsi_);
|
||||
}
|
||||
}
|
||||
|
||||
void WsServer2::Private::SendMessage(json_t * message)
|
||||
{
|
||||
char* message_text = json_dumps(message, JSON_COMPACT);
|
||||
SendMessage(message_text);
|
||||
json_decref(message);
|
||||
free(message_text);
|
||||
}
|
||||
|
||||
void WsServer2::Private::OnMessageReceived(struct lws * wsi, char const * data, size_t length)
|
||||
{
|
||||
(void) wsi;
|
||||
|
||||
json_t * request = json_loadb(data, length, JSON_DECODE_ANY, nullptr);
|
||||
json_t * method = json_object_get(request, "method");
|
||||
json_t * params = json_object_get(request, "params");
|
||||
json_t * id = json_object_get(request, "id");
|
||||
|
||||
if (json_is_string(method) && json_is_array(params) && json_is_integer(id))
|
||||
{
|
||||
json_t * response = json_object();
|
||||
|
||||
try
|
||||
{
|
||||
std::string result_text = handler_.Invoke(json_string_value(method), params);
|
||||
json_t * result = json_loads(result_text.c_str(), JSON_DECODE_ANY, nullptr);
|
||||
json_object_set_new(response, "result", result);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
json_t * error = json_object();
|
||||
json_object_set_new(error, "code", json_integer(1));
|
||||
json_object_set_new(response, "error", error);
|
||||
}
|
||||
|
||||
json_object_set(response, "id", id);
|
||||
SendMessage(response);
|
||||
}
|
||||
|
||||
json_decref(request);
|
||||
}
|
||||
|
||||
std::string const & WsServer2::Private::GetUrl() const
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
#ifndef WF_TEST_UTILS_WS_SERVER2_HPP
|
||||
#define WF_TEST_UTILS_WS_SERVER2_HPP
|
||||
|
||||
#include <jansson.h>
|
||||
#include <string>
|
||||
|
||||
namespace webfuse_test
|
||||
{
|
||||
|
||||
class IIvokationHandler
|
||||
{
|
||||
public:
|
||||
virtual ~IIvokationHandler() = default;
|
||||
virtual std::string Invoke(char const * method, json_t * params) = 0;
|
||||
};
|
||||
|
||||
class WsServer2
|
||||
{
|
||||
WsServer2(WsServer2 const &) = delete;
|
||||
WsServer2 & operator=(WsServer2 const & ) = delete;
|
||||
public:
|
||||
WsServer2(
|
||||
IIvokationHandler& handler,
|
||||
std::string const & protocol,
|
||||
int port = 0,
|
||||
bool enable_tls = false);
|
||||
virtual ~WsServer2();
|
||||
bool IsConnected();
|
||||
std::string const & GetUrl() const;
|
||||
void SendMessage(char const * message);
|
||||
void SendMessage(json_t * message);
|
||||
private:
|
||||
class Private;
|
||||
Private * d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in new issue