diff --git a/data/ip.test.txt b/data/ip.test.txt new file mode 100644 index 0000000..09e0266 --- /dev/null +++ b/data/ip.test.txt @@ -0,0 +1,25 @@ +1.0.0.0|1.0.0.255|澳大利亚|0|0|0|0 +1.0.1.0|1.0.3.255|中国|0|福建省|福州市|电信 +1.0.4.0|1.0.7.255|澳大利亚|0|维多利亚|墨尔本|0 +1.0.8.0|1.0.15.255|中国|0|广东省|广州市|电信 +1.0.16.0|1.0.31.255|日本|0|0|0|0 +1.0.32.0|1.0.63.255|中国|0|广东省|广州市|电信 +1.0.64.0|1.0.79.255|日本|0|广岛县|0|0 +1.0.80.0|1.0.127.255|日本|0|冈山县|0|0 +1.0.128.0|1.0.128.255|泰国|0|清莱府|0|TOT +1.0.129.0|1.0.132.191|泰国|0|曼谷|曼谷|TOT +1.0.132.192|1.0.132.255|泰国|0|Nakhon-Ratchasima|0|TOT +1.0.133.0|1.0.133.255|泰国|0|素攀武里府|0|TOT +1.0.134.0|1.0.134.255|泰国|0|曼谷|曼谷|TOT +1.0.135.0|1.0.135.127|泰国|0|华富里府|0|TOT +1.0.135.128|1.0.135.255|泰国|0|素攀武里府|0|TOT +1.0.136.0|1.0.136.255|泰国|0|龙仔厝府|0|TOT +1.0.137.0|1.0.137.255|泰国|0|大城府|0|TOT +1.0.138.0|1.0.143.255|泰国|0|曼谷|曼谷|TOT +1.0.144.0|1.0.159.255|泰国|0|春蓬府|0|TOT +1.0.160.0|1.0.162.255|泰国|0|洛坤府|0|TOT +1.0.163.0|1.0.163.255|泰国|0|春蓬府|0|TOT +1.0.164.0|1.0.164.63|泰国|0|0|0|TOT +1.0.164.64|1.0.164.127|泰国|0|普吉府|0|TOT +1.0.164.128|1.0.170.255|泰国|0|0|0|TOT +1.0.171.0|1.0.175.255|泰国|0|攀牙府|0|TOT diff --git a/data/segments.tests b/data/segments.tests index 0d46f0f..da0f550 100644 --- a/data/segments.tests +++ b/data/segments.tests @@ -1,5 +1,5 @@ -192.168.2.1|192.168.2.20|办公室A内网IP -192.168.2.21|192.168.2.30|办公室A内网IP -192.168.2.31|192.168.2.60|办公室B内网IP -192.168.2.61|192.168.2.91|办公室B内网IP -223.255.236.0|223.255.239.255|中国|0|上海|上海市|电信 \ No newline at end of file +192.168.2.1|192.168.2.20|0|0|0|内网IP|办公室A +192.168.2.21|192.168.2.30|0|0|0|内网IP|办公室A +192.168.2.31|192.168.2.60|0|0|0|内网IP|办公室B +192.168.2.61|192.168.2.91|0|0|0|内网IP|办公室B +223.255.236.0|223.255.239.255|中国|0|上海|上海市|电信 diff --git a/maker/golang/main.go b/maker/golang/main.go index 88f552a..91b6d4e 100644 --- a/maker/golang/main.go +++ b/maker/golang/main.go @@ -10,6 +10,7 @@ import ( "github.com/lionsoul2014/ip2region/maker/golang/xdb" "log" "os" + "regexp" "strings" "time" ) @@ -303,6 +304,12 @@ func edit() { return } + rExp, err := regexp.Compile("\\s+") + if err != nil { + fmt.Printf("failed to compile regexp: %s\n", err) + return + } + fmt.Printf("init the editor from source @ `%s` ... \n", srcFile) var tStart = time.Now() editor, err := xdb.NewEditor(srcFile) @@ -314,11 +321,12 @@ func edit() { fmt.Printf("all segments loaded, length: %d, elapsed: %s\n", editor.SegLen(), time.Since(tStart)) var help = func() { fmt.Printf("command list: \n") - fmt.Printf(" put [segment] : put the specifield segment\n") - fmt.Printf(" put_file [file] : put all the segments from the specified file\n") - fmt.Printf(" save : save all the changes to the destination source file\n") - fmt.Printf(" exit : exit the program\n") - fmt.Printf(" help : print this help menu\n") + fmt.Printf(" put [segment] : put the specifield $segment\n") + fmt.Printf(" put_file [file] : put all the segments from the specified $file\n") + fmt.Printf(" list [offset] [size] : list the first $size segments start from $offset\n") + fmt.Printf(" save : save all the changes to the destination source file\n") + fmt.Printf(" quit : exit the program\n") + fmt.Printf(" help : print this help menu\n") } help() @@ -341,7 +349,7 @@ func edit() { cmd := strings.TrimSpace(line) if cmd == "help" { help() - } else if cmd == "exit" { + } else if cmd == "quit" { if editor.NeedSave() { fmt.Printf("there are changes that need to save, type 'quit!' to force quit\n") } else { @@ -357,22 +365,45 @@ func edit() { continue } fmt.Printf("all segments saved to %s\n", srcFile) + } else if strings.HasPrefix(cmd, "list") { + var sErr error + off, size, l := 0, 10, len("list") + str := strings.TrimSpace(cmd) + if len(str) > l { + sets := rExp.Split(cmd, 3) + switch len(sets) { + case 2: + _, sErr = fmt.Sscanf(cmd, "%s %d", &str, &off) + case 3: + _, sErr = fmt.Sscanf(cmd, "%s %d %d", &str, &off, &size) + } + } + + if sErr != nil { + fmt.Printf("failed to parse the offset and size: %s\n", sErr) + continue + } + + fmt.Printf("+-slice(%d,%d): \n", off, size) + for _, s := range editor.Slice(off, size) { + fmt.Printf("%s\n", s) + } } else if strings.HasPrefix(cmd, "put ") { - seg := cmd[len("put "):] - err = editor.Put(seg) + seg := strings.TrimSpace(cmd[len("put "):]) + o, n, err := editor.Put(seg) if err != nil { fmt.Printf("failed to Put(%s): %s\n", seg, err) continue } - fmt.Printf("Put(%s): Ok\n", seg) + fmt.Printf("Put(%s): Ok, with %d deletes and %d additions\n", seg, o, n) } else if strings.HasPrefix(cmd, "put_file ") { - file := cmd[len("put_file "):] - err = editor.PutFile(file) + file := strings.TrimSpace(cmd[len("put_file "):]) + o, n, err := editor.PutFile(file) if err != nil { fmt.Printf("failed to PutFile(%s): %s\n", file, err) continue } - fmt.Printf("PutFile(%s): Ok\n", file) + fmt.Printf("PutFile(%s): Ok, with %d deletes and %d additions\n", file, o, n) } else if len(cmd) > 0 { help() } diff --git a/maker/golang/xdb/editor.go b/maker/golang/xdb/editor.go index 2d80ff5..42232c9 100644 --- a/maker/golang/xdb/editor.go +++ b/maker/golang/xdb/editor.go @@ -81,10 +81,36 @@ func (e *Editor) SegLen() int { return e.segments.Len() } -func (e *Editor) Put(ip string) error { +func (e *Editor) Slice(offset int, size int) []*Segment { + var index = -1 + var out []*Segment + var next *list.Element + for ele := e.segments.Front(); ele != nil; ele = next { + next = ele.Next() + s, ok := ele.Value.(*Segment) + if !ok { + continue + } + + // offset match + index++ + if index < offset { + continue + } + + out = append(out, s) + if len(out) >= size { + break + } + } + + return out +} + +func (e *Editor) Put(ip string) (int, int, error) { seg, err := SegmentFrom(ip) if err != nil { - return err + return 0, 0, err } return e.PutSegment(seg) @@ -92,16 +118,17 @@ func (e *Editor) Put(ip string) error { // PutSegment put the specified segment into the current segment list with // the following position relationships. -// 1, fully contained like: +// 1, A - fully contained like: // StartIP------seg.StartIP--------seg.EndIP----EndIP // |------------------| -// 2, intersect like: +// 2, B - intersect like: // StartIP------seg.StartIP------EndIP------| // |---------------------seg.EndIP // -func (e *Editor) PutSegment(seg *Segment) error { - var tOne *list.Element +func (e *Editor) PutSegment(seg *Segment) (int, int, error) { var next *list.Element + var eList []*list.Element + var found = false for ele := e.segments.Front(); ele != nil; ele = next { next = ele.Next() s, ok := ele.Value.(*Segment) @@ -110,50 +137,114 @@ func (e *Editor) PutSegment(seg *Segment) error { continue } - // find the related segment - if seg.StartIP >= s.StartIP && seg.StartIP <= s.EndIP { - tOne = ele + // found the related segment + if seg.StartIP <= s.EndIP && seg.StartIP >= s.StartIP { + found = true + } + + if found == false { + continue + } + + eList = append(eList, ele) + if seg.EndIP <= s.EndIP { break } } - if tOne == nil { + if len(eList) == 0 { // could this even be a case ? // if the loaded segments contains all the segments we have // from 0 to 0xffffffff - return fmt.Errorf("failed to find the related segment") + return 0, 0, fmt.Errorf("failed to find the related segment") } - s, ok := tOne.Value.(*Segment) - if !ok { - return fmt.Errorf("internal error: invalid segment type") + // print for debug + // for i, s := range eList { + // fmt.Printf("ele %d: %s\n", i, s.Value.(*Segment)) + // } + + // segment split + var sList []*Segment + var head = eList[0].Value.(*Segment) + if seg.StartIP > head.StartIP { + sList = append(sList, &Segment{ + StartIP: head.StartIP, + EndIP: seg.StartIP - 1, + Region: head.Region, + }) } - fmt.Printf("tOne: %s\n", s) + // append the new segment + sList = append(sList, seg) + + // check and do the tailing segment append + if len(sList) > 0 { + // check and append the tailing + var tail = eList[len(eList)-1].Value.(*Segment) + if seg.EndIP < tail.EndIP { + sList = append(sList, &Segment{ + StartIP: seg.EndIP + 1, + EndIP: tail.EndIP, + Region: tail.Region, + }) + } + } + + // print for debug + // for i, s := range sList { + // fmt.Printf("%d: %s\n", i, s) + // } + + // delete all the in-range segments and + var base *list.Element + var oldRows, newRows = len(eList), len(sList) + for _, ele := range eList { + base = ele.Next() + e.segments.Remove(ele) + } + + // add all the new segments + if base == nil { + for _, s := range sList { + e.segments.PushBack(s) + } + } else { + for _, s := range sList { + e.segments.InsertBefore(s, base) + } + } // open the to save flag e.toSave = true - return nil + return oldRows, newRows, nil } -func (e *Editor) PutFile(src string) error { +func (e *Editor) PutFile(src string) (int, int, error) { handle, err := os.OpenFile(src, os.O_RDONLY, 0600) if err != nil { - return err + return 0, 0, err } + var oldRows, newRows = 0, 0 iErr := IterateSegments(handle, func(l string) { // do nothing here }, func(seg *Segment) error { - return e.PutSegment(seg) + o, n, err := e.PutSegment(seg) + if err == nil { + oldRows += o + newRows += n + } + + return err }) if iErr != nil { - return iErr + return oldRows, newRows, iErr } _ = handle.Close() - return nil + return oldRows, newRows, nil } func (e *Editor) Save() error {