model.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. # This file is part of DarkFi (https://dark.fi)
  2. #
  3. # Copyright (C) 2020-2026 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 or id not in channel_lookup:
  50. outbounds = self.nodes[name]['outbound'][f'{i}'] = ['none', 0]
  51. continue
  52. url = channel_lookup[id]['url']
  53. outbounds = self.nodes[name]['outbound'][f'{i}'] = [url, id]
  54. for channel in channels:
  55. if channel['session'] != 'seed':
  56. continue
  57. id = channel['id']
  58. url = channel['url']
  59. self.nodes[name]['seed'][f'{id}'] = url
  60. for channel in channels:
  61. if channel['session'] != 'manual':
  62. continue
  63. id = channel['id']
  64. url = channel['url']
  65. self.nodes[name]['manual'][f'{id}'] = url
  66. for channel in channels:
  67. if channel['session'] != 'direct':
  68. continue
  69. id = channel['id']
  70. url = channel['url']
  71. self.nodes[name]['direct'][f'{url}'] = [url, id]
  72. def add_offline(self, node, is_lilith: bool):
  73. name = list(node.keys())[0]
  74. values = list(node.values())[0]
  75. if is_lilith:
  76. self.liliths[name] = values
  77. else:
  78. self.nodes[name] = values
  79. def add_event(self, event):
  80. name = list(event.keys())[0]
  81. values = list(event.values())[0]
  82. params = values.get('params')
  83. event = params[0].get('event')
  84. info = params[0].get('info')
  85. t = time.localtime()
  86. current_time = time.strftime('%H:%M:%S', t)
  87. match event:
  88. case 'send':
  89. nano = info.get('time')
  90. cmd = info.get('cmd')
  91. chan = info.get('chan')
  92. addr = chan.get('addr')
  93. t = (dt.datetime
  94. .fromtimestamp(int(nano)/1000000000)
  95. .strftime('%H:%M:%S'))
  96. msgs = self.nodes[name]['msgs']
  97. msgs[addr].append((t, event, cmd))
  98. case 'recv':
  99. nano = info.get('time')
  100. cmd = info.get('cmd')
  101. chan = info.get('chan')
  102. addr = chan.get('addr')
  103. t = (dt.datetime
  104. .fromtimestamp(int(nano)/1000000000)
  105. .strftime('%H:%M:%S'))
  106. msgs = self.nodes[name]['msgs']
  107. msgs[addr].append((t, event, cmd))
  108. case 'inbound_connected':
  109. addr = info['addr']
  110. id = info.get('channel_id')
  111. self.nodes[name]['inbound'][f'{id}'] = addr
  112. logging.debug(f'{current_time} inbound (connect): {addr}')
  113. case 'inbound_disconnected':
  114. addr = info['addr']
  115. id = info.get('channel_id')
  116. self.nodes[name]['inbound'][f'{id}'] = {}
  117. logging.debug(f'{current_time} inbound (disconnect): {addr}')
  118. case 'outbound_slot_sleeping':
  119. slot = info['slot']
  120. event = self.nodes[name]['event']
  121. event[(f'{name}', f'{slot}')] = ['sleeping', 0]
  122. logging.debug(f'{current_time} slot {slot}: sleeping')
  123. case 'outbound_slot_connecting':
  124. slot = info['slot']
  125. addr = info['addr']
  126. event = self.nodes[name]['event']
  127. event[(f'{name}', f'{slot}')] = [f'connecting: addr={addr}', 0]
  128. logging.debug(f'{current_time} slot {slot}: connecting addr={addr}')
  129. case 'outbound_slot_connected':
  130. slot = info['slot']
  131. addr = info['addr']
  132. event = self.nodes[name]['event']
  133. event[(f'{name}', f'{slot}')] = [f'connected: addr={addr}', 0]
  134. id = info['channel_id']
  135. self.nodes[name]['outbound'][f'{slot}'] = [addr, id]
  136. logging.debug(f'{current_time} slot {slot}: connected addr={addr}')
  137. case 'outbound_slot_disconnected':
  138. slot = info['slot']
  139. err = info['err']
  140. event = self.nodes[name]['event']
  141. event[(f'{name}', f'{slot}')] = [f'disconnected: {err}', 0]
  142. logging.debug(f'{current_time} slot {slot}: disconnected err={err}')
  143. case 'outbound_peer_discovery':
  144. attempt = info['attempt']
  145. state = info['state']
  146. event = self.nodes[name]['event']
  147. key = (f'{name}', 'outbound')
  148. event[key] = f'peer discovery: {state} (attempt {attempt})'
  149. logging.debug(f'{current_time} peer_discovery: {state} (attempt {attempt})')
  150. case 'direct_connecting':
  151. connect_addr = info['connect_addr']
  152. event = self.nodes[name]['event']
  153. event[(f'{name}', f'{connect_addr}')] = [f'connecting: addr={connect_addr}', 0]
  154. self.nodes[name]['direct'][f'{connect_addr}'] = ['', 0]
  155. logging.debug(f'{current_time} direct (connecting): addr={connect_addr}')
  156. case 'direct_connected':
  157. connect_addr = info['connect_addr']
  158. addr = info['addr']
  159. id = info['channel_id']
  160. event = self.nodes[name]['event']
  161. event[(f'{name}', f'{connect_addr}')] = [addr, id]
  162. self.nodes[name]['direct'][f'{connect_addr}'] = [addr, id]
  163. logging.debug(f'{current_time} direct (connected): addr={addr}')
  164. case 'direct_disconnected':
  165. connect_addr = info['connect_addr']
  166. err = info['err']
  167. self.nodes[name]['direct'][f'{connect_addr}'] = {}
  168. logging.debug(f'{current_time} direct (disconnected): addr={connect_addr} err={err}')
  169. case 'direct_peer_discovery':
  170. if self.nodes[name]['direct_peer_discovery'] is None:
  171. self.nodes[name]['direct_peer_discovery'] = 0
  172. attempt = info['attempt']
  173. state = info['state']
  174. event = self.nodes[name]['event']
  175. key = (f'{name}', 'direct')
  176. event[key] = f'peer discovery: {state} (attempt {attempt})'
  177. logging.debug(f'{current_time} peer_discovery: {state} (attempt {attempt})')
  178. def add_lilith(self, lilith):
  179. key = list(lilith.keys())[0]
  180. values = list(lilith.values())[0]
  181. info = values['result']
  182. spawns = info['spawns']
  183. self.liliths[key] = {}
  184. self.liliths[key]['spawns'] = {}
  185. for (i, spawn) in enumerate(spawns):
  186. name = spawn['name']
  187. urls = spawn['urls']
  188. whitelist = spawn['whitelist']
  189. greylist = spawn['greylist']
  190. goldlist = spawn['goldlist']
  191. spawn = self.liliths[key]['spawns'][name] = {}
  192. spawn['urls'] = urls
  193. spawn['whitelist'] = whitelist
  194. spawn['greylist'] = greylist
  195. spawn['goldlist'] = goldlist
  196. #logging.debug(f'added lilith {self.liliths}')
  197. def __repr__(self):
  198. return f'{self.nodes}'
  199. return f'{self.liliths}'