<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"time"

	"github.com/google/flatbuffers/go"
	"github.com/gorilla/websocket"
	influx "github.com/influxdata/influxdb/client/v2"
	"github.com/mohae/autofact"
	"github.com/mohae/autofact/client"
	"github.com/mohae/autofact/db"
	"github.com/mohae/autofact/message"
	"github.com/mohae/autofact/sysinfo"
)

// server is the container for a server's information and everything that it
// is tracking/serving.
type server struct {
	// ID of the server
	ID uint32
	// URL of the server
	url.URL
	// Period between pings
	PingPeriod time.Duration
	// How long to wait for a pong response before timing out
	PongWait time.Duration
	// Flatbuffers serialized default client config
	ClientCfg []byte
	// A map of clients, by ID
	Inventory inventory
	// TODO: add handling to prevent the same client from connecting
	// more than once:  this requires detection of reconnect of an
	// existing client vs an existing client maintaining multiple
	// con-current connections
	DB db.Bolt
	// InfluxDB client
	*InfluxClient
}

func newServer(id uint32) server {
	return server{
		ID:        id,
		Inventory: newInventory(),
	}
}

// LoadInventory populates the server's inventory from the database.  This
// is a cached list of clients.
func (s *server) LoadInventory() (int, error) {
	var n int
	clients, err := s.DB.Clients()
	if err != nil {
		return n, err
	}
	for i, c := range clients {
		s.Inventory.AddNodeInf(c.ID(), c)
		n = i
	}
	return n, nil
}

// connects to InfluxDB
func (s *server) connectToInfluxDB() error {
	var err error
	s.InfluxClient, err = newInfluxClient(influxDBName, influxAddress, influxUser, influxPassword)
	return err
}

// Node checks the inventory to see if the client exists.  If it exists,
// a Node is created from the client.Inf in the inventory.
func (s *server) Node(id uint32) (*Node, bool) {
	inf, ok := s.Inventory.ClientInf(id)
	if !ok {
		return nil, false
	}
	return &Node{
		Inf: inf,
		Cfg: client.GetRootAsCfg(clientCfg, 0),
	}, true
}

// NewNode creates a new Node, adds it to the server's inventory and
// returns the client.Inf to the caller.   If the save of the Node's inf to
// the database results in an error, it will be returned.
func (s *server) NewNode() (*Node, error) {
	// get a new client
	n := s.Inventory.NewNode()
	n.InfluxClient = s.InfluxClient
	// save the client info to the db
	err := s.DB.SaveClientInf(n.Inf)
	return n, err
}

// Node holds information about a client node.<commit_msg>known clients should get an InfluxDB connection on connect<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"time"

	"github.com/google/flatbuffers/go"
	"github.com/gorilla/websocket"
	influx "github.com/influxdata/influxdb/client/v2"
	"github.com/mohae/autofact"
	"github.com/mohae/autofact/client"
	"github.com/mohae/autofact/db"
	"github.com/mohae/autofact/message"
	"github.com/mohae/autofact/sysinfo"
)

// server is the container for a server's information and everything that it
// is tracking/serving.
type server struct {
	// ID of the server
	ID uint32
	// URL of the server
	url.URL
	// Period between pings
	PingPeriod time.Duration
	// How long to wait for a pong response before timing out
	PongWait time.Duration
	// Flatbuffers serialized default client config
	ClientCfg []byte
	// A map of clients, by ID
	Inventory inventory
	// TODO: add handling to prevent the same client from connecting
	// more than once:  this requires detection of reconnect of an
	// existing client vs an existing client maintaining multiple
	// con-current connections
	DB db.Bolt
	// InfluxDB client
	*InfluxClient
}

func newServer(id uint32) server {
	return server{
		ID:        id,
		Inventory: newInventory(),
	}
}

// LoadInventory populates the server's inventory from the database.  This
// is a cached list of clients.
func (s *server) LoadInventory() (int, error) {
	var n int
	clients, err := s.DB.Clients()
	if err != nil {
		return n, err
	}
	for i, c := range clients {
		s.Inventory.AddNodeInf(c.ID(), c)
		n = i
	}
	return n, nil
}

// connects to InfluxDB
func (s *server) connectToInfluxDB() error {
	var err error
	s.InfluxClient, err = newInfluxClient(influxDBName, influxAddress, influxUser, influxPassword)
	return err
}

// Node checks the inventory to see if the client exists.  If it exists,
// a Node is created from the client.Inf in the inventory.
func (s *server) Node(id uint32) (*Node, bool) {
	inf, ok := s.Inventory.ClientInf(id)
	if !ok {
		return nil, false
	}
	return &Node{
		Inf:          inf,
		Cfg:          client.GetRootAsCfg(clientCfg, 0),
		InfluxClient: s.InfluxClient,
	}, true
}

// NewNode creates a new Node, adds it to the server's inventory and
// returns the client.Inf to the caller.   If the save of the Node's inf to
// the database results in an error, it will be returned.
func (s *server) NewNode() (*Node, error) {
	// get a new client
	n := s.Inventory.NewNode()
	n.InfluxClient = s.InfluxClient
	// save the client info to the db
	err := s.DB.SaveClientInf(n.Inf)
	return n, err
}

// Node holds information about a client node.
{'fraction_non_alphanumeric': 0.10639119521143078, 'fraction_numerical': 0.0030893994979725816, 'mean_word_length': 3.450171821305842, 'pattern_counts': {'":': 0, '<': 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': '5363034', 'n_tokens_mistral': 1834, 'n_tokens_neox': 1765, 'n_words': 617}