degesch: remove cyclic dependency
Between users and channels.
This commit is contained in:
parent
7c2085d528
commit
6ef472beb2
74
degesch.c
74
degesch.c
|
@ -101,12 +101,6 @@ static struct config_item g_config_table[] =
|
||||||
return false; \
|
return false; \
|
||||||
BLOCK_END
|
BLOCK_END
|
||||||
|
|
||||||
struct user;
|
|
||||||
static void user_unref (struct user *self);
|
|
||||||
|
|
||||||
struct channel;
|
|
||||||
static void channel_unref (struct channel *self);
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
// We need a few reference countable objects with support
|
// We need a few reference countable objects with support
|
||||||
|
@ -144,8 +138,6 @@ struct user_channel
|
||||||
{
|
{
|
||||||
LIST_HEADER (struct user_channel)
|
LIST_HEADER (struct user_channel)
|
||||||
|
|
||||||
// FIXME: this should be a weak reference to destroy a cycle
|
|
||||||
|
|
||||||
struct channel *channel; ///< Reference to channel
|
struct channel *channel; ///< Reference to channel
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -159,7 +151,8 @@ user_channel_new (void)
|
||||||
static void
|
static void
|
||||||
user_channel_destroy (struct user_channel *self)
|
user_channel_destroy (struct user_channel *self)
|
||||||
{
|
{
|
||||||
channel_unref (self->channel);
|
// The "channel" reference is weak and this object should get
|
||||||
|
// destroyed whenever the user stops being in the channel.
|
||||||
free (self);
|
free (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,8 +220,10 @@ channel_user_destroy (struct channel_user *self)
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
// We keep references to channels in their users and buffers,
|
// We keep references to channels in their buffers,
|
||||||
// and weak references in the name lookup table.
|
// and weak references in their users and the name lookup table.
|
||||||
|
|
||||||
|
// XXX: this doesn't really have to be reference countable
|
||||||
|
|
||||||
struct channel
|
struct channel
|
||||||
{
|
{
|
||||||
|
@ -259,8 +254,8 @@ channel_destroy (struct channel *self)
|
||||||
free (self->name);
|
free (self->name);
|
||||||
free (self->mode);
|
free (self->mode);
|
||||||
free (self->topic);
|
free (self->topic);
|
||||||
LIST_FOR_EACH (struct channel_user, iter, self->users)
|
// Owner has to make sure we have no users by now
|
||||||
channel_user_destroy (iter);
|
hard_assert (!self->users);
|
||||||
str_vector_free (&self->names_buf);
|
str_vector_free (&self->names_buf);
|
||||||
free (self);
|
free (self);
|
||||||
}
|
}
|
||||||
|
@ -1327,11 +1322,31 @@ irc_get_or_make_user_buffer (struct app_context *ctx, const char *nickname)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
irc_channel_unlink_user
|
||||||
|
(struct channel *channel, struct channel_user *channel_user)
|
||||||
|
{
|
||||||
|
// First destroy the user's weak references to the channel
|
||||||
|
struct user *user = channel_user->user;
|
||||||
|
LIST_FOR_EACH (struct user_channel, iter, user->channels)
|
||||||
|
if (iter->channel == channel)
|
||||||
|
{
|
||||||
|
LIST_UNLINK (user->channels, iter);
|
||||||
|
user_channel_destroy (iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then just unlink the user from the channel
|
||||||
|
LIST_UNLINK (channel->users, channel_user);
|
||||||
|
channel_user_destroy (channel_user);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
irc_channel_on_destroy (void *object, void *user_data)
|
irc_channel_on_destroy (void *object, void *user_data)
|
||||||
{
|
{
|
||||||
struct channel *channel = object;
|
struct channel *channel = object;
|
||||||
struct app_context *ctx = user_data;
|
struct app_context *ctx = user_data;
|
||||||
|
LIST_FOR_EACH (struct channel_user, iter, channel->users)
|
||||||
|
irc_channel_unlink_user (channel, iter);
|
||||||
str_map_set (&ctx->irc_channels, channel->name, NULL);
|
str_map_set (&ctx->irc_channels, channel->name, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1351,21 +1366,11 @@ irc_make_channel (struct app_context *ctx, char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
irc_unlink_user_from_channel (struct user *user, struct channel *channel)
|
irc_remove_user_from_channel (struct user *user, struct channel *channel)
|
||||||
{
|
{
|
||||||
// The order is important here as the channel can hold the last reference
|
|
||||||
LIST_FOR_EACH (struct user_channel, iter, user->channels)
|
|
||||||
if (iter->channel == channel)
|
|
||||||
{
|
|
||||||
LIST_UNLINK (user->channels, iter);
|
|
||||||
user_channel_destroy (iter);
|
|
||||||
}
|
|
||||||
LIST_FOR_EACH (struct channel_user, iter, channel->users)
|
LIST_FOR_EACH (struct channel_user, iter, channel->users)
|
||||||
if (iter->user == user)
|
if (iter->user == user)
|
||||||
{
|
irc_channel_unlink_user (channel, iter);
|
||||||
LIST_UNLINK (channel->users, iter);
|
|
||||||
channel_user_destroy (iter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Supporting code ---------------------------------------------------------
|
// --- Supporting code ---------------------------------------------------------
|
||||||
|
@ -1945,7 +1950,7 @@ irc_handle_join (struct app_context *ctx, const struct irc_message *msg)
|
||||||
|
|
||||||
// Link the user with the channel
|
// Link the user with the channel
|
||||||
struct user_channel *user_channel = user_channel_new ();
|
struct user_channel *user_channel = user_channel_new ();
|
||||||
user_channel->channel = channel_ref (channel);
|
user_channel->channel = channel;
|
||||||
LIST_PREPEND (user->channels, user_channel);
|
LIST_PREPEND (user->channels, user_channel);
|
||||||
|
|
||||||
struct channel_user *channel_user = channel_user_new ();
|
struct channel_user *channel_user = channel_user_new ();
|
||||||
|
@ -1985,7 +1990,7 @@ irc_handle_kick (struct app_context *ctx, const struct irc_message *msg)
|
||||||
|
|
||||||
// It would be is weird for this to be false
|
// It would be is weird for this to be false
|
||||||
if (user && channel)
|
if (user && channel)
|
||||||
irc_unlink_user_from_channel (user, channel);
|
irc_remove_user_from_channel (user, channel);
|
||||||
|
|
||||||
if (buffer)
|
if (buffer)
|
||||||
{
|
{
|
||||||
|
@ -2106,7 +2111,7 @@ irc_handle_part (struct app_context *ctx, const struct irc_message *msg)
|
||||||
|
|
||||||
// It would be is weird for this to be false
|
// It would be is weird for this to be false
|
||||||
if (user && channel)
|
if (user && channel)
|
||||||
irc_unlink_user_from_channel (user, channel);
|
irc_remove_user_from_channel (user, channel);
|
||||||
|
|
||||||
if (buffer)
|
if (buffer)
|
||||||
{
|
{
|
||||||
|
@ -2202,17 +2207,8 @@ irc_handle_quit (struct app_context *ctx, const struct irc_message *msg)
|
||||||
buffer_send (ctx, buffer, BUFFER_LINE_QUIT, 0,
|
buffer_send (ctx, buffer, BUFFER_LINE_QUIT, 0,
|
||||||
msg->prefix, message, "");
|
msg->prefix, message, "");
|
||||||
|
|
||||||
// Unlink the user from the channel
|
// This destroys "iter" which doesn't matter to us
|
||||||
struct channel *channel = iter->channel;
|
irc_remove_user_from_channel (user, iter->channel);
|
||||||
LIST_FOR_EACH (struct channel_user, iter, channel->users)
|
|
||||||
if (iter->user == user)
|
|
||||||
{
|
|
||||||
LIST_UNLINK (channel->users, iter);
|
|
||||||
channel_user_destroy (iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
LIST_UNLINK (user->channels, iter);
|
|
||||||
user_channel_destroy (iter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue