| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 | package database/*	ArOZ Online Database Access Module	author: tobychui	This is an improved Object oriented base solution to the original	aroz online database script.*/import (	"encoding/json"	"errors"	"log"	"sync"	"github.com/boltdb/bolt")type Database struct {	Db       *bolt.DB	Tables   sync.Map	ReadOnly bool}func NewDatabase(dbfile string, readOnlyMode bool) (*Database, error) {	db, err := bolt.Open(dbfile, 0600, nil)	log.Println("Key-value Database Service Started: " + dbfile)	tableMap := sync.Map{}	//Build the table list from database	err = db.View(func(tx *bolt.Tx) error {		return tx.ForEach(func(name []byte, _ *bolt.Bucket) error {			tableMap.Store(string(name), "")			return nil		})	})	return &Database{		Db:       db,		Tables:   tableMap,		ReadOnly: readOnlyMode,	}, err}/*	Create / Drop a table	Usage:	err := sysdb.NewTable("MyTable")	err := sysdb.DropTable("MyTable")*/func (d *Database) UpdateReadWriteMode(readOnly bool) {	d.ReadOnly = readOnly}//Dump the whole db into a log filefunc (d *Database) Dump(filename string) ([]string, error) {	results := []string{}	d.Tables.Range(func(tableName, v interface{}) bool {		entries, err := d.ListTable(tableName.(string))		if err != nil {			log.Println("Reading table " + tableName.(string) + " failed: " + err.Error())			return false		}		for _, keypairs := range entries {			results = append(results, string(keypairs[0])+":"+string(keypairs[1])+"\n")		}		return true	})	return results, nil}//Create a new tablefunc (d *Database) NewTable(tableName string) error {	if d.ReadOnly == true {		return errors.New("Operation rejected in ReadOnly mode")	}	err := d.Db.Update(func(tx *bolt.Tx) error {		_, err := tx.CreateBucketIfNotExists([]byte(tableName))		if err != nil {			return err		}		return nil	})	d.Tables.Store(tableName, "")	return err}//Check is table existsfunc (d *Database) TableExists(tableName string) bool {	if _, ok := d.Tables.Load(tableName); ok {		return true	}	return false}//Drop the given tablefunc (d *Database) DropTable(tableName string) error {	if d.ReadOnly == true {		return errors.New("Operation rejected in ReadOnly mode")	}	err := d.Db.Update(func(tx *bolt.Tx) error {		err := tx.DeleteBucket([]byte(tableName))		if err != nil {			return err		}		return nil	})	return err}/*	Write to database with given tablename and key. Example Usage:	type demo struct{		content string	}	thisDemo := demo{		content: "Hello World",	}	err := sysdb.Write("MyTable", "username/message",thisDemo);*/func (d *Database) Write(tableName string, key string, value interface{}) error {	if d.ReadOnly == true {		return errors.New("Operation rejected in ReadOnly mode")	}	jsonString, err := json.Marshal(value)	if err != nil {		return err	}	err = d.Db.Update(func(tx *bolt.Tx) error {		_, err := tx.CreateBucketIfNotExists([]byte(tableName))		b := tx.Bucket([]byte(tableName))		err = b.Put([]byte(key), jsonString)		return err	})	return err}/*	Read from database and assign the content to a given datatype. Example Usage:	type demo struct{		content string	}	thisDemo := new(demo)	err := sysdb.Read("MyTable", "username/message",&thisDemo);*/func (d *Database) Read(tableName string, key string, assignee interface{}) error {	err := d.Db.View(func(tx *bolt.Tx) error {		b := tx.Bucket([]byte(tableName))		v := b.Get([]byte(key))		json.Unmarshal(v, &assignee)		return nil	})	return err}func (d *Database) KeyExists(tableName string, key string) bool {	resultIsNil := false	err := d.Db.View(func(tx *bolt.Tx) error {		b := tx.Bucket([]byte(tableName))		v := b.Get([]byte(key))		if v == nil {			resultIsNil = true		}		return nil	})	if err != nil {		return false	} else {		if resultIsNil {			return false		} else {			return true		}	}}/*	Delete a value from the database table given tablename and key	err := sysdb.Delete("MyTable", "username/message");*/func (d *Database) Delete(tableName string, key string) error {	if d.ReadOnly == true {		return errors.New("Operation rejected in ReadOnly mode")	}	err := d.Db.Update(func(tx *bolt.Tx) error {		tx.Bucket([]byte(tableName)).Delete([]byte(key))		return nil	})	return err}/*	//List table example usage	//Assume the value is stored as a struct named "groupstruct"	entries, err := sysdb.ListTable("test")	if err != nil {		panic(err)	}	for _, keypairs := range entries{		log.Println(string(keypairs[0]))		group := new(groupstruct)		json.Unmarshal(keypairs[1], &group)		log.Println(group);	}*/func (d *Database) ListTable(tableName string) ([][][]byte, error) {	var results [][][]byte	err := d.Db.View(func(tx *bolt.Tx) error {		b := tx.Bucket([]byte(tableName))		c := b.Cursor()		for k, v := c.First(); k != nil; k, v = c.Next() {			results = append(results, [][]byte{k, v})		}		return nil	})	return results, err}func (d *Database) Close() {	d.Db.Close()	return}
 |