summaryrefslogtreecommitdiffstats
path: root/plugins/samples/ClientCtx.c
blob: 4d8e7205a9b68ed569f59bae59a654640c0a10c6 (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
/*
 * Copyright (C) 2015, 2016 "IoT.bzh"
 * Author "Fulup Ar Foll"
 *
 * 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, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <json-c/json.h>

#include "afb-plugin.h"

typedef struct {
  /* 
   * client context is attached a session but private to a each plugin.
   * Context is passed to each API under request->context
   * 
   * Note:
   *  -client context is free when a session is closed. Developer should not
   *   forget that even if context is private to each plugin, session is unique
   *   to a client. When session close, every plugin are notified to free there
   *   private context.
   *  -by default standard "free" function from libc is used to free context.
   *   Developer may define it own under plugin->freeCB. This call received
   *   FreeCtxCb(void *ClientCtx, void*PluginHandle, char*SessionUUID) if
   *   FreeCtxCb=(void*)-1 then context wont be free by session manager.
   *  -when an API use AFB_SESSION_RESET this close the session and each plugin
   *   will be notified to free ressources.
   */
    
  int  count;
  char *abcd;
  
} MyClientContextT;

// This function is call at session open time. Any client trying to 
// call it with an already open session will be denied.
// Ex: http://localhost:1234/api/context/create?token=123456789
static void myCreate (struct afb_req request)
{
    MyClientContextT *ctx = malloc (sizeof (MyClientContextT));

    // store something in our plugin private client context
    ctx->count = 0;
    ctx->abcd  = "SomeThingUseful";        

    afb_req_context_set(request, ctx, free);
    afb_req_success_f(request, NULL, "SUCCESS: create client context for plugin [%s]", ctx->abcd);
}

// This function can only be called with a valid token. Token should be renew before
// session timeout a standard renew api is avaliable at /api/token/renew this API
// can be called automatically with <token-renew> HTML5 widget.
// ex: http://localhost:1234/api/context/action?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx
static void myAction (struct afb_req request)
{
    MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request);
    
    // store something in our plugin private client context
    ctx->count++;
    afb_req_success_f(request, NULL, "SUCCESS: plugin [%s] Check=[%d]\n", ctx->abcd, ctx->count);
}

// After execution of this function, client session will be close and if they
// created a context [request->context != NULL] every plugins will be notified
// that they should free context resources.
// ex: http://localhost:1234/api/context/close?token=xxxxxx-xxxxxx-xxxxx-xxxxx-xxxxxx
static void myClose (struct afb_req request)
{
    MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request);
    
    // store something in our plugin private client context
    ctx->count++;
    afb_req_success_f(request, NULL, "SUCCESS: plugin [%s] Close=[%d]\n", ctx->abcd, ctx->count);
}

// NOTE: this sample does not use session to keep test a basic as possible
//       in real application most APIs should be protected with AFB_SESSION_CHECK
static const struct AFB_restapi pluginApis[]= {
  {"create", AFB_SESSION_CREATE, myCreate  , "Create a new session"},
  {"action", AFB_SESSION_CHECK , myAction  , "Use Session Context"},
  {"close" , AFB_SESSION_CLOSE , myClose   , "Free Context"},
  {NULL}
};

static const struct AFB_plugin plugin_desc = {
	.type = AFB_PLUGIN_JSON,
	.info = "Sample of Client Context Usage",
	.prefix = "context",
	.apis = pluginApis,
};

const struct AFB_plugin *pluginRegister (const struct AFB_interface *itf)
{
	return &plugin_desc;
}
(main: \"%s\") (sub: " "\"%s\")", this->layer_id, l.name.c_str(), l.main_match.c_str(), l.sub_match.c_str()); return l; }); } HMI_DEBUG("wm", "layer_id:%d is_normal_layout_only:%d\n", this->layer_id, this->is_normal_layout_only); } struct result<struct layer_map> to_layer_map(nlohmann::json const &j) { try { layer_map stl{}; auto m = j["mappings"]; std::transform(std::cbegin(m), std::cend(m), std::inserter(stl.mapping, stl.mapping.end()), [](nlohmann::json const &j) { return std::pair<int, struct layer>( j.value("layer_id", -1), layer(j)); }); // TODO: add sanity checks here? // * check for double IDs // * check for double names/roles stl.layers.reserve(m.size()); std::transform(std::cbegin(stl.mapping), std::cend(stl.mapping), std::back_inserter(stl.layers), [&stl](std::pair<int, struct layer> const &k) { stl.roles.emplace_back( std::make_pair(k.second.role, k.second.layer_id)); return unsigned(k.second.layer_id); }); std::sort(stl.layers.begin(), stl.layers.end()); for (auto i : stl.mapping) { if (i.second.name.empty()) { return Err<struct layer_map>("Found mapping w/o name"); } if (i.second.layer_id == -1) { return Err<struct layer_map>("Found invalid/unset IDs in mapping"); } } auto msi = j.find("main_surface"); if (msi != j.end()) { stl.main_surface_name = msi->value("surface_role", ""); stl.main_surface = -1; } return Ok(stl); } catch (std::exception &e) { return Err<struct layer_map>(e.what()); } } optional<int> layer_map::get_layer_id(int surface_id) { auto i = this->surfaces.find(surface_id); if (i != this->surfaces.end()) { return optional<int>(i->second); } return nullopt; } optional<int> layer_map::get_layer_id(std::string const &role) { for (auto const &r : this->roles) { auto re = std::regex(r.first); if (std::regex_match(role, re)) { HMI_DEBUG("wm", "role %s matches layer %d", role.c_str(), r.second); return optional<int>(r.second); } } HMI_DEBUG("wm", "role %s does NOT match any layer", role.c_str()); return nullopt; } json layer::to_json() const { auto is_full = this->rect == compositor::full_rect; json r{}; if (is_full) { r = {{"type", "full"}}; } else { r = {{"type", "rect"}, {"rect", {{"x", this->rect.x}, {"y", this->rect.y}, {"width", this->rect.w}, {"height", this->rect.h}}}}; } return { {"name", this->name}, {"role", this->role}, {"layer_id", this->layer_id}, {"area", r}, }; } json layer_map::to_json() const { json j{}; for (auto const &i : this->mapping) { j.push_back(i.second.to_json()); } return j; } } // namespace wm