コード例 #1
0
ファイル: proxy.go プロジェクト: nanopack/mist
func (p *Proxy) handleMessages() {

	defer func() {
		lumber.Trace("Got p.done, closing check and pipe")
		close(p.check)
		close(p.Pipe) // don't close pipe (response/pong messages need it), but leaving it unclosed leaves ram bloat on server even after client disconnects
	}()

	//
	for {
		select {

		// we need to ensure that this subscription actually has these tags before
		// sending anything to it; not doing this will cause everything to come
		// across the channel
		case msg := <-p.check:
			lumber.Trace("Got p.check")
			p.RLock()
			match := p.subscriptions.Match(msg.Tags)
			p.RUnlock()

			// if there is a subscription for the tags publish the message
			if match {
				lumber.Trace("Sending msg on pipe")
				p.Pipe <- msg
			}

		//
		case <-p.done:
			return
		}
	}
}
コード例 #2
0
ファイル: kapacitor.go プロジェクト: nanopack/pulse
// SetTask adds or updates a kapacitor task
func SetTask(task Task) error {
	var Type client.TaskType
	var Status client.TaskStatus
	DBRPs := make([]client.DBRP, 1)

	// convert type
	switch strings.ToUpper(task.Type) {
	case "BATCH":
		Type = client.BatchTask
	case "STREAM":
		Type = client.StreamTask
	default:
		return fmt.Errorf("Bad task type - '%v'", task.Type)
	}

	DBRPs[0].Database = task.Database
	DBRPs[0].RetentionPolicy = task.RetentionPolicy

	// convert status
	switch strings.ToUpper(task.Status) {
	case "DISABLED":
		Status = client.Disabled
	case "ENABLED":
		Status = client.Enabled
	case "":
		// default to disabled
		Status = client.Disabled
	default:
		return fmt.Errorf("Bad task status - '%v'", task.Status)
	}

	var err error
	l := cli.TaskLink(task.Id)
	t, _ := cli.Task(l, nil)
	if t.ID == "" {
		_, err = cli.CreateTask(client.CreateTaskOptions{
			ID:         task.Id,
			Type:       Type,
			DBRPs:      DBRPs,
			TICKscript: task.Script,
			Status:     Status,
		})
		lumber.Trace("Task Created")
	} else {
		_, err = cli.UpdateTask(
			l,
			client.UpdateTaskOptions{
				Type:       Type,
				DBRPs:      DBRPs,
				TICKscript: task.Script,
			},
		)
		lumber.Trace("Task Updated")
	}
	if err != nil {
		return fmt.Errorf("Failed to create task - %v", err)
	}

	return nil
}
コード例 #3
0
ファイル: relay.go プロジェクト: nanopack/pulse
// runLoop handles communication from the server
func (relay *Relay) runLoop(reader *bufio.Reader) {
	for {
		// when implementing relay, set `lumber.Level(lumber.LvlInt("TRACE"))` in client to view logs
		line, err := reader.ReadString('\n')
		if err != nil {
			lumber.Error("[PULSE :: RELAY] Disconnected from host %v!", relay.hostAddr)
			// retry indefinitely
			for {
				if reader, err = relay.establishConnection(); err == nil {
					lumber.Info("[PULSE :: RELAY] Reconnected to host %v!", relay.hostAddr)
					break
				}
				lumber.Debug("[PULSE :: RELAY] Reconnecting to host %v...  Fail!", relay.hostAddr)
				<-time.After(5 * time.Second)
			}
			// we won't have anything in 'line' so continue
			continue
		}

		line = strings.TrimSuffix(line, "\n")
		split := strings.SplitN(line, " ", 2)

		cmd := split[0]
		switch cmd {
		case "ok":
			lumber.Trace("[PULSE :: RELAY] OK: %v", split)
			// just an ack
		case "get":
			lumber.Trace("[PULSE :: RELAY] GET: %v", split)
			if len(split) != 2 {
				continue
			}
			stats := strings.Split(split[1], ",")
			results := make([]string, 0)
			for _, stat := range stats {
				tagCollector, ok := relay.collectors[stat]
				if !ok {
					continue
				}
				for name, value := range tagCollector.collector.Collect() {
					formatted := strconv.FormatFloat(value, 'f', 4, 64)
					if name == "" {
						name = stat
					}
					results = append(results, fmt.Sprintf("%s-%s:%s", stat, name, formatted))
				}
			}
			response := fmt.Sprintf("got %s\n", strings.Join(results, ","))
			relay.conn.Write([]byte(response))
		default:
			lumber.Trace("[PULSE :: RELAY] BAD: %v", split)
			relay.conn.Write([]byte("unknown command\n"))
		}
	}
}
コード例 #4
0
ファイル: poll.go プロジェクト: nanopack/pulse
// PollAll polls all clients for registered collectors(stats to be collected)
func PollAll() {
	lumber.Trace("[PULSE :: SERVER] PollAll...")
	for _, client := range clients {
		command := "get " + strings.Join(client.collectorList(), ",") + "\n"
		go client.conn.Write([]byte(command))
	}
}
コード例 #5
0
ファイル: mist.go プロジェクト: nanopack/mist
// subscribe adds a proxy to the list of mist subscribers; we need this so that
// we can lock this process incase multiple proxies are subscribing at the same
// time
func subscribe(p *Proxy) {
	lumber.Trace("Adding proxy to subscribers...")

	mutex.Lock()
	subscribers[p.id] = p
	mutex.Unlock()
}
コード例 #6
0
ファイル: mist.go プロジェクト: nanopack/mist
// unsubscribe removes a proxy from the list of mist subscribers; we need this
// so that we can lock this process incase multiple proxies are unsubscribing at
// the same time
func unsubscribe(pid uint32) {
	lumber.Trace("Removing proxy from subscribers...")

	mutex.Lock()
	delete(subscribers, pid)
	mutex.Unlock()
}
コード例 #7
0
ファイル: proxy.go プロジェクト: nanopack/mist
// List returns a list of all current subscriptions
func (p *Proxy) List() (data [][]string) {
	lumber.Trace("Proxy listing subscriptions...")
	p.RLock()
	data = p.subscriptions.ToSlice()
	p.RUnlock()

	return
}
コード例 #8
0
ファイル: client.go プロジェクト: hfeeki/turnpike
func (c *Client) Send() {
	for msg := range c.messages {
		log.Trace("Sending message: %s", msg)
		if err := websocket.Message.Send(c.ws, msg); err != nil {
			log.Error("Error sending message: %s", err)
		}
	}
}
コード例 #9
0
ファイル: client.go プロジェクト: hfeeki/turnpike
func (c *Client) Publish(topicURI string, event interface{}, opts ...interface{}) error {
	log.Trace("sending publish)")
	msg, err := CreatePublish(topicURI, event, opts...)
	if err != nil {
		return fmt.Errorf("turnpike: %s", err)
	}
	c.messages <- string(msg)
	return nil
}
コード例 #10
0
ファイル: client.go プロジェクト: hfeeki/turnpike
func (c *Client) Unsubscribe(topicURI string) error {
	log.Trace("sending unsubscribe")
	msg, err := CreateUnsubscribe(topicURI)
	if err != nil {
		return fmt.Errorf("turnpike: %s", err)
	}
	c.messages <- string(msg)
	return nil
}
コード例 #11
0
ファイル: client.go プロジェクト: hfeeki/turnpike
func (c *Client) Call(callID, procURI string, args ...interface{}) error {
	log.Trace("sending call")
	msg, err := CreateCall(callID, procURI, args...)
	if err != nil {
		return fmt.Errorf("turnpike: %s", err)
	}
	c.messages <- string(msg)
	return nil
}
コード例 #12
0
ファイル: influx.go プロジェクト: nanopack/pulse
func Query(sql string) (*client.Response, error) {
	lumber.Trace("[PULSE :: INFLUX] Querying influx: '%v'...", sql)

	c, err := influxClient()
	if err != nil {
		return nil, err
	}
	return c.Query(client.NewQuery(fmt.Sprint(sql), "statistics", "s"))
}
コード例 #13
0
ファイル: relay.go プロジェクト: nanopack/pulse
// AddCollector adds a collector to relay
func (relay *Relay) AddCollector(name string, tags []string, collector Collector) error {
	if name == "_connected" || strings.ContainsAny(name, "-:,") {
		lumber.Trace("[PULSE :: RELAY] Reserved name!")
		return ReservedName
	}
	if _, ok := relay.collectors[name]; ok {
		lumber.Trace("[PULSE :: RELAY] Duplicate collector!")
		return DuplicateCollector
	}
	if _, err := relay.conn.Write([]byte(fmt.Sprintf("add %s:%s\n", name, strings.Join(tags, ",")))); err != nil {
		lumber.Trace("[PULSE :: RELAY] Failed to write!")
		return err
	}

	// if successfully added collector, add it to relay's known collectors
	relay.collectors[name] = taggedCollector{collector: collector, tags: tags}
	return nil
}
コード例 #14
0
ファイル: server.go プロジェクト: hfeeki/turnpike
func (t *Server) handleUnsubscribe(id string, msg UnsubscribeMsg) {
	log.Trace("Handling unsubscribe message")
	t.subLock.Lock()
	topic := CheckCurie(t.prefixes[id], msg.TopicURI)
	if lm, ok := t.subscriptions[topic]; ok {
		lm.Remove(id)
	}
	t.subLock.Unlock()
	log.Debug("Client %s unsubscribed from topic: %s", id, topic)
}
コード例 #15
0
ファイル: poll.go プロジェクト: nanopack/pulse
// Poll polls based on tags
func Poll(tags []string) {
	lumber.Trace("[PULSE :: SERVER] Poll...")
	if tags == nil {
		PollAll()
		return
	}
	ids := findIds(tags)
	command := "get " + strings.Join(tags, ",") + "\n"
	sendAll(command, ids)
}
コード例 #16
0
ファイル: server.go プロジェクト: hfeeki/turnpike
func (t *Server) handlePrefix(id string, msg PrefixMsg) {
	log.Trace("Handling prefix message")
	if _, ok := t.prefixes[id]; !ok {
		t.prefixes[id] = make(PrefixMap)
	}
	if err := t.prefixes[id].RegisterPrefix(msg.Prefix, msg.URI); err != nil {
		log.Error("Error registering prefix: %s", err)
	}
	log.Debug("Client %s registered prefix '%s' for URI: %s", id, msg.Prefix, msg.URI)
}
コード例 #17
0
ファイル: mist.go プロジェクト: nanopack/mist
// publish publishes to all subscribers except the one who issued the publish
func publish(pid uint32, tags []string, data string) error {

	if len(tags) == 0 {
		return fmt.Errorf("Failed to publish. Missing tags")
	}

	// if there are no subscribers, the message goes nowhere
	//
	// this could be more optimized, but it might not be an issue unless thousands
	// of clients are using mist.
	go func() {
		mutex.RLock()
		for _, subscriber := range subscribers {
			select {
			case <-subscriber.done:
				lumber.Trace("Subscriber done")
				// do nothing?

			default:

				// dont send this message to the publisher who just sent it
				if subscriber.id == pid {
					lumber.Trace("Subscriber is publisher, skipping publish")
					continue
				}

				// create message
				msg := Message{Command: "publish", Tags: tags, Data: data}

				// we don't want this operation blocking the range of other subscribers
				// waiting to get messages
				go func(p *Proxy, msg Message) {
					p.check <- msg
					lumber.Trace("Published message")
				}(subscriber, msg)
			}
		}
		mutex.RUnlock()
	}()

	return nil
}
コード例 #18
0
ファイル: proxy.go プロジェクト: nanopack/mist
// Close ...
func (p *Proxy) Close() {
	lumber.Trace("Proxy closing...")

	if len(p.subscriptions.ToSlice()) != 0 {
		// remove the local p from mist's list of subscribers
		unsubscribe(p.id)
	}

	// this closes the goroutine that is matching messages to subscriptions
	close(p.done)
}
コード例 #19
0
ファイル: server.go プロジェクト: hfeeki/turnpike
func (t *Server) handleSubscribe(id string, msg SubscribeMsg) {
	log.Trace("Handling subscribe message")
	t.subLock.Lock()
	topic := CheckCurie(t.prefixes[id], msg.TopicURI)
	if _, ok := t.subscriptions[topic]; !ok {
		t.subscriptions[topic] = make(map[string]bool)
	}
	t.subscriptions[topic].Add(id)
	t.subLock.Unlock()
	log.Debug("Client %s subscribed to topic: %s", id, topic)
}
コード例 #20
0
ファイル: proxy.go プロジェクト: nanopack/mist
// Unsubscribe ...
func (p *Proxy) Unsubscribe(tags []string) {
	lumber.Trace("Proxy unsubscribing from '%v'...", tags)

	if len(tags) == 0 {
		return
	}

	// remove tags from subscription
	p.Lock()
	p.subscriptions.Remove(tags)
	p.Unlock()
}
コード例 #21
0
ファイル: client.go プロジェクト: hfeeki/turnpike
func (c *Client) Prefix(prefix, URI string) error {
	log.Trace("sending prefix")
	err := c.prefixes.RegisterPrefix(prefix, URI)
	if err != nil {
		return fmt.Errorf("turnpike: %s", err)
	}
	msg, err := CreatePrefix(prefix, URI)
	if err != nil {
		return fmt.Errorf("turnpike: %s", err)
	}
	c.messages <- string(msg)
	return nil
}
コード例 #22
0
ファイル: proxy.go プロジェクト: nanopack/mist
// Subscribe ...
func (p *Proxy) Subscribe(tags []string) {
	lumber.Trace("Proxy subscribing to '%v'...", tags)

	if len(tags) == 0 {
		return
	}

	// add proxy to subscribers list here so not all clients are 'subscribers'
	// since gets added to a map, there are no duplicates
	subscribe(p)

	// add tags to subscription
	p.Lock()
	p.subscriptions.Add(tags)
	p.Unlock()
}
コード例 #23
0
ファイル: client.go プロジェクト: hfeeki/turnpike
func (c *Client) Listen() {
	for {
		var rec string
		err := websocket.Message.Receive(c.ws, &rec)
		if err != nil {
			if err != io.EOF {
				log.Error("Error receiving message, aborting connection: %s", err)
			}
			break
		}
		log.Trace("Message received: %s", rec)

		data := []byte(rec)

		switch typ := ParseType(rec); typ {
		case CALLRESULT:
			var msg CallResultMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("Error unmarshalling call result message: %s", err)
			}
			c.handleCallResult(msg)
		case CALLERROR:
			var msg CallErrorMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("Error unmarshalling call error message: %s", err)
			}
			c.handleCallError(msg)
		case EVENT:
			var msg EventMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("Error unmarshalling event message: %s", err)
			}
			c.handleEvent(msg)
		case PREFIX, CALL, SUBSCRIBE, UNSUBSCRIBE, PUBLISH:
			log.Error("Client -> server message received, ignored: %s", TypeString(typ))
		case WELCOME:
			log.Error("Received extraneous welcome message, ignored")
		default:
			log.Error("Invalid message format, message dropped: %s", data)
		}
	}
}
コード例 #24
0
ファイル: client.go プロジェクト: hfeeki/turnpike
func (c *Client) Connect(server, origin string) error {
	log.Trace("connect")
	var err error
	if c.ws, err = websocket.Dial(server, WAMP_SUBPROTOCOL_ID, origin); err != nil {
		return fmt.Errorf("Error connecting to websocket server: %s", err)
	}

	// Receive welcome message
	if err = c.ReceiveWelcome(); err != nil {
		return err
	}
	log.Info("Connected to server: %s", server)

	go c.Listen()
	go c.Send()

	return nil
}
コード例 #25
0
ファイル: server.go プロジェクト: hfeeki/turnpike
func (t *Server) handleCall(id string, msg CallMsg) {
	log.Trace("Handling call message")
	var out string
	var err error

	if f, ok := t.rpcHooks[msg.ProcURI]; ok && f != nil {
		var res interface{}
		res, err = f(id, msg.ProcURI, msg.CallArgs...)
		if err != nil {
			var errorURI, desc string
			var details interface{}
			if er, ok := err.(RPCError); ok {
				errorURI = er.URI()
				desc = er.Description()
				details = er.Details()
			} else {
				errorURI = msg.ProcURI + "#generic-error"
				desc = err.Error()
			}

			if details != nil {
				out, err = CreateCallError(msg.CallID, errorURI, desc, details)
			} else {
				out, err = CreateCallError(msg.CallID, errorURI, desc)
			}
		} else {
			out, err = CreateCallResult(msg.CallID, res)
		}
	} else {
		log.Warn("RPC call not registered: %s", msg.ProcURI)
		out, err = CreateCallError(msg.CallID, "error:notimplemented", "RPC call '%s' not implemented", msg.ProcURI)
	}

	if err != nil {
		// whatever, let the client hang...
		log.Fatal("Error creating callError message: %s", err)
		return
	}
	if client, ok := t.clients[id]; ok {
		client <- out
	}
}
コード例 #26
0
ファイル: influx.go プロジェクト: nanopack/pulse
func Insert(messageSet plexer.MessageSet) error {
	lumber.Trace("[PULSE :: INFLUX] Insert: %+v...", messageSet)

	// create a set of points we will be inserting
	points := []*client.Point{}

	for _, message := range messageSet.Messages {
		// create a list of tags for each message
		tags := map[string]string{}

		// make sure to include the MessageSet's tags
		for _, tag := range append(messageSet.Tags, message.Tags...) {
			elems := strings.SplitN(tag, ":", 2)
			// only include tags with key:value format
			if len(elems) < 2 {
				continue
			}

			// insert the tag into my list of tags
			tags[elems[0]] = elems[1]
		}

		// if there
		value, err := strconv.ParseFloat(message.Data, 64)
		if err != nil {
			value = -1
		}

		// only one field per set of message tags.
		field := map[string]interface{}{message.ID: value}
		// create a point
		point, err := client.NewPoint(message.ID, tags, field, time.Now())
		if err != nil {
			continue
		}
		points = append(points, point)
	}
	return writePoints("statistics", "one_day", points)
}
コード例 #27
0
ファイル: client.go プロジェクト: hfeeki/turnpike
func (c *Client) ReceiveWelcome() error {
	log.Trace("Receive welcome")
	var rec string
	err := websocket.Message.Receive(c.ws, &rec)
	if err != nil {
		return fmt.Errorf("Error receiving welcome message: %s", err)
	}
	if typ := ParseType(rec); typ != WELCOME {
		return fmt.Errorf("First message received was not welcome")
	}
	var msg WelcomeMsg
	err = json.Unmarshal([]byte(rec), &msg)
	if err != nil {
		return fmt.Errorf("Error unmarshalling welcome message: %s", err)
	}
	c.SessionId = msg.SessionId
	log.Debug("Session id: %s", c.SessionId)
	c.ProtocolVersion = msg.ProtocolVersion
	log.Debug("Protocol version: %d", c.ProtocolVersion)
	c.ServerIdent = msg.ServerIdent
	log.Debug("Server ident: %s", c.ServerIdent)
	return nil
}
コード例 #28
0
ファイル: poll.go プロジェクト: nanopack/pulse
// StartPolling polls clients at preconfigured interval.
// Examples:
//  StartPolling(nil, nil, 60, nil)
//  StartPolling(nil, []string{"cpu"}, 1, ch)
//  StartPolling([]string{"computer1", "computer2"}, []string{"cpu"}, 1, ch)
func StartPolling(ids, tags []string, interval time.Duration, done chan struct{}) {
	lumber.Trace("[PULSE :: SERVER] StartPolling...")
	tick := time.Tick(interval)

	// getstat allows us to poll without waiting for the tick
	// since we can't send to receive only `tick` channel.
	getstat := func() {
		if ids == nil {
			Poll(tags)
			return
		}

		newIds := []string{}
		for _, sid := range findIds(tags) {
			for _, id := range ids {
				if id == sid {
					newIds = append(newIds, id)
				}
			}
		}
		command := "get " + strings.Join(tags, ",") + "\n"
		sendAll(command, ids)
	}

	// fetch stat immediately (dont wait `interval`)
	getstat()

	for {
		select {
		case <-tick:
			getstat()
		case <-done:
			return
		}
	}
}
コード例 #29
0
ファイル: server.go プロジェクト: nanopack/pulse
func handleConnection(conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)
	line, err := r.ReadString('\n')
	if err != nil {
		return
	}
	line = strings.TrimSuffix(line, "\n")
	split := strings.SplitN(line, " ", 2)
	if split[0] != "id" {
		conn.Write([]byte("identify first with the 'id' command\n"))
		return
	}
	if len(split) != 2 {
		conn.Write([]byte("missing id\n"))
		return
	}

	id := split[1]
	clients[id] = &client{conn: conn}
	conn.Write([]byte("ok\n"))

	// now handle commands and data
	for {
		line, err := r.ReadString('\n')
		if err != nil {
			return
		}
		line = strings.TrimSuffix(line, "\n")
		if line == "close" {
			return
		}
		split := strings.SplitN(line, " ", 2)
		if len(split) != 2 {
			continue
		}

		cmd := split[0]
		switch cmd {
		case "ok":
			lumber.Trace("[PULSE :: SERVER] OK: %v", split)
			// just an ack
		case "got":
			lumber.Trace("[PULSE :: SERVER] GOT: %v", split)
			stats := strings.Split(split[1], ",")

			metric := plexer.MessageSet{
				Tags:     []string{"metrics", "host:" + id},
				Messages: make([]plexer.Message, 0),
			}

			for _, stat := range stats {
				splitStat := strings.Split(stat, ":")
				if len(splitStat) != 2 {
					// i can only handle key value
					continue
				}

				name := splitStat[0]
				splitName := strings.Split(name, "-")
				if len(splitName) != 2 {
					// the name didnt come in as collector-name
					continue
				}
				tags := clients[id].tagList(splitName[0])
				message := plexer.Message{
					ID:   splitName[1],
					Tags: tags,
					Data: splitStat[1],
				}

				metric.Messages = append(metric.Messages, message)
			}
			publish(metric)
		case "add":
			lumber.Trace("[PULSE :: SERVER] ADD: %v", split)
			if !strings.Contains(split[1], ":") {
				clients[id].add(split[1], []string{})
				continue
			}
			split = strings.SplitN(split[1], ":", 2)
			tags := strings.Split(split[1], ",")
			if split[1] == "" {
				tags = []string{}
			}
			clients[id].add(split[0], tags)

		case "remove":
			lumber.Trace("[PULSE :: SERVER] REMOVE: %v", split)
			clients[id].remove(split[1])
			// record that the remote does not have a stat available
		case "close":
			lumber.Trace("[PULSE :: SERVER] CLOSE: %v", split)
			// clean shutoff of the connection
			delete(clients, id)
		default:
			lumber.Trace("[PULSE :: SERVER] BAD: %v", split)
			conn.Write([]byte("unknown command\n"))
		}

	}
}
コード例 #30
0
ファイル: plex.go プロジェクト: nanopack/pulse
func (plex *Plexer) RemoveObserver(name string) {
	lumber.Trace("[PULSE :: PLEXER] Remove observer: %v...", name)
	delete(plex.single, name)
}