use interfaces for cleaner code
This commit is contained in:
parent
1a07be6018
commit
22bf5e7e66
@ -1,5 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
// Bookmark type
|
||||||
type Bookmark struct {
|
type Bookmark struct {
|
||||||
url string
|
url string
|
||||||
metadata string
|
metadata string
|
||||||
@ -9,9 +10,7 @@ type Bookmark struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bk *Bookmark) add(db *DB) {
|
func (bk *Bookmark) add(db *DB) {
|
||||||
// TODO
|
//log.Debugf("Adding bookmark %s", bk.url)
|
||||||
// Single out unique urls
|
|
||||||
//debugPrint("%v", bk)
|
|
||||||
_db := db.handle
|
_db := db.handle
|
||||||
|
|
||||||
tx, err := _db.Begin()
|
tx, err := _db.Begin()
|
||||||
|
81
browsers.go
81
browsers.go
@ -1,23 +1,42 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"fmt"
|
||||||
|
"path"
|
||||||
|
|
||||||
fsnotify "gopkg.in/fsnotify.v1"
|
"github.com/fsnotify/fsnotify"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BrowserType uint8
|
type BrowserType uint8
|
||||||
|
|
||||||
|
// Browser types
|
||||||
const (
|
const (
|
||||||
TChromeBrowser BrowserType = iota
|
TChrome BrowserType = iota
|
||||||
FirefoxBrowser
|
TFirefox
|
||||||
)
|
)
|
||||||
|
|
||||||
type Browser interface {
|
// Chrome details
|
||||||
New(BrowserType) *Browser // Creates and initialize new browser
|
var Chrome = struct {
|
||||||
Watch() *fsnotify.Watcher // Starts watching bookmarks and runs Load on change
|
BookmarkFile string
|
||||||
Load() // Loads bookmarks to db without watching
|
BookmarkDir string
|
||||||
|
}{
|
||||||
|
"Bookmarks",
|
||||||
|
"/home/spike/.config/google-chrome/Default/",
|
||||||
|
}
|
||||||
|
|
||||||
|
type IWatchable interface {
|
||||||
|
Watch() bool
|
||||||
|
Watcher() *fsnotify.Watcher // returns browser watcher
|
||||||
Parse() // Main parsing method
|
Parse() // Main parsing method
|
||||||
|
GetPath() string //returns bookmark path
|
||||||
|
GetDir() string // returns bookmarks dir
|
||||||
|
}
|
||||||
|
|
||||||
|
type IBrowser interface {
|
||||||
|
SetupWatcher() // Starts watching bookmarks and runs Load on change
|
||||||
|
Watch() bool
|
||||||
|
InitBuffer() // init buffer db, should be defered to close after call
|
||||||
|
Load() // Loads bookmarks to db without watching
|
||||||
//Parse(...ParseHook) // Main parsing method with different parsing hooks
|
//Parse(...ParseHook) // Main parsing method with different parsing hooks
|
||||||
Close() // Gracefully finish work and stop watching
|
Close() // Gracefully finish work and stop watching
|
||||||
}
|
}
|
||||||
@ -25,16 +44,52 @@ type Browser interface {
|
|||||||
// Base browser class serves as reference for implmented browser types
|
// Base browser class serves as reference for implmented browser types
|
||||||
// Browser should contain enough data internally to not rely on any global
|
// Browser should contain enough data internally to not rely on any global
|
||||||
// variable or constant if possible.
|
// variable or constant if possible.
|
||||||
|
// To create new browsers, you must implement a New<BrowserType>() function
|
||||||
|
|
||||||
type BaseBrowser struct {
|
type BaseBrowser struct {
|
||||||
watcher *fsnotify.Watcher
|
watcher *fsnotify.Watcher
|
||||||
baseDir string
|
baseDir string
|
||||||
bkFile string
|
bkFile string
|
||||||
parseFunc func(*Browser)
|
bufferDB *DB
|
||||||
bufferDB *sql.DB
|
stats *ParserStats
|
||||||
stats *parserStats
|
bType BrowserType
|
||||||
|
name string
|
||||||
|
isWatching bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChromeBrowser struct {
|
func (bw *BaseBrowser) Watcher() *fsnotify.Watcher {
|
||||||
BaseBrowser //embedding
|
return bw.watcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bw *BaseBrowser) Load() {
|
||||||
|
log.Debug("BaseBrowser Load()")
|
||||||
|
}
|
||||||
|
|
||||||
|
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) InitBuffer() {
|
||||||
|
bufferName := fmt.Sprintf("buffer_%s", b.name)
|
||||||
|
bufferPath := fmt.Sprintf(DBBufferFmt, bufferName)
|
||||||
|
b.bufferDB = DB{}.New(bufferName, bufferPath)
|
||||||
|
b.bufferDB.Init()
|
||||||
}
|
}
|
||||||
|
181
chrome.go
Normal file
181
chrome.go
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
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 //embidding
|
||||||
|
}
|
||||||
|
|
||||||
|
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() !")
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrint("preloading bookmarks")
|
||||||
|
bw.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bw *ChromeBrowser) Parse() {
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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++
|
||||||
|
|
||||||
|
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
|
||||||
|
case 1: // name or title
|
||||||
|
bookmark.metadata = _s(value)
|
||||||
|
case 2:
|
||||||
|
bookmark.url = _s(value)
|
||||||
|
case 3:
|
||||||
|
children, childrenType = value, vt
|
||||||
|
}
|
||||||
|
}, paths...)
|
||||||
|
|
||||||
|
// 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++
|
||||||
|
bookmark.add(bw.bufferDB)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
|
||||||
|
debugPrint("loading bookmarks to bufferdb")
|
||||||
|
// Load bookmarks to currentJobDB
|
||||||
|
jsonparser.ObjectEach(rootsData, gJsonParseRecursive)
|
||||||
|
|
||||||
|
// Finished parsing
|
||||||
|
log.Infof("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)
|
||||||
|
debugPrint("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
|
||||||
|
debugPrint("TODO: check if new/modified bookmarks in %s compared to %s", bw.bufferDB.name, cacheDB.name)
|
||||||
|
|
||||||
|
}
|
4
db.go
4
db.go
@ -20,7 +20,7 @@ var (
|
|||||||
const (
|
const (
|
||||||
DB_FILENAME = "gomarks.db"
|
DB_FILENAME = "gomarks.db"
|
||||||
DB_MEMCACHE_PATH = "file:memcache?mode=memory&cache=shared"
|
DB_MEMCACHE_PATH = "file:memcache?mode=memory&cache=shared"
|
||||||
DB_BUFFER_PATH = "file:buffer?mode=memory&cache=shared"
|
DBBufferFmt = "file:%s?mode=memory&cache=shared"
|
||||||
DB_BACKUP_HOOK = "sqlite_with_backup"
|
DB_BACKUP_HOOK = "sqlite_with_backup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ func (db *DB) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) Close() {
|
func (db *DB) Close() {
|
||||||
//debugPrint("Closing <%s>", db.name)
|
debugPrint("Closing <%s>", db.name)
|
||||||
db.handle.Close()
|
db.handle.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
main.go
9
main.go
@ -15,16 +15,15 @@ func main() {
|
|||||||
// Initialize sqlite database available in global `cacheDB` variable
|
// Initialize sqlite database available in global `cacheDB` variable
|
||||||
initDB()
|
initDB()
|
||||||
|
|
||||||
chromeWatcher := &bookmarkWatcher{}
|
cb := NewChromeBrowser()
|
||||||
chromeWatcher.Init(BOOKMARK_DIR, BOOKMARK_FILE, TChromeBrowser)
|
cb.Load()
|
||||||
chromeWatcher.Preload()
|
_ = cb.Watch()
|
||||||
chromeWatcher.Start()
|
|
||||||
|
|
||||||
// Flush to disk for testing
|
// Flush to disk for testing
|
||||||
//flushToDisk()
|
//flushToDisk()
|
||||||
|
|
||||||
//var chrome Browser
|
//var chrome Browser
|
||||||
//chrome = browsers.New()
|
//chrome = browsers.New(browsres.TChrome)
|
||||||
//chrome.Watch()
|
//chrome.Watch()
|
||||||
|
|
||||||
<-block
|
<-block
|
||||||
|
140
parse.go
140
parse.go
@ -1,35 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"path"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/buger/jsonparser"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RE_TAGS = `\B#\w+`
|
RE_TAGS = `\B#\w+`
|
||||||
)
|
)
|
||||||
|
|
||||||
type parserStats struct {
|
type ParserStats struct {
|
||||||
lastNodeCount int
|
lastNodeCount int
|
||||||
lastUrlCount int
|
lastURLCount int
|
||||||
currentNodeCount int
|
currentNodeCount int
|
||||||
currentUrlCount int
|
currentUrlCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
func _s(value interface{}) string {
|
func _s(value interface{}) string {
|
||||||
return string(value.([]byte))
|
return string(value.([]byte))
|
||||||
}
|
}
|
||||||
@ -39,124 +24,3 @@ func findTagsInTitle(title []byte) {
|
|||||||
tags := regex.FindAll(title, -1)
|
tags := regex.FindAll(title, -1)
|
||||||
debugPrint("%s ---> found following tags: %s", title, tags)
|
debugPrint("%s ---> found following tags: %s", title, tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func googleParseBookmarks(bw *bookmarkWatcher) {
|
|
||||||
|
|
||||||
// Create buffer db
|
|
||||||
//bufferDB := DB{"buffer", DB_BUFFER_PATH, nil, false}
|
|
||||||
bufferDB := DB{}.New("buffer", DB_BUFFER_PATH)
|
|
||||||
defer bufferDB.Close()
|
|
||||||
bufferDB.Init()
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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++
|
|
||||||
|
|
||||||
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
|
|
||||||
case 1: // name or title
|
|
||||||
bookmark.metadata = _s(value)
|
|
||||||
case 2:
|
|
||||||
bookmark.url = _s(value)
|
|
||||||
case 3:
|
|
||||||
children, childrenType = value, vt
|
|
||||||
}
|
|
||||||
}, paths...)
|
|
||||||
|
|
||||||
// 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++
|
|
||||||
bookmark.add(bufferDB)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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")
|
|
||||||
|
|
||||||
debugPrint("loading bookmarks to bufferdb")
|
|
||||||
// Load bookmarks to currentJobDB
|
|
||||||
jsonparser.ObjectEach(rootsData, gJsonParseRecursive)
|
|
||||||
|
|
||||||
// Finished parsing
|
|
||||||
log.Infof("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)
|
|
||||||
debugPrint("cache empty: loading bufferdb to cachedb")
|
|
||||||
|
|
||||||
//start := time.Now()
|
|
||||||
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
|
|
||||||
debugPrint("TODO: check if new/modified bookmarks in %s compared to %s", bufferDB.name, cacheDB.name)
|
|
||||||
|
|
||||||
//_ = cacheDB.Print()
|
|
||||||
}
|
|
||||||
|
84
watcher.go
84
watcher.go
@ -1,100 +1,32 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bookmarkWatcher struct {
|
func WatcherThread(w IWatchable) {
|
||||||
watcher *fsnotify.Watcher
|
|
||||||
baseDir string
|
|
||||||
bkFile string
|
|
||||||
parseFunc func(*bookmarkWatcher)
|
|
||||||
bufferDB *sql.DB
|
|
||||||
stats *parserStats
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bw *bookmarkWatcher) Close() error {
|
bookmarkPath := w.GetPath()
|
||||||
if err := bw.watcher.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bw *bookmarkWatcher) Init(basedir string, bkfile string, browserType BrowserType) *bookmarkWatcher {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
bw.baseDir = basedir
|
|
||||||
bw.bkFile = bkfile
|
|
||||||
|
|
||||||
bw.stats = &parserStats{}
|
|
||||||
|
|
||||||
bw.watcher, err = fsnotify.NewWatcher()
|
|
||||||
logPanic(err)
|
|
||||||
|
|
||||||
switch browserType {
|
|
||||||
case TChromeBrowser:
|
|
||||||
bw.parseFunc = googleParseBookmarks
|
|
||||||
}
|
|
||||||
|
|
||||||
return bw
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bw *bookmarkWatcher) Preload() *bookmarkWatcher {
|
|
||||||
|
|
||||||
// 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("please run bookmarkWatcher.Init() first !")
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint("preloading bookmarks")
|
|
||||||
bw.parseFunc(bw)
|
|
||||||
|
|
||||||
return bw
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bw *bookmarkWatcher) Start() error {
|
|
||||||
|
|
||||||
if err := bw.watcher.Add(bw.baseDir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
go bWatcherThread(bw, bw.parseFunc)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func bWatcherThread(bw *bookmarkWatcher, parseFunc func(bw *bookmarkWatcher)) {
|
|
||||||
|
|
||||||
bookmarkPath := path.Join(bw.baseDir, bw.bkFile)
|
|
||||||
log.Infof("watching %s", bookmarkPath)
|
log.Infof("watching %s", bookmarkPath)
|
||||||
|
|
||||||
|
watcher := w.Watcher()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case event := <-bw.watcher.Events:
|
case event := <-watcher.Events:
|
||||||
|
|
||||||
if event.Op&fsnotify.Create == fsnotify.Create &&
|
if event.Op&fsnotify.Create == fsnotify.Create &&
|
||||||
event.Name == bookmarkPath {
|
event.Name == bookmarkPath {
|
||||||
|
|
||||||
debugPrint("event: %v | eventName: %v", event.Op, event.Name)
|
debugPrint("event: %v | eventName: %v", event.Op, event.Name)
|
||||||
//debugPrint("modified file: %s", event.Name)
|
//debugPrint("modified file: %s", event.Name)
|
||||||
//start := time.Now()
|
//start := time.Now()
|
||||||
parseFunc(bw)
|
//parseFunc(bw)
|
||||||
|
w.Parse()
|
||||||
//elapsed := time.Since(start)
|
//elapsed := time.Since(start)
|
||||||
//debugPrint("parsed in %s", elapsed)
|
//debugPrint("parsed in %s", elapsed)
|
||||||
}
|
}
|
||||||
case err := <-bw.watcher.Errors:
|
case err := <-watcher.Errors:
|
||||||
log.Errorf("error: %s", err)
|
log.Errorf("error: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debugPrint("Exiting watch thread")
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user