github / src / client.py @ fa348e33
1 |
# Copyright (c) 2016, LE GOFF Vincent |
---|---|
2 |
# All rights reserved.
|
3 |
|
4 |
# Redistribution and use in source and binary forms, with or without
|
5 |
# modification, are permitted provided that the following conditions are met:
|
6 |
|
7 |
# * Redistributions of source code must retain the above copyright notice, this
|
8 |
# list of conditions and the following disclaimer.
|
9 |
|
10 |
# * Redistributions in binary form must reproduce the above copyright notice,
|
11 |
# this list of conditions and the following disclaimer in the documentation
|
12 |
# and/or other materials provided with the distribution.
|
13 |
|
14 |
# * Neither the name of ytranslate nor the names of its
|
15 |
# contributors may be used to endorse or promote products derived from
|
16 |
# this software without specific prior written permission.
|
17 |
|
18 |
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19 |
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20 |
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21 |
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
22 |
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
23 |
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
24 |
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
25 |
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
26 |
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27 |
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28 |
|
29 |
"""This file contains the client that can connect to a MUD.
|
30 |
|
31 |
It is launched in a new thread, so as not to block the main thread.
|
32 |
|
33 |
"""
|
34 |
|
35 |
import re |
36 |
from telnetlib import Telnet, WONT, WILL, ECHO |
37 |
import threading |
38 |
import time |
39 |
|
40 |
try:
|
41 |
from UniversalSpeech import say, braille |
42 |
except ImportError: |
43 |
say = None
|
44 |
braille = None
|
45 |
|
46 |
from sharp.engine import SharpScript |
47 |
|
48 |
# Constants
|
49 |
ANSI_ESCAPE = re.compile(r'\x1b[^m]*m')
|
50 |
|
51 |
class Client(threading.Thread): |
52 |
|
53 |
"""Class to receive data from the MUD."""
|
54 |
|
55 |
def __init__(self, host, port=4000, timeout=0.1, engine=None): |
56 |
"""Connects to the MUD."""
|
57 |
threading.Thread.__init__(self)
|
58 |
self.client = None |
59 |
self.timeout = timeout
|
60 |
self.engine = engine
|
61 |
self.running = False |
62 |
self.sharp_engine = SharpScript(engine, self) |
63 |
|
64 |
# Try to connect to the specified host and port
|
65 |
self.client = Telnet(host, port)
|
66 |
self.running = True |
67 |
|
68 |
def run(self): |
69 |
"""Run the thread."""
|
70 |
while self.running: |
71 |
time.sleep(self.timeout)
|
72 |
msg = self.client.read_very_eager()
|
73 |
if msg:
|
74 |
self.handle_message(msg)
|
75 |
|
76 |
def handle_message(self, msg): |
77 |
"""When the client receives a message."""
|
78 |
pass
|
79 |
|
80 |
def write(self, text): |
81 |
"""Write text to the client."""
|
82 |
if text.startswith("#"): |
83 |
print "Executing", text |
84 |
self.sharp_engine.execute(text)
|
85 |
else:
|
86 |
self.client.write(text)
|
87 |
|
88 |
|
89 |
class GUIClient(Client): |
90 |
|
91 |
"""Client specifically linked to a GUI window.
|
92 |
|
93 |
This client proceeds to send the text it receives to the frame.
|
94 |
|
95 |
"""
|
96 |
|
97 |
def __init__(self, host, port=4000, timeout=0.1, engine=None): |
98 |
Client.__init__(self, host, port, timeout, engine)
|
99 |
self.window = None |
100 |
if self.client: |
101 |
self.client.set_option_negotiation_callback(self.handle_option) |
102 |
|
103 |
def link_window(self, window): |
104 |
"""Link to a window (a GUI object).
|
105 |
|
106 |
This objectt can be of various types. The client only interacts
|
107 |
with it in two ways: First, whenever it receives a message,
|
108 |
it sends it to the window's 'handle_message' method. It also
|
109 |
calls the window's 'handle_option' method whenever it receives
|
110 |
a Telnet option that it can recognize.
|
111 |
|
112 |
"""
|
113 |
self.window = window
|
114 |
window.client = self
|
115 |
|
116 |
def handle_message(self, msg): |
117 |
"""When the client receives a message."""
|
118 |
msg = msg.decode("utf-8", "replace") |
119 |
msg = ANSI_ESCAPE.sub('', msg)
|
120 |
if self.window: |
121 |
self.window.handle_message(msg)
|
122 |
|
123 |
# In any case, tries to find the TTS
|
124 |
if self.engine.TTS_on: |
125 |
if say and braille: |
126 |
say(msg, interrupt=False)
|
127 |
braille(msg) |
128 |
|
129 |
def handle_option(self, socket, command, option): |
130 |
"""Handle a received option."""
|
131 |
name = ""
|
132 |
if command == WILL and option == ECHO: |
133 |
name = "hide"
|
134 |
elif command == WONT and option == ECHO: |
135 |
name = "show"
|
136 |
|
137 |
if name and self.window: |
138 |
self.window.handle_option(name)
|