2 * Copyright (C) 2019 Konsulko Group
3 * Author: Matt Ranostay <matt.ranostay@konsulko.com>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
27 #include <glib/gstdio.h>
29 #include <json-c/json.h>
31 #define AFB_BINDING_VERSION 3
32 #include <afb/afb-binding.h>
34 #include "navigation-api.h"
36 struct navigation_state *navigation_get_userdata(afb_req_t request) {
37 afb_api_t api = afb_req_get_api(request);
38 return afb_api_get_userdata(api);
41 static afb_event_t get_event_from_value(struct navigation_state *ns,
44 if (!g_strcmp0(value, "status"))
45 return ns->status_event;
47 if (!g_strcmp0(value, "position"))
48 return ns->position_event;
50 if (!g_strcmp0(value, "waypoints"))
51 return ns->waypoints_event;
56 static json_object **get_storage_from_value(struct navigation_state *ns,
59 if (!g_strcmp0(value, "status"))
60 return &ns->status_storage;
62 if (!g_strcmp0(value, "position"))
63 return &ns->position_storage;
65 if (!g_strcmp0(value, "waypoints"))
66 return &ns->waypoints_storage;
71 static void navigation_subscribe_unsubscribe(afb_req_t request,
74 struct navigation_state *ns = navigation_get_userdata(request);
75 json_object *jresp = json_object_new_object();
80 value = afb_req_value(request, "value");
82 afb_req_fail_f(request, "failed", "Missing \"value\" event");
86 event = get_event_from_value(ns, value);
88 afb_req_fail_f(request, "failed", "Bad \"value\" event \"%s\"",
95 rc = afb_req_subscribe(request, event);
97 g_rw_lock_reader_lock(&ns->rw_lock);
98 storage = *get_storage_from_value(ns, value);
100 // increment reference counter, and send out cached value
101 json_object_get(storage);
102 afb_event_push(event, storage);
104 g_rw_lock_reader_unlock(&ns->rw_lock);
106 rc = afb_req_unsubscribe(request, event);
109 afb_req_fail_f(request, "failed",
110 "%s error on \"value\" event \"%s\"",
111 !unsub ? "subscribe" : "unsubscribe",
116 afb_req_success_f(request, jresp, "Navigation %s to event \"%s\"",
117 !unsub ? "subscribed" : "unsubscribed",
121 static void subscribe(afb_req_t request)
123 navigation_subscribe_unsubscribe(request, FALSE);
126 static void unsubscribe(afb_req_t request)
128 navigation_subscribe_unsubscribe(request, TRUE);
131 static void broadcast(afb_req_t request, const char *name, gboolean cache)
133 struct navigation_state *ns = navigation_get_userdata(request);
134 afb_event_t event = get_event_from_value(ns, name);
135 json_object *jresp = afb_req_json(request);
138 json_object **storage = get_storage_from_value(ns, name);
140 g_rw_lock_writer_lock(&ns->rw_lock);
143 json_object_put(*storage);
145 // increment reference for storage
146 json_object_get(jresp);
149 // increment reference for event
150 json_object_get(jresp);
151 afb_event_push(event, jresp);
153 g_rw_lock_writer_unlock(&ns->rw_lock);
158 g_rw_lock_reader_lock(&ns->rw_lock);
160 // increment reference for event
161 json_object_get(jresp);
162 afb_event_push(event, jresp);
164 g_rw_lock_reader_unlock(&ns->rw_lock);
167 static void broadcast_status(afb_req_t request)
169 broadcast(request, "status", TRUE);
171 afb_req_success(request, NULL, "Broadcast status send");
174 static void broadcast_position(afb_req_t request)
176 const char *position = afb_req_value(request, "position");
177 gboolean cache = FALSE;
179 // only send out a car position event on subscribe
180 if (position && !g_strcmp0(position, "car"))
183 broadcast(request, "position", cache);
185 afb_req_success(request, NULL, "Broadcast position send");
188 static void broadcast_waypoints(afb_req_t request)
190 broadcast(request, "waypoints", TRUE);
192 afb_req_success(request, NULL, "Broadcast waypoints send");
195 static int init(afb_api_t api)
197 struct navigation_state *ns;
199 ns = g_try_malloc0(sizeof(*ns));
201 AFB_ERROR("out of memory allocating navigation state");
205 ns->status_event = afb_daemon_make_event("status");
206 ns->position_event = afb_daemon_make_event("position");
207 ns->waypoints_event = afb_daemon_make_event("waypoints");
209 if (!afb_event_is_valid(ns->status_event) ||
210 !afb_event_is_valid(ns->position_event) ||
211 !afb_event_is_valid(ns->waypoints_event)) {
212 AFB_ERROR("Cannot create events");
216 afb_api_set_userdata(api, ns);
218 g_rw_lock_init(&ns->rw_lock);
223 static const afb_verb_t binding_verbs[] = {
226 .callback = subscribe,
227 .info = "Subscribe to event"
229 .verb = "unsubscribe",
230 .callback = unsubscribe,
231 .info = "Unsubscribe to event"
233 .verb = "broadcast_status",
234 .callback = broadcast_status,
235 .info = "Allows clients to broadcast status events"
237 .verb = "broadcast_position",
238 .callback = broadcast_position,
239 .info = "Broadcast out position event"
241 .verb = "broadcast_waypoints",
242 .callback = broadcast_waypoints,
243 .info = "Broadcast out waypoint event"
249 * description of the binding for afb-daemon
251 const afb_binding_t afbBindingV3 = {
253 .verbs = binding_verbs,