mirror of
https://github.com/lionsoul2014/ip2region.git
synced 2025-12-08 19:25:22 +00:00
122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
// Copyright 2022 The Ip2Region Authors. All rights reserved.
|
|
// Use of this source code is governed by a Apache2.0-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// original source ip processor
|
|
|
|
package xdb
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
type Processor struct {
|
|
srcHandle *os.File
|
|
dstHandle *os.File
|
|
|
|
fields []int
|
|
segments []*Segment
|
|
}
|
|
|
|
func NewProcessor(srcFile string, dstFile string, fields []int) (*Processor, error) {
|
|
// open the source file with READONLY mode
|
|
srcHandle, err := os.OpenFile(srcFile, os.O_RDONLY, 0600)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open source file `%s`: %w", srcFile, err)
|
|
}
|
|
|
|
// open the destination file with Read/Write mode
|
|
dstHandle, err := os.OpenFile(dstFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open target file `%s`: %w", dstFile, err)
|
|
}
|
|
|
|
return &Processor{
|
|
srcHandle: srcHandle,
|
|
dstHandle: dstHandle,
|
|
|
|
// filter fields index
|
|
fields: fields,
|
|
|
|
segments: []*Segment{},
|
|
}, nil
|
|
}
|
|
|
|
func (p *Processor) loadSegments() error {
|
|
slog.Info("try to load the segments ... ")
|
|
var tStart = time.Now()
|
|
|
|
var iErr = IterateSegments(p.srcHandle, func(l string) {
|
|
slog.Debug("loaded", "segment", l)
|
|
}, func(seg *Segment) error {
|
|
// check the continuity of the data segment
|
|
// if err := seg.AfterCheck(last); err != nil {
|
|
// return err
|
|
// }
|
|
|
|
// apply the field filter
|
|
region, err := RegionFiltering(seg.Region, p.fields)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// slog.Info("filtered", "source", seg.Region, "filtered", region)
|
|
seg.Region = region
|
|
p.segments = append(p.segments, seg)
|
|
return nil
|
|
})
|
|
if iErr != nil {
|
|
return fmt.Errorf("failed to load segments: %s", iErr)
|
|
}
|
|
|
|
slog.Info("all segments loaded", "length", len(p.segments), "elapsed", time.Since(tStart))
|
|
return nil
|
|
}
|
|
|
|
// Init the db binary file
|
|
func (p *Processor) Init() error {
|
|
// load all the segments
|
|
err := p.loadSegments()
|
|
if err != nil {
|
|
return fmt.Errorf("load segments: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Processor) Start() error {
|
|
slog.Info("try to sort all the segments based on its start ip ...")
|
|
sort.Slice(p.segments, func(i, j int) bool {
|
|
return IPCompare(p.segments[i].StartIP, p.segments[j].StartIP) < 0
|
|
})
|
|
|
|
slog.Info("try to write all segments to target file ...")
|
|
for _, seg := range p.segments {
|
|
_, err := fmt.Fprintln(p.dstHandle, seg.String())
|
|
if err != nil {
|
|
return fmt.Errorf("write segment index for '%s': %w", seg.String(), err)
|
|
}
|
|
}
|
|
|
|
slog.Info("process done", "segments", len(p.segments))
|
|
return nil
|
|
}
|
|
|
|
func (p *Processor) End() error {
|
|
err := p.dstHandle.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = p.srcHandle.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|