]>
Commit | Line | Data |
---|---|---|
1 | #+TITLE: jabber.el Developer Documentation | |
2 | ||
3 | * Description | |
4 | :PROPERTIES: | |
5 | :CUSTOM_ID: description | |
6 | :END: | |
7 | ** Debugging tips | |
8 | :PROPERTIES: | |
9 | :CUSTOM_ID: debugging-tips | |
10 | :END: | |
11 | Useful tips for debugging: | |
12 | ||
13 | - There is a buffer called ~*fsm-debug*~ that displays all transitions and errors during the event handling. | |
14 | - There is a =jabber-debug= customization group. | |
15 | - You can set the [[file:jabber.org::#debug-log-xml][jabber-debug-log-xml]] custom variable to ~t~ to enable the XML debug console. | |
16 | - The XML console is a buffer called ~*-jabber-console-ACCOUNT-*~ by default. Enable ~jabber-debug-log-xml~ and switch to that buffer to see the incoming and outgoing XML stanzas. See [[file:jabber.org::#xml-console-mode][xml-console-mode]]. | |
17 | ||
18 | ** fsm.el - the Finite State Machine library | |
19 | :PROPERTIES: | |
20 | :CUSTOM_ID: fsm | |
21 | :END: | |
22 | fsm.el implements functions to define multiple [[https://en.wikipedia.org/wiki/Finite-state_machine][finite state machines]] (FSM), their states, and all the events associated to each of them. | |
23 | ||
24 | The following is a list of the most important functions or macros defined in this library: | |
25 | ||
26 | - ~(define-state-machine name &key start sleep)~ | |
27 | - ~(define-state fsm-name state-name arglist &body body)~ | |
28 | - ~(define-enter-state fsm-name state-name arglist &body body)~ | |
29 | - ~(define-fsm name &key strat sleep states ...)~ | |
30 | - ~(fsm-send fsm event &optional callback)~ | |
31 | - ~(fsm-call fsm event)~ | |
32 | ||
33 | It is required a name and the starting state to define a new FSM. The ~define-state-machine~ creates a new function called ~start-NAME~. Its ~start~ argument is a function argument and body definition used by the created function. The result of the new function must be a list ~(STATE STATE-DATA [TIMEOUT])~ which is the starting state of the machine. | |
34 | ||
35 | See [[file:jabber.org::*jabber-connection][jabber-connection]] section for an example. Its ~:start~ parameter explicitly mentioned, and its value is a list with the arguments ( ~(username server resource ...)~ ), a docstring ( ~"Start a jabber connection."~ ) and the body of the ~start-jabber-connection~ function. | |
36 | ||
37 | The machine requires states. They are defined with the ~define-state~ function. | |
38 | ||
39 | ** The jabber-connection FSM | |
40 | :PROPERTIES: | |
41 | :CUSTOM_ID: jabber-connection-fsm | |
42 | :END: | |
43 | jabber.el use a finite state machine (FSM) to track the current Jabber connection step. It defines a FSM called [[file:jabber.org::#fsm-connection][jabber-connection]] (or ~jc~ when it is used as parameter in functions) and several states along with their sentinels. The Org-mode tag ~:fsm:~ is used at jabber.org headlines to describe FSM definitions. | |
44 | ||
45 | *** States | |
46 | :PROPERTIES: | |
47 | :CUSTOM_ID: states | |
48 | :END: | |
49 | The following graph shows the states and their transitions, as of commit [[https://codeberg.org/emacs-jabber/emacs-jabber/commit/dddcccb926f422b03d22a66b60db46f1266eb141][dddcccb926]] (2021-03-20). The nodes represent the states and the arrows are events. | |
50 | ||
51 | All states have filter and sentinel events that do not change the FSM state. Also, they have a ~:do-disconnect~ event that change the FSM to the ~nil~ state except for the ~connecting~ state. | |
52 | ||
53 | Some state changes depend on the event and the data received, in this case, the event name has a number added. For instance, ~:stream-start1~, ~:stream-start2~ and ~:stream-start3~ is the same event (~:stream-start~) but triggers different states changes depending on the data received. | |
54 | ||
55 | #+name: fig:states | |
56 | #+BEGIN_SRC graphviz-dot :file images/states-dot.png :exports results :tangle no | |
57 | digraph "jabber-connection" { | |
58 | nil; | |
59 | ||
60 | connecting -> connected [label=":connected"]; | |
61 | connecting -> nil [label=":connection-failed"]; | |
62 | connecting -> defer [label=":do-disconnect"]; | |
63 | ||
64 | connected -> "connected" [label=":filter, :sentinel, :stream-start1,"]; | |
65 | connected -> "register-account" [label=":stream-start2, :stanza1"]; | |
66 | connected -> "legacy-auth" [label=":stream-start3"]; | |
67 | connected -> "starttls" [label=":stanza2"]; | |
68 | connected -> "sasl-auth" [label=":stanza3"]; | |
69 | ||
70 | "register-account" -> "register-account" [label=":stanza"]; | |
71 | ||
72 | starttls -> connected [label=":stanza"]; | |
73 | ||
74 | "legacy-auth" -> "legacy-auth" [label=":stanza"]; | |
75 | "legacy-auth" -> "session-established" [label=":authontication-success"]; | |
76 | "legacy-auth" -> "nil" [label=":authentication-failure"]; | |
77 | ||
78 | "sasl-auth" -> "sasl-auth" [label=":stanza"]; | |
79 | "sasl-auth" -> "legacy-auth" [label=":use-legacy-auth-instead"]; | |
80 | "sasl-auth" -> bind [label=":authentication-success"]; | |
81 | "sasl-auth" -> nil [label=":authentication-failure"]; | |
82 | ||
83 | bind -> bind [label=":stream-start, :stanza1"]; | |
84 | bind -> nil [label=":stanza2, :bind-failure, :session-failure"]; | |
85 | bind -> "session-established" [label=":bind-success, :session-success"]; | |
86 | ||
87 | "session-established" -> "session-established" [label=":stanza; :roster-update, :timeout, :send-if-connected"]; | |
88 | } | |
89 | #+END_SRC | |
90 | ||
91 | #+caption: Implemented states in the Jabber FSM. | |
92 | #+RESULTS: fig:states | |
93 | [[file:images/states-dot.png]] | |
94 | ||
95 | ** Stanza processing | |
96 | :PROPERTIES: | |
97 | :CUSTOM_ID: stanza-processing | |
98 | :END: | |
99 | The following is a brief summary about the stanza processing. | |
100 | ||
101 | 1. The ~:session-established~ state is reached. | |
102 | 2. The FSM receives the event ~:stanza~ at the ~:session-established~ state. | |
103 | 3. If no error has been found, call ~jabber-process-input~. See [[file:jabber.org::*jabber-process-input][jabber-process-input]] section. | |
104 | 4. Select one of the following variables depending on the type of message received: ~jabber-iq-chain~, ~jabber-presence-chain~ and ~jabber-message-chain~. All of them contains a list of functions that process its type of message. | |
105 | 5. Call all of their functions with the jabber connection and XML data as parameters . | |
106 | 6. Continue in the same state. | |
107 | ||
108 | * How-to guides | |
109 | :PROPERTIES: | |
110 | :CUSTOM_ID: how-to-guides | |
111 | :END: | |
112 | ** How to contribute to jabber.el | |
113 | :PROPERTIES: | |
114 | :CUSTOM_ID: how-to-contribute | |
115 | :END: | |
116 | 1. Fork the repository, then clone your fork. | |
117 | #+BEGIN_SRC shell :tangle no | |
118 | mkdir ~/git/ && cd ~/git/ | |
119 | git clone https://codeberg.org/YOUR-ACCOUNT/emacs-jabber | |
120 | #+END_SRC | |
121 | + You can also send patches to [[mailto:wgreenhouse@tilde.club][wgreenhouse@tilde.club]], using [[https://git-send-email.io/][git-send-email]]. In that case, you don't need to fork the repository or create an account. | |
122 | ||
123 | 2. Optionally, evaluate the following to install additional development tools (requires MELPA to be set up as package source) - | |
124 | #+BEGIN_SRC emacs-lisp :tangle no | |
125 | (mapcar #'package-install | |
126 | '(indent-lint package-lint relint nameless)) | |
127 | #+END_SRC | |
128 | ||
129 | 3. Make your edits, then run =make dev= to run the byte compiler and linters. Try to address any warnings they emit. | |
130 | ||
131 | 4. Try to follow [[https://cbea.ms/git-commit/#seven-rules][the seven rules of a great Git commit message]] in your commits. | |
132 | ||
133 | 5. Update the documentation. | |
134 | 1. Add your name to the [[#contributors][list of contributors]]. | |
135 | 2. Document user-facing changes in [[file:CHANGELOG.org][CHANGELOG.org]] and . | |
136 | 3. Update the [[file:README.org][user-facing documentation]] (this file). | |
137 | + Try to follow the [[https://diataxis.fr/][Diataxis Framework]]. | |
138 | 4. Update the [[file:DEV.org][developer documentation]]. | |
139 | + Try to follow the [[https://diataxis.fr/][Diataxis Framework]]. | |
140 | ||
141 | 6. Push and create your PR. |