disaggregate templates
parent
adbb2c374b
commit
7ce411b643
@ -1,9 +1,48 @@
|
|||||||
#include "MyService.proxy.h"
|
#include "MyService.proxy.h"
|
||||||
|
#include "rpc/RpcChannel.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RpcChannelFifoClient : public RpcChannel {
|
||||||
|
public:
|
||||||
|
RpcChannelFifoClient(const char* inPipe, const char* outPipe) {
|
||||||
|
fdOut = open(inPipe, O_WRONLY);
|
||||||
|
fdIn = open(outPipe, O_RDONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(const std::string& data) override {
|
||||||
|
::write(fdOut, data.c_str(), data.size());
|
||||||
|
::write(fdOut, "\n", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string receive() override {
|
||||||
|
char buf[4096];
|
||||||
|
int n = ::read(fdIn, buf, sizeof(buf) - 1);
|
||||||
|
if (n <= 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
buf[n] = 0;
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fdIn{};
|
||||||
|
int fdOut{};
|
||||||
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
MyServiceProxy proxy("/tmp/rpc_in", "/tmp/rpc_out");
|
mkfifo("/tmp/rpc_in", 0666);
|
||||||
|
mkfifo("/tmp/rpc_out", 0666);
|
||||||
|
|
||||||
|
RpcChannelFifoClient ch("/tmp/rpc_in", "/tmp/rpc_out");
|
||||||
|
MyServiceProxy proxy(ch);
|
||||||
|
|
||||||
int r = proxy.add(7, 8);
|
int r = proxy.add(7, 8);
|
||||||
std::cout << "RESULT: " << r << std::endl;
|
std::cout << "RESULT: " << r << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class RpcChannel {
|
||||||
|
public:
|
||||||
|
virtual ~RpcChannel() = default;
|
||||||
|
|
||||||
|
virtual void send(const std::string& data) = 0;
|
||||||
|
virtual std::string receive() = 0;
|
||||||
|
};
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
#include "RpcChannel.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RpcChannelFifo : public RpcChannel {
|
||||||
|
public:
|
||||||
|
RpcChannelFifo(const char* inPipe, const char* outPipe) {
|
||||||
|
fdOut = open(inPipe, O_WRONLY);
|
||||||
|
fdIn = open(outPipe, O_RDONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(const std::string& data) override {
|
||||||
|
::write(fdOut, data.c_str(), data.size());
|
||||||
|
::write(fdOut, "\n", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string receive() override {
|
||||||
|
char buf[4096];
|
||||||
|
int n = ::read(fdIn, buf, sizeof(buf) - 1);
|
||||||
|
if (n <= 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
buf[n] = 0;
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fdIn{};
|
||||||
|
int fdOut{};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RpcChannel.h"
|
||||||
|
#include "RpcSerializer.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RpcClient {
|
||||||
|
public:
|
||||||
|
explicit RpcClient(RpcChannel& ch) : channel(ch) {}
|
||||||
|
|
||||||
|
template<typename Ret, typename... Args>
|
||||||
|
Ret call(const std::string& method, const Args&... args) {
|
||||||
|
std::ostringstream out;
|
||||||
|
|
||||||
|
// имя метода
|
||||||
|
RpcSerializer::write(out, method);
|
||||||
|
|
||||||
|
// аргументы
|
||||||
|
(RpcSerializer::write(out, args), ...);
|
||||||
|
|
||||||
|
// отправить
|
||||||
|
channel.send(out.str());
|
||||||
|
|
||||||
|
// получить ответ
|
||||||
|
std::string resp = channel.receive();
|
||||||
|
std::istringstream in(resp);
|
||||||
|
|
||||||
|
return RpcSerializer::read<Ret>(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RpcChannel& channel;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RpcSerializer.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class RpcInvoker {
|
||||||
|
public:
|
||||||
|
template<typename Obj, typename Ret, typename... Args>
|
||||||
|
void registerMethod(Obj* instance,
|
||||||
|
const std::string& name,
|
||||||
|
Ret (Obj::*method)(Args...)) {
|
||||||
|
handlers[name] =
|
||||||
|
[instance, method](const std::string& req) -> std::string {
|
||||||
|
std::istringstream in(req);
|
||||||
|
|
||||||
|
// пропустить имя метода
|
||||||
|
std::string skip;
|
||||||
|
in >> skip;
|
||||||
|
|
||||||
|
// читать аргументы и вызвать метод
|
||||||
|
return callMethod<Ret, Obj, Args...>(instance, method, in);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string dispatch(const std::string& request) {
|
||||||
|
std::istringstream in(request);
|
||||||
|
std::string method;
|
||||||
|
in >> method;
|
||||||
|
|
||||||
|
auto it = handlers.find(method);
|
||||||
|
if (it == handlers.end()) {
|
||||||
|
return "ERR";
|
||||||
|
}
|
||||||
|
|
||||||
|
return it->second(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename Ret, typename Obj, typename... Args>
|
||||||
|
static std::string callMethod(Obj* obj,
|
||||||
|
Ret (Obj::*method)(Args...),
|
||||||
|
std::istringstream& in) {
|
||||||
|
auto tuple = readArgs<Args...>(in);
|
||||||
|
Ret result =
|
||||||
|
std::apply(method, std::tuple_cat(std::make_tuple(obj), tuple));
|
||||||
|
|
||||||
|
std::ostringstream out;
|
||||||
|
RpcSerializer::write(out, result);
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static std::tuple<Args...> readArgs(std::istringstream& in) {
|
||||||
|
return std::tuple<Args...>{RpcSerializer::read<Args>(in)...};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string,
|
||||||
|
std::function<std::string(const std::string&)>>
|
||||||
|
handlers;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RpcSerializer {
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
static void write(std::ostringstream& out, const T& v) {
|
||||||
|
out << v << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static T read(std::istringstream& in) {
|
||||||
|
T v;
|
||||||
|
in >> v;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1,31 +1,58 @@
|
|||||||
#include "MyService.h"
|
#include "MyService.h"
|
||||||
#include "MyService.skeleton.h"
|
#include "MyService.skeleton.h"
|
||||||
|
|
||||||
|
#include "rpc/RpcChannel.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RpcChannelFifoServer : public RpcChannel {
|
||||||
|
public:
|
||||||
|
RpcChannelFifoServer(const char* inPipe, const char* outPipe) {
|
||||||
|
fdIn = open(inPipe, O_RDONLY);
|
||||||
|
fdOut = open(outPipe, O_WRONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(const std::string& data) override {
|
||||||
|
::write(fdOut, data.c_str(), data.size());
|
||||||
|
::write(fdOut, "\n", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string receive() override {
|
||||||
|
char buf[4096];
|
||||||
|
int n = ::read(fdIn, buf, sizeof(buf) - 1);
|
||||||
|
if (n <= 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
buf[n] = 0;
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fdIn{};
|
||||||
|
int fdOut{};
|
||||||
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
mkfifo("/tmp/rpc_in", 0666);
|
mkfifo("/tmp/rpc_in", 0666);
|
||||||
mkfifo("/tmp/rpc_out", 0666);
|
mkfifo("/tmp/rpc_out", 0666);
|
||||||
|
|
||||||
int fdIn = open("/tmp/rpc_in", O_RDONLY);
|
RpcChannelFifoServer ch("/tmp/rpc_in", "/tmp/rpc_out");
|
||||||
int fdOut = open("/tmp/rpc_out", O_WRONLY);
|
|
||||||
|
|
||||||
MyService realObj;
|
MyService realObj;
|
||||||
MyServiceSkeleton skeleton(realObj);
|
MyServiceSkeleton skeleton(realObj);
|
||||||
|
|
||||||
char buf[256];
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int n = read(fdIn, buf, sizeof(buf)-1);
|
std::string req = ch.receive();
|
||||||
if (n <= 0) break;
|
if (req.empty()) {
|
||||||
|
break;
|
||||||
buf[n] = 0;
|
}
|
||||||
std::string req(buf);
|
std::string resp = skeleton.dispatch(req);
|
||||||
std::string resp = skeleton.handleRequest(req);
|
ch.send(resp);
|
||||||
|
|
||||||
write(fdOut, resp.c_str(), resp.size());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,38 +1,20 @@
|
|||||||
#include "{{ cls.name }}.proxy.h"
|
#include "{{ cls.name }}.proxy.h"
|
||||||
#include <unistd.h>
|
#include "rpc/RpcClient.h"
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
{{ cls.name }}Proxy::{{ cls.name }}Proxy(const char* pipeIn, const char* pipeOut) {
|
class {{ cls.name }}Proxy::Impl {
|
||||||
fdIn = open(pipeIn, O_WRONLY);
|
public:
|
||||||
if (fdIn < 0) {
|
explicit Impl(RpcChannel& ch)
|
||||||
perror("open pipeIn");
|
: client(ch) {}
|
||||||
}
|
|
||||||
fdOut = open(pipeOut, O_RDONLY);
|
RpcClient client;
|
||||||
if (fdOut < 0) {
|
};
|
||||||
perror("open pipeOut");
|
|
||||||
}
|
{{ cls.name }}Proxy::{{ cls.name }}Proxy(RpcChannel& ch)
|
||||||
}
|
: impl(new Impl(ch)) {}
|
||||||
|
|
||||||
{% for m in cls.methods %}
|
{% for m in cls.methods %}
|
||||||
{{ m.return_type }} {{ cls.name }}Proxy::{{ m.name }}({% for a in m.args %}{{ a.type }} {{ a.name }}{% if not loop.last %}, {% endif %}{% endfor %}) {
|
{{ m.return_type }} {{ cls.name }}Proxy::{{ m.name }}({% for a in m.args %}{{ a.type }} {{ a.name }}{% if not loop.last %}, {% endif %}{% endfor %}) {
|
||||||
std::ostringstream out;
|
return impl->client.call<{{ m.return_type }}>("{{ cls.name }}.{{ m.name }}"{% for a in m.args %}, {{ a.name }}{% endfor %});
|
||||||
out << "{{ m.name }}";
|
|
||||||
{% for a in m.args %}
|
|
||||||
out << " " << {{ a.name }};
|
|
||||||
{% endfor %}
|
|
||||||
out << "\n";
|
|
||||||
std::string s = out.str();
|
|
||||||
write(fdIn, s.c_str(), (ssize_t)s.size());
|
|
||||||
|
|
||||||
char buf[256];
|
|
||||||
ssize_t n = read(fdOut, buf, sizeof(buf)-1);
|
|
||||||
if (n <= 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
buf[n] = '\0';
|
|
||||||
return std::atoi(buf);
|
|
||||||
}
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
#include "rpc/RpcChannel.h"
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
class {{ cls.name }}Proxy {
|
class {{ cls.name }}Proxy {
|
||||||
public:
|
public:
|
||||||
{{ cls.name }}Proxy(const char* pipeIn, const char* pipeOut);
|
explicit {{ cls.name }}Proxy(RpcChannel& ch);
|
||||||
{% for m in cls.methods %}
|
{% for m in cls.methods %}
|
||||||
{{ m.return_type }} {{ m.name }}({% for a in m.args %}{{ a.type }} {{ a.name }}{% if not loop.last %}, {% endif %}{% endfor %});
|
{{ m.return_type }} {{ m.name }}({% for a in m.args %}{{ a.type }} {{ a.name }}{% if not loop.last %}, {% endif %}{% endfor %});
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fdIn;
|
class Impl;
|
||||||
int fdOut;
|
Impl* impl;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
#include "{{ cls.name }}.skeleton.h"
|
#include "{{ cls.name }}.skeleton.h"
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
{{ cls.name }}Skeleton::{{ cls.name }}Skeleton({{ cls.name }}& o) : obj(o) {}
|
{{ cls.name }}Skeleton::{{ cls.name }}Skeleton({{ cls.name }}& obj)
|
||||||
|
{
|
||||||
|
{% for m in cls.methods %}
|
||||||
|
invoker.registerMethod(&obj,
|
||||||
|
"{{ cls.name }}.{{ m.name }}",
|
||||||
|
&{{ cls.name }}::{{ m.name }});
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
std::string {{ cls.name }}Skeleton::handleRequest(const std::string& req) {
|
std::string {{ cls.name }}Skeleton::dispatch(const std::string& req) {
|
||||||
std::istringstream in(req);
|
return invoker.dispatch(req);
|
||||||
std::string method;
|
|
||||||
in >> method;
|
|
||||||
{% for m in cls.methods %}
|
|
||||||
if (method == "{{ m.name }}") {
|
|
||||||
{% for a in m.args %}int {{ a.name }}; in >> {{ a.name }};
|
|
||||||
{% endfor %}
|
|
||||||
int res = obj.{{ m.name }}({% for a in m.args %}{{ a.name }}{% if not loop.last %}, {% endif %}{% endfor %});
|
|
||||||
return std::to_string(res);
|
|
||||||
}
|
|
||||||
{% endfor %}
|
|
||||||
return std::string("ERR");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "{{ cls.name }}.h"
|
#include "{{ cls.name }}.h"
|
||||||
|
#include "rpc/RpcInvoker.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class {{ cls.name }}Skeleton {
|
class {{ cls.name }}Skeleton {
|
||||||
public:
|
public:
|
||||||
{{ cls.name }}Skeleton({{ cls.name }}& obj);
|
explicit {{ cls.name }}Skeleton({{ cls.name }}& obj);
|
||||||
std::string handleRequest(const std::string& req);
|
|
||||||
|
std::string dispatch(const std::string& req);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
{{ cls.name }}& obj;
|
RpcInvoker invoker;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue