<commit_before>package client

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/armon/mdns"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/go-ninja/logger"
)

var log = logger.GetLogger("Client")

type client struct {
}

func Start() {

	log.Infof("Starting client on Node: %s", config.Serial())
	client := &client{}

	if !client.isPaired() {
		log.Infof("Client is unpaired. Attempting to pair.")
		if err := client.pair(); err != nil {
			log.Infof("An error occurred while pairing. Restarting. error: %s", err)
			os.Exit(1)
		}

		log.Infof("Pairing was successful.")
		// We reload the config so the creds can be picked up
		config.MustRefresh()

		if !client.isPaired() {
			log.Infof("Pairing appeared successful, but we did not get the credentials. Restarting.")
			os.Exit(1)
		}
	}

	log.Infof("Client is paired. Site: %s User: %s", config.MustString("siteId"), config.MustString("userId"))

	masterId := config.String(config.Serial(), "masterNodeId")

	if masterId == config.Serial() {
		log.Infof("We are the master")
	} else {
		log.Infof("We are a slave. The master is %s", masterId)
	}

	// Make a channel for results and start listening
	entriesCh := make(chan *mdns.ServiceEntry, 4)
	go func() {
		for entry := range entriesCh {

			info := parseMdnsInfo(entry.Info)

			id, ok := info["ninja.sphere.node_id"]

			if !ok {
				log.Warningf("Found a node, but couldn't get it's node id. %v", entry)
				continue
			}

			if id == masterId {
				log.Infof("Found the master node (%s) - %s", id, entry.Addr)
			} else {

				user, ok := info["ninja.sphere.user_id"]

				if !ok {
					log.Warningf("Found a node, but couldn't get it's user id. %v", entry)
					continue
				}

				if user == config.MustString("userId") {
					log.Infof("Found a sibling node (%s) - %s", id, entry.Addr)
				} else {
					log.Infof("Found a node owned by another user (%s) (%s) - %s", user, id, entry.Addr)
				}

			}
		}
	}()

	// Start the lookup
	mdns.Lookup("_ninja-homecloud-mqtt._tcp", entriesCh)
	close(entriesCh)

}

func (c *client) isPaired() bool {
	return config.HasString("siteId") && config.HasString("token") && config.HasString("userId") && config.HasString("nodeId")
}

func (c *client) pair() error {

	localIP, err := ninja.GetNetAddress()

	if err != nil {
		log.Fatalf("Could not find local IP: %s", err)
	}

	var boardType string
	if config.HasString("boardType") {
		boardType = config.MustString("boardType")<commit_msg>Set up the bridge when we're the master, update the lights on dev kits<commit_after>package client

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/armon/mdns"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/go-ninja/logger"
)

var log = logger.GetLogger("Client")

type client struct {
	conn   *ninja.Connection
	master bool
}

type bridgeStatus struct {
	Connected  bool `json:"connected"`
	Configured bool `json:"connected"`
}

func Start() {
	log.Infof("Starting client on Node: %s", config.Serial())

	conn, err := ninja.Connect("client")
	if err != nil {
		log.Fatalf("Failed to connect to sphere: %s", err)
	}

	client := &client{conn, false}

	client.updatePairingLight("black", false)

	conn.Subscribe("$sphere/bridge/status", client.onBridgeStatus)

	client.start()
}

func (c *client) start() {

	if !c.isPaired() {
		log.Infof("Client is unpaired. Attempting to pair.")
		if err := c.pair(); err != nil {
			log.Infof("An error occurred while pairing. Restarting. error: %s", err)
			os.Exit(1)
		}

		log.Infof("Pairing was successful.")
		// We reload the config so the creds can be picked up
		config.MustRefresh()

		if !c.isPaired() {
			log.Infof("Pairing appeared successful, but we did not get the credentials. Restarting.")
			os.Exit(1)
		}
	}

	log.Infof("Client is paired. Site: %s User: %s", config.MustString("siteId"), config.MustString("userId"))

	masterID := config.String(config.Serial(), "masterNodeId")

	if masterID == config.Serial() {
		log.Infof("We are the master.")

	} else {
		log.Infof("We are a slave. The master is %s", masterID)
	}

	// Make a channel for results and start listening
	entriesCh := make(chan *mdns.ServiceEntry, 4)
	go func() {
		for entry := range entriesCh {

			info := parseMdnsInfo(entry.Info)

			id, ok := info["ninja.sphere.node_id"]

			if !ok {
				log.Warningf("Found a node, but couldn't get it's node id. %v", entry)
				continue
			}

			if id == masterID {
				log.Infof("Found the master node (%s) - %s", id, entry.Addr)
			} else {

				user, ok := info["ninja.sphere.user_id"]

				if !ok {
					log.Warningf("Found a node, but couldn't get it's user id. %v", entry)
					continue
				}

				if user == config.MustString("userId") {
					log.Infof("Found a sibling node (%s) - %s", id, entry.Addr)
				} else {
					log.Infof("Found a node owned by another user (%s) (%s) - %s", user, id, entry.Addr)
				}

			}
		}
	}()

	// Start the lookup
	mdns.Lookup("_ninja-homecloud-mqtt._tcp", entriesCh)
	close(entriesCh)

}

func (c *client) isPaired() bool {
	return config.HasString("siteId") && config.HasString("token") && config.HasString("userId") && config.HasString("nodeId")
}

func (c *client) onBridgeStatus(status *bridgeStatus) bool {
	log.Debugf("Got bridge status: %v", status)

	if status.Connected {
		c.updatePairingLight("green", false)
	} else {
		c.updatePairingLight("red", true)
	}

	if !status.Configured && c.master {
		log.Infof("Configuring bridge")

		c.conn.SendNotification("$sphere/bridge/connect", map[string]string{
			"url":   config.MustString("cloud", "url"),
			"token": config.MustString("token"),
		})
	}

	return true
}

func (c *client) updatePairingLight(color string, flash bool) {
	c.conn.SendNotification("$hardware/status/pairing", map[string]interface{}{
		"color": color,
		"flash": flash,
	})
}

func (c *client) pair() error {

	localIP, err := ninja.GetNetAddress()

	if err != nil {
		log.Fatalf("Could not find local IP: %s", err)
	}

	var boardType string
	if config.HasString("boardType") {
		boardType = config.MustString("boardType")
{'fraction_non_alphanumeric': 0.1594896331738437, 'fraction_numerical': 0.0009569377990430622, 'mean_word_length': 3.6246312684365782, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7611521', 'n_tokens_mistral': 2490, 'n_tokens_neox': 2226, 'n_words': 583}