spincycle
Version:
A reactive message router and object manager that lets clients subscribe to object property changes on the server
360 lines (334 loc) • 12 kB
text/coffeescript
Db = require('mongodb').Db
Server = require('mongodb').Server
MongoClient = require('mongodb').MongoClient
defer = require('node-promise').defer
MongoOplog = require('mongo-oplog');
debug = process.env["DEBUG"]
oplog = undefined
cursor = undefined
class MongoPersistence
if process.env['MONGODB_PORT_27017_TCP_PORT'] then madr = 'mongodb' else madr = '127.0.0.1'
mport = process.env['MONGODB_PORT_27017_TCP_PORT'] or '27017'
if debug then console.log 'mongodb adr = '+madr+', port = '+mport
watcher = undefined
constructor: (@dburl, @DB) ->
@dbs = []
connect: ()=>
q = defer()
#console.log 'Mongo connect called'
@getConnection().then () =>
if debug then console.log '-----Mongo initialized'
q.resolve(@)
return q
getConnection: () =>
#console.log 'getconnection called. db = '+@db
q = defer()
if @db
q.resolve(@db)
else
@foo(q)
return q
foo: (q) =>
#console.log 'foo called'
@cstring = 'mongodb://'+madr+':'+mport+'/spincycle'
repls = process.env['MONGODB_REPLS']
rs = process.env['MONGODB_RS']
if repls
@cstring = 'mongodb://'+repls+'/spincycle?replicaSet='+rs
if debug then console.log 'Mongo driver cstring is '+@cstring
MongoClient.connect @cstring, {fsync: true, slave_ok: true, replSet:{replicaSet: rs, connectWithNoPrimary: true}}, (err, db) =>
if err
console.log 'MONGO Error connecting to "'+@cstring+'" '+err
console.dir err
console.log 'retrying.....'
setTimeout(
()=>
@foo(q)
2000)
else
if debug then console.log("---- We are connected ---- *")
@db = db
rs=[]
rarr = repls.split ","
rarr.forEach (repl) ->
parts = repl.split ":"
rs.push {host: parts[0], port: parts[1]}
console.log 'watcher replicas ---->'
console.dir rs
q.resolve(db)
else
if debug then console.log 'Mongo driver cstring is '+@cstring
MongoClient.connect @cstring, {fsync: true, slave_ok: true}, (err, db) =>
if err
console.log 'MONGO Error connecting to "'+@cstring+'" '+err
console.dir err
console.log 'retrying.....'
setTimeout(
()=>
@foo(q)
2000)
else
if debug then console.log("---- We are connected ----")
@db = db
q.resolve(db)
getDbFor: (_type) =>
q = defer()
type = _type.toLowerCase()
db = @dbs[type]
if not db
@getConnection().then (connection) =>
#console.log 'getDbFor for '+_type+' got connection'
connection.collection(type, (err, ndb) =>
if err
console.log 'MONGO Error getting collection: '+err
console.dir err
q.resolve(null)
else
@dbs[type] = ndb
repls = process.env['MONGODB_REPLS']
if repls
#-----------------------------------------------------------------
oplog = MongoOplog('mongodb://'+repls+'/local', { ns: 'spincycle.'+type }).tail()
oplog.on 'insert', (doc) =>
console.log('insert '+type+' --> '+doc.o._id)
#console.dir doc
oplog.on 'update', (doc) =>
#console.log('mongo update '+type+' --> '+doc.o.id)
#if not doc.o.id then console.dir doc.o
@DB.onUpdated(doc.o)
#console.dir doc
oplog.on 'delete', (doc) =>
console.log('delete '+type+' --> '+doc.o._id)
#console.dir doc
#-----------------------------------------------------------------
#console.log 'getDbFor resolving db'
q.resolve(ndb)
)
else
q.resolve(db)
return q
all: (_type, query, cb)=>
if debug then console.log 'Mongo::all called for type '+_type+' query is'
if debug then console.dir query
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
if collection
if debug then console.log 'Mongo.all collection is '+collection
collection.find {}, query, (err,res) =>
res.toArray (err, items) =>
if err
console.log 'MONGO Error getting all: '+err
console.dir err
cb(null)
else
cb (items)
else
cb (null)
count: (_type)=>
if debug then console.log 'Mongo::count called for type '+_type
type = _type.toLowerCase()
q = defer()
@getDbFor(type).then (collection) =>
if collection
collection.count {},(err,count) =>
if err
console.log 'MONGO count Error: '+err
console.dir err
cb(-1)
else
q.resolve(count)
else
console.log '!!!!! Mongo.count could not get collection!!!!!!!! '+collection
cb (-1)
return q
get: (_type, id, cb) =>
type = _type.toLowerCase()
#if debug then console.log '--------------------- Mongo.get called for type '+type+' and id '+id
if typeof id == 'object'
console.log 'Mongo.get got an object as id instead of string !!!!! '
console.dir id
cb(null)
@getDbFor(type).then (collection) =>
collection.findOne {id: id}, (err, item) =>
if err
console.log 'MONGO get Error: '+err
console.dir err
cb(null)
else
#if debug then console.log '------ Mongo get found object'
#if debug then console.dir item
cb(item)
byProviderId: (_type, pid) =>
#console.log 'byProviderId called for pid '+pid+' and type '+_type
q = defer()
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
collection.findOne {providerId: pid}, (err, item) =>
if err
console.log 'MONGO byProviderId Error: '+err
console.dir err
q.resolve(null)
else
#if debug then console.log 'Mongo byProviderId for '+pid+' got back'
#if debug then console.dir item
q.resolve(item)
return q
# This is not easily implementable in couch, so now we're diverging
find: (_type, property, _value) =>
value = _value or ""
if value
value = value.toString()
#value = value.replace(/[^\w\s@.-]/gi, '')
if debug then console.log 'Mongo find called for type '+_type+' property '+property+' and value '+value
q = defer()
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
query = {}
query[property] = value
if debug then console.log 'query is '
if debug then console.dir query
collection.findOne query, (err, item) =>
if err
console.log 'MONGO find Error: '+err
console.dir err
q.resolve(null)
else
if debug then console.log 'find result is '
if debug then console.dir item
if not item or item[property] isnt value
q.resolve(null)
else
q.resolve(item)
return q
findMany: (_type, property, _value) =>
value = _value or ""
if value
value = value.toString()
value = value.replace(/[^\w\s@.-]/gi, '')
if debug then console.log 'Mongo findmany called for type '+_type+' property '+property+' and value '+value
q = defer()
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
query = {}
query[property] = value
if debug then console.log 'query is '
if debug then console.dir query
collection.find query, (err, cursor)=>
if err
console.log 'MONGO findQuery Error: '+err
console.dir err
q.resolve(null)
else
if cursor and cursor.each
cursor.each (err, el) ->
if el == null
cursor.toArray (err, items) =>
if debug then console.log 'findmany cursor returns'
if debug then console.dir items
q.resolve(items)
else
q.resolve(null)
return q
findQuery: (_type, query) =>
if debug then console.log 'Mongo findQuery called for type '+_type
if debug then console.dir query
q = defer()
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
value = query.value or ""
if value
value = value.toString()
value = value.replace(/[^\w\s@.-]/gi, '')
qu = {}
qu[query.property] = value
if query.wildcard then qu[query.property or 'name'] = new RegExp(''+value+'')
options = {}
if query.limit then options.limit = query.limit else options.limit = 10
if query.skip then options.skip = query.skip
if query.sort then options.sort = query.sort
if debug then console.log 'query is '
if debug then console.dir qu
if debug then console.log 'options are '
if debug then console.dir options
collection.find qu, options, (err, cursor) =>
if err
console.log 'MONGO findQuery Error: '+err
console.dir err
q.resolve(null)
else
cursor.each (err, el) ->
if el == null
cursor.toArray (err, items) =>
if debug then console.log 'findQuery cursor returns'
if debug then console.dir items
q.resolve(items)
return q
search: (_type, property, _value) =>
value = _value or ""
if value
value = value.toString()
value = value.replace(/[^\w\s@.]/gi, '')
console.log 'Mongo search called for type '+_type+' property '+property+' and value '+value
q = defer()
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
query = {}
query[property] = {$regex: '^'+value}
if debug then console.log 'mongo find query is'
if debug then console.dir query
collection.find query, (err, items) =>
if err
console.log 'MONGO search Error: '+err
console.dir err
q.resolve(null)
else
items.toArray (err2, docs)=>
if err2
console.log 'MONGO search toArray Error: '+err2
console.dir err2
else
q.resolve(docs)
return q
extend: (_type, id, field, def) =>
q = defer()
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
#if debug then console.log 'Mongo.extend called for type '+type+' new field '+field+' and default value '+def
collection.findOne {id: id}, (err, item) =>
if not item[field]
set = {$set:{}}
set['$set'][field] = def
collection.update { id: id }, set, { w: 1 }, (err) =>
if err
throw err
#console.log 'entry '+id+' type '+type+' updated'
@get _type,id,(o)=>
#console.dir o
o[field] = def
@set _type,o,()=> q.resolve(o)
return q
set: (_type, obj, cb)=>
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
#if debug then console.log 'Mongo.set called for type '+type+' and id '+obj.id
if typeof obj.id == 'object' then console.dir obj
collection.update {id: obj.id}, obj,{ upsert: true }, (err, result, details) =>
#if debug then console.log 'mongo set result was '+result
if err
console.log 'MONGO set Error: '+err
console.dir err
cb(null)
else
cb(result)
remove: (_type, obj, cb) =>
#console.log 'Mongo.remove called'
type = _type.toLowerCase()
@getDbFor(type).then (collection) =>
collection.remove {id: obj.id}, {w:1}, (err, numberOfRemovedDocs) =>
if err
console.log 'MONGO remove Error: '+err
console.dir err
cb(null)
else
cb(obj)
module.exports = MongoPersistence