Asterisk - The Open Source Telephony Project  21.4.1
message_json.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Sangoma Technologies Corporation
5  *
6  * Kevin Harwell <kharwell@sangoma.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 #include "asterisk.h"
20 
21 #include "asterisk/json.h"
22 
24 
25 #define JSON_MSG(lvalue, rvalue) struct message_json *lvalue = \
26  ((struct message_json *)rvalue)
27 
28 /*!
29  * \brief Asterisk external application JSON message type
30  */
31 struct message_json {
32  /*! The base message type (must be first) */
34  /*! Underlying JSON data structure */
35  struct ast_json *json;
36 };
37 
38 static int message_json_construct1(struct ast_aeap_message *self, const void *params)
39 {
40  JSON_MSG(msg, self);
41 
42  msg->json = ast_json_ref((struct ast_json *)params) ?: ast_json_object_create();
43 
44  return msg->json ? 0 : -1;
45 }
46 
47 static int message_json_construct2(struct ast_aeap_message *self, const char *msg_type,
48  const char *name, const char *id, const void *params)
49 {
50  struct ast_json *msg_data;
51  int res;
52 
53  msg_data = ast_json_pack("{s:s,s:s*}", msg_type, name, "id", id);
54 
55  if (!msg_data) {
56  ast_log(LOG_ERROR, "AEAP message json: failed to create data for '%s: %s'", msg_type, name);
57  return -1;
58  }
59 
60  if (params && ast_json_object_update(msg_data, (struct ast_json *)params)) {
61  ast_log(LOG_ERROR, "AEAP message json: failed to update data for '%s: %s'", msg_type, name);
62  ast_json_unref(msg_data);
63  return -1;
64  }
65 
66  res = message_json_construct1(self, msg_data);
67  ast_json_unref(msg_data);
68  return res;
69 }
70 
71 static void message_json_destruct(struct ast_aeap_message *self)
72 {
73  JSON_MSG(msg, self);
74 
75  ast_json_unref(msg->json);
76 }
77 
78 static int message_json_deserialize(struct ast_aeap_message *self, const void *buf, intmax_t size)
79 {
80  JSON_MSG(msg, self);
81 
82  msg->json = ast_json_load_buf(buf, size, NULL);
83 
84  return msg->json ? 0 : -1;
85 }
86 
87 static int message_json_serialize(const struct ast_aeap_message *self, void **buf, intmax_t *size)
88 {
89  const JSON_MSG(msg, self);
90 
91  *buf = ast_json_dump_string(msg->json);
92  if (!*buf) {
93  *size = 0;
94  return -1;
95  }
96 
97  *size = strlen(*buf);
98 
99  return 0;
100 }
101 
102 static const char *message_json_id(const struct ast_aeap_message *self)
103 {
104  const JSON_MSG(msg, self);
105 
106  return ast_json_object_string_get(msg->json, "id");
107 }
108 
109 static int message_json_id_set(struct ast_aeap_message *self, const char *id)
110 {
111  JSON_MSG(msg, self);
112 
113  if (ast_json_object_set(msg->json, "id", ast_json_string_create(id))) {
114  return -1;
115  }
116 
117  return 0;
118 }
119 
120 static const char *message_json_name(const struct ast_aeap_message *self)
121 {
122  const JSON_MSG(msg, self);
123  struct ast_json_iter *iter;
124 
125  iter = ast_json_object_iter_at(msg->json, "response");
126  if (!iter) {
127  iter = ast_json_object_iter_at(msg->json, "request");
128  }
129 
130  return iter ? ast_json_string_get(ast_json_object_iter_value(iter)) : "";
131 }
132 
133 static void *message_json_data(struct ast_aeap_message *self)
134 {
135  JSON_MSG(msg, self);
136 
137  return msg->json;
138 }
139 
140 static int message_json_is_request(const struct ast_aeap_message *self)
141 {
142  const JSON_MSG(msg, self);
143 
144  return ast_json_object_iter_at(msg->json, "request") != NULL;
145 }
146 
147 static int message_json_is_response(const struct ast_aeap_message *self)
148 {
149  const JSON_MSG(msg, self);
150 
151  return ast_json_object_iter_at(msg->json, "response") != NULL;
152 }
153 
154 static const char *message_json_error_msg(const struct ast_aeap_message *self)
155 {
156  const JSON_MSG(msg, self);
157 
158  return ast_json_object_string_get(msg->json, "error_msg");
159 }
160 
161 static int message_json_error_msg_set(struct ast_aeap_message *self, const char *error_msg)
162 {
163  JSON_MSG(msg, self);
164 
165  if (ast_json_object_set(msg->json, "error_msg", ast_json_string_create(error_msg))) {
166  return -1;
167  }
168 
169  return 0;
170 }
171 
172 static const struct ast_aeap_message_type message_type_json = {
173  .type_size = sizeof(struct message_json),
174  .type_name = "json",
175  .serial_type = AST_AEAP_DATA_TYPE_STRING,
176  .construct1 = message_json_construct1,
177  .construct2 = message_json_construct2,
178  .destruct = message_json_destruct,
179  .deserialize = message_json_deserialize,
180  .serialize = message_json_serialize,
181  .id = message_json_id,
182  .id_set = message_json_id_set,
183  .name = message_json_name,
184  .data = message_json_data,
185  .is_request = message_json_is_request,
186  .is_response = message_json_is_response,
187  .error_msg = message_json_error_msg,
188  .error_msg_set = message_json_error_msg_set,
189 };
190 
191 const struct ast_aeap_message_type *ast_aeap_message_type_json = &message_type_json;
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
Asterisk main include file. File version handling, generic pbx functions.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
struct ast_json * ast_json_load_buf(const char *buffer, size_t buflen, struct ast_json_error *error)
Parse buffer with known length into a JSON object or array.
Definition: json.c:585
Asterisk External Application Protocol Message API.
struct ast_json * json
Definition: message_json.c:35
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
Iterator for JSON object key/values.
int ast_json_object_update(struct ast_json *object, struct ast_json *other)
Update object with all of the fields of other.
Definition: json.c:426
Asterisk external application JSON message type.
Definition: message_json.c:31
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:810
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
struct ast_aeap_message base
Definition: message_json.c:33
Asterisk JSON abstraction layer.
struct ast_json * ast_json_object_iter_value(struct ast_json_iter *iter)
Get the value from an iterator.
Definition: json.c:455
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
#define ast_json_object_string_get(object, key)
Get a string field from a JSON object.
Definition: json.h:600
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
Asterisk external application base message.
Message type virtual method table.
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:399
Abstract JSON element (object, array, string, int, ...).
struct ast_json_iter * ast_json_object_iter_at(struct ast_json *object, const char *key)
Get an iterator pointing to a specified key in object.
Definition: json.c:443
const struct ast_aeap_message_type * ast_aeap_message_type_json
Asterisk external application JSON message type.
Definition: message_json.c:191