summaryrefslogtreecommitdiffstats
path: root/controller/ctl-action.c
blob: 8955adc5fb2a04175d28f7102a0eb7eddb001efe (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * Copyright (C) 2016 "IoT.bzh"
 * Author Fulup Ar Foll <fulup@iot.bzh>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, something express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Reference:
 *   Json load using json_unpack https://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

#include "ctl-config.h"


int ActionExecOne(CtlActionT* action, json_object *queryJ) {
    int err;

    switch (action->type) {
        case CTL_TYPE_API:
        {
            json_object *returnJ;

            // if query is empty increment usage count and pass args else
            // create new JSON object
            if (!queryJ || json_object_get_type(queryJ) != json_type_object) {
                if(action->argsJ) {
                    json_object_get(action->argsJ);
                    queryJ = action->argsJ;
                }
                else {
                    queryJ = json_object_new_object();
                }
            } else if (action->argsJ) {

                // Merge queryJ and argsJ before sending request
                if (json_object_get_type(action->argsJ) == json_type_object) {

                    json_object_object_foreach(action->argsJ, key, val) {
                        json_object_object_add(queryJ, key, val);
                    }
                } else {
                    json_object_object_add(queryJ, "args", action->argsJ);
                }
            }
            json_object_object_add(queryJ, "label", json_object_new_string(action->source.label));

            int err = afb_service_call_sync(action->api, action->call, queryJ, &returnJ);
            if (err) {
                static const char*format = "ActionExecOne(Api) api=%s verb=%s args=%s";
                AFB_ERROR(format, action->api, action->call, action->source.label);
                goto OnErrorExit;
            }
            break;
        }

#ifdef CONTROL_SUPPORT_LUA
        case CTL_TYPE_LUA:
            err = LuaCallFunc(action, queryJ);
            if (err) {
                AFB_ERROR("ActionExecOne(Lua) label=%s func=%s args=%s", action->source.label, action->call, json_object_get_string(action->argsJ));
                goto OnErrorExit;
            }
            break;
#endif

        case CTL_TYPE_CB:
            err = (*action->actionCB) (&action->source, action->argsJ, queryJ);
            if (err) {
                AFB_ERROR("ActionExecOne(Callback) label%s func=%s args=%s", action->source.label, action->call, json_object_get_string(action->argsJ));
                goto OnErrorExit;
            }
            break;

        default:
        {
            AFB_ERROR("ActionExecOne(unknown) API type label=%s", action->source.label);
            goto OnErrorExit;
        }
    }

    return 0;

OnErrorExit:
    return -1;
}


// unpack individual action object

int ActionLoadOne(CtlActionT *action, json_object *actionJ) {
    char *api = NULL, *verb = NULL, *lua = NULL;
    int err, modeCount = 0;
    json_object *callbackJ=NULL;

    err = wrap_json_unpack(actionJ, "{ss,s?s,s?o,s?s,s?s,s?s,s?o !}"
            , "label", &action->source.label, "info", &action->source.info, "callback", &callbackJ, "lua", &lua, "api", &api, "verb", &verb, "args", &action->argsJ);
    if (err) {
        AFB_ERROR("ACTION-LOAD-ONE Missing something label|info|callback|lua|(api+verb)|args in:\n--  %s", json_object_get_string(actionJ));
        goto OnErrorExit;
    }

    if (lua) {
        action->type = CTL_TYPE_LUA;
        action->call = lua;
        modeCount++;
    }

    if (api && verb) {
        action->type = CTL_TYPE_API;
        action->api = api;
        action->call = verb;
        modeCount++;
    }

    if (callbackJ) {
        action->type = CTL_TYPE_CB;
        modeCount++;
        err = PluginGetCB (action, callbackJ);
        if (err) goto OnErrorExit;

    }

    // make sure at least one mode is selected
    if (modeCount == 0) {
        AFB_ERROR("ACTION-LOAD-ONE No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
        goto OnErrorExit;
    }

    if (modeCount > 1) {
        AFB_ERROR("ACTION-LOAD-ONE:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
        goto OnErrorExit;
    }
    return 0;

OnErrorExit:
    return 1;
};

CtlActionT *ActionLoad(json_object *actionsJ) {
    int err = 0;
    CtlActionT *actions;

    // action array is close with a nullvalue;
    if (json_object_get_type(actionsJ) == json_type_array) {
        int count = json_object_array_length(actionsJ);
        actions = calloc(count + 1, sizeof (CtlActionT));

        for (int idx = 0; idx < count; idx++) {
            json_object *actionJ = json_object_array_get_idx(actionsJ, idx);
            err = ActionLoadOne(&actions[idx], actionJ);
            if (err) goto OnErrorExit;
        }

    } else {
        actions = calloc(2, sizeof (CtlActionT));
        err = ActionLoadOne(&actions[0], actionsJ);
        if (err) goto OnErrorExit;
    }

    return actions;

OnErrorExit:
    return NULL;

}