source: xplra/misc/client.py@ 7:bafe58db1509

Last change on this file since 7:bafe58db1509 was 7:bafe58db1509, checked in by István Váradi <ivaradi@…>, 11 years ago

Added support for setting values

  • Property exe set to *
File size: 8.2 KB
Line 
1#!/usr/bin/env python
2
3import sys
4import cmd
5import struct
6import socket
7import os
8
9#------------------------------------------------------------------------------
10
11class CLI(cmd.Cmd):
12 """Simple command-line interface for the X-Plane Remote Access plugin."""
13 _types = { "i" : 0x01,
14 "f" : 0x02,
15 "d" : 0x03,
16 "fa" : 0x11,
17 "ia" : 0x12,
18 "ba" : 0x13,
19 "s" : 0x13 }
20
21 @staticmethod
22 def _splitArgs(args):
23 """Split the given argument string into a list of words."""
24 words = []
25 word = ""
26 inQuote = False
27 for c in args:
28 if c.isspace() and not inQuote:
29 if word:
30 words.append(word)
31 word = ""
32 elif c=="\"" and (not word or inQuote):
33 inQuote = not inQuote
34 else:
35 word += c
36 if word:
37 words.append(word)
38 return words
39
40 @staticmethod
41 def _packLength(x):
42 """Pack the given integer as a variable-length value."""
43 s = ""
44 while True:
45 y = x&0x7f
46 x >>= 7
47 if x>0: y |= 0x80
48 s += struct.pack("B", y)
49 if x==0:
50 return s
51
52 @staticmethod
53 def _packString(s):
54 """Pack the given string."""
55 return CLI._packLength(len(s)) + s
56
57 def __init__(self, stream):
58 """Construct the CLI."""
59 cmd.Cmd.__init__(self)
60
61 self._stream = stream
62
63 self.use_rawinput = True
64 self.intro = "\nX-Plane Remote Access plugin command prompt\n"
65 self.prompt = "XPLRA> "
66
67 self.daemon = True
68
69 def default(self, line):
70 """Handle uhandled commands"""
71 if line=="EOF":
72 print
73 return True
74 else:
75 return super(CLI, self).default(line)
76
77 def do_get(self, args):
78 """Handle the 'get' command"""
79 words = self._splitArgs(args)
80 if len(words)<2:
81 print >> sys.stderr, "Missing parameters"
82 return False
83
84 name = words[0]
85
86 type = words[1]
87 if type not in self._types:
88 print >> sys.stderr, "Invalid type"
89 return False
90
91 length = None
92 offset = None
93 if len(words)>3:
94 length = int(words[2])
95 offset = int(words[3])
96
97 self._writeU8(0x01)
98 self._writeString(name)
99 self._writeU8(self._types[type])
100 if length is not None:
101 self._writeS32(length)
102 self._writeS32(offset)
103 self._flush()
104
105 result = self._readU8()
106 if result==0:
107 print self._readValue(type)
108 else:
109 print "Error code:", result
110
111 def do_set(self, args):
112 """Handle the 'set' command"""
113 words = self._splitArgs(args)
114 if len(words)<3:
115 print >> sys.stderr, "Missing parameters"
116 return False
117
118 name = words[0]
119
120 type = words[1]
121 if type not in self._types:
122 print >> sys.stderr, "Invalid type"
123 return False
124
125 value = words[2]
126
127 length = None
128 offset = None
129 if len(words)>4:
130 length = int(words[3])
131 offset = int(words[4])
132
133 self._writeU8(0x02)
134 self._writeString(name)
135 self._writeU8(self._types[type])
136 if length is not None:
137 self._writeS32(length)
138 self._writeS32(offset)
139 self._writeValue(type, value, length)
140
141 self._flush()
142
143 result = self._readU8()
144 if result!=0:
145 print "Error code:", result
146
147 def _writeU8(self, x):
148 """Write the given value as an unsigned, 8-bit value."""
149 self._stream.write(struct.pack("B", x))
150
151 def _writeS32(self, x):
152 """Write the given value as a signed, 32-bit value."""
153 self._stream.write(struct.pack("i", x))
154
155 def _writeFloat(self, x):
156 """Write the given value as a single-precision floating point."""
157 self._stream.write(struct.pack("f", x))
158
159 def _writeDouble(self, x):
160 """Write the given value as a double-precision floating point."""
161 self._stream.write(struct.pack("d", x))
162
163 def _writeLength(self, length):
164 """Write the given value is a variable-length value into our stream."""
165 self._stream.write(self._packLength(length))
166
167 def _writeString(self, str):
168 """Write the given string into the stream."""
169 self._stream.write(self._packString(str))
170
171 def _flush(self):
172 """Flush our stream."""
173 self._stream.flush()
174
175 def _readU8(self):
176 """Read an unsigned, 8-bit value from the stream."""
177 (value,) = struct.unpack("B", self._stream.read(1))
178 return value
179
180 def _readS32(self):
181 """Read a signed, 32-bit value from the stream."""
182 (value,) = struct.unpack("i", self._stream.read(4))
183 return value
184
185 def _readFloat(self):
186 """Read a single-precision floating point value from the stream."""
187 (value,) = struct.unpack("f", self._stream.read(4))
188 return value
189
190 def _readDouble(self):
191 """Read a double-precision floating point value from the stream."""
192 (value,) = struct.unpack("d", self._stream.read(8))
193 return value
194
195 def _readLength(self):
196 """Read a variable-length value from our stream."""
197 length = 0
198 while True:
199 (x,) = struct.unpack("B", self._stream.read(1))
200 length <<= 7
201 length |= x&0x7f
202 if x&0x80==0:
203 return length
204
205 def _readString(self):
206 """Read a string from our stream."""
207 length = self._readLength()
208 return self._stream.read(length)
209
210 def _readValue(self, type):
211 """Read the value of the given type from the stream."""
212 if type=="i":
213 return self._readS32()
214 elif type=="f":
215 return self._readFloat()
216 elif type=="d":
217 return self._readDouble()
218 elif type in ["fa", "ia", "ba", "s"]:
219 length = self._readS32()
220 if length>8192:
221 print "Very big length:", length
222 return None
223 elif length>0:
224 if type=="fa":
225 return [self._readFloat() for i in range(0, length)]
226 elif type=="ia":
227 return [self._readS32() for i in range(0, length)]
228 elif type=="ba" or type=="s":
229 bytes = [self._readU8() for i in range(0, length)]
230 if type=="ba":
231 return bytes
232 else:
233 string = ""
234 for b in bytes:
235 if b==0: break
236 string += chr(b)
237 return string
238 elif length==0:
239 return []
240 else:
241 return None
242
243 def _writeValue(self, type, value, length = None):
244 """Write the given value of the given type to the stream."""
245 if type=="i":
246 self._writeS32(int(value))
247 elif type=="f":
248 self._writeFloat(float(value))
249 elif type=="d":
250 self._writeDouble(float(value))
251 elif type in ["fa", "ia", "ba", "s"]:
252 if type=="s":
253 values = [ord(c) for c in value]
254 else:
255 words = [word.strip() for word in value.split(",")]
256 values = [float(word) if type=="fa" else int(word)
257 for word in words]
258 if len(values)<length:
259 values += [0.0 if type=="fa" else 0] * (length-len(values))
260 elif len(values)>length:
261 values = values[:length]
262 for value in values:
263 if type=="fa":
264 self._writeFloat(value)
265 elif type=="ia":
266 self._writeS32(value)
267 else:
268 self._writeU8(value)
269
270#------------------------------------------------------------------------------
271
272if __name__ == "__main__":
273 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
274 s.connect("/tmp/xplra-" + os.environ["LOGNAME"])
275 CLI(s.makefile()).cmdloop()
Note: See TracBrowser for help on using the repository browser.