degesch: replace degesch.connect with async.dial
Halfway there, looks much saner.
This commit is contained in:
parent
52d1ded7df
commit
e2bb051bd3
275
degesch.c
275
degesch.c
|
@ -9580,149 +9580,6 @@ lua_plugin_push_connection (struct lua_plugin *plugin, int socket_fd)
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
/// Identifier for the Lua metatable
|
|
||||||
#define XLUA_CONNECTOR_METATABLE "connector"
|
|
||||||
|
|
||||||
struct lua_connector
|
|
||||||
{
|
|
||||||
struct lua_plugin *plugin; ///< The plugin we belong to
|
|
||||||
struct connector connector; ///< Connector object
|
|
||||||
bool active; ///< Whether the connector is alive
|
|
||||||
|
|
||||||
int ref_on_success; ///< Reference to "on_success" callback
|
|
||||||
int ref_on_error; ///< Reference to "on_error" callback
|
|
||||||
|
|
||||||
char *last_error; ///< Connecting error, if any
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
lua_connector_discard (struct lua_connector *self)
|
|
||||||
{
|
|
||||||
if (self->active)
|
|
||||||
{
|
|
||||||
connector_free (&self->connector);
|
|
||||||
self->active = false;
|
|
||||||
|
|
||||||
luaL_unref (self->plugin->L, LUA_REGISTRYINDEX, self->ref_on_success);
|
|
||||||
luaL_unref (self->plugin->L, LUA_REGISTRYINDEX, self->ref_on_error);
|
|
||||||
self->ref_on_success = LUA_REFNIL;
|
|
||||||
self->ref_on_error = LUA_REFNIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free (self->last_error);
|
|
||||||
self->last_error = NULL;
|
|
||||||
|
|
||||||
lua_cache_invalidate (self->plugin->L, self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lua_connector_abort (lua_State *L)
|
|
||||||
{
|
|
||||||
lua_connector_discard (luaL_checkudata (L, 1, XLUA_CONNECTOR_METATABLE));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static luaL_Reg lua_connector_table[] =
|
|
||||||
{
|
|
||||||
{ "abort", lua_connector_abort },
|
|
||||||
{ "__gc", lua_connector_abort },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
|
|
||||||
static void
|
|
||||||
lua_connector_on_connected (void *user_data, int socket, const char *hostname)
|
|
||||||
{
|
|
||||||
struct lua_connector *self = user_data;
|
|
||||||
|
|
||||||
// TODO: use the hostname for SNI once TLS is implemented
|
|
||||||
|
|
||||||
if (self->ref_on_success != LUA_REFNIL)
|
|
||||||
{
|
|
||||||
lua_State *L = self->plugin->L;
|
|
||||||
lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_on_success);
|
|
||||||
struct lua_connection *connection =
|
|
||||||
lua_plugin_push_connection (self->plugin, socket); // 1: connection
|
|
||||||
lua_pushstring (L, hostname); // 2: hostname
|
|
||||||
|
|
||||||
struct error *e = NULL;
|
|
||||||
if (!lua_plugin_call (self->plugin, 2, 0, &e))
|
|
||||||
{
|
|
||||||
lua_plugin_log_error (self->plugin, "connector on_success", e);
|
|
||||||
// The connection has placed itself in the cache
|
|
||||||
lua_connection_discard (connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_connector_discard (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
lua_connector_on_failure (void *user_data)
|
|
||||||
{
|
|
||||||
struct lua_connector *self = user_data;
|
|
||||||
if (self->ref_on_error != LUA_REFNIL)
|
|
||||||
{
|
|
||||||
lua_State *L = self->plugin->L;
|
|
||||||
lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_on_error);
|
|
||||||
lua_pushstring (L, self->last_error); // 1: error string
|
|
||||||
|
|
||||||
struct error *e = NULL;
|
|
||||||
if (!lua_plugin_call (self->plugin, 1, 0, &e))
|
|
||||||
lua_plugin_log_error (self->plugin, "connector on_error", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_connector_discard (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
lua_connector_on_error (void *user_data, const char *error)
|
|
||||||
{
|
|
||||||
struct lua_connector *self = user_data;
|
|
||||||
free (self->last_error);
|
|
||||||
self->last_error = xstrdup (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lua_plugin_connect (lua_State *L)
|
|
||||||
{
|
|
||||||
struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
|
|
||||||
const char *host = luaL_checkstring (L, 1);
|
|
||||||
const char *service = luaL_checkstring (L, 2);
|
|
||||||
luaL_checktype (L, 3, LUA_TTABLE);
|
|
||||||
|
|
||||||
struct lua_connector *self = lua_newuserdata (L, sizeof *self);
|
|
||||||
luaL_setmetatable (L, XLUA_CONNECTOR_METATABLE);
|
|
||||||
memset (self, 0, sizeof *self);
|
|
||||||
|
|
||||||
self->plugin = plugin;
|
|
||||||
self->ref_on_success = LUA_REFNIL;
|
|
||||||
self->ref_on_error = LUA_REFNIL;
|
|
||||||
|
|
||||||
(void) lua_plugin_check_field (L, 3, "on_success", LUA_TFUNCTION, true);
|
|
||||||
self->ref_on_success = luaL_ref (L, LUA_REGISTRYINDEX);
|
|
||||||
(void) lua_plugin_check_field (L, 3, "on_error", LUA_TFUNCTION, true);
|
|
||||||
self->ref_on_error = luaL_ref (L, LUA_REGISTRYINDEX);
|
|
||||||
|
|
||||||
struct app_context *ctx = plugin->ctx;
|
|
||||||
struct connector *connector = &self->connector;
|
|
||||||
connector_init (connector, &ctx->poller);
|
|
||||||
connector_add_target (connector, host, service);
|
|
||||||
|
|
||||||
connector->on_connected = lua_connector_on_connected;
|
|
||||||
connector->on_connecting = NULL;
|
|
||||||
connector->on_error = lua_connector_on_error;
|
|
||||||
connector->on_failure = lua_connector_on_failure;
|
|
||||||
connector->user_data = self;
|
|
||||||
|
|
||||||
self->active = true;
|
|
||||||
lua_cache_store (L, self, -1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
|
|
||||||
// The script can create as many wait channels as wanted. They only actually
|
// The script can create as many wait channels as wanted. They only actually
|
||||||
// do anything once they get yielded to the main lua_resume() call.
|
// do anything once they get yielded to the main lua_resume() call.
|
||||||
|
|
||||||
|
@ -9978,6 +9835,127 @@ lua_plugin_push_wait_timer (struct lua_plugin *plugin, lua_State *L,
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
struct lua_wait_dial
|
||||||
|
{
|
||||||
|
struct lua_wait_channel super; ///< The structure we're deriving
|
||||||
|
|
||||||
|
struct lua_plugin *plugin; ///< The plugin we belong to
|
||||||
|
struct connector connector; ///< Connector object
|
||||||
|
bool active; ///< Whether the connector is alive
|
||||||
|
|
||||||
|
struct lua_connection *connection; ///< Established connection
|
||||||
|
char *hostname; ///< Target hostname
|
||||||
|
char *last_error; ///< Connecting error, if any
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
lua_wait_dial_check (struct lua_wait_channel *wchannel)
|
||||||
|
{
|
||||||
|
struct lua_wait_dial *self =
|
||||||
|
CONTAINER_OF (wchannel, struct lua_wait_dial, super);
|
||||||
|
|
||||||
|
lua_State *L = self->super.task->thread;
|
||||||
|
if (self->connection)
|
||||||
|
{
|
||||||
|
// FIXME: this way the connection can leak, it shouldn't stay in cache
|
||||||
|
// automatically all the time but clean itself up on GC
|
||||||
|
lua_cache_get (L, self->connection);
|
||||||
|
lua_pushstring (L, self->hostname);
|
||||||
|
self->connection = NULL;
|
||||||
|
}
|
||||||
|
else if (self->last_error)
|
||||||
|
{
|
||||||
|
lua_pushnil (L);
|
||||||
|
lua_pushnil (L);
|
||||||
|
lua_pushstring (L, self->last_error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_wait_dial_cancel (struct lua_wait_dial *self)
|
||||||
|
{
|
||||||
|
if (self->active)
|
||||||
|
{
|
||||||
|
connector_free (&self->connector);
|
||||||
|
self->active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_wait_dial_cleanup (struct lua_wait_channel *wchannel)
|
||||||
|
{
|
||||||
|
struct lua_wait_dial *self =
|
||||||
|
CONTAINER_OF (wchannel, struct lua_wait_dial, super);
|
||||||
|
|
||||||
|
lua_wait_dial_cancel (self);
|
||||||
|
if (self->connection)
|
||||||
|
lua_connection_discard (self->connection);
|
||||||
|
|
||||||
|
free (self->hostname);
|
||||||
|
free (self->last_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_wait_dial_on_connected (void *user_data, int socket, const char *hostname)
|
||||||
|
{
|
||||||
|
struct lua_wait_dial *self = user_data;
|
||||||
|
if (self->super.task)
|
||||||
|
lua_task_wakeup (self->super.task);
|
||||||
|
|
||||||
|
self->connection = lua_plugin_push_connection (self->plugin, socket);
|
||||||
|
// TODO: use the hostname for SNI once TLS is implemented
|
||||||
|
self->hostname = xstrdup (hostname);
|
||||||
|
lua_wait_dial_cancel (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_wait_dial_on_failure (void *user_data)
|
||||||
|
{
|
||||||
|
struct lua_wait_dial *self = user_data;
|
||||||
|
if (self->super.task)
|
||||||
|
lua_task_wakeup (self->super.task);
|
||||||
|
lua_wait_dial_cancel (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_wait_dial_on_error (void *user_data, const char *error)
|
||||||
|
{
|
||||||
|
struct lua_wait_dial *self = user_data;
|
||||||
|
free (self->last_error);
|
||||||
|
self->last_error = xstrdup (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lua_plugin_push_wait_dial (struct lua_plugin *plugin, lua_State *L,
|
||||||
|
const char *host, const char *service)
|
||||||
|
{
|
||||||
|
struct lua_wait_dial *self = lua_newuserdata (L, sizeof *self);
|
||||||
|
luaL_setmetatable (L, XLUA_WCHANNEL_METATABLE);
|
||||||
|
memset (self, 0, sizeof *self);
|
||||||
|
|
||||||
|
self->super.check = lua_wait_dial_check;
|
||||||
|
self->super.cleanup = lua_wait_dial_cleanup;
|
||||||
|
|
||||||
|
struct connector *connector = &self->connector;
|
||||||
|
connector_init (connector, &plugin->ctx->poller);
|
||||||
|
connector_add_target (connector, host, service);
|
||||||
|
|
||||||
|
connector->on_connected = lua_wait_dial_on_connected;
|
||||||
|
connector->on_connecting = NULL;
|
||||||
|
connector->on_error = lua_wait_dial_on_error;
|
||||||
|
connector->on_failure = lua_wait_dial_on_failure;
|
||||||
|
connector->user_data = self;
|
||||||
|
|
||||||
|
self->plugin = plugin;
|
||||||
|
self->active = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lua_async_go (lua_State *L)
|
lua_async_go (lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -10017,10 +9995,19 @@ lua_async_timer_ms (lua_State *L)
|
||||||
return lua_plugin_push_wait_timer (plugin, L, timeout);
|
return lua_plugin_push_wait_timer (plugin, L, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lua_async_dial (lua_State *L)
|
||||||
|
{
|
||||||
|
struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
|
||||||
|
return lua_plugin_push_wait_dial (plugin, L,
|
||||||
|
luaL_checkstring (L, 1), luaL_checkstring (L, 2));
|
||||||
|
}
|
||||||
|
|
||||||
static luaL_Reg lua_async_library[] =
|
static luaL_Reg lua_async_library[] =
|
||||||
{
|
{
|
||||||
{ "go", lua_async_go },
|
{ "go", lua_async_go },
|
||||||
{ "timer_ms", lua_async_timer_ms },
|
{ "timer_ms", lua_async_timer_ms },
|
||||||
|
{ "dial", lua_async_dial },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10050,7 +10037,6 @@ static luaL_Reg lua_plugin_library[] =
|
||||||
{ "hook_prompt", lua_plugin_hook_prompt },
|
{ "hook_prompt", lua_plugin_hook_prompt },
|
||||||
{ "hook_completion", lua_plugin_hook_completion },
|
{ "hook_completion", lua_plugin_hook_completion },
|
||||||
{ "setup_config", lua_plugin_setup_config },
|
{ "setup_config", lua_plugin_setup_config },
|
||||||
{ "connect", lua_plugin_connect },
|
|
||||||
|
|
||||||
// And these are methods:
|
// And these are methods:
|
||||||
|
|
||||||
|
@ -10332,7 +10318,6 @@ lua_plugin_load (struct app_context *ctx, const char *filename,
|
||||||
lua_plugin_reg_weak (L, &lua_server_info, lua_server_table);
|
lua_plugin_reg_weak (L, &lua_server_info, lua_server_table);
|
||||||
lua_plugin_reg_meta (L, XLUA_SCHEMA_METATABLE, lua_schema_table);
|
lua_plugin_reg_meta (L, XLUA_SCHEMA_METATABLE, lua_schema_table);
|
||||||
lua_plugin_reg_meta (L, XLUA_CONNECTION_METATABLE, lua_connection_table);
|
lua_plugin_reg_meta (L, XLUA_CONNECTION_METATABLE, lua_connection_table);
|
||||||
lua_plugin_reg_meta (L, XLUA_CONNECTOR_METATABLE, lua_connector_table);
|
|
||||||
|
|
||||||
lua_plugin_reg_meta (L, XLUA_TASK_METATABLE, lua_task_table);
|
lua_plugin_reg_meta (L, XLUA_TASK_METATABLE, lua_task_table);
|
||||||
lua_plugin_reg_meta (L, XLUA_WCHANNEL_METATABLE, lua_wchannel_table);
|
lua_plugin_reg_meta (L, XLUA_WCHANNEL_METATABLE, lua_wchannel_table);
|
||||||
|
|
|
@ -118,24 +118,23 @@ end
|
||||||
local running
|
local running
|
||||||
|
|
||||||
-- Initiate a connection to last.fm servers
|
-- Initiate a connection to last.fm servers
|
||||||
|
async, await = degesch.async, coroutine.yield
|
||||||
local make_request = function (buffer, action)
|
local make_request = function (buffer, action)
|
||||||
if not user or not api_key then
|
if not user or not api_key then
|
||||||
report_error (buffer, "configuration is incomplete")
|
report_error (buffer, "configuration is incomplete")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if running then running.abort () end
|
if running then running:cancel () end
|
||||||
|
running = async.go (function ()
|
||||||
running = degesch.connect ("ws.audioscrobbler.com", 80, {
|
local c, host, e = await (async.dial ("ws.audioscrobbler.com", 80))
|
||||||
on_success = function (c, host)
|
if e then
|
||||||
on_connected (buffer, c, host, action)
|
|
||||||
running = nil
|
|
||||||
end,
|
|
||||||
on_error = function (e)
|
|
||||||
report_error (buffer, e)
|
report_error (buffer, e)
|
||||||
running = nil
|
else
|
||||||
|
on_connected (buffer, c, host, action)
|
||||||
end
|
end
|
||||||
})
|
running = nil
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
Loading…
Reference in New Issue