Add set_event_handler, added int returns for all API methods.
[staging/windowmanager.git] / AFBClient.cpp
1 #include "AFBClient.h"
2
3 #include <cctype>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <errno.h>
7 #include <string.h>
8 #include <unistd.h>
9
10 #define UNUSED(x) (void)(x)
11
12 constexpr const int token_maxlen = 20;
13 const char * AFBClient::wmAPI = "winman";
14
15 AFBClient::AFBClient() : itf()
16 {
17     ///* itinializing the callback interface for wsj1 */
18     itf.on_hangup = AFBClient::onHangup;
19     itf.on_call = AFBClient::onCall;
20     itf.on_event = AFBClient::onEvent;
21 }
22
23 AFBClient::~AFBClient()
24 {
25 }
26
27 int AFBClient::init(int port, char const *token)
28 {
29     char *uribuf = NULL;
30     int rc = -1;
31
32     printf("AFBClient::init() -->\n");
33
34     if (!token || strlen(token) > token_maxlen) {
35        fprintf(stderr, "Token is invalid\n");
36        rc = -EINVAL;
37        goto fail;
38     }
39
40     for (char const *p = token; *p; p++) {
41        if (!isalnum(*p)) {
42           fprintf(stderr, "Token is invalid\n");
43           rc = -EINVAL;
44           goto fail;
45        }
46     }
47
48     if (port < 1 && port > 0xffff) {
49        fprintf(stderr, "Port is invalid\n");
50        rc = -EINVAL;
51        goto fail;
52     }
53
54     /* get the default event loop */
55     rc = sd_event_default(&loop);
56     if (rc < 0) {
57         fprintf(stderr, "Connection to default event loop failed: %s\n", strerror(-rc));
58         goto fail;
59     }
60
61     asprintf(&uribuf, "ws://localhost:%d/api?token=%s", port, token);
62
63     /* connect the websocket wsj1 to the uri given by the first argument */
64     wsj1 = afb_ws_client_connect_wsj1(loop, uribuf, &itf, NULL);
65     if (wsj1 == NULL) {
66         sd_event_unref(loop);
67         fprintf(stderr, "Connection to %s failed: %m\n", uribuf);
68         rc = -errno;
69         goto fail;
70     }
71
72     printf("AFBClient::init() <--\n");
73     return 0;
74
75 fail:
76     printf("AFBClient::init() <--\n");
77     return rc;
78 }
79
80 int AFBClient::dispatch(uint64_t timeout) {
81     return sd_event_run(loop, timeout);
82 }
83
84 int AFBClient::requestSurface(const char *label)
85 {
86    printf("AFBClient::requestSurface(%s) -->\n", label);
87    constexpr char const *verb = "request_surface";
88
89    json_object *jp = json_object_new_object();
90    json_object_object_add(jp, "drawing_name", json_object_new_string(label));
91
92    // std::experimental::optional look-alike
93    struct optional {
94       int value;
95       bool is_not_set;
96    };
97
98    constexpr struct optional const nullopt = {0, true};
99    auto id = nullopt;
100
101    /* send the request */
102    int rc = afb_wsj1_call_j(
103       wsj1, AFBClient::wmAPI, verb, jp,
104       [](void *closure, afb_wsj1_msg *msg) {
105          if (afb_wsj1_msg_is_reply_ok(msg)) {
106             int id = json_object_get_int(
107                json_object_object_get(afb_wsj1_msg_object_j(msg), "response"));
108             auto oid = (optional *)closure;
109             *oid = optional{id};
110          } else
111             fprintf(stderr, "wrong request surface reply received!\n");
112       },
113       (void *)&id);
114
115    if (rc < 0) {
116       fprintf(stderr, "calling %s/%s(%s) failed: %m\n", AFBClient::wmAPI, verb,
117               json_object_to_json_string(jp));
118    } else {
119       // Lets make this call sync here...
120       dispatch(-1);
121
122       if (! id.is_not_set) {
123           char *buf;
124           asprintf(&buf, "%d", id.value);
125           printf("setenv(\"QT_IVI_SURFACE_ID\", %s, 1)\n", buf);
126           if (setenv("QT_IVI_SURFACE_ID", buf, 1) != 0) {
127               fprintf(stderr, "putenv failed: %m\n");
128           } else {
129               rc = 0; // Single point of success
130           }
131       } else {
132           fprintf(stderr, "Could not get surface ID from WM\n");
133           rc = -EINVAL;
134       }
135    }
136
137    printf("AFBClient::requestSurface(%s) = %d <--\n", label, rc);
138
139    return rc;
140 }
141
142 int AFBClient::activateSurface(const char *label)
143 {
144     printf("AFBClient::activateSurface(%s) -->\n", label);
145     fflush(stdout);
146
147     const char begin[] = "{\"drawing_name\":\"";
148     const char end[] = "\"}";
149     const char verb[] = "activate_surface";
150     char *parameter = (char *)malloc(strlen(begin) +
151                                      strlen(label) +
152                                      strlen(end) + 1);
153     strcpy(parameter, begin);
154     strcat(parameter, label);
155     strcat(parameter, end);
156     call(AFBClient::wmAPI, verb, parameter);
157
158     // Sync this one too
159     dispatch(-1);
160
161     printf("AFBClient::activateSurface(%s) <--\n", label);
162     fflush(stdout);
163     return 0;
164 }
165
166 int AFBClient::deactivateSurface(const char *label)
167 {
168     printf("AFBClient::deactivateSurface(%s) -->\n", label);
169     fflush(stdout);
170     json_object *j = json_object_new_object();
171     json_object_object_add(j, "drawing_name", json_object_new_string(label));
172     call(AFBClient::wmAPI, "deactivate_surface", json_object_to_json_string(j));
173     json_object_put(j);
174     dispatch(-1);
175     printf("AFBClient::deactivateSurface(%s) <--\n", label);
176     fflush(stdout);
177     return 0;
178 }
179
180 int AFBClient::endDraw(const char *label)
181 {
182     printf("AFBClient::endDraw(%s) -->\n", label);
183     fflush(stdout);
184     json_object *j = json_object_new_object();
185     json_object_object_add(j, "drawing_name", json_object_new_string(label));
186     call(AFBClient::wmAPI, "enddraw", json_object_to_json_string(j));
187     json_object_put(j);
188     dispatch(-1);
189     printf("AFBClient::endDraw(%s) <--\n", label);
190     fflush(stdout);
191     return 0;
192 }
193
194 /* called when wsj1 receives a method invocation */
195 void AFBClient::onCall(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
196 {
197     UNUSED(closure);
198     int rc;
199     printf("ON-CALL %s/%s:\n%s\n", api, verb,
200            json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg),
201                                           JSON_C_TO_STRING_PRETTY));
202     fflush(stdout);
203     rc = afb_wsj1_reply_error_s(msg, "\"unimplemented\"", NULL);
204     if (rc < 0)
205         fprintf(stderr, "replying failed: %m\n");
206 }
207
208 /* called when wsj1 receives an event */
209 void AFBClient::onEvent(void *closure, const char *event, afb_wsj1_msg *msg)
210 {
211     UNUSED(closure);
212     printf("ON-EVENT %s:\n%s\n", event,
213            json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg),
214                                           JSON_C_TO_STRING_PRETTY));
215     fflush(stdout);
216 }
217
218 /* called when wsj1 hangsup */
219 void AFBClient::onHangup(void *closure, afb_wsj1 *wsj1)
220 {
221     UNUSED(closure);
222     UNUSED(wsj1);
223     printf("ON-HANGUP\n");
224     fflush(stdout);
225     exit(0);
226 }
227
228 /* called when wsj1 receives a reply */
229 void AFBClient::onReply(void *closure, afb_wsj1_msg *msg)
230 {
231     printf("ON-REPLY %s: %s\n%s\n", (char*)closure,
232            afb_wsj1_msg_is_reply_ok(msg) ? "OK" : "ERROR",
233            json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg),
234                                           JSON_C_TO_STRING_PRETTY));
235     fflush(stdout);
236     free(closure);
237 }
238
239 /* makes a call */
240 void AFBClient::call(const char *api, const char *verb, const char *object)
241 {
242     static int num = 0;
243     char *key;
244     int rc;
245
246     printf("call(%s, %s, %s) -->\n", api, verb, object);
247     fflush(stdout);
248
249     /* allocates an id for the request */
250     rc = asprintf(&key, "%d:%s/%s", ++num, api, verb);
251
252     /* send the request */
253     rc = afb_wsj1_call_s(wsj1, api, verb, object, AFBClient::onReply, key);
254     if (rc < 0)
255         fprintf(stderr, "calling %s/%s(%s) failed: %m\n", api, verb, object);
256
257     printf("call(%s, %s, %s) <--\n", api, verb, object);
258     fflush(stdout);
259 }
260
261 /* sends an event */
262 void AFBClient::event(const char *event, const char *object)
263 {
264     int rc;
265
266     rc = afb_wsj1_send_event_s(wsj1, event, object);
267     if (rc < 0)
268         fprintf(stderr, "sending !%s(%s) failed: %m\n", event, object);
269 }
270
271 void AFBClient::set_event_handler(enum EventType at, std::function<void(char const *)> func) {
272    // XXX todo
273 }