Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/net/packet_encoding.py : 67%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python
2# This file is part of Xpra.
3# Copyright (C) 2011-2020 Antoine Martin <antoine@xpra.org>
4# Copyright (C) 2008, 2009, 2010 Nathaniel Smith <njs@pobox.com>
5# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
6# later version. See the file COPYING for details.
8from collections import namedtuple
10from xpra.log import Logger
11from xpra.net.header import FLAGS_RENCODE, FLAGS_YAML, FLAGS_BENCODE, FLAGS_NOHEADER
12from xpra.util import envbool
14#all the encoders we know about, in best compatibility order:
15ALL_ENCODERS = ("rencode", "bencode", "yaml", "none")
16#order for performance:
17PERFORMANCE_ORDER = ("rencode", "bencode", "yaml")
19Encoding = namedtuple("Encoding", ["name", "flag", "version", "encode", "decode"])
21ENCODERS = {}
24def init_rencode():
25 from rencode import dumps, loads, __version__
26 def do_rencode(v):
27 return dumps(v), FLAGS_RENCODE
28 return Encoding("rencode", FLAGS_RENCODE, __version__, do_rencode, loads)
30def init_bencode():
31 from xpra.net.bencode import bencode, bdecode, __version__
32 def do_bencode(v):
33 return bencode(v), FLAGS_BENCODE
34 def do_bdecode(data):
35 packet, l = bdecode(data)
36 assert len(data)==l, "expected %i bytes, but got %i" % (l, len(data))
37 return packet
38 return Encoding("bencode", FLAGS_BENCODE, __version__, do_bencode, do_bdecode)
40def init_yaml():
41 #json messes with strings and unicode (makes it unusable for us)
42 from yaml import dump, safe_load, __version__
43 def yaml_dump(v):
44 return dump(v).encode("latin1"), FLAGS_YAML
45 return Encoding("yaml", FLAGS_YAML, __version__, yaml_dump, safe_load)
47def init_none():
48 def encode(data):
49 #just send data as a string for clients that don't understand xpra packet format:
50 import codecs
51 def b(x):
52 if isinstance(x, bytes):
53 return x
54 return codecs.latin_1_encode(x)[0]
55 return b(": ".join(str(x) for x in data)+"\n"), FLAGS_NOHEADER
56 return Encoding("none", FLAGS_NOHEADER, 0, encode, None)
59def init_all():
60 for x in list(ALL_ENCODERS)+["none"]:
61 if not envbool("XPRA_%s" % (x.upper()), True):
62 continue
63 fn = globals().get("init_%s" % x)
64 try:
65 e = fn()
66 assert e
67 ENCODERS[x] = e
68 except (ImportError, AttributeError):
69 logger = Logger("network", "protocol")
70 logger.debug("no %s", x, exc_info=True)
71init_all()
74def get_packet_encoding_caps() -> dict:
75 caps = {}
76 for name in ALL_ENCODERS:
77 d = caps.setdefault(name, {})
78 e = ENCODERS.get(name)
79 d[""] = e is not None
80 if e is None:
81 continue
82 d["version"] = e.version
83 return caps
85def get_enabled_encoders(order=ALL_ENCODERS):
86 return tuple(x for x in order if x in ENCODERS)
89def get_encoder(e):
90 assert e in ALL_ENCODERS, "invalid encoder name: %s" % e
91 assert e in ENCODERS, "%s is not available" % e
92 return ENCODERS[e].encode
94def get_packet_encoding_type(protocol_flags) -> str:
95 if protocol_flags & FLAGS_RENCODE:
96 return "rencode"
97 if protocol_flags & FLAGS_YAML:
98 return "yaml"
99 return "bencode"
102def sanity_checks():
103 if "rencode" not in ENCODERS:
104 log = Logger("network", "protocol")
105 log.warn("Warning: 'rencode' packet encoder not found")
106 log.warn(" the other packet encoders are much slower")
109class InvalidPacketEncodingException(Exception):
110 pass
113def pack_one_packet(packet):
114 from xpra.net.header import pack_header
115 ee = get_enabled_encoders()
116 if ee:
117 e = get_encoder(ee[0])
118 data, flags = e(packet)
119 return pack_header(flags, 0, 0, len(data))+data
120 return str(packet)
123def decode(data, protocol_flags):
124 if isinstance(data, memoryview):
125 data = data.tobytes()
126 ptype = get_packet_encoding_type(protocol_flags)
127 e = ENCODERS.get(ptype)
128 if e:
129 return e.decode(data)
130 raise InvalidPacketEncodingException("%s decoder is not available" % ptype)
133def main(): # pragma: no cover
134 from xpra.util import print_nested_dict
135 from xpra.platform import program_context
136 with program_context("Packet Encoding", "Packet Encoding Info"):
137 print_nested_dict(get_packet_encoding_caps())
140if __name__ == "__main__": # pragma: no cover
141 main()