Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Example for notification library which repeatedly reads some keys and
5 : * reacts to them
6 : *
7 : * Requires:
8 : * - io_uv binding
9 : * - Transport plugins (e.g. kdb global-mount dbus announce=once dbusrecv)
10 : *
11 : * Relevant keys for this example:
12 : * - /sw/example/notification/#0/current/value: Set to any integer value
13 : * - /sw/example/notification/#0/current/color: Set the text color. Possible
14 : * values are "red", "green" and "blue".
15 : *
16 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
17 : *
18 : */
19 :
20 : #include <kdb.h>
21 : #include <kdbhelper.h> // elektraFree
22 : #include <kdbio.h> // I/O binding functions (elektraIo*)
23 : #include <kdbio/uv.h> // I/O binding constructor for uv (elektraIoUvNew)
24 : #include <kdbnotification.h> // notification functions
25 :
26 : #include <uv.h> // uv functions
27 :
28 : #include <signal.h> // signal()
29 : #include <stdio.h> // printf() & co
30 :
31 : uv_async_t wakeup;
32 :
33 : #ifdef HAVE_LIBUV0
34 : static void wakeupCallback (uv_async_t * async ELEKTRA_UNUSED, int unknown ELEKTRA_UNUSED)
35 : {
36 : // nothing to do; callback required for libuv 0.x
37 : }
38 : #endif
39 :
40 : // from https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
41 : #define ANSI_COLOR_RESET "\x1b[0m"
42 : #define ANSI_COLOR_RED "\x1b[31m"
43 : #define ANSI_COLOR_GREEN "\x1b[32m"
44 : #define ANSI_COLOR_BLUE "\x1b[34m"
45 :
46 0 : static void setTerminalColor (Key * color, void * context ELEKTRA_UNUSED)
47 : {
48 0 : const char * value = keyString (color);
49 0 : printf ("Callback called. Changing color to %s\n", value);
50 :
51 0 : if (elektraStrCmp (value, "red") == 0)
52 : {
53 0 : printf (ANSI_COLOR_RED);
54 : }
55 0 : else if (elektraStrCmp (value, "green") == 0)
56 : {
57 0 : printf (ANSI_COLOR_GREEN);
58 : }
59 0 : else if (elektraStrCmp (value, "blue") == 0)
60 : {
61 0 : printf (ANSI_COLOR_BLUE);
62 : }
63 : else
64 : {
65 0 : printf ("Specified color (%s) did not match \"red\", \"green\" or \"blue\". Using default color.\n", value);
66 0 : printf (ANSI_COLOR_RESET);
67 : }
68 0 : }
69 :
70 : static void resetTerminalColor (void)
71 : {
72 0 : printf (ANSI_COLOR_RESET "\n");
73 : }
74 :
75 0 : static void onSIGNAL (int signal)
76 : {
77 0 : if (signal == SIGINT)
78 : {
79 0 : uv_stop (uv_default_loop ());
80 : // Without this call the loop would be "sleeping" until the next timer interval
81 0 : uv_async_send (&wakeup);
82 : }
83 0 : }
84 :
85 0 : static void printVariable (ElektraIoTimerOperation * timerOp)
86 : {
87 0 : int value = *(int *) elektraIoTimerGetData (timerOp);
88 0 : printf ("\nMy integer value is %d\n", value);
89 0 : }
90 :
91 0 : int main (void)
92 : {
93 : // Cleanup on SIGINT
94 0 : signal (SIGINT, onSIGNAL);
95 :
96 0 : KeySet * config = ksNew (20, KS_END);
97 :
98 0 : Key * key = keyNew ("/sw/example/notification/#0/current", KEY_END);
99 0 : KDB * kdb = kdbOpen (key);
100 0 : if (kdb == NULL)
101 : {
102 0 : printf ("could not open KDB, aborting\n");
103 0 : return -1;
104 : }
105 :
106 0 : uv_loop_t * loop = uv_default_loop ();
107 0 : ElektraIoInterface * binding = elektraIoUvNew (loop);
108 0 : elektraIoSetBinding (kdb, binding);
109 :
110 0 : int result = elektraNotificationOpen (kdb);
111 0 : if (!result)
112 : {
113 0 : printf ("could not init notification, aborting\n");
114 0 : return -1;
115 : }
116 :
117 0 : int value = 0;
118 0 : Key * intKeyToWatch = keyNew ("/sw/example/notification/#0/current/value", KEY_END);
119 0 : result = elektraNotificationRegisterInt (kdb, intKeyToWatch, &value);
120 0 : if (!result)
121 : {
122 0 : printf ("could not register variable, aborting\n");
123 0 : return -1;
124 : }
125 :
126 0 : Key * callbackKeyToWatch = keyNew ("/sw/example/notification/#0/current/color", KEY_END);
127 0 : result = elektraNotificationRegisterCallback (kdb, callbackKeyToWatch, &setTerminalColor, NULL);
128 0 : if (!result)
129 : {
130 0 : printf ("could not register callback, aborting!");
131 0 : return -1;
132 : }
133 :
134 : // Setup timer that repeatedly prints the variable
135 0 : ElektraIoTimerOperation * timer = elektraIoNewTimerOperation (2000, 1, printVariable, &value);
136 0 : elektraIoBindingAddTimer (binding, timer);
137 :
138 0 : printf ("Asynchronous Notification Example Application\n");
139 0 : printf ("Please note that notification transport plugins are required see\n"
140 : " https://www.libelektra.org/tutorials/notifications#notification-configuration!\n");
141 0 : printf ("- Set \"%s\" to red, blue or green to change the text color\n", keyName (callbackKeyToWatch));
142 0 : printf ("- Set \"%s\" to any integer value\n", keyName (intKeyToWatch));
143 0 : printf ("Send SIGINT (Ctl+C) to exit.\n\n");
144 :
145 : // Get configuration
146 0 : kdbGet (kdb, config, key);
147 0 : printVariable (timer); // "value" was automatically updated
148 :
149 : // This allows us to wake the loop from our signal handler
150 : #ifdef HAVE_LIBUV1
151 0 : uv_async_init (loop, &wakeup, NULL);
152 : #else
153 : uv_async_init (loop, &wakeup, wakeupCallback);
154 : #endif
155 :
156 0 : uv_run (loop, UV_RUN_DEFAULT);
157 :
158 : // Cleanup
159 : resetTerminalColor ();
160 0 : elektraIoBindingRemoveTimer (timer);
161 0 : elektraFree (timer);
162 0 : elektraNotificationClose (kdb);
163 0 : kdbClose (kdb, key);
164 :
165 0 : elektraIoBindingCleanup (binding);
166 0 : uv_run (loop, UV_RUN_NOWAIT);
167 : #ifdef HAVE_LIBUV1
168 0 : uv_loop_close (uv_default_loop ());
169 : #else
170 : uv_loop_delete (uv_default_loop ());
171 : #endif
172 :
173 0 : ksDel (config);
174 0 : keyDel (intKeyToWatch);
175 0 : keyDel (callbackKeyToWatch);
176 0 : keyDel (key);
177 0 : printf ("cleanup done!\n");
178 : }
|