1
|
#!/usr/bin/env python
|
2
|
#
|
3
|
# Really noddy script to connect to HTSP server
|
4
|
#
|
5
|
|
6
|
#
|
7
|
# translation of htsmsg_binary.c
|
8
|
#
|
9
|
# Note: source message should be a standard python types, dict, list, string
|
10
|
# and integer
|
11
|
#
|
12
|
|
13
|
HMF_MAP = 1
|
14
|
HMF_S64 = 2
|
15
|
HMF_STR = 3
|
16
|
HMF_BIN = 4
|
17
|
HMF_LIST = 5
|
18
|
|
19
|
def hmf_type ( f ):
|
20
|
if type(f) == list:
|
21
|
return HMF_MAP
|
22
|
elif type(f) == dict:
|
23
|
return HMF_LIST
|
24
|
elif type(f) == str:
|
25
|
return HMF_STR
|
26
|
elif type(f) == int:
|
27
|
return HMF_S64
|
28
|
else:
|
29
|
raise Exception('invalid type')
|
30
|
|
31
|
def int2bin ( i ):
|
32
|
return chr(i >> 24 & 0xFF) + chr(i >> 16 & 0xFF)\
|
33
|
+ chr(i >> 16 & 0xFF) + chr(i & 0xFF)
|
34
|
|
35
|
def bin2int ( d ):
|
36
|
return (ord(d[0]) << 24) + (ord(d[1]) << 16)\
|
37
|
+ (ord(d[2]) << 8) + ord(d[3])
|
38
|
|
39
|
def _htsmsg_binary_count ( f ):
|
40
|
ret = 0
|
41
|
if type(f) == str:
|
42
|
ret = ret + len(f)
|
43
|
elif type(f) == int:
|
44
|
while (f):
|
45
|
ret = ret + 1
|
46
|
f = f >> 8
|
47
|
elif type(f) == list or type(f) == map:
|
48
|
ret = ret + htsmsg_binary_count(f)
|
49
|
else:
|
50
|
raise Exception('invalid data type')
|
51
|
return ret
|
52
|
|
53
|
def htsmsg_binary_count ( msg ):
|
54
|
ret = 0
|
55
|
lst = type(msg) == list
|
56
|
for f in msg:
|
57
|
ret = ret + 6
|
58
|
if not lst:
|
59
|
ret = ret + len(f)
|
60
|
f = msg[f]
|
61
|
ret = ret + _htsmsg_binary_count(f)
|
62
|
return ret
|
63
|
|
64
|
def htsmsg_binary_write ( msg ):
|
65
|
ret = ''
|
66
|
lst = type(msg) == list
|
67
|
for f in msg:
|
68
|
na = ''
|
69
|
if not lst:
|
70
|
na = f
|
71
|
f = msg[f]
|
72
|
ret = ret + chr(hmf_type(f))
|
73
|
ret = ret + chr(len(na) & 0xFF)
|
74
|
l = _htsmsg_binary_count(f)
|
75
|
ret = ret + int2bin(l)
|
76
|
ret = ret + na
|
77
|
|
78
|
if type(f) == list or type(f) == dict:
|
79
|
ret = ret + htsmsg_binary_write(f)
|
80
|
elif type(f) == str:
|
81
|
ret = ret + f
|
82
|
elif type(f) == int:
|
83
|
while f:
|
84
|
ret = ret + chr(f & 0xFF)
|
85
|
f = f >> 8
|
86
|
else:
|
87
|
raise Exception('invalid type')
|
88
|
return ret
|
89
|
|
90
|
def htsmsg_binary_serialize ( msg ):
|
91
|
cnt = htsmsg_binary_count(msg)
|
92
|
return int2bin(cnt) + htsmsg_binary_write(msg)
|
93
|
|
94
|
def htsmsg_binary_deserialize ( data ):
|
95
|
msg = {}
|
96
|
while len(data) > 5:
|
97
|
typ = ord(data[0])
|
98
|
nlen = ord(data[1])
|
99
|
dlen = bin2int(data[2:6])
|
100
|
data = data[6:]
|
101
|
|
102
|
if len < nlen + dlen: raise Exception('not enough data')
|
103
|
|
104
|
name = data[:nlen]
|
105
|
data = data[nlen:]
|
106
|
if typ in [ HMF_STR, HMF_BIN ]:
|
107
|
item = data[:dlen]
|
108
|
elif typ == HMF_S64:
|
109
|
item = 0
|
110
|
i = dlen - 1
|
111
|
while i:
|
112
|
item = (item << 8) | data[i]
|
113
|
elif typ in [ HMF_LIST, HMF_MAP ]:
|
114
|
item = htsmsg_binary_deserialize(data[:dlen])
|
115
|
else:
|
116
|
raise Exception('invalid data type %d' % typ)
|
117
|
msg[name] = item
|
118
|
data = data[dlen:]
|
119
|
return msg
|
120
|
|
121
|
def htsp_read ( s ):
|
122
|
data = s.recv(4)
|
123
|
if len(data) != 4: raise Exception('not enough data')
|
124
|
num = bin2int(data)
|
125
|
print 'length = %d' %num
|
126
|
data = s.recv(num)
|
127
|
if len(data) != num: raise Exception('not enough data')
|
128
|
# TODO: this should be done properly to handle partial read() calls
|
129
|
return data
|
130
|
|
131
|
def htsp_method ( func, args ):
|
132
|
args['method'] = func
|
133
|
return htsmsg_binary_serialize(args)
|
134
|
|
135
|
#
|
136
|
# Test
|
137
|
#
|
138
|
|
139
|
if __name__ == '__main__':
|
140
|
import socket, pprint
|
141
|
s = socket.create_connection(('localhost', 9982))
|
142
|
helo = {
|
143
|
'htspversion' : 5,
|
144
|
'clientname' : 'HTSP PyDemo'
|
145
|
}
|
146
|
data = htsp_method('hello', helo)
|
147
|
s.send(data)
|
148
|
data = htsp_read(s)
|
149
|
print data
|
150
|
msg = htsmsg_binary_deserialize(data)
|
151
|
pprint.pprint(msg)
|