televault 0.1.0__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- televault/__init__.py +1 -1
- televault/chunker.py +29 -27
- televault/cli.py +237 -90
- televault/compress.py +59 -23
- televault/config.py +16 -17
- televault/core.py +140 -203
- televault/crypto.py +26 -33
- televault/models.py +29 -30
- televault/telegram.py +136 -107
- televault/tui.py +632 -0
- televault-2.0.0.dist-info/METADATA +310 -0
- televault-2.0.0.dist-info/RECORD +14 -0
- {televault-0.1.0.dist-info → televault-2.0.0.dist-info}/entry_points.txt +1 -0
- televault-0.1.0.dist-info/METADATA +0 -242
- televault-0.1.0.dist-info/RECORD +0 -13
- {televault-0.1.0.dist-info → televault-2.0.0.dist-info}/WHEEL +0 -0
televault/__init__.py
CHANGED
televault/chunker.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""File chunking utilities for TeleVault."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
from
|
|
5
|
-
from typing import Iterator, BinaryIO
|
|
4
|
+
from collections.abc import Iterator
|
|
6
5
|
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
7
|
|
|
8
8
|
import blake3
|
|
9
9
|
|
|
@@ -16,12 +16,12 @@ MAX_CHUNK_SIZE = 2000 * 1024 * 1024 # ~2GB (with margin)
|
|
|
16
16
|
@dataclass
|
|
17
17
|
class Chunk:
|
|
18
18
|
"""A chunk of file data ready for upload."""
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
index: int
|
|
21
21
|
data: bytes
|
|
22
22
|
hash: str
|
|
23
23
|
size: int
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
@property
|
|
26
26
|
def filename(self) -> str:
|
|
27
27
|
"""Generate chunk filename."""
|
|
@@ -53,20 +53,20 @@ def iter_chunks(
|
|
|
53
53
|
) -> Iterator[Chunk]:
|
|
54
54
|
"""
|
|
55
55
|
Split a file into chunks.
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
Yields Chunk objects with index, data, hash, and size.
|
|
58
58
|
Memory-efficient: only one chunk in memory at a time.
|
|
59
59
|
"""
|
|
60
60
|
if chunk_size > MAX_CHUNK_SIZE:
|
|
61
61
|
raise ValueError(f"Chunk size {chunk_size} exceeds max {MAX_CHUNK_SIZE}")
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
with open(file_path, "rb") as f:
|
|
64
64
|
index = 0
|
|
65
65
|
while True:
|
|
66
66
|
data = f.read(chunk_size)
|
|
67
67
|
if not data:
|
|
68
68
|
break
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
yield Chunk(
|
|
71
71
|
index=index,
|
|
72
72
|
data=data,
|
|
@@ -94,7 +94,7 @@ def read_chunk(
|
|
|
94
94
|
data = f.read(chunk_size)
|
|
95
95
|
if not data:
|
|
96
96
|
raise ValueError(f"Chunk {index} is empty or out of range")
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
return Chunk(
|
|
99
99
|
index=index,
|
|
100
100
|
data=data,
|
|
@@ -106,37 +106,39 @@ def read_chunk(
|
|
|
106
106
|
class ChunkWriter:
|
|
107
107
|
"""
|
|
108
108
|
Reassemble chunks into a file.
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
Handles out-of-order chunks by writing to correct positions.
|
|
111
111
|
"""
|
|
112
|
-
|
|
113
|
-
def __init__(
|
|
112
|
+
|
|
113
|
+
def __init__(
|
|
114
|
+
self, output_path: str | Path, total_size: int, chunk_size: int = DEFAULT_CHUNK_SIZE
|
|
115
|
+
):
|
|
114
116
|
self.output_path = Path(output_path)
|
|
115
117
|
self.total_size = total_size
|
|
116
118
|
self.chunk_size = chunk_size
|
|
117
119
|
self.written_chunks: set[int] = set()
|
|
118
|
-
|
|
120
|
+
|
|
119
121
|
# Pre-allocate file
|
|
120
122
|
self.output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
121
123
|
with open(self.output_path, "wb") as f:
|
|
122
124
|
f.truncate(total_size)
|
|
123
|
-
|
|
125
|
+
|
|
124
126
|
def write_chunk(self, chunk: Chunk) -> None:
|
|
125
127
|
"""Write a chunk to the correct position."""
|
|
126
128
|
if chunk.index in self.written_chunks:
|
|
127
129
|
return # Already written
|
|
128
|
-
|
|
130
|
+
|
|
129
131
|
offset = chunk.index * self.chunk_size
|
|
130
132
|
with open(self.output_path, "r+b") as f:
|
|
131
133
|
f.seek(offset)
|
|
132
134
|
f.write(chunk.data)
|
|
133
|
-
|
|
135
|
+
|
|
134
136
|
self.written_chunks.add(chunk.index)
|
|
135
|
-
|
|
137
|
+
|
|
136
138
|
def is_complete(self, expected_chunks: int) -> bool:
|
|
137
139
|
"""Check if all chunks have been written."""
|
|
138
140
|
return len(self.written_chunks) == expected_chunks
|
|
139
|
-
|
|
141
|
+
|
|
140
142
|
def missing_chunks(self, expected_chunks: int) -> list[int]:
|
|
141
143
|
"""Get list of missing chunk indices."""
|
|
142
144
|
return [i for i in range(expected_chunks) if i not in self.written_chunks]
|
|
@@ -145,26 +147,26 @@ class ChunkWriter:
|
|
|
145
147
|
class ChunkBuffer:
|
|
146
148
|
"""
|
|
147
149
|
Buffer for streaming chunk creation.
|
|
148
|
-
|
|
150
|
+
|
|
149
151
|
Useful when reading from a stream (network, compression, encryption)
|
|
150
152
|
rather than a file.
|
|
151
153
|
"""
|
|
152
|
-
|
|
154
|
+
|
|
153
155
|
def __init__(self, chunk_size: int = DEFAULT_CHUNK_SIZE):
|
|
154
156
|
self.chunk_size = chunk_size
|
|
155
157
|
self.buffer = bytearray()
|
|
156
158
|
self.index = 0
|
|
157
|
-
|
|
159
|
+
|
|
158
160
|
def write(self, data: bytes) -> Iterator[Chunk]:
|
|
159
161
|
"""
|
|
160
162
|
Write data to buffer, yielding complete chunks.
|
|
161
163
|
"""
|
|
162
164
|
self.buffer.extend(data)
|
|
163
|
-
|
|
165
|
+
|
|
164
166
|
while len(self.buffer) >= self.chunk_size:
|
|
165
|
-
chunk_data = bytes(self.buffer[:self.chunk_size])
|
|
166
|
-
self.buffer = self.buffer[self.chunk_size:]
|
|
167
|
-
|
|
167
|
+
chunk_data = bytes(self.buffer[: self.chunk_size])
|
|
168
|
+
self.buffer = self.buffer[self.chunk_size :]
|
|
169
|
+
|
|
168
170
|
yield Chunk(
|
|
169
171
|
index=self.index,
|
|
170
172
|
data=chunk_data,
|
|
@@ -172,15 +174,15 @@ class ChunkBuffer:
|
|
|
172
174
|
size=len(chunk_data),
|
|
173
175
|
)
|
|
174
176
|
self.index += 1
|
|
175
|
-
|
|
177
|
+
|
|
176
178
|
def flush(self) -> Chunk | None:
|
|
177
179
|
"""Flush remaining data as final chunk."""
|
|
178
180
|
if not self.buffer:
|
|
179
181
|
return None
|
|
180
|
-
|
|
182
|
+
|
|
181
183
|
chunk_data = bytes(self.buffer)
|
|
182
184
|
self.buffer.clear()
|
|
183
|
-
|
|
185
|
+
|
|
184
186
|
return Chunk(
|
|
185
187
|
index=self.index,
|
|
186
188
|
data=chunk_data,
|