aegis-framework 0.1.1 → 0.1.3
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.
- package/README.md +44 -0
- package/aegis/core/__pycache__/window.cpython-312.pyc +0 -0
- package/aegis/core/window.py +108 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -181,7 +181,51 @@ console.log(result.output);
|
|
|
181
181
|
// Python code
|
|
182
182
|
const py = await Aegis.run({ py: '2 + 2' });
|
|
183
183
|
console.log(py.output); // "4"
|
|
184
|
+
|
|
185
|
+
// Async command with streaming output (UI won't freeze!)
|
|
186
|
+
await Aegis.runAsync(
|
|
187
|
+
{ sh: 'apt update' },
|
|
188
|
+
(progress) => console.log(progress.line)
|
|
189
|
+
);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Downloads (with aria2c turbo mode!)
|
|
193
|
+
|
|
194
|
+
Aegis uses **aria2c** for blazing fast downloads with multiple connections:
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
// Basic download with progress
|
|
198
|
+
await Aegis.download(
|
|
199
|
+
{
|
|
200
|
+
url: 'https://example.com/large-file.zip',
|
|
201
|
+
dest: '/home/user/downloads/file.zip'
|
|
202
|
+
},
|
|
203
|
+
(progress) => {
|
|
204
|
+
console.log(`${progress.percent.toFixed(1)}%`);
|
|
205
|
+
console.log(`Speed: ${progress.speed}`); // "5.2 MiB/s"
|
|
206
|
+
console.log(`Engine: ${progress.engine}`); // "aria2c" or "urllib"
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// Turbo mode with 16 connections (for fast internet)
|
|
211
|
+
await Aegis.download(
|
|
212
|
+
{
|
|
213
|
+
url: 'https://example.com/game.iso',
|
|
214
|
+
dest: '/home/user/games/game.iso',
|
|
215
|
+
connections: 16 // Up to 16 simultaneous connections!
|
|
216
|
+
},
|
|
217
|
+
(progress) => {
|
|
218
|
+
progressBar.style.width = progress.percent + '%';
|
|
219
|
+
speedLabel.textContent = progress.speed;
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Note:** For maximum speed, install aria2c:
|
|
225
|
+
```bash
|
|
226
|
+
sudo apt install aria2
|
|
184
227
|
```
|
|
228
|
+
If aria2c is not installed, Aegis automatically falls back to standard downloads.
|
|
185
229
|
|
|
186
230
|
## 🔒 Security (preload.js)
|
|
187
231
|
|
|
Binary file
|
package/aegis/core/window.py
CHANGED
|
@@ -677,45 +677,140 @@ class AegisWindow(Gtk.Window):
|
|
|
677
677
|
GLib.idle_add(self._send_error, callback_id, str(e))
|
|
678
678
|
|
|
679
679
|
def _handle_download(self, payload, callback_id):
|
|
680
|
-
"""Download file with progress updates"""
|
|
680
|
+
"""Download file with progress updates - uses aria2c if available for faster downloads"""
|
|
681
|
+
url = payload.get('url')
|
|
682
|
+
dest = payload.get('dest')
|
|
683
|
+
connections = payload.get('connections', 8) # Max simultaneous connections
|
|
684
|
+
|
|
681
685
|
try:
|
|
682
|
-
|
|
683
|
-
dest
|
|
686
|
+
# Ensure destination directory exists
|
|
687
|
+
os.makedirs(os.path.dirname(dest) or '.', exist_ok=True)
|
|
688
|
+
|
|
689
|
+
# Check if aria2c is available for faster downloads
|
|
690
|
+
if shutil.which('aria2c'):
|
|
691
|
+
self._download_with_aria2(url, dest, connections, callback_id)
|
|
692
|
+
else:
|
|
693
|
+
self._download_with_urllib(url, dest, callback_id)
|
|
694
|
+
|
|
695
|
+
except Exception as e:
|
|
696
|
+
GLib.idle_add(self._send_error, callback_id, str(e))
|
|
697
|
+
|
|
698
|
+
def _download_with_aria2(self, url, dest, connections, callback_id):
|
|
699
|
+
"""Download using aria2c for multi-connection speed boost"""
|
|
700
|
+
import subprocess
|
|
701
|
+
import re
|
|
702
|
+
|
|
703
|
+
try:
|
|
704
|
+
dest_dir = os.path.dirname(dest) or '.'
|
|
705
|
+
dest_file = os.path.basename(dest)
|
|
706
|
+
|
|
707
|
+
cmd = [
|
|
708
|
+
'aria2c',
|
|
709
|
+
'-x', str(connections), # Max connections per server
|
|
710
|
+
'-s', str(connections), # Split file into N parts
|
|
711
|
+
'-k', '1M', # Min split size
|
|
712
|
+
'--console-log-level=warn',
|
|
713
|
+
'--summary-interval=1',
|
|
714
|
+
'--download-result=hide',
|
|
715
|
+
'-d', dest_dir,
|
|
716
|
+
'-o', dest_file,
|
|
717
|
+
'--allow-overwrite=true',
|
|
718
|
+
url
|
|
719
|
+
]
|
|
720
|
+
|
|
721
|
+
process = subprocess.Popen(
|
|
722
|
+
cmd,
|
|
723
|
+
stdout=subprocess.PIPE,
|
|
724
|
+
stderr=subprocess.STDOUT,
|
|
725
|
+
text=True,
|
|
726
|
+
bufsize=1
|
|
727
|
+
)
|
|
684
728
|
|
|
685
|
-
|
|
729
|
+
total_size = 0
|
|
730
|
+
downloaded = 0
|
|
731
|
+
|
|
732
|
+
for line in process.stdout:
|
|
733
|
+
# Parse aria2c progress: [#abc123 1.2MiB/50MiB(2%) CN:8 DL:5.2MiB]
|
|
734
|
+
progress_match = re.search(r'\[#\w+\s+([\d.]+)(\w+)/([\d.]+)(\w+)\s*\((\d+)%\).*DL:([\d.]+)(\w+)', line)
|
|
735
|
+
if progress_match:
|
|
736
|
+
dl_num, dl_unit, total_num, total_unit, percent, speed_num, speed_unit = progress_match.groups()
|
|
737
|
+
|
|
738
|
+
# Convert to bytes
|
|
739
|
+
def to_bytes(num, unit):
|
|
740
|
+
multipliers = {'B': 1, 'KiB': 1024, 'MiB': 1024**2, 'GiB': 1024**3}
|
|
741
|
+
return float(num) * multipliers.get(unit, 1)
|
|
742
|
+
|
|
743
|
+
downloaded = int(to_bytes(dl_num, dl_unit))
|
|
744
|
+
total_size = int(to_bytes(total_num, total_unit))
|
|
745
|
+
speed = f"{speed_num} {speed_unit}/s"
|
|
746
|
+
|
|
747
|
+
progress = {
|
|
748
|
+
'downloaded': downloaded,
|
|
749
|
+
'total': total_size,
|
|
750
|
+
'percent': float(percent),
|
|
751
|
+
'speed': speed,
|
|
752
|
+
'connections': connections,
|
|
753
|
+
'engine': 'aria2c'
|
|
754
|
+
}
|
|
755
|
+
GLib.idle_add(self._send_progress, callback_id, progress)
|
|
756
|
+
|
|
757
|
+
process.wait()
|
|
758
|
+
|
|
759
|
+
if process.returncode == 0:
|
|
760
|
+
# Get final file size
|
|
761
|
+
final_size = os.path.getsize(dest) if os.path.exists(dest) else downloaded
|
|
762
|
+
result = {
|
|
763
|
+
'success': True,
|
|
764
|
+
'path': dest,
|
|
765
|
+
'size': final_size,
|
|
766
|
+
'engine': 'aria2c'
|
|
767
|
+
}
|
|
768
|
+
GLib.idle_add(self._send_response, callback_id, result)
|
|
769
|
+
else:
|
|
770
|
+
# aria2c failed (e.g., snap sandbox restrictions) - fallback to urllib
|
|
771
|
+
print(f"[Aegis] aria2c failed (code {process.returncode}), falling back to urllib")
|
|
772
|
+
self._download_with_urllib(url, dest, callback_id)
|
|
773
|
+
|
|
774
|
+
except Exception as e:
|
|
775
|
+
# On any error, fallback to urllib
|
|
776
|
+
print(f"[Aegis] aria2c error: {e}, falling back to urllib")
|
|
777
|
+
self._download_with_urllib(url, dest, callback_id)
|
|
778
|
+
|
|
779
|
+
def _download_with_urllib(self, url, dest, callback_id):
|
|
780
|
+
"""Fallback download using urllib (single connection)"""
|
|
781
|
+
try:
|
|
686
782
|
req = urllib.request.Request(url, headers={
|
|
687
783
|
'User-Agent': 'Aegis/0.1.0'
|
|
688
784
|
})
|
|
689
785
|
|
|
690
|
-
response = urllib.request.urlopen(req, timeout=
|
|
786
|
+
response = urllib.request.urlopen(req, timeout=60)
|
|
691
787
|
total_size = int(response.headers.get('Content-Length', 0))
|
|
692
788
|
downloaded = 0
|
|
693
789
|
|
|
694
|
-
# Ensure destination directory exists
|
|
695
|
-
os.makedirs(os.path.dirname(dest) or '.', exist_ok=True)
|
|
696
|
-
|
|
697
790
|
with open(dest, 'wb') as f:
|
|
698
791
|
while True:
|
|
699
|
-
chunk = response.read(
|
|
792
|
+
chunk = response.read(65536) # 64KB chunks
|
|
700
793
|
if not chunk:
|
|
701
794
|
break
|
|
702
795
|
|
|
703
796
|
f.write(chunk)
|
|
704
797
|
downloaded += len(chunk)
|
|
705
798
|
|
|
706
|
-
# Send progress update
|
|
707
799
|
progress = {
|
|
708
800
|
'downloaded': downloaded,
|
|
709
801
|
'total': total_size,
|
|
710
|
-
'percent': (downloaded / total_size * 100) if total_size else 0
|
|
802
|
+
'percent': (downloaded / total_size * 100) if total_size else 0,
|
|
803
|
+
'speed': None,
|
|
804
|
+
'connections': 1,
|
|
805
|
+
'engine': 'urllib'
|
|
711
806
|
}
|
|
712
807
|
GLib.idle_add(self._send_progress, callback_id, progress)
|
|
713
808
|
|
|
714
|
-
# Send completion
|
|
715
809
|
result = {
|
|
716
810
|
'success': True,
|
|
717
811
|
'path': dest,
|
|
718
|
-
'size': downloaded
|
|
812
|
+
'size': downloaded,
|
|
813
|
+
'engine': 'urllib'
|
|
719
814
|
}
|
|
720
815
|
GLib.idle_add(self._send_response, callback_id, result)
|
|
721
816
|
|
package/package.json
CHANGED