docs: add per package README for implementation details (AI generated with human review)

This commit is contained in:
yusing
2026-01-08 23:39:19 +08:00
parent 13441286d1
commit e9d7edef12
54 changed files with 13431 additions and 1519 deletions

358
internal/homepage/README.md Normal file
View File

@@ -0,0 +1,358 @@
# Homepage
The homepage package provides the GoDoxy WebUI dashboard with support for categories, favorites, widgets, and dynamic item configuration.
## Overview
The homepage package implements the WebUI dashboard, managing homepage items, categories, sorting methods, and widget integration for monitoring container status and providing interactive features.
### Key Features
- Dynamic homepage item management
- Category-based organization (All, Favorites, Hidden, Others)
- Multiple sort methods (clicks, alphabetical, custom)
- Widget support for live data display
- Icon URL handling with favicon integration
- Item override configuration
- Click tracking and statistics
## Architecture
```mermaid
graph TD
A[HomepageMap] --> B{Category Management}
B --> C[All]
B --> D[Favorites]
B --> E[Hidden]
B --> F[Others]
G[Item] --> H[ItemConfig]
H --> I[Widget Config]
H --> J[Icon]
H --> K[Category]
L[Widgets] --> M[HTTP Widget]
N[Sorting] --> O[Clicks]
N --> P[Alphabetical]
N --> Q[Custom]
```
## Core Types
### Homepage Structure
```go
type HomepageMap struct {
ordered.Map[string, *Category]
}
type Homepage []*Category
type Category struct {
Items []*Item
Name string
}
type Item struct {
ItemConfig
SortOrder int
FavSortOrder int
AllSortOrder int
Clicks int
Widgets []Widget
Alias string
Provider string
OriginURL string
ContainerID string
}
type ItemConfig struct {
Show bool
Name string
Icon *IconURL
Category string
Description string
URL string
Favorite bool
WidgetConfig *widgets.Config
}
```
### Sort Methods
```go
const (
SortMethodClicks = "clicks"
SortMethodAlphabetical = "alphabetical"
SortMethodCustom = "custom"
)
```
### Categories
```go
const (
CategoryAll = "All"
CategoryFavorites = "Favorites"
CategoryHidden = "Hidden"
CategoryOthers = "Others"
)
```
## Public API
### Creation
```go
// NewHomepageMap creates a new homepage map with default categories.
func NewHomepageMap(total int) *HomepageMap
```
### Item Management
```go
// Add adds an item to appropriate categories.
func (c *HomepageMap) Add(item *Item)
// GetOverride returns the override configuration for an item.
func (cfg Item) GetOverride() Item
```
### Sorting
```go
// Sort sorts a category by the specified method.
func (c *Category) Sort(method SortMethod)
```
## Usage
### Creating a Homepage Map
```go
homepageMap := homepage.NewHomepageMap(100) // Reserve space for 100 items
```
### Adding Items
```go
item := &homepage.Item{
Alias: "my-app",
Provider: "docker",
OriginURL: "http://myapp.local",
ItemConfig: homepage.ItemConfig{
Name: "My Application",
Show: true,
Favorite: true,
Category: "Docker",
Description: "My Docker application",
},
}
homepageMap.Add(item)
```
### Sorting Categories
```go
allCategory := homepageMap.Get(homepage.CategoryAll)
if allCategory != nil {
allCategory.Sort(homepage.SortMethodClicks)
}
```
### Filtering by Category
```go
favorites := homepageMap.Get(homepage.CategoryFavorites)
for _, item := range favorites.Items {
fmt.Printf("Favorite: %s\n", item.Name)
}
```
## Widgets
The homepage supports widgets for each item:
```go
type Widget struct {
Label string
Value string
}
type Config struct {
// Widget configuration
}
```
### Widget Types
Widgets can display various types of information:
- **Status**: Container health status
- **Stats**: Usage statistics
- **Links**: Quick access links
- **Custom**: Provider-specific data
## Icon Handling
Icons are handled via `IconURL` type:
```go
type IconURL struct {
// Icon URL with various sources
}
// Automatic favicon fetching from item URL
```
## Categories
### Default Categories
| Category | Description |
| --------- | ------------------------ |
| All | Contains all items |
| Favorites | User-favorited items |
| Hidden | Items with `Show: false` |
| Others | Uncategorized items |
### Custom Categories
Custom categories are created dynamically:
```go
// Adding to custom category
item := &homepage.Item{
ItemConfig: homepage.ItemConfig{
Name: "App",
Category: "Development",
},
}
homepageMap.Add(item)
// "Development" category is auto-created
```
## Override Configuration
Items can have override configurations for customization:
```go
// GetOverride returns the effective configuration
func (cfg Item) GetOverride() Item {
return overrideConfigInstance.GetOverride(cfg)
}
```
## Sorting Methods
### Clicks Sort
Sorts by click count (most clicked first):
```go
func (c *Category) sortByClicks() {
slices.SortStableFunc(c.Items, func(a, b *Item) int {
if a.Clicks > b.Clicks {
return -1
}
if a.Clicks < b.Clicks {
return 1
}
return strings.Compare(title(a.Name), title(b.Name))
})
}
```
### Alphabetical Sort
Sorts alphabetically by name:
```go
func (c *Category) sortByAlphabetical() {
slices.SortStableFunc(c.Items, func(a, b *Item) int {
return strings.Compare(title(a.Name), title(b.Name))
})
}
```
### Custom Sort
Sorts by predefined sort order:
```go
func (c *Category) sortByCustom() {
// Uses SortOrder, FavSortOrder, AllSortOrder fields
}
```
## Data Flow
```mermaid
sequenceDiagram
participant RouteProvider
participant HomepageMap
participant Category
participant Widget
RouteProvider->>HomepageMap: Add(Item)
HomepageMap->>HomepageMap: Add to All
HomepageMap->>HomepageMap: Add to Category
alt Item.Favorite
HomepageMap->>CategoryFavorites: Add item
else !Item.Show
HomepageMap->>CategoryHidden: Add item
end
User->>HomepageMap: Get Category
HomepageMap-->>User: Items
User->>Category: Sort(method)
Category-->>User: Sorted Items
User->>Item: Get Widgets
Item->>Widget: Fetch Data
Widget-->>Item: Widget Data
Item-->>User: Display Widgets
```
## Integration Points
The homepage package integrates with:
- **Route Provider**: Item discovery from routes
- **Container**: Container status and metadata
- **Widgets**: Live data display
- **API**: Frontend data API
- **Configuration**: Default and override configs
## Configuration
### Active Configuration
```go
var ActiveConfig atomic.Pointer[Config]
```
### Configuration Structure
```go
type Config struct {
UseDefaultCategories bool
// ... other options
}
```
## Serialization
The package registers default value factories for serialization:
```go
func init() {
serialization.RegisterDefaultValueFactory(func() *ItemConfig {
return &ItemConfig{
Show: true,
}
})
}
```

View File

@@ -0,0 +1,227 @@
# qBittorrent Integration Package
This package provides a qBittorrent widget for the GoDoxy homepage dashboard, enabling real-time monitoring of torrent status and transfer statistics.
> [!WARNING]
>
> This package is a work in progress and is not stable.
## Overview
The `internal/homepage/integrations/qbittorrent` package implements the `widgets.Widget` interface for qBittorrent. It provides functionality to connect to a qBittorrent instance and fetch transfer information.
## Architecture
### Core Components
```
integrations/qbittorrent/
├── client.go # Client and API methods
├── transfer_info.go # Transfer info widget data
└── version.go # Version checking
└── logs.go # Log fetching
```
### Main Types
```go
type Client struct {
URL string
Username string
Password string
}
```
## API Reference
### Client Methods
#### Initialize
Connects to the qBittorrent API and verifies authentication.
```go
func (c *Client) Initialize(ctx context.Context, url string, cfg map[string]any) error
```
**Parameters:**
- `ctx` - Context for the HTTP request
- `url` - Base URL of the qBittorrent instance
- `cfg` - Configuration map containing `username` and `password`
**Returns:**
- `error` - Connection or authentication error
**Example:**
```go
client := &qbittorrent.Client{}
err := client.Initialize(ctx, "http://localhost:8080", map[string]any{
"username": "admin",
"password": "your-password",
})
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
```
#### Data
Returns current transfer statistics as name-value pairs.
```go
func (c *Client) Data(ctx context.Context) ([]widgets.NameValue, error)
```
**Returns:**
- `[]widgets.NameValue` - Transfer statistics
- `error` - API request error
**Example:**
```go
data, err := client.Data(ctx)
if err != nil {
log.Fatal(err)
}
for _, nv := range data {
fmt.Printf("%s: %s\n", nv.Name, nv.Value)
}
// Output:
// Status: connected
// Download: 1.5 GB
// Upload: 256 MB
// Download Speed: 5.2 MB/s
// Upload Speed: 1.1 MB/s
```
### Internal Methods
#### doRequest
Performs an HTTP request to the qBittorrent API.
```go
func (c *Client) doRequest(ctx context.Context, method, endpoint string, query url.Values, body io.Reader) (*http.Response, error)
```
#### jsonRequest
Performs a JSON API request and unmarshals the response.
```go
func jsonRequest[T any](ctx context.Context, client *Client, endpoint string, query url.Values) (result T, err error)
```
## Data Types
### TransferInfo
Represents transfer statistics from qBittorrent.
```go
type TransferInfo struct {
ConnectionStatus string `json:"connection_status"`
SessionDownloads uint64 `json:"dl_info_data"`
SessionUploads uint64 `json:"up_info_data"`
DownloadSpeed uint64 `json:"dl_info_speed"`
UploadSpeed uint64 `json:"up_info_speed"`
}
```
## API Endpoints
| Endpoint | Method | Description |
| ----------------------- | ------ | ----------------------- |
| `/api/v2/transfer/info` | GET | Get transfer statistics |
| `/api/v2/app/version` | GET | Get qBittorrent version |
## Usage Example
### Complete Widget Usage
```go
package main
import (
"context"
"fmt"
"github.com/yusing/godoxy/internal/homepage/integrations/qbittorrent"
"github.com/yusing/godoxy/internal/homepage/widgets"
)
func main() {
ctx := context.Background()
// Create and initialize client
client := &qbittorrent.Client{}
err := client.Initialize(ctx, "http://localhost:8080", map[string]any{
"username": "admin",
"password": "password123",
})
if err != nil {
fmt.Printf("Connection failed: %v\n", err)
return
}
// Get transfer data
data, err := client.Data(ctx)
if err != nil {
fmt.Printf("Failed to get data: %v\n", err)
return
}
// Display in dashboard format
fmt.Println("qBittorrent Status:")
fmt.Println(strings.Repeat("-", 30))
for _, nv := range data {
fmt.Printf(" %-15s %s\n", nv.Name+":", nv.Value)
}
}
```
## Integration with Homepage Widgets
```mermaid
graph TD
A[Homepage Dashboard] --> B[Widget Config]
B --> C{qBittorrent Provider}
C --> D[Create Client]
D --> E[Initialize with credentials]
E --> F[Fetch Transfer Info]
F --> G[Format as NameValue pairs]
G --> H[Render in UI]
```
### Widget Configuration
```yaml
widgets:
- provider: qbittorrent
config:
url: http://localhost:8080
username: admin
password: password123
```
## Error Handling
```go
// Handle HTTP errors
resp, err := client.doRequest(ctx, http.MethodGet, endpoint, query, body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, widgets.ErrHTTPStatus.Subject(resp.Status)
}
```
## Related Packages
- `internal/homepage/widgets` - Widget framework and interface
- `github.com/bytedance/sonic` - JSON serialization
- `github.com/yusing/goutils/strings` - String utilities for formatting

View File

@@ -0,0 +1,188 @@
# Homepage Widgets Package
> [!WARNING]
>
> This package is a work in progress and is not stable.
This package provides a widget framework for the GoDoxy homepage dashboard, enabling integration with various service providers to display real-time data.
## Overview
The `internal/homepage/widgets` package defines the widget interface and common utilities for building homepage widgets. It provides a standardized way to integrate external services into the homepage dashboard.
## Architecture
### Core Components
```
widgets/
├── widgets.go # Widget interface and config
└── http.go # HTTP client and error definitions
```
### Data Types
```go
type Config struct {
Provider string `json:"provider"`
Config Widget `json:"config"`
}
type Widget interface {
Initialize(ctx context.Context, url string, cfg map[string]any) error
Data(ctx context.Context) ([]NameValue, error)
}
type NameValue struct {
Name string `json:"name"`
Value string `json:"value"`
}
```
### Constants
```go
const (
WidgetProviderQbittorrent = "qbittorrent"
)
```
### Errors
```go
var ErrInvalidProvider = gperr.New("invalid provider")
var ErrHTTPStatus = gperr.New("http status")
```
## API Reference
### Widget Interface
```go
type Widget interface {
// Initialize sets up the widget with connection configuration
Initialize(ctx context.Context, url string, cfg map[string]any) error
// Data returns current widget data as name-value pairs
Data(ctx context.Context) ([]NameValue, error)
}
```
### Configuration
#### Config.UnmarshalMap
Parses widget configuration from a map.
```go
func (cfg *Config) UnmarshalMap(m map[string]any) error
```
**Parameters:**
- `m` - Map containing `provider` and `config` keys
**Returns:**
- `error` - Parsing or validation error
**Example:**
```go
widgetCfg := widgets.Config{}
err := widgetCfg.UnmarshalMap(map[string]any{
"provider": "qbittorrent",
"config": map[string]any{
"username": "admin",
"password": "password123",
},
})
```
### HTTP Client
```go
var HTTPClient = &http.Client{
Timeout: 10 * time.Second,
}
```
### Available Providers
- **qbittorrent** - qBittorrent torrent client integration (WIP)
## Usage Example
### Creating a Custom Widget
```go
package mywidget
import (
"context"
"github.com/yusing/godoxy/internal/homepage/widgets"
)
type MyWidget struct {
URL string
APIKey string
}
func (m *MyWidget) Initialize(ctx context.Context, url string, cfg map[string]any) error {
m.URL = url
m.APIKey = cfg["api_key"].(string)
return nil
}
func (m *MyWidget) Data(ctx context.Context) ([]widgets.NameValue, error) {
// Fetch data and return as name-value pairs
return []widgets.NameValue{
{Name: "Status", Value: "Online"},
{Name: "Uptime", Value: "24h"},
}, nil
}
```
### Registering the Widget
```go
// In widgets initialization
widgetProviders["mywidget"] = struct{}{}
```
### Using the Widget in Homepage
```go
// Fetch widget data
widget := getWidget("qbittorrent")
data, err := widget.Data(ctx)
if err != nil {
log.Fatal(err)
}
// Display data
for _, nv := range data {
fmt.Printf("%s: %s\n", nv.Name, nv.Value)
}
```
## Integration with Homepage
```mermaid
graph TD
A[Homepage Dashboard] --> B[Widget Config]
B --> C[Widget Factory]
C --> D{Provider Type}
D -->|qbittorrent| E[qBittorrent Widget]
D -->|custom| F[Custom Widget]
E --> G[Initialize]
F --> G
G --> H[Data Fetch]
H --> I[Render UI]
```
## Related Packages
- `internal/homepage/integrations/qbittorrent` - qBittorrent widget implementation
- `internal/serialization` - Configuration unmarshaling utilities
- `github.com/yusing/goutils/errs` - Error handling