feat(app): implement basic function
General - 配置界面支持配置对象存储桶 - 快捷键进入截图 - 一键上传截图 & 复制截图链接 MacOS - 状态栏指示器和应用图标
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
// Package domain — configuration types.
|
||||
//
|
||||
// S3Config is intentionally split into its own file so that future providers
|
||||
// can introduce their own configuration types side-by-side without polluting
|
||||
// the core domain types file.
|
||||
package domain
|
||||
|
||||
// S3Config describes the connection parameters for any S3-compatible
|
||||
// endpoint (AWS S3, MinIO, Cloudflare R2, Backblaze B2, Aliyun OSS S3
|
||||
// endpoint, etc.).
|
||||
//
|
||||
// Field design notes:
|
||||
// - PathPrefix supports object name templating so users can group screenshots
|
||||
// by date.
|
||||
// - PublicURLBase is optional to support CDN-fronted buckets; otherwise the
|
||||
// adapter falls back to "{Endpoint}/{Bucket}/{Key}" (path-style).
|
||||
// - UsePathStyle defaults to true because many self-hosted MinIO / R2
|
||||
// deployments do not support virtual-hosted-style addressing.
|
||||
type S3Config struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
Region string `json:"region"`
|
||||
Bucket string `json:"bucket"`
|
||||
AccessKeyID string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
PathPrefix string `json:"pathPrefix"`
|
||||
PublicURLBase string `json:"publicUrlBase"`
|
||||
UsePathStyle bool `json:"usePathStyle"`
|
||||
}
|
||||
|
||||
// AppConfig is the top-level on-disk configuration document.
|
||||
//
|
||||
// We keep S3 nested so that adding more providers later (e.g. AliyunOSS, COS)
|
||||
// only requires a new sibling field rather than a schema rewrite.
|
||||
type AppConfig struct {
|
||||
// Hotkey describes the global shortcut that triggers a capture.
|
||||
// Stored as a human-readable string like "cmd+shift+a"; parsing happens
|
||||
// in the infrastructure hotkey adapter.
|
||||
Hotkey string `json:"hotkey"`
|
||||
|
||||
// S3 holds the active S3-compatible storage configuration.
|
||||
S3 S3Config `json:"s3"`
|
||||
}
|
||||
|
||||
// DefaultAppConfig returns sane zero-value defaults used on first launch.
|
||||
func DefaultAppConfig() AppConfig {
|
||||
return AppConfig{
|
||||
Hotkey: "cmd+shift+a",
|
||||
S3: S3Config{
|
||||
PathPrefix: "snapgo/",
|
||||
UsePathStyle: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// IsS3Configured reports whether the user has filled the mandatory S3 fields.
|
||||
func (c AppConfig) IsS3Configured() bool {
|
||||
return c.S3.Endpoint != "" &&
|
||||
c.S3.Bucket != "" &&
|
||||
c.S3.AccessKeyID != "" &&
|
||||
c.S3.SecretAccessKey != ""
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Package domain defines the core business types of SnapGo.
|
||||
//
|
||||
// Design rationale:
|
||||
// - Keep this layer free of any third-party SDK or OS API.
|
||||
// - Higher layers (application, infrastructure) depend on these types,
|
||||
// but this package depends on nothing except the Go standard library.
|
||||
// - Encapsulating data here makes the upgrade path to multiple OSS providers
|
||||
// (Aliyun OSS, Qiniu, Tencent COS, etc.) trivial — only a new infra adapter
|
||||
// is needed.
|
||||
package domain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"image"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Screenshot represents a single captured image in PNG-encoded byte form.
|
||||
//
|
||||
// We hold the encoded bytes (not image.Image) because:
|
||||
// 1. Uploaders need a byte stream;
|
||||
// 2. Local fallback writes the same bytes to disk;
|
||||
// 3. Avoids re-encoding cost.
|
||||
type Screenshot struct {
|
||||
PNG []byte // PNG-encoded payload
|
||||
Region image.Rectangle // The captured region in virtual screen coords
|
||||
Width int // Logical width of the region
|
||||
Height int // Logical height of the region
|
||||
CreatedAt time.Time // When the capture happened
|
||||
}
|
||||
|
||||
// UploadResult describes the outcome of a successful upload.
|
||||
type UploadResult struct {
|
||||
URL string // Public URL that was copied to the clipboard
|
||||
Key string // Object key on the remote storage
|
||||
Provider string // Provider name, e.g. "s3"
|
||||
Elapsed time.Duration // How long the upload took
|
||||
}
|
||||
|
||||
// OSSProvider is the abstraction every storage adapter MUST implement.
|
||||
//
|
||||
// Why an interface:
|
||||
// - Allows the application layer to remain agnostic of the concrete SDK.
|
||||
// - Future providers (Aliyun OSS / COS / Qiniu) only need a new adapter
|
||||
// without touching the service layer.
|
||||
type OSSProvider interface {
|
||||
// Upload pushes data with the given key and content-type to remote storage,
|
||||
// returning the publicly accessible URL on success.
|
||||
Upload(ctx context.Context, key string, data []byte, contentType string) (publicURL string, err error)
|
||||
|
||||
// Name returns a stable identifier of the provider implementation
|
||||
// (used in logs, telemetry, history records).
|
||||
Name() string
|
||||
}
|
||||
Reference in New Issue
Block a user