1package bootstrap
2
3import (
4 "github.com/bnema/dumber/internal/application/port"
5 "github.com/bnema/dumber/internal/domain/entity"
6 "github.com/bnema/dumber/internal/infrastructure/config"
7)
8
9type configChangeManager interface {
10 Get() *config.Config
11 Watch() error
12 OnConfigChange(func(*config.Config))
13}
14
15type runtimeConfigProvider struct {
16 fallback entity.RuntimeConfigSnapshot
17 manager configChangeManager
18}
19
20func NewRuntimeConfigProvider(cfg *config.Config, manager configChangeManager) port.RuntimeConfigProvider {
21 return &runtimeConfigProvider{
22 fallback: RuntimeConfigSnapshotFromConfig(cfg),
23 manager: manager,
24 }
25}
26
27func (p *runtimeConfigProvider) Current() entity.RuntimeConfigSnapshot {
28 if p == nil {
29 return entity.RuntimeConfigSnapshot{}
30 }
31 if p.manager == nil {
32 return cloneRuntimeConfigSnapshot(p.fallback)
33 }
34 cfg := p.manager.Get()
35 if cfg == nil {
36 return cloneRuntimeConfigSnapshot(p.fallback)
37 }
38 return RuntimeConfigSnapshotFromConfig(cfg)
39}
40
41func (p *runtimeConfigProvider) Watch() error {
42 if p == nil || p.manager == nil {
43 return nil
44 }
45 return p.manager.Watch()
46}
47
48func (p *runtimeConfigProvider) OnChange(callback func(entity.RuntimeConfigSnapshot)) {
49 if p == nil || p.manager == nil || callback == nil {
50 return
51 }
52 p.manager.OnConfigChange(func(cfg *config.Config) {
53 if cfg == nil {
54 callback(cloneRuntimeConfigSnapshot(p.fallback))
55 return
56 }
57 callback(RuntimeConfigSnapshotFromConfig(cfg))
58 })
59}
60
61func EngineSettingsPayloadFromConfig(cfg *config.Config) entity.EngineSettingsPayload {
62 if cfg == nil {
63 return entity.EngineSettingsPayload{}
64 }
65 return entity.EngineSettingsPayload{
66 DefaultUIScale: cfg.DefaultUIScale,
67 WebContent: entity.EngineWebContentSettingsPayload{
68 SansFont: cfg.Appearance.SansFont,
69 SerifFont: cfg.Appearance.SerifFont,
70 MonospaceFont: cfg.Appearance.MonospaceFont,
71 DefaultFontSize: cfg.Appearance.DefaultFontSize,
72 EnableDevTools: cfg.Debug.EnableDevTools,
73 CaptureConsole: cfg.Logging.CaptureConsole,
74 DrawCompositingIndicators: cfg.Engine.WebKit.DrawCompositingIndicators,
75 HardwareDecoding: engineHardwareDecodingModeFromConfig(cfg.Media.HardwareDecodingMode),
76 AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection,
77 },
78 }
79}
80
81func RuntimeConfigSnapshotFromConfig(cfg *config.Config) entity.RuntimeConfigSnapshot {
82 if cfg == nil {
83 return entity.RuntimeConfigSnapshot{}
84 }
85 return entity.RuntimeConfigSnapshot{
86 EngineSettings: EngineSettingsPayloadFromConfig(cfg),
87 UI: entity.RuntimeUIConfig{
88 DefaultUIScale: cfg.DefaultUIScale,
89 SidebarWidth: cfg.SidebarWidth,
90 Appearance: cfg.Appearance,
91 Workspace: cloneWorkspaceConfig(cfg.Workspace),
92 Session: cloneSessionConfig(cfg.Session),
93 Clipboard: entity.RuntimeClipboardConfig{AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection},
94 SearchShortcuts: runtimeSearchShortcutsFromConfig(cfg.SearchShortcuts),
95 DefaultSearchEngine: cfg.DefaultSearchEngine,
96 Omnibox: entity.RuntimeOmniboxConfig{
97 InitialBehavior: cfg.Omnibox.InitialBehavior,
98 MostVisitedDays: cfg.Omnibox.MostVisitedDays,
99 AutoOpenOnNewPane: cfg.Omnibox.AutoOpenOnNewPane,
100 },
101 Update: entity.RuntimeUpdateConfig{
102 EnableOnStartup: cfg.Update.EnableOnStartup,
103 AutoDownload: cfg.Update.AutoDownload,
104 NotifyOnNewSettings: cfg.Update.NotifyOnNewSettings,
105 },
106 Downloads: entity.RuntimeDownloadsConfig{Path: cfg.Downloads.Path},
107 },
108 }
109}
110
111func runtimeSearchShortcutsFromConfig(in map[string]config.SearchShortcut) map[string]entity.RuntimeSearchShortcut {
112 out := make(map[string]entity.RuntimeSearchShortcut, len(in))
113 for key, shortcut := range in {
114 out[key] = entity.RuntimeSearchShortcut{
115 URL: shortcut.URL,
116 Description: shortcut.Description,
117 }
118 }
119 return out
120}
121
122func cloneRuntimeConfigSnapshot(snapshot entity.RuntimeConfigSnapshot) entity.RuntimeConfigSnapshot {
123 snapshot.UI.SearchShortcuts = cloneRuntimeSearchShortcuts(snapshot.UI.SearchShortcuts)
124 snapshot.UI.Workspace = cloneWorkspaceConfig(snapshot.UI.Workspace)
125 snapshot.UI.Session = cloneSessionConfig(snapshot.UI.Session)
126 return snapshot
127}
128
129func cloneRuntimeSearchShortcuts(in map[string]entity.RuntimeSearchShortcut) map[string]entity.RuntimeSearchShortcut {
130 if in == nil {
131 return nil
132 }
133 out := make(map[string]entity.RuntimeSearchShortcut, len(in))
134 for key, shortcut := range in {
135 out[key] = shortcut
136 }
137 return out
138}
139
140func cloneWorkspaceConfig(in entity.WorkspaceConfig) entity.WorkspaceConfig {
141 in.PaneMode.Actions = cloneActionBindings(in.PaneMode.Actions)
142 in.TabMode.Actions = cloneActionBindings(in.TabMode.Actions)
143 in.ResizeMode.Actions = cloneActionBindings(in.ResizeMode.Actions)
144 in.Shortcuts.Actions = cloneActionBindings(in.Shortcuts.Actions)
145 in.FloatingPane.Profiles = cloneFloatingPaneProfiles(in.FloatingPane.Profiles)
146 return in
147}
148
149func cloneSessionConfig(in entity.SessionConfig) entity.SessionConfig {
150 in.SessionMode.Actions = cloneActionBindings(in.SessionMode.Actions)
151 return in
152}
153
154func cloneActionBindings(in map[string]entity.ActionBinding) map[string]entity.ActionBinding {
155 if in == nil {
156 return nil
157 }
158 out := make(map[string]entity.ActionBinding, len(in))
159 for action, binding := range in {
160 binding.Keys = cloneStringSlice(binding.Keys)
161 out[action] = binding
162 }
163 return out
164}
165
166func cloneFloatingPaneProfiles(in map[string]entity.FloatingPaneProfile) map[string]entity.FloatingPaneProfile {
167 if in == nil {
168 return nil
169 }
170 out := make(map[string]entity.FloatingPaneProfile, len(in))
171 for name, profile := range in {
172 profile.Keys = cloneStringSlice(profile.Keys)
173 out[name] = profile
174 }
175 return out
176}
177
178func cloneStringSlice(in []string) []string {
179 if in == nil {
180 return nil
181 }
182 out := make([]string, len(in))
183 copy(out, in)
184 return out
185}
186
187func engineHardwareDecodingModeFromConfig(mode config.HardwareDecodingMode) entity.EngineHardwareDecodingMode {
188 switch mode {
189 case config.HardwareDecodingForce:
190 return entity.EngineHardwareDecodingForce
191 case config.HardwareDecodingDisable:
192 return entity.EngineHardwareDecodingDisable
193 default:
194 return entity.EngineHardwareDecodingAuto
195 }
196}