tauri-plugin-device-info 1.0.1

A Tauri plugin to access device information.
Documentation
# 🍎 macOS Device Info - Code Documentation

## 📋 Overview

Collects device information for macOS platform using **system_profiler** command and **sysinfo** crate. Apple's native system profiler tool `system_profiler` provides access to hardware information in JSON format.

## 🔧 Code Analysis

### Dependencies
```rust
use std::process::Command;
use sysinfo::System;
use crate::models::*;
```

**Explanation:**
- **std::process::Command**: For executing system commands
- **sysinfo::System**: Cross-platform hostname retrieval
- **crate::models::***: For DeviceInfoResponse struct

### Main Function
```rust
pub fn get_device_info() -> crate::Result<DeviceInfoResponse>
```

This function collects macOS device information and returns a `DeviceInfoResponse` struct.

## 🔄 Process Steps

### 1. Running system_profiler Command
```rust
let output = Command::new("system_profiler")
    .args(["SPHardwareDataType", "-json"])
    .output()
    .ok()
    .and_then(|o| String::from_utf8(o.stdout).ok());
```

**What It Does:**
- Runs `system_profiler SPHardwareDataType -json` command
- `.output()` captures command result
- `.ok()` returns `None` on error
- `String::from_utf8()` converts bytes to string
- Chain operation ensures `output = None` if any step fails

**Command Explanation:**
- `system_profiler`: Apple's native system profile command
- `SPHardwareDataType`: Fetch only hardware information
- `-json`: Output in JSON format

### 2. Getting Hostname
```rust
let hostname = System::host_name().unwrap_or_else(|| "Unknown Device".to_string());
```

**Why Separate Retrieval:**
- `system_profiler` doesn't include hostname information
- `sysinfo::System::host_name()` works cross-platform
- Falls back to "Unknown Device" on failure

### 3. JSON Parse and Device Info Creation
```rust
if let Some(json) = output {
    let v: serde_json::Value = serde_json::from_str(&json).unwrap_or_default();
    if let Some(h) = v.get("SPHardwareDataType").and_then(|v| v.get(0)) {
        return Ok(DeviceInfoResponse {
            device_name: Some(hostname),
            manufacturer: Some("Apple Inc.".to_string()), // Fixed for Apple devices
            model: h
                .get("machine_name")
                .and_then(|v| v.as_str().map(|s| s.to_string())),
            uuid: h
                .get("platform_UUID")
                .and_then(|v| v.as_str().map(|s| s.to_string())),
            serial: h
                .get("serial_number")
                .and_then(|v| v.as_str().map(|s| s.to_string())),
            android_id: None,
        });
    }
}
```

**Step-by-Step Explanation:**

#### a) JSON Parsing
```rust
let v: serde_json::Value = serde_json::from_str(&json).unwrap_or_default();
```
- Parses JSON string into serde_json::Value
- Returns empty JSON object (`{}`) if parsing fails

#### b) Hardware Data Access
```rust
if let Some(h) = v.get("SPHardwareDataType").and_then(|v| v.get(0))
```
- Searches for "SPHardwareDataType" array in JSON
- Gets the first element of the array (usually single element)
- Each step can return `None`, safe chain

#### c) DeviceInfoResponse Creation
```rust
return Ok(DeviceInfoResponse {
    device_name: Some(hostname),
    manufacturer: Some("Apple Inc.".to_string()),
    model: h.get("machine_name").and_then(|v| v.as_str().map(|s| s.to_string())),
    uuid: h.get("platform_UUID").and_then(|v| v.as_str().map(|s| s.to_string())),
    serial: h.get("serial_number").and_then(|v| v.as_str().map(|s| s.to_string())),
    android_id: None,
});
```

### Field Mapping Description:

| DeviceInfoResponse | system_profiler JSON | Description |
|--------------------|----------------------|-------------|
| `device_name` | hostname (from sysinfo) | Computer network name |
| `manufacturer` | Fixed: "Apple Inc." | All Macs are Apple products |
| `model` | `machine_name` | "MacBook Pro", "iMac", "Mac Studio", etc. |
| `uuid` | `platform_UUID` | Hardware UUID (unique identifier) |
| `serial` | `serial_number` | Apple serial number |
| `android_id` | `None` | Not applicable for macOS |

### 4. Fallback Response
```rust
// Fallback response
Ok(DeviceInfoResponse {
    device_name: Some(hostname),
    manufacturer: Some("Apple Inc.".to_string()),
    model: None,
    uuid: None,
    serial: None,
    android_id: None,
})
```

**When It Runs:**
- If `system_profiler` command fails
- If JSON cannot be parsed
- If "SPHardwareDataType" array is not found

**Graceful Degradation:**
- At least hostname and manufacturer information is preserved
- Application doesn't crash, returns partial information
- All fields are `Option<String>` for safety

## 📊 system_profiler JSON Example

Real system_profiler output example:
```json
{
  "SPHardwareDataType" : [ {
    "machine_name" : "MacBook Pro",
    "machine_model" : "MacBookPro18,2",
    "platform_UUID" : "12345678-1234-5678-9ABC-DEF012345678",
    "serial_number" : "C02ABC123DEF",
    "cpu_type" : "Apple M1 Pro",
    "memory" : "16 GB",
    "boot_rom_version" : "8419.41.10"
  } ]
}
```

## 🛡️ Error Handling

### 1. Command Execution Error
```rust
.output()
.ok()  // Returns None on error
```
- system_profiler command not found
- Permission issue
- System resource shortage

### 2. UTF-8 Conversion Error
```rust
.and_then(|o| String::from_utf8(o.stdout).ok())
```
- Command output not in UTF-8 format
- Binary data returned

### 3. JSON Parse Error
```rust
serde_json::from_str(&json).unwrap_or_default()
```
- Corrupted JSON format
- Unexpected data structure
- Returns empty object, no crash

### 4. Missing Fields
```rust
h.get("machine_name").and_then(|v| v.as_str().map(|s| s.to_string()))
```
- Expected field missing in JSON
- Field type is not string
- Returns `None`, safe

## 🔧 Debug and Test

### Manual Terminal Test
```bash
# System profiler command
system_profiler SPHardwareDataType -json

# Format JSON nicely
system_profiler SPHardwareDataType -json | jq '.'

# Only the fields we use
system_profiler SPHardwareDataType -json | jq '.SPHardwareDataType[0] | {machine_name, platform_UUID, serial_number}'

# Hostname test
hostname
```

## 📝 Example Outputs

### MacBook Pro M1 (2021) - Success
```json
{
  "device_name": "Johns-MacBook-Pro",
  "manufacturer": "Apple Inc.",
  "model": "MacBook Pro",
  "uuid": "12345678-1234-5678-9ABC-DEF012345678",
  "serial": "C02ABC123DEF",
  "android_id": null
}
```

### iMac Intel (2019) - Success
```json
{
  "device_name": "Office-iMac",
  "manufacturer": "Apple Inc.",
  "model": "iMac",
  "uuid": "87654321-4321-8765-CBA9-FED654321098",
  "serial": "C02XYZ789GHI",
  "android_id": null
}
```

### Virtual Machine (VMware) - Partial Info
```json
{
  "device_name": "macOS-VM",
  "manufacturer": "Apple Inc.",
  "model": "VMware7,1",
  "uuid": "56789012-5678-9012-3456-789012345678",
  "serial": null,
  "android_id": null
}
```

### system_profiler Failed - Fallback
```json
{
  "device_name": "Unknown-Mac",
  "manufacturer": "Apple Inc.",
  "model": null,
  "uuid": null,
  "serial": null,
  "android_id": null
}
```

## ⚡ Performance

### Execution Time
- **system_profiler command**: ~100-300ms
- **JSON parsing**: ~1-5ms
- **Getting hostname**: ~1ms
- **Total time**: ~105-305ms

### Memory Usage
- **JSON output size**: ~2-10KB
- **Parse overhead**: Minimal
- **String allocations**: Only required fields

## ⚠️ Considerations

### Security
- system_profiler doesn't require admin privileges
- Hardware information is publicly accessible
- Serial number may be sensitive

### Compatibility
- macOS 10.10+ (for JSON support)
- Apple Silicon and Intel supported
- Partial info in virtual machines

### Maintenance
- Apple may change system_profiler format
- Field names may change
- JSON parse error handling available

---

This documentation contains a complete analysis of the actual macos.rs code. Each line's purpose and reasoning is explained.