lantern-p2p 1.0.0__tar.gz

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.
@@ -0,0 +1,33 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Virtual environments
7
+ venv/
8
+ env/
9
+ ENV/
10
+
11
+ # IDE
12
+ .vscode/
13
+ .idea/
14
+ *.swp
15
+ *.swo
16
+
17
+ # OS
18
+ .DS_Store
19
+ Thumbs.db
20
+
21
+ # Shared files (user data)
22
+ shared_files/
23
+ !shared_files/.gitkeep
24
+
25
+ # Logs
26
+ *.log
27
+
28
+ extras/
29
+
30
+ # Build artifacts
31
+ dist/
32
+ build/
33
+ *.egg-info/
@@ -0,0 +1,173 @@
1
+ Metadata-Version: 2.4
2
+ Name: lantern-p2p
3
+ Version: 1.0.0
4
+ Summary: Lantern - A P2P file sharing system with TUI dashboard
5
+ Project-URL: Homepage, https://github.com/shx-dow/lantern
6
+ Project-URL: Documentation, https://github.com/shx-dow/lantern#readme
7
+ Project-URL: Repository, https://github.com/shx-dow/lantern
8
+ Project-URL: Issues, https://github.com/shx-dow/lantern/issues
9
+ Author-email: shx-dow <83426772+shx-dow@users.noreply.github.com>
10
+ License: MIT
11
+ Keywords: file-sharing,lan,p2p,transfer,tui
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Communications :: File Sharing
24
+ Classifier: Topic :: Internet :: File Transfer Protocol (FTP)
25
+ Classifier: Topic :: System :: Networking
26
+ Requires-Python: >=3.8
27
+ Requires-Dist: psutil>=5.9.0
28
+ Requires-Dist: textual>=0.50.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: black; extra == 'dev'
31
+ Requires-Dist: pytest>=7.0; extra == 'dev'
32
+ Requires-Dist: ruff; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # Lantern
36
+
37
+ A peer-to-peer file sharing system with a beautiful terminal UI (TUI) dashboard.
38
+
39
+ ![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)
40
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
41
+
42
+ ## Features
43
+
44
+ - **P2P File Sharing** - Share files directly between computers on the same network
45
+ - **Auto Discovery** - Automatically discovers peers on the LAN via UDP broadcast
46
+ - **Beautiful TUI** - Modern terminal interface built with Textual
47
+ - **Dual Mode** - Both CLI and TUI modes available
48
+ - **Light/Dark Themes** - Toggle between color schemes
49
+ - **Progress Bars** - Visual feedback for large file transfers
50
+ - **Notifications** - Toast notifications for operation completion
51
+ - **Path Safety** - Built-in protection against path traversal attacks
52
+
53
+ ## Installation
54
+
55
+ ### From PyPI (when published)
56
+
57
+ ```bash
58
+ pip install lantern-p2p
59
+ ```
60
+
61
+ ### From Source
62
+
63
+ ```bash
64
+ git clone https://github.com/shx-dow/lantern.git
65
+ cd lantern
66
+ pip install -e .
67
+ ```
68
+
69
+ ## Usage
70
+
71
+ ### TUI Mode (Default)
72
+
73
+ Launch the terminal dashboard (beautiful visual interface):
74
+
75
+ ```bash
76
+ lantern
77
+ ```
78
+
79
+ Or explicitly:
80
+
81
+ ```bash
82
+ lantern --tui
83
+ ```
84
+
85
+ ### CLI Mode
86
+
87
+ Use command-line interface (text-based commands):
88
+
89
+ ```bash
90
+ lantern --cli
91
+ ```
92
+
93
+ Available CLI commands:
94
+ - `peers` - Show discovered peers
95
+ - `list <host[:port]>` - List files on remote peer
96
+ - `download <host[:port]> <file>` - Download a file
97
+ - `upload <host[:port]> <path>` - Upload a file
98
+ - `delete <host[:port]> <file>` - Delete remote file
99
+ - `myfiles` - List your shared files
100
+ - `help` - Show help
101
+ - `quit` - Exit
102
+
103
+ ### Custom Port
104
+
105
+ ```bash
106
+ lantern --port 6000
107
+ ```
108
+
109
+ ## Key Bindings (TUI Mode)
110
+
111
+ | Key | Action |
112
+ |-----|--------|
113
+ | `F1` | Show help |
114
+ | `F5` | Refresh files |
115
+ | `t` | Toggle theme |
116
+ | `u` | Upload file |
117
+ | `d` | Download file |
118
+ | `x` | Delete file |
119
+ | `Tab` | Cycle focus |
120
+ | `q` | Quit |
121
+
122
+ ## Configuration
123
+
124
+ Shared files are stored in the `shared_files/` directory by default. This directory is created automatically when you first run Lantern.
125
+
126
+ ## Requirements
127
+
128
+ - Python 3.8 or higher
129
+ - textual >= 0.50.0
130
+ - psutil >= 5.9.0
131
+
132
+ ## Architecture
133
+
134
+ ```
135
+ lantern/
136
+ ├── config.py # Configuration constants
137
+ ├── protocol.py # Message framing & file transfer protocol
138
+ ├── discovery.py # UDP peer discovery
139
+ ├── server.py # TCP file server
140
+ ├── client.py # TCP client operations
141
+ ├── peer.py # CLI entry point
142
+ ├── tui.py # Textual TUI dashboard
143
+ ├── main.py # Package entry point
144
+ └── styles/ # CSS stylesheets
145
+ └── lantern.css
146
+ ```
147
+
148
+ ## Development
149
+
150
+ Install with dev dependencies:
151
+
152
+ ```bash
153
+ pip install -e ".[dev]"
154
+ ```
155
+
156
+ Run linting:
157
+
158
+ ```bash
159
+ black lantern/
160
+ ruff check lantern/
161
+ ```
162
+
163
+ ## License
164
+
165
+ MIT License - see LICENSE file for details.
166
+
167
+ ## Contributing
168
+
169
+ Contributions welcome! Please open an issue or pull request.
170
+
171
+ ## Acknowledgments
172
+
173
+ Built with [Textual](https://textual.textualize.io/) for the TUI.
@@ -0,0 +1,139 @@
1
+ # Lantern
2
+
3
+ A peer-to-peer file sharing system with a beautiful terminal UI (TUI) dashboard.
4
+
5
+ ![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)
6
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
7
+
8
+ ## Features
9
+
10
+ - **P2P File Sharing** - Share files directly between computers on the same network
11
+ - **Auto Discovery** - Automatically discovers peers on the LAN via UDP broadcast
12
+ - **Beautiful TUI** - Modern terminal interface built with Textual
13
+ - **Dual Mode** - Both CLI and TUI modes available
14
+ - **Light/Dark Themes** - Toggle between color schemes
15
+ - **Progress Bars** - Visual feedback for large file transfers
16
+ - **Notifications** - Toast notifications for operation completion
17
+ - **Path Safety** - Built-in protection against path traversal attacks
18
+
19
+ ## Installation
20
+
21
+ ### From PyPI (when published)
22
+
23
+ ```bash
24
+ pip install lantern-p2p
25
+ ```
26
+
27
+ ### From Source
28
+
29
+ ```bash
30
+ git clone https://github.com/shx-dow/lantern.git
31
+ cd lantern
32
+ pip install -e .
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### TUI Mode (Default)
38
+
39
+ Launch the terminal dashboard (beautiful visual interface):
40
+
41
+ ```bash
42
+ lantern
43
+ ```
44
+
45
+ Or explicitly:
46
+
47
+ ```bash
48
+ lantern --tui
49
+ ```
50
+
51
+ ### CLI Mode
52
+
53
+ Use command-line interface (text-based commands):
54
+
55
+ ```bash
56
+ lantern --cli
57
+ ```
58
+
59
+ Available CLI commands:
60
+ - `peers` - Show discovered peers
61
+ - `list <host[:port]>` - List files on remote peer
62
+ - `download <host[:port]> <file>` - Download a file
63
+ - `upload <host[:port]> <path>` - Upload a file
64
+ - `delete <host[:port]> <file>` - Delete remote file
65
+ - `myfiles` - List your shared files
66
+ - `help` - Show help
67
+ - `quit` - Exit
68
+
69
+ ### Custom Port
70
+
71
+ ```bash
72
+ lantern --port 6000
73
+ ```
74
+
75
+ ## Key Bindings (TUI Mode)
76
+
77
+ | Key | Action |
78
+ |-----|--------|
79
+ | `F1` | Show help |
80
+ | `F5` | Refresh files |
81
+ | `t` | Toggle theme |
82
+ | `u` | Upload file |
83
+ | `d` | Download file |
84
+ | `x` | Delete file |
85
+ | `Tab` | Cycle focus |
86
+ | `q` | Quit |
87
+
88
+ ## Configuration
89
+
90
+ Shared files are stored in the `shared_files/` directory by default. This directory is created automatically when you first run Lantern.
91
+
92
+ ## Requirements
93
+
94
+ - Python 3.8 or higher
95
+ - textual >= 0.50.0
96
+ - psutil >= 5.9.0
97
+
98
+ ## Architecture
99
+
100
+ ```
101
+ lantern/
102
+ ├── config.py # Configuration constants
103
+ ├── protocol.py # Message framing & file transfer protocol
104
+ ├── discovery.py # UDP peer discovery
105
+ ├── server.py # TCP file server
106
+ ├── client.py # TCP client operations
107
+ ├── peer.py # CLI entry point
108
+ ├── tui.py # Textual TUI dashboard
109
+ ├── main.py # Package entry point
110
+ └── styles/ # CSS stylesheets
111
+ └── lantern.css
112
+ ```
113
+
114
+ ## Development
115
+
116
+ Install with dev dependencies:
117
+
118
+ ```bash
119
+ pip install -e ".[dev]"
120
+ ```
121
+
122
+ Run linting:
123
+
124
+ ```bash
125
+ black lantern/
126
+ ruff check lantern/
127
+ ```
128
+
129
+ ## License
130
+
131
+ MIT License - see LICENSE file for details.
132
+
133
+ ## Contributing
134
+
135
+ Contributions welcome! Please open an issue or pull request.
136
+
137
+ ## Acknowledgments
138
+
139
+ Built with [Textual](https://textual.textualize.io/) for the TUI.
@@ -0,0 +1,51 @@
1
+ """
2
+ Lantern - P2P File Sharing System
3
+
4
+ A peer-to-peer file sharing application with a beautiful TUI dashboard.
5
+ """
6
+
7
+ __version__ = "1.0.0"
8
+ __author__ = "shx-dow"
9
+
10
+ from .config import (
11
+ TCP_PORT,
12
+ UDP_PORT,
13
+ BUFFER_SIZE,
14
+ BROADCAST_INTERVAL,
15
+ PEER_TIMEOUT,
16
+ SEPARATOR,
17
+ SHARED_DIR,
18
+ PEER_ID,
19
+ )
20
+ from .discovery import PeerDiscovery
21
+ from .server import FileServer
22
+ from .client import (
23
+ fetch_file_list,
24
+ do_download,
25
+ do_upload,
26
+ do_delete,
27
+ format_size,
28
+ )
29
+ from .protocol import send_msg, recv_msg, send_file, recv_file
30
+
31
+ __all__ = [
32
+ "TCP_PORT",
33
+ "UDP_PORT",
34
+ "BUFFER_SIZE",
35
+ "BROADCAST_INTERVAL",
36
+ "PEER_TIMEOUT",
37
+ "SEPARATOR",
38
+ "SHARED_DIR",
39
+ "PEER_ID",
40
+ "PeerDiscovery",
41
+ "FileServer",
42
+ "fetch_file_list",
43
+ "do_download",
44
+ "do_upload",
45
+ "do_delete",
46
+ "format_size",
47
+ "send_msg",
48
+ "recv_msg",
49
+ "send_file",
50
+ "recv_file",
51
+ ]
@@ -0,0 +1,212 @@
1
+ """
2
+ TCP client — connects to a remote peer and performs file operations.
3
+
4
+ Each operation opens a fresh TCP connection, sends a command, processes the
5
+ response, and closes the connection. This keeps the protocol stateless and
6
+ simple.
7
+
8
+ Two API layers:
9
+ - Core functions (fetch_*) return structured data for the TUI.
10
+ - CLI wrappers (list_files, download_file, …) print results for the CLI.
11
+ """
12
+
13
+ import os
14
+ import socket
15
+
16
+ from .config import SEPARATOR, BUFFER_SIZE, SHARED_DIR
17
+ from .protocol import send_msg, recv_msg, recv_file
18
+
19
+
20
+ def _connect(host: str, port: int) -> socket.socket:
21
+ """Open a TCP connection to a remote peer."""
22
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
23
+ sock.settimeout(10)
24
+ sock.connect((host, port))
25
+ return sock
26
+
27
+
28
+ def format_size(size_bytes: int | float) -> str:
29
+ """Human-readable file size."""
30
+ for unit in ("B", "KB", "MB", "GB"):
31
+ if size_bytes < 1024:
32
+ return f"{size_bytes:.1f} {unit}"
33
+ size_bytes /= 1024
34
+ return f"{size_bytes:.1f} TB"
35
+
36
+
37
+ # ======================================================================
38
+ # Core API — returns structured data (used by TUI and CLI wrappers)
39
+ # ======================================================================
40
+
41
+ def fetch_file_list(host: str, port: int) -> list[dict]:
42
+ """
43
+ Fetch the file listing from a remote peer.
44
+
45
+ Returns a list of dicts: [{"name": str, "size": int}, ...]
46
+ Raises RuntimeError on protocol errors.
47
+ """
48
+ sock = _connect(host, port)
49
+ try:
50
+ send_msg(sock, "LIST")
51
+ response = recv_msg(sock)
52
+ if response is None:
53
+ raise RuntimeError("No response from peer")
54
+
55
+ parts = response.split(SEPARATOR, 1)
56
+ if parts[0] != "OK":
57
+ raise RuntimeError(parts[1] if len(parts) > 1 else "Unknown error")
58
+
59
+ listing = parts[1] if len(parts) > 1 else ""
60
+ if not listing.strip():
61
+ return []
62
+
63
+ files = []
64
+ for line in listing.split("\n"):
65
+ if SEPARATOR in line:
66
+ name, size_str = line.split(SEPARATOR, 1)
67
+ files.append({"name": name, "size": int(size_str)})
68
+ return files
69
+ finally:
70
+ sock.close()
71
+
72
+
73
+ def do_download(host: str, port: int, filename: str) -> tuple[str, int]:
74
+ """
75
+ Download a file from a remote peer.
76
+
77
+ Returns (destination_path, bytes_received).
78
+ Raises RuntimeError on failure.
79
+ """
80
+ sock = _connect(host, port)
81
+ try:
82
+ send_msg(sock, f"DOWNLOAD{SEPARATOR}{filename}")
83
+ response = recv_msg(sock)
84
+ if response is None:
85
+ raise RuntimeError("No response from peer")
86
+
87
+ if response.startswith("ERROR"):
88
+ parts = response.split(SEPARATOR, 1)
89
+ raise RuntimeError(parts[1] if len(parts) > 1 else "Unknown error")
90
+
91
+ os.makedirs(SHARED_DIR, exist_ok=True)
92
+ dest = os.path.join(SHARED_DIR, filename)
93
+ received = recv_file(sock, dest)
94
+ return dest, received
95
+ finally:
96
+ sock.close()
97
+
98
+
99
+ def do_upload(host: str, port: int, filepath: str) -> str:
100
+ """
101
+ Upload a local file to a remote peer.
102
+
103
+ Returns a success message string.
104
+ Raises RuntimeError on failure.
105
+ """
106
+ if not os.path.isfile(filepath):
107
+ raise RuntimeError(f"Local file not found: {filepath}")
108
+
109
+ filename = os.path.basename(filepath)
110
+ filesize = os.path.getsize(filepath)
111
+
112
+ sock = _connect(host, port)
113
+ try:
114
+ send_msg(sock, f"UPLOAD{SEPARATOR}{filename}{SEPARATOR}{filesize}")
115
+
116
+ response = recv_msg(sock)
117
+ if response is None or not response.startswith("OK"):
118
+ parts = (response or "").split(SEPARATOR, 1)
119
+ raise RuntimeError(f"Peer rejected upload: {parts[1] if len(parts) > 1 else 'unknown'}")
120
+
121
+ sent = 0
122
+ with open(filepath, "rb") as f:
123
+ while sent < filesize:
124
+ chunk = f.read(BUFFER_SIZE)
125
+ if not chunk:
126
+ break
127
+ sock.sendall(chunk)
128
+ sent += len(chunk)
129
+
130
+ confirm = recv_msg(sock)
131
+ if confirm and confirm.startswith("OK"):
132
+ parts = confirm.split(SEPARATOR, 1)
133
+ return parts[1] if len(parts) > 1 else "Upload complete"
134
+ else:
135
+ parts = (confirm or "").split(SEPARATOR, 1)
136
+ raise RuntimeError(f"Upload issue: {parts[1] if len(parts) > 1 else 'unknown'}")
137
+ finally:
138
+ sock.close()
139
+
140
+
141
+ def do_delete(host: str, port: int, filename: str) -> str:
142
+ """
143
+ Request deletion of a file on a remote peer.
144
+
145
+ Returns a success message string.
146
+ Raises RuntimeError on failure.
147
+ """
148
+ sock = _connect(host, port)
149
+ try:
150
+ send_msg(sock, f"DELETE{SEPARATOR}{filename}")
151
+ response = recv_msg(sock)
152
+ if response is None:
153
+ raise RuntimeError("No response from peer")
154
+
155
+ parts = response.split(SEPARATOR, 1)
156
+ msg = parts[1] if len(parts) > 1 else ""
157
+
158
+ if parts[0] == "OK":
159
+ return msg
160
+ else:
161
+ raise RuntimeError(msg)
162
+ finally:
163
+ sock.close()
164
+
165
+
166
+ # ======================================================================
167
+ # CLI wrappers — print results (used by peer.py CLI mode)
168
+ # ======================================================================
169
+
170
+ def list_files(host: str, port: int) -> None:
171
+ """Print the file listing from a remote peer."""
172
+ try:
173
+ files = fetch_file_list(host, port)
174
+ except RuntimeError as e:
175
+ print(f" [!] {e}")
176
+ return
177
+
178
+ if not files:
179
+ print(" (no files)")
180
+ return
181
+
182
+ print(f" {'Filename':<40} {'Size':>12}")
183
+ print(f" {'-'*40} {'-'*12}")
184
+ for f in files:
185
+ print(f" {f['name']:<40} {format_size(f['size']):>12}")
186
+
187
+
188
+ def download_file(host: str, port: int, filename: str) -> None:
189
+ """Download a file and print the result."""
190
+ try:
191
+ dest, received = do_download(host, port, filename)
192
+ print(f" Downloaded {filename} ({format_size(received)}) -> {dest}")
193
+ except RuntimeError as e:
194
+ print(f" [!] {e}")
195
+
196
+
197
+ def upload_file(host: str, port: int, filepath: str) -> None:
198
+ """Upload a file and print the result."""
199
+ try:
200
+ msg = do_upload(host, port, filepath)
201
+ print(f" {msg}")
202
+ except RuntimeError as e:
203
+ print(f" [!] {e}")
204
+
205
+
206
+ def delete_file(host: str, port: int, filename: str) -> None:
207
+ """Delete a remote file and print the result."""
208
+ try:
209
+ msg = do_delete(host, port, filename)
210
+ print(f" {msg}")
211
+ except RuntimeError as e:
212
+ print(f" [!] {e}")
@@ -0,0 +1,23 @@
1
+ """
2
+ Configuration constants for the P2P file sharing system.
3
+ """
4
+
5
+ import os
6
+ import uuid
7
+
8
+ # --- Networking ---
9
+ TCP_PORT = 5000 # Default TCP port for file operations
10
+ UDP_PORT = 5001 # UDP port for peer discovery broadcasts
11
+ BUFFER_SIZE = 4096 # Chunk size (bytes) for file transfer
12
+ BROADCAST_INTERVAL = 5 # Seconds between UDP discovery beacons
13
+ PEER_TIMEOUT = 15 # Seconds before a peer is considered offline
14
+
15
+ # --- Protocol ---
16
+ SEPARATOR = "<SEP>" # Delimiter used in protocol messages
17
+
18
+ # --- File Storage ---
19
+ SHARED_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shared_files")
20
+
21
+ # --- Identity ---
22
+ # Each peer gets a unique ID at startup so it can ignore its own broadcasts
23
+ PEER_ID = str(uuid.uuid4())[:8]