gosuki/browsers.go
2018-05-27 18:10:49 +02:00

149 lines
3.4 KiB
Go

// ### Browsers API
//
// All constants and common API for browsers should be implemented here.
//
// For *browser specific* implementation create a new file for that browser.
//
// You must then implement a `func New[BrowserType]() IBrowser` function and
// implement parsing.
package main
import (
"fmt"
"path"
"github.com/fsnotify/fsnotify"
"github.com/sp4ke/hashmap"
)
type BrowserType uint8
// Browser types
const (
TChrome BrowserType = iota
TFirefox
)
// Chrome details
var Chrome = struct {
BookmarkFile string
BookmarkDir string
}{
"Bookmarks",
"/home/spike/.config/google-chrome-unstable/Default/",
}
type IBrowser interface {
IWatchable
InitBuffer() // init buffer db, should be defered to close after call
InitIndex() // Creates in memory Index (RB-Tree)
RegisterHooks(...ParseHook)
Load() // Loads bookmarks to db without watching
//Parse(...ParseHook) // Main parsing method with different parsing hooks
Close() // Gracefully finish work and stop watching
}
// Base browser class serves as reference for implmented browser types
// Browser should contain enough data internally to not rely on any global
// variable or constant if possible.
// To create new browsers, you must implement a New<BrowserType>() IBrowser function
//
// URLIndex (HashMap RBTree):
// Used as fast query db representing the last known browser bookmarks.
//
// nodeTree (Tree DAG):
// Used in each job to represent bookmarks in a tree
//
// bufferDB: across jobs sqlite buffer
type BaseBrowser struct {
watcher *fsnotify.Watcher
baseDir string
bkFile string
bufferDB *DB
URLIndex *hashmap.RBTree // Fast query of last browser state
nodeTree *Node // pointer to root of the node tree
stats *ParserStats
bType BrowserType
name string
isWatching bool
parseHooks []ParseHook
}
func (bw *BaseBrowser) Watcher() *fsnotify.Watcher {
return bw.watcher
}
func (bw *BaseBrowser) Load() {
log.Debug("BaseBrowser Load()")
bw.InitIndex()
// Check if cache is initialized
if CacheDB == nil || CacheDB.Handle == nil {
log.Critical("cache is not yet initialized !")
panic("cache is not yet initialized !")
}
if bw.watcher == nil {
log.Fatal("watcher not initialized, use SetupWatcher() when creating the browser !")
}
log.Debug("preloading bookmarks")
}
func (bw *BaseBrowser) GetPath() string {
return path.Join(bw.baseDir, bw.bkFile)
}
func (bw *BaseBrowser) GetDir() string {
return bw.baseDir
}
func (bw *BaseBrowser) SetupWatcher() {
var err error
bw.watcher, err = fsnotify.NewWatcher()
logPanic(err)
err = bw.watcher.Add(bw.baseDir)
logPanic(err)
}
func (bw *BaseBrowser) Close() {
err := bw.watcher.Close()
bw.bufferDB.Close()
logPanic(err)
}
func (b *BaseBrowser) InitIndex() {
b.URLIndex = NewIndex()
}
func (b *BaseBrowser) RebuildIndex() {
log.Debugf("Rebuilding index based on current nodeTree")
b.URLIndex = NewIndex()
WalkBuildIndex(b.nodeTree, b)
}
func (b *BaseBrowser) InitBuffer() {
bufferName := fmt.Sprintf("buffer_%s", b.name)
bufferPath := fmt.Sprintf(DBBufferFmt, bufferName)
b.bufferDB = DB{}.New(bufferName, bufferPath)
b.bufferDB.Init()
b.bufferDB.Attach(CacheDB)
}
func (b *BaseBrowser) RegisterHooks(hooks ...ParseHook) {
log.Debug("Registering hooks")
for _, hook := range hooks {
b.parseHooks = append(b.parseHooks, hook)
}
}
// Runs browsed defined hooks on bookmark
func (b *BaseBrowser) RunParseHooks(node *Node) {
for _, hook := range b.parseHooks {
hook(node)
}
}