diff --git a/evennia/server/inputfuncs.py b/evennia/server/inputfuncs.py index 3715bb53fe..28546c2064 100644 --- a/evennia/server/inputfuncs.py +++ b/evennia/server/inputfuncs.py @@ -160,10 +160,10 @@ def client_options(session, *args, **kwargs): raw (bool): Turn off parsing """ - flags = session.protocol_flags + old_flags = session.protocol_flags if not kwargs or kwargs.get("get", False): # return current settings - options = dict((key, flags[key]) for key in flags + options = dict((key, old_flags[key]) for key in old_flags if key.upper() in ("ANSI", "XTERM256", "MXP", "UTF-8", "SCREENREADER", "ENCODING", "MCCP", "SCREENHEIGHT", @@ -189,6 +189,7 @@ def client_options(session, *args, **kwargs): return True if val.lower() in ("true", "on", "1") else False return bool(val) + flags = {} for key, value in kwargs.iteritems(): key = key.lower() if key == "client": @@ -230,9 +231,11 @@ def client_options(session, *args, **kwargs): err = _ERROR_INPUT.format( name="client_settings", session=session, inp=key) session.msg(text=err) - session.protocol_flags = flags - # we must update the portal as well - session.sessionhandler.session_portal_sync(session) + + session.protocol_flags.update(flags) + # we must update the protocol flags on the portal session copy as well + session.sessionhandler.session_portal_partial_sync( + {session.sessid: {"protocol_flags": flags}}) # GMCP alias diff --git a/evennia/server/portal/telnet.py b/evennia/server/portal/telnet.py index 4112d85e2a..afd0a9094f 100644 --- a/evennia/server/portal/telnet.py +++ b/evennia/server/portal/telnet.py @@ -72,7 +72,7 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): # timeout the handshakes in case the client doesn't reply at all from evennia.utils.utils import delay - delay(2, callback=self.handshake_done, force=True) + delay(2, callback=self.handshake_done, timeout=True) # TCP/IP keepalive watches for dead links self.transport.setTcpKeepAlive(1) @@ -100,17 +100,18 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session): self.nop_keep_alive = LoopingCall(self._send_nop_keepalive) self.nop_keep_alive.start(30, now=False) - def handshake_done(self, force=False): + def handshake_done(self, timeout=False): """ This is called by all telnet extensions once they are finished. When all have reported, a sync with the server is performed. The system will force-call this sync after a small time to handle clients that don't reply to handshakes at all. """ - if self.handshakes > 0: - if force: + if timeout: + if self.handshakes > 0: + self.handshakes = 0 self.sessionhandler.sync(self) - return + else: self.handshakes -= 1 if self.handshakes <= 0: # do the sync diff --git a/evennia/server/portal/ttype.py b/evennia/server/portal/ttype.py index 96ae1c1100..b9c3e8b239 100644 --- a/evennia/server/portal/ttype.py +++ b/evennia/server/portal/ttype.py @@ -66,7 +66,7 @@ class Ttype(object): option (Option): Not used. """ - self.protocol.protocol_flags['TTYPE'] = True + self.protocol.protocol_flags['TTYPE'] = False self.protocol.handshake_done() def will_ttype(self, option): diff --git a/evennia/server/session.py b/evennia/server/session.py index 70be0708d7..cf29430185 100644 --- a/evennia/server/session.py +++ b/evennia/server/session.py @@ -118,7 +118,13 @@ class Session(object): """ for propname, value in sessdata.items(): - setattr(self, propname, value) + if (propname == "prototocol_flags" and isinstance(value, dict) and + hasattr(self, "protocol_flags") and + isinstance(self.protocol_flags.propname, dict)): + # special handling to allow partial update of protocol flags + self.protocol_flags.update(value) + else: + setattr(self, propname, value) def at_sync(self): """ diff --git a/evennia/server/sessionhandler.py b/evennia/server/sessionhandler.py index 825cf6da30..c8c0fafd64 100644 --- a/evennia/server/sessionhandler.py +++ b/evennia/server/sessionhandler.py @@ -538,6 +538,22 @@ class ServerSessionHandler(SessionHandler): sessiondata=sessdata, clean=False) + def session_portal_partial_sync(self, session_data): + """ + Call to make a partial update of the session, such as only a particular property. + + Args: + session_data (dict): Store `{sessid: {property:value}, ...}` defining one or + more sessions in detail. + + """ + return self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, + operation=SSYNC, + sessiondata=session_data, + clean=False) + + + def disconnect_all_sessions(self, reason="You have been disconnected."): """ Cleanly disconnect all of the connected sessions.