summaryrefslogtreecommitdiff
path: root/doc/api.pod
blob: 71f6b734de95b8c1e4d0bc41706d5114d90a3e40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
=head1 Introduction

This document describes the D-Bus API of the Globster daemon. Familiarity with
D-Bus is assumed; There's a good
L<overview available|http://packages.python.org/txdbus/dbus_overview.html> if
you're new to D-Bus, and there's also the (surprisingly readable)
L<official specification|http://dbus.freedesktop.org/doc/dbus-specification.html>.

Globster is still in an early stage of its life, so the objects and interfaces
described here are subject to change. I do have every intention on stabilizing
the interfaces in the future. As Globster gets more mature, I intent to add new
features and improvements in an incremental and backwards compatible manner.

=head2 Overview

As ugly as they are, Globster follows the D-Bus naming conventions. All object
names are prefixed with C</net/blicky/Globster> and all interface names with
C<net.blicky.Globster>. The Globster daemon registers itself to D-Bus with the
I<well-known> bus name C<net.blicky.Globster>.

The hierarchy of all exported objects is as follows:

  net
  └─ blicky
     └─ Globster
        ├─ HubManager
        └─ Hub
           ├─ 1
           ├─ 2
           └─ $n

And here's a listing of all exported objects with the names of the interfaces
they implement.

  /net/blicky/Globster
    net.blicky.Globster

  /net/blicky/Globster/HubManager
    net.blicky.Globster.HubManager

  /net/blicky/Globster/Hub/$n
    net.blicky.Globster.Hub
    net.blicky.Globster.HubConnection
    net.blicky.Globster.HubUsers
    net.blicky.Globster.HubChat

Each C</net/blicky/Globster/Hub/$n> object represents a connection to a hub.
These objects are dynamically created and destroyed through the
C</net/blicky/Globster/HubManager> object.


=head1 Interfaces

The interfaces are described in detail below. Note that this entire document
actually serves two different purposes. The first obviously being
documentation, but this document also happens to function as the input for a
code generator within Globster. The interface names and method, signal and
property signatures are automatically extracted from this document and used to
generate code to ease the implementation of these services. As such, the
interface descriptions follow a common format.

Every interface heading has the full name of the interface followed by a short
name in parenthesis. E.g. C<net.blicky.Globster (app)>. The short name is used
internally by Globster, feel free to ignore it. Methods, signals and properties
are defined in code blocks and use the following notation.

  method <name>(<args>)
  method <name>(<args>) -> (<args>)
  signal <name>(<args>)
  property <type> <name> <access>

Where C<< <args> >> is a possibly empty list of arguments. Each argument
follows C-style notation, i.e. C<< <type> <name> >>. Multiple arguments are
separated by a comma. As part of D-Bus, a method can have multiple return
values (I<out arguments>). If a method doesn't have any out arguments, the
second argument list is omitted.

A C<< <type> >> refers to a I<single complete type> in the short D-Bus
notation. E.g. C<u> is an unsigned 32-bit integer and C<ay> is an array of
bytes. Refer to the
L<D-Bus specification|http://packages.python.org/txdbus/dbus_overview.html>
for the complete list. The C<< <access> >> of a property is either C<r>, C<w>
or C<rw> for read-only, write-only or read-write properties, respectively.

Unless otherwise noted, changes to a property always emit a
C<org.freedesktop.DBus.Properties.PropertiesChanged> signal with the new value.


=head2 net.blicky.Globster (app)

This interface is used for application-global stuff. Accessed through the
C</net/blicky/Globster> object.

  method Shutdown()

Calling this method will cause the Globster daemon to shut itself down.

  property s VersionString r
  property u VersionNumber r

These properties provide the version of the Globster daemon. The VersionString
follows the following format (stuff between square brackets is optional):

  <major>[.<minor>[.<patch>]][-<commit>-g<hash>[-d]]

The VersionNumber provides a numeric version of the above for the purpose of
easy comparison. In the decimal representation, this number is formatted as
C<aaiiippccc>, where a=major, i=minor, p=patch, c=commit. For example,
C<0.0-180> becomes 180, and C<1.5.12-10> is 100512010.

  property s LogLevel rw

The currently active log level. The format is equivalent to the C<--log-level>
argument of L<globster(1)>. This setting can be changed on the fly.

  property s TigerPID rw
  property s TigerCID r

These properties provide the base32-encoded PID and CID of the client. It is
possible to change the PID, the CID will be updated automatically in that case.
A modification to the PID/CID pair requires reconnecting to each hub to be
effective.


=head2 net.blicky.Globster.HubManager (hubm)

Three methods to manage hubs:

  method Create() -> (u id)
  method Delete(u id)
  method List() -> (au list)

These should be self-explanatory. Create() creates a new hub object that can be
accessed with C</net/blicky/Globster/Hub/$id>, with C<$id> replaced with the
decimal number returned by Create(). Hubs and their associated configuration
are stored in the database and remembered after a restart of the Globster
daemon.

  signal Created(u id)
  signal Deleted(u id)

  property q NormalHubs r
  property q RegHubs r
  property q OpHubs r


=head2 net.blicky.Globster.Hub (hub)

Generic hub interface, holds miscellaneous settings and information.

  property s MyNick rw
  property s MyDescription rw
  property s MyEmail rw
  property u MyConnection rw

These properties specify the public information of the user. MyConnection
should indicate the upload speed of the user in bytes/s. All fields can be left
empty, except MyNick. If no nick is set, a randomly generated one is used.

  property s MyPassword rw

Should be set prior to connecting if the hub requires a password.  (I<TODO:>
Allow more dynamic login, e.g. by providing a "hub wants your password" signal
and a "here's my password" method.)

  property s HubEncoding rw

Configures the encoding used for messages sent to and received from the hub.
Defaults to UTF-8. This setting is only used for NMDC hubs, ADC always uses
UTF-8.  Modifying the encoding while being connected to an NMDC hub may cause
odd issues with some chat messages and user nicks using the old encoding while
others use the new. A reconnect is thus recommended.

All of the above settings, with the exception of MyPassword, are stored in the
database and remembered across restarts. (I<TODO:> Figure something out for
MyPassword, too).

  property s HubName r
  property s HubDescription r
  property s HubVersion r

Information provided by the hub while logging in. HubVersion is (currently)
always empty for NMDC hubs. These properties are reset to an empty string when
the hub is disconnected.

  property s HubError r
  property s HubErrorMessage r
  property s HubRedirect r

These properties are set when the hub indicates an error of any kind, and can
be checked when the hub is Disconnected() with an
C<net.blicky.Globster.Error.Hub> error. These properties are reset to an empty
string after a reconnect.  HubError takes any of the following values:

  VALUE             MEANING
   Full              Hub is full
   InvalidNick       Invalid nick name, or nick already taken
   NeedPassword      Hub requires a password, but MyPassword is empty
   InvalidPassword   Invalid password
   Redirect          Hub wants you to redirect to another address
   Disconnect        Hub has disconnected you (kick/ban/whatever - only on ADC)
   Protocol          Any other error

The HubErrorMessage property will have a human-readable error message, which
often originates from the hub. If HubError is C<Redirect>, then HubRedirect
will hold the address to redirect to. Redirects are currently not automatically
followed.


=head2 net.blicky.Globster.HubConnection (hubc)

  property q ConnectState r

Holds the connection state of the hub. Possible values are 0:IDLE (not
connected), 1:BUSY (connecting), 2:CONN (connected), 3:DISC (disconnecting),
4:TIMER (IDLE, but reconnect timeout is active). The connection follows the
following state machine:

     /--------------\  1   /------\  3   /------\  5   /------\
  -> | IDLE / TIMER | ---> | BUSY | ---> | CONN | ---> | DISC |
     \--------------/      \------/      \------/      \------/
            ^                  |             |             |
            |                2 |           4 |           6 |
            |                  |             |             |
            '----------------------------------------------`

The numbered state transitions happen on the following events:

=over

=item 1. Connect() method or automatic reconnect (see ReconnectTimeout)

=item 2. Disconnect(), ForceDisconnect() or Delete() method, or the connection failed

=item 3. Connection was successful

=item 4. ForceDisconnect() or Delete() method, or a fatal network error

=item 5. Disconnect() method, or a protocol error

=item 6. ForceDisconnect() or Delete() method, network error, or successful disconnect

=back

The Delete() method refers to the one in the C<net.blicky.Globster.HubManager>
interface. The connection always transitions to the IDLE state right before the
hub object is deleted. The other methods are described below.

  method Connect(s addr, q timeout_sec)

Can only be called in the IDLE or TIMER state. Moves to the BUSY state,
resolves the address and tries to open a connection. Only returns after the
connection has been established - at which point we're in the CONN state - or
moves back to IDLE or TIMER on error.

If I<addr> takes the form of C<adc://host:port/> or C<adcs://..>, then the hub
is assumed to understand the ADC protocol. Otherwise NMDC is assumed. If
I<addr> starts with C<adcs://> or C<nmdcs://>, the hub is assumed to use TLS.
If I<addr> is an empty string, the address given to the last call to Connect()
is re-used, or an error is thrown if Connect() hasn't been called before. The
given address is saved in the database and can be re-used across Globster
restarts.

I<timeout_sec> must be smaller than the D-Bus method reply timeout, otherwise
you will receive a generic timeout error and not the actual result of the
Connect() method. With most D-Bus bindings, you should be able to specify this
timeout. The default timeout is 25 seconds in libdbus (1.6.4). Perl's Net::DBus
(1.0.0) unfortunately uses a hardcoded timeout of 60 seconds.

Connect() may throw the following errors:

  net.blicky.Globster.Disconnected
    Operation cancelled by a Disconnect().

  org.freedesktop.DBus.Error.InvalidArgs
    Invalid address format.

  net.blicky.Globster.Error.DNS
    DNS lookup failed

  net.blicky.Globster.Error.ConnectionRefused
    Remote server didn't accept the connection

  org.freedesktop.DBus.Error.Timeout
    The timeout exceeded.

  org.freedesktop.DBus.Error.IOError
    Other network error while connecting

Note that the TLS handshake and hub login is done in the CONN state rather than
the BUSY state. This means that Connect() may succeed without errors even if,
shortly afterwards, the TLS handshake fails or if you couldn't login to the
hub.

If ReconnectTimeout > 0, automatic reconnect will be attempted if connecting
fails with any error other than C<net.blicky.Globster.Disconnected> or
C<org.freedesktop.DBus.Error.InvalidArgs>.

  method Disconnect()
  method ForceDisconnect()

Disconnect() aborts a connection attempt in the BUSY state, performs a graceful
disconnect in the CONN state, or disables the reconnect timeout in the TIMER
state. It throws an error when used in any other state. ForceDisconnect() is a
stronger version of Disconnect() that can be called from any state. It moves
directly into the IDLE state, forcefully aborting a connection attempt and
forcing a hub disconnect when connected.

  property b AutoConnect rw

When set, a Connect() with an empty string as address and a 60 second connect
timeout is automatically done when the Globster daemon is (re)started. This
functionality can be globally disabled with the C<-n> option to globster(1).

  property s ConnectAddress r
  property s ResolvedAddress r

ConnectAddress holds the address as last given to Connect(), or an empty string
if Connect() hasn't been called yet. ResolvedAddress holds the resolved IP
address and port, and is updated on each connection attempt.

  property q ReconnectTimeout rw

Configured timeout before automatically reconnecting to the hub after being
disconnected, in seconds. This timeout will start when the Disconnected signal
has been emitted with a network error or non-fatal hub error. Setting this to 0
will disable automatic reconnect. Default is 60 seconds. If this setting is
changed while in the TIMER state, the timer will be restarted with the new
value or the IDLE state is activated if the new timeout is 0.

  property s KeyprintSHA256 r

If TLS is enabled, this property will hold the base32-encoded SHA-256 keyprint
of the hub certificate. This property is set to an empty string whenever a new
connection is attempted (transition 1 in the state diagram), and updated to
reflect the actual keyprint of the hub as soon as the TLS handshake has been
completed in the CONN state.

  signal Disconnected(s reason, s message)

This signal is emitted whenever the hub moves from the BUSY or CONN states to
the IDLE, TIMER or DISC state (transitions 2, 4 and 5 in the state diagram).
When moving out of the BUSY state, I<reason> takes the same value as the error
code of Connect(). The following values are used for I<reason> when moving out
of the CONN state:

  net.blicky.Globster.Disconnected
    User-initiated disconnect, either through Disconnect(), ForceDisconnect()
    or Delete() on the hub object.

  net.blicky.Globster.Error.ConnectionReset
    Hub closed the connection.

  net.blicky.Globster.Error.TLSHandshake
    TLS handshake failed.

  net.blicky.Globster.Error.LoginTimeout
    TLS handshake or hub login took too long.

  org.freedesktop.DBus.Error.IOError
    Other network error.

  net.blicky.Globster.Error.Hub
    ADC or NMDC hub error. See the HubError properties in the
    net.blicky.Globster.Hub interface for more detailed information.

The I<message> argument may have more detailed human-readable information.


=head2 net.blicky.Globster.HubUsers (hubu)

This interface provides access to the user list of the connected hub.

A user is internally identified with a signed 64-bit positive number.  This
number uniquely identifies a (hub, user) pair within the entire application:
The same user on two different hubs will have a different ID. The number is
stable in the sense that it remains the same for a certain user even after
reconnect or restart.  On ADC, this identifies a (hub, CID) tuple, on NMDC a
(hub, nick) tuple.  The special value 0 always identifies this client (and
violates the "unique within the entire application" property, since it's 0 on
every hub).  Negative identifiers may have a special meaning depending on the
context where the ID is used.

User information is stored in the following I<fields>,

  NO TYPE    DEFAULT   DESCRIPTION
   1 s       -         Nick (not guaranteed to be unique on an
                       NMDC hub, due to conversion issues)
   2 s       empty     Description
   3 s       empty     Client
   4 s       empty     E-Mail
   5 u       0         Slot count
   6 u       0         Number of shared files
   7 t       0         Share size, in bytes
   8 u       0         Upload speed, in bytes/s
   9 (uuu)   0         Number hubs this user in on
                       (normal/registered/operator)
  10 s       empty     IPv4 address
  11 s       empty     IPv6 address
  12 u       0         Auto-opens slots if total upload is smaller
                       than this number in bytes/s
  13 ay      empty     CID
  14 u       0         Flags

NO is the field number, referenced by the methods and signals described below.
DEFAULT is its value if the field is not known or empty. Note that in many
cases these default values are also valid, so it's not always possible to
determine the difference between "we simply don't know the value of this field"
and "this field has intentionally been left empty".

The C<Flags> field is a bit mask of the following numbers:

   1: Set if the user is currently online
   2: Set if the user is 'away'
   4: Set if the user is an operator
   8: Set if the users' client supports C-C TLS
  16: Set if the user is in active mode (May not always be known on NMDC hubs)

Note that the user list does not only contain users that are B<currently>
online, but may also include a few users that used to be online or that are
still connecting. The above C<online> flag is used to indicates this status.

More fields and flags may be added in future versions.

  method UserInfo(x user, aq reqfields) -> (aq fields, a{xv} list)

The UserInfo() method is used to obtain the full user list (if I<user> is
negative) or fetch information of only a single user (if I<user> is
non-negative). The list includes users that don't have their C<online> flag
set. An empty list is returned if the user list if empty or if the requested
user ID does not exist.

I<list> is a dictionary with the user ID as key, and a (variable) struct as
value. The struct contains the fields in the same order as they appear in the
returned I<fields> array. For example, if I<fields> is C<[13, 3, 7]>, then the
type of the variant will be C<(ayst)>. If the I<fields> array is empty, then
the type of the variant will simply be a bool with value C<true>.

The I<fields> array will contain all the requested fields in I<reqfields> known
to the Globster daemon. Unknown or duplicate fields are removed and the order
in which the fields appear may be different.

  property b UserListComplete r

This property is C<true> when the user list has been successfully synchronised
with the hub. If this is false, then we're either not logged in to the hub or
we're still receiving the user list. Note that on some NMDC hubs, this signal
may be delayed for a few seconds after receiving the user list. This is because
it's not always possible to detect when we've received the full list. In rare
cases, it's also possible that this signal is emitted before the list has been
fully received.

  signal UserChanged(x user, aq fields, v values)
  signal UserJoined(x user, aq fields, v values)
  signal UserLeft(x user, x initiator, s message)

These signals are emitted when a users' information has changed, a user has
joined the hub or quit the hub, respectively.

The I<fields> and I<values> arguments to UserChanged and UserJoined have the
same meaning as described for the UserInfo() method. The UserJoined signal only
mentions fields that have a non-empty value for the new user. Similarly, the
UserChanged signal only mentions modified fields. Keep in mind that new fields
may be added in later versions, so your program has to deal with (ignore)
unknown fields. The type of each field, including those not known to your
program, can be inferred by the type of the struct included in the D-Bus
message. For most D-Bus bindings you should just be able to skip over an
unknown value without caring about its type.

The I<initiator> argument to UserLeft indicates user who kicked/banned the user
out of the hub. The special value C<-1> is used for the hub (i.e. no specific
user), and the special value C<-2> indicates that the user has not been kicked
out, but just left the hub. Many hubs do not actually send this information, so
C<-2> can mean anything. I<message> indicates the reason for leaving the hub or
the kick/ban message. Again, many hubs don't send this information, so it's
often just an empty string.

After a UserLeft signal, the user can still be queried for with UserInfo() for
at least 30 seconds. That is, it will remain in the list for a while with it's
C<online> flag reset.

The above signals are B<only> sent when the UserListComplete property is true,
and B<only> for users with the C<online> flag set. In order to obtain the full
user list, first wait for UserListComplete property to become true, then use
UserInfo() to fetch everything, and then check these signals for changes.

  property u UserCount r
  property t UserShareSize r

These properties hold the number of users currently online and the total share
size that they provide. As with the above signals, changes to these properties
are only emitted once UserListComplete is true.


=head2 net.blicky.Globster.HubChat (hubch)

This interface provides access to the chatting and private messaging facilities
of the hub. All chat messages are assigned to a I<group>. For private messages,
this is the ID of the user. For chat rooms, this is the ID of the chat room
user (on Direct Connect, "chat rooms" appear as "users"). The main chat has the
special group '-1'.

  method SendChat(x group, s message, b me)

Send a message to a I<group>. Setting I<me> to true will send it in first person,
as in C</me>. Since NMDC does not support first-person speak, the message will
simple be prefixed with "/me" instead. Throws a
C<org.freedesktop.DBus.Error.InvalidArgs> error if the specified group does not
exist or we're not logged in to the hub.

Messages sent with SendChat() will be echoed back in the ReceiveChat signal and
ChatLog() method. Normally, this echoing happens through the hub (i.e. we
receive our own message back from the hub), but on NMDC hubs this echo is
emulated for private messages. This is noticeable only by the fact that the
message is echoed immediately rather than after a round-trip delay through the
hub.

  signal ReceiveChat(x group, x from, s message, b me)

This signal is emitted when a new chat message has been received. I<from> can
have the special value -1 to indicate that the message came directly from the
hub.  The MOTD and hub-related status messages are currently sent in a
ReceiveChat as well, but this is subject to change.

  property u ChatLogSize rw

This property determines how many messages to keep in memory for each group. It
defaults to 0 in order to preserve memory, so applications that makes use of
the ChatLog() and ChatGroups() methods below should change this property to a
sane value. There will never be more messages in the log than specified by this
property, so decreasing this value will behave as if the CleanLog() method is
called for every item in ChatGroups().

  method ChatLog(x group, u number, d maxage) -> (a(dxsb) log)

Returns the contents of the in-memory message log for the particular group. At
most I<number> messages are returned, and only those that are newer than
I<maxage> (in seconds). Each log message is represented as a struct (in
pseudo-C):

  struct {
    double  age;
    int64_t from;
    string  message;
    bool    me;
  };

I<age> is the time since the arrival of the message, in seconds. The other
fields are equivalent to the respective arguments of the ReceiverChat signal.
An empty list is returned if there are no messages in the log for the requested
group.

If I<group> or I<from> refer to an actual user (i.e. not -1), then they are
guaranteed to still be available in the user list and their information can be
queried for with a UserInfo(), even if the user hasn't been online in the past
few days. Note, however, that the user information may have changed after a
message has been received. In particular, on ADC it is possible for users to
change their nick, so a message may have been sent from a different nick.
Similarly, this log only handles chat messages, information about where in the
chat history a user has joined or quit is not available.

  method ChatGroups() -> (ax groups)

Returns a list of groups for which we have at least one message logged. I.e.
the groups for which ChatLog() will return a non-empty list.

  method ClearLog(x group, u keep)

Remove old messages from the in-memory log for a particular group. At most
I<keep> messages will be kept.