summaryrefslogtreecommitdiff
path: root/src/dged/jsonrpc.c
blob: 215274ff73a30a6175522d54817d8a20b7e7cf4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "jsonrpc.h"

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

struct jsonrpc_message jsonrpc_parse(const uint8_t *buf, uint64_t size) {

  struct json_result res = json_parse(buf, size);
  if (!res.ok) {
    return (struct jsonrpc_message){
        .type = Jsonrpc_Response,
        .document = (struct json_value){.type = Json_Null, .parent = NULL},
        .message.response = (struct jsonrpc_response){
            .id = (struct json_value){.type = Json_Null},
            .ok = false,
            .value.error =
                (struct jsonrpc_error){
                    .code = 0,
                    .message = s8(res.result.error),
                },
        }};
  }

  struct json_value doc = res.result.document;
  struct json_object *obj = doc.value.object;

  if (json_contains(obj, s8("error"))) {
    struct json_object *err_obj = json_get(obj, s8("error"))->value.object;
    return (struct jsonrpc_message){
        .type = Jsonrpc_Response,
        .document = doc,
        .message.response =
            (struct jsonrpc_response){
                .id = *json_get(obj, s8("id")),
                .ok = false,
                .value.error =
                    (struct jsonrpc_error){
                        .code = json_get(err_obj, s8("code"))->value.number,
                        .message =
                            json_get(err_obj, s8("message"))->value.string,
                    },
            },
    };
  } else if (!json_contains(obj, s8("id"))) {
    // no id == notification
    return (struct jsonrpc_message){
        .type = Jsonrpc_Notification,
        .document = doc,
        .message.notification =
            (struct jsonrpc_notification){
                .method = json_get(obj, s8("method"))->value.string,
                .params = *json_get(obj, s8("params")),
            },
    };
  } else if (json_contains(obj, s8("method"))) {
    // request
    return (struct jsonrpc_message){
        .type = Jsonrpc_Request,
        .document = doc,
        .message.request = (struct jsonrpc_request){
            .id = *json_get(obj, s8("id")),
            .method = json_get(obj, s8("method"))->value.string,
            .params = *json_get(obj, s8("params")),
        }};
  }

  // response
  return (struct jsonrpc_message){
      .type = Jsonrpc_Response,
      .document = doc,
      .message.response = (struct jsonrpc_response){
          .id = *json_get(obj, s8("id")),
          .ok = true,
          .value.result = *json_get(obj, s8("result")),
      }};
}

struct s8 jsonrpc_format_request(struct json_value id, struct s8 method,
                                 struct s8 params) {
  const char *fmt = "{ \"jsonrpc\": \"2.0\", \"id\": %d, \"method\": \"%.*s\", "
                    "\"params\": %.*s }";
  size_t s = snprintf(NULL, 0, fmt, (int)id.value.number, method.l, method.s,
                      params.l, params.s);
  char *buf = calloc(s + 1, 1);
  snprintf(buf, s + 1, fmt, (int)id.value.number, method.l, method.s, params.l,
           params.s);

  return (struct s8){
      .s = (uint8_t *)buf,
      .l = s,
  };
}

struct s8 jsonrpc_format_response(struct json_value id, struct s8 result) {
  const char *fmt = "{ \"jsonrpc\": \"2.0\", \"id\": %d, \"result\": %.*s }";
  size_t s = snprintf(NULL, 0, fmt, (int)id.value.number, result.l, result.s);
  char *buf = calloc(s + 1, 1);
  snprintf(buf, s + 1, fmt, (int)id.value.number, result.l, result.s);

  return (struct s8){
      .s = (uint8_t *)buf,
      .l = s,
  };
}

struct s8 jsonrpc_format_notification(struct s8 method, struct s8 params) {
  const char *fmt = "{ \"jsonrpc\": \"2.0\", \"method\": \"%.*s\", "
                    "\"params\": %.*s }";
  size_t s = snprintf(NULL, 0, fmt, method.l, method.s, params.l, params.s);
  char *buf = calloc(s + 1, 1);
  snprintf(buf, s + 1, fmt, method.l, method.s, params.l, params.s);

  return (struct s8){
      .s = (uint8_t *)buf,
      .l = s,
  };
}