2013-08-06 03:51:26 +00:00
|
|
|
package dbutil
|
2013-02-09 04:43:39 +00:00
|
|
|
|
|
|
|
import (
|
2013-05-09 13:41:06 +00:00
|
|
|
"github.com/vbatts/imgsrv/hash"
|
2013-05-09 16:13:46 +00:00
|
|
|
"github.com/vbatts/imgsrv/types"
|
2013-08-06 00:29:16 +00:00
|
|
|
"labix.org/v2/mgo"
|
2013-03-27 20:30:24 +00:00
|
|
|
"labix.org/v2/mgo/bson"
|
2013-10-04 02:49:57 +00:00
|
|
|
"strings"
|
2013-02-09 04:43:39 +00:00
|
|
|
)
|
|
|
|
|
2013-10-04 03:26:01 +00:00
|
|
|
const (
|
|
|
|
DEFAULT_DB_NAME = "filesrv"
|
|
|
|
)
|
|
|
|
|
2013-08-06 03:51:26 +00:00
|
|
|
type Util struct {
|
2013-10-04 03:26:01 +00:00
|
|
|
Seed string // mongo host seed to Dial into
|
|
|
|
User string // mongo credentials, if needed
|
|
|
|
Pass string // mongo credentials, if needed
|
|
|
|
DbName string // mongo database name, if needed
|
|
|
|
Session *mgo.Session
|
|
|
|
FileDb *mgo.Database
|
|
|
|
Gfs *mgo.GridFS
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *Util) Init() error {
|
|
|
|
var err error
|
|
|
|
u.Session, err = mgo.Dial(u.Seed)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(u.DbName) > 0 {
|
|
|
|
u.FileDb = u.Session.DB(u.DbName)
|
|
|
|
} else {
|
|
|
|
u.FileDb = u.Session.DB(DEFAULT_DB_NAME)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(u.User) > 0 && len(u.Pass) > 0 {
|
|
|
|
err = u.FileDb.Login(u.User, u.Pass)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u.Gfs = u.FileDb.GridFS("fs")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u Util) Close() {
|
|
|
|
u.Session.Close()
|
2013-08-06 03:51:26 +00:00
|
|
|
}
|
2013-02-11 16:00:57 +00:00
|
|
|
|
2013-10-04 02:49:57 +00:00
|
|
|
/*
|
|
|
|
pass through for GridFs
|
|
|
|
*/
|
|
|
|
func (u Util) Open(filename string) (file *mgo.GridFile, err error) {
|
|
|
|
return u.Gfs.Open(strings.ToLower(filename))
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
pass through for GridFs
|
|
|
|
*/
|
2013-10-03 21:04:37 +00:00
|
|
|
func (u Util) Create(filename string) (file *mgo.GridFile, err error) {
|
2013-10-04 02:49:57 +00:00
|
|
|
return u.Gfs.Create(strings.ToLower(filename))
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
pass through for GridFs
|
|
|
|
*/
|
|
|
|
func (u Util) Remove(filename string) (err error) {
|
|
|
|
return u.Gfs.Remove(strings.ToLower(filename))
|
2013-10-03 21:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Find files by their MD5 checksum
|
|
|
|
*/
|
|
|
|
func (u Util) FindFilesByMd5(md5 string) (files []types.File, err error) {
|
|
|
|
err = u.Gfs.Find(bson.M{"md5": md5}).Sort("-metadata.timestamp").All(&files)
|
2013-10-04 02:49:57 +00:00
|
|
|
return files, err
|
2013-10-03 21:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
match for file name
|
|
|
|
*/
|
|
|
|
func (u Util) FindFilesByName(filename string) (files []types.File, err error) {
|
2013-10-04 02:49:57 +00:00
|
|
|
err = u.Gfs.Find(bson.M{"filename": filename}).Sort("-metadata.timestamp").All(&files)
|
|
|
|
return files, err
|
2013-10-03 21:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Case-insensitive pattern match for file name
|
|
|
|
*/
|
|
|
|
func (u Util) FindFilesByPatt(filename_pat string) (files []types.File, err error) {
|
2013-10-04 02:49:57 +00:00
|
|
|
err = u.Gfs.Find(bson.M{"filename": bson.M{"$regex": filename_pat, "$options": "i"}}).Sort("-metadata.timestamp").All(&files)
|
|
|
|
return files, err
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Case-insensitive pattern match for file name
|
|
|
|
*/
|
|
|
|
func (u Util) FindFilesByKeyword(keyword string) (files []types.File, err error) {
|
|
|
|
err = u.Gfs.Find(bson.M{"metadata.keywords": strings.ToLower(keyword)}).Sort("-metadata.timestamp").All(&files)
|
|
|
|
return files, err
|
2013-10-03 21:04:37 +00:00
|
|
|
}
|
|
|
|
|
2013-10-04 02:49:57 +00:00
|
|
|
/*
|
|
|
|
Get all the files.
|
|
|
|
|
|
|
|
pass -1 for all files
|
|
|
|
*/
|
|
|
|
func (u Util) GetFiles(limit int) (files []types.File, err error) {
|
2013-10-04 03:26:01 +00:00
|
|
|
//files = []types.File{}
|
2013-10-04 02:49:57 +00:00
|
|
|
if limit == -1 {
|
|
|
|
err = u.Gfs.Find(nil).Sort("-metadata.timestamp").Limit(limit).All(&files)
|
|
|
|
} else {
|
|
|
|
err = u.Gfs.Find(nil).Sort("-metadata.timestamp").All(&files)
|
|
|
|
}
|
|
|
|
return files, err
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Count the filename matches
|
|
|
|
*/
|
|
|
|
func (u Util) CountFiles(filename string) (count int, err error) {
|
|
|
|
query := u.Gfs.Find(bson.M{"filename": strings.ToLower(filename)})
|
|
|
|
return query.Count()
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Get one file back, by searching by file name
|
|
|
|
*/
|
2013-08-06 03:51:26 +00:00
|
|
|
func (u Util) GetFileByFilename(filename string) (this_file types.File, err error) {
|
2013-10-04 02:49:57 +00:00
|
|
|
err = u.Gfs.Find(bson.M{"filename": strings.ToLower(filename)}).One(&this_file)
|
2013-03-27 20:30:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return this_file, err
|
|
|
|
}
|
|
|
|
return this_file, nil
|
2013-02-11 16:00:57 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 03:51:26 +00:00
|
|
|
func (u Util) GetFileRandom() (this_file types.File, err error) {
|
2013-05-09 13:41:06 +00:00
|
|
|
r := hash.Rand64()
|
2013-08-06 03:51:26 +00:00
|
|
|
err = u.Gfs.Find(bson.M{"random": bson.M{"$gt": r}}).One(&this_file)
|
2013-03-27 20:30:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return this_file, err
|
|
|
|
}
|
|
|
|
if len(this_file.Md5) == 0 {
|
2013-08-06 03:51:26 +00:00
|
|
|
err = u.Gfs.Find(bson.M{"random": bson.M{"$lt": r}}).One(&this_file)
|
2013-03-27 20:30:24 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return this_file, err
|
|
|
|
}
|
|
|
|
return this_file, nil
|
2013-02-11 16:00:57 +00:00
|
|
|
}
|
|
|
|
|
2013-10-04 02:49:57 +00:00
|
|
|
/*
|
|
|
|
Check whether this types.File filename is on Mongo
|
|
|
|
*/
|
2013-08-06 03:51:26 +00:00
|
|
|
func (u Util) HasFileByFilename(filename string) (exists bool, err error) {
|
2013-10-04 02:49:57 +00:00
|
|
|
c, err := u.CountFiles(filename)
|
2013-03-27 20:30:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
exists = (c > 0)
|
|
|
|
return exists, nil
|
2013-02-09 04:43:39 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 03:51:26 +00:00
|
|
|
func (u Util) HasFileByMd5(md5 string) (exists bool, err error) {
|
|
|
|
c, err := u.Gfs.Find(bson.M{"md5": md5}).Count()
|
2013-03-27 20:30:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
exists = (c > 0)
|
|
|
|
return exists, nil
|
2013-02-09 04:43:39 +00:00
|
|
|
}
|
|
|
|
|
2013-08-06 03:51:26 +00:00
|
|
|
func (u Util) HasFileByKeyword(keyword string) (exists bool, err error) {
|
2013-10-04 02:49:57 +00:00
|
|
|
c, err := u.Gfs.Find(bson.M{"metadata": bson.M{"keywords": strings.ToLower(keyword)}}).Count()
|
2013-03-27 20:30:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
exists = (c > 0)
|
|
|
|
return exists, nil
|
2013-02-09 04:43:39 +00:00
|
|
|
}
|
2013-08-06 00:29:16 +00:00
|
|
|
|
2013-08-06 15:00:57 +00:00
|
|
|
/*
|
|
|
|
get a list of file extensions and their frequency count
|
|
|
|
*/
|
|
|
|
func (u Util) GetExtensions() (kp []types.IdCount, err error) {
|
|
|
|
job := &mgo.MapReduce{
|
|
|
|
Map: `
|
|
|
|
function() {
|
|
|
|
if (!this.filename) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = this.filename.split(".")
|
|
|
|
ext = s[s.length - 1] // get the last segment of the split
|
|
|
|
emit(ext,1);
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
Reduce: `
|
|
|
|
function(previous, current) {
|
|
|
|
var count = 0;
|
|
|
|
|
|
|
|
for (index in current) {
|
|
|
|
count += current[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
}
|
|
|
|
if _, err := u.Gfs.Find(nil).MapReduce(job, &kp); err != nil {
|
|
|
|
return kp, err
|
|
|
|
}
|
2013-09-10 18:51:44 +00:00
|
|
|
// Less than effecient, but cleanest place to put this
|
|
|
|
for i := range kp {
|
|
|
|
kp[i].Root = "ext" // for extension. Maps to /ext/
|
|
|
|
}
|
2013-08-06 15:00:57 +00:00
|
|
|
return kp, nil
|
|
|
|
}
|
2013-09-10 18:51:44 +00:00
|
|
|
|
2013-08-06 03:51:26 +00:00
|
|
|
/*
|
|
|
|
get a list of keywords and their frequency count
|
|
|
|
*/
|
2013-08-06 14:37:58 +00:00
|
|
|
func (u Util) GetKeywords() (kp []types.IdCount, err error) {
|
2013-08-06 00:29:16 +00:00
|
|
|
job := &mgo.MapReduce{
|
|
|
|
Map: `
|
|
|
|
function() {
|
|
|
|
if (!this.metadata.keywords) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (index in this.metadata.keywords) {
|
|
|
|
emit(this.metadata.keywords[index], 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
Reduce: `
|
|
|
|
function(previous, current) {
|
|
|
|
var count = 0;
|
|
|
|
|
|
|
|
for (index in current) {
|
|
|
|
count += current[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
}
|
2013-08-06 03:51:26 +00:00
|
|
|
if _, err := u.Gfs.Find(nil).MapReduce(job, &kp); err != nil {
|
2013-08-06 00:29:16 +00:00
|
|
|
return kp, err
|
|
|
|
}
|
2013-09-10 18:51:44 +00:00
|
|
|
// Less than effecient, but cleanest place to put this
|
|
|
|
for i := range kp {
|
|
|
|
kp[i].Root = "k" // for keyword. Maps to /k/
|
|
|
|
}
|
2013-08-06 00:29:16 +00:00
|
|
|
return kp, nil
|
|
|
|
}
|