[Bug 25236] TpBaseClient - an abstract class to implement clients

bugzilla-daemon at freedesktop.org bugzilla-daemon at freedesktop.org
Wed Apr 28 11:23:58 CEST 2010


https://bugs.freedesktop.org/show_bug.cgi?id=25236

--- Comment #25 from Guillaume Desmottes <guillaume.desmottes at collabora.co.uk> 2010-04-28 02:23:57 PDT ---
(In reply to comment #24)
> This looks as though it's on track. I think it's worth merging as soon as it
> can support observers cleanly.

Agreed.

> > tp_observe_channels_context_get_recovering
> 
> is_recovering(), perhaps?

renamed.

> > + * TpBaseClientClassObserveChannelsImpl:
> ...
> > + * @dispatch_operation: a #TpChannelDispatchOperation or %NULL; the
> > + * dispatch_operation is not garanteed to be prepared
> 
> "not guaranteed to" (same misspelling in @requests).
> 
> Annotations needed (where "..." means the docs you already have):
> 
> @channels: (element-type Tp.Channel): ...
> @requests: (element-type Tp.ChannelRequest): ...
> @dispatch_operation: (allow-none): ...
> 
> I'd be inclined to call the first parameter "client" or "observer" rather than
> "self" here, but that's a matter of taste.

Fixed.

> > + * tp_base_client_add_observer_filter:
> ...
> > + * @filter: (transfer none) (element-type utf8 GObject.Value):
> 
> This seems to contain non-breaking spaces in the annotations, for some reason?
> Is that what you intended?

Humm weird.

> (To see non-breaking spaces in vim, ":set list listchars=tab:»→,trail:…,nbsp:‽"
> or some such.)
> 
> It would be nice to assert (with g_return_if_fail) that there is an
> observe_channels implementation.

Done in tp_base_client_take_observer_filter as _add_ uses this one.

> You should explicitly say that the client mustn't have been registered, and I
> don't think this is really enough documentation (it should be possible to guess
> more or less what's going on without referring to telepathy-spec). How about
> this?
> 
> /**
>  * tp_base_client_add_observer_filter:
>  * @self: a #TpBaseClient
>  * @filter: (transfer none) (element-type utf8 GObject.Value):
>  * a %TP_HASH_TYPE_CHANNEL_CLASS
>  *
>  * Register a new channel class as Observer.ObserverChannelFilter.
>  * The @observe_channels virtual method set up using
>  * tp_base_client_implement_observe_channels() will be called whenever
>  * a new channel's properties match the ones in @filter.
>  *
>  * This method may only be called before tp_base_client_register() is
>  * called, and may only be called on objects that implement
>  * @observe_channels.
>  *
>  * Since: 0.11.UNRELEASED
>  */

I replaced doc by this.

> > + * tp_base_client_take_observer_filter:
> ...
> > + * @filter: (transfer container) (element-type utf8 GObject.Value):
> 
> This contains non-breaking spaces, and parameters that are stolen (like this
> one) should be (transfer full).

fixed.

> Also, the entire function should really be (skip) (there's no point in it for
> language bindings), but that breaks gtk-doc <= 1.14, so we can't do that until
> 1.15 comes out (or at least until we get a gtk-doc with patches from upstream
> git into major distributions).

I added a FIXME.

> > + * Define the value of the Observer.Recover property.
> 
> That's not really enough. How about this?
> 
>  * Set whether the channel dispatcher should attempt to recover
>  * this Observer if it crashes. (This is implemented by setting
>  * the value of its Recover D-Bus property.)
>  *
>  * Normally, Observers are only notified when new channels
>  * appear. If an Observer is set to recover, when it registers with
>  * tp_base_client_register(), it will also be told about any channels
>  * that already existed before it started.
>  *
>  * For Observers that are activatable as a D-Bus service, if the
>  * Observer exits or crashes while there are any channels that match
>  * its filter, it will automatically be restarted by service-activation.
>  * 
>  * This method may only be called before tp_base_client_register() is
>  * called, and may only be called on objects that implement
>  * @observe_channels.

Much better; I changed.
I also added a g_return_if_fail checking that observe_channels_impl has been
defined.

> > + * tp_base_client_register:
> ...
> > + * Returns: %TRUE if the client has been registered.
> > + * Methods that set the filters and other immutable state cannot be called
> > + * after this one.
> 
> I'd prefer an example: "... state, such as
> tp_base_client_add_observer_filter(), cannot ..."

done.

> > + * tp_base_client_register:
> ...
> > + * Returns: %TRUE if the client has been registered.
> 
> I'd prefer this worded as "if the client was registered successfully" - your
> wording makes it sound as if, if you call this method twice, the second call
> will also return TRUE.

changed.

> > +      g_warning ("Failed to register bus name %s\n", string->str);
> 
> No thanks. If registering the bus name failed, just raise the GError - it's up
> to the caller what they do about it.

replaced by a DEBUG().

> > +  path = g_strdup_printf ("/%s", g_strdelimit (string->str, ".", '/'));
> 
> g_strdelimit edits the string in-place. It's OK here because you don't re-use
> it, but I'd prefer it to be obviously correct at a glance:
> 
>   path = g_strdup_printf ("/%s", string->str);
>   g_strdelimit (path, ".", '/');

changed.

> > +      case PROP_DBUS_DAEMON:
> > +        g_value_set_object (value, self->priv->dbus);
> > +        break;
> > +      case PROP_NAME:
> 
> I vaguely prefer to have a blank line between cases in a switch, although it
> doesn't really matter when the implementations are so small.

done.

> > +      case PROP_DBUS_DAEMON:
> > +        self->priv->dbus = g_value_dup_object (value);
> 
> I'd prefer this case to start with:
> 
>   g_assert (self->priv->dbus == NULL);    /* construct-only */
> 
> to make it obvious why it isn't a potential leak. Similar for PROP_NAME.

done.

> > +#if 0
> > +    case DP_APPROVER_CHANNEL_FILTER:
> 
> If you're going to #if these, you should do the same to their
> TpDBusPropertiesMixinPropImpl and TpDBusPropertiesMixinIfaceImpl structs.
> Otherwise, you'll be remotely-assertable (by retrieving the offending
> properties).

As said in an earlier comment, ,I'll remove the code once the branch is ready
to be merged (to be able to revert the commit without conflict). I #if 0 them
for now.


> I wonder whether there should be a property and/or accessor for the client's
> bus name and object path? If so, they should be set during the constructor
> based on name and uniquify, and then used as-is at register time (i.e. move
> some code from register to constructor).

Sounds like a good idea. I'll add that.

> > +  TpBaseClientClassPrivate *cls_pv = G_TYPE_CLASS_GET_PRIVATE (
> > +      TP_BASE_CLIENT_GET_CLASS (self), TP_TYPE_BASE_CLIENT,
> > +      TpBaseClientClassPrivate);
> 
> Please avoid nonstandard abbreviations like "pv" where feasible (private things
> are called private or priv).
> 
> Can we cache this in FooClass.priv in class_init, like the way we cache object
> private structures in Foo.priv in the instance init? Then you could use
> cls->priv->observe_channels_impl().

Very good idea! Done.

> > +          "Implementation of ObserveChannels of %s didn't call "
> 
> Nitpicking: "Implementation of ObserveChannels in %s" would avoid the repeated
> "of" while remaining grammatically correct.

changed.

> > + * tp_observe_channels_context_delay:
> > + * @self: a #TpObserveChannelsContext
> > + *
> > + * Called by #TpBaseClientClassObserveChannelsImpl to indicate that it
> > + * implements the method in an async way. It has to ref the
> > + * #TpObserveChannelsContext before calling this function and is responsible
> > + * to call tp_observe_channels_context_accept once the call is done.
> 
> I'd prefer:
> 
> ... an async way. The caller must take a reference to the
> #TpObserveChannelsContext before calling this function, and is responsible for
> calling either tp_observe_channels_context_accept() or
> tp_observe_channels_context_fail() later.

changed.

> If disposed in state NONE or DELAYED, the context should probably g_critical(),
> and raise NotImplemented on D-Bus.

done.

> > + * If the "recovering" key in present in the Observer_Info hash table
> > + * associated with this context, its value; %FALSE if the key is not present.
> > + *
> > + * Returns: value
> 
> That describes the mechanism, but not the purpose. I'd prefer:
> 
>  * If this call to ObserveChannels is for channels that already
>  * existed before this observer started (because the observer used
>  * tp_base_client_set_observer_recover()), return %TRUE.
>  *
>  * In most cases, the result is %FALSE.
>  *
>  * Returns: %TRUE for pre-existing channels, %FALSE for new channels

changed.

> Perhaps ..._is_recovering() would be a better name? I don't know.
> 
> > +_tp_observe_channels_context_prepare_async (TpObserveChannelsContext *self,
> ...
> > +  g_return_if_fail (self->priv->result == NULL);
> 
> This deserves a comment, something like:
> 
>   /* This is only used once, by TpBaseClient, so for simplicity, we only
>    * allow one asynchronous preparation */

added.

> 
> Still to review
> ===============
> 
> I haven't reviewed the test or the SimpleClient yet.

I guess you mean SimpleObserver :)
I think that's ok, we can merge the Observer bits of BaseClient first. At least
we know that it allows to easily write SimpleObserver.

> Future work
> ===========
> 
> I think we should get Observers working nicely (including an example and
> perhaps TpSimpleObserver) before we move on to the other classes. After that,
> I'd recommend Handler next - Approver is harder, because it needs more API on
> ChannelDispatchOperation.
> 
> > +/**
> > + * SECTION:base-client
> > + * @title: TpBaseClient
> > + * @short_description: base class for Telepathy clients on D-Bus
> > + *
> > + * This base class makes it easier to write #TpSvcClient
> > + * implementations. Subclasses should usually pass the filters they
> > + * want and override the D-Bus methods they implement.
> > + */
> 
> Eventually, I'd like a code example or a reference to TpSimpleObserver (etc.)
> here.
> 
> It'd be nice to have an observer in examples/client/ that just does a
> g_message() whenever a StreamedMedia call starts or finishes, or something
> similarly easy.

Would you implement it using TpBaseClient or TpSimpleObserver?

-- 
Configure bugmail: https://bugs.freedesktop.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.


More information about the telepathy-bugs mailing list