func (t *Transformer) toMsg(incoming interface{}, msg *message.Msg) error {

	switch newMsg := incoming.(type) {
	case map[string]interface{}: // we're a proper message.Msg, so copy the data over
		msg.Op = message.OpTypeFromString(newMsg["op"].(string))
		msg.Timestamp = newMsg["ts"].(int64)
		msg.Namespace = newMsg["ns"].(string)

		switch data := newMsg["data"].(type) {
		case otto.Value:
			exported, err := data.Export()
			if err != nil {
				t.pipe.Err <- t.transformerError(ERROR, err, msg)
				return nil
			}
			d, err := mejson.Unmarshal(exported.(map[string]interface{}))
			if err != nil {
				t.pipe.Err <- t.transformerError(ERROR, err, msg)
				return nil
			}
			msg.Data = map[string]interface{}(d)
		case map[string]interface{}:
			d, err := mejson.Unmarshal(data)
			if err != nil {
				t.pipe.Err <- t.transformerError(ERROR, err, msg)
				return nil
			}
			msg.Data = map[string]interface{}(d)
		default:
			msg.Data = data
		}
	case bool: // skip this doc if we're a bool and we're false
		if !newMsg {
			msg.Op = message.Noop
			return nil
		}
	default: // something went wrong
		return fmt.Errorf("returned doc was not a map[string]interface{}")
	}

	return nil
}
Exemple #2
0
/*
 * tail the oplog
 */
func (m *Mongodb) tailData() (err error) {

	var (
		collection = m.mongoSession.DB("local").C("oplog.rs")
		result     oplogDoc // hold the document
		query      = bson.M{
			"ts": bson.M{"$gte": m.oplogTime},
		}

		iter = collection.Find(query).LogReplay().Sort("$natural").Tail(m.oplogTimeout)
	)

	for {
		for iter.Next(&result) {
			if stop := m.pipe.Stopped; stop {
				return
			}
			if result.validOp() {
				_, coll, _ := m.splitNamespace(result.Ns)

				if strings.HasPrefix(coll, "system.") {
					continue
				} else if match := m.collectionMatch.MatchString(coll); !match {
					continue
				}

				var doc bson.M
				switch result.Op {
				case "i":
					doc = result.O
				case "d":
					doc = result.O
				case "u":
					doc, err = m.getOriginalDoc(result.O2, coll)
					if err != nil { // errors aren't fatal here, but we need to send it down the pipe
						m.pipe.Err <- NewError(ERROR, m.path, fmt.Sprintf("Mongodb error (%s)", err.Error()), nil)
						continue
					}
				default:
					m.pipe.Err <- NewError(ERROR, m.path, "Mongodb error (unknown op type)", nil)
					continue
				}

				msg := message.NewMsg(message.OpTypeFromString(result.Op), doc, m.computeNamespace(coll))
				msg.Timestamp = int64(result.Ts) >> 32

				m.oplogTime = result.Ts
				m.pipe.Send(msg)
			}
			result = oplogDoc{}
		}

		// we've exited the mongo read loop, lets figure out why
		// check here again if we've been asked to quit
		if stop := m.pipe.Stopped; stop {
			return
		}
		if iter.Timeout() {
			continue
		}
		if iter.Err() != nil {
			return NewError(CRITICAL, m.path, fmt.Sprintf("Mongodb error (error reading collection %s)", iter.Err()), nil)
		}

		// query will change,
		query = bson.M{
			"ts": bson.M{"$gte": m.oplogTime},
		}
		iter = collection.Find(query).LogReplay().Tail(m.oplogTimeout)
	}
}