<commit_before>package artnet

import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"

	"github.com/jsimonetti/go-artnet/packet"
	"github.com/jsimonetti/go-artnet/packet/code"
)

// Node is the information known about a node
type Node struct {
	// Config holds the configuration of this node
	Config NodeConfig

	// conn is the UDP connection this node will listen on
	conn   *net.UDPConn
	sendCh chan netPayload
	recvCh chan netPayload

	// shutdownCh will be closed on shutdown of the node
	shutdownCh   chan struct{}
	shutdown     bool
	shutdownErr  error
	shutdownLock sync.Mutex

	// pollCh will receive ArtPoll packets
	pollCh chan packet.ArtPollPacket
	// pollCh will send ArtPollReply packets
	pollReplyCh chan packet.ArtPollReplyPacket

	log Logger
}

// netPayload contains bytes read from the network and/or an error
type netPayload struct {
	address net.UDPAddr
	err     error
	data    []byte
}

// NewNode return a Node
func NewNode(name string, style code.StyleCode, ip net.IP) *Node {
	n := &Node{
		Config: NodeConfig{
			Name: name,
			Type: style,
		},
		conn:     nil,
		shutdown: true,
		log:      NewLogger(),
	}
	if len(ip) > 0 {
		n.Config.IP = ip
	}
	//n.Config.IP = GenerateIP()
	return n
}

// Stop will stop all running routines and close the network connection
func (n *Node) Stop() {
	n.shutdownLock.Lock()
	n.shutdown = true
	n.shutdownLock.Unlock()
	close(n.shutdownCh)
	if n.conn != nil {
		n.conn.Close()
		n.conn = nil
	}
}

// Start will start the controller
func (n *Node) Start() {
	n.sendCh = make(chan netPayload, 10)
	n.recvCh = make(chan netPayload, 10)
	n.pollCh = make(chan packet.ArtPollPacket, 10)
	n.pollReplyCh = make(chan packet.ArtPollReplyPacket, 10)
	n.shutdownCh = make(chan struct{})
	n.shutdown = false

	src := fmt.Sprintf("%s:%d", n.Config.IP, packet.ArtNetPort)
	localBroadcastAddr, _ := net.ResolveUDPAddr("udp", src)

	var err error
	n.conn, err = net.ListenUDP("udp", localBroadcastAddr)
	if err != nil {
		n.shutdownErr = fmt.Errorf("error net.ListenUDP: %s", err)
	}

	go n.recvLoop()
	go n.sendLoop()
}

// pollReplyLoop loops to reply to ArtPoll packets
// when a controller asks for continuous updates, we do that using a ticker
func (n *Node) pollReplyLoop() {
	var timer time.Ticker

	// loop untill shutdown
	for {
		select {
		case <-timer.C:
			// if we should regularly send replies (can be requested by the controller)
			// we send it here

		case poll := <-n.pollCh:
			// reply with pollReply
			n.log.With(Fields{"poll": poll}).Printf("poll received, now send a reply")

			// if we are asked to send changes regularyl, set the Ticker here

		case <-n.shutdownCh:
			return
		}
	}
}

// sendLoop is used to send packets to the network
func (n *Node) sendLoop() {
	// loop untill shutdown
	for {
		select {
		case payload := <-n.sendCh:
			n.shutdownLock.Lock()
			if !n.shutdown {
				num, err := n.conn.WriteTo(payload.data, &payload.address)
				if err != nil {
					n.log.With(Fields{"error": err}).Printf("error writing packet")
					continue
				}
				n.log.With(Fields{"dst": payload.address.String(), "bytes": num}).Printf("packet sent")
			}
			n.shutdownLock.Unlock()
		case <-n.shutdownCh:
			return
		}
	}
}

func AddrToUDPAddr(addr net.Addr) net.UDPAddr {
	udp, _ := net.ResolveUDPAddr(addr.Network(), addr.String())
	return *udp<commit_msg>Add comments<commit_after>package artnet

import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"

	"github.com/jsimonetti/go-artnet/packet"
	"github.com/jsimonetti/go-artnet/packet/code"
)

// Node is the information known about a node
type Node struct {
	// Config holds the configuration of this node
	Config NodeConfig

	// conn is the UDP connection this node will listen on
	conn   *net.UDPConn
	sendCh chan netPayload
	recvCh chan netPayload

	// shutdownCh will be closed on shutdown of the node
	shutdownCh   chan struct{}
	shutdown     bool
	shutdownErr  error
	shutdownLock sync.Mutex

	// pollCh will receive ArtPoll packets
	pollCh chan packet.ArtPollPacket
	// pollCh will send ArtPollReply packets
	pollReplyCh chan packet.ArtPollReplyPacket

	log Logger
}

// netPayload contains bytes read from the network and/or an error
type netPayload struct {
	address net.UDPAddr
	err     error
	data    []byte
}

// NewNode return a Node
func NewNode(name string, style code.StyleCode, ip net.IP) *Node {
	n := &Node{
		Config: NodeConfig{
			Name: name,
			Type: style,
		},
		conn:     nil,
		shutdown: true,
		log:      NewLogger(),
	}
	if len(ip) > 0 {
		n.Config.IP = ip
	}
	//n.Config.IP = GenerateIP()
	return n
}

// Stop will stop all running routines and close the network connection
func (n *Node) Stop() {
	n.shutdownLock.Lock()
	n.shutdown = true
	n.shutdownLock.Unlock()
	close(n.shutdownCh)
	if n.conn != nil {
		n.conn.Close()
		n.conn = nil
	}
}

// Start will start the controller
func (n *Node) Start() {
	n.sendCh = make(chan netPayload, 10)
	n.recvCh = make(chan netPayload, 10)
	n.pollCh = make(chan packet.ArtPollPacket, 10)
	n.pollReplyCh = make(chan packet.ArtPollReplyPacket, 10)
	n.shutdownCh = make(chan struct{})
	n.shutdown = false

	src := fmt.Sprintf("%s:%d", n.Config.IP, packet.ArtNetPort)
	localBroadcastAddr, _ := net.ResolveUDPAddr("udp", src)

	var err error
	n.conn, err = net.ListenUDP("udp", localBroadcastAddr)
	if err != nil {
		n.shutdownErr = fmt.Errorf("error net.ListenUDP: %s", err)
	}

	go n.recvLoop()
	go n.sendLoop()
}

// pollReplyLoop loops to reply to ArtPoll packets
// when a controller asks for continuous updates, we do that using a ticker
func (n *Node) pollReplyLoop() {
	var timer time.Ticker

	// loop untill shutdown
	for {
		select {
		case <-timer.C:
			// if we should regularly send replies (can be requested by the controller)
			// we send it here

		case poll := <-n.pollCh:
			// reply with pollReply
			n.log.With(Fields{"poll": poll}).Printf("poll received, now send a reply")

			// if we are asked to send changes regularyl, set the Ticker here

		case <-n.shutdownCh:
			return
		}
	}
}

// sendLoop is used to send packets to the network
func (n *Node) sendLoop() {
	// loop untill shutdown
	for {
		select {
		case payload := <-n.sendCh:
			n.shutdownLock.Lock()
			if !n.shutdown {
				num, err := n.conn.WriteTo(payload.data, &payload.address)
				if err != nil {
					n.log.With(Fields{"error": err}).Printf("error writing packet")
					continue
				}
				n.log.With(Fields{"dst": payload.address.String(), "bytes": num}).Printf("packet sent")
			}
			n.shutdownLock.Unlock()
		case <-n.shutdownCh:
			return
		}
	}
}

// AddrToUDPAddr will turn a net.Addr into a net.UDPAddr
func AddrToUDPAddr(addr net.Addr) net.UDPAddr {
	udp, _ := net.ResolveUDPAddr(addr.Network(), addr.String())
	return *udp
{'fraction_non_alphanumeric': 0.11951000896325067, 'fraction_numerical': 0.00268897520167314, 'mean_word_length': 3.311010946555055, 'pattern_counts': {'":': 8, '<': 13, '<?xml version=': 0, '>': 5, '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': '1898613', 'n_tokens_mistral': 2531, 'n_tokens_neox': 2336, 'n_words': 712}