v0.15.0 9006957

network_session.go RawHistoryFolder

1package webkit
2
3import (
4	"fmt"
5
6	"github.com/bnema/dumber/internal/logging"
7	webkit "github.com/diamondburned/gotk4-webkitgtk/pkg/webkit/v6"
8)
9
10var (
11	// globalNetworkSession holds the persistent network session to prevent garbage collection
12	// This must be kept alive for the entire application lifetime
13	globalNetworkSession *webkit.NetworkSession
14)
15
16// InitPersistentSession creates and initializes a persistent NetworkSession
17// with the provided data and cache directories.
18// This should be called before creating any WebViews to ensure they use persistent storage.
19// Returns an error if initialization fails.
20//
21// IMPORTANT: Once created, this session is stored globally and will be used by all
22// WebViews created afterward, as per WebKitGTK 6.0's design where the first created
23// session becomes the default for the network process.
24func InitPersistentSession(dataDir, cacheDir string) error {
25	// If session already exists, return success (idempotent)
26	// This ensures we only create ONE session for the entire application
27	if globalNetworkSession != nil {
28		logging.Debug(fmt.Sprintf("[webkit] Using existing persistent network session"))
29		return nil
30	}
31
32	// Create persistent network session using gotk4 API
33	// Per WebKitGTK 6.0 docs: "The first WebKitNetworkSession created becomes the default"
34	session := webkit.NewNetworkSession(dataDir, cacheDir)
35	if session == nil {
36		return fmt.Errorf("failed to create persistent network session")
37	}
38
39	// Store the session globally to prevent garbage collection
40	// This is CRITICAL - if the session is GC'd, WebKit falls back to ephemeral storage
41	globalNetworkSession = session
42
43	logging.Debug(fmt.Sprintf("[webkit] Persistent network session created: data=%s, cache=%s", dataDir, cacheDir))
44
45	// Verify the session is not ephemeral
46	if session.IsEphemeral() {
47		return fmt.Errorf("created session is ephemeral despite providing data directories")
48	}
49
50	// Verify the WebsiteDataManager is not ephemeral
51	websiteDataManager := session.WebsiteDataManager()
52	if websiteDataManager == nil {
53		return fmt.Errorf("failed to get website data manager from network session")
54	}
55	if websiteDataManager.IsEphemeral() {
56		return fmt.Errorf("website data manager is ephemeral despite providing data directories")
57	}
58	logging.Debug(fmt.Sprintf("[webkit] WebsiteDataManager verified as non-ephemeral"))
59
60	// Configure CookieManager for persistent cookie storage
61	// This is REQUIRED - without this, cookies are not persisted to disk
62	cookieManager := session.CookieManager()
63	if cookieManager == nil {
64		return fmt.Errorf("failed to get cookie manager from network session")
65	}
66
67	// Set cookie persistent storage to SQLite database
68	// Format: filepath.Join(dataDir, "cookies.db")
69	cookiePath := dataDir + "/cookies.db"
70	cookieManager.SetPersistentStorage(cookiePath, webkit.CookiePersistentStorageSqlite)
71
72	// Set cookie accept policy to no third-party (default)
73	cookieManager.SetAcceptPolicy(webkit.CookiePolicyAcceptNoThirdParty)
74
75	logging.Debug(fmt.Sprintf("[webkit] Cookie manager configured: storage=%s, policy=no-third-party", cookiePath))
76
77	// Enable persistent credential storage (HTTP auth, etc.)
78	session.SetPersistentCredentialStorageEnabled(true)
79
80	// Configure TLS errors to emit signals instead of failing silently
81	// This enables the load-failed-with-tls-errors signal
82	session.SetTLSErrorsPolicy(webkit.TLSErrorsPolicyFail)
83	logging.Debug(fmt.Sprintf("[webkit] TLS errors policy set to FAIL (signals enabled)"))
84
85	// Verify this is indeed the default session now
86	defaultSession := webkit.NetworkSessionGetDefault()
87	if defaultSession == nil {
88		return fmt.Errorf("default network session is nil after creating persistent session")
89	}
90
91	// Check if they're the same session by comparing ephemeral status
92	if defaultSession.IsEphemeral() {
93		return fmt.Errorf("default network session is ephemeral after creating persistent session")
94	}
95
96	logging.Debug(fmt.Sprintf("[webkit] Network session verified as persistent and set as default"))
97	return nil
98}
99
100// GetGlobalNetworkSession returns the global network session.
101// Returns nil if InitPersistentSession hasn't been called successfully.
102func GetGlobalNetworkSession() *webkit.NetworkSession {
103	return globalNetworkSession
104}
105
106// PrefetchDNS prefetches DNS for the given hostname to speed up future requests.
107// This is useful for preloading DNS for links that the user might click.
108// Safe to call even if the hostname is invalid or session is not initialized.
109func PrefetchDNS(hostname string) {
110	if globalNetworkSession == nil {
111		return // Session not initialized yet
112	}
113	if hostname == "" {
114		return // Nothing to prefetch
115	}
116	globalNetworkSession.PrefetchDns(hostname)
117}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close