1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
38 package mongo
39
40 import (
41 "go4.org/jsonconfig"
42 "go4.org/legal"
43 "gopkg.in/mgo.v2"
44 "perkeep.org/pkg/blobserver"
45 )
46
47 type mongoStorage struct {
48 c *mgo.Collection
49 }
50
51
52
53 type blobDoc struct {
54
55 Key string
56
57 Size uint32
58
59 Blob []byte
60 }
61
62 func init() {
63 blobserver.RegisterStorageConstructor("mongo", blobserver.StorageConstructor(newFromConfig))
64 legal.RegisterLicense(`
65 For Mongo Driver
66 mgo - MongoDB driver for Go
67 Copyright (c) 2010-2013 - Gustavo Niemeyer <gustavo@niemeyer.net>
68 All rights reserved.
69 `)
70 }
71
72 func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (blobserver.Storage, error) {
73 cfg, err := configFromJSON(config)
74 if err != nil {
75 return nil, err
76 }
77 return newMongoStorage(cfg)
78 }
79
80 var uniqueKeyIndex = mgo.Index{
81 Key: []string{"key"},
82 Unique: true,
83 DropDups: false,
84 Background: false,
85 Sparse: false,
86 }
87
88 func newMongoStorage(cfg config) (blobserver.Storage, error) {
89 session, err := getConnection(cfg.url())
90 if err != nil {
91 return nil, err
92 }
93 c := session.DB(cfg.database).C(cfg.collection)
94 err = c.EnsureIndex(uniqueKeyIndex)
95 if err != nil {
96 return nil, err
97 }
98 return blobserver.Storage(&mongoStorage{c: c}), nil
99
100 }
101
102
103 type config struct {
104 server string
105 database string
106 collection string
107 user string
108 password string
109 }
110
111 func (cfg *config) url() string {
112 if cfg.user == "" || cfg.password == "" {
113 return cfg.server
114 }
115 return cfg.user + ":" + cfg.password + "@" + cfg.server + "/" + cfg.database
116 }
117
118
119
120 func configFromJSON(cfg jsonconfig.Obj) (config, error) {
121 conf := config{
122 server: cfg.OptionalString("host", "localhost"),
123 database: cfg.RequiredString("database"),
124 collection: cfg.OptionalString("collection", "blobs"),
125 user: cfg.OptionalString("user", ""),
126 password: cfg.OptionalString("password", ""),
127 }
128 if err := cfg.Validate(); err != nil {
129 return config{}, err
130 }
131 return conf, nil
132 }
133
134 func getConnection(url string) (*mgo.Session, error) {
135 session, err := mgo.Dial(url)
136 if err != nil {
137 return nil, err
138 }
139 session.SetMode(mgo.Monotonic, true)
140 session.SetSafe(&mgo.Safe{})
141 return session, nil
142 }