-
Notifications
You must be signed in to change notification settings - Fork 0
/
knownnodes.html
392 lines (376 loc) · 16 KB
/
knownnodes.html
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>knownnodes.html</title>
<style type="text/css">
.end-element { fill : #FFCCFF; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.3.0/raphael.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowchart/1.17.1/flowchart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.1/js/bootstrap.bundle.min.js"></script>
<!-- <script src="../release/flowchart.min.js"></script> -->
<script>
window.onload = function () {
var btn = document.getElementById("run"),
cd = document.getElementById("code"),
chart;
(btn.onclick = function () {
var code = cd.value;
if (chart) {
chart.clean();
}
chart = flowchart.parse(code);
chart.drawSVG('canvas', {
'x': 0,
'y': 0,
'line-width': 3,
//'maxWidth': 15,//ensures the flowcharts fits within a certain width
'line-length': 50,
'text-margin': 10,
'font-size': 14,
'font': 'normal',
'font-family': 'Helvetica',
'font-weight': 'normal',
'font-color': 'black',
'line-color': 'black',
'element-color': 'black',
'fill': 'white',
'yes-text': 'yes',
'no-text': 'no',
'arrow-end': 'block',
'scale': 1,
'symbols': {
'start': {
'font-size': 14,
'font-color': 'yellow',
'element-color': 'blue',
'fill': 'green',
'class': 'start-element'
},
'inputoutput': {
'font-color': 'black',
'element-color': 'black',
'fill': 'bisque'
},
'operation': {
'font-color': 'black',
'element-color': 'black',
'fill': 'linen'
},
'subroutine': {
'font-color': 'black',
'element-color': 'blue',
'fill': 'lightgreen'
},
'condition': {
'font-color': 'red',
'element-color': 'black',
'fill': 'yellow'
},
'end':{
'font-size': 20,
'class': 'end-element'
}
},
'flowstate' : {
//'past' : { 'fill' : '#CCCCCC', 'font-size' : 12},
//'current' : {'fill' : 'yellow', 'font-color' : 'red', 'font-weight' : 'bold'},
//'future' : { 'fill' : '#FFFF99'},
'request' : { 'fill' : 'blue'},
'invalid': {'fill' : '#444444'},
'approved' : { 'fill' : '#58C4A3', 'font-size' : 12, 'yes-text' : 'APPROVED', 'no-text' : 'n/a' },
'rejected' : { 'fill' : '#C45879', 'font-size' : 12, 'yes-text' : 'n/a', 'no-text' : 'REJECTED' }
}
});
//create base64 encoding of SVG to generate download link for title(without html or htm).SVG
var currentCanvasDIV = document.getElementById('canvas')
var currentDrawSVG = currentCanvasDIV.innerHTML.replaceAll('ë','e');
const OUTsvgBASE64 = btoa(currentDrawSVG)
doctitle = document.title.replace('.html','');
doctitle = doctitle.replace('.htm','');
var currentCanvasDIV = document.getElementById('canvas')
var currentDrawSVG = currentCanvasDIV.innerHTML.replaceAll('ë','e');
svgSource = currentDrawSVG
svgXML = currentDrawSVG;
// Use SVG Height and Width from the SVG XML to set canvas size
svgXMLsubstringHeight = svgXML.substring(svgXML.indexOf('height='), svgXML.indexOf('version='));
svgXMLsubstringWidth = svgXML.substring(svgXML.indexOf('width='), svgXML.indexOf('xmlns='));
HeightValue = svgXMLsubstringHeight.substring(svgXMLsubstringHeight.indexOf('"')+1,svgXMLsubstringHeight.lastIndexOf('"'));
WidthValue = svgXMLsubstringWidth.substring(svgXMLsubstringWidth.indexOf('"')+1,svgXMLsubstringWidth.lastIndexOf('"'));
HeightValueInt = Math.round(HeightValue)
WidthValueInt = Math.round(WidthValue)
// setup input for base64SvgToBase64Png
let svgSrc = "data:image/svg+xml;base64,"+OUTsvgBASE64;
var pngBase
imageUtil.base64SvgToBase64Png(svgSrc, WidthValueInt, HeightValueInt).then(pngSrc => {
pngBase = pngSrc
// output download link for base64 PNG converted on download from base64
var pngOutHtml = `<a href="${pngBase}" download="${doctitle}.png">PNG - Click here to download current rendered flowchart as ${doctitle}.png</a>`
document.getElementById("pngbase64").innerHTML=pngOutHtml;
});
// output download link for base64 SVG converted on download from base64
var svgOutHtml = `<a href="data:image/svg+xml;base64,${OUTsvgBASE64}" download=${doctitle}.svg>SVG - Click here to download current rendered flowchart as ${doctitle}.svg</a> `
document.getElementById("svgbase64").innerHTML=svgOutHtml;
})();
};
// derived from https://stackoverflow.com/a/64800570
// we need to use web browser canvas to generate a image. In this case png
let imageUtil = {};
/**
* converts a base64 encoded data url SVG image to a PNG image
* @param originalBase64 data url of svg image
* @param width target width in pixel of PNG image
* @param secondTry used internally to prevent endless recursion
* @return {Promise<unknown>} resolves to png data url of the image
*/
imageUtil.base64SvgToBase64Png = function (originalBase64, width, height, secondTry) {
return new Promise(resolve => {
let img = document.createElement('img');
img.onload = function () {
if (!secondTry && (img.naturalWidth === 0 || img.naturalHeight === 0)) {
let svgDoc = base64ToSvgDocument(originalBase64);
let fixedDoc = fixSvgDocumentFF(svgDoc);
return imageUtil.base64SvgToBase64Png(svgDocumentToBase64(fixedDoc), width, height, true).then(result => {
resolve(result);
});
}
//document.body.appendChild(img);
let canvas2 = document.createElement("canvas");
//document.body.removeChild(img);
canvas2.width = width;
canvas2.height = height;
let ctx = canvas2.getContext("2d");
ctx.drawImage(img, 0, 0, canvas2.width, canvas2.height);
try {
let data = canvas2.toDataURL('image/png');
resolve(data);
} catch (e) {
resolve(null);
}
};
img.src = originalBase64;
});
}
//needed because Firefox doesn't correctly handle SVG with size = 0, see https://bugzilla.mozilla.org/show_bug.cgi?id=700533
function fixSvgDocumentFF(svgDocument) {
try {
let widthInt = parseInt(svgDocument.documentElement.width.baseVal.value) || 500;
let heightInt = parseInt(svgDocument.documentElement.height.baseVal.value) || 500;
svgDocument.documentElement.width.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PX, widthInt);
svgDocument.documentElement.height.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PX, heightInt);
return svgDocument;
} catch (e) {
return svgDocument;
}
}
function svgDocumentToBase64(svgDocument) {
try {
let base64EncodedSVG = btoa(new XMLSerializer().serializeToString(svgDocument));
return 'data:image/svg+xml;base64,' + base64EncodedSVG;
} catch (e) {
return null;
}
}
function base64ToSvgDocument(base64) {
let svg = atob(base64.substring(base64.indexOf('base64,') + 7));
svg = svg.substring(svg.indexOf('<svg'));
let parser = new DOMParser();
return parser.parseFromString(svg, "image/svg+xml");
}
</script>
<script>
function HelpText() {
var x = document.getElementById("HelpTextBlock");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
</head>
<body>
<div><textarea id="code" style="width: 100%;" rows="11">op2=>operation: '\nManipulations with knownNodes dictionary.\n'
op4=>operation: import json
op6=>operation: import logging
op8=>operation: import os
op10=>operation: import pickle
op12=>operation: import threading
op14=>operation: import time
op16=>operation: try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable
op18=>operation: import state
op20=>operation: from bmconfigparser import config
op22=>operation: from network.node import Peer
op24=>operation: state.Peer = Peer
op26=>operation: knownNodesLock = threading.RLock()
op28=>operation: 'Thread lock for knownnodes modification'
op30=>operation: knownNodes = {stream: {} for stream in range(1, 4)}
op32=>operation: 'The dict of known nodes for each stream'
op34=>operation: knownNodesTrimAmount = 2000
op36=>operation: 'trim stream knownnodes dict to this length'
op38=>operation: knownNodesForgetRating = (- 0.5)
op40=>operation: 'forget a node after rating is this low'
op42=>operation: knownNodesActual = False
op44=>operation: logger = logging.getLogger('default')
op46=>operation: DEFAULT_NODES = (Peer('5.45.99.75', 8444), Peer('75.167.159.54', 8444), Peer('95.165.168.168', 8444), Peer('85.180.139.241', 8444), Peer('158.222.217.190', 8080), Peer('178.62.12.187', 8448), Peer('24.188.198.204', 8111), Peer('109.147.204.113', 1195), Peer('178.11.46.221', 8444))
st49=>start: start json_serialize_knownnodes
io51=>inputoutput: input: output
op54=>operation: '\n Reorganize knownnodes dict and write it as JSON to output\n '
op56=>operation: _serialized = []
cond59=>condition: for (stream, peers) in knownNodes.iteritems()
cond81=>condition: for (peer, info) in peers.iteritems()
sub90=>subroutine: info.update(rating=round(info.get('rating', 0), 2))
sub92=>subroutine: _serialized.append({'stream': stream, 'peer': peer._asdict(), 'info': info})
sub98=>subroutine: json.dump(_serialized, output, indent=4)
e100=>end: end json_serialize_knownnodes
st104=>start: start json_deserialize_knownnodes
io106=>inputoutput: input: source
op109=>operation: '\n Read JSON from source and make knownnodes dict\n '
op111=>operation: global knownNodesActual
cond114=>condition: for node in json.load(source)
op138=>operation: peer = node['peer']
op140=>operation: info = node['info']
op142=>operation: peer = Peer(str(peer['host']), peer.get('port', 8444))
op144=>operation: knownNodes[node['stream']][peer] = info
cond147=>operation: knownNodesActual = True if ((not (knownNodesActual or info.get('self'))) and (peer not in DEFAULT_NODES))
e159=>end: end json_deserialize_knownnodes
st163=>start: start pickle_deserialize_old_knownnodes
io165=>inputoutput: input: source
op168=>operation: '\n Unpickle source and reorganize knownnodes dict if it has old format\n the old format was {Peer:lastseen, ...}\n the new format is {Peer:{"lastseen":i, "rating":f}}\n '
op170=>operation: global knownNodes
op172=>operation: knownNodes = pickle.load(source)
cond175=>condition: for stream in knownNodes.keys()
cond211=>condition: for (node, params) in knownNodes[stream].iteritems()
cond228=>operation: addKnownNode(stream, node, params) if isinstance(params, (float, int))
e242=>end: end pickle_deserialize_old_knownnodes
st246=>start: start saveKnownNodes
io248=>inputoutput: input: dirName
op251=>operation: 'Save knownnodes to filesystem'
cond254=>operation: dirName = state.appdata if (dirName is None)
op264=>operation: with knownNodesLock:
with open(os.path.join(dirName, 'knownnodes.dat'), 'wb') as output:
json_serialize_knownnodes(output)
e266=>end: end saveKnownNodes
st270=>start: start addKnownNode
io272=>inputoutput: input: stream, peer, lastseen, is_self
op275=>operation: '\n Add a new node to the dict or update lastseen if it already exists.\n Do it for each stream number if *stream* is `Iterable`.\n Returns True if added a new node.\n '
cond278=>condition: if isinstance(stream, Iterable)
op282=>operation: with knownNodesLock:
for s in stream:
addKnownNode(s, peer, lastseen, is_self)
e285=>end: end function return
op291=>operation: rating = 0.0
cond294=>condition: if (not lastseen)
op298=>operation: lastseen = int(time.time())
cond308=>condition: if (not is_self)
cond313=>condition: if (len(knownNodes[stream]) > config.safeGetInt('knownnodes', 'maxnodes'))
e318=>end: end function return
op327=>operation: knownNodes[stream][peer] = {'lastseen': lastseen, 'rating': ((rating or 1) if is_self else 0), 'self': is_self}
io332=>inputoutput: output: True
e330=>end: end function return
op302=>operation: lastseen = int(lastseen)
op304=>operation: try:
info = knownNodes[stream].get(peer)
if (lastseen > info['lastseen']):
info['lastseen'] = lastseen
except (KeyError, TypeError):
pass
else:
return
op2->op4
op4->op6
op6->op8
op8->op10
op10->op12
op12->op14
op14->op16
op16->op18
op18->op20
op20->op22
op22->op24
op24->op26
op26->op28
op28->op30
op30->op32
op32->op34
op34->op36
op36->op38
op38->op40
op40->op42
op42->op44
op44->op46
op46->st49
st49->io51
io51->op54
op54->op56
op56->cond59
cond59(yes)->cond81
cond81(yes)->sub90
sub90->sub92
sub92(left)->cond81
cond81(no)->cond59
cond59(no)->sub98
sub98->e100
e100->st104
st104->io106
io106->op109
op109->op111
op111->cond114
cond114(yes)->op138
op138->op140
op140->op142
op142->op144
op144->cond147
cond147->cond114
cond114(no)->e159
e159->st163
st163->io165
io165->op168
op168->op170
op170->op172
op172->cond175
cond175(yes)->cond211
cond211(yes)->cond228
cond228->cond211
cond211(no)->cond175
cond175(no)->e242
e242->st246
st246->io248
io248->op251
op251->cond254
cond254->op264
op264->e266
e266->st270
st270->io272
io272->op275
op275->cond278
cond278(yes)->op282
op282->e285
cond278(no)->op291
op291->cond294
cond294(yes)->op298
op298->cond308
cond308(yes)->cond313
cond313(yes)->e318
cond313(no)->op327
op327->io332
io332->e330
cond308(no)->op327
cond294(no)->op302
op302->op304
op304->cond308
</textarea></div>
<div><button id="run" type="button">Run</button> <button onclick="HelpText()">Format Help</button></div>
<div id="HelpTextBlock" style="display:none"><br/>Conditions can also be redirected like cond(yes, bottom) or cond(yes, right)
... and the other symbols too... like sub1(right)<br/>
You can also tweak the <b>diagram.drawSVG('diagram', {});</b> script in this file for more changes<br/>
This is based on <a href="https://github.com/adrai/flowchart.js">flowchart.js on github</a> and <a href="http://flowchart.js.org">http://flowchart.js.org</a> more documentation can be found over there.
</div><br/><div id="svgbase64"></div>
<div id="pngbase64"></div>
<div id="canvas"></div>
</body>
</html>