mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-01 01:09:22 +01:00
Merge branch 'devel' into engine-rework
Conflicts: classes.py
This commit is contained in:
commit
0033612fa3
12
classes.py
12
classes.py
@ -1295,7 +1295,7 @@ utils._proto_utils_class = PyLinkNetworkCoreWithUtils # Used by compatibility w
|
|||||||
|
|
||||||
class IRCNetwork(PyLinkNetworkCoreWithUtils):
|
class IRCNetwork(PyLinkNetworkCoreWithUtils):
|
||||||
S2S_BUFSIZE = 510
|
S2S_BUFSIZE = 510
|
||||||
SOCKET_REPOLL_WAIT = 0.5
|
SOCKET_REPOLL_WAIT = 1.0
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@ -1540,6 +1540,11 @@ class IRCNetwork(PyLinkNetworkCoreWithUtils):
|
|||||||
data = b''
|
data = b''
|
||||||
try:
|
try:
|
||||||
data = self._socket.recv(2048)
|
data = self._socket.recv(2048)
|
||||||
|
except (BlockingIOError, ssl.SSLWantReadError, ssl.SSLWantWriteError):
|
||||||
|
log.debug('(%s) No data to read, trying again later...', self.name)
|
||||||
|
if self._aborted.wait(self.SOCKET_REPOLL_WAIT):
|
||||||
|
break
|
||||||
|
continue
|
||||||
except OSError:
|
except OSError:
|
||||||
# Suppress socket read warnings from lingering recv() calls if
|
# Suppress socket read warnings from lingering recv() calls if
|
||||||
# we've been told to shutdown.
|
# we've been told to shutdown.
|
||||||
@ -1577,8 +1582,9 @@ class IRCNetwork(PyLinkNetworkCoreWithUtils):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self._socket.send(encoded_data)
|
self._socket.send(encoded_data)
|
||||||
except (OSError, AttributeError):
|
except:
|
||||||
log.exception("(%s) Failed to send message %r; did the network disconnect?", self.name, data)
|
log.exception("(%s) Failed to send message %r; aborting!", self.name, data)
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
def send(self, data, queue=True):
|
def send(self, data, queue=True):
|
||||||
"""send() wrapper with optional queueing support."""
|
"""send() wrapper with optional queueing support."""
|
||||||
|
@ -33,10 +33,7 @@ default_permissions = {"*!*@*": ['relay.linked'],
|
|||||||
def initialize_all(irc):
|
def initialize_all(irc):
|
||||||
"""Initializes all relay channels for the given IRC object."""
|
"""Initializes all relay channels for the given IRC object."""
|
||||||
|
|
||||||
# Wait for all IRC objects to be created first. This prevents
|
def _initialize_all():
|
||||||
# relay servers from being spawned too early (before server authentication),
|
|
||||||
# which would break connections.
|
|
||||||
if world.started.wait(TCONDITION_TIMEOUT):
|
|
||||||
for chanpair, entrydata in db.items():
|
for chanpair, entrydata in db.items():
|
||||||
network, channel = chanpair
|
network, channel = chanpair
|
||||||
|
|
||||||
@ -48,6 +45,14 @@ def initialize_all(irc):
|
|||||||
if network == irc.name:
|
if network == irc.name:
|
||||||
initialize_channel(irc, channel)
|
initialize_channel(irc, channel)
|
||||||
|
|
||||||
|
# Wait for all IRC objects to be created first. This prevents
|
||||||
|
# relay servers from being spawned too early (before server authentication),
|
||||||
|
# which would break connections.
|
||||||
|
if world.started.wait(TCONDITION_TIMEOUT):
|
||||||
|
t = threading.Thread(target=_initialize_all, daemon=True,
|
||||||
|
name='relay initialize_all thread from network %r' % irc.name)
|
||||||
|
t.start()
|
||||||
|
|
||||||
def main(irc=None):
|
def main(irc=None):
|
||||||
"""Main function, called during plugin loading at start."""
|
"""Main function, called during plugin loading at start."""
|
||||||
log.debug('relay.main: loading links database')
|
log.debug('relay.main: loading links database')
|
||||||
@ -281,14 +286,9 @@ def get_relay_server_sid(irc, remoteirc, spawn_if_missing=True):
|
|||||||
sid = spawn_relay_server(irc, remoteirc)
|
sid = spawn_relay_server(irc, remoteirc)
|
||||||
|
|
||||||
log.debug('(%s) get_relay_server_sid: got %s for %s.relay', irc.name, sid, remoteirc.name)
|
log.debug('(%s) get_relay_server_sid: got %s for %s.relay', irc.name, sid, remoteirc.name)
|
||||||
if sid not in irc.servers:
|
if (sid not in irc.servers) or (sid in irc.servers and irc.servers[sid].remote != remoteirc.name):
|
||||||
log.warning('(%s) Possible desync? SID %s for %s.relay doesn\'t exist anymore', irc.name, sid, remoteirc.name)
|
# SID changed in the meantime; abort.
|
||||||
# Our stored server doesn't exist anymore. This state is probably a holdover from a netsplit,
|
return
|
||||||
# so let's refresh it.
|
|
||||||
sid = spawn_relay_server(irc, remoteirc)
|
|
||||||
elif sid in irc.servers and irc.servers[sid].remote != remoteirc.name:
|
|
||||||
log.debug('(%s) Possible desync? SID %s for %s.relay doesn\'t exist anymore is mismatched (got %s.relay)', irc.name, irc.servers[sid].remote, remoteirc.name)
|
|
||||||
sid = spawn_relay_server(irc, remoteirc)
|
|
||||||
|
|
||||||
log.debug('(%s) get_relay_server_sid: got %s for %s.relay (round 2)', irc.name, sid, remoteirc.name)
|
log.debug('(%s) get_relay_server_sid: got %s for %s.relay (round 2)', irc.name, sid, remoteirc.name)
|
||||||
spawnlocks_servers[irc.name].release()
|
spawnlocks_servers[irc.name].release()
|
||||||
@ -336,7 +336,7 @@ def spawn_relay_user(irc, remoteirc, user, times_tagged=0):
|
|||||||
|
|
||||||
rsid = get_relay_server_sid(remoteirc, irc)
|
rsid = get_relay_server_sid(remoteirc, irc)
|
||||||
if not rsid:
|
if not rsid:
|
||||||
log.error('(%s) spawn_relay_user: aborting user spawn for %s/%s @ %s (failed to retrieve a '
|
log.debug('(%s) spawn_relay_user: aborting user spawn for %s/%s @ %s (failed to retrieve a '
|
||||||
'working SID).', irc.name, user, nick, remoteirc.name)
|
'working SID).', irc.name, user, nick, remoteirc.name)
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
@ -505,9 +505,8 @@ def initialize_channel(irc, channel):
|
|||||||
# from the config. Skip this.
|
# from the config. Skip this.
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Give each network a tiny bit of leeway to finish up its connection.
|
# Remote net isn't ready yet, try again later.
|
||||||
# This is better than just dropping users their completely.
|
if not remoteirc.connected.is_set():
|
||||||
if not remoteirc.connected.wait(TCONDITION_TIMEOUT):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Join their (remote) users and set their modes, if applicable.
|
# Join their (remote) users and set their modes, if applicable.
|
||||||
@ -1475,16 +1474,20 @@ def handle_messages(irc, numeric, command, args):
|
|||||||
# Otherwise, the sender doesn't have a client representing them
|
# Otherwise, the sender doesn't have a client representing them
|
||||||
# on the remote network, and we won't have anything to send our
|
# on the remote network, and we won't have anything to send our
|
||||||
# messages from.
|
# messages from.
|
||||||
|
# Note: don't spam ulined senders (e.g. services announcers) with
|
||||||
|
# these notices.
|
||||||
if homenet not in remoteusers.keys():
|
if homenet not in remoteusers.keys():
|
||||||
irc.msg(numeric, 'You must be in a common channel '
|
if not _is_uline(irc, numeric):
|
||||||
'with %r in order to send messages.' % \
|
irc.msg(numeric, 'You must be in a common channel '
|
||||||
irc.users[target].nick, notice=True)
|
'with %r in order to send messages.' % \
|
||||||
|
irc.users[target].nick, notice=True)
|
||||||
return
|
return
|
||||||
remoteirc = world.networkobjects[homenet]
|
remoteirc = world.networkobjects[homenet]
|
||||||
|
|
||||||
if (not remoteirc.has_cap('can-spawn-clients')) and not conf.conf.get('relay', {}).get('allow_clientbot_pms'):
|
if (not remoteirc.has_cap('can-spawn-clients')) and not conf.conf.get('relay', {}).get('allow_clientbot_pms'):
|
||||||
irc.msg(numeric, 'Private messages to users connected via Clientbot have '
|
if not _is_uline(irc, numeric):
|
||||||
'been administratively disabled.', notice=True)
|
irc.msg(numeric, 'Private messages to users connected via Clientbot have '
|
||||||
|
'been administratively disabled.', notice=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
user = get_remote_user(irc, remoteirc, numeric, spawn_if_missing=False)
|
user = get_remote_user(irc, remoteirc, numeric, spawn_if_missing=False)
|
||||||
|
@ -60,7 +60,7 @@ def cb_relay_core(irc, source, command, args):
|
|||||||
|
|
||||||
real_command = 'ACTION'
|
real_command = 'ACTION'
|
||||||
|
|
||||||
elif not irc.is_channel(args['target']):
|
elif not irc.is_channel(args['target'].lstrip(''.join(irc.prefixmodes.values()))):
|
||||||
# Target is a user; handle this accordingly.
|
# Target is a user; handle this accordingly.
|
||||||
if relay_conf.get('allow_clientbot_pms'):
|
if relay_conf.get('allow_clientbot_pms'):
|
||||||
real_command = 'PNOTICE' if args.get('is_notice') else 'PM'
|
real_command = 'PNOTICE' if args.get('is_notice') else 'PM'
|
||||||
@ -113,8 +113,12 @@ def cb_relay_core(irc, source, command, args):
|
|||||||
netname = sourcenet
|
netname = sourcenet
|
||||||
|
|
||||||
# Figure out where the message is destined to.
|
# Figure out where the message is destined to.
|
||||||
target = args.get('channel') or args.get('target')
|
stripped_target = target = args.get('channel') or args.get('target')
|
||||||
if target is None or not (irc.is_channel(target) or private):
|
if target is not None:
|
||||||
|
# HACK: cheap fix to prevent @#channel messages from interpreted as non-channel specific
|
||||||
|
stripped_target = target.lstrip(''.join(irc.prefixmodes.values()))
|
||||||
|
|
||||||
|
if target is None or not (irc.is_channel(stripped_target) or private):
|
||||||
# Non-channel specific message (e.g. QUIT or NICK). If this isn't a PM, figure out
|
# Non-channel specific message (e.g. QUIT or NICK). If this isn't a PM, figure out
|
||||||
# all channels that the sender shares over the relay, and relay them to those
|
# all channels that the sender shares over the relay, and relay them to those
|
||||||
# channels.
|
# channels.
|
||||||
@ -127,7 +131,7 @@ def cb_relay_core(irc, source, command, args):
|
|||||||
else:
|
else:
|
||||||
# Pluralize the channel so that we can iterate over it.
|
# Pluralize the channel so that we can iterate over it.
|
||||||
targets = [target]
|
targets = [target]
|
||||||
args['channel'] = target
|
args['channel'] = stripped_target
|
||||||
log.debug('(%s) relay_cb_core: Relaying event %s to channels: %s', irc.name, real_command, targets)
|
log.debug('(%s) relay_cb_core: Relaying event %s to channels: %s', irc.name, real_command, targets)
|
||||||
|
|
||||||
identhost = ''
|
identhost = ''
|
||||||
|
@ -98,6 +98,10 @@ def _map(irc, source, args, show_relay=True):
|
|||||||
if remoteirc.has_cap('can-track-servers'):
|
if remoteirc.has_cap('can-track-servers'):
|
||||||
# Only ever show relay subservers once - this prevents infinite loops.
|
# Only ever show relay subservers once - this prevents infinite loops.
|
||||||
showall(remoteirc, remoteirc.sid, hops=hops, is_relay_server=True)
|
showall(remoteirc, remoteirc.sid, hops=hops, is_relay_server=True)
|
||||||
|
else:
|
||||||
|
# For Clientbot links, show the server we're actually connected to.
|
||||||
|
reply("%s\x02%s\x02 (actual server name)" %
|
||||||
|
(' '*(hops+1), remoteirc.uplink))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Afterwards, decrement the hopcount.
|
# Afterwards, decrement the hopcount.
|
||||||
|
@ -87,7 +87,8 @@ def handle_stats(irc, source, command, args):
|
|||||||
try:
|
try:
|
||||||
permissions.check_permissions(irc, source, perms)
|
permissions.check_permissions(irc, source, perms)
|
||||||
except utils.NotAuthorizedError as e:
|
except utils.NotAuthorizedError as e:
|
||||||
irc.msg(source, 'Error: %s' % e) # Note, no irc.error() because this is not a command, but a handler
|
# Note, no irc.error() because this is not a command, but a handler
|
||||||
|
irc.msg(source, 'Error: %s' % e, notice=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
log.info('(%s) /STATS %s requested by %s', irc.name, stats_type, irc.get_hostmask(source))
|
log.info('(%s) /STATS %s requested by %s', irc.name, stats_type, irc.get_hostmask(source))
|
||||||
|
Loading…
Reference in New Issue
Block a user