Merge branch 'master' of git.b612.me:b612/staros

master v1.1.8
兔子 4 months ago
commit 0b6373e9e3

@ -28,21 +28,151 @@ func SystemHostpath() string {
return `/etc/hosts` return `/etc/hosts`
} }
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)
}
type HostNode struct { type HostNode struct {
uid uint64 uid uint64
nextuid uint64 nextuid uint64
lastuid uint64 lastuid uint64
IP string ip string
Host []string host []string
Comment string comment string
Original string original string
OnlyComment bool onlyComment bool
Valid bool valid bool
} }
type Host struct { type Host struct {
idx uint64 idx uint64
hostPath string hostPath string
nextUid uint64 firstUid uint64
lastUid uint64 lastUid uint64
fulldata map[uint64]*HostNode fulldata map[uint64]*HostNode
hostData map[string][]*HostNode hostData map[string][]*HostNode
@ -61,6 +191,9 @@ func NewHosts() *Host {
func (h *Host) Parse(hostPath string) error { func (h *Host) Parse(hostPath string) error {
h.Lock() h.Lock()
defer h.Unlock() defer h.Unlock()
h.idx = 0
h.firstUid = 0
h.lastUid = 0
h.hostPath = hostPath h.hostPath = hostPath
h.fulldata = make(map[uint64]*HostNode) h.fulldata = make(map[uint64]*HostNode)
h.hostData = make(map[string][]*HostNode) h.hostData = make(map[string][]*HostNode)
@ -94,14 +227,14 @@ func (h *Host) parse() error {
data.lastuid = h.idx - 1 data.lastuid = h.idx - 1
data.nextuid = h.idx + 1 data.nextuid = h.idx + 1
h.fulldata[data.uid] = &data h.fulldata[data.uid] = &data
if h.nextUid == 0 { if h.firstUid == 0 {
h.nextUid = h.idx h.firstUid = h.idx
} }
if data.Valid { if data.valid {
for _, v := range data.Host { for _, v := range data.host {
h.hostData[v] = append(h.hostData[v], &data) h.hostData[v] = append(h.hostData[v], &data)
} }
h.ipData[data.IP] = append(h.ipData[data.IP], &data) h.ipData[data.ip] = append(h.ipData[data.ip], &data)
} }
} }
@ -110,14 +243,15 @@ func (h *Host) parse() error {
func (h *Host) parseLine(data string) (HostNode, error) { func (h *Host) parseLine(data string) (HostNode, error) {
var res = HostNode{ var res = HostNode{
Original: data, original: data,
} }
if len(data) == 0 { if len(data) == 0 {
return res, fmt.Errorf("empty line") return res, fmt.Errorf("empty line")
} }
if data[0] == '#' { if data[0] == '#' {
res.Comment = data res.comment = data
res.OnlyComment = true res.onlyComment = true
res.valid = true
return res, nil return res, nil
} }
var dataArr []string var dataArr []string
@ -155,16 +289,16 @@ func (h *Host) parseLine(data string) (HostNode, error) {
for k, v := range dataArr { for k, v := range dataArr {
switch k { switch k {
case 0: case 0:
res.IP = v res.ip = v
default: default:
if strings.HasPrefix(v, "#") { if strings.HasPrefix(v, "#") {
res.Comment = v res.comment = v
} else { } else {
res.Host = append(res.Host, v) res.host = append(res.host, v)
} }
} }
} }
res.Valid = true res.valid = true
return res, nil return res, nil
} }
@ -172,7 +306,7 @@ func (h *Host) List() []*HostNode {
h.RLock() h.RLock()
defer h.RUnlock() defer h.RUnlock()
var res []*HostNode var res []*HostNode
nextUid := h.nextUid nextUid := h.firstUid
for { for {
if nextUid == 0 { if nextUid == 0 {
break break
@ -183,6 +317,36 @@ func (h *Host) List() []*HostNode {
return res return res
} }
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
}
func (h *Host) ListByHost(host string) []*HostNode { func (h *Host) ListByHost(host string) []*HostNode {
h.RLock() h.RLock()
defer h.RUnlock() defer h.RUnlock()
@ -200,7 +364,7 @@ func (h *Host) ListIPsByHost(host string) []string {
} }
var res []string var res []string
for _, v := range h.hostData[host] { for _, v := range h.hostData[host] {
res = append(res, v.IP) res = append(res, v.ip)
} }
return res return res
} }
@ -212,7 +376,7 @@ func (h *Host) ListFirstIPByHost(host string) string {
return "" return ""
} }
for _, v := range h.hostData[host] { for _, v := range h.hostData[host] {
return v.IP return v.ip
} }
return "" return ""
} }
@ -228,6 +392,7 @@ func (h *Host) ListByIP(ip string) []*HostNode {
func (h *Host) ListHostsByIP(ip string) []string { func (h *Host) ListHostsByIP(ip string) []string {
h.RLock() h.RLock()
defer h.RUnlock()
return h.listHostsByIP(ip) return h.listHostsByIP(ip)
} }
@ -237,7 +402,7 @@ func (h *Host) listHostsByIP(ip string) []string {
} }
var res []string var res []string
for _, v := range h.ipData[ip] { for _, v := range h.ipData[ip] {
res = append(res, v.Host...) res = append(res, v.host...)
} }
return res return res
} }
@ -249,8 +414,8 @@ func (h *Host) ListFirstHostByIP(ip string) string {
return "" return ""
} }
for _, v := range h.ipData[ip] { for _, v := range h.ipData[ip] {
if len(v.Host) > 0 { if len(v.host) > 0 {
return v.Host[0] return v.host[0]
} }
} }
return "" return ""
@ -277,12 +442,12 @@ func (h *Host) RemoveIPHosts(ip string, hosts ...string) error {
cntfor: cntfor:
for _, v := range ipInfo { for _, v := range ipInfo {
for _, host := range hosts { for _, host := range hosts {
if len(v.Host) == 1 && v.Host[0] == host { if len(v.host) == 1 && v.host[0] == host {
delete(h.ipData, ip) delete(h.ipData, ip)
if v.lastuid != 0 { if v.lastuid != 0 {
h.fulldata[v.lastuid].nextuid = v.nextuid h.fulldata[v.lastuid].nextuid = v.nextuid
} else { } else {
h.nextUid = v.nextuid h.firstUid = v.nextuid
} }
if v.nextuid != 0 { if v.nextuid != 0 {
h.fulldata[v.nextuid].lastuid = v.lastuid h.fulldata[v.nextuid].lastuid = v.lastuid
@ -290,7 +455,7 @@ cntfor:
h.lastUid = v.lastuid h.lastUid = v.lastuid
} }
var newHostData []*HostNode var newHostData []*HostNode
for _, vv := range h.hostData[v.Host[0]] { for _, vv := range h.hostData[v.host[0]] {
if vv.uid != v.uid { if vv.uid != v.uid {
newHostData = append(newHostData, vv) newHostData = append(newHostData, vv)
} }
@ -300,14 +465,14 @@ cntfor:
v = nil v = nil
continue cntfor continue cntfor
} }
if len(v.Host) > 1 { if len(v.host) > 1 {
var newHosts []string var newHosts []string
for _, vv := range v.Host { for _, vv := range v.host {
if vv != host { if vv != host {
newHosts = append(newHosts, vv) newHosts = append(newHosts, vv)
} }
} }
v.Host = newHosts v.host = newHosts
var newHostData []*HostNode var newHostData []*HostNode
for _, vv := range h.hostData[host] { for _, vv := range h.hostData[host] {
if vv.uid != v.uid { if vv.uid != v.uid {
@ -338,14 +503,14 @@ func (h *Host) RemoveIPs(ips ...string) error {
if v.lastuid != 0 { if v.lastuid != 0 {
h.fulldata[v.lastuid].nextuid = v.nextuid h.fulldata[v.lastuid].nextuid = v.nextuid
} else { } else {
h.nextUid = v.nextuid h.firstUid = v.nextuid
} }
if v.nextuid != 0 { if v.nextuid != 0 {
h.fulldata[v.nextuid].lastuid = v.lastuid h.fulldata[v.nextuid].lastuid = v.lastuid
} else { } else {
h.lastUid = v.lastuid h.lastUid = v.lastuid
} }
for _, host := range v.Host { for _, host := range v.host {
var newHostData []*HostNode var newHostData []*HostNode
for _, vv := range h.hostData[host] { for _, vv := range h.hostData[host] {
if vv.uid != v.uid { if vv.uid != v.uid {
@ -373,18 +538,18 @@ func (h *Host) RemoveHosts(hosts ...string) error {
delete(h.hostData, host) delete(h.hostData, host)
for _, v := range hostInfo { for _, v := range hostInfo {
var newHosts []string var newHosts []string
for _, vv := range v.Host { for _, vv := range v.host {
if vv != host { if vv != host {
newHosts = append(newHosts, vv) newHosts = append(newHosts, vv)
} }
} }
v.Host = newHosts v.host = newHosts
if len(v.Host) == 0 { if len(v.host) == 0 {
delete(h.ipData, v.IP) delete(h.ipData, v.ip)
if v.lastuid != 0 { if v.lastuid != 0 {
h.fulldata[v.lastuid].nextuid = v.nextuid h.fulldata[v.lastuid].nextuid = v.nextuid
} else { } else {
h.nextUid = v.nextuid h.firstUid = v.nextuid
} }
if v.nextuid != 0 { if v.nextuid != 0 {
h.fulldata[v.nextuid].lastuid = v.lastuid h.fulldata[v.nextuid].lastuid = v.lastuid
@ -399,6 +564,14 @@ func (h *Host) RemoveHosts(hosts ...string) error {
} }
func (h *Host) SetIPHosts(ip string, hosts ...string) error { func (h *Host) SetIPHosts(ip string, hosts ...string) error {
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
}
err := h.RemoveIPs(ip) err := h.RemoveIPs(ip)
if err != nil { if err != nil {
return err return err
@ -406,6 +579,23 @@ func (h *Host) SetIPHosts(ip string, hosts ...string) error {
return h.AddHosts(ip, hosts...) return h.AddHosts(ip, hosts...)
} }
func (h *Host) SetHostIPs(host string, ips ...string) error {
if len(ips) == 0 {
return fmt.Errorf("no ip address")
}
err := h.RemoveHosts(host)
if err != nil {
return err
}
for _, ip := range ips {
err := h.AddHosts(ip, host)
if err != nil {
return err
}
}
return nil
}
func (h *Host) addHosts(comment string, ip string, hosts ...string) error { func (h *Host) addHosts(comment string, ip string, hosts ...string) error {
h.Lock() h.Lock()
defer h.Unlock() defer h.Unlock()
@ -422,14 +612,17 @@ func (h *Host) addHosts(comment string, ip string, hosts ...string) error {
if len(needAddHosts) == 0 { if len(needAddHosts) == 0 {
return nil return nil
} }
if comment != "" && !strings.HasPrefix(strings.TrimSpace(comment), "#") {
comment = "#" + comment
}
hostNode := HostNode{ hostNode := HostNode{
uid: h.idx + 1, uid: h.idx + 1,
nextuid: 0, nextuid: 0,
lastuid: h.lastUid, lastuid: h.lastUid,
IP: ip, ip: ip,
Host: needAddHosts, host: needAddHosts,
Valid: true, valid: true,
Comment: comment, comment: comment,
} }
h.idx++ h.idx++
h.fulldata[h.lastUid].nextuid = h.idx h.fulldata[h.lastUid].nextuid = h.idx
@ -442,7 +635,7 @@ func (h *Host) addHosts(comment string, ip string, hosts ...string) error {
return nil return nil
} }
func (h *Host) InsertNodes(node *HostNode, before bool, comment string, ip string, hosts ...string) error { func (h *Host) InsertNodeByData(node *HostNode, before bool, comment string, ip string, hosts ...string) error {
h.Lock() h.Lock()
defer h.Unlock() defer h.Unlock()
if h.hostData == nil { if h.hostData == nil {
@ -451,15 +644,18 @@ func (h *Host) InsertNodes(node *HostNode, before bool, comment string, ip strin
if _, ok := h.fulldata[node.uid]; !ok { if _, ok := h.fulldata[node.uid]; !ok {
return fmt.Errorf("node not exists") return fmt.Errorf("node not exists")
} }
if comment != "" && !strings.HasPrefix(strings.TrimSpace(comment), "#") {
comment = "#" + comment
}
hostNode := HostNode{ hostNode := HostNode{
uid: h.idx + 1, uid: h.idx + 1,
IP: ip, ip: ip,
Host: hosts, host: hosts,
Valid: true, valid: true,
Comment: comment, comment: comment,
} }
if ip == "" && len(hosts) == 0 && comment != "" { if ip == "" && len(hosts) == 0 && comment != "" {
hostNode.OnlyComment = true hostNode.onlyComment = true
} }
if before { if before {
hostNode.nextuid = node.uid hostNode.nextuid = node.uid
@ -467,7 +663,7 @@ func (h *Host) InsertNodes(node *HostNode, before bool, comment string, ip strin
if node.lastuid != 0 { if node.lastuid != 0 {
h.fulldata[node.lastuid].nextuid = h.idx h.fulldata[node.lastuid].nextuid = h.idx
} else { } else {
h.nextUid = h.idx h.firstUid = h.idx
} }
node.lastuid = h.idx node.lastuid = h.idx
} else { } else {
@ -483,6 +679,119 @@ func (h *Host) InsertNodes(node *HostNode, before bool, comment string, ip strin
return nil return nil
} }
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
}
func inArray(arr []string, v string) bool { func inArray(arr []string, v string) bool {
for _, vv := range arr { for _, vv := range arr {
if v == vv { if v == vv {
@ -493,75 +802,325 @@ func inArray(arr []string, v string) bool {
} }
func (h *Host) SaveAs(path string) error { func (h *Host) SaveAs(path string) error {
h.Lock()
defer h.Unlock()
return h.save(path) return h.save(path)
} }
func (h *Host) Save() error { func (h *Host) Save() error {
h.Lock()
defer h.Unlock()
return h.save(h.hostPath) return h.save(h.hostPath)
} }
func (h *Host) save(path string) error { func (h *Host) save(path string) error {
h.Lock() h.Lock()
defer h.Unlock() defer h.Unlock()
if h.firstUid == 0 || h.fulldata == nil {
return fmt.Errorf("no data")
}
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil { if err != nil {
return fmt.Errorf("open hosts file %s error: %s", h.hostPath, err) return fmt.Errorf("open hosts file %s error: %s", h.hostPath, err)
} }
defer f.Close() defer f.Close()
for _, v := range h.fulldata { node := h.fulldata[h.firstUid]
if v.OnlyComment { if node == nil {
if _, err := f.WriteString(v.Comment + "\n"); err != nil { return fmt.Errorf("no data")
}
for {
if node.onlyComment {
if _, err := f.WriteString(node.comment + "\n"); err != nil {
return fmt.Errorf("write hosts file error: %s", err) return fmt.Errorf("write hosts file error: %s", err)
} }
if node.nextuid == 0 {
break
}
node = h.fulldata[node.nextuid]
continue continue
} }
if _, err := f.WriteString(v.IP + " "); err != nil { if _, err := f.WriteString(node.ip + " "); err != nil {
return fmt.Errorf("write hosts file error: %s", err) return fmt.Errorf("write hosts file error: %s", err)
} }
if _, err := f.WriteString(strings.Join(v.Host, " ")); err != nil { if _, err := f.WriteString(strings.Join(node.host, " ")); err != nil {
return fmt.Errorf("write hosts file error: %s", err) return fmt.Errorf("write hosts file error: %s", err)
} }
if len(v.Comment) > 0 { if len(node.comment) > 0 {
if _, err := f.WriteString(" " + v.Comment); err != nil { if _, err := f.WriteString(" " + node.comment); err != nil {
return fmt.Errorf("write hosts file error: %s", err) return fmt.Errorf("write hosts file error: %s", err)
} }
} }
if _, err := f.WriteString(lineBreaker); err != nil { if _, err := f.WriteString(lineBreaker); err != nil {
return fmt.Errorf("write hosts file error: %s", err) return fmt.Errorf("write hosts file error: %s", err)
} }
if node.nextuid == 0 {
break
}
node = h.fulldata[node.nextuid]
} }
return nil return nil
} }
func (h *Host) Build() ([]byte, error) { func (h *Host) Build() ([]byte, error) {
if h.firstUid == 0 || h.fulldata == nil {
return nil, fmt.Errorf("no data")
}
h.Lock() h.Lock()
defer h.Unlock() defer h.Unlock()
var f bytes.Buffer var f bytes.Buffer
for _, v := range h.fulldata { node := h.fulldata[h.firstUid]
if v.OnlyComment { if node == nil {
if _, err := f.WriteString(v.Comment + "\n"); err != nil { return nil, fmt.Errorf("no data")
}
for {
if node.onlyComment {
if _, err := f.WriteString(node.comment + "\n"); err != nil {
return nil, fmt.Errorf("write hosts file error: %s", err) return nil, fmt.Errorf("write hosts file error: %s", err)
} }
if node.nextuid == 0 {
break
}
node = h.fulldata[node.nextuid]
continue continue
} }
if _, err := f.WriteString(v.IP + " "); err != nil { if _, err := f.WriteString(node.ip + " "); err != nil {
return nil, fmt.Errorf("write hosts file error: %s", err) return nil, fmt.Errorf("write hosts file error: %s", err)
} }
if _, err := f.WriteString(strings.Join(v.Host, " ")); err != nil { if _, err := f.WriteString(strings.Join(node.host, " ")); err != nil {
return nil, fmt.Errorf("write hosts file error: %s", err) return nil, fmt.Errorf("write hosts file error: %s", err)
} }
if len(v.Comment) > 0 { if len(node.comment) > 0 {
if _, err := f.WriteString(" " + v.Comment); err != nil { if _, err := f.WriteString(" " + node.comment); err != nil {
return nil, fmt.Errorf("write hosts file error: %s", err) return nil, fmt.Errorf("write hosts file error: %s", err)
} }
} }
if _, err := f.WriteString(lineBreaker); err != nil { if _, err := f.WriteString(lineBreaker); err != nil {
return nil, fmt.Errorf("write hosts file error: %s", err) return nil, fmt.Errorf("write hosts file error: %s", err)
} }
if node.nextuid == 0 {
break
}
node = h.fulldata[node.nextuid]
} }
return f.Bytes(), nil return f.Bytes(), nil
} }
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
}

@ -11,27 +11,144 @@ func Test_Hosts(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
for _, v := range h.List() { next := h.firstUid
fmt.Printf("%+v\n", v) for next != 0 {
node, _ := h.GetNode(next)
fmt.Printf("Last %d, Next: %d, IP: %s, Hosts: %s, Comment: %s\n", node.LastUID(), node.NextUID(), node.IP(), node.Hosts(), node.Comment())
next = node.NextUID()
} }
fmt.Println(h.nextUid, h.lastUid) data := h.ListHostsByIP("11.22.33.44")
fmt.Println("") if len(data) != 2 {
err = h.AddHosts("122.23.12.123", "b612.me", "ok.b612.me") t.Error("Expected 2, got ", len(data))
} else {
t.Log(data)
}
data = h.ListIPsByHost("dns.b612.me")
if len(data) < 1 || data[0] != "4.5.6.7" {
t.Error("Expected 4.5.6.7, got ", data)
} else {
t.Log(data)
}
err = h.RemoveHosts("dns.b612.me")
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("dns.b612.me")
if len(data) > 0 {
t.Error("Expected 0, got ", len(data))
} else {
t.Log(data)
}
err = h.RemoveHosts("test.dns.set.b612.me")
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("remove.b612.me")
if len(data) < 1 || data[0] != "11.22.33.44" {
t.Error("Expected 11.22.33.44, got ", data)
} else {
t.Log(data)
}
nodes := h.ListByIP("11.22.33.44")
if nodes == nil {
t.Error("Expected not nil, got ", nodes)
} else {
t.Log(nodes)
}
nodes[0].AddHosts("hello.b612.me")
err = h.UpdateNode(nodes[0])
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("hello.b612.me")
if len(data) < 1 || data[0] != "11.22.33.44" {
t.Error("Not Expected Data", data)
} else {
t.Log(data)
}
insertNode := new(HostNode)
insertNode.SetIP("11.11.11.11")
insertNode.SetHosts("insert.b612.me")
insertNode.SetComment("Insert Node")
insertNode.SetNextUID(nodes[0].UID())
insertNode.SetLastUID(nodes[0].LastUID())
err = h.InsertNode(insertNode)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
for _, v := range h.List() { data = h.ListIPsByHost("insert.b612.me")
fmt.Printf("%+v\n", v) if len(data) < 1 || data[0] != "11.11.11.11" {
t.Error("Expected 11.11.11.11 got ", data)
} else {
t.Log(data)
} }
fmt.Println(h.nextUid, h.lastUid)
fmt.Println("") err = h.SaveAs("./test_hosts_01.txt")
err = h.RemoveIPHosts("11.22.33.44", "remove.b612.me", "test.dns.set.b612.me")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
for _, v := range h.List() {
fmt.Printf("%+v\n", v) err = h.DeleteNode(insertNode)
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("insert.b612.me")
if len(data) > 0 {
t.Error("Expected 0 got ", data)
} else {
t.Log(data)
}
for i := 0; i < 100; i++ {
err = h.RemoveHosts("release-ftpd")
if err != nil {
t.Error(err)
}
err = h.AddHosts("2.3.4.9", "release-ftpd")
if err != nil {
t.Error(err)
}
}
err = h.SetHostIPs("ssh.b612.me", "9.9.9.9")
if err != nil {
t.Error(err)
}
data = h.ListIPsByHost("ssh.b612.me")
if len(data) == 0 {
t.Error("Expected 1 got ", data)
} else {
t.Log(data)
}
err = h.SetIPHosts("10.10.10.10", "ssh.b612.me", "ssr.b612.me")
if len(data) == 0 {
t.Error("Expected 1 got ", data)
}
err = h.SaveAs("./test_hosts_02.txt")
if err != nil {
t.Error(err)
}
}
func BenchmarkAddHosts(b *testing.B) {
var h = NewHosts()
err := h.Parse("./test_hosts.txt")
if err != nil {
b.Error(err)
}
for i := 0; i < b.N; i++ {
err = h.AddHosts("1.3.4.5", "test.b612.me")
if err != nil {
b.Error(err)
}
} }
fmt.Println(h.nextUid, h.lastUid)
fmt.Println("")
} }

@ -8,6 +8,7 @@
#special IPv6 addre #special IPv6 addre
127.0.0.1 localhost 127.0.0.1 localhost
127.0.0.1 b612 127.0.0.1 b612
8.8.8.8 ssh.b612.me
#special IPv6 addresses #special IPv6 addresses
::1 localhost ipv6-localhost ipv6-loopback ::1 localhost ipv6-localhost ipv6-loopback
fe00::0 ipv6-localnet fe00::0 ipv6-localnet

@ -33,11 +33,10 @@ func Test_Parse(t *testing.T) {
fmt.Println(cfg.Parse([]byte(data))) fmt.Println(cfg.Parse([]byte(data)))
cfg.Reverse() cfg.Reverse()
cfg.Data[0].Delete(`pp.com`) cfg.Data[0].Delete(`pp.com`)
//fmt.Println(cfg.Data[0].Comment) //fmt.Println(cfg.Data[0].comment)
fmt.Println(string(cfg.Build())) fmt.Println(string(cfg.Build()))
} }
type slicetest struct { type slicetest struct {
A string `seg:"s" key:"a"` A string `seg:"s" key:"a"`
B string `seg:"a" key:"b"` B string `seg:"a" key:"b"`
@ -50,7 +49,7 @@ type testme struct {
func Test_Marshal(t *testing.T) { func Test_Marshal(t *testing.T) {
var info string =` var info string = `
[love] [love]
a=abc a=abc
b=123 b=123
@ -59,10 +58,10 @@ a=456
b=789 b=789
` `
var tmp testme var tmp testme
ini:=NewIni() ini := NewIni()
ini.Parse([]byte(info)) ini.Parse([]byte(info))
ini.Unmarshal(&tmp) ini.Unmarshal(&tmp)
fmt.Printf("%+v\n",tmp) fmt.Printf("%+v\n", tmp)
b,_:=ini.Marshal(tmp) b, _ := ini.Marshal(tmp)
fmt.Println(string(b)) fmt.Println(string(b))
} }
Loading…
Cancel
Save