# megalib
[](https://crates.io/crates/megalib)
[](https://docs.rs/megalib)
[](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
<img src="https://upload.wikimedia.org/wikipedia/commons/b/bc/MEGA_logo.png" alt="MEGA Logo" width="300">
A Rust client library for the MEGA cloud storage service.
This library provides a clean, asynchronous Rust interface for interacting with MEGA, supporting authentication, filesystem access, and file management.
## Features
- **Authentication**:
- Full registration flow (account creation + email verification)
- Login (supports both v1 and v2/PBKDF2 authentication)
- Session management and caching
- Password Change (`change_password`)
- **Filesystem**:
- Fetch filesystem tree
- List files and directories
- Get node information (`stat`)
- Create directories (`mkdir`)
- Remove files/folders (`rm`)
- Rename files/folders (`rename`)
- Move files/folders (`mv`)
- Access Public Folders (`open_folder`)
- **File Transfer**:
- File upload with optional resume support
- File download with resume support
- Parallel transfer workers support
- Progress callbacks for monitoring transfers
- Text/Video/Image streaming support
- Automatic thumbnail generation on upload
- Public link generation (`export`, `export_many`)
- Proxy support (HTTP/HTTPS/SOCKS5)
- **Node Operations**:
- Get node by handle
- Check ancestor relationships
- Check write permissions
- **Sharing & Contacts**:
- Share folders with other users (`share_folder`)
- List contacts (`list_contacts`)
- Access incoming shared folders
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
megalib = "0.1.0"
tokio = { version = "1", features = ["full"] }
```
## Usage Examples
### 1. Authentication
#### Registration
```rust
use megalib::session::registration::{register, verify_registration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Step 1: Initiate registration
let state = register("newuser@example.com", "MySecretPassword", "New User").await?;
println!("Registration initiated! Check your email for the confirmation link.");
// Save state string to use after user clicks the link
let state_str = state.serialize();
// ... User clicks link ...
// Step 2: Complete registration with the link
let link = "https://mega.nz/#confirm..."; // From email
let restored_state = megalib::session::registration::RegistrationState::deserialize(&state_str)?;
verify_registration(&restored_state, link).await?;
println!("Account verified successfully!");
Ok(())
}
```
#### Login (Standard)
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let session = Session::login("user@example.com", "password").await?;
println!("Logged in as: {}", session.email);
Ok(())
}
```
#### Login (With Proxy)
The library supports HTTP, HTTPS, and SOCKS5 proxies.
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Use a SOCKS5 proxy
let session = Session::login_with_proxy(
"user@example.com",
"password",
"socks5://127.0.0.1:9050"
).await?;
println!("Logged in via proxy as: {}", session.email);
Ok(())
}
```
#### Change Password
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "old_password").await?;
session.change_password("new_secure_password").await?;
println!("Password changed successfully!");
Ok(())
}
```
### 2. Session Management
#### Session Caching
Save your session to avoid logging in every time.
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load from file if exists
let mut session = match Session::load("session.json").await? {
Some(s) => s,
None => {
// Fallback to login
let s = Session::login("user@example.com", "password").await?;
s.save("session.json")?;
s
}
};
// Validate session
session.refresh().await?;
Ok(())
}
```
#### Loading Session with Proxy
When loading a cached session, you can optionally specify a proxy to use for the restored session.
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = match Session::load_with_proxy("session.json", "http://proxy:8080").await? {
Some(s) => s,
None => {
// Login with proxy if no cache
let s = Session::login_with_proxy("user@example.com", "password", "http://proxy:8080").await?;
s.save("session.json")?;
s
}
};
session.refresh().await?;
Ok(())
}
```
### 3. Filesystem Operations
#### List Files and Get Info
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// List root directory
let nodes = session.list("/", false)?;
for node in nodes {
println!("- {} ({} bytes)", node.name, node.size);
}
// Get info for a specific file
if let Some(node) = session.stat("/Root/Documents/Report.pdf") {
println!("Found file: {}", node.name);
}
Ok(())
}
```
#### File Management (mkdir, mv, rename, rm)
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// Create directory
session.mkdir("/Root/Project").await?;
// Move a file
session.mv("/Root/draft.txt", "/Root/Project").await?;
// Rename a file
session.rename("/Root/Project/draft.txt", "final.txt").await?;
// Delete a file
session.rm("/Root/Project/old_notes.txt").await?;
Ok(())
}
```
#### Storage Quota
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
let quota = session.quota().await?;
println!("Used: {} / {} bytes ({:.1}%)",
quota.used, quota.total, quota.usage_percent());
println!("Free: {} bytes", quota.free());
Ok(())
}
```
#### Node Type Checks
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
for node in session.list("/Root", true)? {
if node.is_file() {
println!("File: {} ({} bytes)", node.name, node.size);
} else if node.is_folder() {
println!("Folder: {}/", node.name);
}
// Check if already exported
if node.is_exported() {
if let Some(url) = node.get_link(true) {
println!(" Public link: {}", url);
}
}
}
Ok(())
}
```
#### Node Operations
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// Get node by handle (useful for API integrations)
if let Some(node) = session.get_node_by_handle("ABC123xyz") {
println!("Found: {}", node.name);
}
// Check if a node is inside a folder
let file = session.stat("/Root/Documents/report.pdf").unwrap();
let folder = session.stat("/Root/Documents").unwrap();
if session.node_has_ancestor(file, folder) {
println!("File is inside Documents folder");
}
// Check if node is writable
if file.is_writable() {
println!("Can modify this file");
}
Ok(())
}
```
#### List Contacts
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// List users who have shared files with you
for contact in session.list_contacts() {
println!("Contact: {} ({})", contact.name, contact.handle);
}
Ok(())
}
```
### 4. File Transfer
#### Upload
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
let node = session.upload("local_file.txt", "/Root/Project").await?;
println!("Uploaded: {}", node.name);
Ok(())
}
```
#### Upload with Thumbnail Generation
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// Enable automatic thumbnail generation for images/videos
session.enable_previews(true);
// Upload will now generate and attach thumbnails
let node = session.upload("photo.jpg", "/Root/Photos").await?;
println!("Uploaded with thumbnail: {}", node.name);
Ok(())
}
```
#### Download
```rust
use megalib::Session;
use std::fs::File;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
if let Some(node) = session.stat("/Root/Project/final.txt").cloned() {
let mut file = File::create("downloaded_final.txt")?;
session.download(&node, &mut file).await?;
}
Ok(())
}
```
#### Download Resume Support
Enable resumption of interrupted downloads.
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// Enable resume support
session.set_resume(true);
// Speed up large downloads with parallel workers
session.set_workers(4);
// download_to_file automatically resumes partial downloads
if let Some(node) = session.stat("/Root/LargeVideo.mp4").cloned() {
session.download_to_file(&node, "video.mp4").await?;
}
Ok(())
}
```
#### Upload with Resume Support
For large uploads that may be interrupted:
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// Speed up large uploads with parallel workers
session.set_workers(4);
// upload_resumable saves state to .megalib_upload file
// If interrupted, re-running will resume from last chunk
let node = session.upload_resumable("large_file.zip", "/Root").await?;
println!("Uploaded: {}", node.name);
Ok(())
}
```
#### Progress Callbacks
Monitor transfer progress:
```rust
use megalib::{Session, progress::TransferProgress};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// Set progress callback
session.watch_status(Box::new(|progress: &TransferProgress| {
println!("{:.1}% - {}", progress.percent(), progress.filename);
true // Return false to cancel
}));
// Upload/download will now report progress
session.upload("file.txt", "/Root").await?;
Ok(())
}
```
### 5. Sharing
#### Export Public Link
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
let url = session.export("/Root/Project/final.txt").await?;
println!("Public Download Link: {}", url);
Ok(())
}
```
#### Export Multiple Files
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
// Export multiple files in one batch (more efficient)
let paths = &["/Root/doc1.pdf", "/Root/doc2.pdf", "/Root/image.png"];
let results = session.export_many(paths).await?;
for (path, url) in results {
println!("{} -> {}", path, url);
}
Ok(())
}
```
#### Get Existing Export Link
```rust
use megalib::Session;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut session = Session::login("user@example.com", "password").await?;
session.refresh().await?;
if let Some(node) = session.stat("/Root/shared_file.txt") {
// Get link if already exported
if let Some(url) = node.get_link(true) {
println!("Existing link: {}", url);
}
// Get just the key (for manual link construction)
if let Some(key) = node.get_key() {
println!("Node key: {}", key);
}
}
Ok(())
}
```
#### Share a folder
Share a folder with another MEGA user.
```rust
// Share folder with friend@example.com (Read-only)
session.share_folder("FOLDER_HANDLE", "friend@example.com", 0).await?;
```
Access levels:
- `0`: Read-only
- `1`: Read/Write
- `2`: Full Access
### 6. Public Links & Folders (No Login Required)
You can interact with public MEGA links without logging in.
#### Download a Public File
```rust
use megalib::public::download_public_file;
use std::fs::File;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut file = File::create("shared_file.zip")?;
// Download directly from a public link
download_public_file("https://mega.nz/file/ABC123#key...", &mut file).await?;
println!("Download complete!");
Ok(())
}
```
#### Browse and Download from Public Folder
```rust
use megalib::public::open_folder;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Open a public folder
let folder = open_folder("https://mega.nz/folder/XYZ789#key...").await?;
// List files
for node in folder.list("/", true) {
println!("Found: {} ({} bytes)", node.name, node.size);
// Download a specific file
if node.name == "image.jpg" {
let mut file = std::fs::File::create("image.jpg")?;
folder.download(node, &mut file).await?;
}
}
Ok(())
}
```
## Running Examples
Clone the repository and run the included examples:
```bash
# Register
cargo run --example register -- --email test@example.com --password TestPass123 --name "Test User"
# Verify Registration
cargo run --example verify -- "https://mega.nz/#confirm..."
# Change Password
cargo run --example passwd -- --email test@example.com --old OldPass --new NewPass
# Login and list files
cargo run --example ls -- --email test@example.com --password TestPass123 --path /Root/
# Session Caching
cargo run --example cached_session -- --email test@example.com --password TestPass123
# File Operations
cargo run --example mkdir -- --email test@example.com --password TestPass123 /Root/NewFolder
cargo run --example mv -- --email test@example.com --password TestPass123 /Root/file.txt /Root/NewFolder/
cargo run --example rename -- --email test@example.com --password TestPass123 /Root/file.txt "new_name.txt"
cargo run --example rm -- --email test@example.com --password TestPass123 /Root/delete_me.txt
cargo run --example stat -- --email test@example.com --password TestPass123 /Root/file.txt
# Upload (standard)
cargo run --example upload -- --email test@example.com --password TestPass123 local_file.txt /Root/
# Upload with resume support & parallel workers
cargo run --example upload_resume -- --email test@example.com --password TestPass123 large_file.zip /Root/
# Download (standard)
cargo run --example download -- --email test@example.com --password TestPass123 /Root/file.zip ./file.zip
# Download with resume support & parallel workers
cargo run --example download_resume -- --email test@example.com --password TestPass123 /Root/file.zip ./file.zip
# Export public link
cargo run --example export -- --email test@example.com --password TestPass123 /Root/file.txt
# Share a folder
cargo run --example share -- --email test@example.com --password TestPass123 --folder /Root/Documents --recipient friend@example.com --level 0
# Public File Download (no login)
cargo run --example download_public -- "https://mega.nz/file/..."
# Public Folder Browser (no login)
cargo run --example folder -- "https://mega.nz/folder/..."
```
## Acknowledgements
This project is based on the work of [megatools](https://xff.cz/megatools/) by Ondřej Jirman, which provided the foundational understanding of the MEGA API protocol and served as a reference implementation.
## License
This project is licensed under the GNU General Public License v2.0 (GPLv2) - see the [license](license) file for details.
## Disclaimer
This is an unofficial client library and is not affiliated with, associated with, authorized by, endorsed by, or in any way officially connected with Mega Limited.