代码拉取完成,页面将自动刷新
package main
import (
"github.com/labstack/echo"
"net/http"
"github.com/labstack/echo/middleware"
"github.com/asaskevich/govalidator"
"os"
"time"
"github.com/labstack/gommon/log"
"github.com/influxdata/influxdb/client"
"net/url"
"fmt"
"strconv"
"flag"
"github.com/PedroGao/CmsGo/pkg/ip"
"io/ioutil"
"github.com/json-iterator/go"
)
const (
welcome = `
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Watcher</title>
<style>
.body {
text-align: center;
margin: 0 auto;
width: 1000px;
border: 1px solid #003300;
}
</style>
</head>
<body>
<div class="body">
<h1>Hello From Watcher</h1>
<small>Powered By Pedro🤣</small>
</div>
</body>
</html>
`
TAOBAO_IP_REQUEST_URL = "http://ip.taobao.com/service/getIpInfo.php?ip=%s"
)
// ip_flow struct
type (
IpFlow struct {
// 传入
Devkey string `json:"devkey" valid:"required,devkey"`
Puid int `json:"puid" valid:"required,int"`
Ip string `json:"ip" valid:"required,ip"`
ApiSign string `json:"api_sign" valid:"required"`
Appkey string `json:"appkey" valid:"required"`
// 查询所得
Country string `json:"country"`
Region string `json:"region"` // 省份
City string `json:"city"`
Isp string `json:"isp"`
}
NotFoundIp struct {
NotComplete *IpFlow `json:"not_complete"`
Time time.Time `json:"time"`
}
EValidator struct {
}
)
func (cv *EValidator) Validate(i interface{}) error {
if ok, err := govalidator.ValidateStruct(i); ok {
return nil
} else {
return err
}
}
func addCustomValidators() {
// Add your own struct validation tags
govalidator.TagMap["devkey"] = govalidator.Validator(func(str string) bool {
return str == "8uy6da" || str == "ku7hax"
})
}
var (
region *ip.Ip2Region
// todo 把当时的时间记录下来,然后丢入channel里面
unusedIps chan *NotFoundIp
//receivedIps chan string
ipInfos chan *IpFlow
e *echo.Echo
conn *client.Client
dbPath string
)
func init() {
flag.StringVar(&dbPath, "db_path", "pkg/data/ip2region.db", "the ip db path")
}
func initRegion(path string) {
_, err := os.Stat(path)
if os.IsNotExist(err) {
panic("not found db " + path)
}
if region, err = ip.New(path); err != nil {
panic("open ip db failed")
}
// 寻找地域失败的ip 100 的缓冲区
unusedIps = make(chan *NotFoundIp, 100)
// 接收到ip 1000的缓冲区
//receivedIps = make(chan string, 1000)
//查询得到的ip区域信息 1000的缓冲区
ipInfos = make(chan *IpFlow, 1000)
}
func main() {
flag.Parse()
// db init
initRegion(dbPath)
// server init
e = echo.New()
// not debug
e.Debug = false
e.Use(middleware.Recover())
e.Use(middleware.Logger())
// add validator for echo
addCustomValidators()
e.Validator = &EValidator{}
// init influx client
host, err := url.Parse(fmt.Sprintf("http://%s:%d", "localhost", 8086))
if err != nil {
panic(err)
}
conf := client.Config{
URL: *host,
Username: "root",
Password: "root",
}
conn, err = client.NewClient(conf)
if err != nil {
panic(err)
}
// route
e.GET("/", func(c echo.Context) error {
return c.HTML(http.StatusOK, welcome)
})
// 写信息
go func() {
for {
select {
case info := <-ipInfos:
e.Logger.Infof("get an ip info : %v", info)
go writePoints(info, time.Now())
// 若一个小时未收到任何信息输出一条日志
case <-time.After(time.Hour * 1):
e.Logger.Info("there is no ip infos received in an hour")
}
}
}()
// 若有信息查询不到
go func() {
for {
select {
case unusedInfo := <-unusedIps:
e.Logger.Infof("get an unused ip info : %v", unusedInfo)
go queryAndWrite(unusedInfo)
// 若一天未收到任何信息输出一条日志
case <-time.After(time.Hour * 24):
e.Logger.Info("there is no unused ip infos received in a day")
}
}
}()
e.POST("/ip", ipHandler)
e.Logger.SetLevel(log.INFO)
e.Logger.Fatal(e.Start(":3000"))
}
func writePoints(info *IpFlow, time time.Time) {
point := client.Point{
Measurement: "ip_flow",
Tags: map[string]string{
"puid": strconv.Itoa(info.Puid),
"devkey": info.Devkey,
"api_sign": info.ApiSign,
"ip": info.Ip,
"appkey": info.Appkey,
},
Fields: map[string]interface{}{
"country": info.Country,
"region": info.Region,
"city": info.City,
"isp": info.Isp,
},
Time: time,
}
bps := client.BatchPoints{
Points: []client.Point{point},
Database: "pkg",
//RetentionPolicy: "default",
}
if _, err := conn.Write(bps); err != nil {
e.Logger.Infof("write an ip info to influxdb err: %v", err)
}
}
func queryAndWrite(unusedInfo *NotFoundIp) {
if ok := QueryForRegion(unusedInfo.NotComplete.Ip, unusedInfo.NotComplete); ok {
writePoints(unusedInfo.NotComplete, unusedInfo.Time)
}
}
func QueryForRegion(ip string, NotComplete *IpFlow) bool {
url := fmt.Sprintf(TAOBAO_IP_REQUEST_URL, ip)
resp, err := http.Get(url)
if err != nil {
e.Logger.Infof("get taobao ip api err: %v", err)
}
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
e.Logger.Infof("get taobao ip api err: %v", err)
}
code := jsoniter.Get(bytes, "code").ToInt()
// 其中code的值的含义为,0:成功,1:失败。
if code == 0 {
data := jsoniter.Get(bytes, "data")
country := data.Get("country").ToString()
region := data.Get("region").ToString()
city := data.Get("city").ToString()
isp := data.Get("isp").ToString()
NotComplete.Country = country
NotComplete.Region = region
NotComplete.City = city
NotComplete.Isp = isp
return true
}
return false
}
func ipHandler(c echo.Context) error {
var (
err error
)
ip := new(IpFlow)
if err = c.Bind(ip); err != nil {
c.Error(echo.NewHTTPError(400, err.Error()))
return nil
}
if err = c.Validate(ip); err != nil {
c.Error(echo.NewHTTPError(400, err.Error()))
return nil
}
// 将ip查询放入协程中
go func() {
// 如果没有找到ip 将ip写入到channel中
if info, err := region.BtreeSearch(ip.Ip); err != nil {
// 传入的信息及传入时间写到channel中,供后续调用
unusedIps <- &NotFoundIp{
NotComplete: ip,
Time: time.Now(),
}
} else {
// 写入 ip信息
ip.Country = info.Country
ip.Region = info.Region
ip.City = info.City
ip.Isp = info.ISP
// 写入 channel中
ipInfos <- ip
}
}()
return c.JSON(http.StatusOK, map[string]string{"message": "ok"})
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。