2 """Holds the state of a list of selected Yadis services, managing
3 storing it in a session and iterating over the services in order."""
4
5 - def __init__(self, starting_url, yadis_url, services, session_key):
6
7 self.starting_url = starting_url
8
9
10 self.yadis_url = yadis_url
11
12
13 self.services = list(services)
14
15 self.session_key = session_key
16
17
18 self._current = None
19
21 """How many untried services remain?"""
22 return len(self.services)
23
26
28 """Return the next service
29
30 self.current() will continue to return that service until the
31 next call to this method."""
32 try:
33 self._current = self.services.pop(0)
34 except IndexError:
35 raise StopIteration
36 else:
37 return self._current
38
40 """Return the current service.
41
42 Returns None if there are no services left.
43 """
44 return self._current
45
47 return url in [self.starting_url, self.yadis_url]
48
50 """Has the first service been returned?"""
51 return self._current is not None
52
53 - def store(self, session):
54 """Store this object in the session, by its session key."""
55 session[self.session_key] = self
56
58 """State management for discovery.
59
60 High-level usage pattern is to call .getNextService(discover) in
61 order to find the next available service for this user for this
62 session. Once a request completes, call .finish() to clean up the
63 session state.
64
65 @ivar session: a dict-like object that stores state unique to the
66 requesting user-agent. This object must be able to store
67 serializable objects.
68
69 @ivar url: the URL that is used to make the discovery request
70
71 @ivar session_key_suffix: The suffix that will be used to identify
72 this object in the session object.
73 """
74
75 DEFAULT_SUFFIX = 'auth'
76 PREFIX = '_yadis_services_'
77
78 - def __init__(self, session, url, session_key_suffix=None):
79 """Initialize a discovery object"""
80 self.session = session
81 self.url = url
82 if session_key_suffix is None:
83 session_key_suffix = self.DEFAULT_SUFFIX
84
85 self.session_key_suffix = session_key_suffix
86
88 """Return the next authentication service for the pair of
89 user_input and session. This function handles fallback.
90
91
92 @param discover: a callable that takes a URL and returns a
93 list of services
94
95 @type discover: str -> [service]
96
97
98 @return: the next available service
99 """
100 manager = self.getManager()
101 if manager is not None and not manager:
102 self.destroyManager()
103
104 if not manager:
105 yadis_url, services = discover(self.url)
106 manager = self.createManager(services, yadis_url)
107
108 if manager:
109 service = manager.next()
110 manager.store(self.session)
111 else:
112 service = None
113
114 return service
115
117 """Clean up Yadis-related services in the session and return
118 the most-recently-attempted service from the manager, if one
119 exists.
120
121 @param force: True if the manager should be deleted regardless
122 of whether it's a manager for self.url.
123
124 @return: current service endpoint object or None if there is
125 no current service
126 """
127 manager = self.getManager(force=force)
128 if manager is not None:
129 service = manager.current()
130 self.destroyManager(force=force)
131 else:
132 service = None
133
134 return service
135
136
137
139 """Get the session key for this starting URL and suffix
140
141 @return: The session key
142 @rtype: str
143 """
144 return self.PREFIX + self.session_key_suffix
145
147 """Extract the YadisServiceManager for this object's URL and
148 suffix from the session.
149
150 @param force: True if the manager should be returned
151 regardless of whether it's a manager for self.url.
152
153 @return: The current YadisServiceManager, if it's for this
154 URL, or else None
155 """
156 manager = self.session.get(self.getSessionKey())
157 if (manager is not None and (manager.forURL(self.url) or force)):
158 return manager
159 else:
160 return None
161
163 """Create a new YadisService Manager for this starting URL and
164 suffix, and store it in the session.
165
166 @raises KeyError: When I already have a manager.
167
168 @return: A new YadisServiceManager or None
169 """
170 key = self.getSessionKey()
171 if self.getManager():
172 raise KeyError('There is already a %r manager for %r' %
173 (key, self.url))
174
175 if not services:
176 return None
177
178 manager = YadisServiceManager(self.url, yadis_url, services, key)
179 manager.store(self.session)
180 return manager
181
183 """Delete any YadisServiceManager with this starting URL and
184 suffix from the session.
185
186 If there is no service manager or the service manager is for a
187 different URL, it silently does nothing.
188
189 @param force: True if the manager should be deleted regardless
190 of whether it's a manager for self.url.
191 """
192 if self.getManager(force=force) is not None:
193 key = self.getSessionKey()
194 del self.session[key]
195