Browse Source

Merge #1223: Choose directory node based on where nicks seen.

041ea4a Choose directory node based on where nicks seen. (Adam Gibson)
master
Adam Gibson 4 years ago
parent
commit
739f50c204
No known key found for this signature in database
GPG Key ID: 141001A1AF77F20B
  1. 49
      jmdaemon/jmdaemon/onionmc.py

49
jmdaemon/jmdaemon/onionmc.py

@ -3,6 +3,7 @@ from jmdaemon.protocol import COMMAND_PREFIX, JM_VERSION
from jmbase import get_log, JM_APP_NAME, JMHiddenService, stop_reactor
import json
import copy
import random
from typing import Callable, Union, Tuple, List
from twisted.internet import reactor, task, protocol
from twisted.protocols import basic
@ -116,6 +117,9 @@ class OnionCustomMessageDecodingError(Exception):
class InvalidLocationStringError(Exception):
pass
class OnionDirectoryPeerNotFound(Exception):
pass
class OnionCustomMessage(object):
""" Encapsulates the messages passed over the wire
to and from other onion peers
@ -586,6 +590,14 @@ class OnionDirectoryPeer(OnionPeer):
except OnionPeerConnectionError:
reactor.callLater(self.delay, self.try_to_connect)
def register_connection(self) -> None:
self.messagechannel.update_directory_map(self, connected=True)
super().register_connection()
def register_disconnection(self) -> None:
self.messagechannel.update_directory_map(self, connected=False)
super().register_disconnection()
class OnionMessageChannel(MessageChannel):
""" Sends messages to other nodes of the same type over Tor
@ -687,6 +699,14 @@ class OnionMessageChannel(MessageChannel):
# the rpc connection calls are not using twisted)
self.wait_for_directories_loop = None
# this dict plays the same role as `active_channels` in `MessageChannelCollection`.
# it has structure {nick: set(),..} where set() has elements that are dicts:
# {OnionPeer: bool}.
# Entries get updated with changing connection status of directories,
# allowing us to decide where to send each message we want to send when we have no
# direct connection.
self.active_directories = {}
def info_callback(self, msg: str) -> None:
log.info(msg)
@ -787,11 +807,10 @@ class OnionMessageChannel(MessageChannel):
log.debug("Privmsg peer: {} but don't have peerid; "
"sending via directory.".format(nick))
try:
# TODO change this to redundant or switching
peer_sendable = self.get_connected_directory_peers()[0]
except Exception as e:
peer_sendable = self.get_directory_for_nick(nick)
except OnionDirectoryPeerNotFound:
log.warn("Failed to send privmsg because no "
"directory peer is connected. Error: {}".format(repr(e)))
"directory peer is connected.")
return
self._send(peer_sendable, encoded_privmsg)
@ -965,6 +984,28 @@ class OnionMessageChannel(MessageChannel):
except Exception as e:
log.debug("Invalid Joinmarket message: {}, error was: {}".format(
msgval, repr(e)))
# add the nick to the directories map, whether pubmsg or privmsg, but
# only if it passed the above syntax Exception catch:
if peer.directory and not self.self_as_peer.directory:
if from_nick not in self.active_directories:
self.active_directories[from_nick] = {}
self.active_directories[from_nick][peer] = True
def update_directory_map(self, p: OnionDirectoryPeer, connected: bool) -> None:
nicks = []
for nick in self.active_directories:
if p in self.active_directories[nick]:
nicks.append(nick)
for nick in nicks:
self.active_directories[nick][p] = connected
def get_directory_for_nick(self, nick: str) -> OnionDirectoryPeer:
if nick not in self.active_directories:
raise OnionDirectoryPeerNotFound
adn = self.active_directories[nick]
if len(adn) == 0:
raise OnionDirectoryPeerNotFound
return random.choice([x for x in list(adn) if adn[x] is True])
def forward_pubmsg_to_peers(self, msg: str, from_nick: str) -> None:
""" Used by directory nodes currently. Takes a received

Loading…
Cancel
Save