2
# Twisted, the Framework of Your Internet
3
# Copyright (C) 2001 Matthew W. Lefkowitz
5
# This library is free software; you can redistribute it and/or
6
# modify it under the terms of version 2.1 of the GNU Lesser General Public
7
# License as published by the Free Software Foundation.
9
# This library is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
# Lesser General Public License for more details.
14
# You should have received a copy of the GNU Lesser General Public
15
# License along with this library; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
"""Plumbing classes (pump, pipeline) to put Twisted Reality on the net.
23
from cStringIO import StringIO
25
from twisted.reality import player
26
from twisted.protocols import telnet, protocol, http
27
from twisted.python import log
28
from twisted.internet import tcp
29
from twisted.web import resource, html, widgets, guard
30
from twisted import copyright
33
from twisted.cred.util import Unauthorized
38
class Hose(telnet.Telnet):
39
"""A telnet protocol implementation for TR.
43
def welcomeMessage(self):
44
"""A message welcoming you to TR.
46
return "\r\nTwisted Reality %s\r\n" % copyright.version
49
def loginPrompt(self):
50
"""A login prompt that asks for your character name.
55
def processPassword(self, password):
56
"""Checks authentication against the reality; returns a boolean indicating success.
58
self.transport.write(telnet.IAC+ telnet.WONT+ telnet.ECHO+".....\r\n")
59
req = self.factory.reality.application.authorizer.getIdentityRequest(self.username)
61
req.addCallbacks(self.loggedIn, self.notLoggedIn)
63
# kludge; this really ought to be called later, but since the arm()
64
# call actually calls self.loggedIn, then the return value of this
65
# function will be used to assign to self.mode... ugh.
66
if self.mode == 'Command':
70
def loggedIn(self, identity):
71
"""The player's identity has been retrieved. Now, check their password.
73
if identity.verifyPlainPassword(self.pw):
74
# The identity checks out.
76
# XXX REFACTOR: Hmm. Is this next bit common behavior?
77
r = self.factory.reality
78
nm = r.getServiceName()
79
for serviceName, perspectiveName in identity.getAllKeys():
82
### This can't really be done this way.
83
### getPerspectiveNamed ought to be asynchronous.
84
characters.append(r.getPerspectiveNamed(perspectiveName))
90
self.transport.write("TODO: character selection menu\r\n")
92
raise Unauthorized("that identity has no TR characters")
94
p = p.attached(self, identity)
96
self.identity = identity
97
self.transport.write("Hello "+self.player.name+", welcome to Reality!\r\n"+
98
telnet.IAC+telnet.WONT+telnet.ECHO)
101
log.msg("incorrect password")
102
self.transport.loseConnection()
104
def notLoggedIn(self, err):
105
log.msg('requested bad username')
106
self.transport.loseConnection()
108
def processPending(self, pend):
109
self.transport.write("Please hold...\r\n")
112
def processCommand(self, cmd):
113
"""Execute a command as a player.
115
self.player.execute(cmd)
118
def connectionLost(self):
119
"""Disconnect player from this Intelligence, and clean up connection.
121
telnet.Telnet.connectionLost(self)
122
if hasattr(self, 'player'):
123
if hasattr(self.player, 'intelligence'):
124
self.player.detached(self, self.identity)
126
def seeName(self, name):
127
"""Display a focused name bracketed, in bold.
129
self.transport.write(telnet.BOLD_MODE_ON+"[ "+name+" ]"+telnet.BOLD_MODE_OFF+
132
def callRemote(self, key, *args, **kw):
133
# pass-through of remote methods
134
apply(getattr(self, key), args, kw)
137
def seeItem(self, key, parent, value):
138
"""Display an item that's present.
140
self.transport.write(" "+value+"\r\n")
142
def dontSeeItem(self, key, parent):
143
"""no-op; would be nonsensical over telnet.
146
def seeNoItems(self):
147
"""no-op; would be nonsensical over telnet.
150
def seeExit(self, direction):
151
"""Display a single exit.
153
self.transport.write("You can go "+direction+"\r\n")
155
def dontSeeExit(self, direction):
156
"""no-op; would be nonsensical over telnet.
159
def seeNoExits(self):
160
"""no-op; would be nonsensical over telnet.
163
def seeDescription(self, key, description):
164
"""Displays a description.
166
self.transport.write(description+"\r\n")
168
def dontSeeDescription(self, key):
169
"""no-op; would be nonsensical over telnet.
172
def seeNoDescriptions(self):
173
"""no-op; would be nonsensical over telnet.
176
def seeEvent(self, string):
177
"""Displays an event to the player.
179
self.transport.write(string+'\r\n')
181
def request(self, question,default,ok,cancel):
182
"""Requests are not supported by this interface; calls cancel() immediately.
184
self.transport.write('edit operations not supported in telnet!\r\n')
189
class Spigot(protocol.Factory):
191
A telnet factory for twisted.reality.
194
def buildProtocol(self, addr):
199
def __init__(self, world):
200
"""Initialize with a twisted.reality.Reality instance.
204
class ThingWidget(widgets.StreamWidget):
205
"""A web-based interface to a twisted.reality.thing.Thing.
207
def __init__(self, thing):
208
"""Initialize with a particular thing.
212
def getTitle(self, request):
213
"""Return a page title formatting the request.
215
session = request.getSession()
216
return "Twisted Reality: %s" % self.thing.shortName(session.truser)
218
def stream(self, write, request):
219
"""Display representation of a Thing (or move a Thing and redirect, depending on URI).
221
player = request.getSession().truser
222
if request.args.has_key("action"):
224
# request.setHeader("refresh","0; URL=%s" % (request.prePathURL()))
225
player.location = self.thing
227
write("I have an action key! %s, %s" % (player.location, self.thing))
228
# write("Redirecting...")
229
write("<table><tr><td colspan=2>")
230
write(self.thing.descriptionTo(player))
231
write('<br><A HREF="%s?action=moveMe">Move Me Here</a>' %
232
(request.prePathURL()))
233
write("</td></tr><tr><td><ul>")
234
for thing in self.thing.getThings(player):
235
write('<LI><A HREF="%s">%s</A>' % (
237
thing.presentPhrase(player)))
238
if self.thing in player.locations:
239
write('<hr><li><A HREF="%s">You are here.</a>' % (player.thing_id))
240
write("</ul></td><td>")
242
for direc in self.thing.exits:
243
dest = self.thing.findExit(direc)
247
write('<A HREF="%s">' % dest.thing_id)
248
write(dest.shortName(player))
251
write("</td></tr></table>")
253
class Web(guard.ResourceGuard):
254
def __init__(self, reality):
255
guard.ResourceGuard.__init__(self, _Web(reality), reality, 'realIdent', 'truser')
257
class _Web(widgets.Gadget, widgets.StreamWidget):
258
"""A web interface to a twisted.reality.reality.Reality.
260
def __init__(self, in_reality):
261
"""Initialize with a reality.
263
widgets.Gadget.__init__(self)
264
self.reality = in_reality
266
def getWidget(self, name, request):
267
"""Get a Thing from this reality.
269
return ThingWidget(self.reality.getThingById(int(name)))
271
def stream(self, write, request):
272
"""List all availble Things and there IDs
274
player = request.getSession().truser
276
for thing in self.reality.objects():
277
np = thing.nounPhrase(player)
278
write('<LI><A HREF="%s">%s</a>\n'% (str(thing.thing_id),np))