HomeScreenBinding
libhomescreen.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdarg.h>
18 #include <sys/socket.h>
19 #include <iostream>
20 #include <algorithm>
21 #include <thread>
22 #include <errno.h>
23 #include <cassert>
24 #include <cctype>
25 #include <cerrno>
26 #include <cstdio>
27 #include <cstdlib>
28 #include <cstring>
29 
30 #include <libhomescreen.hpp>
31 
32 #define ELOG(args,...) _ELOG(__FUNCTION__,__LINE__,args,##__VA_ARGS__)
33 #define DLOG(args,...) _DLOG(__FUNCTION__,__LINE__,args,##__VA_ARGS__)
34 
35 using namespace std;
36 
37 static void _DLOG(const char* func, const int line, const char* log, ...);
38 static void _ELOG(const char* func, const int line, const char* log, ...);
39 static bool has_verb(const string& verb);
40 static const char API[] = "homescreen";
41 
42 const std::vector<std::string> LibHomeScreen::api_list {
43  std::string("ping"), // debug do not use
44  std::string("tap_shortcut"), // HomeScreen Application only
45  std::string("on_screen_message"),
46  std::string("subscribe"),
47  std::string("unsubscribe")
48 };
49 
50 const std::vector<std::string> LibHomeScreen::event_list {
51  std::string("tap_shortcut"),
52  std::string("on_screen_message"),
53  std::string("none")
54 };
55 
56 
61 static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
62 {
63  static_cast<LibHomeScreen*>(closure)->on_hangup(NULL,wsj);
64 }
65 
66 static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
67 {
68  /* LibHomeScreen is not called from other process */
69 }
70 
71 static void _on_event_static(void* closure, const char* event, struct afb_wsj1_msg *msg)
72 {
73  static_cast<LibHomeScreen*>(closure)->on_event(NULL,event,msg);
74 }
75 
76 static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)
77 {
78  static_cast<LibHomeScreen*>(closure)->on_reply(NULL,msg);
79 }
80 
81 
86 {
87 
88 }
89 
94 {
95  if(mploop)
96  {
97  sd_event_unref(mploop);
98  }
99  if(sp_websock != NULL)
100  {
101  free(sp_websock);
102  }
103 }
104 
119 int LibHomeScreen::init(const int port, const string& token)
120 {
121  int ret = 0;
122  if(port > 0 && token.size() > 0)
123  {
124  mport = port;
125  mtoken = token;
126  }
127  else
128  {
129  ELOG("port and token should be > 0, Initial port and token uses.");
130  }
131 
132  ret = initialize_websocket();
133  if(ret != 0 )
134  {
135  ELOG("Failed to initialize websocket");
136  }
137  else{
138  DLOG("Initialized");
139  }
140 
141  return ret;
142 }
143 
159  void (*event_cb)(const std::string& event, struct json_object* event_contents),
160  void (*reply_cb)(struct json_object* reply_contents),
161  void (*hangup_cb)(void))
162 {
163  onEvent = event_cb;
164  onReply = reply_cb;
165  onHangup = hangup_cb;
166 }
167 
168 int LibHomeScreen::initialize_websocket()
169 {
170  mploop = NULL;
171  onEvent = nullptr;
172  onReply = nullptr;
173  int ret = sd_event_default(&mploop);
174  if(ret < 0)
175  {
176  ELOG("Failed to create event loop");
177  goto END;
178  }
179 
180  /* Initialize interface from websocket */
181  minterface.on_hangup = _on_hangup_static;
182  minterface.on_call = _on_call_static; /* Is this necessary? */
183  minterface.on_event = _on_event_static;
184  muri += "ws://localhost:" + to_string(mport) + "/api?token=" + mtoken; /*To be modified*/
185  sp_websock = afb_ws_client_connect_wsj1(mploop, muri.c_str(), &minterface, this);
186  if(sp_websock == NULL)
187  {
188  ELOG("Failed to create websocket connection");
189  goto END;
190  }
191 
192  /* creates the evsrc */
193  //ret = sd_event_add_io(mploop,&mevent_src, sp_websock->fd, EPOLLIN, event_callback, NULL);
194 
195  return 0;
196 END:
197  if(mploop)
198  {
199  sd_event_unref(mploop);
200  }
201  return -1;
202 }
203 
204 static void *event_loop_run(void *args)
205 {
206  struct sd_event* loop = (struct sd_event*)(args);
207  DLOG("start eventloop");
208  for(;;)
209  sd_event_run(loop, 30000000);
210 }
211 
225 {
226  if(mploop && sp_websock)
227  {
228  pthread_t thread_id;
229  int ret = pthread_create(&thread_id, NULL, event_loop_run, mploop);
230  if(ret != 0)
231  {
232  ELOG("Cannot run eventloop due to error:%d", errno);
233  return -1;
234  }
235  else
236  return thread_id;
237  }
238  else
239  {
240  ELOG("Connecting is not established yet");
241  return -1;
242  }
243 }
244 
256 int LibHomeScreen::tapShortcut(const char* application_name)
257 {
258  if(!sp_websock)
259  {
260  return -1;
261  }
262 
263  struct json_object* j_obj = json_object_new_object();
264  struct json_object* val = json_object_new_string(application_name);
265  json_object_object_add(j_obj, "application_name", val);
266  return this->call("tap_shortcut", j_obj);
267 }
268 
280 int LibHomeScreen::onScreenMessage(const char* display_message)
281 {
282  if(!sp_websock)
283  {
284  return -1;
285  }
286 
287  struct json_object* j_obj = json_object_new_object();
288  struct json_object* val = json_object_new_string(display_message);
289  json_object_object_add(j_obj, "display_message", val);
290  return this->call("on_screen_message", j_obj);
291 }
292 
306 {
307  if (et >= 1 && et <= 2) {
308  switch (et) {
309  case Event_TapShortcut:
311  break;
312  case Event_OnScreenMessage:
314  break;
315  }
316 
317  this->handlers[et] = std::move(f);
318  }
319 }
320 
335 int LibHomeScreen::call(const string& verb, struct json_object* arg)
336 {
337  int ret;
338  if(!sp_websock)
339  {
340  return -1;
341  }
342  if (!has_verb(verb))
343  {
344  ELOG("verb doesn't exit");
345  return -1;
346  }
347  ret = afb_wsj1_call_j(sp_websock, API, verb.c_str(), arg, _on_reply_static, this);
348  if (ret < 0) {
349  ELOG("Failed to call verb:%s",verb.c_str());
350  }
351  return ret;
352 }
353 
369 int LibHomeScreen::call(const char* verb, struct json_object* arg)
370 {
371  int ret;
372  if(!sp_websock)
373  {
374  return -1;
375  }
376  if (!has_verb(string(verb)))
377  {
378  ELOG("verb doesn't exit");
379  return -1;
380  }
381  ret = afb_wsj1_call_j(sp_websock, API, verb, arg, _on_reply_static, this);
382  if (ret < 0) {
383  ELOG("Failed to call verb:%s",verb);
384  }
385  return ret;
386 }
387 
401 int LibHomeScreen::subscribe(const string& event_name)
402 {
403  if(!sp_websock)
404  {
405  return -1;
406  }
407  struct json_object* j_obj = json_object_new_object();
408  json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
409 
410  int ret = afb_wsj1_call_j(sp_websock, API, "subscribe", j_obj, _on_reply_static, this);
411  if (ret < 0) {
412  ELOG("Failed to call verb:%s",__FUNCTION__);
413  }
414  return ret;
415 }
416 
430 int LibHomeScreen::unsubscribe(const string& event_name)
431 {
432  if(!sp_websock)
433  {
434  return -1;
435  }
436  struct json_object* j_obj = json_object_new_object();
437  json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
438 
439  int ret = afb_wsj1_call_j(sp_websock, API, "unsubscribe", j_obj, _on_reply_static, this);
440  if (ret < 0) {
441  ELOG("Failed to call verb:%s",__FUNCTION__);
442  }
443  return ret;
444 }
445 
446 /************* Callback Function *************/
447 
448 void LibHomeScreen::on_hangup(void *closure, struct afb_wsj1 *wsj)
449 {
450  DLOG("%s called", __FUNCTION__);
451  if(onHangup != nullptr)
452  {
453  onHangup();
454  }
455 }
456 
457 void LibHomeScreen::on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
458 {
459 }
460 
461 /*
462 * event is like "homescreen/tap_shortcut"
463 * msg is like {"event":"homescreen\/tap_shortcut","data":{"application_name":"hoge"},"jtype":"afb-event"}
464 * so you can get
465  event name : struct json_object obj = json_object_object_get(msg,"event")
466 */
467 void LibHomeScreen::on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
468 {
469  cout << "[libhomescreen on_event]: " << event << " (" << afb_wsj1_msg_object_s(msg) << ")" << endl;
470 
471  if (strstr(event, API) == NULL) {
472  return;
473  }
474 
475  struct json_object* ev_contents = afb_wsj1_msg_object_j(msg);
476  struct json_object *json_data = json_object_object_get(ev_contents, "data");
477 
478  if(onEvent != nullptr)
479  {
480  const string ev(event);
481  onEvent(ev, ev_contents);
482  }
483 
484  const char* event_only = strchr(event, '/');
485  if (event_only != nullptr) {
486  event_only = event_only + 1;
487  }
488 
489  if (strcasecmp(event_only, LibHomeScreen::event_list[0].c_str()) == 0) {
490  auto i = this->handlers.find(Event_TapShortcut);
491 
492  struct json_object *json_application_name = json_object_object_get(json_data, "application_name");
493  const char* application_name = json_object_get_string(json_application_name);
494 
495  if ( i != this->handlers.end() ) {
496  i->second(application_name);
497  }
498  }
499  else if (strcasecmp(event_only, LibHomeScreen::event_list[1].c_str()) == 0) {
500 
501  auto i = this->handlers.find(Event_OnScreenMessage);
502 
503  struct json_object *json_display_message = json_object_object_get(json_data, "display_message");
504  const char* display_message = json_object_get_string(json_display_message);
505 
506  if ( i != this->handlers.end() ) {
507  i->second(display_message);
508  }
509 
510  }
511 
512  json_object_put(ev_contents);
513 }
514 
519 void LibHomeScreen::on_reply(void *closure, struct afb_wsj1_msg *msg)
520 {
521  cout << "[libhomescreen on_reply]: " << " (" << afb_wsj1_msg_object_s(msg) << ")" << endl;
522  if(onReply != nullptr)
523  {
524  struct json_object* reply = afb_wsj1_msg_object_j(msg);
525  onReply(reply);
526 
527  json_object_put(reply);
528  }
529 }
530 
531 /* Internal Function in libhomescreen */
532 
533 static void _ELOG(const char* func, const int line, const char* log, ...)
534 {
535  char *message;
536  va_list args;
537  va_start(args, log);
538  if (log == NULL || vasprintf(&message, log, args) < 0)
539  message = NULL;
540  cout << "[libhomescreen ERROR]" << func << "(" << line << "):" << message << endl;
541  va_end(args);
542  free(message);
543 }
544 
545 static void _DLOG(const char* func, const int line, const char* log, ...)
546 {
547  char *message;
548  va_list args;
549  va_start(args, log);
550  if (log == NULL || vasprintf(&message, log, args) < 0)
551  message = NULL;
552  cout << "[libhomescreen DEBUG]" << func << "(" << line << "):" << message << endl;
553  va_end(args);
554  free(message);
555 }
556 
557 static bool has_verb(const string& verb)
558 {
559  DLOG("verb is %s", verb.c_str());
560  if(find(LibHomeScreen::api_list.begin(), LibHomeScreen::api_list.end(), verb) != LibHomeScreen::api_list.end())
561  return true;
562  else
563  return false;
564 }
void on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
void on_reply(void *closure, struct afb_wsj1_msg *msg)
void on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
#define DLOG(args,...)
static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
static const char API[]
#define ELOG(args,...)
int call(const std::string &verb, struct json_object *arg)
static void * event_loop_run(void *args)
void on_hangup(void *closure, struct afb_wsj1 *wsj)
int tapShortcut(const char *application_name)
static void _ELOG(const char *func, const int line, const char *log,...)
int subscribe(const std::string &event_name)
static const std::vector< std::string > event_list
static void subscribe(struct afb_req request)
Definition: homescreen.c:151
std::function< void(const char *)> handler_func
int init(const int port, const std::string &token)
static bool has_verb(const string &verb)
static void _on_event_static(void *closure, const char *event, struct afb_wsj1_msg *msg)
int onScreenMessage(const char *display_message)
static const std::vector< std::string > api_list
int unsubscribe(const std::string &event_name)
static void _DLOG(const char *func, const int line, const char *log,...)
void set_event_handler(enum EventType et, handler_func f)
void registerCallback(void(*event_cb)(const std::string &event, struct json_object *event_contents), void(*reply_cb)(struct json_object *reply_contents), void(*hangup_cb)(void)=nullptr)
static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)