diff --git a/platformapi/tiktok_shop/ascription_place/dd_test.go b/platformapi/tiktok_shop/ascription_place/dd_test.go index 7c218fd0..09158726 100644 --- a/platformapi/tiktok_shop/ascription_place/dd_test.go +++ b/platformapi/tiktok_shop/ascription_place/dd_test.go @@ -2,12 +2,11 @@ package ascription_place import ( "fmt" - "github.com/xluohome/phonedata" "testing" ) func TestAscriptionPlace(t *testing.T) { - p, err := phonedata.Find("18744776542") + p, err := Find("18744776542") fmt.Println(p) fmt.Println(err) } diff --git a/platformapi/tiktok_shop/ascription_place/phone.dat b/platformapi/tiktok_shop/ascription_place/phone.dat new file mode 100644 index 00000000..34bcab7f Binary files /dev/null and b/platformapi/tiktok_shop/ascription_place/phone.dat differ diff --git a/platformapi/tiktok_shop/ascription_place/phonedata.go b/platformapi/tiktok_shop/ascription_place/phonedata.go new file mode 100644 index 00000000..4440a6e2 --- /dev/null +++ b/platformapi/tiktok_shop/ascription_place/phonedata.go @@ -0,0 +1,184 @@ +package ascription_place + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "os" + "path" + "runtime" +) + +const ( + CMCC byte = iota + 0x01 //中国移动 + CUCC //中国联通 + CTCC //中国电信 + CTCC_v //电信虚拟运营商 + CUCC_v //联通虚拟运营商 + CMCC_v //移动虚拟运营商 + INT_LEN = 4 + CHAR_LEN = 1 + HEAD_LENGTH = 8 + PHONE_INDEX_LENGTH = 9 + PHONE_DAT = "phone.dat" +) + +type PhoneRecord struct { + PhoneNum string + Province string + City string + ZipCode string + AreaZone string + CardType string +} + +var ( + content []byte + CardTypemap = map[byte]string{ + CMCC: "中国移动", + CUCC: "中国联通", + CTCC: "中国电信", + CTCC_v: "中国电信虚拟运营商", + CUCC_v: "中国联通虚拟运营商", + CMCC_v: "中国移动虚拟运营商", + } + total_len, firstoffset int32 +) + +func init() { + dir := os.Getenv("PHONE_DATA_DIR") + if dir == "" { + _, fulleFilename, _, _ := runtime.Caller(0) + dir = path.Dir(fulleFilename) + } + var err error + content, err = ioutil.ReadFile(path.Join(dir, PHONE_DAT)) + if err != nil { + panic(err) + } + total_len = int32(len(content)) + firstoffset = get4(content[INT_LEN : INT_LEN*2]) +} + +func Debug() { + fmt.Println(version()) + fmt.Println(totalRecord()) + fmt.Println(firstRecordOffset()) +} + +func (pr PhoneRecord) String() string { + return fmt.Sprintf("PhoneNum: %s\nAreaZone: %s\nCardType: %s\nCity: %s\nZipCode: %s\nProvince: %s\n", pr.PhoneNum, pr.AreaZone, pr.CardType, pr.City, pr.ZipCode, pr.Province) +} + +func get4(b []byte) int32 { + if len(b) < 4 { + return 0 + } + return int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 +} + +func getN(s string) (uint32, error) { + var n, cutoff, maxVal uint32 + i := 0 + base := 10 + cutoff = (1<<32-1)/10 + 1 + maxVal = 1<= byte(base) { + return 0, errors.New("invalid syntax") + } + + if n >= cutoff { + // n*base overflows + n = (1<<32 - 1) + return n, errors.New("value out of range") + } + n *= uint32(base) + + n1 := n + uint32(v) + if n1 < n || n1 > maxVal { + // n+v overflows + n = (1<<32 - 1) + return n, errors.New("value out of range") + } + n = n1 + } + return n, nil +} + +func version() string { + return string(content[0:INT_LEN]) +} + +func totalRecord() int32 { + return (int32(len(content)) - firstRecordOffset()) / PHONE_INDEX_LENGTH +} + +func firstRecordOffset() int32 { + return get4(content[INT_LEN : INT_LEN*2]) +} + +// 二分法查询phone数据 +func Find(phone_num string) (pr *PhoneRecord, err error) { + if len(phone_num) < 7 || len(phone_num) > 11 { + return nil, errors.New("illegal phone length") + } + + var left int32 + phone_seven_int, err := getN(phone_num[0:7]) + if err != nil { + return nil, errors.New("illegal phone number") + } + phone_seven_int32 := int32(phone_seven_int) + right := (total_len - firstoffset) / PHONE_INDEX_LENGTH + for { + if left > right { + break + } + mid := (left + right) / 2 + offset := firstoffset + mid*PHONE_INDEX_LENGTH + if offset >= total_len { + break + } + cur_phone := get4(content[offset : offset+INT_LEN]) + record_offset := get4(content[offset+INT_LEN : offset+INT_LEN*2]) + card_type := content[offset+INT_LEN*2 : offset+INT_LEN*2+CHAR_LEN][0] + switch { + case cur_phone > phone_seven_int32: + right = mid - 1 + case cur_phone < phone_seven_int32: + left = mid + 1 + default: + cbyte := content[record_offset:] + end_offset := int32(bytes.Index(cbyte, []byte("\000"))) + data := bytes.Split(cbyte[:end_offset], []byte("|")) + card_str, ok := CardTypemap[card_type] + if !ok { + card_str = "未知电信运营商" + } + pr = &PhoneRecord{ + PhoneNum: phone_num, + Province: string(data[0]), + City: string(data[1]), + ZipCode: string(data[2]), + AreaZone: string(data[3]), + CardType: card_str, + } + return + } + } + return nil, errors.New("phone's data not found") +}