Joedb 10.4.6
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Client.h
Go to the documentation of this file.
1#ifndef joedb_rpc_Client_declared
2#define joedb_rpc_Client_declared
3
8#include "joedb/Thread_Safe.h"
12
13#include <vector>
14
15namespace joedb::rpc
16{
17 class Client: public Ping_Client
18 {
19 private:
20 Buffer<13> buffer;
22 const std::vector<Signature> &signatures;
23
24 int64_t session_id;
25
26 void handshake()
27 {
28 const SHA_256::Hash h = get_hash(signatures);
29
30 {
31 Lock<Channel&> lock(channel);
32 lock->write((const char *)h.data(), h.size() * sizeof h[0]);
33 lock->read(buffer.data, 9);
34 }
35
36 buffer.index = 0;
37 if (buffer.read<char>() != 'H')
38 throw Exception("failed handshake");
39 session_id = buffer.read<int64_t>();
40 }
41
42 Thread_Safe<Channel&> &get_channel() override final {return channel;}
43 void locked_ping(Lock<Channel&> &lock) override final
44 {
45 char c = 'P';
46 lock->write(&c, 1);
47 lock->read(&c, 1);
48 }
49 Keep_Alive_Thread keep_alive;
50
51 const int64_t max_message_size;
52
53 void throw_invalid_size()
54 {
55 throw Exception("invalid size");
56 }
57
58 public:
60 (
61 Channel &channel,
62 const std::vector<Signature> &signatures,
63 std::chrono::milliseconds keep_alive_interval = std::chrono::milliseconds(0),
64 int64_t max_message_size = 1 << 24
65 ):
66 channel(channel),
67 signatures(signatures),
68 keep_alive(*this, keep_alive_interval),
69 max_message_size(max_message_size)
70 {
71 handshake();
72 keep_alive.start();
73 }
74
75 void call(int64_t procedure_id, Memory_File &file)
76 {
77 Lock<Channel&> lock(channel);
78
79 auto &signature = signatures[procedure_id];
80
81 {
82 // Check that the prolog is matching?
83 const int64_t from = int64_t(signature.prolog.size());
84 const int64_t until = file.get_size();
85
86 buffer.index = 0;
87 buffer.write<char>('C');
88 buffer.write<int64_t>(procedure_id);
89 buffer.write<int64_t>(until);
90
91 // Could be optimized into one single write?
92 lock->write(buffer.data, buffer.index);
93 lock->write(file.get_data().data() + from, until - from);
94 lock->read(buffer.data, 9);
95 }
96
97 buffer.index = 0;
98 const char reply = buffer.read<char>();
99
100 if (reply == 'C')
101 {
102 const size_t from = file.get_data().size();
103 const int64_t until = buffer.read<int64_t>();
104
105 if (until < int64_t(from) || until > max_message_size)
106 throw_invalid_size();
107
108 file.get_data().resize(size_t(until));
109 lock->read(file.get_data().data() + from, size_t(until) - from);
110 file.pwrite((const char *)&until, 8, 0);
111 file.pwrite((const char *)&until, 8, 8);
112 }
113 else
114 {
115 const int64_t n = buffer.read<int64_t>();
116
117 if (n < 0 || n > max_message_size)
118 throw_invalid_size();
119
120 std::string error_message;
121 error_message.resize(n);
122 lock->read(error_message.data(), n);
123 throw Exception(error_message);
124 }
125 }
126
128 {
129 try
130 {
131 Lock<Channel&> lock(channel);
132 lock->write("Q", 1);
133 }
134 catch (...)
135 {
136 }
137 }
138 };
139}
140
141#endif
size_t index
Definition Buffer.h:20
void write(T x)
Definition Buffer.h:23
char data[size+extra_size]
Definition Buffer.h:19
void pwrite(const char *buffer, size_t size, int64_t offset) override
Write a range of bytes. Extend file size if necessary.
std::string & get_data()
Definition Memory_File.h:23
int64_t get_size() const override
Get the size of the file, or -1 if it is unknown.
Definition Memory_File.h:27
std::array< uint32_t, 8 > Hash
Definition SHA_256.h:59
Client(Channel &channel, const std::vector< Signature > &signatures, std::chrono::milliseconds keep_alive_interval=std::chrono::milliseconds(0), int64_t max_message_size=1<< 24)
Definition Client.h:60
void call(int64_t procedure_id, Memory_File &file)
Definition Client.h:75
SHA_256::Hash get_hash(const std::vector< Signature > &signatures)
Compute hash code for a collection of procedure signatures.
Definition get_hash.cpp:9