qbolt/main.go

186 lines
3.2 KiB
Go

package main
import "C"
import (
"errors"
"os"
"github.com/boltdb/bolt"
)
//export GetMagic
func GetMagic() int64 {
return 0x10203040
}
//export Bolt_Options_New
func Bolt_Options_New() ObjectReference {
b := *bolt.DefaultOptions
return gms.Put(&b)
}
//export Bolt_Options_New_Readonly
func Bolt_Options_New_Readonly() ObjectReference {
b := *bolt.DefaultOptions
b.ReadOnly = true
return gms.Put(&b)
}
//export Recall
func Recall(f func(a int64) int64) int64 {
return f(3)
}
//export Bolt_Open
func Bolt_Open(path string, mode uint32, opts ObjectReference) (ObjectReference, string) {
optsIFC, ok := gms.Get(opts)
if !ok {
return 0, ""
}
ptrBoltOps, ok := optsIFC.(*bolt.Options)
if !ok {
return 0, ""
}
ptrDB, err := bolt.Open(path, os.FileMode(mode), ptrBoltOps)
if err != nil {
return 0, err.Error()
}
dbRef := gms.Put(ptrDB)
return dbRef, ""
}
func withBoltDBReference(b ObjectReference, fn func(db *bolt.DB) error) error {
dbIFC, ok := gms.Get(b)
if !ok {
return NullObjectReference
}
ptrDB, ok := dbIFC.(*bolt.DB)
if !ok {
return NullObjectReference
}
return fn(ptrDB)
}
type CallResponse struct {
s string
e error
}
type NextCall struct {
content chan CallResponse
}
//export Bolt_ListBuckets
func Bolt_ListBuckets(b ObjectReference, browse []string) ObjectReference {
pNC := &NextCall{
content: make(chan CallResponse, 0),
}
pNC_Ref := gms.Put(pNC)
go func() {
err := withBoltDBReference(b, func(db *bolt.DB) error {
return db.View(func(tx *bolt.Tx) error {
if len(browse) == 0 {
// Root-mode
return tx.ForEach(func(k []byte, _ *bolt.Bucket) error {
pNC.content <- CallResponse{s: string(k)}
return nil
})
} else {
// Nested-mode
bucket := tx.Bucket([]byte(browse[0]))
if bucket == nil {
return errors.New("Unknown bucket")
}
for i := 1; i < len(browse); i += 1 {
bucket = bucket.Bucket([]byte(browse[i]))
if bucket == nil {
return errors.New("Unknown bucket")
}
}
return bucket.ForEach(func(k, v []byte) error {
pNC.content <- CallResponse{s: string(k)}
return nil
})
}
})
})
if err != nil {
pNC.content <- CallResponse{e: err}
}
close(pNC.content)
}()
return pNC_Ref
}
const (
ERROR_AND_STOP_CALLING int = 100
ERROR_AND_KEEP_CALLING = 101
FINISHED_OK = 102
REAL_MESSAGE = 103
)
//export GetNext
func GetNext(oRef ObjectReference) (int, string) {
pNC_Iface, ok := gms.Get(oRef)
if !ok {
return ERROR_AND_STOP_CALLING, NullObjectReference.Error()
}
pNC, ok := pNC_Iface.(*NextCall)
if !ok {
return ERROR_AND_STOP_CALLING, NullObjectReference.Error()
}
cr, ok := <-pNC.content
if !ok {
gms.Delete(oRef)
return FINISHED_OK, ""
}
if cr.e != nil {
return ERROR_AND_KEEP_CALLING, cr.e.Error()
}
return REAL_MESSAGE, cr.s
}
//export Bolt_ListBucketsAtRoot
func Bolt_ListBucketsAtRoot(b ObjectReference) ObjectReference {
return Bolt_ListBuckets(b, nil)
}
//export Bolt_Close
func Bolt_Close(b ObjectReference) string {
err := withBoltDBReference(b, func(db *bolt.DB) error {
return db.Close()
})
if err != nil {
return err.Error()
}
gms.Delete(b)
return ""
}
func main() {
// virtual
}