[CalendarServer-changes] [9058] CalendarServer/branches/users/glyph/ipv6-client/twext/internet
source_changes at macosforge.org
source_changes at macosforge.org
Fri Apr 13 11:44:01 PDT 2012
Revision: 9058
http://trac.macosforge.org/projects/calendarserver/changeset/9058
Author: glyph at apple.com
Date: 2012-04-13 11:44:01 -0700 (Fri, 13 Apr 2012)
Log Message:
-----------
Adapter endpoint that can wrap around a client factory.
Added Paths:
-----------
CalendarServer/branches/users/glyph/ipv6-client/twext/internet/adaptendpoint.py
CalendarServer/branches/users/glyph/ipv6-client/twext/internet/test/test_adaptendpoint.py
Added: CalendarServer/branches/users/glyph/ipv6-client/twext/internet/adaptendpoint.py
===================================================================
--- CalendarServer/branches/users/glyph/ipv6-client/twext/internet/adaptendpoint.py (rev 0)
+++ CalendarServer/branches/users/glyph/ipv6-client/twext/internet/adaptendpoint.py 2012-04-13 18:44:01 UTC (rev 9058)
@@ -0,0 +1,131 @@
+# -*- test-case-name: twext.internet.test.test_adaptendpoint -*-
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+"""
+Adapter for old-style connectTCP/connectSSL code to use endpoints and be happy;
+specifically, to receive the additional duplicate notifications that it wants to
+receive, L{clientConnectionLost} and L{clientConnectionFailed} on the factory.
+"""
+
+from zope.interface import implements
+
+from twisted.internet.interfaces import IConnector
+
+from twisted.internet.protocol import Factory
+from twisted.python import log
+
+
+
+class _WrappedProtocol(object):
+ """
+ A wrapped protocol.
+ """
+
+ def __init__(self, wrapped, wrapper):
+ self._wrapped = wrapped
+ self._wrapper = wrapper
+
+
+ def __getattr__(self, attr):
+ """
+ Relay all undefined methods to the wrapped protocol.
+ """
+ return getattr(self._wrapped, attr)
+
+
+ def connectionLost(self, reason):
+ try:
+ self._wrapped.connectionLost(reason)
+ except:
+ log.err()
+ self._wrapper.callClientConnectionLost(reason)
+
+
+
+class LegacyConnector(object):
+ """
+ Legacy IConnector interface implementation for stuff that uses endpoints.
+ """
+ implements(IConnector)
+
+
+ def __init__(self, wrapper):
+ self.wrapper = wrapper
+
+
+ def getDestination(self):
+ """
+ I don't know, endpoints don't have a destination.
+ """
+ return self.wrapper.endpoint
+
+
+ def connect(self):
+ self.wrapper.beginConnectionAttempt()
+
+
+ def stopConnecting(self):
+ self.wrapper.stopConnectionAttempt()
+ self.wrapper.endpoint.connect(self.wrapper)
+
+
+ def disconnect(self):
+ pass
+
+
+
+class LegacyClientFactoryWrapper(Factory):
+
+ def __init__(self, legacyFactory, endpoint):
+ self.currentlyConnecting = False
+ self.legacyFactory = legacyFactory
+ self.endpoint = endpoint
+ self._connectedProtocol = None
+
+
+ def buildProtocol(self, addr):
+ return _WrappedProtocol(self.legacyFactory.buildProtocol(addr), self)
+
+
+ def callStartedConnecting(self):
+ self.legacyFactory.startedConnecting(LegacyConnector(self))
+
+
+ def callClientConnectionLost(self, reason):
+ self.legacyFactory.clientConnectionLost(LegacyConnector(self), reason)
+
+
+ def callClientConnectionFailed(self):
+ self.legacyFactory.clientConnectionFailed()
+
+
+ def disconnect(self):
+ if self._connectedProtocol is not None:
+ self._connectedProtocol.transport.abortConnection()
+ else:
+ pass
+
+# from twisted.internet.interfaces import IStreamClientEndpoint
+
+def connect(endpoint, clientFactory):
+ """
+ Connect a L{twisted.internet.protocol.ClientFactory} using the given
+ L{twisted.internet.interfaces.IStreamClientEndpoint}.
+ """
+ wrap = LegacyClientFactoryWrapper(clientFactory, endpoint)
+ endpoint.connect(wrap)
+ return LegacyConnector(wrap)
+
Added: CalendarServer/branches/users/glyph/ipv6-client/twext/internet/test/test_adaptendpoint.py
===================================================================
--- CalendarServer/branches/users/glyph/ipv6-client/twext/internet/test/test_adaptendpoint.py (rev 0)
+++ CalendarServer/branches/users/glyph/ipv6-client/twext/internet/test/test_adaptendpoint.py 2012-04-13 18:44:01 UTC (rev 9058)
@@ -0,0 +1,143 @@
+##
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+"""
+Tests for L{twext.internet.adaptendpoint}.
+"""
+
+from zope.interface.verify import verifyObject
+
+from twext.internet.adaptendpoint import connect
+from twisted.internet.defer import Deferred
+from twisted.python.failure import Failure
+
+from twisted.internet.protocol import ClientFactory, Protocol
+from twisted.internet.interfaces import IConnector
+from twisted.trial.unittest import TestCase
+
+class names(object):
+ def __init__(self, **kw):
+ self.__dict__.update(kw)
+
+
+class RecordingProtocol(Protocol, object):
+ def __init__(self):
+ super(RecordingProtocol, self).__init__()
+ self.made = []
+ self.data = []
+ self.lost = []
+
+
+ def connectionMade(self):
+ self.made.append(self.transport)
+
+
+ def dataReceived(self, data):
+ self.data.append(data)
+
+
+ def connectionLost(self, why):
+ self.lost.append(why)
+
+
+
+class RecordingClientFactory(ClientFactory):
+ """
+ L{ClientFactory} subclass that records the things that happen to it.
+ """
+
+ def __init__(self):
+ """
+ Create some records of things that are about to happen.
+ """
+ self.starts = []
+ self.built = []
+ self.fails = []
+ self.lost = []
+
+ def startedConnecting(self, ctr):
+ self.starts.append(ctr)
+
+ def clientConnectionFailed(self, ctr, reason):
+ self.fails.append(names(connector=ctr, reason=reason))
+
+ def clientConnectionLost(self, ctr, reason):
+ self.lost.append(names(connector=ctr, reason=reason))
+
+ def buildProtocol(self, addr):
+ b = RecordingProtocol()
+ self.built.append(names(protocol=b, addr=addr))
+ return b
+
+
+class RecordingEndpoint(object):
+
+ def __init__(self):
+ self.attempts = []
+
+
+ def connect(self, factory):
+ d = Deferred()
+ self.attempts.append(names(deferred=d, factory=factory))
+ return d
+
+
+class AdaptEndpointTests(TestCase):
+ """
+ Tests for L{connect} and the objects that it coordinates.
+ """
+
+ def test_connectStartsConnection(self):
+ """
+ When used with a successful endpoint, L{connect} will simulate all
+ aspects of the connection process; C{buildProtocol}, C{connectionMade},
+ C{dataReceived}.
+ """
+ rcf = RecordingClientFactory()
+ e = RecordingEndpoint()
+ ctr = connect(e, rcf)
+ self.assertIdentical(ctr.getDestination(), e)
+ verifyObject(IConnector, ctr)
+ self.assertEqual(len(e.attempts), 1)
+ self.assertEqual(len(rcf.built), 0)
+ proto = e.attempts[0].factory.buildProtocol(object)
+ self.assertEqual(len(rcf.built), 1)
+ made = rcf.built[0].protocol.made
+ transport = object()
+ self.assertEqual(len(made), 0)
+ proto.makeConnection(transport)
+ self.assertEqual(len(made), 1)
+ self.assertIdentical(made[0], transport)
+
+
+ def test_connectionLost(self):
+ """
+ When the connection is lost, both the protocol and the factory will be
+ notified via connectionLost and clientConnectionLost.
+ """
+ rcf = RecordingClientFactory()
+ e = RecordingEndpoint()
+ connect(e, rcf)
+ why = Failure(RuntimeError())
+ proto = e.attempts[0].factory.buildProtocol(object)
+ proto.makeConnection(object())
+ proto.connectionLost(why)
+ self.assertEquals(len(rcf.built), 1)
+ self.assertEquals(rcf.built[0].protocol.lost, [why])
+ self.assertEquals(len(rcf.lost), 1)
+ self.assertIdentical(rcf.lost[0].reason, why)
+
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120413/44ba6fee/attachment-0001.html>
More information about the calendarserver-changes
mailing list