github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/blobserver/mongo/mongo.go (about) 1 /* 2 Copyright 2014 The Camlistore Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 /* 18 Package mongo registers the "mongo" blobserver storage type, storing 19 blobs using MongoDB. 20 21 Sample (low-level) config: 22 "/bs/": { 23 "handler": "storage-mongo", 24 "handlerArgs": { 25 "host": "172.17.0.2", 26 "database": "camlitest" 27 } 28 }, 29 30 Possible parameters: 31 host (optional, defaults to localhost) 32 database (required) 33 collection (optional, defaults to blobs) 34 user (optional) 35 password (optional) 36 */ 37 package mongo 38 39 import ( 40 "camlistore.org/pkg/blobserver" 41 "camlistore.org/pkg/jsonconfig" 42 "camlistore.org/third_party/labix.org/v2/mgo" 43 ) 44 45 type mongoStorage struct { 46 c *mgo.Collection 47 } 48 49 // blobDoc is the document that gets inserted in the MongoDB database 50 // Its fields are exported because they need to be for the mgo driver to pick them up 51 type blobDoc struct { 52 // Key contains the string representation of a blob reference (e.g. sha1-200d278aa6dd347f494407385ceab316440d5fba). 53 Key string 54 // Size contains the total size of a blob. 55 Size uint32 56 // Blob contains the raw blob data of the blob the above Key refers to. 57 Blob []byte 58 } 59 60 func init() { 61 blobserver.RegisterStorageConstructor("mongo", blobserver.StorageConstructor(newFromConfig)) 62 } 63 64 func newFromConfig(_ blobserver.Loader, config jsonconfig.Obj) (blobserver.Storage, error) { 65 cfg, err := configFromJSON(config) 66 if err != nil { 67 return nil, err 68 } 69 return newMongoStorage(cfg) 70 } 71 72 func newMongoStorage(cfg config) (blobserver.Storage, error) { 73 session, err := getConnection(cfg.url()) 74 if err != nil { 75 return nil, err 76 } 77 c := session.DB(cfg.database).C(cfg.collection) 78 79 return blobserver.Storage(&mongoStorage{c: c}), nil 80 81 } 82 83 // Config holds the parameters used to connect to MongoDB. 84 type config struct { 85 server string // Required. Defaults to "localhost" in ConfigFromJSON. 86 database string // Required. 87 collection string // Required. Defaults to "blobs" in ConfigFromJSON. 88 user string // Optional, unless the server was configured with auth on. 89 password string // Optional, unless the server was configured with auth on. 90 } 91 92 func (cfg *config) url() string { 93 if cfg.user == "" || cfg.password == "" { 94 return cfg.server 95 } 96 return cfg.user + ":" + cfg.password + "@" + cfg.server + "/" + cfg.database 97 } 98 99 // ConfigFromJSON populates Config from cfg, and validates 100 // cfg. It returns an error if cfg fails to validate. 101 func configFromJSON(cfg jsonconfig.Obj) (config, error) { 102 conf := config{ 103 server: cfg.OptionalString("host", "localhost"), 104 database: cfg.RequiredString("database"), 105 collection: cfg.OptionalString("collection", "blobs"), 106 user: cfg.OptionalString("user", ""), 107 password: cfg.OptionalString("password", ""), 108 } 109 if err := cfg.Validate(); err != nil { 110 return config{}, err 111 } 112 return conf, nil 113 } 114 115 func getConnection(url string) (*mgo.Session, error) { 116 session, err := mgo.Dial(url) 117 if err != nil { 118 return nil, err 119 } 120 session.SetMode(mgo.Monotonic, true) 121 session.SetSafe(&mgo.Safe{}) // so we get an ErrNotFound error when deleting an absent key 122 return session, nil 123 }