Skip to content

zhao-leo/pic-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pic-rs

An extensible image upload tool built with Rust, powered by a WebAssembly plugin system.

pic-rs lets you upload images through a configurable pipeline of WASM extensions. Extensions can be chained together using an arrangement graph, enabling flexible workflows such as compression → watermarking → uploading to multiple image hosting services.

Features

  • WASM Extension System — Extensions are WebAssembly components built on the WIT (WebAssembly Interface Types) standard, running in a sandboxed Wasmtime runtime with WASI P2 & HTTP support.
  • Arrangement Pipeline — Chain multiple extensions into a directed graph. The output of one extension feeds into the next, with support for conditional branching.
  • Central Repository — Install extensions from the [pic-rs extension center](Not yet built), a remote URL, or a local file.
  • Per-Extension Environment Variables — Each extension has its own isolated environment configuration (API keys, tokens, etc.) managed through the CLI.
  • Extension SDK — A developer-friendly API crate (picrs_extension_api) to build your own extensions with minimal boilerplate.

Installation

Build from Source

git clone https://github.com/user/pic-rs.git
cd pic-rs
cargo build --release -p picrs-cli

The binary will be available at target/release/picrs-cli.

Quick Start

1. Add an Extension

Install an extension from the central repository, a URL, or a local path:

# From central repository (name@version)
# picrs add smms@0.1.0

# From a remote URL
picrs add https://example.com/my_extension.wasm

# From a local file
picrs add /path/to/extension.wasm

2. Configure Environment Variables

Most extensions require environment variables (e.g. API tokens). Check what's needed and set them:

# Check which variables are unset
picrs env check my_extension

# Set variables interactively
picrs env set-from-io my_extension

Or set them directly:

# Set variables via K=V pairs
picrs env set my_extension --env "API_TOKEN=abc123,BASE_URL=https://api.example.com"

3. Configure the Arrangement Pipeline

Edit ~/.picrs/picrs.toml to define extensions and their arrangement:

# "input" is the entry point; its output goes to "my_uploader"
input = { extensions = ["my_uploader"] }
# "my_uploader" sends its result to "output" (the final result)
my_uploader = { extensions = ["output"] }

4. Upload an Image

picrs upload /path/to/image.png

CLI Reference

Command Description
picrs add <source> Add an extension from name@version, URL, or local path
picrs upload <image> Upload an image through the configured arrangement pipeline
picrs env check <name> Check unset environment variables for an extension
picrs env set <name> --env K=V,... Set/override environment variables for an extension
picrs env set-from-io <name> Interactively set environment variables for an extension
picrs show List all installed extensions
picrs show <name> Show metadata and details for a specific extension
picrs sync Download missing extension files
picrs sync --force Delete all cached extensions and re-download from scratch

Project Structure

pic-rs/
├── src/
│   ├── picrs-cli/            # CLI application (clap-based)
│   ├── picrs-core/           # Core library: config, arrangements, downloader, path management
│   └── picrs_extension_rt/   # WASM runtime: loads & executes extensions via Wasmtime
├── picrs_extension_api/      # Extension SDK: WIT bindings & helpers for extension authors
├── extension-template/       # Template project for creating new extensions
├── Cargo.toml                # Workspace manifest
└── LICENSE                   # MIT License

Crate Overview

Crate Description
picrs-cli Command-line interface built with clap. Parses commands and delegates to picrs-core.
picrs-core Core logic including configuration management (~/.picrs/picrs.toml), the arrangement graph engine, extension instance management, and the extension downloader.
picrs_extension_rt WebAssembly runtime powered by Wasmtime 34.0 with WASI P2 and HTTP support. Loads .wasm components and exposes the WIT interface as Rust methods.
picrs_extension_api SDK for extension developers. Provides the Extension trait, register_extension! macro, WIT type re-exports, and HTTP utilities via waki.

Developing Extensions

Extensions are WASM components that implement the picrs:extension-api/extension WIT interface.

1. Start from the Template

Copy the extension-template/ directory and update extension.toml with your extension's metadata:

id = "my_extension"
name = "My Extension"
version = "0.1.0"
description = "A short description of what this extension does"
license = "MIT"
repo = "https://github.com/user/my-extension"
author = ["Your Name <you@example.com>"]
envs = [
  ["API_TOKEN", "Your API token for the service"],
  ["BASE_URL", "Base URL of the upload endpoint"]
]

2. Implement the Extension Trait

use picrs_extension_api::{register_extension, DataCtx, DataType, Extension as Ext, ExtensionMetadata};

struct MyExtension;

impl Ext for MyExtension {
    fn get_metadata() -> ExtensionMetadata {
        ExtensionMetadata::metadata_from_toml(include_str!("../extension.toml")).unwrap()
    }

    fn get_env_name_description() -> Result<Vec<(String, String)>, String> {
        Ok(ExtensionMetadata::get_env_name_description(include_str!("../extension.toml")).unwrap())
    }

    fn execute_image(ctx_input: DataCtx, env_vars: Vec<(String, String)>) -> Result<DataCtx, String> {
        // Your upload/processing logic here
        Ok(DataCtx {
            data_type: DataType::ImageUrl,
            content: String::from("https://example.com/uploaded.jpg"),
        })
    }

    // ... implement remaining trait methods
}

register_extension!(MyExtension);

3. Build the Extension

Extensions must be compiled as WASM components targeting wasm32-wasip2:

cargo build --target wasm32-wasip2 --release

The resulting .wasm file can be installed locally or published to the extension center.

WIT Interface

The full extension interface is defined in picrs_extension_api/wit/picrs.wit:

Function Description
get-metadata Return extension metadata (id, name, version, author, etc.)
get-env-name-description Return required environment variable names and descriptions
execute-image Process/upload an image; receives a DataCtx and returns a DataCtx
remove-image Remove a previously uploaded image by ID
image-max-size-bytes Query the maximum allowed image size
free-space-bytes Query remaining storage space in bytes
free-space-percent Query remaining storage space as a percentage

Data Types

Extensions communicate via DataCtx, which contains a DataType enum and a content string:

DataType Description
image-url A URL pointing to the image
image-path A local file path to the image
image-base64 Base64-encoded image data
arrange-choice A numeric index to select the next node in the arrangement graph (for conditional branching)

Configuration

pic-rs stores all configuration and cached data under ~/.picrs/:

~/.picrs/
├── picrs.toml          # Main configuration file
├── extensions/         # Cached .wasm extension files
│   └── my_extension.wasm
└── environments/       # Per-extension environment variable files
    └── my_extension.toml

picrs.toml Format

# Extension declarations
[extensions.my_uploader]
version = "0.1.0"                          # From central repository

[extensions.custom_processor]
remote = "https://example.com/proc.wasm"   # From URL

[extensions.local_ext]
local = "/path/to/extension.wasm"          # From local path

# Arrangement graph — defines the processing pipeline
[arrangements]
input = { extensions = ["custom_processor"] }
custom_processor = { extensions = ["my_uploader"] }
my_uploader = { extensions = ["output"] }

License

This project is licensed under the MIT License.

Author

Aprilzhao@zhaocloud.work

About

A command-line tool ,also an alternative to picGo.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages