You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
staros/hosts/hosts.go

1127 lines
23 KiB
Go

5 years ago
package hosts
import (
9 months ago
"bufio"
9 months ago
"bytes"
9 months ago
"fmt"
"io"
"net"
"os"
5 years ago
"runtime"
9 months ago
"strings"
5 years ago
"sync"
)
9 months ago
var lineBreaker string
func init() {
if runtime.GOOS == "windows" {
lineBreaker = "\r\n"
} else {
lineBreaker = "\n"
}
}
9 months ago
func SystemHostpath() string {
5 years ago
if runtime.GOOS == "windows" {
9 months ago
return `C:\Windows\System32\drivers\etc\hosts`
5 years ago
}
9 months ago
return `/etc/hosts`
5 years ago
}
9 months ago
var defaultParser = NewHosts()
func ParseHosts(hostPath string) error {
return defaultParser.Parse(hostPath)
}
func Parse() error {
return defaultParser.Parse(SystemHostpath())
}
func List() []*HostNode {
return defaultParser.List()
}
func ListHosts() map[string][]string {
return defaultParser.ListHosts()
}
func ListIPs() map[string][]string {
return defaultParser.ListIPs()
}
func ListByHost(host string) []*HostNode {
return defaultParser.ListByHost(host)
}
func ListIPsByHost(host string) []string {
return defaultParser.ListIPsByHost(host)
}
func ListFirstIPByHost(host string) string {
return defaultParser.ListFirstIPByHost(host)
}
func ListByIP(ip string) []*HostNode {
return defaultParser.ListByIP(ip)
}
func ListHostsByIP(ip string) []string {
return defaultParser.ListHostsByIP(ip)
}
func ListFirstHostByIP(ip string) string {
return defaultParser.ListFirstHostByIP(ip)
}
func AddHosts(ip string, hosts ...string) error {
return defaultParser.AddHosts(ip, hosts...)
}
func AddHostsComment(comment string, ip string, hosts ...string) error {
return defaultParser.AddHostsComment(comment, ip, hosts...)
}
func RemoveIPHosts(ip string, hosts ...string) error {
return defaultParser.RemoveIPHosts(ip, hosts...)
}
func RemoveIPs(ips ...string) error {
return defaultParser.RemoveIPs(ips...)
}
func RemoveHosts(hosts ...string) error {
return defaultParser.RemoveHosts(hosts...)
}
func SetIPHosts(ip string, hosts ...string) error {
return defaultParser.SetIPHosts(ip, hosts...)
}
func SetHostIPs(host string, ips ...string) error {
return defaultParser.SetHostIPs(host, ips...)
}
func InsertNodes(node *HostNode, before bool, comment string, ip string, hosts ...string) error {
return defaultParser.InsertNodeByData(node, before, comment, ip, hosts...)
}
func SaveAs(path string) error {
return defaultParser.SaveAs(path)
}
func Save() error {
return defaultParser.Save()
}
func Build() ([]byte, error) {
return defaultParser.Build()
}
func GetFirstNode() (*HostNode, error) {
return defaultParser.GetFirstNode()
}
func GetNode(nodeID uint64) (*HostNode, error) {
return defaultParser.GetNode(nodeID)
}
func GetNextNode(nodeID uint64) (*HostNode, error) {
return defaultParser.GetNextNode(nodeID)
}
func GetLastNode(nodeID uint64) (*HostNode, error) {
return defaultParser.GetLastNode(nodeID)
}
func GetLatestNode() (*HostNode, error) {
return defaultParser.GetLatestNode()
}
func DeleteNode(node *HostNode) error {
return defaultParser.DeleteNode(node)
}
func DeleteNodeByUID(uid uint64) error {
return defaultParser.DeleteNodeByUID(uid)
}
func AddNode(node *HostNode) error {
return defaultParser.AddNode(node)
}
func InsertNode(node *HostNode) error {
return defaultParser.InsertNode(node)
}
func UpdateNode(node *HostNode) error {
return defaultParser.UpdateNode(node)
}
9 months ago
type HostNode struct {
uid uint64
nextuid uint64
lastuid uint64
9 months ago
ip string
host []string
comment string
original string
onlyComment bool
valid bool
5 years ago
}
9 months ago
type Host struct {
idx uint64
hostPath string
9 months ago
firstUid uint64
9 months ago
lastUid uint64
fulldata map[uint64]*HostNode
hostData map[string][]*HostNode
ipData map[string][]*HostNode
sync.RWMutex
5 years ago
}
9 months ago
func NewHosts() *Host {
return &Host{
hostData: make(map[string][]*HostNode),
ipData: make(map[string][]*HostNode),
fulldata: make(map[uint64]*HostNode),
5 years ago
}
}
9 months ago
func (h *Host) Parse(hostPath string) error {
h.Lock()
defer h.Unlock()
9 months ago
h.idx = 0
h.firstUid = 0
h.lastUid = 0
9 months ago
h.hostPath = hostPath
h.fulldata = make(map[uint64]*HostNode)
h.hostData = make(map[string][]*HostNode)
h.ipData = make(map[string][]*HostNode)
return h.parse()
}
func (h *Host) parse() error {
f, err := os.OpenFile(h.hostPath, os.O_RDONLY, 0666)
if err != nil {
return fmt.Errorf("open hosts file %s error: %s", h.hostPath, err)
5 years ago
}
9 months ago
defer f.Close()
buf := bufio.NewReader(f)
for {
line, err := buf.ReadString('\n')
if err == io.EOF {
if h.idx-1 >= 0 {
h.fulldata[h.idx].nextuid = 0
h.lastUid = h.idx
}
break
}
if err != nil {
return fmt.Errorf("read hosts file error: %s", err)
}
h.idx++
line = strings.TrimSpace(line)
data, _ := h.parseLine(line)
data.uid = h.idx
data.lastuid = h.idx - 1
data.nextuid = h.idx + 1
h.fulldata[data.uid] = &data
9 months ago
if h.firstUid == 0 {
h.firstUid = h.idx
9 months ago
}
9 months ago
if data.valid {
for _, v := range data.host {
9 months ago
h.hostData[v] = append(h.hostData[v], &data)
}
9 months ago
h.ipData[data.ip] = append(h.ipData[data.ip], &data)
9 months ago
}
5 years ago
}
9 months ago
return nil
5 years ago
}
9 months ago
func (h *Host) parseLine(data string) (HostNode, error) {
var res = HostNode{
9 months ago
original: data,
9 months ago
}
if len(data) == 0 {
return res, fmt.Errorf("empty line")
5 years ago
}
9 months ago
if data[0] == '#' {
9 months ago
res.comment = data
res.onlyComment = true
res.valid = true
9 months ago
return res, nil
}
var dataArr []string
cache := ""
for k, v := range data {
if v == '#' {
if len(cache) > 0 {
dataArr = append(dataArr, cache)
cache = ""
}
dataArr = append(dataArr, data[k:])
break
}
if v == ' ' || v == '\t' {
if len(cache) > 0 {
dataArr = append(dataArr, cache)
cache = ""
}
continue
}
cache += string(v)
5 years ago
}
9 months ago
if len(cache) > 0 {
dataArr = append(dataArr, cache)
}
if len(dataArr) < 2 {
return res, fmt.Errorf("invalid line")
}
if strings.HasPrefix(dataArr[1], "#") {
return res, fmt.Errorf("invalid line")
}
if net.ParseIP(dataArr[0]) == nil {
return res, fmt.Errorf("invalid ip address")
}
for k, v := range dataArr {
switch k {
case 0:
9 months ago
res.ip = v
9 months ago
default:
if strings.HasPrefix(v, "#") {
9 months ago
res.comment = v
9 months ago
} else {
9 months ago
res.host = append(res.host, v)
9 months ago
}
}
}
9 months ago
res.valid = true
9 months ago
return res, nil
5 years ago
}
9 months ago
func (h *Host) List() []*HostNode {
h.RLock()
defer h.RUnlock()
var res []*HostNode
9 months ago
nextUid := h.firstUid
9 months ago
for {
if nextUid == 0 {
break
}
res = append(res, h.fulldata[nextUid])
nextUid = h.fulldata[nextUid].nextuid
5 years ago
}
9 months ago
return res
5 years ago
}
9 months ago
func (h *Host) ListHosts() map[string][]string {
h.RLock()
defer h.RUnlock()
if h.hostData == nil {
return nil
}
var res = make(map[string][]string)
for k, v := range h.hostData {
for _, vv := range v {
res[k] = append(res[k], vv.ip)
}
}
return res
}
func (h *Host) ListIPs() map[string][]string {
h.RLock()
defer h.RUnlock()
if h.ipData == nil {
return nil
}
var res = make(map[string][]string)
for k, v := range h.ipData {
for _, vv := range v {
res[k] = append(res[k], vv.host...)
}
}
return res
}
9 months ago
func (h *Host) ListByHost(host string) []*HostNode {
h.RLock()
defer h.RUnlock()
if h.hostData == nil {
return nil
5 years ago
}
9 months ago
return h.hostData[host]
5 years ago
}
9 months ago
func (h *Host) ListIPsByHost(host string) []string {
h.RLock()
defer h.RUnlock()
if h.hostData == nil {
return nil
}
var res []string
for _, v := range h.hostData[host] {
9 months ago
res = append(res, v.ip)
5 years ago
}
9 months ago
return res
5 years ago
}
9 months ago
func (h *Host) ListFirstIPByHost(host string) string {
h.RLock()
defer h.RUnlock()
if h.hostData == nil {
return ""
}
for _, v := range h.hostData[host] {
9 months ago
return v.ip
5 years ago
}
9 months ago
return ""
5 years ago
}
9 months ago
func (h *Host) ListByIP(ip string) []*HostNode {
h.RLock()
defer h.RUnlock()
if h.ipData == nil {
return nil
5 years ago
}
9 months ago
return h.ipData[ip]
}
func (h *Host) ListHostsByIP(ip string) []string {
h.RLock()
9 months ago
defer h.RUnlock()
9 months ago
return h.listHostsByIP(ip)
5 years ago
}
9 months ago
func (h *Host) listHostsByIP(ip string) []string {
if h.ipData == nil {
return nil
}
var res []string
for _, v := range h.ipData[ip] {
9 months ago
res = append(res, v.host...)
5 years ago
}
9 months ago
return res
5 years ago
}
9 months ago
func (h *Host) ListFirstHostByIP(ip string) string {
h.RLock()
defer h.RUnlock()
if h.ipData == nil {
return ""
5 years ago
}
9 months ago
for _, v := range h.ipData[ip] {
9 months ago
if len(v.host) > 0 {
return v.host[0]
9 months ago
}
}
return ""
5 years ago
}
9 months ago
func (h *Host) AddHosts(ip string, hosts ...string) error {
return h.addHosts("", ip, hosts...)
5 years ago
}
9 months ago
func (h *Host) AddHostsComment(comment string, ip string, hosts ...string) error {
return h.addHosts(comment, ip, hosts...)
}
func (h *Host) RemoveIPHosts(ip string, hosts ...string) error {
h.Lock()
defer h.Unlock()
if h.ipData == nil {
return fmt.Errorf("hosts data not initialized")
5 years ago
}
9 months ago
ipInfo := h.ipData[ip]
if len(ipInfo) == 0 {
return nil
}
cntfor:
for _, v := range ipInfo {
for _, host := range hosts {
9 months ago
if len(v.host) == 1 && v.host[0] == host {
9 months ago
delete(h.ipData, ip)
if v.lastuid != 0 {
h.fulldata[v.lastuid].nextuid = v.nextuid
} else {
9 months ago
h.firstUid = v.nextuid
9 months ago
}
if v.nextuid != 0 {
h.fulldata[v.nextuid].lastuid = v.lastuid
} else {
h.lastUid = v.lastuid
}
var newHostData []*HostNode
9 months ago
for _, vv := range h.hostData[v.host[0]] {
9 months ago
if vv.uid != v.uid {
newHostData = append(newHostData, vv)
}
}
h.hostData[host] = newHostData
delete(h.fulldata, v.uid)
v = nil
continue cntfor
}
9 months ago
if len(v.host) > 1 {
9 months ago
var newHosts []string
9 months ago
for _, vv := range v.host {
9 months ago
if vv != host {
newHosts = append(newHosts, vv)
}
}
9 months ago
v.host = newHosts
9 months ago
var newHostData []*HostNode
for _, vv := range h.hostData[host] {
if vv.uid != v.uid {
newHostData = append(newHostData, vv)
}
}
h.hostData[host] = newHostData
}
5 years ago
}
}
9 months ago
return nil
5 years ago
}
9 months ago
func (h *Host) RemoveIPs(ips ...string) error {
h.Lock()
defer h.Unlock()
if h.ipData == nil {
return fmt.Errorf("hosts data not initialized")
5 years ago
}
9 months ago
for _, ip := range ips {
ipInfo := h.ipData[ip]
if len(ipInfo) == 0 {
continue
}
for _, v := range ipInfo {
delete(h.ipData, ip)
delete(h.fulldata, v.uid)
if v.lastuid != 0 {
h.fulldata[v.lastuid].nextuid = v.nextuid
} else {
9 months ago
h.firstUid = v.nextuid
9 months ago
}
if v.nextuid != 0 {
h.fulldata[v.nextuid].lastuid = v.lastuid
} else {
h.lastUid = v.lastuid
}
9 months ago
for _, host := range v.host {
9 months ago
var newHostData []*HostNode
for _, vv := range h.hostData[host] {
if vv.uid != v.uid {
newHostData = append(newHostData, vv)
}
}
h.hostData[host] = newHostData
}
5 years ago
}
}
9 months ago
return nil
5 years ago
}
9 months ago
func (h *Host) RemoveHosts(hosts ...string) error {
h.Lock()
defer h.Unlock()
if h.hostData == nil {
return fmt.Errorf("hosts data not initialized")
5 years ago
}
9 months ago
for _, host := range hosts {
hostInfo := h.hostData[host]
if len(hostInfo) == 0 {
continue
}
delete(h.hostData, host)
for _, v := range hostInfo {
var newHosts []string
9 months ago
for _, vv := range v.host {
9 months ago
if vv != host {
newHosts = append(newHosts, vv)
}
}
9 months ago
v.host = newHosts
if len(v.host) == 0 {
delete(h.ipData, v.ip)
9 months ago
if v.lastuid != 0 {
h.fulldata[v.lastuid].nextuid = v.nextuid
} else {
9 months ago
h.firstUid = v.nextuid
9 months ago
}
if v.nextuid != 0 {
h.fulldata[v.nextuid].lastuid = v.lastuid
} else {
h.lastUid = v.lastuid
}
delete(h.fulldata, v.uid)
}
5 years ago
}
}
9 months ago
return nil
5 years ago
}
9 months ago
func (h *Host) SetIPHosts(ip string, hosts ...string) error {
9 months ago
info := h.ListByIP(ip)
if len(info) == 0 {
return h.AddHosts(ip, hosts...)
} else if len(info) == 1 {
info[0].host = hosts
info[0].comment = ""
return nil
}
9 months ago
err := h.RemoveIPs(ip)
if err != nil {
return err
5 years ago
}
9 months ago
return h.AddHosts(ip, hosts...)
}
9 months ago
func (h *Host) SetHostIPs(host string, ips ...string) error {
9 months ago
if len(ips) == 0 {
return fmt.Errorf("no ip address")
9 months ago
}
err := h.RemoveHosts(host)
if err != nil {
return err
}
9 months ago
for _, ip := range ips {
err := h.AddHosts(ip, host)
if err != nil {
return err
}
}
return nil
9 months ago
}
9 months ago
func (h *Host) addHosts(comment string, ip string, hosts ...string) error {
h.Lock()
defer h.Unlock()
if h.hostData == nil {
return fmt.Errorf("hosts data not initialized")
}
ipInfo := h.listHostsByIP(ip)
var needAddHosts []string
for _, v := range hosts {
if !inArray(ipInfo, v) {
needAddHosts = append(needAddHosts, v)
5 years ago
}
}
9 months ago
if len(needAddHosts) == 0 {
return nil
}
9 months ago
if comment != "" && !strings.HasPrefix(strings.TrimSpace(comment), "#") {
comment = "#" + comment
}
9 months ago
hostNode := HostNode{
uid: h.idx + 1,
nextuid: 0,
lastuid: h.lastUid,
9 months ago
ip: ip,
host: needAddHosts,
valid: true,
comment: comment,
9 months ago
}
h.idx++
h.fulldata[h.lastUid].nextuid = h.idx
h.lastUid = h.idx
h.fulldata[h.idx] = &hostNode
h.ipData[ip] = append(h.ipData[ip], &hostNode)
for _, v := range needAddHosts {
h.hostData[v] = append(h.hostData[v], &hostNode)
}
return nil
}
9 months ago
func (h *Host) InsertNodeByData(node *HostNode, before bool, comment string, ip string, hosts ...string) error {
9 months ago
h.Lock()
defer h.Unlock()
if h.hostData == nil {
return fmt.Errorf("hosts data not initialized")
}
if _, ok := h.fulldata[node.uid]; !ok {
return fmt.Errorf("node not exists")
}
9 months ago
if comment != "" && !strings.HasPrefix(strings.TrimSpace(comment), "#") {
comment = "#" + comment
}
9 months ago
hostNode := HostNode{
uid: h.idx + 1,
9 months ago
ip: ip,
host: hosts,
valid: true,
comment: comment,
9 months ago
}
if ip == "" && len(hosts) == 0 && comment != "" {
9 months ago
hostNode.onlyComment = true
9 months ago
}
if before {
hostNode.nextuid = node.uid
hostNode.lastuid = node.lastuid
if node.lastuid != 0 {
h.fulldata[node.lastuid].nextuid = h.idx
} else {
9 months ago
h.firstUid = h.idx
9 months ago
}
node.lastuid = h.idx
} else {
hostNode.lastuid = node.uid
hostNode.nextuid = node.nextuid
if node.nextuid != 0 {
h.fulldata[node.nextuid].lastuid = h.idx
} else {
h.lastUid = h.idx
}
node.nextuid = h.idx
}
return nil
}
9 months ago
func (h *Host) DeleteNode(node *HostNode) error {
h.Lock()
defer h.Unlock()
if h.hostData == nil {
return fmt.Errorf("hosts data not initialized")
}
if _, ok := h.fulldata[node.uid]; !ok {
return fmt.Errorf("node not exists")
}
if node.lastuid != 0 {
h.fulldata[node.lastuid].nextuid = node.nextuid
} else {
h.firstUid = node.nextuid
}
if node.nextuid != 0 {
h.fulldata[node.nextuid].lastuid = node.lastuid
} else {
h.lastUid = node.lastuid
}
for _, v := range node.host {
var newHostData []*HostNode
for _, vv := range h.hostData[v] {
if vv.uid != node.uid {
newHostData = append(newHostData, vv)
}
}
h.hostData[v] = newHostData
}
ipInfo := h.ipData[node.ip]
var newIPData []*HostNode
for _, v := range ipInfo {
if v.uid != node.uid {
newIPData = append(newIPData, v)
}
}
h.ipData[node.ip] = newIPData
delete(h.fulldata, node.uid)
return nil
}
func (h *Host) DeleteNodeByUID(uid uint64) error {
h.RLock()
node, ok := h.fulldata[uid]
if !ok {
h.RUnlock()
return fmt.Errorf("node not exists")
}
h.RUnlock()
return h.DeleteNode(node)
}
func (h *Host) AddNode(node *HostNode) error {
h.Lock()
defer h.Unlock()
if h.hostData == nil {
return fmt.Errorf("hosts data not initialized")
}
if node.comment != "" && !strings.HasPrefix(strings.TrimSpace(node.comment), "#") {
node.comment = "#" + node.comment
}
if node.ip == "" && len(node.host) == 0 && node.comment != "" {
node.onlyComment = true
}
h.idx++
node.uid = h.idx
node.lastuid = h.lastUid
node.nextuid = 0
h.fulldata[h.lastUid].nextuid = node.uid
h.lastUid = node.uid
h.fulldata[node.uid] = node
node.valid = node.CheckValid()
if node.valid {
h.ipData[node.ip] = append(h.ipData[node.ip], node)
for _, v := range node.host {
h.hostData[v] = append(h.hostData[v], node)
}
}
return nil
}
func (h *Host) InsertNode(node *HostNode) error {
if node.lastuid == 0 && node.nextuid == 0 {
return h.AddNode(node)
}
h.Lock()
defer h.Unlock()
if h.hostData == nil {
return fmt.Errorf("hosts data not initialized")
}
if node.comment != "" && !strings.HasPrefix(strings.TrimSpace(node.comment), "#") {
node.comment = "#" + node.comment
}
if node.ip == "" && len(node.host) == 0 && node.comment != "" {
node.onlyComment = true
}
node.uid = h.idx + 1
if h.fulldata[node.lastuid].nextuid != node.nextuid {
return fmt.Errorf("node lastuid nextuid not match")
}
h.idx++
h.fulldata[node.lastuid].nextuid = node.uid
h.fulldata[node.nextuid].lastuid = node.uid
h.fulldata[node.uid] = node
node.valid = node.CheckValid()
if node.valid {
h.ipData[node.ip] = append(h.ipData[node.ip], node)
for _, v := range node.host {
h.hostData[v] = append(h.hostData[v], node)
}
}
return nil
}
9 months ago
func inArray(arr []string, v string) bool {
for _, vv := range arr {
if v == vv {
return true
}
}
return false
5 years ago
}
9 months ago
func (h *Host) SaveAs(path string) error {
return h.save(path)
}
func (h *Host) Save() error {
return h.save(h.hostPath)
}
func (h *Host) save(path string) error {
h.Lock()
defer h.Unlock()
9 months ago
if h.firstUid == 0 || h.fulldata == nil {
return fmt.Errorf("no data")
}
9 months ago
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return fmt.Errorf("open hosts file %s error: %s", h.hostPath, err)
}
defer f.Close()
9 months ago
node := h.fulldata[h.firstUid]
if node == nil {
return fmt.Errorf("no data")
}
for {
if node.onlyComment {
if _, err := f.WriteString(node.comment + "\n"); err != nil {
9 months ago
return fmt.Errorf("write hosts file error: %s", err)
}
9 months ago
if node.nextuid == 0 {
break
}
node = h.fulldata[node.nextuid]
9 months ago
continue
}
9 months ago
if _, err := f.WriteString(node.ip + " "); err != nil {
9 months ago
return fmt.Errorf("write hosts file error: %s", err)
}
9 months ago
if _, err := f.WriteString(strings.Join(node.host, " ")); err != nil {
9 months ago
return fmt.Errorf("write hosts file error: %s", err)
}
9 months ago
if len(node.comment) > 0 {
if _, err := f.WriteString(" " + node.comment); err != nil {
9 months ago
return fmt.Errorf("write hosts file error: %s", err)
}
}
if _, err := f.WriteString(lineBreaker); err != nil {
return fmt.Errorf("write hosts file error: %s", err)
}
9 months ago
if node.nextuid == 0 {
break
}
node = h.fulldata[node.nextuid]
9 months ago
}
return nil
}
func (h *Host) Build() ([]byte, error) {
9 months ago
if h.firstUid == 0 || h.fulldata == nil {
return nil, fmt.Errorf("no data")
}
9 months ago
h.Lock()
defer h.Unlock()
var f bytes.Buffer
9 months ago
node := h.fulldata[h.firstUid]
if node == nil {
return nil, fmt.Errorf("no data")
}
for {
if node.onlyComment {
if _, err := f.WriteString(node.comment + "\n"); err != nil {
9 months ago
return nil, fmt.Errorf("write hosts file error: %s", err)
}
9 months ago
if node.nextuid == 0 {
break
}
node = h.fulldata[node.nextuid]
9 months ago
continue
}
9 months ago
if _, err := f.WriteString(node.ip + " "); err != nil {
9 months ago
return nil, fmt.Errorf("write hosts file error: %s", err)
}
9 months ago
if _, err := f.WriteString(strings.Join(node.host, " ")); err != nil {
9 months ago
return nil, fmt.Errorf("write hosts file error: %s", err)
}
9 months ago
if len(node.comment) > 0 {
if _, err := f.WriteString(" " + node.comment); err != nil {
9 months ago
return nil, fmt.Errorf("write hosts file error: %s", err)
}
}
if _, err := f.WriteString(lineBreaker); err != nil {
return nil, fmt.Errorf("write hosts file error: %s", err)
}
9 months ago
if node.nextuid == 0 {
break
}
node = h.fulldata[node.nextuid]
9 months ago
}
return f.Bytes(), nil
}
9 months ago
func (h *Host) GetFirstNode() (*HostNode, error) {
h.RLock()
defer h.RUnlock()
if h.firstUid == 0 {
return nil, fmt.Errorf("no data")
}
if h.fulldata == nil {
return nil, fmt.Errorf("no data")
}
return h.fulldata[h.firstUid], nil
}
func (h *Host) GetNode(nodeID uint64) (*HostNode, error) {
h.RLock()
defer h.RUnlock()
if h.fulldata == nil {
return nil, fmt.Errorf("no data")
}
if node, ok := h.fulldata[nodeID]; ok {
return node, nil
}
return nil, fmt.Errorf("node not exists")
}
func (h *Host) GetNextNode(nodeID uint64) (*HostNode, error) {
h.RLock()
defer h.RUnlock()
if h.fulldata == nil {
return nil, fmt.Errorf("no data")
}
if node, ok := h.fulldata[nodeID]; ok {
if node.nextuid == 0 {
return nil, fmt.Errorf("no next node")
}
return h.fulldata[node.nextuid], nil
}
return nil, fmt.Errorf("node not exists")
}
func (h *Host) GetLastNode(nodeID uint64) (*HostNode, error) {
h.RLock()
defer h.RUnlock()
if h.fulldata == nil {
return nil, fmt.Errorf("no data")
}
if node, ok := h.fulldata[nodeID]; ok {
if node.lastuid == 0 {
return nil, fmt.Errorf("no last node")
}
return h.fulldata[node.lastuid], nil
}
return nil, fmt.Errorf("node not exists")
}
func (h *Host) GetLatestNode() (*HostNode, error) {
h.RLock()
defer h.RUnlock()
if h.lastUid == 0 {
return nil, fmt.Errorf("no data")
}
if h.fulldata == nil {
return nil, fmt.Errorf("no data")
}
return h.fulldata[h.lastUid], nil
}
func (h *Host) UpdateNode(node *HostNode) error {
h.Lock()
defer h.Unlock()
if h.fulldata == nil {
return fmt.Errorf("no data")
}
if _, ok := h.fulldata[node.uid]; !ok {
return fmt.Errorf("node not exists")
}
if node.comment != "" && !strings.HasPrefix(strings.TrimSpace(node.comment), "#") {
node.comment = "#" + node.comment
}
if node.ip == "" && len(node.host) == 0 && node.comment != "" {
node.onlyComment = true
}
h.fulldata[node.uid] = node
node.valid = node.CheckValid()
for k, v := range h.ipData {
var newIPData []*HostNode
for _, vv := range v {
if vv.uid != node.uid {
newIPData = append(newIPData, vv)
}
}
h.ipData[k] = newIPData
}
for k, v := range h.hostData {
var newHostData []*HostNode
for _, vv := range v {
if vv.uid != node.uid {
newHostData = append(newHostData, vv)
}
}
h.hostData[k] = newHostData
}
if node.valid {
h.ipData[node.ip] = append(h.ipData[node.ip], node)
for _, v := range node.host {
h.hostData[v] = append(h.hostData[v], node)
}
}
return nil
}
func (n *HostNode) String() string {
if n.onlyComment {
return n.comment
}
return fmt.Sprintf("%s %s %s", n.ip, strings.Join(n.host, " "), n.comment)
}
func (n *HostNode) Bytes() []byte {
return []byte(n.String())
}
func (n *HostNode) Hosts() []string {
return n.host
}
func (n *HostNode) IP() string {
return n.ip
}
func (n *HostNode) Comment() string {
return n.comment
}
func (n *HostNode) UID() uint64 {
return n.uid
}
func (n *HostNode) NextUID() uint64 {
return n.nextuid
}
func (n *HostNode) LastUID() uint64 {
return n.lastuid
}
func (n *HostNode) Valid() bool {
return n.valid
}
func (n *HostNode) OnlyComment() bool {
return n.onlyComment
}
func (n *HostNode) Original() string {
return n.original
}
func (n *HostNode) SetHosts(hosts ...string) {
n.host = hosts
}
func (n *HostNode) SetIP(ip string) {
n.ip = ip
}
func (n *HostNode) SetComment(comment string) {
if comment == "" {
return
}
if !strings.HasPrefix(strings.TrimSpace(comment), "#") {
n.comment = "#" + comment
return
}
n.comment = comment
}
func (n *HostNode) SetValid(valid bool) {
n.valid = valid
}
func (n *HostNode) SetOnlyComment(onlyComment bool) {
n.onlyComment = onlyComment
}
func (n *HostNode) SetOriginal(original string) {
n.original = original
}
func (n *HostNode) AddHosts(hosts ...string) {
n.host = append(n.host, hosts...)
}
func (n *HostNode) SetLastUID(uid uint64) error {
if n.uid != 0 {
return fmt.Errorf("uid already set,you cannot change the existing node")
}
n.lastuid = uid
return nil
}
func (n *HostNode) SetNextUID(uid uint64) error {
if n.uid != 0 {
return fmt.Errorf("uid already set,you cannot change the existing node")
}
n.nextuid = uid
return nil
}
func (n *HostNode) CheckValid() bool {
if n.ip == "" && len(n.host) == 0 && n.comment == "" {
return true
}
if n.ip == "" && len(n.host) == 0 && n.comment != "" {
return true
}
if n.ip == "" && len(n.host) > 0 {
return false
}
if net.ParseIP(n.ip) == nil {
return false
}
return true
}