1// Package port defines application-layer interfaces for external capabilities.
2// Ports abstract infrastructure concerns, allowing the application layer to
3// remain independent of specific implementations (WebKit, GTK, etc.).
4package port
5
6import (
7 "context"
8 "encoding/json"
9)
10
11// CookiePolicy controls cookie acceptance behavior for the engine's network session.
12type CookiePolicy string
13
14const (
15 // CookiePolicyAlways accepts all cookies.
16 CookiePolicyAlways CookiePolicy = "always"
17 // CookiePolicyNoThirdParty rejects third-party cookies.
18 CookiePolicyNoThirdParty CookiePolicy = "no_third_party"
19 // CookiePolicyNever rejects all cookies.
20 CookiePolicyNever CookiePolicy = "never"
21)
22
23// MemoryPressureConfig holds memory pressure settings for an engine process.
24// This is a value type (no infrastructure dependencies) co-located with the
25// interfaces that use it (MemoryPressureApplier, EngineOptions).
26// Zero values mean "use engine defaults".
27type MemoryPressureConfig struct {
28 // MemoryLimitMB sets the memory limit in megabytes.
29 // 0 means unset (uses engine default).
30 MemoryLimitMB int
31
32 // PollIntervalSec sets the interval for memory usage checks.
33 // 0 means unset (uses engine default: 30 seconds).
34 PollIntervalSec float64
35
36 // ConservativeThreshold sets threshold for conservative memory release.
37 // Must be in (0, 1). 0 means unset (uses engine default: 0.33).
38 ConservativeThreshold float64
39
40 // StrictThreshold sets threshold for strict memory release.
41 // Must be in (0, 1). 0 means unset (uses engine default: 0.5).
42 StrictThreshold float64
43}
44
45// IsConfigured returns true if any memory pressure setting is configured.
46func (c *MemoryPressureConfig) IsConfigured() bool {
47 if c == nil {
48 return false
49 }
50 return c.MemoryLimitMB > 0 ||
51 c.PollIntervalSec > 0 ||
52 c.ConservativeThreshold > 0 ||
53 c.StrictThreshold > 0
54}
55
56// MemoryPressureApplier applies memory pressure settings to engine processes.
57// This interface abstracts engine-specific memory pressure configuration
58// to allow testing without engine dependencies.
59type MemoryPressureApplier interface {
60 // ApplyNetworkProcessSettings applies memory pressure settings to the network process.
61 // Must be called BEFORE creating any NetworkSession.
62 ApplyNetworkProcessSettings(ctx context.Context, cfg *MemoryPressureConfig) error
63
64 // ApplyWebProcessSettings applies memory pressure settings to web processes.
65 // Returns an opaque settings object that should be passed to context creation.
66 // Returns nil if no settings are configured.
67 ApplyWebProcessSettings(ctx context.Context, cfg *MemoryPressureConfig) (any, error)
68}
69
70// EngineOptions configures engine initialization.
71type EngineOptions struct {
72 // DataDir is the directory for persistent data (cookies, storage, etc.).
73 DataDir string
74
75 // CacheDir is the directory for cache data.
76 CacheDir string
77
78 // CookiePolicy controls cookie acceptance behavior.
79 // Empty value means runtime defaults are used.
80 CookiePolicy CookiePolicy
81
82 // WebProcessMemory configures memory pressure for web processes.
83 // nil means use engine defaults.
84 WebProcessMemory *MemoryPressureConfig
85
86 // NetworkProcessMemory configures memory pressure for the network process.
87 // nil means use engine defaults.
88 NetworkProcessMemory *MemoryPressureConfig
89}
90
91// Engine is the top-level interface for a browser engine implementation.
92// It provides access to all engine subsystems and manages the lifecycle
93// of the underlying browser context.
94//
95// Engines are fully initialized by their constructor (e.g., webkit.NewEngine).
96// There is no separate Init step.
97type Engine interface {
98 // Factory returns the WebViewFactory for creating new WebView instances.
99 Factory() WebViewFactory
100
101 // Pool returns the WebViewPool for acquiring pre-warmed WebView instances.
102 Pool() WebViewPool
103
104 // ContentInjector returns the ContentInjector for injecting scripts and styles.
105 ContentInjector() ContentInjector
106
107 // SettingsApplier returns the SettingsApplier for applying browser settings.
108 SettingsApplier() SettingsApplier
109
110 // FilterApplier returns the FilterApplier for applying content filters.
111 // Returns nil if content filtering is not supported by this engine.
112 FilterApplier() FilterApplier
113
114 // FaviconDatabase returns the FaviconDatabase for async favicon lookups.
115 FaviconDatabase() FaviconDatabase
116
117 // InternalSchemePath returns the URI scheme used for internal app resources.
118 InternalSchemePath() string
119
120 // Close releases all resources held by the engine.
121 Close() error
122
123 // RegisterHandlers registers all WebUI message bridge handlers.
124 RegisterHandlers(ctx context.Context, deps HandlerDependencies) error
125
126 // RegisterAccentHandlers registers accent/dead-key input handlers.
127 RegisterAccentHandlers(ctx context.Context, handler AccentKeyHandler) error
128
129 // ConfigureDownloads sets up download handling for this engine.
130 ConfigureDownloads(ctx context.Context, downloadPath string, eventHandler DownloadEventHandler, preparer DownloadPreparer) error
131
132 // OnToolkitReady is called after the UI toolkit has initialized.
133 OnToolkitReady(ctx context.Context) error
134
135 // UpdateAppearance updates default background color for new WebViews.
136 UpdateAppearance(ctx context.Context, r, g, b, alpha float64) error
137
138 // UpdateSettings applies runtime config changes to engine internals.
139 UpdateSettings(ctx context.Context, update EngineSettingsUpdate) error
140
141 // SetHandlerContext sets the base context for message handler dispatch.
142 SetHandlerContext(ctx context.Context)
143}
144
145// EngineSettingsUpdate carries a runtime config change to the engine.
146//
147// The Raw field holds the implementation-specific config object; each engine
148// implementation type-asserts it to its concrete config type (e.g. the WebKit
149// engine asserts to *infrastructure/config.Config).
150//
151// This is the only intentional use of `any` in the Engine port. A fully typed
152// approach would require either moving the entire config schema into the domain
153// layer (a large refactor) or defining a SettingsProvider interface — which
154// would itself reduce to `any` because callers would embed engine-specific data
155// behind an empty interface. Until the config schema is promoted to domain,
156// the type assertion in the engine implementation is the least-invasive option.
157type EngineSettingsUpdate struct {
158 // Raw holds the implementation-specific config.
159 // WebKit engine expects *infrastructure/config.Config.
160 Raw any //nolint:iface // intentional: see type comment above
161}
162
163// WebUIMessageHandler handles a decoded message payload from the JS bridge.
164// Used by both WebKit and CEF message routers via the shared handlers package.
165type WebUIMessageHandler interface {
166 Handle(ctx context.Context, webviewID WebViewID, payload json.RawMessage) (any, error)
167}
168
169// WebUIMessageHandlerFunc adapts a function to the WebUIMessageHandler interface.
170type WebUIMessageHandlerFunc func(ctx context.Context, webviewID WebViewID, payload json.RawMessage) (any, error)
171
172// Handle calls f(ctx, webviewID, payload).
173func (f WebUIMessageHandlerFunc) Handle(ctx context.Context, webviewID WebViewID, payload json.RawMessage) (any, error) {
174 return f(ctx, webviewID, payload)
175}
176
177// WebUIHandlerRouter registers message handlers for the JS↔Go bridge.
178// Both WebKit's MessageRouter and CEF's MessageRouter implement this interface,
179// allowing shared handler registration code.
180type WebUIHandlerRouter interface {
181 RegisterHandler(msgType string, handler WebUIMessageHandler) error
182 RegisterHandlerWithCallbacks(msgType, callback, errorCallback, worldName string, handler WebUIMessageHandler) error
183}
184
185// WebUIMessage represents a JS -> Go message envelope.
186// Used by both WebKit (postMessage) and CEF (fetch to /api/message).
187type WebUIMessage struct {
188 Type string `json:"type"`
189 Payload json.RawMessage `json:"payload"`
190 WebViewID uint64 `json:"webview_id,omitempty"`
191 WebViewIDAlt uint64 `json:"webviewId,omitempty"`
192}
193
194// HandlerDependencies holds use cases needed by WebUI message handlers.
195type HandlerDependencies struct {
196 HistoryUC HomepageHistory
197 FavoritesUC HomepageFavorites
198 Clipboard Clipboard
199 AutoCopyConfig AutoCopyConfig
200 ClipboardTextOrchestrator ClipboardTextOrchestrator
201 OnClipboardCopied func(textLen int)
202 HandlerDeps
203}
204
205// SchemeHandler defines the port interface for registering custom URI schemes.
206// Implementations intercept navigation to registered schemes and serve content
207// from application code.
208type SchemeHandler interface {
209 // RegisterScheme registers a handler for the given URI scheme.
210 // The handler receives the full URI and returns the response body,
211 // MIME type, and any error.
212 RegisterScheme(scheme string, handler func(uri string) ([]byte, string, error))
213}
214
215// SettingsApplier defines the port interface for applying browser settings to WebViews.
216// Implementations apply engine-specific settings (security, features, etc.) uniformly
217// across a set of WebView instances.
218type SettingsApplier interface {
219 // ApplyToAll applies settings to all provided WebView instances.
220 ApplyToAll(ctx context.Context, webviews []WebView)
221}
222
223// FilterApplier defines the port interface for applying content filters to WebViews.
224// Implementations configure content blocking rules on a set of WebView instances.
225// This interface is optional; Engine.FilterApplier() returns nil if not supported.
226type FilterApplier interface {
227 // ApplyToAll applies content filters to all provided WebView instances.
228 ApplyToAll(ctx context.Context, webviews []WebView)
229}
230
231// FaviconDatabase defines the port interface for async favicon lookups.
232// Implementations retrieve favicons from an engine-managed database and
233// deliver them via callback on the main thread.
234type FaviconDatabase interface {
235 // GetFaviconAsync retrieves the favicon for the given page URL asynchronously.
236 // The callback is invoked with the favicon Texture when available.
237 GetFaviconAsync(pageURL string, callback func(Texture))
238}
239
240// ScriptRefresher defines the port interface for refreshing injected scripts
241// across multiple WebView instances (e.g., after a settings change).
242type ScriptRefresher interface {
243 // RefreshAll re-injects scripts into all provided WebView instances.
244 RefreshAll(ctx context.Context, webviews []WebView)
245}
246
247// FilterManagerProvider is an optional capability interface for engines that
248// support content filter management (e.g. ad blocking). Callers should type-assert
249// the Engine to FilterManagerProvider rather than a concrete engine type.
250type FilterManagerProvider interface {
251 InternalFilterManager() FilterManager
252}
253
254// NativeWidgetProvider is an optional capability for WebViews that can provide
255// a native widget pointer for embedding into the host toolkit's layout system.
256// For GTK-based engines this returns a *gtk.Widget pointer; other engines
257// provide their equivalent embedding handle.
258type NativeWidgetProvider interface {
259 NativeWidget() uintptr
260}