gosuki/chrome.go

208 lines
4.9 KiB
Go

package main
import (
"io/ioutil"
"path"
"github.com/buger/jsonparser"
)
var jsonNodeTypes = struct {
Folder, URL string
}{"folder", "url"}
var jsonNodePaths = struct {
Type, Children, URL string
}{"type", "children", "url"}
type ParseChildFunc func([]byte, jsonparser.ValueType, int, error)
type RecursiveParseFunc func([]byte, []byte, jsonparser.ValueType, int) error
type ChromeBrowser struct {
BaseBrowser //embedding
}
func NewChromeBrowser() IBrowser {
browser := &ChromeBrowser{}
browser.name = "chrome"
browser.bType = TChrome
browser.baseDir = Chrome.BookmarkDir
browser.bkFile = Chrome.BookmarkFile
browser.stats = &ParserStats{}
browser.SetupWatcher()
return browser
}
func (bw *ChromeBrowser) Watch() bool {
if !bw.isWatching {
go WatcherThread(bw)
bw.isWatching = true
return true
}
return false
}
func (bw *ChromeBrowser) Load() {
// 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 SetupWatcher() !")
}
log.Debug("preloading bookmarks")
bw.Run()
}
func (bw *ChromeBrowser) Run() {
// Create buffer db
//bufferDB := DB{"buffer", DB_BUFFER_PATH, nil, false}
bw.InitBuffer()
defer bw.bufferDB.Close()
// Load bookmark file
bookmarkPath := path.Join(bw.baseDir, bw.bkFile)
f, err := ioutil.ReadFile(bookmarkPath)
logPanic(err)
var parseChildren ParseChildFunc
var gJsonParseRecursive RecursiveParseFunc
parseChildren = func(childVal []byte, dataType jsonparser.ValueType, offset int, err error) {
if err != nil {
log.Panic(err)
}
gJsonParseRecursive(nil, childVal, dataType, offset)
}
rootsNode := new(Node)
currentNode := rootsNode
//gRecursiveParse = func(isRoot bool) RecursiveParseFunc {
//if isRoot {
//currentNode = rootsNode
//}
//}
gJsonParseRecursive = func(key []byte, node []byte, dataType jsonparser.ValueType, offset int) error {
// Core of google chrome bookmark parsing
// Any loading to local db is done here
bw.stats.currentNodeCount++
parentNode := currentNode
currentNode := new(Node)
var nodeType, children []byte
var childrenType jsonparser.ValueType
bookmark := &Bookmark{}
// Paths to lookup in node payload
paths := [][]string{
[]string{"type"},
[]string{"name"}, // Title of page
[]string{"url"},
[]string{"children"},
}
jsonparser.EachKey(node, func(idx int, value []byte, vt jsonparser.ValueType, err error) {
switch idx {
case 0:
nodeType = value
currentNode.Type = _s(value)
case 1: // name or title
currentNode.Name = _s(value)
case 2:
currentNode.URL = _s(value)
case 3:
children, childrenType = value, vt
}
}, paths...)
bookmark.Metadata = currentNode.Name
bookmark.URL = currentNode.URL
// If node type is string ignore (needed for sync_transaction_version)
if dataType == jsonparser.String {
return nil
}
// if node is url(leaf), handle the url
if _s(nodeType) == jsonNodeTypes.URL {
// Add bookmark to db here
//debugPrint("%s", url)
//debugPrint("%s", node)
// Find tags in title
//findTagsInTitle(name)
bw.stats.currentUrlCount++
// Run parsehoos before adding bookmark
bw.RunParseHooks(bookmark)
// Add bookmark
bookmark.add(bw.bufferDB)
}
parentNode.Children = append(parentNode.Children, currentNode)
// if node is a folder with children
if childrenType == jsonparser.Array && len(children) > 2 { // if len(children) > len("[]")
jsonparser.ArrayEach(node, parseChildren, jsonNodePaths.Children)
}
return nil
}
//debugPrint("parsing bookmarks")
// Begin parsing
rootsData, _, _, _ := jsonparser.Get(f, "roots")
log.Debug("loading bookmarks to bufferdb")
// Load bookmarks to currentJobDB
jsonparser.ObjectEach(rootsData, gJsonParseRecursive)
go WalkNode(rootsNode)
// Finished parsing
log.Debugf("parsed %d bookmarks", bw.stats.currentUrlCount)
// Reset parser counter
bw.stats.lastURLCount = bw.stats.currentUrlCount
bw.stats.lastNodeCount = bw.stats.currentNodeCount
bw.stats.currentNodeCount = 0
bw.stats.currentUrlCount = 0
// Compare currentDb with memCacheDb for new bookmarks
// If cacheDB is empty just copy bufferDB to cacheDB
// until local db is already populated and preloaded
//debugPrint("%d", bufferDB.Count())
if empty, err := cacheDB.isEmpty(); empty {
logPanic(err)
log.Debug("cache empty: loading bufferdb to cachedb")
//start := time.Now()
bw.bufferDB.SyncTo(cacheDB)
//debugPrint("<%s> is now (%d)", cacheDB.name, cacheDB.Count())
//elapsed := time.Since(start)
//debugPrint("copy in %s", elapsed)
debugPrint("syncing <%s> to disk", cacheDB.name)
cacheDB.SyncToDisk(getDBFullPath())
}
// TODO: Check if new/modified bookmarks in buffer compared to cache
log.Debugf("TODO: check if new/modified bookmarks in %s compared to %s", bw.bufferDB.name, cacheDB.name)
}