mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-27 21:19:31 +01:00
relay: stop execution if spawn lock acquire fails
Also, make the lock timeout a consistent, global variable. (partial merge of commit e24bc54bbcefc40bf73a197de2dc24f7cd42cf79)
This commit is contained in:
parent
fd15600d80
commit
5c7752a203
125
plugins/relay.py
125
plugins/relay.py
@ -8,6 +8,9 @@ from pylinkirc import utils, world, conf, structures
|
|||||||
from pylinkirc.log import log
|
from pylinkirc.log import log
|
||||||
from pylinkirc.coremods import permissions
|
from pylinkirc.coremods import permissions
|
||||||
|
|
||||||
|
# Sets the timeout to wait for as individual servers / the PyLink daemon to start up.
|
||||||
|
TCONDITION_TIMEOUT = 2
|
||||||
|
|
||||||
### GLOBAL (statekeeping) VARIABLES
|
### GLOBAL (statekeeping) VARIABLES
|
||||||
relayusers = defaultdict(dict)
|
relayusers = defaultdict(dict)
|
||||||
relayservers = defaultdict(dict)
|
relayservers = defaultdict(dict)
|
||||||
@ -31,16 +34,16 @@ def initialize_all(irc):
|
|||||||
# Wait for all IRC objects to be created first. This prevents
|
# Wait for all IRC objects to be created first. This prevents
|
||||||
# relay servers from being spawned too early (before server authentication),
|
# relay servers from being spawned too early (before server authentication),
|
||||||
# which would break connections.
|
# which would break connections.
|
||||||
world.started.wait(2)
|
if world.started.wait(TCONDITION_TIMEOUT):
|
||||||
|
for chanpair, entrydata in db.items():
|
||||||
|
# Iterate over all the channels stored in our relay links DB.
|
||||||
|
network, channel = chanpair
|
||||||
|
|
||||||
for chanpair, entrydata in db.items():
|
# Initialize each relay channel on their home network, and on every linked one too.
|
||||||
# Iterate over all the channels stored in our relay links DB.
|
|
||||||
network, channel = chanpair
|
|
||||||
# Initialize each relay channel on their home network, and on every linked one too.
|
|
||||||
initialize_channel(irc, channel)
|
|
||||||
for link in entrydata['links']:
|
|
||||||
network, channel = link
|
|
||||||
initialize_channel(irc, channel)
|
initialize_channel(irc, channel)
|
||||||
|
for link in entrydata['links']:
|
||||||
|
network, channel = link
|
||||||
|
initialize_channel(irc, channel)
|
||||||
|
|
||||||
def main(irc=None):
|
def main(irc=None):
|
||||||
"""Main function, called during plugin loading at start."""
|
"""Main function, called during plugin loading at start."""
|
||||||
@ -209,37 +212,40 @@ def get_prefix_modes(irc, remoteirc, channel, user, mlist=None):
|
|||||||
return modes
|
return modes
|
||||||
|
|
||||||
def spawn_relay_server(irc, remoteirc):
|
def spawn_relay_server(irc, remoteirc):
|
||||||
irc.connected.wait(5)
|
if irc.connected.wait(TCONDITION_TIMEOUT):
|
||||||
try:
|
try:
|
||||||
# ENDBURST is delayed by 3 secs on supported IRCds to prevent
|
# ENDBURST is delayed by 3 secs on supported IRCds to prevent
|
||||||
# triggering join-flood protection and the like.
|
# triggering join-flood protection and the like.
|
||||||
suffix = conf.conf.get('relay', {}).get('server_suffix', 'relay')
|
suffix = conf.conf.get('relay', {}).get('server_suffix', 'relay')
|
||||||
# Strip any leading or trailing .'s
|
# Strip any leading or trailing .'s
|
||||||
suffix = suffix.strip('.')
|
suffix = suffix.strip('.')
|
||||||
sid = irc.proto.spawnServer('%s.%s' % (remoteirc.name, suffix),
|
sid = irc.proto.spawnServer('%s.%s' % (remoteirc.name, suffix),
|
||||||
desc="PyLink Relay network - %s" %
|
desc="PyLink Relay network - %s" %
|
||||||
(remoteirc.getFullNetworkName()), endburst_delay=3)
|
(remoteirc.getFullNetworkName()), endburst_delay=3)
|
||||||
except (RuntimeError, ValueError): # Network not initialized yet, or a server name conflict.
|
except (RuntimeError, ValueError): # Network not initialized yet, or a server name conflict.
|
||||||
log.exception('(%s) Failed to spawn server for %r (possible jupe?):',
|
log.exception('(%s) Failed to spawn server for %r (possible jupe?):',
|
||||||
irc.name, remoteirc.name)
|
irc.name, remoteirc.name)
|
||||||
# We will just bail here. Disconnect the bad network.
|
# We will just bail here. Disconnect the bad network.
|
||||||
irc.disconnect()
|
irc.disconnect()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Mark the server as a relay server
|
# Mark the server as a relay server
|
||||||
irc.servers[sid].remote = remoteirc.name
|
irc.servers[sid].remote = remoteirc.name
|
||||||
|
|
||||||
# Assign the newly spawned server as our relay server for the target net.
|
# Assign the newly spawned server as our relay server for the target net.
|
||||||
relayservers[irc.name][remoteirc.name] = sid
|
relayservers[irc.name][remoteirc.name] = sid
|
||||||
|
|
||||||
return sid
|
return sid
|
||||||
|
else:
|
||||||
|
log.debug('(%s) skipping spawn_relay_server(%s, %s); the remote is not ready yet',
|
||||||
|
irc.name, irc.name, remoteirc.name)
|
||||||
|
|
||||||
def get_remote_sid(irc, remoteirc, spawn_if_missing=True):
|
def get_remote_sid(irc, remoteirc, spawn_if_missing=True):
|
||||||
"""Gets the remote server SID representing remoteirc on irc, spawning
|
"""Gets the remote server SID representing remoteirc on irc, spawning
|
||||||
it if it doesn't exist (and spawn_if_missing is enabled)."""
|
it if it doesn't exist (and spawn_if_missing is enabled)."""
|
||||||
|
|
||||||
log.debug('(%s) Grabbing spawnlocks_servers[%s]', irc.name, irc.name)
|
log.debug('(%s) Grabbing spawnlocks_servers[%s]', irc.name, irc.name)
|
||||||
if spawnlocks_servers[irc.name].acquire(5):
|
if spawnlocks_servers[irc.name].acquire(timeout=TCONDITION_TIMEOUT):
|
||||||
try:
|
try:
|
||||||
sid = relayservers[irc.name][remoteirc.name]
|
sid = relayservers[irc.name][remoteirc.name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -343,36 +349,38 @@ def get_remote_user(irc, remoteirc, user, spawn_if_missing=True, times_tagged=0)
|
|||||||
spawning one if it doesn't exist and spawn_if_missing is True."""
|
spawning one if it doesn't exist and spawn_if_missing is True."""
|
||||||
|
|
||||||
# Wait until the network is working before trying to spawn anything.
|
# Wait until the network is working before trying to spawn anything.
|
||||||
irc.connected.wait(5)
|
if irc.connected.wait(TCONDITION_TIMEOUT):
|
||||||
|
# Don't spawn clones for registered service bots.
|
||||||
|
sbot = irc.getServiceBot(user)
|
||||||
|
if sbot:
|
||||||
|
return sbot.uids.get(remoteirc.name)
|
||||||
|
|
||||||
# Don't spawn clones for registered service bots.
|
log.debug('(%s) Grabbing spawnlocks[%s]', irc.name, irc.name)
|
||||||
sbot = irc.getServiceBot(user)
|
if spawnlocks[irc.name].acquire(timeout=TCONDITION_TIMEOUT):
|
||||||
if sbot:
|
# Be sort-of thread safe: lock the user spawns for the current net first.
|
||||||
return sbot.uids.get(remoteirc.name)
|
u = None
|
||||||
|
try:
|
||||||
|
# Look up the existing user, stored here as dict entries in the format:
|
||||||
|
# {('ournet', 'UID'): {'remotenet1': 'UID1', 'remotenet2': 'UID2'}}
|
||||||
|
u = relayusers[(irc.name, user)][remoteirc.name]
|
||||||
|
except KeyError:
|
||||||
|
# User doesn't exist. Spawn a new one if requested.
|
||||||
|
if spawn_if_missing:
|
||||||
|
u = spawn_relay_user(irc, remoteirc, user, times_tagged=times_tagged)
|
||||||
|
|
||||||
log.debug('(%s) Grabbing spawnlocks[%s]', irc.name, irc.name)
|
# This is a sanity check to make sure netsplits and other state resets
|
||||||
if spawnlocks[irc.name].acquire(5):
|
# don't break the relayer. If it turns out there was a client in our relayusers
|
||||||
# Be sort-of thread safe: lock the user spawns for the current net first.
|
# cache for the requested UID, but it doesn't match the request,
|
||||||
u = None
|
# assume it was a leftover from the last split and replace it with a new one.
|
||||||
try:
|
if u and ((u not in remoteirc.users) or remoteirc.users[u].remote != (irc.name, user)):
|
||||||
# Look up the existing user, stored here as dict entries in the format:
|
|
||||||
# {('ournet', 'UID'): {'remotenet1': 'UID1', 'remotenet2': 'UID2'}}
|
|
||||||
u = relayusers[(irc.name, user)][remoteirc.name]
|
|
||||||
except KeyError:
|
|
||||||
# User doesn't exist. Spawn a new one if requested.
|
|
||||||
if spawn_if_missing:
|
|
||||||
u = spawn_relay_user(irc, remoteirc, user, times_tagged=times_tagged)
|
u = spawn_relay_user(irc, remoteirc, user, times_tagged=times_tagged)
|
||||||
|
|
||||||
# This is a sanity check to make sure netsplits and other state resets
|
spawnlocks[irc.name].release()
|
||||||
# don't break the relayer. If it turns out there was a client in our relayusers
|
|
||||||
# cache for the requested UID, but it doesn't match the request,
|
|
||||||
# assume it was a leftover from the last split and replace it with a new one.
|
|
||||||
if u and ((u not in remoteirc.users) or remoteirc.users[u].remote != (irc.name, user)):
|
|
||||||
u = spawn_relay_user(irc, remoteirc, user, times_tagged=times_tagged)
|
|
||||||
|
|
||||||
spawnlocks[irc.name].release()
|
return u
|
||||||
|
else:
|
||||||
return u
|
log.debug('(%s) skipping spawn_relay_user(%s, %s, %s, ...); the remote is not ready yet',
|
||||||
|
irc.name, irc.name, remoteirc.name, user)
|
||||||
|
|
||||||
def get_orig_user(irc, user, targetirc=None):
|
def get_orig_user(irc, user, targetirc=None):
|
||||||
"""
|
"""
|
||||||
@ -937,7 +945,7 @@ def handle_quit(irc, numeric, command, args):
|
|||||||
# Lock the user spawning mechanism before proceeding, since we're going to be
|
# Lock the user spawning mechanism before proceeding, since we're going to be
|
||||||
# deleting client from the relayusers cache.
|
# deleting client from the relayusers cache.
|
||||||
log.debug('(%s) Grabbing spawnlocks[%s]', irc.name, irc.name)
|
log.debug('(%s) Grabbing spawnlocks[%s]', irc.name, irc.name)
|
||||||
if spawnlocks[irc.name].acquire(5):
|
if spawnlocks[irc.name].acquire(timeout=TCONDITION_TIMEOUT):
|
||||||
for netname, user in relayusers[(irc.name, numeric)].copy().items():
|
for netname, user in relayusers[(irc.name, numeric)].copy().items():
|
||||||
remoteirc = world.networkobjects[netname]
|
remoteirc = world.networkobjects[netname]
|
||||||
try: # Try to quit the client. If this fails because they're missing, bail.
|
try: # Try to quit the client. If this fails because they're missing, bail.
|
||||||
@ -1468,7 +1476,7 @@ def handle_disconnect(irc, numeric, command, args):
|
|||||||
# Quit all of our users' representations on other nets, and remove
|
# Quit all of our users' representations on other nets, and remove
|
||||||
# them from our relay clients index.
|
# them from our relay clients index.
|
||||||
log.debug('(%s) Grabbing spawnlocks[%s]', irc.name, irc.name)
|
log.debug('(%s) Grabbing spawnlocks[%s]', irc.name, irc.name)
|
||||||
if spawnlocks[irc.name].acquire(5):
|
if spawnlocks[irc.name].acquire(timeout=TCONDITION_TIMEOUT):
|
||||||
for k, v in relayusers.copy().items():
|
for k, v in relayusers.copy().items():
|
||||||
if irc.name in v:
|
if irc.name in v:
|
||||||
del relayusers[k][irc.name]
|
del relayusers[k][irc.name]
|
||||||
@ -1479,7 +1487,7 @@ def handle_disconnect(irc, numeric, command, args):
|
|||||||
# SQUIT all relay pseudoservers spawned for us, and remove them
|
# SQUIT all relay pseudoservers spawned for us, and remove them
|
||||||
# from our relay subservers index.
|
# from our relay subservers index.
|
||||||
log.debug('(%s) Grabbing spawnlocks_servers[%s]', irc.name, irc.name)
|
log.debug('(%s) Grabbing spawnlocks_servers[%s]', irc.name, irc.name)
|
||||||
if spawnlocks_servers[irc.name].acquire(5):
|
if spawnlocks_servers[irc.name].acquire(timeout=TCONDITION_TIMEOUT):
|
||||||
for name, ircobj in world.networkobjects.copy().items():
|
for name, ircobj in world.networkobjects.copy().items():
|
||||||
if name != irc.name:
|
if name != irc.name:
|
||||||
try:
|
try:
|
||||||
@ -1855,7 +1863,6 @@ def linked(irc, source, args):
|
|||||||
|
|
||||||
# Sort the list of shared channels when displaying
|
# Sort the list of shared channels when displaying
|
||||||
for k, v in sorted(db.items()):
|
for k, v in sorted(db.items()):
|
||||||
|
|
||||||
# Skip if we're filtering by network and the network given isn't relayed
|
# Skip if we're filtering by network and the network given isn't relayed
|
||||||
# to the channel.
|
# to the channel.
|
||||||
if net and not (net == k[0] or net in [link[0] for link in v['links']]):
|
if net and not (net == k[0] or net in [link[0] for link in v['links']]):
|
||||||
|
Loading…
Reference in New Issue
Block a user