File: OoliteDebugConsoleProtocol.py

package info (click to toggle)
oolite 1.77.1-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 41,264 kB
  • ctags: 5,362
  • sloc: objc: 132,090; ansic: 10,457; python: 2,225; sh: 1,325; makefile: 332; perl: 259; xml: 125; php: 5
file content (239 lines) | stat: -rw-r--r-- 7,029 bytes parent folder | download
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#
#  OoliteDebugConsoleP.py
#  ooliteConsoleServer
#
#  Created by Jens Ayton on 2007-11-29.
#  Copyright (c) 2007 Jens Ayton. All rights reserved.
#


from PropertyListPacketProtocol import PropertyListPacketProtocol
import ooliteConsoleServer._protocol as P
import sys


class OoliteDebugConsoleProtocol (PropertyListPacketProtocol):
	"""
	Class handling a debug console connection.
	Each instance has a delegate, to which high-level behaviour is dispatched.
	If the delegate is None, the connection will be cleanly rejected.
	
	Pubic methods:
		isOpen()
		sendCommand(commandString)
		closeConnection()
		configurationValue(key)
		hasConfigurationValue(key)
		setConfigurationValue(key, value)  -- the effect is not immediate, and does nothing if connection is not oepn.
	
	Public properties:
		rejectMessage  -- message used when rejecting connection because there is no delegate.
	
	
	Delegate methods:
		acceptConnection()
		connectionOpened(ooliteVersionString)
		connectionClosed(message)
		writeToConsole(message, colorKey, emphasisRanges)
		clearConsole()
		showConsole()
	
	Delegate properties:
		identityString  -- The name of the console server, sent to Oolite when accepting connection.
	"""
	
	rejectMessage = None
	
	__configuration = {}
	__open = False
	__closed = False
	
	
	def isOpen(self):
		return self.__open
	
	
	def sendCommand(self, commandString):
		if self.__open:
			packet = { P.packetTypeKey: P.performCommandPacket, P.messageKey: commandString or "" }
			self.sendPlistPacket(packet)
	
	
	def closeConnection(self, message):
		if self.__open:
			self.__open = False
			packet = { P.packetTypeKey: P.closeConnectionPacket }
			if message != None:  packet[P.messageKey] = message
			self.sendPlistPacket(packet)
			
			self.__closed = True
			self.transport.loseConnection()
			self.delegate.connectionClosed(message)
	
	
	def configurationValue(self, key):
		return self.__configuration[key]
	
	
	def hasConfigurationValue(self, key):
		return key in self.__configuration
	
	
	def setConfigurationValue(self, key, value):
		if self.__open and self.__configuration[key] != value:
			packet = { P.packetTypeKey: P.noteConfigurationPacket }
			if value != None:
				packet[P.configurationKey] = { key: value }
			else:
				packet[P.removedConfigurationKeysKey] = [key]
			self.sendPlistPacket(packet)
	
	# Internals beyod this point
	def connectionMade(self):
		self.delegate = self.factory.delegateClass(self)
	
	
	def connectionLost(self, reason):
		if self.__open:
			self.__open = False
			self.delegate.connectionClosed(None)
			return
		elif not self.__closed:
			self.__closed = True
		self.delegate.connectionClosed(reason)
	
	def plistPacketReceived(self, packet):
		# Dispatch based on packet type.
		type = packet[P.packetTypeKey]
		if type == P.requestConnectionPacket:
			self.__requestConnectionPacket(packet)
		elif type == P.closeConnectionPacket:
			self.__closeConnectionPacket(packet)
		elif type == P.consoleOutputPacket:
			self.__consoleOutputPacket(packet)
		elif type == P.clearConsolePacket:
			self.__clearConsolePacket(packet)
		elif type == P.showConsolePacket:
			self.__showConsolePacket(packet)
		elif type == P.noteConfigurationPacket:
			self.__noteConfigurationPacket(packet)
		elif type == P.noteConfigurationChangePacket:
			self.__noteConfigurationChangePacket(packet)
		elif type == P.pingPacket:
			self.__pingPacket(packet)
		elif type == P.pongPacket:
			self.__pongPacket(packet)
		else:
			self.__unknownPacket(type, packet)
	
	
	def badPacketReceived(self, data):
		print >> sys.stderr, "Received bad packet, ignoring."
	
	
	def badPListSend(self, plist):
		print >> sys.stderr, "Attempt to send bad packet: ", data
	
	
	def __requestConnectionPacket(self, packet):
		if not P.versionCompatible(P.protocolVersion_1_1_0, packet[P.protocolVersionKey]):
			# Protocol mismatch -> reject connection.
			response = { P.packetTypeKey: P.rejectConnectionPacket, P.messageKey: "This console does not support the requested protocol version." }
			self.sendPlistPacket(response)
			self.transport.loseConnection()
			try:
				self.delegate.connectionClosed("This console does not support the requested protocol version.")
			except:
				print "OoliteDebugConsoleProtocol: delegate.connectionClosed failed."
				# Ignore
		else:
			# Handle connection request
			try:
				if self.delegate.acceptConnection():
					response = { P.packetTypeKey: P.approveConnectionPacket }
					response[P.consoleIdentityKey] = self.delegate.identityString
					self.sendPlistPacket(response)
					# Pass to delegate
					self.delegate.connectionOpened(packet[P.ooliteVersionKey])
					self.__open = True
			except Exception, inst:
				print "Exception in connection set-up: ", inst
			
			if not self.__open:
				print "Failed to open connection."
				# No delegate or delegate failed -> reject connection.
				response = { P.packetTypeKey: P.rejectConnectionPacket, P.messageKey: "This console is not accepting connections." }
				if self.rejectMessage != None:
					response[P.messageKey] = self.rejectMessage
				self.sendPlistPacket(response)
				self.transport.loseConnection()
	
	
	def __closeConnectionPacket(self, packet):
		if self.__open:
			self.__open = False
			self.__closed = True
			self.transport.loseConnection()
			message = "remote closed connection"
			if P.messageKey in packet:
				message = packet[P.messageKey]
			self.delegate.connectionClosed(message)
	
	
	def __consoleOutputPacket(self, packet):
		if self.__open:
			message = None
			colorKey = None
			emphasisRanges = None
			
			if P.messageKey in packet:
				message = packet[P.messageKey]
			if P.colorKeyKey in packet:
				colorKey = packet[P.colorKeyKey]
			if P.emphasisRangesKey in packet:
				emphasisRanges = packet[P.emphasisRangesKey]
			
			self.delegate.writeToConsole(message, colorKey, emphasisRanges)
	
	
	def __clearConsolePacket(self, packet):
		if self.__open:
			self.delegate.clearConsole()
	
	
	def __showConsolePacket(self, packet):
		if self.__open:
			self.delegate.showConsole()
	
	
	def __noteConfigurationPacket(self, packet):
		if self.__open and P.configurationKey in packet:
			self.__configuration = packet[P.configurationKey]
	
	
	def __noteConfigurationChangePacket(self, packet):
		if self.__open:
			if P.configurationKey in packet:
				for k, v in packet[P.configurationKey].iteritems():
					self.__configuration[k] = v
			if P.removedConfigurationKeysKey in packet:
				for k in packet[P.removedConfigurationKeysKey]:
					del self.__configuration[k]
	
	
	def __pingPacket(self, packet):
		# Respond to ping packet by sending back pong packet with same message (if any).
		response = { P.packetTypeKey: P.pongPacket }
		if P.messageKey in packet:
			response[P.messageKey] = packet[P.messageKey]
		self.sendPlistPacket(response)
	
	
	def __pongPacket(self, packet):
		# Nothing to do, since we don't send pings.
		pass
	
	
	def __unknownPacket(self, type, packet):
		#unknown packet, complain.
		print >> sys.stderr, 'Unkown packet type "' + type + '", ignoring.'