summaryrefslogtreecommitdiff
path: root/src/leap/soledad/client/_pipes.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/soledad/client/_pipes.py')
-rw-r--r--src/leap/soledad/client/_pipes.py78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/leap/soledad/client/_pipes.py b/src/leap/soledad/client/_pipes.py
new file mode 100644
index 00000000..eef3f1f9
--- /dev/null
+++ b/src/leap/soledad/client/_pipes.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+# _pipes.py
+# Copyright (C) 2017 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+Components for piping data on streams.
+"""
+from io import BytesIO
+
+
+__all__ = ['TruncatedTailPipe', 'PreamblePipe']
+
+
+class TruncatedTailPipe(object):
+ """
+ Truncate the last `tail_size` bytes from the stream.
+ """
+
+ def __init__(self, output=None, tail_size=16):
+ self.tail_size = tail_size
+ self.output = output or BytesIO()
+ self.buffer = BytesIO()
+
+ def write(self, data):
+ self.buffer.write(data)
+ if self.buffer.tell() > self.tail_size:
+ self._truncate_tail()
+
+ def _truncate_tail(self):
+ overflow_size = self.buffer.tell() - self.tail_size
+ self.buffer.seek(0)
+ self.output.write(self.buffer.read(overflow_size))
+ remaining = self.buffer.read()
+ self.buffer.seek(0)
+ self.buffer.write(remaining)
+ self.buffer.truncate()
+
+ def close(self):
+ return self.output
+
+
+class PreamblePipe(object):
+ """
+ Consumes data until a space is found, then calls a callback with it and
+ starts forwarding data to consumer returned by this callback.
+ """
+
+ def __init__(self, callback):
+ self.callback = callback
+ self.preamble = BytesIO()
+ self.output = None
+
+ def write(self, data):
+ if not self.output:
+ self._write_preamble(data)
+ else:
+ self.output.write(data)
+
+ def _write_preamble(self, data):
+ if ' ' not in data:
+ self.preamble.write(data)
+ return
+ preamble_chunk, remaining = data.split(' ', 1)
+ self.preamble.write(preamble_chunk)
+ self.output = self.callback(self.preamble)
+ self.output.write(remaining)