-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchatserver.py
executable file
·111 lines (88 loc) · 3.38 KB
/
chatserver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python
import sys
from twisted.protocols import amp
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory
from twisted.python import usage
from twisted.cred.checkers import FilePasswordDB
from twisted.cred.portal import Portal
from twisted.cred import credentials
from Realm import Realm, IAvatar
import commands
default_port = 65432
class Options(usage.Options):
optParameters = [
["port", "p", default_port, "server port"],
]
class ChatProtocol(amp.AMP):
@commands.Login.responder
def login(self, username, password):
"""Attempt to login."""
if username in self.factory.username_to_protocol:
raise commands.LoginError("User '%s' already logged in" % username)
creds = credentials.UsernamePassword(username, password)
deferred = self.factory.portal.login(creds, None, IAvatar)
deferred.addCallback(self.login_succeeded)
deferred.addErrback(self.login_failed)
return deferred
def login_succeeded(self, (avatar_interface, avatar, logout)):
name = avatar.name
self.username = name
self.factory.username_to_protocol[name] = self
# Tell all users about this user
for protocol in self.factory.username_to_protocol.itervalues():
protocol.callRemote(commands.AddUser, user=name)
# Tell this user about all other users
for username in self.factory.username_to_protocol:
if username != name:
self.callRemote(commands.AddUser, user=username)
return {}
def login_failed(self, failure):
raise commands.LoginError("Incorrect username or password")
@commands.SendToUsers.responder
def send_to_users(self, message, usernames):
for username in usernames:
protocol = self.factory.username_to_protocol.get(username)
if protocol:
protocol.callRemote(commands.Send, message=message,
sender=self.username)
# Also show it to the sender
if self.username not in usernames:
self.callRemote(commands.Send, message=message,
sender=self.username)
return {}
@commands.SendToAll.responder
def send_to_all(self, message):
for protocol in self.factory.username_to_protocol.itervalues():
protocol.callRemote(commands.Send, message=message,
sender=self.username)
return {}
def connectionLost(self, unused):
try:
del self.factory.username_to_protocol[self.username]
except KeyError:
pass
for protocol in self.factory.username_to_protocol.itervalues():
protocol.callRemote(commands.DelUser, user=self.username)
class ChatFactory(ServerFactory):
protocol = ChatProtocol
def __init__(self, portal):
self.portal = portal
self.username_to_protocol = {}
def main():
options = Options()
try:
options.parseOptions()
except usage.UsageError, err:
print "%s: %s" % (sys.argv[0], err)
print "%s: Try --help for usage details" % sys.argv[0]
sys.exit(1)
port = int(options["port"])
realm = Realm()
checker = FilePasswordDB("passwd.txt")
portal = Portal(realm, [checker])
factory = ChatFactory(portal)
reactor.listenTCP(port, factory)
reactor.run()
if __name__ == "__main__":
main()