model.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. # This file is part of DarkFi (https://dark.fi)
  2. #
  3. # Copyright (C) 2020-2025 Dyne.org foundation
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU Affero General Public License as
  7. # published by the Free Software Foundation, either version 3 of the
  8. # License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Affero General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License
  16. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. import logging, time
  18. import datetime as dt
  19. from collections import defaultdict as dd
  20. class Model:
  21. def __init__(self):
  22. self.nodes = {}
  23. self.liliths = {}
  24. def add_node(self, node):
  25. channel_lookup = {}
  26. name = list(node.keys())[0]
  27. values = list(node.values())[0]
  28. info = values['result']
  29. channels = info['channels']
  30. self.nodes[name] = {}
  31. self.nodes[name]['outbound'] = {}
  32. self.nodes[name]['inbound'] = {}
  33. self.nodes[name]['manual'] = {}
  34. self.nodes[name]['direct'] = {}
  35. self.nodes[name]['direct_peer_discovery'] = None
  36. self.nodes[name]['event'] = {}
  37. self.nodes[name]['seed'] = {}
  38. self.nodes[name]['msgs'] = dd(list)
  39. for channel in channels:
  40. id = channel['id']
  41. channel_lookup[id] = channel
  42. for channel in channels:
  43. if channel['session'] != 'inbound':
  44. continue
  45. id = channel['id']
  46. url = channel_lookup[id]['url']
  47. self.nodes[name]['inbound'][f'{id}'] = url
  48. for i, id in enumerate(info['outbound_slots']):
  49. if id == 0:
  50. outbounds = self.nodes[name]['outbound'][f'{i}'] = ['none', 0]
  51. continue
  52. assert id in channel_lookup
  53. url = channel_lookup[id]['url']
  54. outbounds = self.nodes[name]['outbound'][f'{i}'] = [url, id]
  55. for channel in channels:
  56. if channel['session'] != 'seed':
  57. continue
  58. id = channel['id']
  59. url = channel['url']
  60. self.nodes[name]['seed'][f'{id}'] = url
  61. for channel in channels:
  62. if channel['session'] != 'manual':
  63. continue
  64. id = channel['id']
  65. url = channel['url']
  66. self.nodes[name]['manual'][f'{id}'] = url
  67. for channel in channels:
  68. if channel['session'] != 'direct':
  69. continue
  70. id = channel['id']
  71. url = channel['url']
  72. self.nodes[name]['direct'][f'{url}'] = [url, id]
  73. def add_offline(self, node, is_lilith: bool):
  74. name = list(node.keys())[0]
  75. values = list(node.values())[0]
  76. if is_lilith:
  77. self.liliths[name] = values
  78. else:
  79. self.nodes[name] = values
  80. def add_event(self, event):
  81. name = list(event.keys())[0]
  82. values = list(event.values())[0]
  83. params = values.get('params')
  84. event = params[0].get('event')
  85. info = params[0].get('info')
  86. t = time.localtime()
  87. current_time = time.strftime('%H:%M:%S', t)
  88. match event:
  89. case 'send':
  90. nano = info.get('time')
  91. cmd = info.get('cmd')
  92. chan = info.get('chan')
  93. addr = chan.get('addr')
  94. t = (dt.datetime
  95. .fromtimestamp(int(nano)/1000000000)
  96. .strftime('%H:%M:%S'))
  97. msgs = self.nodes[name]['msgs']
  98. msgs[addr].append((t, event, cmd))
  99. case 'recv':
  100. nano = info.get('time')
  101. cmd = info.get('cmd')
  102. chan = info.get('chan')
  103. addr = chan.get('addr')
  104. t = (dt.datetime
  105. .fromtimestamp(int(nano)/1000000000)
  106. .strftime('%H:%M:%S'))
  107. msgs = self.nodes[name]['msgs']
  108. msgs[addr].append((t, event, cmd))
  109. case 'inbound_connected':
  110. addr = info['addr']
  111. id = info.get('channel_id')
  112. self.nodes[name]['inbound'][f'{id}'] = addr
  113. logging.debug(f'{current_time} inbound (connect): {addr}')
  114. case 'inbound_disconnected':
  115. addr = info['addr']
  116. id = info.get('channel_id')
  117. self.nodes[name]['inbound'][f'{id}'] = {}
  118. logging.debug(f'{current_time} inbound (disconnect): {addr}')
  119. case 'outbound_slot_sleeping':
  120. slot = info['slot']
  121. event = self.nodes[name]['event']
  122. event[(f'{name}', f'{slot}')] = ['sleeping', 0]
  123. logging.debug(f'{current_time} slot {slot}: sleeping')
  124. case 'outbound_slot_connecting':
  125. slot = info['slot']
  126. addr = info['addr']
  127. event = self.nodes[name]['event']
  128. event[(f'{name}', f'{slot}')] = [f'connecting: addr={addr}', 0]
  129. logging.debug(f'{current_time} slot {slot}: connecting addr={addr}')
  130. case 'outbound_slot_connected':
  131. slot = info['slot']
  132. addr = info['addr']
  133. event = self.nodes[name]['event']
  134. event[(f'{name}', f'{slot}')] = [f'connected: addr={addr}', 0]
  135. id = info['channel_id']
  136. self.nodes[name]['outbound'][f'{slot}'] = [addr, id]
  137. logging.debug(f'{current_time} slot {slot}: connected addr={addr}')
  138. case 'outbound_slot_disconnected':
  139. slot = info['slot']
  140. err = info['err']
  141. event = self.nodes[name]['event']
  142. event[(f'{name}', f'{slot}')] = [f'disconnected: {err}', 0]
  143. logging.debug(f'{current_time} slot {slot}: disconnected err={err}')
  144. case 'outbound_peer_discovery':
  145. attempt = info['attempt']
  146. state = info['state']
  147. event = self.nodes[name]['event']
  148. key = (f'{name}', 'outbound')
  149. event[key] = f'peer discovery: {state} (attempt {attempt})'
  150. logging.debug(f'{current_time} peer_discovery: {state} (attempt {attempt})')
  151. case 'direct_connecting':
  152. connect_addr = info['connect_addr']
  153. event = self.nodes[name]['event']
  154. event[(f'{name}', f'{connect_addr}')] = [f'connecting: addr={connect_addr}', 0]
  155. self.nodes[name]['direct'][f'{connect_addr}'] = ['', 0]
  156. logging.debug(f'{current_time} direct (connecting): addr={connect_addr}')
  157. case 'direct_connected':
  158. connect_addr = info['connect_addr']
  159. addr = info['addr']
  160. id = info['channel_id']
  161. event = self.nodes[name]['event']
  162. event[(f'{name}', f'{connect_addr}')] = [addr, id]
  163. self.nodes[name]['direct'][f'{connect_addr}'] = [addr, id]
  164. logging.debug(f'{current_time} direct (connected): addr={addr}')
  165. case 'direct_disconnected':
  166. connect_addr = info['connect_addr']
  167. err = info['err']
  168. self.nodes[name]['direct'][f'{connect_addr}'] = {}
  169. logging.debug(f'{current_time} direct (disconnected): addr={connect_addr} err={err}')
  170. case 'direct_peer_discovery':
  171. if self.nodes[name]['direct_peer_discovery'] is None:
  172. self.nodes[name]['direct_peer_discovery'] = 0
  173. attempt = info['attempt']
  174. state = info['state']
  175. event = self.nodes[name]['event']
  176. key = (f'{name}', 'direct')
  177. event[key] = f'peer discovery: {state} (attempt {attempt})'
  178. logging.debug(f'{current_time} peer_discovery: {state} (attempt {attempt})')
  179. def add_lilith(self, lilith):
  180. key = list(lilith.keys())[0]
  181. values = list(lilith.values())[0]
  182. info = values['result']
  183. spawns = info['spawns']
  184. self.liliths[key] = {}
  185. self.liliths[key]['spawns'] = {}
  186. for (i, spawn) in enumerate(spawns):
  187. name = spawn['name']
  188. urls = spawn['urls']
  189. whitelist = spawn['whitelist']
  190. greylist = spawn['greylist']
  191. goldlist = spawn['goldlist']
  192. spawn = self.liliths[key]['spawns'][name] = {}
  193. spawn['urls'] = urls
  194. spawn['whitelist'] = whitelist
  195. spawn['greylist'] = greylist
  196. spawn['goldlist'] = goldlist
  197. #logging.debug(f'added lilith {self.liliths}')
  198. def __repr__(self):
  199. return f'{self.nodes}'
  200. return f'{self.liliths}'