1 module tagion.monitor.Monitor;
2 
3 //import std.bitmanip : BitArray;
4 
5 import tagion.hashgraph.Event : Event;
6 import tagion.hashgraph.HashGraph : HashGraph;
7 import tagion.hashgraph.HashGraphBasic : Tides;
8 import tagion.hashgraph.Round;
9 import tagion.hashgraphview.EventMonitorCallbacks : EventMonitorCallbacks;
10 import tagion.network.ListenerSocket;
11 
12 //import tagion.hashg : EventMonitorCallbacks; //NetCallbacks;
13 //import tagion.gossip.GossipNet : StdGossipNet;
14 import std.format;
15 import std.string;
16 import tagion.Keywords;
17 import tagion.basic.ConsensusExceptions : ConsensusException;
18 import tagion.basic.Message;
19 import tagion.basic.Types : FileExtension;
20 import tagion.basic.basic : EnumText, basename;
21 import tagion.basic.tagionexceptions : TagionException;
22 import tagion.crypto.Types : Pubkey;
23 import tagion.hibon.Document;
24 import tagion.hibon.HiBON;
25 import tagion.hibon.HiBONJSON;
26 import tagion.logger.Logger;
27 import tagion.utils.BitMask;
28 
29 @safe
30 class MonitorException : TagionException {
31     this(immutable(char)[] msg, string file = __FILE__, size_t line = __LINE__) pure {
32         super(msg, file, line);
33     }
34 }
35 
36 HiBON bitarray2bool(const(BitMask) bits) @trusted {
37     auto mask = new HiBON;
38     uint i;
39     foreach (n; bits[]) {
40         mask[i++] = n;
41     }
42     return mask;
43 }
44 
45 //import core.thread : dur, msecs, seconds;
46 import core.thread;
47 import std.concurrency;
48 import std.socket;
49 import std.stdio : writefln, writeln;
50 
51 @safe
52 class MonitorCallBacks : EventMonitorCallbacks {
53     protected enum _params = [
54         "altitude",
55         "mother",
56         "father",
57         "order",
58         "number",
59         "payload",
60         "famous",
61         "famous_votes",
62         "remove",
63         "list",
64         "epoch",
65         "strong_votes",
66         "decided",
67         "decided_count",
68         "witness",
69         "witness_mask",
70         "received_number",
71         "coin",
72         "coin_round",
73         "round",
74         "is_grounded",
75         "count",
76     ];
77     mixin(EnumText!("Params", _params));
78 
79     protected {
80         Tid _socket_thread_id;
81         //       Tid _network_socket_tread_id;
82     }
83     // immutable uint _global_node_id;
84     immutable FileExtension ext;
85 
86     @trusted
87     void socket_send(const(HiBON) hibon) nothrow {
88 
89         void inner_send() {
90             const doc = Document(hibon);
91 
92             with (FileExtension) {
93                 switch (ext) {
94                 case json:
95                     // log("SENDING JSON: %s", doc.toJSON.toString);
96                     _socket_thread_id.send(doc.toJSON.toString);
97                     break;
98                 case hibon:
99                     // log("SENDING HIBON");
100                     _socket_thread_id.send(doc);
101                     break;
102                 default:
103                     throw new MonitorException(message("Bad fileformat %s. Only %s and %s allowed", json, hibon));
104                 }
105             }
106         }
107 
108         try {
109             inner_send();
110         }
111         catch (Exception e) {
112             log.error("Monitor callback failed\n%s", e);
113         }
114     }
115 
116     static HiBON createHiBON(const(Event) e) nothrow {
117         auto hibon = new HiBON;
118 
119         try {
120             hibon[basename!(e.id)] = e.id;
121             hibon[basename!(e.node_id)] = e.node_id;
122             hibon[Params.count] = Event.count;
123             if (e.mother !is null) {
124                 hibon[Params.mother] = e.mother.id;
125             }
126             if (e.father !is null) {
127                 hibon[Params.father] = e.father.id;
128             }
129 
130         }
131         catch (Exception excp) {
132             // empty
133         }
134         return hibon;
135     }
136 
137     const(string) getBitMaskString(const(BitMask) bitmask, uint node_size) @trusted {
138         return format("%*.*s", node_size, node_size, bitmask);
139     }
140 
141     nothrow {
142         import tagion.basic.Debug;
143         import tagion.hibon.HiBONJSON;
144 
145         void connect(const(Event) e) {
146 
147             immutable _witness = e.witness !is null;
148 
149             auto hibon = createHiBON(e);
150 
151             try {
152                 hibon[Params.altitude] = e.altitude;
153                 hibon[Params.order] = e.order;
154                 if (e.hasRound) {
155                     hibon[Params.number] = e.round.number;
156                 }
157                 if (e.mother !is null) {
158                     hibon[Params.mother] = e.mother.id;
159                 }
160                 if (e.father !is null) {
161                     hibon[Params.father] = e.father.id;
162                 }
163                 if (!e.payload.empty) {
164                     hibon[Params.payload] = e.payload;
165                 }
166             }
167             catch (Exception excp) {
168                 //empty
169             }
170 
171             socket_send(hibon);
172         }
173 
174         void witness(const(Event) e) {
175             immutable _witness = e.witness !is null;
176             auto hibon = createHiBON(e);
177             try {
178                 hibon[Params.witness] = _witness;
179             }
180             catch (Exception excp) {
181                 // empty
182             }
183             socket_send(hibon);
184         }
185 
186         void round_received(const(Event) e) {
187             auto hibon = createHiBON(e);
188             try {
189                 hibon[Params.received_number] = e.round_received.number;
190             }
191             catch (Exception excp) {
192                 //empty
193             }
194 
195             socket_send(hibon);
196         }
197 
198         void round_decided(const(Round.Rounder) rounder) {
199             // auto hibon = new HiBON;
200             // auto round = new HiBON;
201             // const r = rounder.last_decided_round;
202 
203             // assumeWontThrow({
204             //     round[Params.number] = r.number;
205             //     round[Params.decided] = true;
206             //     round[Params.decided_count] = rounder.cached_decided_count; // decided_count;
207             // });
208 
209             // socket_send(hibon);
210         }
211 
212         void coin_round(const(Round) r) {
213             // auto hibon = new HiBON;
214             // auto round = new HiBON;
215             // assumeWontThrow({ round[Params.number] = r.number; round[Params.coin] = true; hibon[Params.round] = round; });
216 
217             // socket_send(hibon);
218         }
219 
220         void looked_at(const(Event) e) {
221             // auto hibon=createHiBON(e);
222             // auto round=new HiBON;
223             // round[Keywords.number]=e.round.number;
224             // round[Keywords.looked_at_mask]=bitarray2bool(e.round.looked_at_mask);
225             // round[Keywords.looked_at_count]=cast(int)e.round.looked_at_count;
226             // round[Keywords.seeing_completed]=cast(int)e.round.seeing_completed;
227             // round[Keywords.completed]=cast(int)e.round.completed;
228 
229             // hibon[Keywords.round]=round;
230             // socket_send(hibon);
231         }
232 
233         void famous(const(Event) e) {
234             auto hibon = createHiBON(e);
235 
236             try {
237                 hibon[Params.famous] = e.isFamous();
238             }
239             catch (Exception excp) {
240                 // empty
241             }
242             socket_send(hibon);
243         }
244 
245         void son(const(Event) e) {
246             // auto hibon=createHiBON(e);
247             // hibon[Keywords.son]=e.son.id;
248             // socket_send(hibon);
249         }
250 
251         void daughter(const(Event) e) {
252             // auto hibon=createHiBON(e);
253             // hibon[Keywords.daughter]=e.daughter.id;
254             // socket_send(hibon);
255         }
256 
257         void round(const(Event) e) {
258             auto hibon = createHiBON(e);
259             auto round = new HiBON;
260             try {
261                 round[Params.number] = e.round.number;
262                 round[Keywords.completed] = e.round.decided;
263                 hibon[Keywords.round] = round;
264             }
265             catch (Exception excp) {
266                 //empty
267             }
268             socket_send(hibon);
269         }
270 
271         void forked(const(Event) e) {
272             // auto hibon=createHiBON(e);
273             // hibon[Keywords.forked]=e.forked;
274             // socket_send(hibon);
275         }
276 
277         void remove(const(Event) e) {
278             // set the daugther to be grounded
279             set_grounded(e.daughter);
280 
281             auto hibon = createHiBON(e);
282             try {
283                 hibon[Params.remove] = true;
284             }
285             catch (Exception excp) {
286                 // empty
287             }
288             // assumeWontThrow({ hibon[Params.remove] = true; });
289             socket_send(hibon);
290         }
291 
292         // sets the event to grounded
293         void set_grounded(const(Event) e) {
294             // log("SETTING GROUNDED");
295             // auto hibon = createHiBON(e);
296             // try {
297             //     hibon[Params.is_grounded] = true;
298             // } catch (Exception excp) {
299             //     // empty
300             // }
301             // socket_send(hibon);
302         }
303 
304         void remove(const(Round) r) {
305             // auto hibon = new HiBON;
306             // auto round = new HiBON;
307             // assumeWontThrow({ round[Params.number] = r.number; round[Params.remove] = true; });
308             // // hibon[Keywords.round]=round;
309             // socket_send(hibon);
310         }
311 
312         void strong_vote(const(Event) e, immutable uint votes) {
313             // auto hibon = createHiBON(e);
314             // assumeWontThrow({ hibon[Params.strong_votes] = votes; });
315             // socket_send(hibon);
316         }
317 
318         void iterations(const(Event) e, const uint count) {
319             // auto hibon=createHiBON(e);
320             // hibon[Keywords.iterations]=count;
321             // socket_send(hibon);
322         }
323 
324         void epoch(const(Event[]) received_events) {
325             // auto epoch = new HiBON;
326             // auto hibon = new HiBON;
327             // auto list = new HiBON[received_events.length];
328             // assumeWontThrow({
329             //     foreach (i, e; received_events) {
330             //         auto hibon_e = new HiBON;
331             //         hibon_e[basename!(e.id)] = e.id;
332             //         list[i] = hibon_e;
333             //     }
334             //     hibon[Params.list] = list;
335             //     epoch[Params.epoch] = hibon;
336             // });
337             // socket_send(epoch);
338         }
339 
340         void receive(lazy const(Document) doc) {
341 
342         }
343 
344         void consensus_failure(const(ConsensusException) e) {
345             // writefln("Impl. needed. %s  msg=%s ",  __FUNCTION__, e.msg);
346         }
347 
348         // void wavefront_state_receive(const(Document) doc) {
349         //     //import tagion.Base : cutHex;
350         //     // writefln("Impl. needed. %s  node=%s ",  __FUNCTION__, n.pubkey.cutHex);
351         // }
352 
353         void sent_tidewave(immutable(Pubkey) receiving_channel, const(Tides) tides) {
354             // writefln("Impl. needed. %s  tides=%d ",  __FUNCTION__, tides.length);
355         }
356 
357         void received_tidewave(immutable(Pubkey) sending_channel, const(Tides) tides) {
358             // writefln("Impl. needed. %s  tides=%d ",  __FUNCTION__, tides.length);
359         }
360 
361         void receive(const(Document) doc) {
362             // writefln("Impl. needed. %s  ",  __FUNCTION__);
363         }
364 
365         void send(const(Pubkey) channel, lazy const(Document) doc) {
366             //import tagion.Base : cutHex;
367             // writefln("Impl. needed. %s  channel=%s",  __FUNCTION__, channel.cutHex);
368         }
369 
370         void exiting(const(Pubkey) owner_key, const(HashGraph)) {
371             //import tagion.Base : cutHex;
372             // writefln("Impl. needed. %s  node=%s ",  __FUNCTION__, n.pubkey.cutHex);
373         }
374     }
375 
376     @trusted
377     this(Tid socket_thread_id,
378             const FileExtension dataformat) {
379         this._socket_thread_id = socket_thread_id;
380         this.ext = dataformat;
381     }
382 
383     @trusted
384     void sendMessage(string msg) {
385         _socket_thread_id.send(msg);
386     }
387 
388 }