aboutsummaryrefslogtreecommitdiffstats
path: root/src/afb-wsj1.hpp
blob: fc990928615580aa69faa4a6e42fc756c2f78b5a (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
/*
 * Copyright (C) 2015-2018 "IoT.bzh"
 * Author Gabin Fodop
 * Author José Bollo <jose.bollo@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, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#define _GNU_SOURCE

#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>

extern "C" {
#include <json-c/json.h>
#include <afb-wsj1.h>
#include <afb-ws-client.h>
}

#include <iostream>
#include <string>
#include <functional>
#include <thread>
#include <mutex>

#include <systemd/sd-event.h>

namespace afb {

class wsj1 {
public:
	wsj1() noexcept = default;
	wsj1(const wsj1 &other) = delete;
	wsj1(wsj1 &&other) noexcept { wsj1_ = other.wsj1_; other.wsj1_ = nullptr; }
	wsj1(const std::string &uri) { connect(uri); }
	wsj1(const char *uri) { connect(uri); }
	~wsj1() { if (wsj1_) disconnect(); }
	void connect(const std::string &uri) { connect(uri.c_str()); }
	void connect(const char *uri);
	void disconnect();
	void call(const char *api, const char *verb, char *request, std::function<void(const char*)> onreply);
#if 0
	void call(const char *api, const char *verb, json_object *request, std::function<void(json_object*)> &onreply)
	{
		call(api,verb,json_object_to_json_string_ext(request,JSON_C_TO_STRING_PLAIN),[](const char *x){onreply(std::string(x));});
	};
	void call(const std::string &api, const std::string &verb, const std::string &request, std::function<void(std::string&)> &onreply)
	{
		call(api.c_str(), verb.c_str(), request.c_str(), [=](const char *x){onreply(std::string(x));});
	}
#endif
public:
	class msg {
		friend class wsj1;
		msg(afb_wsj1_msg *msg) : msg_{msg} {}
		afb_wsj1_msg *msg_;
	public:
	};
private:
	afb_wsj1 *wsj1_ = nullptr;
private:
	static struct afb_wsj1_itf wsj1_itf;
	static void itf_hangup_(void *closure, struct afb_wsj1 *wsj1);
	static void itf_on_call_(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg);
	static void itf_on_event_(void *closure, const char *event, struct afb_wsj1_msg *msg);
private:
	void on_hangup_(struct afb_wsj1 *wsj1) {}
	void on_call_(const char *api, const char *verb, struct afb_wsj1_msg *msg) {}
	void on_event_(const char *event, struct afb_wsj1_msg *msg);
private:
	static sd_event *eloop_();
private:
	static void on_reply_(void *closure, struct afb_wsj1_msg *msg);
};

struct afb_wsj1_itf wsj1::wsj1_itf = {
	wsj1::itf_hangup_,
	wsj1::itf_on_call_,
	wsj1::itf_on_event_
};

void wsj1::connect(const char *uri) {
	if (wsj1_)
		throw std::runtime_error("already-connected");
	wsj1_ = afb_ws_client_connect_wsj1(eloop_(), uri, &wsj1_itf, reinterpret_cast<void*>(this));
	if (!wsj1_)
		throw std::runtime_error("connection-failed");
}

void wsj1::disconnect() {
	if (!wsj1_)
		throw std::runtime_error("not-connected");
	afb_wsj1_unref(wsj1_);
	wsj1_ = nullptr;
}

void wsj1::itf_on_event_(void *closure, const char *event, struct afb_wsj1_msg *msg) {
	reinterpret_cast<wsj1*>(closure)->on_event_(event, msg);
}

void wsj1::on_event_(const char *event, struct afb_wsj1_msg *msg) {

}

void wsj1::call(const char *api, const char *verb, char *request, std::function<void(const char*)> onreply) {
	if (!wsj1_)
		throw std::runtime_error("not-connected");
	std::function<void(const char*)> *onrep = new std::function<void(const char*)>(onreply);
	afb_wsj1_call_s(wsj1_,api,verb,request,on_reply_,reinterpret_cast<void*>(onrep));
}

void wsj1::on_reply_(void *closure, struct afb_wsj1_msg *msg) {
	std::function<void(const char*)> *onreply = reinterpret_cast<std::function<void(const char*)>*>(closure);
	(*onreply)(afb_wsj1_msg_object_s(msg));
	afb_wsj1_msg_unref(msg);
	delete onreply;
}

sd_event *wsj1::eloop_() {
	static sd_event *el = nullptr;
	static std::mutex lock;
	std::lock_guard<std::mutex> guard(lock);
	if (!el) {
		if (sd_event_new(&el) == 0) {
		    std::thread t(sd_event_loop, el);
		    t.detach();
		}
	}
}



}
// faire un test qui verifi le fonctionnement de la classe,
// il faut faire bien attention avec la fonction call qui doit se terminer 	avan tle programme, un get char ou un cin 
// ecrire lma fonction on reply qui affichhe le resultat de la requete à l'ecran