1
<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>Twisted Documentation: Managing Clients of Perspectives</title><link href="stylesheet.css" type="text/css" rel="stylesheet" /><link href="http://twistedmatrix.com/users/acapnotic/" rel="author" title="Kevin Turner" /></head><body bgcolor="white"><h1 class="title">Managing Clients of Perspectives</h1><div class="toc"><ol><li><a href="#auto0">Overview</a></li><li><a href="#auto1">Managing Avatars</a></li><li><a href="#auto2">Managing Clients</a></li></ol></div><div class="content"><span></span><h2>Overview<a name="auto0"></a></h2><p>In all the <code class="API"><a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.spread.pb.IPerspective.html" title="twisted.spread.pb.IPerspective">IPerspective</a></code>
1
<?xml version="1.0" encoding="utf-8"?>
3
PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'
4
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
5
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
7
<title>Twisted Documentation: Managing Clients of Perspectives</title>
8
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
9
<link href="http://twistedmatrix.com/users/acapnotic/" rel="author" title="Kevin Turner"/></head>
11
<body bgcolor="white">
12
<h1 class="title">Managing Clients of Perspectives</h1>
13
<div class="toc"><ol><li><a href="#auto0">Overview</a></li><li><a href="#auto1">Managing Avatars</a></li><li><a href="#auto2">Managing Clients</a></li></ol></div>
17
<h2>Overview<a name="auto0"/></h2>
19
<p>In all the <code class="API"><a href="http://twistedmatrix.com/documents/9.0.0/api/twisted.spread.pb.IPerspective.html" title="twisted.spread.pb.IPerspective">IPerspective</a></code>
3
20
we have shown so far, we ignored the <code>mind</code> argument and created
4
21
a new <code>Avatar</code> for every connection. This is usually an easy
5
design choice, and it works well for simple cases.</p><p>In more complicated cases, for example an <code>Avatar</code> that
22
design choice, and it works well for simple cases.</p>
24
<p>In more complicated cases, for example an <code>Avatar</code> that
6
25
represents a player object which is persistent in the game universe,
7
26
we will want connections from the same player to use the same
8
<code>Avatar</code>.</p><p>Another thing which is necessary in more complicated scenarios
27
<code>Avatar</code>.</p>
29
<p>Another thing which is necessary in more complicated scenarios
9
30
is notifying a player asynchronously. While it is possible, of
10
31
course, to allow a player to call
11
32
<code>perspective_remoteListener(referencable)</code> that would
12
33
mean both duplication of code and a higher latency in logging in,
13
both bad.</p><p>In previous sections all realms looked to be identical.
36
<p>In previous sections all realms looked to be identical.
14
37
In this one we will show the usefulness of realms in accomplishing
15
those two objectives.</p><h2>Managing Avatars<a name="auto1"></a></h2><p>The simplest way to manage persistent avatars is to use a straight-forward
16
caching mechanism:</p><pre class="python">
17
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
38
those two objectives.</p>
40
<h2>Managing Avatars<a name="auto1"/></h2>
42
<p>The simplest way to manage persistent avatars is to use a straight-forward
43
caching mechanism:</p>
45
<pre class="python"><p class="py-linenumber"> 1
68
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
19
70
<span class="py-src-keyword">class</span> <span class="py-src-identifier">SimpleAvatar</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Avatar</span>):
20
71
<span class="py-src-variable">greetings</span> = <span class="py-src-number">0</span>
37
88
<span class="py-src-keyword">else</span>:
38
89
<span class="py-src-variable">p</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">avatars</span>[<span class="py-src-variable">avatarId</span>] = <span class="py-src-variable">SimpleAvatar</span>(<span class="py-src-variable">avatarId</span>)
39
90
<span class="py-src-keyword">return</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">IPerspective</span>, <span class="py-src-variable">p</span>, <span class="py-src-keyword">lambda</span>:<span class="py-src-variable">None</span>
40
</pre><p>This gives us a perspective which counts the number of greetings it
93
<p>This gives us a perspective which counts the number of greetings it
41
94
sent its client. Implementing a caching strategy, as opposed to generating
42
95
a realm with the correct avatars already in it, is usually easier. This
43
96
makes adding new checkers to the portal, or adding new users to a checker
44
97
database, transparent. Otherwise, careful synchronization is needed between
45
98
the checker and avatar is needed (much like the synchronization between
46
UNIX's <code>/etc/shadow</code> and <code>/etc/passwd</code>).</p><p>Sometimes, however, an avatar will need enough per-connection state
99
UNIX's <code>/etc/shadow</code> and <code>/etc/passwd</code>).</p>
101
<p>Sometimes, however, an avatar will need enough per-connection state
47
102
that it would be easier to generate a new avatar and cache something
48
else. Here is an example of that:</p><pre class="python">
49
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
103
else. Here is an example of that:</p>
105
<pre class="python"><p class="py-linenumber"> 1
134
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
51
136
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Greeter</span>:
52
137
<span class="py-src-variable">greetings</span> = <span class="py-src-number">0</span>
75
160
<span class="py-src-keyword">else</span>:
76
161
<span class="py-src-variable">p</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">greeters</span>[<span class="py-src-variable">avatarId</span>] = <span class="py-src-variable">Greeter</span>()
77
162
<span class="py-src-keyword">return</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">IPerspective</span>, <span class="py-src-variable">SimpleAvatar</span>(<span class="py-src-variable">avatarId</span>, <span class="py-src-variable">p</span>), <span class="py-src-keyword">lambda</span>:<span class="py-src-variable">None</span>
78
</pre><p>It might seem tempting to use this pattern to have an avatar which
165
<p>It might seem tempting to use this pattern to have an avatar which
79
166
is notified of new connections. However, the problems here are twofold:
80
167
it would lead to a thin class which needs to forward all of its methods,
81
168
and it would be impossible to know when disconnections occur. Luckily,
82
there is a better pattern:</p><pre class="python">
83
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
169
there is a better pattern:</p>
171
<pre class="python"><p class="py-linenumber"> 1
200
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
85
202
<span class="py-src-keyword">class</span> <span class="py-src-identifier">SimpleAvatar</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Avatar</span>):
86
203
<span class="py-src-variable">greetings</span> = <span class="py-src-number">0</span>
109
226
<span class="py-src-variable">p</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">avatars</span>[<span class="py-src-variable">avatarId</span>] = <span class="py-src-variable">SimpleAvatar</span>(<span class="py-src-variable">avatarId</span>)
110
227
<span class="py-src-variable">p</span>.<span class="py-src-variable">connect</span>()
111
228
<span class="py-src-keyword">return</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">IPerspective</span>, <span class="py-src-variable">p</span>, <span class="py-src-variable">p</span>.<span class="py-src-variable">disconnect</span>
112
</pre><p>It is possible to use such a pattern to define an arbitrary limit for
113
the number of concurrent connections:</p><pre class="python">
114
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
231
<p>It is possible to use such a pattern to define an arbitrary limit for
232
the number of concurrent connections:</p>
234
<pre class="python"><p class="py-linenumber"> 1
266
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
116
268
<span class="py-src-keyword">class</span> <span class="py-src-identifier">SimpleAvatar</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Avatar</span>):
117
269
<span class="py-src-variable">greetings</span> = <span class="py-src-number">0</span>
143
295
<span class="py-src-keyword">raise</span> <span class="py-src-variable">ValueError</span>(<span class="py-src-string">"too many connections"</span>)
144
296
<span class="py-src-variable">p</span>.<span class="py-src-variable">connect</span>()
145
297
<span class="py-src-keyword">return</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">IPerspective</span>, <span class="py-src-variable">p</span>, <span class="py-src-variable">p</span>.<span class="py-src-variable">disconnect</span>
146
</pre><h2>Managing Clients<a name="auto2"></a></h2><p>So far, all our realms have ignored the <code>mind</code> argument.
300
<h2>Managing Clients<a name="auto2"/></h2>
302
<p>So far, all our realms have ignored the <code>mind</code> argument.
147
303
In the case of PB, the <code>mind</code> is an object supplied by
148
304
the remote login method -- usually, when it passes over the wire,
149
305
it becomes a <code>pb.RemoteReference</code>. This object allows
150
306
sending messages to the client as soon as the connection is established
151
and authenticated.</p><p>Here is a simple remote-clock application which shows the usefulness
152
of the <code>mind</code> argument:</p><pre class="python">
153
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
307
and authenticated.</p>
309
<p>Here is a simple remote-clock application which shows the usefulness
310
of the <code>mind</code> argument:</p>
312
<pre class="python"><p class="py-linenumber"> 1
335
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
155
337
<span class="py-src-keyword">class</span> <span class="py-src-identifier">SimpleAvatar</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Avatar</span>):
156
338
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">client</span>):
173
355
<span class="py-src-keyword">if</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">IPerspective</span> <span class="py-src-keyword">not</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">interfaces</span>: <span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>
174
356
<span class="py-src-variable">p</span> = <span class="py-src-variable">SimpleAvatar</span>(<span class="py-src-variable">mind</span>)
175
357
<span class="py-src-keyword">return</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">IPerspective</span>, <span class="py-src-variable">p</span>, <span class="py-src-variable">p</span>.<span class="py-src-variable">logout</span>
176
</pre><p>In more complicated situations, you might want to cache the avatars
177
and give each one a set of <q>current clients</q> or something similar.</p></div><p><a href="index.html">Index</a></p><span class="version">Version: 8.2.0</span></body></html>
b'\\ No newline at end of file'
360
<p>In more complicated situations, you might want to cache the avatars
361
and give each one a set of <q>current clients</q> or something similar.</p>
365
<p><a href="index.html">Index</a></p>
366
<span class="version">Version: 9.0.0</span>
b'\\ No newline at end of file'