Skip to content
MooncellWikiPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Janus

A stateless RESTful API gateway that posts to Bilibili dynamics, receives Aliyun OSS EventBridge webhooks, and refreshes Aliyun CDN. Built with Axum framework, with container support via Docker and CI/CD support via GitHub Actions.

Features

  • Stateless architecture - No database, pure HTTP API service
  • Bilibili integration - Post dynamics with multipart file upload
  • Aliyun OSS EventBridge - Receive and process OSS events via webhooks
  • Aliyun CDN refresh - Cache invalidation support
  • JWT authentication - ES256 (ECDSA P-256) for protected routes
  • OpenAPI documentation - Scalar UI at /api/scalar
  • mimalloc allocator - High-performance memory allocation

Tech Stack

  • Axum 0.8 + Tower middleware
  • Reqwest for external APIs
  • Utoipa for OpenAPI spec generation
  • ES256 JWT (ECDSA P-256) for authentication
  • Aliyun V3 signature for OSS EventBridge

Configuration

The configuration is divided into several main sections:

  • Logger
  • Server
  • Bilibili (API credentials)
  • Aliyun (OSS/CDN credentials)
  • JWT (ES256 keys)
  • Sentry (Optional)

Logger Configuration

Controls the application's logging behavior.

Field Description Options
enable Enable log writing to stdout true/false
level Set logging level trace, debug, info, warn, error
format Set logger format compact, pretty, json
override_filter Override default tracing filter Any valid tracing filter string

Server Configuration

Configures the web server settings.

[server]
binding = "0.0.0.0"
port = 25150
host = "http://localhost"
Field Description
binding Server binding address (defaults to "0.0.0.0")
port Port number for the server
host Web server host URL

Bilibili Configuration

Bilibili API credentials for posting dynamics.

[bilibili]
sessdata = "your_bilibili_sessdata_cookie"
bili_jct = "your_bilibili_bili_jct"
Field Description
sessdata Bilibili SESSDATA cookie value
bili_jct Bilibili bili_jct cookie value (for CSRF)

Aliyun Configuration

Aliyun OSS and CDN credentials.

[aliyun]
access_key_id = "your_aliyun_access_key_id"
access_key_secret = "your_aliyun_access_key_secret"

[aliyun.bucket_url_map]
prts-static = "https://static.prts.wiki/{object_key}"
ak-media = "https://media.prts.wiki/{object_key}"
Field Description
access_key_id Aliyun Access Key ID
access_key_secret Aliyun Access Key Secret
bucket_url_map Bucket to URL template mapping (optional)

The {object_key} placeholder in bucket_url_map will be URL-encoded and replaced with the actual object key.

JWT Configuration

ES256 (ECDSA P-256) keys for API authentication.

[jwt]
private_key = """-----BEGIN EC PRIVATE KEY-----
YOUR_PRIVATE_KEY_HERE
-----END EC PRIVATE KEY-----"""
public_key = """-----BEGIN PUBLIC KEY-----
YOUR_PUBLIC_KEY_HERE
-----END PUBLIC KEY-----"""
Field Description
private_key ES256 private key (PEM format)
public_key ES256 public key (PEM format)

Generating ES256 Key Pair

# Generate private key (prime256v1 = P-256)
openssl ecparam -genkey -name prime256v1 -noout -out private.pem

# Extract public key
openssl ec -in private.pem -pubout -out public.pem

Sentry Configuration (Optional)

Optional configuration for Sentry error tracking and monitoring.

[sentry]
dsn = "https://your-sentry-dsn@sentry.io/project-id"
traces_sample_rate = 1.0
Field Description Required
dsn Sentry DSN for error reporting No
traces_sample_rate Sampling rate for performance traces (0.0-1.0) No

API Endpoints

Public Routes

Method Path Description
GET /api/_ping Health check (ping)
GET /api/_health Health check (detailed)
POST /api/aliyun/events OSS EventBridge webhook

Protected Routes (Bearer JWT)

All protected routes require Authorization: Bearer <token> header.

Method Path Description
POST /api/bilibili/createDynamic Create Bilibili dynamic with file upload

Documentation

Path Description
/api/scalar Scalar UI (OpenAPI)
/api/openapi.json OpenAPI specification

Authentication

Bilibili Routes

Protected routes use ES256 JWT. Generate a token:

cargo run -- generate-jwt --config config.toml --subject user_id

Use the token in requests:

curl -X POST http://localhost:25150/api/bilibili/createDynamic \
  -H "Authorization: Bearer <token>" \
  -F "file=@/path/to/image.jpg" \
  -F "text=Hello Bilibili"

Aliyun Routes

EventBridge webhooks use a custom header x-eventbridge-signature-token for authentication, verified using the same JWT verification as Bilibili routes.

Commands

# Build the project
cargo build

# Run the server
cargo run -- server --config config.toml

# Generate a JWT token
cargo run -- generate-jwt --config config.toml --subject user_id

# Format code
cargo fmt

# Run linter (must pass in CI)
cargo clippy --all-features -- -D warnings

# Install development tools
just init

# Generate changelog for release
just pre-release <version>

Docker

docker build -t janus:local .
docker run --rm -p 25150:25150 \
  --mount type=bind,src="$(pwd)/config.toml",dst=/app/config.toml,readonly \
  janus:local

# Override the default server command to use other CLI commands
docker run --rm janus:local /app/janus version

Create config.toml from example.toml and fill in your credentials before starting the container. The container runs as UID/GID 10001:10001; the mounted configuration must be readable by that user. Bind the server to 0.0.0.0 in the configuration to expose it outside the container. Local configuration, keys, and build artifacts are excluded from the build context.

Dependency compilation is cached separately from application code with cargo-chef. CI and release builds share a scoped BuildKit cache, and release images include the commit SHA in /app/janus version.

Development

Code Style

  • 4-space indentation for Rust files
  • 100 character line limit
  • Run cargo fmt before committing
  • Run cargo clippy --all-features -- -D warnings (CI enforces this)

Testing

# Run tests
cargo test

CI checks formatting, runs Clippy for all targets and features, runs the tests with the lockfile enforced, and builds the Docker image. A container smoke test verifies the CLI and the /api/_ping endpoint using example.toml.

Release Process

  1. just pre-release <version> - Generate CHANGELOG.md via git-cliff
  2. cargo release <version> - Create git tag
  3. GitHub Action builds and pushes Docker image to GHCR

Example Configuration

See the example.toml file for a complete example configuration.

Architecture

Entry Points

  • main.rs (15 lines): Sets mimalloc, calls app::run()
  • lib.rs (11 lines): Public exports: aliyun, app, auth, error
  • app.rs (84 lines): CLI parser - server, generate-jwt, version

AppState (src/state.rs)

  • bilibili_config: BilibiliConfig - API credentials
  • aliyun_config: AliyunConfig - OSS/CDN credentials
  • jwt_config: JwtConfig - ES256 private/public keys
  • http_client: reqwest::Client - Shared HTTP client
  • NO database or repository

Module Organization

src/
├── main.rs           # CLI entry
├── lib.rs            # Public exports
├── app.rs            # CLI + server startup
├── config.rs         # TOML config
├── state.rs          # AppState
├── error.rs          # AppError
├── auth.rs           # JWT ES256
├── middleware.rs     # Tower layers
├── tracing.rs        # Logging setup
├── shutdown.rs       # Graceful shutdown
├── aliyun/          # OSS signature + CDN
│   ├── cdn.rs
│   └── signature.rs
└── routes/           # HTTP handlers
    ├── bilibili_handlers.rs
    ├── aliyun_handlers.rs
    └── misc_handlers.rs

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages