aegis-framework 0.1.1 → 0.1.2

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 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
 
@@ -677,45 +677,136 @@ 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
- url = payload.get('url')
683
- dest = payload.get('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
- # Create request
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
+ GLib.idle_add(self._send_error, callback_id, f"aria2c exited with code {process.returncode}")
771
+
772
+ except Exception as e:
773
+ GLib.idle_add(self._send_error, callback_id, str(e))
774
+
775
+ def _download_with_urllib(self, url, dest, callback_id):
776
+ """Fallback download using urllib (single connection)"""
777
+ try:
686
778
  req = urllib.request.Request(url, headers={
687
779
  'User-Agent': 'Aegis/0.1.0'
688
780
  })
689
781
 
690
- response = urllib.request.urlopen(req, timeout=30)
782
+ response = urllib.request.urlopen(req, timeout=60)
691
783
  total_size = int(response.headers.get('Content-Length', 0))
692
784
  downloaded = 0
693
785
 
694
- # Ensure destination directory exists
695
- os.makedirs(os.path.dirname(dest) or '.', exist_ok=True)
696
-
697
786
  with open(dest, 'wb') as f:
698
787
  while True:
699
- chunk = response.read(8192)
788
+ chunk = response.read(65536) # 64KB chunks
700
789
  if not chunk:
701
790
  break
702
791
 
703
792
  f.write(chunk)
704
793
  downloaded += len(chunk)
705
794
 
706
- # Send progress update
707
795
  progress = {
708
796
  'downloaded': downloaded,
709
797
  'total': total_size,
710
- 'percent': (downloaded / total_size * 100) if total_size else 0
798
+ 'percent': (downloaded / total_size * 100) if total_size else 0,
799
+ 'speed': None,
800
+ 'connections': 1,
801
+ 'engine': 'urllib'
711
802
  }
712
803
  GLib.idle_add(self._send_progress, callback_id, progress)
713
804
 
714
- # Send completion
715
805
  result = {
716
806
  'success': True,
717
807
  'path': dest,
718
- 'size': downloaded
808
+ 'size': downloaded,
809
+ 'engine': 'urllib'
719
810
  }
720
811
  GLib.idle_add(self._send_response, callback_id, result)
721
812
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aegis-framework",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Lightweight AppImage framework using WebKit2GTK and Python - An alternative to Electron that creates ~200KB apps instead of 150MB!",
5
5
  "keywords": [
6
6
  "appimage",