oneshim-core
모든 크레이트의 기반이 되는 핵심 크레이트. 도메인 모델, 포트 인터페이스, 에러 정의, 설정을 담당합니다.
역할
- 도메인 모델: 모든 데이터 구조 정의
- 포트 인터페이스: 외부 시스템과의 계약 (trait)
- 에러 정의: 통합 에러 타입 (23개 변형)
- 설정: 애플리케이션 설정 구조체
Hexagonal Architecture
oneshim-core는 Hexagonal Architecture의 Core 역할을 합니다.
모든 비즈니스 로직과 인터페이스는 여기서 정의되고, 나머지 9개 크레이트가 어댑터로 구현합니다.
디렉토리 구조
oneshim-core/src/
├── lib.rs # 크레이트 루트, 모듈 재export
├── config.rs # AppConfig + 섹션별 설정 (자동화/AI 포함)
├── config_manager.rs # JSON 기반 설정 파일 관리 + 플랫폼별 경로
├── consent.rs # ConsentManager, GDPR Article 17/20 준수
├── error.rs # CoreError enum (thiserror, 23개 변형)
├── models/ # 도메인 모델
│ ├── mod.rs
│ ├── suggestion.rs # Suggestion, SuggestionType, Priority
│ ├── event.rs # ContextEvent, EventType, InputActivityEvent
│ ├── frame.rs # CapturedFrame, FrameMetadata, ProcessedFrame
│ ├── context.rs # ContextPayload, DeviceInfo
│ ├── session.rs # SessionInfo, SessionStatus
│ ├── system.rs # SystemMetrics, CpuMetrics, MemoryMetrics
│ ├── telemetry.rs # Telemetry 관련 모델
│ ├── automation.rs # AutomationAction, MouseButton
│ └── intent.rs # AutomationIntent, UiElement, WorkflowPreset
└── ports/ # 포트 인터페이스 (trait, 11개)
├── mod.rs
├── api_client.rs # ApiClient, SseClient, SseEvent
├── storage.rs # StorageService
├── monitor.rs # SystemMonitor, ProcessMonitor, ActivityMonitor
├── vision.rs # CaptureTrigger, FrameProcessor
├── notifier.rs # DesktopNotifier
├── compressor.rs # Compressor
├── element_finder.rs # ElementFinder — UI 요소 탐색
├── input_driver.rs # InputDriver — 마우스/키보드 입력
├── ocr_provider.rs # OcrProvider — OCR 텍스트 인식
├── llm_provider.rs # LlmProvider — LLM 추론
└── sandbox.rs # Sandbox — OS 네이티브 샌드박스
주요 모델
Suggestion (제안)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Suggestion {
pub suggestion_id: String,
pub suggestion_type: SuggestionType,
pub content: String,
pub priority: Priority,
pub confidence_score: f64,
pub relevance_score: f64,
pub is_actionable: bool,
pub created_at: DateTime<Utc>,
}
ContextEvent (컨텍스트 이벤트)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContextEvent {
pub event_id: String,
pub session_id: String,
pub event_type: EventType,
pub timestamp: DateTime<Utc>,
pub application: String,
pub window_title: String,
pub metadata: HashMap<String, Value>,
}
CapturedFrame (캡처 프레임)
pub struct CapturedFrame {
pub frame_id: String,
pub data: Vec<u8>,
pub width: u32,
pub height: u32,
pub captured_at: DateTime<Utc>,
pub source: FrameSource,
}
SystemMetrics (시스템 메트릭)
pub struct SystemMetrics {
pub cpu_usage: f64,
pub memory_used_mb: u64,
pub memory_total_mb: u64,
pub disk_used_gb: u64,
pub disk_total_gb: u64,
pub network_rx_bytes: u64,
pub network_tx_bytes: u64,
pub collected_at: DateTime<Utc>,
}
자동화 모델
AutomationAction — 저수준 자동화 액션
pub enum AutomationAction {
MouseMove { x: f64, y: f64 },
MouseClick { button: MouseButton, x: f64, y: f64 },
KeyType { text: String },
KeyPress { key: String },
KeyRelease { key: String },
Hotkey { keys: Vec<String> },
}
pub enum MouseButton { Left, Right, Middle }
AutomationIntent — 서버→클라이언트 고수준 의도
pub enum AutomationIntent {
ClickElement { text: String, role: Option<String>,
app_name: Option<String>, button: MouseButton },
TypeIntoElement { element_text: String, role: Option<String>, text: String },
ExecuteHotkey { keys: Vec<String> },
WaitForText { text: String, timeout_ms: u64 },
ActivateApp { app_name: String },
Raw(AutomationAction),
}
2-레이어 액션 모델
AutomationIntent (서버→클라이언트): 고수준 의도 — "파일 저장 버튼 클릭"
AutomationAction (클라이언트 내부): 저수준 액션 — "마우스 (320, 150) 클릭"
IntentResolver가 OCR/LLM을 활용하여 Intent → Action 시퀀스로 변환합니다.
UiElement — 화면에서 발견된 UI 요소
pub struct UiElement {
pub text: String,
pub bounds: ElementBounds,
pub role: Option<String>,
pub confidence: f64, // 0.0-1.0
pub source: FinderSource, // Ocr | Accessibility | TemplateMatcher
}
pub struct ElementBounds {
pub x: f64, pub y: f64,
pub width: f64, pub height: f64,
}
WorkflowPreset — 워크플로우 프리셋
pub struct WorkflowPreset {
pub id: String,
pub name: String,
pub description: String,
pub category: PresetCategory, // Productivity | AppManagement | Workflow | Custom
pub steps: Vec<WorkflowStep>,
pub builtin: bool,
pub platform: Option<String>,
}
pub struct WorkflowStep {
pub name: String,
pub intent: AutomationIntent,
pub delay_ms: u64,
pub stop_on_failure: bool,
}
pub enum PresetCategory {
Productivity, // 생산성
AppManagement, // 앱 관리
Workflow, // 워크플로우
Custom, // 사용자 정의
}
IntentResult / IntentConfig — 실행 결과 및 설정
pub struct IntentResult {
pub success: bool,
pub element: Option<UiElement>,
pub verification: Option<VerificationResult>,
pub retry_count: u32,
pub elapsed_ms: u64,
pub error: Option<String>,
}
pub struct IntentConfig {
pub min_confidence: f64, // 0.7
pub max_retries: u32, // 3
pub retry_interval_ms: u64, // 500
pub verify_after_action: bool, // true
pub verify_delay_ms: u64, // 1000
}
포트 인터페이스 (Traits) — 11개
기본 포트 (6개)
ApiClient (REST API)
#[async_trait]
pub trait ApiClient: Send + Sync {
async fn upload_context(&self, payload: &ContextPayload) -> Result<(), CoreError>;
async fn upload_frames(&self, frames: Vec<ProcessedFrame>) -> Result<(), CoreError>;
async fn send_feedback(&self, suggestion_id: &str, accepted: bool) -> Result<(), CoreError>;
}
SseClient (SSE 스트림)
#[async_trait]
pub trait SseClient: Send + Sync {
async fn connect(&self, session_id: &str, tx: mpsc::Sender<SseEvent>) -> Result<(), CoreError>;
}
StorageService (로컬 저장소)
#[async_trait]
pub trait StorageService: Send + Sync {
async fn save_event(&self, event: &ContextEvent) -> Result<(), CoreError>;
async fn get_events(&self, since: DateTime<Utc>) -> Result<Vec<ContextEvent>, CoreError>;
async fn save_frame(&self, frame: &ProcessedFrame) -> Result<(), CoreError>;
async fn get_frames(&self, since: DateTime<Utc>) -> Result<Vec<ProcessedFrame>, CoreError>;
async fn cleanup_old_data(&self, before: DateTime<Utc>) -> Result<usize, CoreError>;
}
SystemMonitor / ProcessMonitor / ActivityMonitor
#[async_trait]
pub trait SystemMonitor: Send + Sync {
async fn get_metrics(&self) -> Result<SystemMetrics, CoreError>;
}
#[async_trait]
pub trait ProcessMonitor: Send + Sync {
async fn get_active_window(&self) -> Result<ActiveWindow, CoreError>;
async fn get_running_processes(&self) -> Result<Vec<ProcessInfo>, CoreError>;
}
#[async_trait]
pub trait ActivityMonitor: Send + Sync {
async fn is_idle(&self) -> Result<bool, CoreError>;
async fn get_idle_duration(&self) -> Result<Duration, CoreError>;
}
CaptureTrigger / FrameProcessor (비전)
#[async_trait]
pub trait CaptureTrigger: Send + Sync {
async fn should_capture(&self, event: &ContextEvent) -> Result<CaptureDecision, CoreError>;
}
#[async_trait]
pub trait FrameProcessor: Send + Sync {
async fn process(&self, frame: CapturedFrame) -> Result<ProcessedFrame, CoreError>;
}
DesktopNotifier (알림)
#[async_trait]
pub trait DesktopNotifier: Send + Sync {
async fn notify(&self, suggestion: &Suggestion) -> Result<(), CoreError>;
}
자동화 포트 (5개)
Sandbox — OS 네이티브 커널 샌드박스
#[async_trait]
pub trait Sandbox: Send + Sync {
async fn execute(&self, action: &AutomationAction) -> Result<(), CoreError>;
fn capabilities(&self) -> SandboxCapabilities;
}
pub struct SandboxCapabilities {
pub filesystem_isolation: bool,
pub network_filtering: bool,
pub memory_limits: bool,
pub cpu_limits: bool,
}
ElementFinder — UI 요소 탐색
#[async_trait]
pub trait ElementFinder: Send + Sync {
async fn find_element(&self, text: &str, role: Option<&str>) -> Result<Vec<UiElement>, CoreError>;
}
InputDriver — 마우스/키보드 입력
#[async_trait]
pub trait InputDriver: Send + Sync {
async fn execute_action(&self, action: &AutomationAction) -> Result<(), CoreError>;
}
OcrProvider — OCR 텍스트 인식
#[async_trait]
pub trait OcrProvider: Send + Sync {
async fn recognize(&self, image_data: &[u8]) -> Result<Vec<UiElement>, CoreError>;
}
LlmProvider — LLM 추론
#[async_trait]
pub trait LlmProvider: Send + Sync {
async fn resolve_intent(&self, intent: &AutomationIntent) -> Result<Vec<AutomationAction>, CoreError>;
}
에러 정의 (23개 변형)
#[derive(Debug, thiserror::Error)]
pub enum CoreError {
// 기본 에러
#[error("직렬화 실패")] Serialization(#[from] serde_json::Error),
#[error("설정 에러: {0}")] Config(String),
#[error("유효성 검증 실패: {field}")] Validation { field: String, message: String },
#[error("인증 실패: {0}")] Auth(String),
#[error("{resource_type} 미발견: {id}")] NotFound { resource_type: String, id: String },
#[error("내부 오류: {0}")] Internal(String),
#[error("I/O 오류")] Io(#[from] std::io::Error),
// 네트워크 에러
#[error("네트워크 오류: {0}")] Network(String),
#[error("요청 한도 초과")] RateLimit { retry_after_secs: Option<u64> },
#[error("서비스 일시 불가: {0}")] ServiceUnavailable(String),
// 정책/자동화 에러
#[error("정책 거부: {0}")] PolicyDenied(String),
#[error("프로세스 불허: {0}")] ProcessNotAllowed(String),
#[error("잘못된 인자: {0}")] InvalidArguments(String),
#[error("바이너리 해시 불일치")] BinaryHashMismatch { expected: String, actual: String },
// 동의 에러
#[error("동의 필요: {0}")] ConsentRequired(String),
#[error("동의 만료")] ConsentExpired,
// 샌드박스 에러
#[error("샌드박스 초기화 실패: {0}")] SandboxInit(String),
#[error("샌드박스 실행 실패: {0}")] SandboxExecution(String),
#[error("샌드박스 미지원: {0}")] SandboxUnsupported(String),
// 자동화 에러
#[error("실행 타임아웃: {timeout_ms}ms")] ExecutionTimeout { timeout_ms: u64 },
#[error("UI 요소 미발견: {0}")] ElementNotFound(String),
#[error("프라이버시 거부: {0}")] PrivacyDenied(String),
#[error("OCR 처리 실패: {0}")] OcrError(String),
}
설정 (AppConfig)
pub struct AppConfig {
pub server: ServerConfig,
pub monitor: MonitorConfig,
pub storage: StorageConfig,
pub vision: VisionConfig,
pub update: UpdateConfig,
pub web: WebConfig,
pub notification: NotificationConfig,
pub telemetry: TelemetryConfig,
pub privacy: PrivacyConfig,
pub schedule: ScheduleConfig,
pub file_access: FileAccessConfig,
// 자동화 시스템
pub automation: AutomationConfig,
pub ai_provider: AiProviderConfig,
}
자동화 설정
/// 자동화 제어 설정
pub struct AutomationConfig {
pub enabled: bool,
pub sandbox: SandboxConfig,
pub custom_presets: Vec<WorkflowPreset>,
}
/// OS 네이티브 샌드박스 설정
pub struct SandboxConfig {
pub enabled: bool,
pub profile: SandboxProfile, // Permissive | Standard | Strict
pub allowed_read_paths: Vec<String>,
pub allowed_write_paths: Vec<String>,
pub allow_network: bool,
pub max_memory_bytes: u64,
pub max_cpu_time_ms: u64,
}
pub enum SandboxProfile {
Permissive, // 최소 제한
Standard, // 표준 제한 (기본)
Strict, // 엄격한 제한
}
AI 제공자 설정
/// AI OCR/LLM 제공자 설정
pub struct AiProviderConfig {
pub ocr_provider: OcrProviderType, // Local | Remote
pub llm_provider: LlmProviderType, // Local | Remote
pub ocr_api: Option<ExternalApiEndpoint>,
pub llm_api: Option<ExternalApiEndpoint>,
pub external_data_policy: ExternalDataPolicy,
pub fallback_to_local: bool,
}
/// 외부 API 엔드포인트
pub struct ExternalApiEndpoint {
pub endpoint: String,
pub api_key: String, // config.json에 직접 저장
pub model: Option<String>,
pub timeout_secs: u64, // 기본 30초
}
/// 외부 데이터 전송 정책
pub enum ExternalDataPolicy {
PiiFilterStrict, // PII 필터 Strict + 민감 앱 차단
PiiFilterStandard, // PII 필터 Standard
AllowFiltered, // 사용자 설정 그대로
}
/// AI API 제공자 타입
///
/// URL 문자열 매칭 대신 명시적 enum으로 제공자를 구분한다.
/// OSS 아키텍처에서 특정 벤더가 특권을 갖지 않도록 설정 파일 주도 방식으로 설계.
/// `ai_llm_client.rs`와 `ai_ocr_client.rs`가 이 값을 읽어 요청 형식과
/// 인증 헤더를 결정하는 벤더 중립적 분기를 수행한다.
pub enum AiProviderType {
Anthropic, // Anthropic Claude API — x-api-key 헤더 + /v1/messages 형식
OpenAi, // OpenAI 호환 API — Authorization: Bearer 헤더 + /v1/chat/completions 형식
Generic, // 기타 제공자 — 커스텀 헤더 없음, 범용 응답 파싱 사용 (기본값)
}
의존성 규칙
규칙:
- 모든 어댑터는
oneshim-core에만 의존 - 어댑터 간 직접 의존 금지 (예외:
suggestion → network,ui → suggestion) - 역방향 의존 절대 금지
관련 문서:
- 클라이언트 개요
- oneshim-network - API 클라이언트 구현
- oneshim-automation - 자동화 제어
- oneshim-storage - 저장소 구현