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
25 return self
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 @return: current service endpoint object or None if there is
122 no current service
123 """
124 manager = self.getManager()
125 if manager is not None:
126 service = manager.current()
127 self.destroyManager()
128 else:
129 service = None
130
131 return service
132
133
134
136 """Get the session key for this starting URL and suffix
137
138 @return: The session key
139 @rtype: str
140 """
141 return self.PREFIX + self.session_key_suffix
142
144 """Extract the YadisServiceManager for this object's URL and
145 suffix from the session.
146
147 @return: The current YadisServiceManager, if it's for this
148 URL, or else None
149 """
150 manager = self.session.get(self.getSessionKey())
151 if (manager is not None and manager.forURL(self.url)):
152 return manager
153 else:
154 return None
155
157 """Create a new YadisService Manager for this starting URL and
158 suffix, and store it in the session.
159
160 @raises KeyError: When I already have a manager.
161
162 @return: A new YadisServiceManager or None
163 """
164 key = self.getSessionKey()
165 if self.getManager():
166 raise KeyError('There is already a %r manager for %r' %
167 (key, self.url))
168
169 if not services:
170 return None
171
172 manager = YadisServiceManager(self.url, yadis_url, services, key)
173 manager.store(self.session)
174 return manager
175
177 """Delete any YadisServiceManager with this starting URL and
178 suffix from the session.
179
180 If there is no service manager or the service manager is for a
181 different URL, it silently does nothing.
182 """
183 if self.getManager() is not None:
184 key = self.getSessionKey()
185 del self.session[key]
186