diff --git a/client.go b/client.go index 0ee4fef..d4e0b6b 100644 --- a/client.go +++ b/client.go @@ -1,92 +1,46 @@ package feishu import ( - "go.dtapp.net/dorm" "go.dtapp.net/golog" "go.dtapp.net/gorequest" ) -// client *dorm.GormClient -type gormClientFun func() *dorm.GormClient - -// client *dorm.MongoClient -// databaseName string -type mongoClientFun func() (*dorm.MongoClient, string) - // ClientConfig 实例配置 type ClientConfig struct { - Key string - GormClientFun gormClientFun // 日志配置 - MongoClientFun mongoClientFun // 日志配置 - Debug bool // 日志开关 - ZapLog *golog.ZapLog // 日志服务 - CurrentIp string // 当前ip + Key string + ApiGormClientFun golog.ApiClientFun // 日志配置 + Debug bool // 日志开关 + ZapLog *golog.ZapLog // 日志服务 } // Client 实例 type Client struct { requestClient *gorequest.App // 请求服务 zapLog *golog.ZapLog // 日志服务 - currentIp string // 当前ip config struct { key string } log struct { - gorm bool // 日志开关 - gormClient *dorm.GormClient // 日志数据库 - logGormClient *golog.ApiClient // 日志服务 - mongo bool // 日志开关 - mongoClient *dorm.MongoClient // 日志数据库 - logMongoClient *golog.ApiClient // 日志服务 + status bool // 状态 + client *golog.ApiClient // 日志服务 } } // NewClient 创建实例化 func NewClient(config *ClientConfig) (*Client, error) { - var err error c := &Client{} c.zapLog = config.ZapLog - c.currentIp = config.CurrentIp - c.config.key = config.Key c.requestClient = gorequest.NewHttp() - gormClient := config.GormClientFun() - if gormClient != nil && gormClient.Db != nil { - c.log.logGormClient, err = golog.NewApiGormClient(&golog.ApiGormClientConfig{ - GormClientFun: func() (*dorm.GormClient, string) { - return gormClient, logTable - }, - Debug: config.Debug, - ZapLog: c.zapLog, - CurrentIp: c.currentIp, - }) - if err != nil { - return nil, err - } - c.log.gorm = true - c.log.gormClient = gormClient - } - - mongoClient, databaseName := config.MongoClientFun() - if mongoClient != nil && mongoClient.Db != nil { - c.log.logMongoClient, err = golog.NewApiMongoClient(&golog.ApiMongoClientConfig{ - MongoClientFun: func() (*dorm.MongoClient, string, string) { - return mongoClient, databaseName, logTable - }, - Debug: config.Debug, - ZapLog: c.zapLog, - CurrentIp: c.currentIp, - }) - if err != nil { - return nil, err - } - c.log.mongo = true - c.log.mongoClient = mongoClient + apiGormClient := config.ApiGormClientFun() + if apiGormClient != nil { + c.log.client = apiGormClient + c.log.status = true } return c, nil diff --git a/const.go b/const.go index 06b5d33..b217b8b 100644 --- a/const.go +++ b/const.go @@ -1,7 +1,10 @@ package feishu const ( - apiUrl = "https://open.feishu.cn" - logTable = "feishu" - Version = "1.0.9" + apiUrl = "https://open.feishu.cn" +) + +const ( + LogTable = "feishu" + Version = "1.0.10" ) diff --git a/get.go b/get.go index e0914b0..8ee6f99 100644 --- a/get.go +++ b/get.go @@ -6,10 +6,6 @@ func (c *Client) GetKey() string { return c.config.key } -func (c *Client) GetLogGorm() *golog.ApiClient { - return c.log.logGormClient -} - -func (c *Client) GetLogMongo() *golog.ApiClient { - return c.log.logMongoClient +func (c *Client) GetLog() *golog.ApiClient { + return c.log.client } diff --git a/go.mod b/go.mod index 68d0520..583d0c6 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,7 @@ module go.dtapp.net/feishu go 1.19 require ( - go.dtapp.net/dorm v1.0.33 - go.dtapp.net/golog v1.0.73 + go.dtapp.net/golog v1.0.88 go.dtapp.net/gorequest v1.0.31 ) @@ -17,7 +16,7 @@ require ( github.com/gin-gonic/gin v1.8.1 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.11.0 // indirect + github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/go-redis/redis/v9 v9.0.0-beta.2 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/goccy/go-json v0.9.11 // indirect @@ -34,7 +33,7 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.15.9 // indirect + github.com/klauspost/compress v1.15.10 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/lib/pq v1.10.7 // indirect github.com/mattn/go-isatty v0.0.16 // indirect @@ -42,6 +41,8 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.6.6 // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect + github.com/oschwald/geoip2-golang v1.8.0 // indirect + github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/saracen/go7z v0.0.0-20191010121135-9c09b6bd7fda // indirect @@ -64,7 +65,8 @@ require ( github.com/xdg-go/scram v1.1.1 // indirect github.com/xdg-go/stringprep v1.0.3 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect - go.dtapp.net/goip v1.0.30 // indirect + go.dtapp.net/dorm v1.0.38 // indirect + go.dtapp.net/goip v1.0.36 // indirect go.dtapp.net/gorandom v1.0.1 // indirect go.dtapp.net/gostring v1.0.10 // indirect go.dtapp.net/gotime v1.0.5 // indirect @@ -74,17 +76,17 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.23.0 // indirect - golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect + golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect + golang.org/x/net v0.0.0-20220920152717-4a395b0a80a1 // indirect golang.org/x/sync v0.0.0-20220907140024-f12130a52804 // indirect - golang.org/x/sys v0.0.0-20220913175220-63ea55921009 // indirect + golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gorm.io/driver/mysql v1.3.6 // indirect - gorm.io/driver/postgres v1.3.9 // indirect - gorm.io/gorm v1.23.8 // indirect + gorm.io/driver/postgres v1.3.10 // indirect + gorm.io/gorm v1.23.9 // indirect mellium.im/sasl v0.3.0 // indirect modernc.org/sqlite v1.18.1 // indirect xorm.io/builder v0.3.12 // indirect diff --git a/go.sum b/go.sum index 3a477cd..cc1c07f 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,8 @@ github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw= -github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-redis/redis/v9 v9.0.0-beta.2 h1:ZSr84TsnQyKMAg8gnV+oawuQezeJR11/09THcWCQzr4= github.com/go-redis/redis/v9 v9.0.0-beta.2/go.mod h1:Bldcd/M/bm9HbnNPi/LUtYBSD8ttcZYBMupwMXhdU0o= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -193,7 +193,6 @@ github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/ github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= @@ -213,7 +212,6 @@ github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= @@ -229,7 +227,6 @@ github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI github.com/jackc/pgtype v1.8.0/go.mod h1:PqDKcEBtllAtk/2p6z6SHdXW5UB+MhE75tUol2OKexE= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= @@ -242,7 +239,6 @@ github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CI github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= -github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -271,8 +267,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -362,6 +358,10 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs= +github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw= +github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg= +github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -495,12 +495,12 @@ github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -go.dtapp.net/dorm v1.0.33 h1:QRAVEQ6Uf3WENSOrXytzzH+PjH90JySowd3jbB9PQjw= -go.dtapp.net/dorm v1.0.33/go.mod h1:4WNSzrUGs7YIudq1cRZQNkHOlPAbG6thI3mXX1tQcYY= -go.dtapp.net/goip v1.0.30 h1:/wP2ewSNWLzG2Oh2VsTfQCv/2rw1KKi9XerD4rQaMLM= -go.dtapp.net/goip v1.0.30/go.mod h1:9l8e/slVanziGXfvrUwOMx6028EV/lzN5vVpixmtUYY= -go.dtapp.net/golog v1.0.73 h1:1j7EU1iIM8b0UTMScxqUHZsgYFjKRy9SG/ArlpdcnfE= -go.dtapp.net/golog v1.0.73/go.mod h1:I1WfgHWcEikqxjhMdoyH+/VVi/9KmnZy11NnqpsugqY= +go.dtapp.net/dorm v1.0.38 h1:9OgWY5bnar6D0Xdho62xn7RluXJNe8i7Kz/IeSUObF4= +go.dtapp.net/dorm v1.0.38/go.mod h1:z9ksZ4Y0HHH0odjEiG57d90/ZUBM51qXEWJC8fS+dEM= +go.dtapp.net/goip v1.0.36 h1:+wexFCMnP3f+6jPYXjBLMyjnP+DfQrslWvXifndxkdc= +go.dtapp.net/goip v1.0.36/go.mod h1:9/Oo1HVM4EVUsvAebdV6CaBAK4S6qQMQWT3LcJfH6jM= +go.dtapp.net/golog v1.0.88 h1:lng1qJq3RrP+3vmMjZA+XLcDXKl/D5Se+PKN7YvHBdg= +go.dtapp.net/golog v1.0.88/go.mod h1:WL/R0YtUJGbosalRyZtaaJRWkuotcuUBk4SGwlo08k8= go.dtapp.net/gorandom v1.0.1 h1:IWfMClh1ECPvyUjlqD7MwLq4mZdUusD1qAwAdsvEJBs= go.dtapp.net/gorandom v1.0.1/go.mod h1:ZPdgalKpvFV/ATQqR0k4ns/F/IpITAZpx6WkWirr5Y8= go.dtapp.net/gorequest v1.0.31 h1:r/OoU5Y00TbJjkQtpvwjsb/pllqO0UQQjFRY1veZYZc= @@ -556,13 +556,12 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY= +golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -594,8 +593,8 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220920152717-4a395b0a80a1 h1:KPlMURVqlGj7IS5s1RR3RyiiiKAgGMrh3O4A0tpOQOg= +golang.org/x/net v0.0.0-20220920152717-4a395b0a80a1/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -641,8 +640,8 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220913175220-63ea55921009 h1:PuvuRMeLWqsf/ZdT1UUZz0syhioyv1mzuFZsXs4fvhw= -golang.org/x/sys v0.0.0-20220913175220-63ea55921009/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -727,11 +726,12 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.3.6 h1:BhX1Y/RyALb+T9bZ3t07wLnPZBukt+IRkMn8UZSNbGM= gorm.io/driver/mysql v1.3.6/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= -gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg= -gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U= +gorm.io/driver/postgres v1.3.10 h1:Fsd+pQpFMGlGxxVMUPJhNo8gG8B1lKtk8QQ4/VZZAJw= +gorm.io/driver/postgres v1.3.10/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.9 h1:NSHG021i+MCznokeXR3udGaNyFyBQJW8MbjrJMVCfGw= +gorm.io/gorm v1.23.9/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/request.go b/request.go index 8e0b1e2..2281c63 100644 --- a/request.go +++ b/request.go @@ -25,12 +25,9 @@ func (c *Client) request(ctx context.Context, url string, params map[string]inte return gorequest.Response{}, err } - // 日志 - if c.log.gorm { - go c.log.logGormClient.GormMiddleware(ctx, request, Version) - } - if c.log.mongo { - go c.log.logMongoClient.MongoMiddleware(ctx, request, Version) + // 记录日志 + if c.log.status { + go c.log.client.Middleware(ctx, request, Version) } return request, err diff --git a/vendor/github.com/go-playground/validator/v10/README.md b/vendor/github.com/go-playground/validator/v10/README.md index 8b730b6..9d0a79e 100644 --- a/vendor/github.com/go-playground/validator/v10/README.md +++ b/vendor/github.com/go-playground/validator/v10/README.md @@ -1,7 +1,7 @@ Package validator ================= [![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -![Project status](https://img.shields.io/badge/version-10.11.0-green.svg) +![Project status](https://img.shields.io/badge/version-10.11.1-green.svg) [![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) diff --git a/vendor/github.com/go-playground/validator/v10/baked_in.go b/vendor/github.com/go-playground/validator/v10/baked_in.go index f2f0939..c9b1db4 100644 --- a/vendor/github.com/go-playground/validator/v10/baked_in.go +++ b/vendor/github.com/go-playground/validator/v10/baked_in.go @@ -1484,10 +1484,15 @@ func isAlphaUnicode(fl FieldLevel) bool { return alphaUnicodeRegex.MatchString(fl.Field().String()) } -// isBoolean is the validation function for validating if the current field's value can be safely converted to a boolean. +// isBoolean is the validation function for validating if the current field's value is a valid boolean value or can be safely converted to a boolean value. func isBoolean(fl FieldLevel) bool { - _, err := strconv.ParseBool(fl.Field().String()) - return err == nil + switch fl.Field().Kind() { + case reflect.Bool: + return true + default: + _, err := strconv.ParseBool(fl.Field().String()) + return err == nil + } } // isDefault is the opposite of required aka hasValue diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index ad5c63a..2d6b010 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -17,6 +17,12 @@ This package provides various compression algorithms. # changelog +* July 21, 2022 (v1.15.9) + + * zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645 + * zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644 + * zstd: Allow single segments up to "max decoded size" by @klauspost in https://github.com/klauspost/compress/pull/643 + * July 13, 2022 (v1.15.8) * gzip: fix stack exhaustion bug in Reader.Read https://github.com/klauspost/compress/pull/641 diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go index c0c48bd..42a237e 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress.go @@ -763,17 +763,20 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) { d.bufs.Put(buf) return nil, errors.New("corruption detected: stream overrun 1") } - copy(out, buf[0][:]) - copy(out[dstEvery:], buf[1][:]) - copy(out[dstEvery*2:], buf[2][:]) - copy(out[dstEvery*3:], buf[3][:]) - out = out[bufoff:] - decoded += bufoff * 4 // There must at least be 3 buffers left. - if len(out) < dstEvery*3 { + if len(out)-bufoff < dstEvery*3 { d.bufs.Put(buf) return nil, errors.New("corruption detected: stream overrun 2") } + //copy(out, buf[0][:]) + //copy(out[dstEvery:], buf[1][:]) + //copy(out[dstEvery*2:], buf[2][:]) + *(*[bufoff]byte)(out) = buf[0] + *(*[bufoff]byte)(out[dstEvery:]) = buf[1] + *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2] + *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3] + out = out[bufoff:] + decoded += bufoff * 4 } } if off > 0 { @@ -997,17 +1000,22 @@ func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) { d.bufs.Put(buf) return nil, errors.New("corruption detected: stream overrun 1") } - copy(out, buf[0][:]) - copy(out[dstEvery:], buf[1][:]) - copy(out[dstEvery*2:], buf[2][:]) - copy(out[dstEvery*3:], buf[3][:]) - out = out[bufoff:] - decoded += bufoff * 4 // There must at least be 3 buffers left. - if len(out) < dstEvery*3 { + if len(out)-bufoff < dstEvery*3 { d.bufs.Put(buf) return nil, errors.New("corruption detected: stream overrun 2") } + + //copy(out, buf[0][:]) + //copy(out[dstEvery:], buf[1][:]) + //copy(out[dstEvery*2:], buf[2][:]) + // copy(out[dstEvery*3:], buf[3][:]) + *(*[bufoff]byte)(out) = buf[0] + *(*[bufoff]byte)(out[dstEvery:]) = buf[1] + *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2] + *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3] + out = out[bufoff:] + decoded += bufoff * 4 } } if off > 0 { diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go index 9f3e9f7..ba7e8e6 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go @@ -14,12 +14,14 @@ import ( // decompress4x_main_loop_x86 is an x86 assembler implementation // of Decompress4X when tablelog > 8. +// //go:noescape func decompress4x_main_loop_amd64(ctx *decompress4xContext) // decompress4x_8b_loop_x86 is an x86 assembler implementation // of Decompress4X when tablelog <= 8 which decodes 4 entries // per loop. +// //go:noescape func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext) @@ -145,11 +147,13 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) { // decompress4x_main_loop_x86 is an x86 assembler implementation // of Decompress1X when tablelog > 8. +// //go:noescape func decompress1x_main_loop_amd64(ctx *decompress1xContext) // decompress4x_main_loop_x86 is an x86 with BMI2 assembler implementation // of Decompress1X when tablelog > 8. +// //go:noescape func decompress1x_main_loop_bmi2(ctx *decompress1xContext) diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s index dd1a5ae..8d2187a 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s @@ -1,7 +1,6 @@ // Code generated by command: go run gen.go -out ../decompress_amd64.s -pkg=huff0. DO NOT EDIT. //go:build amd64 && !appengine && !noasm && gc -// +build amd64,!appengine,!noasm,gc // func decompress4x_main_loop_amd64(ctx *decompress4xContext) TEXT ·decompress4x_main_loop_amd64(SB), $0-8 diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go index 4f6f37c..908c17d 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go @@ -122,17 +122,21 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) { d.bufs.Put(buf) return nil, errors.New("corruption detected: stream overrun 1") } - copy(out, buf[0][:]) - copy(out[dstEvery:], buf[1][:]) - copy(out[dstEvery*2:], buf[2][:]) - copy(out[dstEvery*3:], buf[3][:]) - out = out[bufoff:] - decoded += bufoff * 4 // There must at least be 3 buffers left. - if len(out) < dstEvery*3 { + if len(out)-bufoff < dstEvery*3 { d.bufs.Put(buf) return nil, errors.New("corruption detected: stream overrun 2") } + //copy(out, buf[0][:]) + //copy(out[dstEvery:], buf[1][:]) + //copy(out[dstEvery*2:], buf[2][:]) + //copy(out[dstEvery*3:], buf[3][:]) + *(*[bufoff]byte)(out) = buf[0] + *(*[bufoff]byte)(out[dstEvery:]) = buf[1] + *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2] + *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3] + out = out[bufoff:] + decoded += bufoff * 4 } } if off > 0 { diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go index 511bba6..298c4f8 100644 --- a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go +++ b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go @@ -18,6 +18,7 @@ func load64(b []byte, i int) uint64 { // emitLiteral writes a literal chunk and returns the number of bytes written. // // It assumes that: +// // dst is long enough to hold the encoded bytes // 1 <= len(lit) && len(lit) <= 65536 func emitLiteral(dst, lit []byte) int { @@ -42,6 +43,7 @@ func emitLiteral(dst, lit []byte) int { // emitCopy writes a copy chunk and returns the number of bytes written. // // It assumes that: +// // dst is long enough to hold the encoded bytes // 1 <= offset && offset <= 65535 // 4 <= length && length <= 65535 @@ -89,6 +91,7 @@ func emitCopy(dst []byte, offset, length int) int { // src[i:i+k-j] and src[j:k] have the same contents. // // It assumes that: +// // 0 <= i && i < j && j <= len(src) func extendMatch(src []byte, i, j int) int { for ; j < len(src) && src[i] == src[j]; i, j = i+1, j+1 { @@ -105,8 +108,9 @@ func hash(u, shift uint32) uint32 { // been written. // // It also assumes that: +// // len(dst) >= MaxEncodedLen(len(src)) && -// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize +// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize func encodeBlock(dst, src []byte) (d int) { // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive. // The table element type is uint16, as s < sLimit and sLimit < len(src) diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md index beb7fa8..65b38ab 100644 --- a/vendor/github.com/klauspost/compress/zstd/README.md +++ b/vendor/github.com/klauspost/compress/zstd/README.md @@ -12,6 +12,8 @@ The `zstd` package is provided as open source software using a Go standard licen Currently the package is heavily optimized for 64 bit processors and will be significantly slower on 32 bit processors. +For seekable zstd streams, see [this excellent package](https://github.com/SaveTheRbtz/zstd-seekable-format-go). + ## Installation Install using `go get -u github.com/klauspost/compress`. The package is located in `github.com/klauspost/compress/zstd`. diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go index 7eed729..f52d1ae 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockdec.go +++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "path/filepath" "sync" @@ -651,7 +650,7 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) { fatalErr(binary.Write(&buf, binary.LittleEndian, hist.decoders.matchLengths.fse)) fatalErr(binary.Write(&buf, binary.LittleEndian, hist.decoders.offsets.fse)) buf.Write(in) - ioutil.WriteFile(filepath.Join("testdata", "seqs", fn), buf.Bytes(), os.ModePerm) + os.WriteFile(filepath.Join("testdata", "seqs", fn), buf.Bytes(), os.ModePerm) } return nil diff --git a/vendor/github.com/klauspost/compress/zstd/bytebuf.go b/vendor/github.com/klauspost/compress/zstd/bytebuf.go index 2ad0207..176788f 100644 --- a/vendor/github.com/klauspost/compress/zstd/bytebuf.go +++ b/vendor/github.com/klauspost/compress/zstd/bytebuf.go @@ -7,7 +7,6 @@ package zstd import ( "fmt" "io" - "io/ioutil" ) type byteBuffer interface { @@ -124,7 +123,7 @@ func (r *readerWrapper) readByte() (byte, error) { } func (r *readerWrapper) skipN(n int64) error { - n2, err := io.CopyN(ioutil.Discard, r.r, n) + n2, err := io.CopyN(io.Discard, r.r, n) if n2 != n { err = io.ErrUnexpectedEOF } diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go index d212f47..6104eb7 100644 --- a/vendor/github.com/klauspost/compress/zstd/decoder.go +++ b/vendor/github.com/klauspost/compress/zstd/decoder.go @@ -312,6 +312,7 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { // Grab a block decoder and frame decoder. block := <-d.decoders frame := block.localFrame + initialSize := len(dst) defer func() { if debugDecoder { printf("re-adding decoder: %p", block) @@ -354,7 +355,16 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { return dst, ErrWindowSizeExceeded } if frame.FrameContentSize != fcsUnknown { - if frame.FrameContentSize > d.o.maxDecodedSize-uint64(len(dst)) { + if frame.FrameContentSize > d.o.maxDecodedSize-uint64(len(dst)-initialSize) { + if debugDecoder { + println("decoder size exceeded; fcs:", frame.FrameContentSize, "> mcs:", d.o.maxDecodedSize-uint64(len(dst)-initialSize), "len:", len(dst)) + } + return dst, ErrDecoderSizeExceeded + } + if d.o.limitToCap && frame.FrameContentSize > uint64(cap(dst)-len(dst)) { + if debugDecoder { + println("decoder size exceeded; fcs:", frame.FrameContentSize, "> (cap-len)", cap(dst)-len(dst)) + } return dst, ErrDecoderSizeExceeded } if cap(dst)-len(dst) < int(frame.FrameContentSize) { @@ -364,7 +374,7 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { } } - if cap(dst) == 0 { + if cap(dst) == 0 && !d.o.limitToCap { // Allocate len(input) * 2 by default if nothing is provided // and we didn't get frame content size. size := len(input) * 2 @@ -382,6 +392,9 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { if err != nil { return dst, err } + if uint64(len(dst)-initialSize) > d.o.maxDecodedSize { + return dst, ErrDecoderSizeExceeded + } if len(frame.bBuf) == 0 { if debugDecoder { println("frame dbuf empty") @@ -852,6 +865,10 @@ decodeStream: } } if err == nil && d.frame.WindowSize > d.o.maxWindowSize { + if debugDecoder { + println("decoder size exceeded, fws:", d.frame.WindowSize, "> mws:", d.o.maxWindowSize) + } + err = ErrDecoderSizeExceeded } if err != nil { diff --git a/vendor/github.com/klauspost/compress/zstd/decoder_options.go b/vendor/github.com/klauspost/compress/zstd/decoder_options.go index c70e6fa..666c271 100644 --- a/vendor/github.com/klauspost/compress/zstd/decoder_options.go +++ b/vendor/github.com/klauspost/compress/zstd/decoder_options.go @@ -20,6 +20,7 @@ type decoderOptions struct { maxWindowSize uint64 dicts []dict ignoreChecksum bool + limitToCap bool } func (o *decoderOptions) setDefault() { @@ -114,6 +115,17 @@ func WithDecoderMaxWindow(size uint64) DOption { } } +// WithDecodeAllCapLimit will limit DecodeAll to decoding cap(dst)-len(dst) bytes, +// or any size set in WithDecoderMaxMemory. +// This can be used to limit decoding to a specific maximum output size. +// Disabled by default. +func WithDecodeAllCapLimit(b bool) DOption { + return func(o *decoderOptions) error { + o.limitToCap = b + return nil + } +} + // IgnoreChecksum allows to forcibly ignore checksum checking. func IgnoreChecksum(b bool) DOption { return func(o *decoderOptions) error { diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go index c769f69..d70e3fd 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_better.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go @@ -416,15 +416,23 @@ encodeLoop: // Try to find a better match by searching for a long match at the end of the current best match if s+matched < sLimit { + // Allow some bytes at the beginning to mismatch. + // Sweet spot is around 3 bytes, but depends on input. + // The skipped bytes are tested in Extend backwards, + // and still picked up as part of the match if they do. + const skipBeginning = 3 + nextHashL := hashLen(load6432(src, s+matched), betterLongTableBits, betterLongLen) - cv := load3232(src, s) + s2 := s + skipBeginning + cv := load3232(src, s2) candidateL := e.longTable[nextHashL] - coffsetL := candidateL.offset - e.cur - matched - if coffsetL >= 0 && coffsetL < s && s-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) { + coffsetL := candidateL.offset - e.cur - matched + skipBeginning + if coffsetL >= 0 && coffsetL < s2 && s2-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) { // Found a long match, at least 4 bytes. - matchedNext := e.matchlen(s+4, coffsetL+4, src) + 4 + matchedNext := e.matchlen(s2+4, coffsetL+4, src) + 4 if matchedNext > matched { t = coffsetL + s = s2 matched = matchedNext if debugMatches { println("long match at end-of-match") @@ -434,12 +442,13 @@ encodeLoop: // Check prev long... if true { - coffsetL = candidateL.prev - e.cur - matched - if coffsetL >= 0 && coffsetL < s && s-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) { + coffsetL = candidateL.prev - e.cur - matched + skipBeginning + if coffsetL >= 0 && coffsetL < s2 && s2-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) { // Found a long match, at least 4 bytes. - matchedNext := e.matchlen(s+4, coffsetL+4, src) + 4 + matchedNext := e.matchlen(s2+4, coffsetL+4, src) + 4 if matchedNext > matched { t = coffsetL + s = s2 matched = matchedNext if debugMatches { println("prev long match at end-of-match") diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go index 7ff0c64..1f4a9a2 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go @@ -1103,7 +1103,8 @@ func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) { } if allDirty || dirtyShardCnt > dLongTableShardCnt/2 { - copy(e.longTable[:], e.dictLongTable) + //copy(e.longTable[:], e.dictLongTable) + e.longTable = *(*[dFastLongTableSize]tableEntry)(e.dictLongTable) for i := range e.longTableShardDirty { e.longTableShardDirty[i] = false } @@ -1114,7 +1115,9 @@ func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) { continue } - copy(e.longTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize], e.dictLongTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize]) + // copy(e.longTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize], e.dictLongTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize]) + *(*[dLongTableShardSize]tableEntry)(e.longTable[i*dLongTableShardSize:]) = *(*[dLongTableShardSize]tableEntry)(e.dictLongTable[i*dLongTableShardSize:]) + e.longTableShardDirty[i] = false } } diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go index f51ab52..181edc0 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_fast.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go @@ -871,7 +871,8 @@ func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) { const shardCnt = tableShardCnt const shardSize = tableShardSize if e.allDirty || dirtyShardCnt > shardCnt*4/6 { - copy(e.table[:], e.dictTable) + //copy(e.table[:], e.dictTable) + e.table = *(*[tableSize]tableEntry)(e.dictTable) for i := range e.tableShardDirty { e.tableShardDirty[i] = false } @@ -883,7 +884,8 @@ func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) { continue } - copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize]) + //copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize]) + *(*[shardSize]tableEntry)(e.table[i*shardSize:]) = *(*[shardSize]tableEntry)(e.dictTable[i*shardSize:]) e.tableShardDirty[i] = false } e.allDirty = false diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go index 9568a4b..1559a20 100644 --- a/vendor/github.com/klauspost/compress/zstd/framedec.go +++ b/vendor/github.com/klauspost/compress/zstd/framedec.go @@ -353,12 +353,23 @@ func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) { // Store input length, so we only check new data. crcStart := len(dst) d.history.decoders.maxSyncLen = 0 + if d.o.limitToCap { + d.history.decoders.maxSyncLen = uint64(cap(dst) - len(dst)) + } if d.FrameContentSize != fcsUnknown { - d.history.decoders.maxSyncLen = d.FrameContentSize + uint64(len(dst)) + if !d.o.limitToCap || d.FrameContentSize+uint64(len(dst)) < d.history.decoders.maxSyncLen { + d.history.decoders.maxSyncLen = d.FrameContentSize + uint64(len(dst)) + } if d.history.decoders.maxSyncLen > d.o.maxDecodedSize { + if debugDecoder { + println("maxSyncLen:", d.history.decoders.maxSyncLen, "> maxDecodedSize:", d.o.maxDecodedSize) + } return dst, ErrDecoderSizeExceeded } - if uint64(cap(dst)) < d.history.decoders.maxSyncLen { + if debugDecoder { + println("maxSyncLen:", d.history.decoders.maxSyncLen) + } + if !d.o.limitToCap && uint64(cap(dst)-len(dst)) < d.history.decoders.maxSyncLen { // Alloc for output dst2 := make([]byte, len(dst), d.history.decoders.maxSyncLen+compressedBlockOverAlloc) copy(dst2, dst) @@ -378,7 +389,13 @@ func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) { if err != nil { break } - if uint64(len(d.history.b)) > d.o.maxDecodedSize { + if uint64(len(d.history.b)-crcStart) > d.o.maxDecodedSize { + println("runDecoder: maxDecodedSize exceeded", uint64(len(d.history.b)-crcStart), ">", d.o.maxDecodedSize) + err = ErrDecoderSizeExceeded + break + } + if d.o.limitToCap && len(d.history.b) > cap(dst) { + println("runDecoder: cap exceeded", uint64(len(d.history.b)), ">", cap(dst)) err = ErrDecoderSizeExceeded break } diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s index da32b44..bcde398 100644 --- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s @@ -1,7 +1,6 @@ // Code generated by command: go run gen_fse.go -out ../fse_decoder_amd64.s -pkg=zstd. DO NOT EDIT. //go:build !appengine && !noasm && gc && !noasm -// +build !appengine,!noasm,gc,!noasm // func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int TEXT ·buildDtable_asm(SB), $0-24 diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go index 7598c10..1c704d3 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go @@ -32,18 +32,22 @@ type decodeSyncAsmContext struct { // sequenceDecs_decodeSync_amd64 implements the main loop of sequenceDecs.decodeSync in x86 asm. // // Please refer to seqdec_generic.go for the reference implementation. +// //go:noescape func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // sequenceDecs_decodeSync_bmi2 implements the main loop of sequenceDecs.decodeSync in x86 asm with BMI2 extensions. +// //go:noescape func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // sequenceDecs_decodeSync_safe_amd64 does the same as above, but does not write more than output buffer. +// //go:noescape func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int // sequenceDecs_decodeSync_safe_bmi2 does the same as above, but does not write more than output buffer. +// //go:noescape func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int @@ -201,20 +205,24 @@ const errorNotEnoughSpace = 5 // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm. // // Please refer to seqdec_generic.go for the reference implementation. +// //go:noescape func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm. // // Please refer to seqdec_generic.go for the reference implementation. +// //go:noescape func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions. +// //go:noescape func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions. +// //go:noescape func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int @@ -308,10 +316,12 @@ type executeAsmContext struct { // Returns false if a match offset is too big. // // Please refer to seqdec_generic.go for the reference implementation. +// //go:noescape func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool // Same as above, but with safe memcopies +// //go:noescape func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s index 27e7677..52e5703 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s @@ -1,7 +1,6 @@ // Code generated by command: go run gen.go -out ../seqdec_amd64.s -pkg=zstd. DO NOT EDIT. //go:build !appengine && !noasm && gc && !noasm -// +build !appengine,!noasm,gc,!noasm // func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: CMOV diff --git a/vendor/github.com/oschwald/geoip2-golang/.gitignore b/vendor/github.com/oschwald/geoip2-golang/.gitignore new file mode 100644 index 0000000..dca0694 --- /dev/null +++ b/vendor/github.com/oschwald/geoip2-golang/.gitignore @@ -0,0 +1,3 @@ +.vscode +*.out +*.test diff --git a/vendor/github.com/oschwald/geoip2-golang/.gitmodules b/vendor/github.com/oschwald/geoip2-golang/.gitmodules new file mode 100644 index 0000000..400b2ab --- /dev/null +++ b/vendor/github.com/oschwald/geoip2-golang/.gitmodules @@ -0,0 +1,3 @@ +[submodule "test-data"] + path = test-data + url = https://github.com/maxmind/MaxMind-DB.git diff --git a/vendor/github.com/oschwald/geoip2-golang/.golangci.toml b/vendor/github.com/oschwald/geoip2-golang/.golangci.toml new file mode 100644 index 0000000..b4f7e6a --- /dev/null +++ b/vendor/github.com/oschwald/geoip2-golang/.golangci.toml @@ -0,0 +1,472 @@ +[run] + deadline = "10m" + + tests = true + +[linters] + disable-all = true + enable = [ + "asciicheck", + "bidichk", + "bodyclose", + "containedctx", + "contextcheck", + "deadcode", + "depguard", + "durationcheck", + "errcheck", + "errchkjson", + "errname", + "errorlint", + "exportloopref", + "forbidigo", + #"forcetypeassert", + "goconst", + "gocyclo", + "gocritic", + "godot", + "gofumpt", + "gomodguard", + "gosec", + "gosimple", + "govet", + "grouper", + "ineffassign", + "lll", + "makezero", + "maintidx", + "misspell", + "nakedret", + "nilerr", + "noctx", + "nolintlint", + "nosprintfhostport", + "predeclared", + "revive", + "rowserrcheck", + "sqlclosecheck", + "staticcheck", + "structcheck", + "stylecheck", + "tenv", + "tparallel", + "typecheck", + "unconvert", + "unparam", + "unused", + "varcheck", + "vetshadow", + "wastedassign", + ] + +# Please note that we only use depguard for stdlib as gomodguard only +# supports modules currently. See https://github.com/ryancurrah/gomodguard/issues/12 +[linters-settings.depguard] + list-type = "blacklist" + include-go-root = true + packages = [ + # ioutil is deprecated. The functions have been moved elsewhere: + # https://golang.org/doc/go1.16#ioutil + "io/ioutil", + ] + +[linters-settings.errcheck] + # Don't allow setting of error to the blank identifier. If there is a legtimate + # reason, there should be a nolint with an explanation. + check-blank = true + + exclude-functions = [ + # If we are rolling back a transaction, we are often already in an error + # state. + '(*database/sql.Tx).Rollback', + + # It is reasonable to ignore errors if Cleanup fails in most cases. + '(*github.com/google/renameio/v2.PendingFile).Cleanup', + + # We often don't care if removing a file failed (e.g., it doesn't exist) + 'os.Remove', + 'os.RemoveAll', + ] + + # Ignoring Close so that we don't have to have a bunch of + # `defer func() { _ = r.Close() }()` constructs when we + # don't actually care about the error. + ignore = "Close,fmt:.*" + +[linters-settings.errorlint] + errorf = true + asserts = true + comparison = true + +[linters-settings.exhaustive] + default-signifies-exhaustive = true + +[linters-settings.forbidigo] + # Forbid the following identifiers + forbid = [ + "^minFraud*", + "^maxMind*", + ] + +[linters-settings.gocritic] + enabled-checks = [ + "appendAssign", + "appendCombine", + "argOrder", + "assignOp", + "badCall", + "badCond", + "badLock", + "badRegexp", + "badSorting", + "boolExprSimplify", + "builtinShadow", + "builtinShadowDecl", + "captLocal", + "caseOrder", + "codegenComment", + "commentedOutCode", + "commentedOutImport", + "commentFormatting", + "defaultCaseOrder", + # Revive's defer rule already captures this. This caught no extra cases. + # "deferInLoop", + "deferUnlambda", + "deprecatedComment", + "docStub", + "dupArg", + "dupBranchBody", + "dupCase", + "dupImport", + "dupSubExpr", + "dynamicFmtString", + "elseif", + "emptyDecl", + "emptyFallthrough", + "emptyStringTest", + "equalFold", + "evalOrder", + "exitAfterDefer", + "exposedSyncMutex", + "externalErrorReassign", + # Given that all of our code runs on Linux and the / separate should + # work fine, this seems less important. + # "filepathJoin", + "flagDeref", + "flagName", + "hexLiteral", + "ifElseChain", + "importShadow", + "indexAlloc", + "initClause", + "ioutilDeprecated", + "mapKey", + "methodExprCall", + "nestingReduce", + "newDeref", + "nilValReturn", + "octalLiteral", + "offBy1", + "paramTypeCombine", + "preferDecodeRune", + "preferFilepathJoin", + "preferFprint", + "preferStringWriter", + "preferWriteByte", + "ptrToRefParam", + "rangeExprCopy", + "rangeValCopy", + "redundantSprint", + "regexpMust", + "regexpPattern", + # This might be good, but I don't think we want to encourage + # significant changes to regexes as we port stuff from Perl. + # "regexpSimplify", + "ruleguard", + "singleCaseSwitch", + "sliceClear", + "sloppyLen", + # This seems like it might also be good, but a lot of existing code + # fails. + # "sloppyReassign", + "returnAfterHttpError", + "sloppyTypeAssert", + "sortSlice", + "sprintfQuotedString", + "sqlQuery", + "stringsCompare", + "stringXbytes", + "switchTrue", + "syncMapLoadAndDelete", + "timeExprSimplify", + "todoCommentWithoutDetail", + "tooManyResultsChecker", + "truncateCmp", + "typeAssertChain", + "typeDefFirst", + "typeSwitchVar", + "typeUnparen", + "underef", + "unlabelStmt", + "unlambda", + # I am not sure we would want this linter and a lot of existing + # code fails. + # "unnamedResult", + "unnecessaryBlock", + "unnecessaryDefer", + "unslice", + "valSwap", + "weakCond", + "wrapperFunc", + "yodaStyleExpr", + # This requires explanations for "nolint" directives. This would be + # nice for gosec ones, but I am not sure we want it generally unless + # we can get the false positive rate lower. + # "whyNoLint" + ] + +[linters-settings.gofumpt] + extra-rules = true + lang-version = "1.18" + +[linters-settings.govet] + "enable-all" = true + +[linters-settings.lll] + line-length = 120 + tab-width = 4 + +[linters-settings.nolintlint] + allow-leading-space = false + allow-unused = false + allow-no-explanation = ["lll", "misspell"] + require-explanation = true + require-specific = true + +[linters-settings.revive] + ignore-generated-header = true + severity = "warning" + + # This might be nice but it is so common that it is hard + # to enable. + # [[linters-settings.revive.rules]] + # name = "add-constant" + + # [[linters-settings.revive.rules]] + # name = "argument-limit" + + [[linters-settings.revive.rules]] + name = "atomic" + + [[linters-settings.revive.rules]] + name = "bare-return" + + [[linters-settings.revive.rules]] + name = "blank-imports" + + [[linters-settings.revive.rules]] + name = "bool-literal-in-expr" + + [[linters-settings.revive.rules]] + name = "call-to-gc" + + # [[linters-settings.revive.rules]] + # name = "cognitive-complexity" + + # Probably a good rule, but we have a lot of names that + # only have case differences. + # [[linters-settings.revive.rules]] + # name = "confusing-naming" + + # [[linters-settings.revive.rules]] + # name = "confusing-results" + + [[linters-settings.revive.rules]] + name = "constant-logical-expr" + + [[linters-settings.revive.rules]] + name = "context-as-argument" + + [[linters-settings.revive.rules]] + name = "context-keys-type" + + # [[linters-settings.revive.rules]] + # name = "cyclomatic" + + # [[linters-settings.revive.rules]] + # name = "deep-exit" + + [[linters-settings.revive.rules]] + name = "defer" + + [[linters-settings.revive.rules]] + name = "dot-imports" + + [[linters-settings.revive.rules]] + name = "duplicated-imports" + + [[linters-settings.revive.rules]] + name = "early-return" + + [[linters-settings.revive.rules]] + name = "empty-block" + + [[linters-settings.revive.rules]] + name = "empty-lines" + + [[linters-settings.revive.rules]] + name = "errorf" + + [[linters-settings.revive.rules]] + name = "error-naming" + + [[linters-settings.revive.rules]] + name = "error-return" + + [[linters-settings.revive.rules]] + name = "error-strings" + + [[linters-settings.revive.rules]] + name = "exported" + + # [[linters-settings.revive.rules]] + # name = "file-header" + + # We have a lot of flag parameters. This linter probably makes + # a good point, but we would need some cleanup or a lot of nolints. + # [[linters-settings.revive.rules]] + # name = "flag-parameter" + + # [[linters-settings.revive.rules]] + # name = "function-result-limit" + + [[linters-settings.revive.rules]] + name = "get-return" + + [[linters-settings.revive.rules]] + name = "identical-branches" + + [[linters-settings.revive.rules]] + name = "if-return" + + [[linters-settings.revive.rules]] + name = "imports-blacklist" + + [[linters-settings.revive.rules]] + name = "import-shadowing" + + [[linters-settings.revive.rules]] + name = "increment-decrement" + + [[linters-settings.revive.rules]] + name = "indent-error-flow" + + # [[linters-settings.revive.rules]] + # name = "line-length-limit" + + # [[linters-settings.revive.rules]] + # name = "max-public-structs" + + [[linters-settings.revive.rules]] + name = "modifies-parameter" + + [[linters-settings.revive.rules]] + name = "modifies-value-receiver" + + # We frequently use nested structs, particularly in tests. + # [[linters-settings.revive.rules]] + # name = "nested-structs" + + [[linters-settings.revive.rules]] + name = "optimize-operands-order" + + [[linters-settings.revive.rules]] + name = "package-comments" + + [[linters-settings.revive.rules]] + name = "range" + + [[linters-settings.revive.rules]] + name = "range-val-address" + + [[linters-settings.revive.rules]] + name = "range-val-in-closure" + + [[linters-settings.revive.rules]] + name = "receiver-naming" + + [[linters-settings.revive.rules]] + name = "redefines-builtin-id" + + [[linters-settings.revive.rules]] + name = "string-of-int" + + [[linters-settings.revive.rules]] + name = "struct-tag" + + [[linters-settings.revive.rules]] + name = "superfluous-else" + + [[linters-settings.revive.rules]] + name = "time-naming" + + [[linters-settings.revive.rules]] + name = "unconditional-recursion" + + [[linters-settings.revive.rules]] + name = "unexported-naming" + + [[linters-settings.revive.rules]] + name = "unexported-return" + + # This is covered elsewhere and we want to ignore some + # functions such as fmt.Fprintf. + # [[linters-settings.revive.rules]] + # name = "unhandled-error" + + [[linters-settings.revive.rules]] + name = "unnecessary-stmt" + + [[linters-settings.revive.rules]] + name = "unreachable-code" + + [[linters-settings.revive.rules]] + name = "unused-parameter" + + # We generally have unused receivers in tests for meeting the + # requirements of an interface. + # [[linters-settings.revive.rules]] + # name = "unused-receiver" + + # This probably makes sense after we upgrade to 1.18 + # [[linters-settings.revive.rules]] + # name = "use-any" + + [[linters-settings.revive.rules]] + name = "useless-break" + + [[linters-settings.revive.rules]] + name = "var-declaration" + + [[linters-settings.revive.rules]] + name = "var-naming" + + [[linters-settings.revive.rules]] + name = "waitgroup-by-value" + +[linters-settings.unparam] + check-exported = true + +[[issues.exclude-rules]] + linters = [ + "govet" + ] + # we want to enable almost all govet rules. It is easier to just filter out + # the ones we don't want: + # + # * fieldalignment - way too noisy. Although it is very useful in particular + # cases where we are trying to use as little memory as possible, having + # it go off on every struct isn't helpful. + # * shadow - although often useful, it complains about _many_ err + # shadowing assignments and some others where shadowing is clear. + text = "^(fieldalignment|shadow)" diff --git a/vendor/github.com/oschwald/geoip2-golang/LICENSE b/vendor/github.com/oschwald/geoip2-golang/LICENSE new file mode 100644 index 0000000..2969677 --- /dev/null +++ b/vendor/github.com/oschwald/geoip2-golang/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2015, Gregory J. Oschwald + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/oschwald/geoip2-golang/README.md b/vendor/github.com/oschwald/geoip2-golang/README.md new file mode 100644 index 0000000..72378f0 --- /dev/null +++ b/vendor/github.com/oschwald/geoip2-golang/README.md @@ -0,0 +1,93 @@ +# GeoIP2 Reader for Go # + +[![PkgGoDev](https://pkg.go.dev/badge/github.com/oschwald/geoip2-golang)](https://pkg.go.dev/github.com/oschwald/geoip2-golang) + +This library reads MaxMind [GeoLite2](http://dev.maxmind.com/geoip/geoip2/geolite2/) +and [GeoIP2](http://www.maxmind.com/en/geolocation_landing) databases. + +This library is built using +[the Go maxminddb reader](https://github.com/oschwald/maxminddb-golang). +All data for the database record is decoded using this library. If you only +need several fields, you may get superior performance by using maxminddb's +`Lookup` directly with a result struct that only contains the required fields. +(See [example_test.go](https://github.com/oschwald/maxminddb-golang/blob/main/example_test.go) +in the maxminddb repository for an example of this.) + +## Installation ## + +``` +go get github.com/oschwald/geoip2-golang +``` + +## Usage ## + +[See GoDoc](http://godoc.org/github.com/oschwald/geoip2-golang) for +documentation and examples. + +## Example ## + +```go +package main + +import ( + "fmt" + "log" + "net" + + "github.com/oschwald/geoip2-golang" +) + +func main() { + db, err := geoip2.Open("GeoIP2-City.mmdb") + if err != nil { + log.Fatal(err) + } + defer db.Close() + // If you are using strings that may be invalid, check that ip is not nil + ip := net.ParseIP("81.2.69.142") + record, err := db.City(ip) + if err != nil { + log.Fatal(err) + } + fmt.Printf("Portuguese (BR) city name: %v\n", record.City.Names["pt-BR"]) + if len(record.Subdivisions) > 0 { + fmt.Printf("English subdivision name: %v\n", record.Subdivisions[0].Names["en"]) + } + fmt.Printf("Russian country name: %v\n", record.Country.Names["ru"]) + fmt.Printf("ISO country code: %v\n", record.Country.IsoCode) + fmt.Printf("Time zone: %v\n", record.Location.TimeZone) + fmt.Printf("Coordinates: %v, %v\n", record.Location.Latitude, record.Location.Longitude) + // Output: + // Portuguese (BR) city name: Londres + // English subdivision name: England + // Russian country name: Великобритания + // ISO country code: GB + // Time zone: Europe/London + // Coordinates: 51.5142, -0.0931 +} + +``` + +## Testing ## + +Make sure you checked out test data submodule: + +``` +git submodule init +git submodule update +``` + +Execute test suite: + +``` +go test +``` + +## Contributing ## + +Contributions welcome! Please fork the repository and open a pull request +with your changes. + +## License ## + +This is free software, licensed under the ISC license. diff --git a/vendor/github.com/oschwald/geoip2-golang/reader.go b/vendor/github.com/oschwald/geoip2-golang/reader.go new file mode 100644 index 0000000..f8439ec --- /dev/null +++ b/vendor/github.com/oschwald/geoip2-golang/reader.go @@ -0,0 +1,418 @@ +// Package geoip2 provides an easy-to-use API for the MaxMind GeoIP2 and +// GeoLite2 databases; this package does not support GeoIP Legacy databases. +// +// The structs provided by this package match the internal structure of +// the data in the MaxMind databases. +// +// See github.com/oschwald/maxminddb-golang for more advanced used cases. +package geoip2 + +import ( + "fmt" + "net" + + "github.com/oschwald/maxminddb-golang" +) + +// The Enterprise struct corresponds to the data in the GeoIP2 Enterprise +// database. +type Enterprise struct { + City struct { + Confidence uint8 `maxminddb:"confidence"` + GeoNameID uint `maxminddb:"geoname_id"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"city"` + Continent struct { + Code string `maxminddb:"code"` + GeoNameID uint `maxminddb:"geoname_id"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"continent"` + Country struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + Confidence uint8 `maxminddb:"confidence"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + } `maxminddb:"country"` + Location struct { + AccuracyRadius uint16 `maxminddb:"accuracy_radius"` + Latitude float64 `maxminddb:"latitude"` + Longitude float64 `maxminddb:"longitude"` + MetroCode uint `maxminddb:"metro_code"` + TimeZone string `maxminddb:"time_zone"` + } `maxminddb:"location"` + Postal struct { + Code string `maxminddb:"code"` + Confidence uint8 `maxminddb:"confidence"` + } `maxminddb:"postal"` + RegisteredCountry struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + Confidence uint8 `maxminddb:"confidence"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + } `maxminddb:"registered_country"` + RepresentedCountry struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + Type string `maxminddb:"type"` + } `maxminddb:"represented_country"` + Subdivisions []struct { + Confidence uint8 `maxminddb:"confidence"` + GeoNameID uint `maxminddb:"geoname_id"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"subdivisions"` + Traits struct { + AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"` + AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"` + ConnectionType string `maxminddb:"connection_type"` + Domain string `maxminddb:"domain"` + IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"` + IsLegitimateProxy bool `maxminddb:"is_legitimate_proxy"` + IsSatelliteProvider bool `maxminddb:"is_satellite_provider"` + ISP string `maxminddb:"isp"` + MobileCountryCode string `maxminddb:"mobile_country_code"` + MobileNetworkCode string `maxminddb:"mobile_network_code"` + Organization string `maxminddb:"organization"` + StaticIPScore float64 `maxminddb:"static_ip_score"` + UserType string `maxminddb:"user_type"` + } `maxminddb:"traits"` +} + +// The City struct corresponds to the data in the GeoIP2/GeoLite2 City +// databases. +type City struct { + City struct { + GeoNameID uint `maxminddb:"geoname_id"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"city"` + Continent struct { + Code string `maxminddb:"code"` + GeoNameID uint `maxminddb:"geoname_id"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"continent"` + Country struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"country"` + Location struct { + AccuracyRadius uint16 `maxminddb:"accuracy_radius"` + Latitude float64 `maxminddb:"latitude"` + Longitude float64 `maxminddb:"longitude"` + MetroCode uint `maxminddb:"metro_code"` + TimeZone string `maxminddb:"time_zone"` + } `maxminddb:"location"` + Postal struct { + Code string `maxminddb:"code"` + } `maxminddb:"postal"` + RegisteredCountry struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"registered_country"` + RepresentedCountry struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + Type string `maxminddb:"type"` + } `maxminddb:"represented_country"` + Subdivisions []struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"subdivisions"` + Traits struct { + IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"` + IsSatelliteProvider bool `maxminddb:"is_satellite_provider"` + } `maxminddb:"traits"` +} + +// The Country struct corresponds to the data in the GeoIP2/GeoLite2 +// Country databases. +type Country struct { + Continent struct { + Code string `maxminddb:"code"` + GeoNameID uint `maxminddb:"geoname_id"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"continent"` + Country struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"country"` + RegisteredCountry struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + } `maxminddb:"registered_country"` + RepresentedCountry struct { + GeoNameID uint `maxminddb:"geoname_id"` + IsInEuropeanUnion bool `maxminddb:"is_in_european_union"` + IsoCode string `maxminddb:"iso_code"` + Names map[string]string `maxminddb:"names"` + Type string `maxminddb:"type"` + } `maxminddb:"represented_country"` + Traits struct { + IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"` + IsSatelliteProvider bool `maxminddb:"is_satellite_provider"` + } `maxminddb:"traits"` +} + +// The AnonymousIP struct corresponds to the data in the GeoIP2 +// Anonymous IP database. +type AnonymousIP struct { + IsAnonymous bool `maxminddb:"is_anonymous"` + IsAnonymousVPN bool `maxminddb:"is_anonymous_vpn"` + IsHostingProvider bool `maxminddb:"is_hosting_provider"` + IsPublicProxy bool `maxminddb:"is_public_proxy"` + IsResidentialProxy bool `maxminddb:"is_residential_proxy"` + IsTorExitNode bool `maxminddb:"is_tor_exit_node"` +} + +// The ASN struct corresponds to the data in the GeoLite2 ASN database. +type ASN struct { + AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"` + AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"` +} + +// The ConnectionType struct corresponds to the data in the GeoIP2 +// Connection-Type database. +type ConnectionType struct { + ConnectionType string `maxminddb:"connection_type"` +} + +// The Domain struct corresponds to the data in the GeoIP2 Domain database. +type Domain struct { + Domain string `maxminddb:"domain"` +} + +// The ISP struct corresponds to the data in the GeoIP2 ISP database. +type ISP struct { + AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"` + AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"` + ISP string `maxminddb:"isp"` + MobileCountryCode string `maxminddb:"mobile_country_code"` + MobileNetworkCode string `maxminddb:"mobile_network_code"` + Organization string `maxminddb:"organization"` +} + +type databaseType int + +const ( + isAnonymousIP = 1 << iota + isASN + isCity + isConnectionType + isCountry + isDomain + isEnterprise + isISP +) + +// Reader holds the maxminddb.Reader struct. It can be created using the +// Open and FromBytes functions. +type Reader struct { + mmdbReader *maxminddb.Reader + databaseType databaseType +} + +// InvalidMethodError is returned when a lookup method is called on a +// database that it does not support. For instance, calling the ISP method +// on a City database. +type InvalidMethodError struct { + Method string + DatabaseType string +} + +func (e InvalidMethodError) Error() string { + return fmt.Sprintf(`geoip2: the %s method does not support the %s database`, + e.Method, e.DatabaseType) +} + +// UnknownDatabaseTypeError is returned when an unknown database type is +// opened. +type UnknownDatabaseTypeError struct { + DatabaseType string +} + +func (e UnknownDatabaseTypeError) Error() string { + return fmt.Sprintf(`geoip2: reader does not support the %q database type`, + e.DatabaseType) +} + +// Open takes a string path to a file and returns a Reader struct or an error. +// The database file is opened using a memory map. Use the Close method on the +// Reader object to return the resources to the system. +func Open(file string) (*Reader, error) { + reader, err := maxminddb.Open(file) + if err != nil { + return nil, err + } + dbType, err := getDBType(reader) + return &Reader{reader, dbType}, err +} + +// FromBytes takes a byte slice corresponding to a GeoIP2/GeoLite2 database +// file and returns a Reader struct or an error. Note that the byte slice is +// used directly; any modification of it after opening the database will result +// in errors while reading from the database. +func FromBytes(bytes []byte) (*Reader, error) { + reader, err := maxminddb.FromBytes(bytes) + if err != nil { + return nil, err + } + dbType, err := getDBType(reader) + return &Reader{reader, dbType}, err +} + +func getDBType(reader *maxminddb.Reader) (databaseType, error) { + switch reader.Metadata.DatabaseType { + case "GeoIP2-Anonymous-IP": + return isAnonymousIP, nil + case "DBIP-ASN-Lite (compat=GeoLite2-ASN)", + "GeoLite2-ASN": + return isASN, nil + // We allow City lookups on Country for back compat + case "DBIP-City-Lite", + "DBIP-Country-Lite", + "DBIP-Country", + "DBIP-Location (compat=City)", + "GeoLite2-City", + "GeoIP2-City", + "GeoIP2-City-Africa", + "GeoIP2-City-Asia-Pacific", + "GeoIP2-City-Europe", + "GeoIP2-City-North-America", + "GeoIP2-City-South-America", + "GeoIP2-Precision-City", + "GeoLite2-Country", + "GeoIP2-Country": + return isCity | isCountry, nil + case "GeoIP2-Connection-Type": + return isConnectionType, nil + case "GeoIP2-Domain": + return isDomain, nil + case "DBIP-ISP (compat=Enterprise)", + "DBIP-Location-ISP (compat=Enterprise)", + "GeoIP2-Enterprise": + return isEnterprise | isCity | isCountry, nil + case "GeoIP2-ISP", + "GeoIP2-Precision-ISP": + return isISP | isASN, nil + default: + return 0, UnknownDatabaseTypeError{reader.Metadata.DatabaseType} + } +} + +// Enterprise takes an IP address as a net.IP struct and returns an Enterprise +// struct and/or an error. This is intended to be used with the GeoIP2 +// Enterprise database. +func (r *Reader) Enterprise(ipAddress net.IP) (*Enterprise, error) { + if isEnterprise&r.databaseType == 0 { + return nil, InvalidMethodError{"Enterprise", r.Metadata().DatabaseType} + } + var enterprise Enterprise + err := r.mmdbReader.Lookup(ipAddress, &enterprise) + return &enterprise, err +} + +// City takes an IP address as a net.IP struct and returns a City struct +// and/or an error. Although this can be used with other databases, this +// method generally should be used with the GeoIP2 or GeoLite2 City databases. +func (r *Reader) City(ipAddress net.IP) (*City, error) { + if isCity&r.databaseType == 0 { + return nil, InvalidMethodError{"City", r.Metadata().DatabaseType} + } + var city City + err := r.mmdbReader.Lookup(ipAddress, &city) + return &city, err +} + +// Country takes an IP address as a net.IP struct and returns a Country struct +// and/or an error. Although this can be used with other databases, this +// method generally should be used with the GeoIP2 or GeoLite2 Country +// databases. +func (r *Reader) Country(ipAddress net.IP) (*Country, error) { + if isCountry&r.databaseType == 0 { + return nil, InvalidMethodError{"Country", r.Metadata().DatabaseType} + } + var country Country + err := r.mmdbReader.Lookup(ipAddress, &country) + return &country, err +} + +// AnonymousIP takes an IP address as a net.IP struct and returns a +// AnonymousIP struct and/or an error. +func (r *Reader) AnonymousIP(ipAddress net.IP) (*AnonymousIP, error) { + if isAnonymousIP&r.databaseType == 0 { + return nil, InvalidMethodError{"AnonymousIP", r.Metadata().DatabaseType} + } + var anonIP AnonymousIP + err := r.mmdbReader.Lookup(ipAddress, &anonIP) + return &anonIP, err +} + +// ASN takes an IP address as a net.IP struct and returns a ASN struct and/or +// an error. +func (r *Reader) ASN(ipAddress net.IP) (*ASN, error) { + if isASN&r.databaseType == 0 { + return nil, InvalidMethodError{"ASN", r.Metadata().DatabaseType} + } + var val ASN + err := r.mmdbReader.Lookup(ipAddress, &val) + return &val, err +} + +// ConnectionType takes an IP address as a net.IP struct and returns a +// ConnectionType struct and/or an error. +func (r *Reader) ConnectionType(ipAddress net.IP) (*ConnectionType, error) { + if isConnectionType&r.databaseType == 0 { + return nil, InvalidMethodError{"ConnectionType", r.Metadata().DatabaseType} + } + var val ConnectionType + err := r.mmdbReader.Lookup(ipAddress, &val) + return &val, err +} + +// Domain takes an IP address as a net.IP struct and returns a +// Domain struct and/or an error. +func (r *Reader) Domain(ipAddress net.IP) (*Domain, error) { + if isDomain&r.databaseType == 0 { + return nil, InvalidMethodError{"Domain", r.Metadata().DatabaseType} + } + var val Domain + err := r.mmdbReader.Lookup(ipAddress, &val) + return &val, err +} + +// ISP takes an IP address as a net.IP struct and returns a ISP struct and/or +// an error. +func (r *Reader) ISP(ipAddress net.IP) (*ISP, error) { + if isISP&r.databaseType == 0 { + return nil, InvalidMethodError{"ISP", r.Metadata().DatabaseType} + } + var val ISP + err := r.mmdbReader.Lookup(ipAddress, &val) + return &val, err +} + +// Metadata takes no arguments and returns a struct containing metadata about +// the MaxMind database in use by the Reader. +func (r *Reader) Metadata() maxminddb.Metadata { + return r.mmdbReader.Metadata +} + +// Close unmaps the database file from virtual memory and returns the +// resources to the system. +func (r *Reader) Close() error { + return r.mmdbReader.Close() +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/.gitignore b/vendor/github.com/oschwald/maxminddb-golang/.gitignore new file mode 100644 index 0000000..fe3fa4a --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/.gitignore @@ -0,0 +1,4 @@ +.vscode +*.out +*.sw? +*.test diff --git a/vendor/github.com/oschwald/maxminddb-golang/.gitmodules b/vendor/github.com/oschwald/maxminddb-golang/.gitmodules new file mode 100644 index 0000000..400b2ab --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/.gitmodules @@ -0,0 +1,3 @@ +[submodule "test-data"] + path = test-data + url = https://github.com/maxmind/MaxMind-DB.git diff --git a/vendor/github.com/oschwald/maxminddb-golang/.golangci.toml b/vendor/github.com/oschwald/maxminddb-golang/.golangci.toml new file mode 100644 index 0000000..b4f7e6a --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/.golangci.toml @@ -0,0 +1,472 @@ +[run] + deadline = "10m" + + tests = true + +[linters] + disable-all = true + enable = [ + "asciicheck", + "bidichk", + "bodyclose", + "containedctx", + "contextcheck", + "deadcode", + "depguard", + "durationcheck", + "errcheck", + "errchkjson", + "errname", + "errorlint", + "exportloopref", + "forbidigo", + #"forcetypeassert", + "goconst", + "gocyclo", + "gocritic", + "godot", + "gofumpt", + "gomodguard", + "gosec", + "gosimple", + "govet", + "grouper", + "ineffassign", + "lll", + "makezero", + "maintidx", + "misspell", + "nakedret", + "nilerr", + "noctx", + "nolintlint", + "nosprintfhostport", + "predeclared", + "revive", + "rowserrcheck", + "sqlclosecheck", + "staticcheck", + "structcheck", + "stylecheck", + "tenv", + "tparallel", + "typecheck", + "unconvert", + "unparam", + "unused", + "varcheck", + "vetshadow", + "wastedassign", + ] + +# Please note that we only use depguard for stdlib as gomodguard only +# supports modules currently. See https://github.com/ryancurrah/gomodguard/issues/12 +[linters-settings.depguard] + list-type = "blacklist" + include-go-root = true + packages = [ + # ioutil is deprecated. The functions have been moved elsewhere: + # https://golang.org/doc/go1.16#ioutil + "io/ioutil", + ] + +[linters-settings.errcheck] + # Don't allow setting of error to the blank identifier. If there is a legtimate + # reason, there should be a nolint with an explanation. + check-blank = true + + exclude-functions = [ + # If we are rolling back a transaction, we are often already in an error + # state. + '(*database/sql.Tx).Rollback', + + # It is reasonable to ignore errors if Cleanup fails in most cases. + '(*github.com/google/renameio/v2.PendingFile).Cleanup', + + # We often don't care if removing a file failed (e.g., it doesn't exist) + 'os.Remove', + 'os.RemoveAll', + ] + + # Ignoring Close so that we don't have to have a bunch of + # `defer func() { _ = r.Close() }()` constructs when we + # don't actually care about the error. + ignore = "Close,fmt:.*" + +[linters-settings.errorlint] + errorf = true + asserts = true + comparison = true + +[linters-settings.exhaustive] + default-signifies-exhaustive = true + +[linters-settings.forbidigo] + # Forbid the following identifiers + forbid = [ + "^minFraud*", + "^maxMind*", + ] + +[linters-settings.gocritic] + enabled-checks = [ + "appendAssign", + "appendCombine", + "argOrder", + "assignOp", + "badCall", + "badCond", + "badLock", + "badRegexp", + "badSorting", + "boolExprSimplify", + "builtinShadow", + "builtinShadowDecl", + "captLocal", + "caseOrder", + "codegenComment", + "commentedOutCode", + "commentedOutImport", + "commentFormatting", + "defaultCaseOrder", + # Revive's defer rule already captures this. This caught no extra cases. + # "deferInLoop", + "deferUnlambda", + "deprecatedComment", + "docStub", + "dupArg", + "dupBranchBody", + "dupCase", + "dupImport", + "dupSubExpr", + "dynamicFmtString", + "elseif", + "emptyDecl", + "emptyFallthrough", + "emptyStringTest", + "equalFold", + "evalOrder", + "exitAfterDefer", + "exposedSyncMutex", + "externalErrorReassign", + # Given that all of our code runs on Linux and the / separate should + # work fine, this seems less important. + # "filepathJoin", + "flagDeref", + "flagName", + "hexLiteral", + "ifElseChain", + "importShadow", + "indexAlloc", + "initClause", + "ioutilDeprecated", + "mapKey", + "methodExprCall", + "nestingReduce", + "newDeref", + "nilValReturn", + "octalLiteral", + "offBy1", + "paramTypeCombine", + "preferDecodeRune", + "preferFilepathJoin", + "preferFprint", + "preferStringWriter", + "preferWriteByte", + "ptrToRefParam", + "rangeExprCopy", + "rangeValCopy", + "redundantSprint", + "regexpMust", + "regexpPattern", + # This might be good, but I don't think we want to encourage + # significant changes to regexes as we port stuff from Perl. + # "regexpSimplify", + "ruleguard", + "singleCaseSwitch", + "sliceClear", + "sloppyLen", + # This seems like it might also be good, but a lot of existing code + # fails. + # "sloppyReassign", + "returnAfterHttpError", + "sloppyTypeAssert", + "sortSlice", + "sprintfQuotedString", + "sqlQuery", + "stringsCompare", + "stringXbytes", + "switchTrue", + "syncMapLoadAndDelete", + "timeExprSimplify", + "todoCommentWithoutDetail", + "tooManyResultsChecker", + "truncateCmp", + "typeAssertChain", + "typeDefFirst", + "typeSwitchVar", + "typeUnparen", + "underef", + "unlabelStmt", + "unlambda", + # I am not sure we would want this linter and a lot of existing + # code fails. + # "unnamedResult", + "unnecessaryBlock", + "unnecessaryDefer", + "unslice", + "valSwap", + "weakCond", + "wrapperFunc", + "yodaStyleExpr", + # This requires explanations for "nolint" directives. This would be + # nice for gosec ones, but I am not sure we want it generally unless + # we can get the false positive rate lower. + # "whyNoLint" + ] + +[linters-settings.gofumpt] + extra-rules = true + lang-version = "1.18" + +[linters-settings.govet] + "enable-all" = true + +[linters-settings.lll] + line-length = 120 + tab-width = 4 + +[linters-settings.nolintlint] + allow-leading-space = false + allow-unused = false + allow-no-explanation = ["lll", "misspell"] + require-explanation = true + require-specific = true + +[linters-settings.revive] + ignore-generated-header = true + severity = "warning" + + # This might be nice but it is so common that it is hard + # to enable. + # [[linters-settings.revive.rules]] + # name = "add-constant" + + # [[linters-settings.revive.rules]] + # name = "argument-limit" + + [[linters-settings.revive.rules]] + name = "atomic" + + [[linters-settings.revive.rules]] + name = "bare-return" + + [[linters-settings.revive.rules]] + name = "blank-imports" + + [[linters-settings.revive.rules]] + name = "bool-literal-in-expr" + + [[linters-settings.revive.rules]] + name = "call-to-gc" + + # [[linters-settings.revive.rules]] + # name = "cognitive-complexity" + + # Probably a good rule, but we have a lot of names that + # only have case differences. + # [[linters-settings.revive.rules]] + # name = "confusing-naming" + + # [[linters-settings.revive.rules]] + # name = "confusing-results" + + [[linters-settings.revive.rules]] + name = "constant-logical-expr" + + [[linters-settings.revive.rules]] + name = "context-as-argument" + + [[linters-settings.revive.rules]] + name = "context-keys-type" + + # [[linters-settings.revive.rules]] + # name = "cyclomatic" + + # [[linters-settings.revive.rules]] + # name = "deep-exit" + + [[linters-settings.revive.rules]] + name = "defer" + + [[linters-settings.revive.rules]] + name = "dot-imports" + + [[linters-settings.revive.rules]] + name = "duplicated-imports" + + [[linters-settings.revive.rules]] + name = "early-return" + + [[linters-settings.revive.rules]] + name = "empty-block" + + [[linters-settings.revive.rules]] + name = "empty-lines" + + [[linters-settings.revive.rules]] + name = "errorf" + + [[linters-settings.revive.rules]] + name = "error-naming" + + [[linters-settings.revive.rules]] + name = "error-return" + + [[linters-settings.revive.rules]] + name = "error-strings" + + [[linters-settings.revive.rules]] + name = "exported" + + # [[linters-settings.revive.rules]] + # name = "file-header" + + # We have a lot of flag parameters. This linter probably makes + # a good point, but we would need some cleanup or a lot of nolints. + # [[linters-settings.revive.rules]] + # name = "flag-parameter" + + # [[linters-settings.revive.rules]] + # name = "function-result-limit" + + [[linters-settings.revive.rules]] + name = "get-return" + + [[linters-settings.revive.rules]] + name = "identical-branches" + + [[linters-settings.revive.rules]] + name = "if-return" + + [[linters-settings.revive.rules]] + name = "imports-blacklist" + + [[linters-settings.revive.rules]] + name = "import-shadowing" + + [[linters-settings.revive.rules]] + name = "increment-decrement" + + [[linters-settings.revive.rules]] + name = "indent-error-flow" + + # [[linters-settings.revive.rules]] + # name = "line-length-limit" + + # [[linters-settings.revive.rules]] + # name = "max-public-structs" + + [[linters-settings.revive.rules]] + name = "modifies-parameter" + + [[linters-settings.revive.rules]] + name = "modifies-value-receiver" + + # We frequently use nested structs, particularly in tests. + # [[linters-settings.revive.rules]] + # name = "nested-structs" + + [[linters-settings.revive.rules]] + name = "optimize-operands-order" + + [[linters-settings.revive.rules]] + name = "package-comments" + + [[linters-settings.revive.rules]] + name = "range" + + [[linters-settings.revive.rules]] + name = "range-val-address" + + [[linters-settings.revive.rules]] + name = "range-val-in-closure" + + [[linters-settings.revive.rules]] + name = "receiver-naming" + + [[linters-settings.revive.rules]] + name = "redefines-builtin-id" + + [[linters-settings.revive.rules]] + name = "string-of-int" + + [[linters-settings.revive.rules]] + name = "struct-tag" + + [[linters-settings.revive.rules]] + name = "superfluous-else" + + [[linters-settings.revive.rules]] + name = "time-naming" + + [[linters-settings.revive.rules]] + name = "unconditional-recursion" + + [[linters-settings.revive.rules]] + name = "unexported-naming" + + [[linters-settings.revive.rules]] + name = "unexported-return" + + # This is covered elsewhere and we want to ignore some + # functions such as fmt.Fprintf. + # [[linters-settings.revive.rules]] + # name = "unhandled-error" + + [[linters-settings.revive.rules]] + name = "unnecessary-stmt" + + [[linters-settings.revive.rules]] + name = "unreachable-code" + + [[linters-settings.revive.rules]] + name = "unused-parameter" + + # We generally have unused receivers in tests for meeting the + # requirements of an interface. + # [[linters-settings.revive.rules]] + # name = "unused-receiver" + + # This probably makes sense after we upgrade to 1.18 + # [[linters-settings.revive.rules]] + # name = "use-any" + + [[linters-settings.revive.rules]] + name = "useless-break" + + [[linters-settings.revive.rules]] + name = "var-declaration" + + [[linters-settings.revive.rules]] + name = "var-naming" + + [[linters-settings.revive.rules]] + name = "waitgroup-by-value" + +[linters-settings.unparam] + check-exported = true + +[[issues.exclude-rules]] + linters = [ + "govet" + ] + # we want to enable almost all govet rules. It is easier to just filter out + # the ones we don't want: + # + # * fieldalignment - way too noisy. Although it is very useful in particular + # cases where we are trying to use as little memory as possible, having + # it go off on every struct isn't helpful. + # * shadow - although often useful, it complains about _many_ err + # shadowing assignments and some others where shadowing is clear. + text = "^(fieldalignment|shadow)" diff --git a/vendor/github.com/oschwald/maxminddb-golang/LICENSE b/vendor/github.com/oschwald/maxminddb-golang/LICENSE new file mode 100644 index 0000000..2969677 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2015, Gregory J. Oschwald + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/oschwald/maxminddb-golang/README.md b/vendor/github.com/oschwald/maxminddb-golang/README.md new file mode 100644 index 0000000..9662888 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/README.md @@ -0,0 +1,36 @@ +# MaxMind DB Reader for Go # + +[![GoDoc](https://godoc.org/github.com/oschwald/maxminddb-golang?status.svg)](https://godoc.org/github.com/oschwald/maxminddb-golang) + +This is a Go reader for the MaxMind DB format. Although this can be used to +read [GeoLite2](http://dev.maxmind.com/geoip/geoip2/geolite2/) and +[GeoIP2](https://www.maxmind.com/en/geoip2-databases) databases, +[geoip2](https://github.com/oschwald/geoip2-golang) provides a higher-level +API for doing so. + +This is not an official MaxMind API. + +## Installation ## + +``` +go get github.com/oschwald/maxminddb-golang +``` + +## Usage ## + +[See GoDoc](http://godoc.org/github.com/oschwald/maxminddb-golang) for +documentation and examples. + +## Examples ## + +See [GoDoc](http://godoc.org/github.com/oschwald/maxminddb-golang) or +`example_test.go` for examples. + +## Contributing ## + +Contributions welcome! Please fork the repository and open a pull request +with your changes. + +## License ## + +This is free software, licensed under the ISC License. diff --git a/vendor/github.com/oschwald/maxminddb-golang/decoder.go b/vendor/github.com/oschwald/maxminddb-golang/decoder.go new file mode 100644 index 0000000..828c57f --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/decoder.go @@ -0,0 +1,897 @@ +package maxminddb + +import ( + "encoding/binary" + "math" + "math/big" + "reflect" + "sync" +) + +type decoder struct { + buffer []byte +} + +type dataType int + +const ( + _Extended dataType = iota + _Pointer + _String + _Float64 + _Bytes + _Uint16 + _Uint32 + _Map + _Int32 + _Uint64 + _Uint128 + _Slice + // We don't use the next two. They are placeholders. See the spec + // for more details. + _Container //nolint: deadcode, varcheck // above + _Marker //nolint: deadcode, varcheck // above + _Bool + _Float32 +) + +const ( + // This is the value used in libmaxminddb. + maximumDataStructureDepth = 512 +) + +func (d *decoder) decode(offset uint, result reflect.Value, depth int) (uint, error) { + if depth > maximumDataStructureDepth { + return 0, newInvalidDatabaseError( + "exceeded maximum data structure depth; database is likely corrupt", + ) + } + typeNum, size, newOffset, err := d.decodeCtrlData(offset) + if err != nil { + return 0, err + } + + if typeNum != _Pointer && result.Kind() == reflect.Uintptr { + result.Set(reflect.ValueOf(uintptr(offset))) + return d.nextValueOffset(offset, 1) + } + return d.decodeFromType(typeNum, size, newOffset, result, depth+1) +} + +func (d *decoder) decodeToDeserializer( + offset uint, + dser deserializer, + depth int, + getNext bool, +) (uint, error) { + if depth > maximumDataStructureDepth { + return 0, newInvalidDatabaseError( + "exceeded maximum data structure depth; database is likely corrupt", + ) + } + skip, err := dser.ShouldSkip(uintptr(offset)) + if err != nil { + return 0, err + } + if skip { + if getNext { + return d.nextValueOffset(offset, 1) + } + return 0, nil + } + + typeNum, size, newOffset, err := d.decodeCtrlData(offset) + if err != nil { + return 0, err + } + + return d.decodeFromTypeToDeserializer(typeNum, size, newOffset, dser, depth+1) +} + +func (d *decoder) decodeCtrlData(offset uint) (dataType, uint, uint, error) { + newOffset := offset + 1 + if offset >= uint(len(d.buffer)) { + return 0, 0, 0, newOffsetError() + } + ctrlByte := d.buffer[offset] + + typeNum := dataType(ctrlByte >> 5) + if typeNum == _Extended { + if newOffset >= uint(len(d.buffer)) { + return 0, 0, 0, newOffsetError() + } + typeNum = dataType(d.buffer[newOffset] + 7) + newOffset++ + } + + var size uint + size, newOffset, err := d.sizeFromCtrlByte(ctrlByte, newOffset, typeNum) + return typeNum, size, newOffset, err +} + +func (d *decoder) sizeFromCtrlByte( + ctrlByte byte, + offset uint, + typeNum dataType, +) (uint, uint, error) { + size := uint(ctrlByte & 0x1f) + if typeNum == _Extended { + return size, offset, nil + } + + var bytesToRead uint + if size < 29 { + return size, offset, nil + } + + bytesToRead = size - 28 + newOffset := offset + bytesToRead + if newOffset > uint(len(d.buffer)) { + return 0, 0, newOffsetError() + } + if size == 29 { + return 29 + uint(d.buffer[offset]), offset + 1, nil + } + + sizeBytes := d.buffer[offset:newOffset] + + switch { + case size == 30: + size = 285 + uintFromBytes(0, sizeBytes) + case size > 30: + size = uintFromBytes(0, sizeBytes) + 65821 + } + return size, newOffset, nil +} + +func (d *decoder) decodeFromType( + dtype dataType, + size uint, + offset uint, + result reflect.Value, + depth int, +) (uint, error) { + result = d.indirect(result) + + // For these types, size has a special meaning + switch dtype { + case _Bool: + return d.unmarshalBool(size, offset, result) + case _Map: + return d.unmarshalMap(size, offset, result, depth) + case _Pointer: + return d.unmarshalPointer(size, offset, result, depth) + case _Slice: + return d.unmarshalSlice(size, offset, result, depth) + } + + // For the remaining types, size is the byte size + if offset+size > uint(len(d.buffer)) { + return 0, newOffsetError() + } + switch dtype { + case _Bytes: + return d.unmarshalBytes(size, offset, result) + case _Float32: + return d.unmarshalFloat32(size, offset, result) + case _Float64: + return d.unmarshalFloat64(size, offset, result) + case _Int32: + return d.unmarshalInt32(size, offset, result) + case _String: + return d.unmarshalString(size, offset, result) + case _Uint16: + return d.unmarshalUint(size, offset, result, 16) + case _Uint32: + return d.unmarshalUint(size, offset, result, 32) + case _Uint64: + return d.unmarshalUint(size, offset, result, 64) + case _Uint128: + return d.unmarshalUint128(size, offset, result) + default: + return 0, newInvalidDatabaseError("unknown type: %d", dtype) + } +} + +func (d *decoder) decodeFromTypeToDeserializer( + dtype dataType, + size uint, + offset uint, + dser deserializer, + depth int, +) (uint, error) { + // For these types, size has a special meaning + switch dtype { + case _Bool: + v, offset := d.decodeBool(size, offset) + return offset, dser.Bool(v) + case _Map: + return d.decodeMapToDeserializer(size, offset, dser, depth) + case _Pointer: + pointer, newOffset, err := d.decodePointer(size, offset) + if err != nil { + return 0, err + } + _, err = d.decodeToDeserializer(pointer, dser, depth, false) + return newOffset, err + case _Slice: + return d.decodeSliceToDeserializer(size, offset, dser, depth) + } + + // For the remaining types, size is the byte size + if offset+size > uint(len(d.buffer)) { + return 0, newOffsetError() + } + switch dtype { + case _Bytes: + v, offset := d.decodeBytes(size, offset) + return offset, dser.Bytes(v) + case _Float32: + v, offset := d.decodeFloat32(size, offset) + return offset, dser.Float32(v) + case _Float64: + v, offset := d.decodeFloat64(size, offset) + return offset, dser.Float64(v) + case _Int32: + v, offset := d.decodeInt(size, offset) + return offset, dser.Int32(int32(v)) + case _String: + v, offset := d.decodeString(size, offset) + return offset, dser.String(v) + case _Uint16: + v, offset := d.decodeUint(size, offset) + return offset, dser.Uint16(uint16(v)) + case _Uint32: + v, offset := d.decodeUint(size, offset) + return offset, dser.Uint32(uint32(v)) + case _Uint64: + v, offset := d.decodeUint(size, offset) + return offset, dser.Uint64(v) + case _Uint128: + v, offset := d.decodeUint128(size, offset) + return offset, dser.Uint128(v) + default: + return 0, newInvalidDatabaseError("unknown type: %d", dtype) + } +} + +func (d *decoder) unmarshalBool(size, offset uint, result reflect.Value) (uint, error) { + if size > 1 { + return 0, newInvalidDatabaseError( + "the MaxMind DB file's data section contains bad data (bool size of %v)", + size, + ) + } + value, newOffset := d.decodeBool(size, offset) + + switch result.Kind() { + case reflect.Bool: + result.SetBool(value) + return newOffset, nil + case reflect.Interface: + if result.NumMethod() == 0 { + result.Set(reflect.ValueOf(value)) + return newOffset, nil + } + } + return newOffset, newUnmarshalTypeError(value, result.Type()) +} + +// indirect follows pointers and create values as necessary. This is +// heavily based on encoding/json as my original version had a subtle +// bug. This method should be considered to be licensed under +// https://golang.org/LICENSE +func (d *decoder) indirect(result reflect.Value) reflect.Value { + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if result.Kind() == reflect.Interface && !result.IsNil() { + e := result.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() { + result = e + continue + } + } + + if result.Kind() != reflect.Ptr { + break + } + + if result.IsNil() { + result.Set(reflect.New(result.Type().Elem())) + } + + result = result.Elem() + } + return result +} + +var sliceType = reflect.TypeOf([]byte{}) + +func (d *decoder) unmarshalBytes(size, offset uint, result reflect.Value) (uint, error) { + value, newOffset := d.decodeBytes(size, offset) + + switch result.Kind() { + case reflect.Slice: + if result.Type() == sliceType { + result.SetBytes(value) + return newOffset, nil + } + case reflect.Interface: + if result.NumMethod() == 0 { + result.Set(reflect.ValueOf(value)) + return newOffset, nil + } + } + return newOffset, newUnmarshalTypeError(value, result.Type()) +} + +func (d *decoder) unmarshalFloat32(size, offset uint, result reflect.Value) (uint, error) { + if size != 4 { + return 0, newInvalidDatabaseError( + "the MaxMind DB file's data section contains bad data (float32 size of %v)", + size, + ) + } + value, newOffset := d.decodeFloat32(size, offset) + + switch result.Kind() { + case reflect.Float32, reflect.Float64: + result.SetFloat(float64(value)) + return newOffset, nil + case reflect.Interface: + if result.NumMethod() == 0 { + result.Set(reflect.ValueOf(value)) + return newOffset, nil + } + } + return newOffset, newUnmarshalTypeError(value, result.Type()) +} + +func (d *decoder) unmarshalFloat64(size, offset uint, result reflect.Value) (uint, error) { + if size != 8 { + return 0, newInvalidDatabaseError( + "the MaxMind DB file's data section contains bad data (float 64 size of %v)", + size, + ) + } + value, newOffset := d.decodeFloat64(size, offset) + + switch result.Kind() { + case reflect.Float32, reflect.Float64: + if result.OverflowFloat(value) { + return 0, newUnmarshalTypeError(value, result.Type()) + } + result.SetFloat(value) + return newOffset, nil + case reflect.Interface: + if result.NumMethod() == 0 { + result.Set(reflect.ValueOf(value)) + return newOffset, nil + } + } + return newOffset, newUnmarshalTypeError(value, result.Type()) +} + +func (d *decoder) unmarshalInt32(size, offset uint, result reflect.Value) (uint, error) { + if size > 4 { + return 0, newInvalidDatabaseError( + "the MaxMind DB file's data section contains bad data (int32 size of %v)", + size, + ) + } + value, newOffset := d.decodeInt(size, offset) + + switch result.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n := int64(value) + if !result.OverflowInt(n) { + result.SetInt(n) + return newOffset, nil + } + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr: + n := uint64(value) + if !result.OverflowUint(n) { + result.SetUint(n) + return newOffset, nil + } + case reflect.Interface: + if result.NumMethod() == 0 { + result.Set(reflect.ValueOf(value)) + return newOffset, nil + } + } + return newOffset, newUnmarshalTypeError(value, result.Type()) +} + +func (d *decoder) unmarshalMap( + size uint, + offset uint, + result reflect.Value, + depth int, +) (uint, error) { + result = d.indirect(result) + switch result.Kind() { + default: + return 0, newUnmarshalTypeError("map", result.Type()) + case reflect.Struct: + return d.decodeStruct(size, offset, result, depth) + case reflect.Map: + return d.decodeMap(size, offset, result, depth) + case reflect.Interface: + if result.NumMethod() == 0 { + rv := reflect.ValueOf(make(map[string]interface{}, size)) + newOffset, err := d.decodeMap(size, offset, rv, depth) + result.Set(rv) + return newOffset, err + } + return 0, newUnmarshalTypeError("map", result.Type()) + } +} + +func (d *decoder) unmarshalPointer( + size, offset uint, + result reflect.Value, + depth int, +) (uint, error) { + pointer, newOffset, err := d.decodePointer(size, offset) + if err != nil { + return 0, err + } + _, err = d.decode(pointer, result, depth) + return newOffset, err +} + +func (d *decoder) unmarshalSlice( + size uint, + offset uint, + result reflect.Value, + depth int, +) (uint, error) { + switch result.Kind() { + case reflect.Slice: + return d.decodeSlice(size, offset, result, depth) + case reflect.Interface: + if result.NumMethod() == 0 { + a := []interface{}{} + rv := reflect.ValueOf(&a).Elem() + newOffset, err := d.decodeSlice(size, offset, rv, depth) + result.Set(rv) + return newOffset, err + } + } + return 0, newUnmarshalTypeError("array", result.Type()) +} + +func (d *decoder) unmarshalString(size, offset uint, result reflect.Value) (uint, error) { + value, newOffset := d.decodeString(size, offset) + + switch result.Kind() { + case reflect.String: + result.SetString(value) + return newOffset, nil + case reflect.Interface: + if result.NumMethod() == 0 { + result.Set(reflect.ValueOf(value)) + return newOffset, nil + } + } + return newOffset, newUnmarshalTypeError(value, result.Type()) +} + +func (d *decoder) unmarshalUint( + size, offset uint, + result reflect.Value, + uintType uint, +) (uint, error) { + if size > uintType/8 { + return 0, newInvalidDatabaseError( + "the MaxMind DB file's data section contains bad data (uint%v size of %v)", + uintType, + size, + ) + } + + value, newOffset := d.decodeUint(size, offset) + + switch result.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n := int64(value) + if !result.OverflowInt(n) { + result.SetInt(n) + return newOffset, nil + } + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr: + if !result.OverflowUint(value) { + result.SetUint(value) + return newOffset, nil + } + case reflect.Interface: + if result.NumMethod() == 0 { + result.Set(reflect.ValueOf(value)) + return newOffset, nil + } + } + return newOffset, newUnmarshalTypeError(value, result.Type()) +} + +var bigIntType = reflect.TypeOf(big.Int{}) + +func (d *decoder) unmarshalUint128(size, offset uint, result reflect.Value) (uint, error) { + if size > 16 { + return 0, newInvalidDatabaseError( + "the MaxMind DB file's data section contains bad data (uint128 size of %v)", + size, + ) + } + value, newOffset := d.decodeUint128(size, offset) + + switch result.Kind() { + case reflect.Struct: + if result.Type() == bigIntType { + result.Set(reflect.ValueOf(*value)) + return newOffset, nil + } + case reflect.Interface: + if result.NumMethod() == 0 { + result.Set(reflect.ValueOf(value)) + return newOffset, nil + } + } + return newOffset, newUnmarshalTypeError(value, result.Type()) +} + +func (d *decoder) decodeBool(size, offset uint) (bool, uint) { + return size != 0, offset +} + +func (d *decoder) decodeBytes(size, offset uint) ([]byte, uint) { + newOffset := offset + size + bytes := make([]byte, size) + copy(bytes, d.buffer[offset:newOffset]) + return bytes, newOffset +} + +func (d *decoder) decodeFloat64(size, offset uint) (float64, uint) { + newOffset := offset + size + bits := binary.BigEndian.Uint64(d.buffer[offset:newOffset]) + return math.Float64frombits(bits), newOffset +} + +func (d *decoder) decodeFloat32(size, offset uint) (float32, uint) { + newOffset := offset + size + bits := binary.BigEndian.Uint32(d.buffer[offset:newOffset]) + return math.Float32frombits(bits), newOffset +} + +func (d *decoder) decodeInt(size, offset uint) (int, uint) { + newOffset := offset + size + var val int32 + for _, b := range d.buffer[offset:newOffset] { + val = (val << 8) | int32(b) + } + return int(val), newOffset +} + +func (d *decoder) decodeMap( + size uint, + offset uint, + result reflect.Value, + depth int, +) (uint, error) { + if result.IsNil() { + result.Set(reflect.MakeMapWithSize(result.Type(), int(size))) + } + + mapType := result.Type() + keyValue := reflect.New(mapType.Key()).Elem() + elemType := mapType.Elem() + elemKind := elemType.Kind() + var elemValue reflect.Value + for i := uint(0); i < size; i++ { + var key []byte + var err error + key, offset, err = d.decodeKey(offset) + + if err != nil { + return 0, err + } + + if !elemValue.IsValid() || elemKind == reflect.Interface { + elemValue = reflect.New(elemType).Elem() + } + + offset, err = d.decode(offset, elemValue, depth) + if err != nil { + return 0, err + } + + keyValue.SetString(string(key)) + result.SetMapIndex(keyValue, elemValue) + } + return offset, nil +} + +func (d *decoder) decodeMapToDeserializer( + size uint, + offset uint, + dser deserializer, + depth int, +) (uint, error) { + err := dser.StartMap(size) + if err != nil { + return 0, err + } + for i := uint(0); i < size; i++ { + // TODO - implement key/value skipping? + offset, err = d.decodeToDeserializer(offset, dser, depth, true) + if err != nil { + return 0, err + } + + offset, err = d.decodeToDeserializer(offset, dser, depth, true) + if err != nil { + return 0, err + } + } + err = dser.End() + if err != nil { + return 0, err + } + return offset, nil +} + +func (d *decoder) decodePointer( + size uint, + offset uint, +) (uint, uint, error) { + pointerSize := ((size >> 3) & 0x3) + 1 + newOffset := offset + pointerSize + if newOffset > uint(len(d.buffer)) { + return 0, 0, newOffsetError() + } + pointerBytes := d.buffer[offset:newOffset] + var prefix uint + if pointerSize == 4 { + prefix = 0 + } else { + prefix = size & 0x7 + } + unpacked := uintFromBytes(prefix, pointerBytes) + + var pointerValueOffset uint + switch pointerSize { + case 1: + pointerValueOffset = 0 + case 2: + pointerValueOffset = 2048 + case 3: + pointerValueOffset = 526336 + case 4: + pointerValueOffset = 0 + } + + pointer := unpacked + pointerValueOffset + + return pointer, newOffset, nil +} + +func (d *decoder) decodeSlice( + size uint, + offset uint, + result reflect.Value, + depth int, +) (uint, error) { + result.Set(reflect.MakeSlice(result.Type(), int(size), int(size))) + for i := 0; i < int(size); i++ { + var err error + offset, err = d.decode(offset, result.Index(i), depth) + if err != nil { + return 0, err + } + } + return offset, nil +} + +func (d *decoder) decodeSliceToDeserializer( + size uint, + offset uint, + dser deserializer, + depth int, +) (uint, error) { + err := dser.StartSlice(size) + if err != nil { + return 0, err + } + for i := uint(0); i < size; i++ { + offset, err = d.decodeToDeserializer(offset, dser, depth, true) + if err != nil { + return 0, err + } + } + err = dser.End() + if err != nil { + return 0, err + } + return offset, nil +} + +func (d *decoder) decodeString(size, offset uint) (string, uint) { + newOffset := offset + size + return string(d.buffer[offset:newOffset]), newOffset +} + +func (d *decoder) decodeStruct( + size uint, + offset uint, + result reflect.Value, + depth int, +) (uint, error) { + fields := cachedFields(result) + + // This fills in embedded structs + for _, i := range fields.anonymousFields { + _, err := d.unmarshalMap(size, offset, result.Field(i), depth) + if err != nil { + return 0, err + } + } + + // This handles named fields + for i := uint(0); i < size; i++ { + var ( + err error + key []byte + ) + key, offset, err = d.decodeKey(offset) + if err != nil { + return 0, err + } + // The string() does not create a copy due to this compiler + // optimization: https://github.com/golang/go/issues/3512 + j, ok := fields.namedFields[string(key)] + if !ok { + offset, err = d.nextValueOffset(offset, 1) + if err != nil { + return 0, err + } + continue + } + + offset, err = d.decode(offset, result.Field(j), depth) + if err != nil { + return 0, err + } + } + return offset, nil +} + +type fieldsType struct { + namedFields map[string]int + anonymousFields []int +} + +var fieldsMap sync.Map + +func cachedFields(result reflect.Value) *fieldsType { + resultType := result.Type() + + if fields, ok := fieldsMap.Load(resultType); ok { + return fields.(*fieldsType) + } + numFields := resultType.NumField() + namedFields := make(map[string]int, numFields) + var anonymous []int + for i := 0; i < numFields; i++ { + field := resultType.Field(i) + + fieldName := field.Name + if tag := field.Tag.Get("maxminddb"); tag != "" { + if tag == "-" { + continue + } + fieldName = tag + } + if field.Anonymous { + anonymous = append(anonymous, i) + continue + } + namedFields[fieldName] = i + } + fields := &fieldsType{namedFields, anonymous} + fieldsMap.Store(resultType, fields) + + return fields +} + +func (d *decoder) decodeUint(size, offset uint) (uint64, uint) { + newOffset := offset + size + bytes := d.buffer[offset:newOffset] + + var val uint64 + for _, b := range bytes { + val = (val << 8) | uint64(b) + } + return val, newOffset +} + +func (d *decoder) decodeUint128(size, offset uint) (*big.Int, uint) { + newOffset := offset + size + val := new(big.Int) + val.SetBytes(d.buffer[offset:newOffset]) + + return val, newOffset +} + +func uintFromBytes(prefix uint, uintBytes []byte) uint { + val := prefix + for _, b := range uintBytes { + val = (val << 8) | uint(b) + } + return val +} + +// decodeKey decodes a map key into []byte slice. We use a []byte so that we +// can take advantage of https://github.com/golang/go/issues/3512 to avoid +// copying the bytes when decoding a struct. Previously, we achieved this by +// using unsafe. +func (d *decoder) decodeKey(offset uint) ([]byte, uint, error) { + typeNum, size, dataOffset, err := d.decodeCtrlData(offset) + if err != nil { + return nil, 0, err + } + if typeNum == _Pointer { + pointer, ptrOffset, err := d.decodePointer(size, dataOffset) + if err != nil { + return nil, 0, err + } + key, _, err := d.decodeKey(pointer) + return key, ptrOffset, err + } + if typeNum != _String { + return nil, 0, newInvalidDatabaseError("unexpected type when decoding string: %v", typeNum) + } + newOffset := dataOffset + size + if newOffset > uint(len(d.buffer)) { + return nil, 0, newOffsetError() + } + return d.buffer[dataOffset:newOffset], newOffset, nil +} + +// This function is used to skip ahead to the next value without decoding +// the one at the offset passed in. The size bits have different meanings for +// different data types. +func (d *decoder) nextValueOffset(offset, numberToSkip uint) (uint, error) { + if numberToSkip == 0 { + return offset, nil + } + typeNum, size, offset, err := d.decodeCtrlData(offset) + if err != nil { + return 0, err + } + switch typeNum { + case _Pointer: + _, offset, err = d.decodePointer(size, offset) + if err != nil { + return 0, err + } + case _Map: + numberToSkip += 2 * size + case _Slice: + numberToSkip += size + case _Bool: + default: + offset += size + } + return d.nextValueOffset(offset, numberToSkip-1) +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/deserializer.go b/vendor/github.com/oschwald/maxminddb-golang/deserializer.go new file mode 100644 index 0000000..c6dd68d --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/deserializer.go @@ -0,0 +1,31 @@ +package maxminddb + +import "math/big" + +// deserializer is an interface for a type that deserializes an MaxMind DB +// data record to some other type. This exists as an alternative to the +// standard reflection API. +// +// This is fundamentally different than the Unmarshaler interface that +// several packages provide. A Deserializer will generally create the +// final struct or value rather than unmarshaling to itself. +// +// This interface and the associated unmarshaling code is EXPERIMENTAL! +// It is not currently covered by any Semantic Versioning guarantees. +// Use at your own risk. +type deserializer interface { + ShouldSkip(offset uintptr) (bool, error) + StartSlice(size uint) error + StartMap(size uint) error + End() error + String(string) error + Float64(float64) error + Bytes([]byte) error + Uint16(uint16) error + Uint32(uint32) error + Int32(int32) error + Uint64(uint64) error + Uint128(*big.Int) error + Bool(bool) error + Float32(float32) error +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/errors.go b/vendor/github.com/oschwald/maxminddb-golang/errors.go new file mode 100644 index 0000000..1327800 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/errors.go @@ -0,0 +1,42 @@ +package maxminddb + +import ( + "fmt" + "reflect" +) + +// InvalidDatabaseError is returned when the database contains invalid data +// and cannot be parsed. +type InvalidDatabaseError struct { + message string +} + +func newOffsetError() InvalidDatabaseError { + return InvalidDatabaseError{"unexpected end of database"} +} + +func newInvalidDatabaseError(format string, args ...interface{}) InvalidDatabaseError { + return InvalidDatabaseError{fmt.Sprintf(format, args...)} +} + +func (e InvalidDatabaseError) Error() string { + return e.message +} + +// UnmarshalTypeError is returned when the value in the database cannot be +// assigned to the specified data type. +type UnmarshalTypeError struct { + Value string // stringified copy of the database value that caused the error + Type reflect.Type // type of the value that could not be assign to +} + +func newUnmarshalTypeError(value interface{}, rType reflect.Type) UnmarshalTypeError { + return UnmarshalTypeError{ + Value: fmt.Sprintf("%v", value), + Type: rType, + } +} + +func (e UnmarshalTypeError) Error() string { + return fmt.Sprintf("maxminddb: cannot unmarshal %s into type %s", e.Value, e.Type.String()) +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/mmap_unix.go b/vendor/github.com/oschwald/maxminddb-golang/mmap_unix.go new file mode 100644 index 0000000..eeb2e05 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/mmap_unix.go @@ -0,0 +1,16 @@ +//go:build !windows && !appengine && !plan9 +// +build !windows,!appengine,!plan9 + +package maxminddb + +import ( + "golang.org/x/sys/unix" +) + +func mmap(fd, length int) (data []byte, err error) { + return unix.Mmap(fd, 0, length, unix.PROT_READ, unix.MAP_SHARED) +} + +func munmap(b []byte) (err error) { + return unix.Munmap(b) +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/mmap_windows.go b/vendor/github.com/oschwald/maxminddb-golang/mmap_windows.go new file mode 100644 index 0000000..661250e --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/mmap_windows.go @@ -0,0 +1,85 @@ +// +build windows,!appengine + +package maxminddb + +// Windows support largely borrowed from mmap-go. +// +// Copyright 2011 Evan Shaw. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +import ( + "errors" + "os" + "reflect" + "sync" + "unsafe" + + "golang.org/x/sys/windows" +) + +type memoryMap []byte + +// Windows +var handleLock sync.Mutex +var handleMap = map[uintptr]windows.Handle{} + +func mmap(fd int, length int) (data []byte, err error) { + h, errno := windows.CreateFileMapping(windows.Handle(fd), nil, + uint32(windows.PAGE_READONLY), 0, uint32(length), nil) + if h == 0 { + return nil, os.NewSyscallError("CreateFileMapping", errno) + } + + addr, errno := windows.MapViewOfFile(h, uint32(windows.FILE_MAP_READ), 0, + 0, uintptr(length)) + if addr == 0 { + return nil, os.NewSyscallError("MapViewOfFile", errno) + } + handleLock.Lock() + handleMap[addr] = h + handleLock.Unlock() + + m := memoryMap{} + dh := m.header() + dh.Data = addr + dh.Len = length + dh.Cap = dh.Len + + return m, nil +} + +func (m *memoryMap) header() *reflect.SliceHeader { + return (*reflect.SliceHeader)(unsafe.Pointer(m)) +} + +func flush(addr, len uintptr) error { + errno := windows.FlushViewOfFile(addr, len) + return os.NewSyscallError("FlushViewOfFile", errno) +} + +func munmap(b []byte) (err error) { + m := memoryMap(b) + dh := m.header() + + addr := dh.Data + length := uintptr(dh.Len) + + flush(addr, length) + err = windows.UnmapViewOfFile(addr) + if err != nil { + return err + } + + handleLock.Lock() + defer handleLock.Unlock() + handle, ok := handleMap[addr] + if !ok { + // should be impossible; we would've errored above + return errors.New("unknown base address") + } + delete(handleMap, addr) + + e := windows.CloseHandle(windows.Handle(handle)) + return os.NewSyscallError("CloseHandle", e) +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/node.go b/vendor/github.com/oschwald/maxminddb-golang/node.go new file mode 100644 index 0000000..16e8b5f --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/node.go @@ -0,0 +1,58 @@ +package maxminddb + +type nodeReader interface { + readLeft(uint) uint + readRight(uint) uint +} + +type nodeReader24 struct { + buffer []byte +} + +func (n nodeReader24) readLeft(nodeNumber uint) uint { + return (uint(n.buffer[nodeNumber]) << 16) | + (uint(n.buffer[nodeNumber+1]) << 8) | + uint(n.buffer[nodeNumber+2]) +} + +func (n nodeReader24) readRight(nodeNumber uint) uint { + return (uint(n.buffer[nodeNumber+3]) << 16) | + (uint(n.buffer[nodeNumber+4]) << 8) | + uint(n.buffer[nodeNumber+5]) +} + +type nodeReader28 struct { + buffer []byte +} + +func (n nodeReader28) readLeft(nodeNumber uint) uint { + return ((uint(n.buffer[nodeNumber+3]) & 0xF0) << 20) | + (uint(n.buffer[nodeNumber]) << 16) | + (uint(n.buffer[nodeNumber+1]) << 8) | + uint(n.buffer[nodeNumber+2]) +} + +func (n nodeReader28) readRight(nodeNumber uint) uint { + return ((uint(n.buffer[nodeNumber+3]) & 0x0F) << 24) | + (uint(n.buffer[nodeNumber+4]) << 16) | + (uint(n.buffer[nodeNumber+5]) << 8) | + uint(n.buffer[nodeNumber+6]) +} + +type nodeReader32 struct { + buffer []byte +} + +func (n nodeReader32) readLeft(nodeNumber uint) uint { + return (uint(n.buffer[nodeNumber]) << 24) | + (uint(n.buffer[nodeNumber+1]) << 16) | + (uint(n.buffer[nodeNumber+2]) << 8) | + uint(n.buffer[nodeNumber+3]) +} + +func (n nodeReader32) readRight(nodeNumber uint) uint { + return (uint(n.buffer[nodeNumber+4]) << 24) | + (uint(n.buffer[nodeNumber+5]) << 16) | + (uint(n.buffer[nodeNumber+6]) << 8) | + uint(n.buffer[nodeNumber+7]) +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/reader.go b/vendor/github.com/oschwald/maxminddb-golang/reader.go new file mode 100644 index 0000000..263cf64 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/reader.go @@ -0,0 +1,310 @@ +// Package maxminddb provides a reader for the MaxMind DB file format. +package maxminddb + +import ( + "bytes" + "errors" + "fmt" + "net" + "reflect" +) + +const ( + // NotFound is returned by LookupOffset when a matched root record offset + // cannot be found. + NotFound = ^uintptr(0) + + dataSectionSeparatorSize = 16 +) + +var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com") + +// Reader holds the data corresponding to the MaxMind DB file. Its only public +// field is Metadata, which contains the metadata from the MaxMind DB file. +// +// All of the methods on Reader are thread-safe. The struct may be safely +// shared across goroutines. +type Reader struct { + hasMappedFile bool + buffer []byte + nodeReader nodeReader + decoder decoder + Metadata Metadata + ipv4Start uint + ipv4StartBitDepth int + nodeOffsetMult uint +} + +// Metadata holds the metadata decoded from the MaxMind DB file. In particular +// it has the format version, the build time as Unix epoch time, the database +// type and description, the IP version supported, and a slice of the natural +// languages included. +type Metadata struct { + BinaryFormatMajorVersion uint `maxminddb:"binary_format_major_version"` + BinaryFormatMinorVersion uint `maxminddb:"binary_format_minor_version"` + BuildEpoch uint `maxminddb:"build_epoch"` + DatabaseType string `maxminddb:"database_type"` + Description map[string]string `maxminddb:"description"` + IPVersion uint `maxminddb:"ip_version"` + Languages []string `maxminddb:"languages"` + NodeCount uint `maxminddb:"node_count"` + RecordSize uint `maxminddb:"record_size"` +} + +// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns +// a Reader structure or an error. +func FromBytes(buffer []byte) (*Reader, error) { + metadataStart := bytes.LastIndex(buffer, metadataStartMarker) + + if metadataStart == -1 { + return nil, newInvalidDatabaseError("error opening database: invalid MaxMind DB file") + } + + metadataStart += len(metadataStartMarker) + metadataDecoder := decoder{buffer[metadataStart:]} + + var metadata Metadata + + rvMetdata := reflect.ValueOf(&metadata) + _, err := metadataDecoder.decode(0, rvMetdata, 0) + if err != nil { + return nil, err + } + + searchTreeSize := metadata.NodeCount * metadata.RecordSize / 4 + dataSectionStart := searchTreeSize + dataSectionSeparatorSize + dataSectionEnd := uint(metadataStart - len(metadataStartMarker)) + if dataSectionStart > dataSectionEnd { + return nil, newInvalidDatabaseError("the MaxMind DB contains invalid metadata") + } + d := decoder{ + buffer[searchTreeSize+dataSectionSeparatorSize : metadataStart-len(metadataStartMarker)], + } + + nodeBuffer := buffer[:searchTreeSize] + var nodeReader nodeReader + switch metadata.RecordSize { + case 24: + nodeReader = nodeReader24{buffer: nodeBuffer} + case 28: + nodeReader = nodeReader28{buffer: nodeBuffer} + case 32: + nodeReader = nodeReader32{buffer: nodeBuffer} + default: + return nil, newInvalidDatabaseError("unknown record size: %d", metadata.RecordSize) + } + + reader := &Reader{ + buffer: buffer, + nodeReader: nodeReader, + decoder: d, + Metadata: metadata, + ipv4Start: 0, + nodeOffsetMult: metadata.RecordSize / 4, + } + + reader.setIPv4Start() + + return reader, err +} + +func (r *Reader) setIPv4Start() { + if r.Metadata.IPVersion != 6 { + return + } + + nodeCount := r.Metadata.NodeCount + + node := uint(0) + i := 0 + for ; i < 96 && node < nodeCount; i++ { + node = r.nodeReader.readLeft(node * r.nodeOffsetMult) + } + r.ipv4Start = node + r.ipv4StartBitDepth = i +} + +// Lookup retrieves the database record for ip and stores it in the value +// pointed to by result. If result is nil or not a pointer, an error is +// returned. If the data in the database record cannot be stored in result +// because of type differences, an UnmarshalTypeError is returned. If the +// database is invalid or otherwise cannot be read, an InvalidDatabaseError +// is returned. +func (r *Reader) Lookup(ip net.IP, result interface{}) error { + if r.buffer == nil { + return errors.New("cannot call Lookup on a closed database") + } + pointer, _, _, err := r.lookupPointer(ip) + if pointer == 0 || err != nil { + return err + } + return r.retrieveData(pointer, result) +} + +// LookupNetwork retrieves the database record for ip and stores it in the +// value pointed to by result. The network returned is the network associated +// with the data record in the database. The ok return value indicates whether +// the database contained a record for the ip. +// +// If result is nil or not a pointer, an error is returned. If the data in the +// database record cannot be stored in result because of type differences, an +// UnmarshalTypeError is returned. If the database is invalid or otherwise +// cannot be read, an InvalidDatabaseError is returned. +func (r *Reader) LookupNetwork( + ip net.IP, + result interface{}, +) (network *net.IPNet, ok bool, err error) { + if r.buffer == nil { + return nil, false, errors.New("cannot call Lookup on a closed database") + } + pointer, prefixLength, ip, err := r.lookupPointer(ip) + + network = r.cidr(ip, prefixLength) + if pointer == 0 || err != nil { + return network, false, err + } + + return network, true, r.retrieveData(pointer, result) +} + +// LookupOffset maps an argument net.IP to a corresponding record offset in the +// database. NotFound is returned if no such record is found, and a record may +// otherwise be extracted by passing the returned offset to Decode. LookupOffset +// is an advanced API, which exists to provide clients with a means to cache +// previously-decoded records. +func (r *Reader) LookupOffset(ip net.IP) (uintptr, error) { + if r.buffer == nil { + return 0, errors.New("cannot call LookupOffset on a closed database") + } + pointer, _, _, err := r.lookupPointer(ip) + if pointer == 0 || err != nil { + return NotFound, err + } + return r.resolveDataPointer(pointer) +} + +func (r *Reader) cidr(ip net.IP, prefixLength int) *net.IPNet { + // This is necessary as the node that the IPv4 start is at may + // be at a bit depth that is less that 96, i.e., ipv4Start points + // to a leaf node. For instance, if a record was inserted at ::/8, + // the ipv4Start would point directly at the leaf node for the + // record and would have a bit depth of 8. This would not happen + // with databases currently distributed by MaxMind as all of them + // have an IPv4 subtree that is greater than a single node. + if r.Metadata.IPVersion == 6 && + len(ip) == net.IPv4len && + r.ipv4StartBitDepth != 96 { + return &net.IPNet{IP: net.ParseIP("::"), Mask: net.CIDRMask(r.ipv4StartBitDepth, 128)} + } + + mask := net.CIDRMask(prefixLength, len(ip)*8) + return &net.IPNet{IP: ip.Mask(mask), Mask: mask} +} + +// Decode the record at |offset| into |result|. The result value pointed to +// must be a data value that corresponds to a record in the database. This may +// include a struct representation of the data, a map capable of holding the +// data or an empty interface{} value. +// +// If result is a pointer to a struct, the struct need not include a field +// for every value that may be in the database. If a field is not present in +// the structure, the decoder will not decode that field, reducing the time +// required to decode the record. +// +// As a special case, a struct field of type uintptr will be used to capture +// the offset of the value. Decode may later be used to extract the stored +// value from the offset. MaxMind DBs are highly normalized: for example in +// the City database, all records of the same country will reference a +// single representative record for that country. This uintptr behavior allows +// clients to leverage this normalization in their own sub-record caching. +func (r *Reader) Decode(offset uintptr, result interface{}) error { + if r.buffer == nil { + return errors.New("cannot call Decode on a closed database") + } + return r.decode(offset, result) +} + +func (r *Reader) decode(offset uintptr, result interface{}) error { + rv := reflect.ValueOf(result) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + return errors.New("result param must be a pointer") + } + + if dser, ok := result.(deserializer); ok { + _, err := r.decoder.decodeToDeserializer(uint(offset), dser, 0, false) + return err + } + + _, err := r.decoder.decode(uint(offset), rv, 0) + return err +} + +func (r *Reader) lookupPointer(ip net.IP) (uint, int, net.IP, error) { + if ip == nil { + return 0, 0, nil, errors.New("IP passed to Lookup cannot be nil") + } + + ipV4Address := ip.To4() + if ipV4Address != nil { + ip = ipV4Address + } + if len(ip) == 16 && r.Metadata.IPVersion == 4 { + return 0, 0, ip, fmt.Errorf( + "error looking up '%s': you attempted to look up an IPv6 address in an IPv4-only database", + ip.String(), + ) + } + + bitCount := uint(len(ip) * 8) + + var node uint + if bitCount == 32 { + node = r.ipv4Start + } + node, prefixLength := r.traverseTree(ip, node, bitCount) + + nodeCount := r.Metadata.NodeCount + if node == nodeCount { + // Record is empty + return 0, prefixLength, ip, nil + } else if node > nodeCount { + return node, prefixLength, ip, nil + } + + return 0, prefixLength, ip, newInvalidDatabaseError("invalid node in search tree") +} + +func (r *Reader) traverseTree(ip net.IP, node, bitCount uint) (uint, int) { + nodeCount := r.Metadata.NodeCount + + i := uint(0) + for ; i < bitCount && node < nodeCount; i++ { + bit := uint(1) & (uint(ip[i>>3]) >> (7 - (i % 8))) + + offset := node * r.nodeOffsetMult + if bit == 0 { + node = r.nodeReader.readLeft(offset) + } else { + node = r.nodeReader.readRight(offset) + } + } + + return node, int(i) +} + +func (r *Reader) retrieveData(pointer uint, result interface{}) error { + offset, err := r.resolveDataPointer(pointer) + if err != nil { + return err + } + return r.decode(offset, result) +} + +func (r *Reader) resolveDataPointer(pointer uint) (uintptr, error) { + resolved := uintptr(pointer - r.Metadata.NodeCount - dataSectionSeparatorSize) + + if resolved >= uintptr(len(r.buffer)) { + return 0, newInvalidDatabaseError("the MaxMind DB file's search tree is corrupt") + } + return resolved, nil +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/reader_appengine.go b/vendor/github.com/oschwald/maxminddb-golang/reader_appengine.go new file mode 100644 index 0000000..c6385d8 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/reader_appengine.go @@ -0,0 +1,28 @@ +// +build appengine plan9 + +package maxminddb + +import "io/ioutil" + +// Open takes a string path to a MaxMind DB file and returns a Reader +// structure or an error. The database file is opened using a memory map, +// except on Google App Engine where mmap is not supported; there the database +// is loaded into memory. Use the Close method on the Reader object to return +// the resources to the system. +func Open(file string) (*Reader, error) { + bytes, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + return FromBytes(bytes) +} + +// Close unmaps the database file from virtual memory and returns the +// resources to the system. If called on a Reader opened using FromBytes +// or Open on Google App Engine, this method sets the underlying buffer +// to nil, returning the resources to the system. +func (r *Reader) Close() error { + r.buffer = nil + return nil +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/reader_other.go b/vendor/github.com/oschwald/maxminddb-golang/reader_other.go new file mode 100644 index 0000000..0ed9de1 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/reader_other.go @@ -0,0 +1,66 @@ +//go:build !appengine && !plan9 +// +build !appengine,!plan9 + +package maxminddb + +import ( + "os" + "runtime" +) + +// Open takes a string path to a MaxMind DB file and returns a Reader +// structure or an error. The database file is opened using a memory map, +// except on Google App Engine where mmap is not supported; there the database +// is loaded into memory. Use the Close method on the Reader object to return +// the resources to the system. +func Open(file string) (*Reader, error) { + mapFile, err := os.Open(file) + if err != nil { + _ = mapFile.Close() + return nil, err + } + + stats, err := mapFile.Stat() + if err != nil { + _ = mapFile.Close() + return nil, err + } + + fileSize := int(stats.Size()) + mmap, err := mmap(int(mapFile.Fd()), fileSize) + if err != nil { + _ = mapFile.Close() + return nil, err + } + + if err := mapFile.Close(); err != nil { + //nolint:errcheck // we prefer to return the original error + munmap(mmap) + return nil, err + } + + reader, err := FromBytes(mmap) + if err != nil { + //nolint:errcheck // we prefer to return the original error + munmap(mmap) + return nil, err + } + + reader.hasMappedFile = true + runtime.SetFinalizer(reader, (*Reader).Close) + return reader, nil +} + +// Close unmaps the database file from virtual memory and returns the +// resources to the system. If called on a Reader opened using FromBytes +// or Open on Google App Engine, this method does nothing. +func (r *Reader) Close() error { + var err error + if r.hasMappedFile { + runtime.SetFinalizer(r, nil) + r.hasMappedFile = false + err = munmap(r.buffer) + } + r.buffer = nil + return err +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/traverse.go b/vendor/github.com/oschwald/maxminddb-golang/traverse.go new file mode 100644 index 0000000..7009ec1 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/traverse.go @@ -0,0 +1,205 @@ +package maxminddb + +import ( + "fmt" + "net" +) + +// Internal structure used to keep track of nodes we still need to visit. +type netNode struct { + ip net.IP + bit uint + pointer uint +} + +// Networks represents a set of subnets that we are iterating over. +type Networks struct { + reader *Reader + nodes []netNode // Nodes we still have to visit. + lastNode netNode + err error + + skipAliasedNetworks bool +} + +var ( + allIPv4 = &net.IPNet{IP: make(net.IP, 4), Mask: net.CIDRMask(0, 32)} + allIPv6 = &net.IPNet{IP: make(net.IP, 16), Mask: net.CIDRMask(0, 128)} +) + +// NetworksOption are options for Networks and NetworksWithin. +type NetworksOption func(*Networks) + +// SkipAliasedNetworks is an option for Networks and NetworksWithin that +// makes them not iterate over aliases of the IPv4 subtree in an IPv6 +// database, e.g., ::ffff:0:0/96, 2001::/32, and 2002::/16. +// +// You most likely want to set this. The only reason it isn't the default +// behavior is to provide backwards compatibility to existing users. +func SkipAliasedNetworks(networks *Networks) { + networks.skipAliasedNetworks = true +} + +// Networks returns an iterator that can be used to traverse all networks in +// the database. +// +// Please note that a MaxMind DB may map IPv4 networks into several locations +// in an IPv6 database. This iterator will iterate over all of these locations +// separately. To only iterate over the IPv4 networks once, use the +// SkipAliasedNetworks option. +func (r *Reader) Networks(options ...NetworksOption) *Networks { + var networks *Networks + if r.Metadata.IPVersion == 6 { + networks = r.NetworksWithin(allIPv6, options...) + } else { + networks = r.NetworksWithin(allIPv4, options...) + } + + return networks +} + +// NetworksWithin returns an iterator that can be used to traverse all networks +// in the database which are contained in a given network. +// +// Please note that a MaxMind DB may map IPv4 networks into several locations +// in an IPv6 database. This iterator will iterate over all of these locations +// separately. To only iterate over the IPv4 networks once, use the +// SkipAliasedNetworks option. +// +// If the provided network is contained within a network in the database, the +// iterator will iterate over exactly one network, the containing network. +func (r *Reader) NetworksWithin(network *net.IPNet, options ...NetworksOption) *Networks { + if r.Metadata.IPVersion == 4 && network.IP.To4() == nil { + return &Networks{ + err: fmt.Errorf( + "error getting networks with '%s': you attempted to use an IPv6 network in an IPv4-only database", + network.String(), + ), + } + } + + networks := &Networks{reader: r} + for _, option := range options { + option(networks) + } + + ip := network.IP + prefixLength, _ := network.Mask.Size() + + if r.Metadata.IPVersion == 6 && len(ip) == net.IPv4len { + if networks.skipAliasedNetworks { + ip = net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ip[0], ip[1], ip[2], ip[3]} + } else { + ip = ip.To16() + } + prefixLength += 96 + } + + pointer, bit := r.traverseTree(ip, 0, uint(prefixLength)) + networks.nodes = []netNode{ + { + ip: ip, + bit: uint(bit), + pointer: pointer, + }, + } + + return networks +} + +// Next prepares the next network for reading with the Network method. It +// returns true if there is another network to be processed and false if there +// are no more networks or if there is an error. +func (n *Networks) Next() bool { + if n.err != nil { + return false + } + for len(n.nodes) > 0 { + node := n.nodes[len(n.nodes)-1] + n.nodes = n.nodes[:len(n.nodes)-1] + + for node.pointer != n.reader.Metadata.NodeCount { + // This skips IPv4 aliases without hardcoding the networks that the writer + // currently aliases. + if n.skipAliasedNetworks && n.reader.ipv4Start != 0 && + node.pointer == n.reader.ipv4Start && !isInIPv4Subtree(node.ip) { + break + } + + if node.pointer > n.reader.Metadata.NodeCount { + n.lastNode = node + return true + } + ipRight := make(net.IP, len(node.ip)) + copy(ipRight, node.ip) + if len(ipRight) <= int(node.bit>>3) { + n.err = newInvalidDatabaseError( + "invalid search tree at %v/%v", ipRight, node.bit) + return false + } + ipRight[node.bit>>3] |= 1 << (7 - (node.bit % 8)) + + offset := node.pointer * n.reader.nodeOffsetMult + rightPointer := n.reader.nodeReader.readRight(offset) + + node.bit++ + n.nodes = append(n.nodes, netNode{ + pointer: rightPointer, + ip: ipRight, + bit: node.bit, + }) + + node.pointer = n.reader.nodeReader.readLeft(offset) + } + } + + return false +} + +// Network returns the current network or an error if there is a problem +// decoding the data for the network. It takes a pointer to a result value to +// decode the network's data into. +func (n *Networks) Network(result interface{}) (*net.IPNet, error) { + if n.err != nil { + return nil, n.err + } + if err := n.reader.retrieveData(n.lastNode.pointer, result); err != nil { + return nil, err + } + + ip := n.lastNode.ip + prefixLength := int(n.lastNode.bit) + + // We do this because uses of SkipAliasedNetworks expect the IPv4 networks + // to be returned as IPv4 networks. If we are not skipping aliased + // networks, then the user will get IPv4 networks from the ::FFFF:0:0/96 + // network as Go automatically converts those. + if n.skipAliasedNetworks && isInIPv4Subtree(ip) { + ip = ip[12:] + prefixLength -= 96 + } + + return &net.IPNet{ + IP: ip, + Mask: net.CIDRMask(prefixLength, len(ip)*8), + }, nil +} + +// Err returns an error, if any, that was encountered during iteration. +func (n *Networks) Err() error { + return n.err +} + +// isInIPv4Subtree returns true if the IP is an IPv6 address in the database's +// IPv4 subtree. +func isInIPv4Subtree(ip net.IP) bool { + if len(ip) != 16 { + return false + } + for i := 0; i < 12; i++ { + if ip[i] != 0 { + return false + } + } + return true +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/verifier.go b/vendor/github.com/oschwald/maxminddb-golang/verifier.go new file mode 100644 index 0000000..88381d7 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/verifier.go @@ -0,0 +1,201 @@ +package maxminddb + +import ( + "reflect" + "runtime" +) + +type verifier struct { + reader *Reader +} + +// Verify checks that the database is valid. It validates the search tree, +// the data section, and the metadata section. This verifier is stricter than +// the specification and may return errors on databases that are readable. +func (r *Reader) Verify() error { + v := verifier{r} + if err := v.verifyMetadata(); err != nil { + return err + } + + err := v.verifyDatabase() + runtime.KeepAlive(v.reader) + return err +} + +func (v *verifier) verifyMetadata() error { + metadata := v.reader.Metadata + + if metadata.BinaryFormatMajorVersion != 2 { + return testError( + "binary_format_major_version", + 2, + metadata.BinaryFormatMajorVersion, + ) + } + + if metadata.BinaryFormatMinorVersion != 0 { + return testError( + "binary_format_minor_version", + 0, + metadata.BinaryFormatMinorVersion, + ) + } + + if metadata.DatabaseType == "" { + return testError( + "database_type", + "non-empty string", + metadata.DatabaseType, + ) + } + + if len(metadata.Description) == 0 { + return testError( + "description", + "non-empty slice", + metadata.Description, + ) + } + + if metadata.IPVersion != 4 && metadata.IPVersion != 6 { + return testError( + "ip_version", + "4 or 6", + metadata.IPVersion, + ) + } + + if metadata.RecordSize != 24 && + metadata.RecordSize != 28 && + metadata.RecordSize != 32 { + return testError( + "record_size", + "24, 28, or 32", + metadata.RecordSize, + ) + } + + if metadata.NodeCount == 0 { + return testError( + "node_count", + "positive integer", + metadata.NodeCount, + ) + } + return nil +} + +func (v *verifier) verifyDatabase() error { + offsets, err := v.verifySearchTree() + if err != nil { + return err + } + + if err := v.verifyDataSectionSeparator(); err != nil { + return err + } + + return v.verifyDataSection(offsets) +} + +func (v *verifier) verifySearchTree() (map[uint]bool, error) { + offsets := make(map[uint]bool) + + it := v.reader.Networks() + for it.Next() { + offset, err := v.reader.resolveDataPointer(it.lastNode.pointer) + if err != nil { + return nil, err + } + offsets[uint(offset)] = true + } + if err := it.Err(); err != nil { + return nil, err + } + return offsets, nil +} + +func (v *verifier) verifyDataSectionSeparator() error { + separatorStart := v.reader.Metadata.NodeCount * v.reader.Metadata.RecordSize / 4 + + separator := v.reader.buffer[separatorStart : separatorStart+dataSectionSeparatorSize] + + for _, b := range separator { + if b != 0 { + return newInvalidDatabaseError("unexpected byte in data separator: %v", separator) + } + } + return nil +} + +func (v *verifier) verifyDataSection(offsets map[uint]bool) error { + pointerCount := len(offsets) + + decoder := v.reader.decoder + + var offset uint + bufferLen := uint(len(decoder.buffer)) + for offset < bufferLen { + var data interface{} + rv := reflect.ValueOf(&data) + newOffset, err := decoder.decode(offset, rv, 0) + if err != nil { + return newInvalidDatabaseError( + "received decoding error (%v) at offset of %v", + err, + offset, + ) + } + if newOffset <= offset { + return newInvalidDatabaseError( + "data section offset unexpectedly went from %v to %v", + offset, + newOffset, + ) + } + + pointer := offset + + if _, ok := offsets[pointer]; !ok { + return newInvalidDatabaseError( + "found data (%v) at %v that the search tree does not point to", + data, + pointer, + ) + } + delete(offsets, pointer) + + offset = newOffset + } + + if offset != bufferLen { + return newInvalidDatabaseError( + "unexpected data at the end of the data section (last offset: %v, end: %v)", + offset, + bufferLen, + ) + } + + if len(offsets) != 0 { + return newInvalidDatabaseError( + "found %v pointers (of %v) in the search tree that we did not see in the data section", + len(offsets), + pointerCount, + ) + } + return nil +} + +func testError( + field string, + expected interface{}, + actual interface{}, +) error { + return newInvalidDatabaseError( + "%v - Expected: %v Actual: %v", + field, + expected, + actual, + ) +} diff --git a/vendor/go.dtapp.net/dorm/const.go b/vendor/go.dtapp.net/dorm/const.go index af53090..2abb4a0 100644 --- a/vendor/go.dtapp.net/dorm/const.go +++ b/vendor/go.dtapp.net/dorm/const.go @@ -1,3 +1,3 @@ package dorm -const Version = "1.0.33" +const Version = "1.0.38" diff --git a/vendor/go.dtapp.net/dorm/gorm.go b/vendor/go.dtapp.net/dorm/gorm.go index 5a13897..c08eeb3 100644 --- a/vendor/go.dtapp.net/dorm/gorm.go +++ b/vendor/go.dtapp.net/dorm/gorm.go @@ -9,6 +9,13 @@ import ( "time" ) +// GormClientFun *GormClient 驱动 +type GormClientFun func() *GormClient + +// GormClientTableFun *GormClient 驱动 +// string 表名 +type GormClientTableFun func() (*GormClient, string) + type ConfigGormClient struct { Dns string // 地址 LogStatus bool // 日志 - 状态 diff --git a/vendor/go.dtapp.net/dorm/gorm_postgresql.go b/vendor/go.dtapp.net/dorm/gorm_postgresql.go index 2fd10b4..a15149a 100644 --- a/vendor/go.dtapp.net/dorm/gorm_postgresql.go +++ b/vendor/go.dtapp.net/dorm/gorm_postgresql.go @@ -160,7 +160,7 @@ func NewGormPostgresqlClient(config *ConfigGormClient) (*GormClient, error) { // 设置了连接可复用的最大时间 if c.config.ConnSetConnMaxLifetime == 0 { - sqlDB.SetConnMaxLifetime(time.Second * 600) + sqlDB.SetConnMaxLifetime(time.Hour) } else { sqlDB.SetConnMaxLifetime(time.Duration(c.config.ConnSetConnMaxLifetime)) } diff --git a/vendor/go.dtapp.net/dorm/mongo.go b/vendor/go.dtapp.net/dorm/mongo.go index af8003f..f11ad2a 100644 --- a/vendor/go.dtapp.net/dorm/mongo.go +++ b/vendor/go.dtapp.net/dorm/mongo.go @@ -4,11 +4,19 @@ import ( "context" "errors" "fmt" - "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) +// MongoClientFun *MongoClient 驱动 +// string 库名 +type MongoClientFun func() (*MongoClient, string) + +// MongoClientCollectionFun *MongoClient 驱动 +// string 库名 +// string 集合 +type MongoClientCollectionFun func() (*MongoClient, string, string) + type ConfigMongoClient struct { Dns string // 地址 Opts *options.ClientOptions @@ -16,36 +24,31 @@ type ConfigMongoClient struct { } type MongoClient struct { - Db *mongo.Client // 驱动 - config *ConfigMongoClient // 配置 - databaseName string // 库名 - collectionName string // 表名 - //filterArr []queryFilter // 查询条件数组 - filter bson.D // 查询条件 + Db *mongo.Client // 驱动 + config *ConfigMongoClient // 配置 } func NewMongoClient(config *ConfigMongoClient) (*MongoClient, error) { + var ctx = context.Background() var err error c := &MongoClient{config: config} - c.databaseName = c.config.DatabaseName - // 连接到MongoDB if c.config.Dns != "" { - c.Db, err = mongo.Connect(context.Background(), options.Client().ApplyURI(c.config.Dns)) + c.Db, err = mongo.Connect(ctx, options.Client().ApplyURI(c.config.Dns)) if err != nil { return nil, errors.New(fmt.Sprintf("连接失败:%v", err)) } } else { - c.Db, err = mongo.Connect(context.Background(), c.config.Opts) + c.Db, err = mongo.Connect(ctx, c.config.Opts) if err != nil { return nil, errors.New(fmt.Sprintf("连接失败:%v", err)) } } // 检查连接 - err = c.Db.Ping(context.TODO(), nil) + err = c.Db.Ping(ctx, nil) if err != nil { return nil, errors.New(fmt.Sprintf("检查连接失败:%v", err)) } @@ -54,10 +57,6 @@ func NewMongoClient(config *ConfigMongoClient) (*MongoClient, error) { } // Close 关闭 -func (c *MongoClient) Close() error { - err := c.Db.Disconnect(context.TODO()) - if err != nil { - return errors.New(fmt.Sprintf("关闭失败:%v", err)) - } - return nil +func (c *MongoClient) Close(ctx context.Context) error { + return c.Db.Disconnect(ctx) } diff --git a/vendor/go.dtapp.net/dorm/mongo_bson.go b/vendor/go.dtapp.net/dorm/mongo_bson.go deleted file mode 100644 index c382773..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_bson.go +++ /dev/null @@ -1 +0,0 @@ -package dorm diff --git a/vendor/go.dtapp.net/dorm/mongo_collection.go b/vendor/go.dtapp.net/dorm/mongo_collection.go new file mode 100644 index 0000000..a84bfb6 --- /dev/null +++ b/vendor/go.dtapp.net/dorm/mongo_collection.go @@ -0,0 +1,56 @@ +package dorm + +import ( + "context" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type MongoCollectionOptions struct { + dbCollection *mongo.Collection // 集合 +} + +// Collection 选择集合 +func (cd *MongoDatabaseOptions) Collection(name string, opts ...*options.CollectionOptions) *MongoCollectionOptions { + return &MongoCollectionOptions{ + dbCollection: cd.dbDatabase.Collection(name, opts...), + } +} + +// CreateOneIndexes 创建一个索引 +func (cc *MongoCollectionOptions) CreateOneIndexes(ctx context.Context, key string, value string) (string, error) { + return cc.dbCollection.Indexes().CreateOne(ctx, mongo.IndexModel{ + Keys: bson.D{{ + Key: key, + Value: value, + }}, + }) +} + +// CreateOneUniqueIndexes 创建一个唯一索引 +func (cc *MongoCollectionOptions) CreateOneUniqueIndexes(ctx context.Context, key string, value string) (string, error) { + return cc.dbCollection.Indexes().CreateOne(ctx, mongo.IndexModel{ + Keys: bson.D{{ + Key: key, + Value: value, + }}, + Options: options.Index().SetUnique(true), + }) +} + +// CreateOneUniqueIndexesOpts 创建一个索引 +func (cc *MongoCollectionOptions) CreateOneUniqueIndexesOpts(ctx context.Context, key string, value string, opts *options.IndexOptions) (string, error) { + return cc.dbCollection.Indexes().CreateOne(ctx, mongo.IndexModel{ + Keys: bson.D{{ + Key: key, + Value: value, + }}, + Options: opts, + }) +} + +// CreateManyIndexes 创建多个索引 +func (cc *MongoCollectionOptions) CreateManyIndexes(ctx context.Context, models []mongo.IndexModel) ([]string, error) { + return cc.dbCollection.Indexes().CreateMany(ctx, models) +} diff --git a/vendor/go.dtapp.net/dorm/mongo_collection_curd.go b/vendor/go.dtapp.net/dorm/mongo_collection_curd.go new file mode 100644 index 0000000..3309494 --- /dev/null +++ b/vendor/go.dtapp.net/dorm/mongo_collection_curd.go @@ -0,0 +1,47 @@ +package dorm + +import ( + "context" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// InsertOne 插入一个文档 +func (cc *MongoCollectionOptions) InsertOne(ctx context.Context, document interface{}, opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error) { + return cc.dbCollection.InsertOne(ctx, document, opts...) +} + +// InsertMany 插入多个文档 +func (cc *MongoCollectionOptions) InsertMany(ctx context.Context, document []interface{}, opts ...*options.InsertManyOptions) (*mongo.InsertManyResult, error) { + return cc.dbCollection.InsertMany(ctx, document, opts...) +} + +// DeleteOne 删除一个文档 +func (cc *MongoCollectionOptions) DeleteOne(ctx context.Context, filter interface{}, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { + return cc.dbCollection.DeleteOne(ctx, filter, opts...) +} + +// DeleteMany 删除多个文档 +func (cc *MongoCollectionOptions) DeleteMany(ctx context.Context, filter interface{}, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { + return cc.dbCollection.DeleteMany(ctx, filter, opts...) +} + +// UpdateOne 更新一个文档 +func (cc *MongoCollectionOptions) UpdateOne(ctx context.Context, filter interface{}, update interface{}, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) { + return cc.dbCollection.UpdateOne(ctx, filter, update, opts...) +} + +// UpdateMany 更新多个文档 +func (cc *MongoCollectionOptions) UpdateMany(ctx context.Context, filter interface{}, update interface{}, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) { + return cc.dbCollection.UpdateMany(ctx, filter, update, opts...) +} + +// FindOne 查询一个文档 +func (cc *MongoCollectionOptions) FindOne(ctx context.Context, filter interface{}, opts ...*options.FindOneOptions) *mongo.SingleResult { + return cc.dbCollection.FindOne(ctx, filter, opts...) +} + +// Find 查询多个文档 +func (cc *MongoCollectionOptions) Find(ctx context.Context, filter interface{}, opts ...*options.FindOptions) (*mongo.Cursor, error) { + return cc.dbCollection.Find(ctx, filter, opts...) +} diff --git a/vendor/go.dtapp.net/dorm/mongo_curd.go b/vendor/go.dtapp.net/dorm/mongo_curd.go deleted file mode 100644 index 80a4908..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_curd.go +++ /dev/null @@ -1,185 +0,0 @@ -package dorm - -import ( - "context" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" -) - -// InsertOne 插入一个文档 -func (c *MongoClient) InsertOne(document interface{}) (result *mongo.InsertOneResult, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - result, err = collection.InsertOne(context.TODO(), document) - return -} - -// InsertMany 插入多个文档 -func (c *MongoClient) InsertMany(documents []interface{}) (result *mongo.InsertManyResult, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - result, err = collection.InsertMany(context.TODO(), documents) - return -} - -// Delete 删除文档 -func (c *MongoClient) Delete(filter interface{}) (err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - _, err = collection.DeleteOne(context.TODO(), filter) - return -} - -// DeleteId 删除文档 -func (c *MongoClient) DeleteId(id interface{}) (err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - _, err = collection.DeleteOne(context.TODO(), bson.M{"_id": id}) - return -} - -// DeleteMany 删除多个文档 -func (c *MongoClient) DeleteMany(filter interface{}) (result *mongo.DeleteResult, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - result, err = collection.DeleteMany(context.TODO(), filter) - return -} - -// UpdateOne 更新单个文档 -// 修改字段的值($set) -// 字段增加值 inc($inc) -// 从数组中增加一个元素 push($push) -// 从数组中删除一个元素 pull($pull) -func (c *MongoClient) UpdateOne(filter interface{}, update interface{}) (err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - _, err = collection.UpdateOne(context.TODO(), filter, update) - return -} - -// UpdateId 更新单个文档 -// 修改字段的值($set) -// 字段增加值 inc($inc) -// 从数组中增加一个元素 push($push) -// 从数组中删除一个元素 pull($pull) -func (c *MongoClient) UpdateId(id interface{}, update interface{}) (err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - _, err = collection.UpdateOne(context.TODO(), bson.M{"_id": id}, update) - return -} - -// UpdateMany 更新多个文档 -// 修改字段的值($set) -// 字段增加值 inc($inc) -// 从数组中增加一个元素 push($push) -// 从数组中删除一个元素 pull($pull) -func (c *MongoClient) UpdateMany(filter interface{}, update interface{}) (result *mongo.UpdateResult, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - result, err = collection.UpdateMany(context.TODO(), filter, update) - return -} - -type FindResultI interface { - Many(result interface{}) error -} - -// Find 查询 -func (c *MongoClient) Find(filter interface{}) (*mongo.Cursor, error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - return collection.Find(context.TODO(), filter) -} - -type FindOneResultI interface { - One(result interface{}) error -} - -// FindOne 查询单个文档 -func (c *MongoClient) FindOne(filter interface{}) *mongo.SingleResult { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - return collection.FindOne(context.TODO(), filter) -} - -type FindManyResultI interface { - Many(result interface{}) error -} - -// FindMany 查询多个文档 -func (c *MongoClient) FindMany(filter interface{}) (*mongo.Cursor, error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - return collection.Find(context.TODO(), filter) -} - -// FindManyByFilters 多条件查询 -func (c *MongoClient) FindManyByFilters(filter interface{}) (result *mongo.Cursor, err error) { - collection, err := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName).Clone() - result, err = collection.Find(context.TODO(), bson.M{"$and": filter}) - return result, err -} - -// FindManyByFiltersSort 多条件查询支持排序 -func (c *MongoClient) FindManyByFiltersSort(filter interface{}, Sort interface{}) (result *mongo.Cursor, err error) { - collection, err := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName).Clone() - findOptions := options.Find() - findOptions.SetSort(Sort) - result, err = collection.Find(context.TODO(), filter, findOptions) - return result, err -} - -// FindCollection 查询集合文档 -func (c *MongoClient) FindCollection(Limit int64) (result *mongo.Cursor, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - findOptions := options.Find() - findOptions.SetLimit(Limit) - result, err = collection.Find(context.TODO(), bson.D{{}}, findOptions) - return result, err -} - -// FindCollectionSort 查询集合文档支持排序 -func (c *MongoClient) FindCollectionSort(Sort interface{}, Limit int64) (result *mongo.Cursor, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - findOptions := options.Find() - findOptions.SetSort(Sort) - findOptions.SetLimit(Limit) - result, err = collection.Find(context.TODO(), bson.D{{}}, findOptions) - return result, err -} - -// FindManyCollectionSort 查询集合文档支持排序支持条件 -func (c *MongoClient) FindManyCollectionSort(filter interface{}, Sort interface{}) (result *mongo.Cursor, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - findOptions := options.Find() - findOptions.SetSort(Sort) - result, err = collection.Find(context.TODO(), filter, findOptions) - return result, err -} - -// CollectionCount 查询集合里有多少数据 -func (c *MongoClient) CollectionCount() (name string, size int64) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - name = collection.Name() - size, _ = collection.EstimatedDocumentCount(context.TODO()) - return name, size -} - -// CollectionDocuments 按选项查询集合 -// Skip 跳过 -// Limit 读取数量 -// sort 1 ,-1 . 1 为升序 , -1 为降序 -func (c *MongoClient) CollectionDocuments(Skip, Limit int64, sort int, key string, value interface{}) (result *mongo.Cursor, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - SORT := bson.D{{"_id", sort}} - filter := bson.D{{key, value}} - findOptions := options.Find().SetSort(SORT).SetLimit(Limit).SetSkip(Skip) - result, err = collection.Find(context.TODO(), filter, findOptions) - return result, err -} - -// AggregateByFiltersSort 统计分析 -func (c *MongoClient) AggregateByFiltersSort(pipeline interface{}) (result *mongo.Cursor, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - result, err = collection.Aggregate(context.TODO(), pipeline) - return result, err -} - -// CountDocumentsByFilters 统计数量 -func (c *MongoClient) CountDocumentsByFilters(filter interface{}) (count int64, err error) { - collection := c.Db.Database(c.getDatabaseName()).Collection(c.collectionName) - count, err = collection.CountDocuments(context.TODO(), filter) - return count, err -} diff --git a/vendor/go.dtapp.net/dorm/mongo_curl_find.go b/vendor/go.dtapp.net/dorm/mongo_curl_find.go deleted file mode 100644 index 3219492..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_curl_find.go +++ /dev/null @@ -1,15 +0,0 @@ -package dorm - -import ( - "context" - "go.mongodb.org/mongo-driver/mongo" -) - -type FindResult struct { - cursor *mongo.Cursor - err error -} - -func (f *FindResult) Many(result interface{}) error { - return f.cursor.All(context.TODO(), result) -} diff --git a/vendor/go.dtapp.net/dorm/mongo_curl_find_many.go b/vendor/go.dtapp.net/dorm/mongo_curl_find_many.go deleted file mode 100644 index 192edf6..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_curl_find_many.go +++ /dev/null @@ -1,15 +0,0 @@ -package dorm - -import ( - "context" - "go.mongodb.org/mongo-driver/mongo" -) - -type FindManyResult struct { - cursor *mongo.Cursor - err error -} - -func (f *FindManyResult) Many(result interface{}) error { - return f.cursor.All(context.TODO(), result) -} diff --git a/vendor/go.dtapp.net/dorm/mongo_curl_find_one.go b/vendor/go.dtapp.net/dorm/mongo_curl_find_one.go deleted file mode 100644 index 4ef3666..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_curl_find_one.go +++ /dev/null @@ -1,11 +0,0 @@ -package dorm - -import "go.mongodb.org/mongo-driver/mongo" - -type FindOneResult struct { - singleResult *mongo.SingleResult -} - -func (f *FindOneResult) One(result interface{}) error { - return f.singleResult.Decode(result) -} diff --git a/vendor/go.dtapp.net/dorm/mongo_database.go b/vendor/go.dtapp.net/dorm/mongo_database.go new file mode 100644 index 0000000..75749f4 --- /dev/null +++ b/vendor/go.dtapp.net/dorm/mongo_database.go @@ -0,0 +1,28 @@ +package dorm + +import ( + "context" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type MongoDatabaseOptions struct { + dbDatabase *mongo.Database // 数据库 +} + +// Database 选择数据库 +func (c *MongoClient) Database(name string, opts ...*options.DatabaseOptions) *MongoDatabaseOptions { + return &MongoDatabaseOptions{ + dbDatabase: c.Db.Database(name, opts...), + } +} + +// CreateCollection 创建集合 +func (cd *MongoDatabaseOptions) CreateCollection(ctx context.Context, name string, opts ...*options.CreateCollectionOptions) error { + return cd.dbDatabase.CreateCollection(ctx, name, opts...) +} + +// CreateTimeSeriesCollection 创建时间序列集合 +func (cd *MongoDatabaseOptions) CreateTimeSeriesCollection(ctx context.Context, name string, timeField string) error { + return cd.dbDatabase.CreateCollection(ctx, name, options.CreateCollection().SetTimeSeriesOptions(options.TimeSeries().SetTimeField(timeField))) +} diff --git a/vendor/go.dtapp.net/dorm/mongo_get.go b/vendor/go.dtapp.net/dorm/mongo_get.go index 8ccd7f6..eaa58b5 100644 --- a/vendor/go.dtapp.net/dorm/mongo_get.go +++ b/vendor/go.dtapp.net/dorm/mongo_get.go @@ -6,13 +6,3 @@ import "go.mongodb.org/mongo-driver/mongo" func (c *MongoClient) GetDb() *mongo.Client { return c.Db } - -// 获取库名 -func (c *MongoClient) getDatabaseName() string { - return c.databaseName -} - -// 获取表名 -func (c *MongoClient) getCollectionName() string { - return c.collectionName -} diff --git a/vendor/go.dtapp.net/dorm/mongo_options.go b/vendor/go.dtapp.net/dorm/mongo_options.go deleted file mode 100644 index c382773..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_options.go +++ /dev/null @@ -1 +0,0 @@ -package dorm diff --git a/vendor/go.dtapp.net/dorm/mongo_session.go b/vendor/go.dtapp.net/dorm/mongo_session.go new file mode 100644 index 0000000..b66ded2 --- /dev/null +++ b/vendor/go.dtapp.net/dorm/mongo_session.go @@ -0,0 +1,50 @@ +package dorm + +import ( + "context" + "errors" + "fmt" + "go.mongodb.org/mongo-driver/mongo" +) + +type MongoSessionOptions struct { + Session mongo.SessionContext // 会话 + Db *mongo.Client // 驱动 + startSession mongo.Session // 开始会话 +} + +// Begin 开始事务,会同时创建开始会话需要在退出时关闭会话 +func (c *MongoClient) Begin() (ms *MongoSessionOptions, err error) { + + var ctx = context.Background() + + ms.Db = c.Db + + // 开始会话 + ms.startSession, err = ms.Db.StartSession() + if err != nil { + return nil, errors.New(fmt.Sprintf("开始会话失败:%v", err)) + } + + // 会话上下文 + ms.Session = mongo.NewSessionContext(ctx, ms.startSession) + + // 会话开启事务 + err = ms.startSession.StartTransaction() + return ms, err +} + +// Close 关闭会话 +func (cs *MongoSessionOptions) Close(ctx context.Context) { + cs.startSession.EndSession(ctx) +} + +// Rollback 回滚事务 +func (cs *MongoSessionOptions) Rollback(ctx context.Context) error { + return cs.startSession.AbortTransaction(ctx) +} + +// Commit 提交事务 +func (cs *MongoSessionOptions) Commit(ctx context.Context) error { + return cs.startSession.CommitTransaction(ctx) +} diff --git a/vendor/go.dtapp.net/dorm/mongo_session_collection.go b/vendor/go.dtapp.net/dorm/mongo_session_collection.go new file mode 100644 index 0000000..31e3905 --- /dev/null +++ b/vendor/go.dtapp.net/dorm/mongo_session_collection.go @@ -0,0 +1,19 @@ +package dorm + +import ( + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type MongoSessionCollectionOptions struct { + session mongo.SessionContext // 会话 + dbCollection *mongo.Collection // 集合 +} + +// Collection 选择集合 +func (csd *MongoSessionDatabaseOptions) Collection(name string, opts ...*options.CollectionOptions) *MongoSessionCollectionOptions { + return &MongoSessionCollectionOptions{ + session: csd.session, // 会话 + dbCollection: csd.dbDatabase.Collection(name, opts...), // 集合 + } +} diff --git a/vendor/go.dtapp.net/dorm/mongo_session_collection_curd.go b/vendor/go.dtapp.net/dorm/mongo_session_collection_curd.go new file mode 100644 index 0000000..7bca5a7 --- /dev/null +++ b/vendor/go.dtapp.net/dorm/mongo_session_collection_curd.go @@ -0,0 +1,46 @@ +package dorm + +import ( + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// InsertOne 插入一个文档 +func (csc *MongoSessionCollectionOptions) InsertOne(document interface{}, opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error) { + return csc.dbCollection.InsertOne(csc.session, document, opts...) +} + +// InsertMany 插入多个文档 +func (csc *MongoSessionCollectionOptions) InsertMany(document []interface{}, opts ...*options.InsertManyOptions) (*mongo.InsertManyResult, error) { + return csc.dbCollection.InsertMany(csc.session, document, opts...) +} + +// DeleteOne 删除一个文档 +func (csc *MongoSessionCollectionOptions) DeleteOne(filter interface{}, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { + return csc.dbCollection.DeleteOne(csc.session, filter, opts...) +} + +// DeleteMany 删除多个文档 +func (csc *MongoSessionCollectionOptions) DeleteMany(filter interface{}, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { + return csc.dbCollection.DeleteMany(csc.session, filter, opts...) +} + +// UpdateOne 更新一个文档 +func (csc *MongoSessionCollectionOptions) UpdateOne(filter interface{}, update interface{}, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) { + return csc.dbCollection.UpdateOne(csc.session, filter, update, opts...) +} + +// UpdateMany 更新多个文档 +func (csc *MongoSessionCollectionOptions) UpdateMany(filter interface{}, update interface{}, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) { + return csc.dbCollection.UpdateMany(csc.session, filter, update, opts...) +} + +// FindOne 查询一个文档 +func (csc *MongoSessionCollectionOptions) FindOne(filter interface{}, opts ...*options.FindOneOptions) *mongo.SingleResult { + return csc.dbCollection.FindOne(csc.session, filter, opts...) +} + +// Find 查询多个文档 +func (csc *MongoSessionCollectionOptions) Find(filter interface{}, opts ...*options.FindOptions) (*mongo.Cursor, error) { + return csc.dbCollection.Find(csc.session, filter, opts...) +} diff --git a/vendor/go.dtapp.net/dorm/mongo_session_database.go b/vendor/go.dtapp.net/dorm/mongo_session_database.go new file mode 100644 index 0000000..1d2952c --- /dev/null +++ b/vendor/go.dtapp.net/dorm/mongo_session_database.go @@ -0,0 +1,19 @@ +package dorm + +import ( + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type MongoSessionDatabaseOptions struct { + session mongo.SessionContext // 会话 + dbDatabase *mongo.Database // 数据库 +} + +// Database 选择数据库 +func (cs *MongoSessionOptions) Database(name string, opts ...*options.DatabaseOptions) *MongoSessionDatabaseOptions { + return &MongoSessionDatabaseOptions{ + session: cs.Session, // 会话 + dbDatabase: cs.Db.Database(name, opts...), // 数据库 + } +} diff --git a/vendor/go.dtapp.net/dorm/mongo_set.go b/vendor/go.dtapp.net/dorm/mongo_set.go deleted file mode 100644 index 818b203..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_set.go +++ /dev/null @@ -1,28 +0,0 @@ -package dorm - -import "reflect" - -// Database 设置库名 -func (c *MongoClient) Database(databaseName string) *MongoClient { - c.databaseName = databaseName - return c -} - -// Collection 设置表名 -func (c *MongoClient) Collection(collectionName string) *MongoClient { - c.collectionName = collectionName - return c -} - -// Model 传入模型自动获取库名和表名 -func (c *MongoClient) Model(value interface{}) *MongoClient { - // https://studygolang.com/articles/896 - val := reflect.ValueOf(value) - if methodValue := val.MethodByName("Database"); methodValue.IsValid() { - c.databaseName = methodValue.Call(nil)[0].String() - } - if methodValue := val.MethodByName("TableName"); methodValue.IsValid() { - c.collectionName = methodValue.Call(nil)[0].String() - } - return c -} diff --git a/vendor/go.dtapp.net/dorm/mongo_time.go b/vendor/go.dtapp.net/dorm/mongo_time.go index b51646c..6331c35 100644 --- a/vendor/go.dtapp.net/dorm/mongo_time.go +++ b/vendor/go.dtapp.net/dorm/mongo_time.go @@ -7,44 +7,79 @@ import ( "time" ) -// BsonTime 类型 +// BsonTime 时间类型 type BsonTime time.Time -// Value 时间类型 -func (t BsonTime) Value() string { - return gotime.SetCurrent(time.Time(t)).Bson() -} - // MarshalJSON 实现json序列化 -func (t BsonTime) MarshalJSON() ([]byte, error) { - //log.Println("MarshalJSON") +func (bt BsonTime) MarshalJSON() ([]byte, error) { + b := make([]byte, 0) - b = append(b, gotime.SetCurrent(time.Time(t)).Bson()...) + + b = append(b, gotime.SetCurrent(time.Time(bt)).Bson()...) + return b, nil } // UnmarshalJSON 实现json反序列化 -func (t *BsonTime) UnmarshalJSON(data []byte) (err error) { - //log.Println("UnmarshalJSON") - t1 := gotime.SetCurrentParse(string(data)) - *t = BsonTime(t1.Time) - return +func (bt *BsonTime) UnmarshalJSON(data []byte) (err error) { + + if string(data) == "null" { + return nil + } + + bsonTime := gotime.SetCurrentParse(string(data)) + + *bt = BsonTime(bsonTime.Time) + + return nil +} + +func (bt BsonTime) Time() time.Time { + return gotime.SetCurrent(time.Time(bt)).Time +} + +func (bt BsonTime) Format() string { + return gotime.SetCurrent(time.Time(bt)).Format() +} + +func (bt BsonTime) TimePro() gotime.Pro { + return gotime.SetCurrent(time.Time(bt)) +} + +// NewBsonTimeCurrent 创建当前时间 +func NewBsonTimeCurrent() BsonTime { + return BsonTime(gotime.Current().Time) +} + +// NewBsonTimeFromTime 创建某个时间 +func NewBsonTimeFromTime(t time.Time) BsonTime { + return BsonTime(t) +} + +// NewBsonTimeFromString 创建某个时间 字符串 +func NewBsonTimeFromString(t string) BsonTime { + return BsonTime(gotime.SetCurrentParse(t).Time) +} + +// Value 时间类型 +func (bt BsonTime) Value() string { + return gotime.SetCurrent(time.Time(bt)).Bson() } // MarshalBSONValue 实现bson序列化 -func (t BsonTime) MarshalBSONValue() (bsontype.Type, []byte, error) { +func (bt BsonTime) MarshalBSONValue() (bsontype.Type, []byte, error) { //log.Println("MarshalBSONValue") - targetTime := gotime.SetCurrent(time.Time(t)).Bson() + targetTime := gotime.SetCurrent(time.Time(bt)).Bson() return bson.MarshalValue(targetTime) } // UnmarshalBSONValue 实现bson反序列化 -func (t *BsonTime) UnmarshalBSONValue(t2 bsontype.Type, data []byte) error { +func (bt *BsonTime) UnmarshalBSONValue(t2 bsontype.Type, data []byte) error { //log.Println("UnmarshalBSONValue") t1 := gotime.SetCurrentParse(string(data)) //if string(data) == "" { // return errors.New(fmt.Sprintf("%s, %s, %s", "读取数据失败:", t2, data)) //} - *t = BsonTime(t1.Time) + *bt = BsonTime(t1.Time) return nil } diff --git a/vendor/go.dtapp.net/dorm/mongo_transaction.go b/vendor/go.dtapp.net/dorm/mongo_transaction.go deleted file mode 100644 index bec0430..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_transaction.go +++ /dev/null @@ -1,48 +0,0 @@ -package dorm - -import ( - "context" - "go.mongodb.org/mongo-driver/mongo" -) - -type MongoTransaction struct { - startSession mongo.Session - Session mongo.SessionContext - db *mongo.Client // 驱动 - databaseName string // 库名 - collectionName string // 表名 -} - -// Begin 开始事务,会同时创建开始会话需要在退出时关闭会话 -func (c *MongoClient) Begin() (ms MongoTransaction, err error) { - - ms.db = c.Db - - // 开始会话 - ms.startSession, err = ms.db.StartSession() - if err != nil { - panic(err) - } - - // 会话上下文 - ms.Session = mongo.NewSessionContext(context.Background(), ms.startSession) - - // 会话开启事务 - err = ms.startSession.StartTransaction() - return ms, err -} - -// Close 关闭会话 -func (ms *MongoTransaction) Close() { - ms.startSession.EndSession(context.TODO()) -} - -// Rollback 回滚事务 -func (ms *MongoTransaction) Rollback() error { - return ms.startSession.AbortTransaction(context.Background()) -} - -// Commit 提交事务 -func (ms *MongoTransaction) Commit() error { - return ms.startSession.CommitTransaction(context.Background()) -} diff --git a/vendor/go.dtapp.net/dorm/mongo_transaction_curd.go b/vendor/go.dtapp.net/dorm/mongo_transaction_curd.go deleted file mode 100644 index e7cfd81..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_transaction_curd.go +++ /dev/null @@ -1,174 +0,0 @@ -package dorm - -import ( - "context" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" -) - -// InsertOne 插入一个文档 -func (ms *MongoTransaction) InsertOne(document interface{}) (result *mongo.InsertOneResult, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - result, err = collection.InsertOne(ms.Session, document) - return -} - -// InsertMany 插入多个文档 -func (ms *MongoTransaction) InsertMany(documents []interface{}) (result *mongo.InsertManyResult, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - result, err = collection.InsertMany(ms.Session, documents) - return -} - -// Delete 删除文档 -func (ms *MongoTransaction) Delete(filter interface{}) (err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - _, err = collection.DeleteOne(ms.Session, filter) - return -} - -// DeleteId 删除文档 -func (ms *MongoTransaction) DeleteId(id interface{}) (err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - _, err = collection.DeleteOne(ms.Session, bson.M{"_id": id}) - return -} - -// DeleteMany 删除多个文档 -func (ms *MongoTransaction) DeleteMany(key string, value interface{}) (result *mongo.DeleteResult, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - filter := bson.D{{key, value}} - result, err = collection.DeleteMany(ms.Session, filter) - return -} - -// UpdateOne 更新单个文档 -// 修改字段的值($set) -// 字段增加值 inc($inc) -// 从数组中增加一个元素 push($push) -// 从数组中删除一个元素 pull($pull) -func (ms *MongoTransaction) UpdateOne(filter interface{}, update interface{}) (err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - _, err = collection.UpdateOne(ms.Session, filter, update) - return -} - -// UpdateId 更新单个文档 -// 修改字段的值($set) -// 字段增加值 inc($inc) -// 从数组中增加一个元素 push($push) -// 从数组中删除一个元素 pull($pull) -func (ms *MongoTransaction) UpdateId(id interface{}, update interface{}) (err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - _, err = collection.UpdateOne(context.TODO(), bson.M{"_id": id}, update) - return -} - -// UpdateMany 更新多个文档 -// 修改字段的值($set) -// 字段增加值 inc($inc) -// 从数组中增加一个元素 push($push) -// 从数组中删除一个元素 pull($pull) -func (ms *MongoTransaction) UpdateMany(filter interface{}, update interface{}) (result *mongo.UpdateResult, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - result, err = collection.UpdateMany(ms.Session, filter, update) - return -} - -// Find 查询 -func (ms *MongoTransaction) Find(filter interface{}) (*mongo.Cursor, error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - return collection.Find(ms.Session, filter) -} - -// FindOne 查询单个文档 -func (ms *MongoTransaction) FindOne(filter interface{}) *mongo.SingleResult { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - return collection.FindOne(ms.Session, filter) -} - -// FindMany 查询多个文档 -func (ms *MongoTransaction) FindMany(filter interface{}) (*mongo.Cursor, error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - return collection.Find(ms.Session, filter) -} - -// FindManyByFilters 多条件查询 -func (ms *MongoTransaction) FindManyByFilters(filter interface{}) (result *mongo.Cursor, err error) { - collection, err := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName).Clone() - result, err = collection.Find(ms.Session, bson.M{"$and": filter}) - return result, err -} - -// FindManyByFiltersSort 多条件查询支持排序 -func (ms *MongoTransaction) FindManyByFiltersSort(filter interface{}, Sort interface{}) (result *mongo.Cursor, err error) { - collection, err := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName).Clone() - findOptions := options.Find() - findOptions.SetSort(Sort) - result, err = collection.Find(ms.Session, filter, findOptions) - return result, err -} - -// FindCollection 查询集合文档 -func (ms *MongoTransaction) FindCollection(Limit int64) (result *mongo.Cursor, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - findOptions := options.Find() - findOptions.SetLimit(Limit) - result, err = collection.Find(ms.Session, bson.D{{}}, findOptions) - return result, err -} - -// FindCollectionSort 查询集合文档支持排序 -func (ms *MongoTransaction) FindCollectionSort(Sort interface{}, Limit int64) (result *mongo.Cursor, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - findOptions := options.Find() - findOptions.SetSort(Sort) - findOptions.SetLimit(Limit) - result, err = collection.Find(ms.Session, bson.D{{}}, findOptions) - return result, err -} - -// FindManyCollectionSort 查询集合文档支持排序支持条件 -func (ms *MongoTransaction) FindManyCollectionSort(filter interface{}, Sort interface{}) (result *mongo.Cursor, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - findOptions := options.Find() - findOptions.SetSort(Sort) - result, err = collection.Find(ms.Session, filter, findOptions) - return result, err -} - -// CollectionCount 查询集合里有多少数据 -func (ms *MongoTransaction) CollectionCount(ctx context.Context) (name string, size int64) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - name = collection.Name() - size, _ = collection.EstimatedDocumentCount(ctx) - return name, size -} - -// CollectionDocuments 按选项查询集合 -// Skip 跳过 -// Limit 读取数量 -// sort 1 ,-1 . 1 为升序 , -1 为降序 -func (ms *MongoTransaction) CollectionDocuments(Skip, Limit int64, sort int, key string, value interface{}) (result *mongo.Cursor, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - SORT := bson.D{{"_id", sort}} - filter := bson.D{{key, value}} - findOptions := options.Find().SetSort(SORT).SetLimit(Limit).SetSkip(Skip) - result, err = collection.Find(ms.Session, filter, findOptions) - return result, err -} - -// AggregateByFiltersSort 统计分析 -func (ms *MongoTransaction) AggregateByFiltersSort(pipeline interface{}) (result *mongo.Cursor, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - result, err = collection.Aggregate(ms.Session, pipeline) - return result, err -} - -// CountDocumentsByFilters 统计数量 -func (ms *MongoTransaction) CountDocumentsByFilters(filter interface{}) (count int64, err error) { - collection := ms.db.Database(ms.getDatabaseName()).Collection(ms.collectionName) - count, err = collection.CountDocuments(ms.Session, filter) - return count, err -} diff --git a/vendor/go.dtapp.net/dorm/mongo_transaction_get.go b/vendor/go.dtapp.net/dorm/mongo_transaction_get.go deleted file mode 100644 index 3926370..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_transaction_get.go +++ /dev/null @@ -1,11 +0,0 @@ -package dorm - -// 获取库名 -func (ms *MongoTransaction) getDatabaseName() string { - return ms.databaseName -} - -// 获取表名 -func (ms *MongoTransaction) getCollectionName() string { - return ms.collectionName -} diff --git a/vendor/go.dtapp.net/dorm/mongo_transaction_set.go b/vendor/go.dtapp.net/dorm/mongo_transaction_set.go deleted file mode 100644 index e36daa6..0000000 --- a/vendor/go.dtapp.net/dorm/mongo_transaction_set.go +++ /dev/null @@ -1,28 +0,0 @@ -package dorm - -import "reflect" - -// Database 设置库名 -func (ms *MongoTransaction) Database(databaseName string) *MongoTransaction { - ms.databaseName = databaseName - return ms -} - -// Collection 设置表名 -func (ms *MongoTransaction) Collection(collectionName string) *MongoTransaction { - ms.collectionName = collectionName - return ms -} - -// Model 传入模型自动获取库名和表名 -func (ms *MongoTransaction) Model(value interface{}) *MongoTransaction { - // https://studygolang.com/articles/896 - val := reflect.ValueOf(value) - if methodValue := val.MethodByName("Database"); methodValue.IsValid() { - ms.databaseName = methodValue.Call(nil)[0].String() - } - if methodValue := val.MethodByName("TableName"); methodValue.IsValid() { - ms.collectionName = methodValue.Call(nil)[0].String() - } - return ms -} diff --git a/vendor/go.dtapp.net/dorm/redis.go b/vendor/go.dtapp.net/dorm/redis.go index 6ce6648..41196db 100644 --- a/vendor/go.dtapp.net/dorm/redis.go +++ b/vendor/go.dtapp.net/dorm/redis.go @@ -8,6 +8,9 @@ import ( "time" ) +// RedisClientFun *RedisClient 驱动 +type RedisClientFun func() *RedisClient + type ConfigRedisClient struct { Addr string // 地址 Password string // 密码 diff --git a/vendor/go.dtapp.net/goip/.gitignore b/vendor/go.dtapp.net/goip/.gitignore index 27a3bc6..4a8d465 100644 --- a/vendor/go.dtapp.net/goip/.gitignore +++ b/vendor/go.dtapp.net/goip/.gitignore @@ -6,3 +6,6 @@ *.log *_test.go gomod.sh +*.zip +*.tar.gz +/vendor/ diff --git a/vendor/go.dtapp.net/goip/analyse.go b/vendor/go.dtapp.net/goip/analyse.go index 10fcab7..136900e 100644 --- a/vendor/go.dtapp.net/goip/analyse.go +++ b/vendor/go.dtapp.net/goip/analyse.go @@ -1,53 +1,53 @@ package goip import ( + "net" "strconv" ) -var ( - ipv4 = "IPV4" - ipv6 = "IPV6" -) - type AnalyseResult struct { - IP string `json:"ip,omitempty"` // 输入的ip地址 - Country string `json:"country,omitempty"` // 国家或地区 - Province string `json:"province,omitempty"` // 省份 - City string `json:"city,omitempty"` // 城市 - Area string `json:"area,omitempty"` // 区域 - Isp string `json:"isp,omitempty"` // 运营商 + Ip string `json:"ip"` // ip + Continent string `json:"continent"` // 大陆 + Country string `json:"country"` // 国家 + Province string `json:"province"` // 省份 + City string `json:"city"` // 城市 + Isp string `json:"isp"` // 运营商 + LocationTimeZone string `json:"location_time_zone"` // 位置时区 + LocationLatitude float64 `json:"location_latitude"` // 位置纬度 + LocationLongitude float64 `json:"location_longitude"` // 位置经度 } func (c *Client) Analyse(item string) AnalyseResult { isIp := c.isIpv4OrIpv6(item) + ipByte := net.ParseIP(item) switch isIp { case ipv4: - info := c.V4db.Find(item) - search, err := c.V4Region.MemorySearch(item) - if err != nil { - return AnalyseResult{ - IP: info.IP, - Country: info.Country, - Area: info.Area, - } - } else { - return AnalyseResult{ - IP: search.IP, - Country: search.Country, - Province: search.Province, - City: search.City, - Isp: info.Area, - } + ip2regionV2Info, _ := c.QueryIp2RegionV2(ipByte) + geoIpInfo, _ := c.QueryGeoIp(ipByte) + return AnalyseResult{ + Ip: ipByte.String(), + Continent: geoIpInfo.Continent.Name, + Country: geoIpInfo.Country.Name, + Province: ip2regionV2Info.Province, + City: ip2regionV2Info.City, + Isp: ip2regionV2Info.Operator, + LocationTimeZone: geoIpInfo.Location.TimeZone, + LocationLatitude: geoIpInfo.Location.Latitude, + LocationLongitude: geoIpInfo.Location.Longitude, } case ipv6: - info := c.V6db.Find(item) + geoIpInfo, _ := c.QueryGeoIp(ipByte) + ipv6Info, _ := c.QueryIpv6wry(ipByte) return AnalyseResult{ - IP: info.IP, - Country: info.Country, - Province: info.Province, - City: info.City, - Area: info.Area, - Isp: info.Isp, + Ip: ipByte.String(), + Continent: geoIpInfo.Continent.Name, + Country: geoIpInfo.Country.Name, + Province: ipv6Info.Province, + City: ipv6Info.City, + Isp: ipv6Info.Isp, + LocationTimeZone: geoIpInfo.Location.TimeZone, + LocationLatitude: geoIpInfo.Location.Latitude, + LocationLongitude: geoIpInfo.Location.Longitude, } default: return AnalyseResult{} diff --git a/vendor/go.dtapp.net/goip/client.go b/vendor/go.dtapp.net/goip/client.go new file mode 100644 index 0000000..20f3527 --- /dev/null +++ b/vendor/go.dtapp.net/goip/client.go @@ -0,0 +1,39 @@ +package goip + +import ( + "go.dtapp.net/goip/geoip" + "go.dtapp.net/goip/ip2region" + "go.dtapp.net/goip/ip2region_v2" + "go.dtapp.net/goip/ipv6wry" + "go.dtapp.net/goip/qqwry" +) + +type Client struct { + ip2regionV2Client *ip2region_v2.Client + ip2regionClient *ip2region.Client + qqwryClient *qqwry.Client + geoIpClient *geoip.Client + ipv6wryClient *ipv6wry.Client +} + +// NewIp 实例化 +func NewIp() *Client { + + c := &Client{} + + c.ip2regionV2Client, _ = ip2region_v2.New() + + c.ip2regionClient = ip2region.New() + + c.qqwryClient = qqwry.New() + + c.geoIpClient, _ = geoip.New() + + c.ipv6wryClient = ipv6wry.New() + + return c +} + +func (c *Client) Close() { + c.geoIpClient.Close() +} diff --git a/vendor/go.dtapp.net/goip/const.go b/vendor/go.dtapp.net/goip/const.go index 70adccf..9048532 100644 --- a/vendor/go.dtapp.net/goip/const.go +++ b/vendor/go.dtapp.net/goip/const.go @@ -1,3 +1,3 @@ package goip -const Version = "1.0.30" +const Version = "1.0.36" diff --git a/vendor/go.dtapp.net/goip/geoip/GeoLite2-ASN.mmdb b/vendor/go.dtapp.net/goip/geoip/GeoLite2-ASN.mmdb new file mode 100644 index 0000000..7b1f24d Binary files /dev/null and b/vendor/go.dtapp.net/goip/geoip/GeoLite2-ASN.mmdb differ diff --git a/vendor/go.dtapp.net/goip/geoip/GeoLite2-City.mmdb b/vendor/go.dtapp.net/goip/geoip/GeoLite2-City.mmdb new file mode 100644 index 0000000..0482b28 Binary files /dev/null and b/vendor/go.dtapp.net/goip/geoip/GeoLite2-City.mmdb differ diff --git a/vendor/go.dtapp.net/goip/geoip/GeoLite2-Country.mmdb b/vendor/go.dtapp.net/goip/geoip/GeoLite2-Country.mmdb new file mode 100644 index 0000000..ef8c639 Binary files /dev/null and b/vendor/go.dtapp.net/goip/geoip/GeoLite2-Country.mmdb differ diff --git a/vendor/go.dtapp.net/goip/geoip/client.go b/vendor/go.dtapp.net/goip/geoip/client.go new file mode 100644 index 0000000..3bb9d01 --- /dev/null +++ b/vendor/go.dtapp.net/goip/geoip/client.go @@ -0,0 +1,52 @@ +package geoip + +import ( + _ "embed" + "github.com/oschwald/geoip2-golang" +) + +//go:embed GeoLite2-ASN.mmdb +var asnBuff []byte + +//go:embed GeoLite2-City.mmdb +var cityBuff []byte + +//go:embed GeoLite2-Country.mmdb +var countryBuff []byte + +type Client struct { + asnDb *geoip2.Reader + cityDb *geoip2.Reader + countryDb *geoip2.Reader +} + +func New() (*Client, error) { + + var err error + c := &Client{} + + c.asnDb, err = geoip2.FromBytes(asnBuff) + if err != nil { + return nil, err + } + + c.cityDb, err = geoip2.FromBytes(cityBuff) + if err != nil { + return nil, err + } + + c.countryDb, err = geoip2.FromBytes(countryBuff) + if err != nil { + return nil, err + } + + return c, err +} + +func (c *Client) Close() { + + c.asnDb.Close() + c.cityDb.Close() + c.countryDb.Close() + +} diff --git a/vendor/go.dtapp.net/goip/geoip/download.go b/vendor/go.dtapp.net/goip/geoip/download.go new file mode 100644 index 0000000..2eefdbd --- /dev/null +++ b/vendor/go.dtapp.net/goip/geoip/download.go @@ -0,0 +1,23 @@ +package geoip + +import ( + "io/ioutil" + "log" + "net/http" +) + +func OnlineDownload(downloadUrl string, downloadName string) { + resp, err := http.Get(downloadUrl) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + + err = ioutil.WriteFile("./"+downloadName, body, 0644) + if err != nil { + panic(err) + } + log.Printf("已下载最新 ip2region.xdb 数据库 %s ", "./"+downloadName) +} diff --git a/vendor/go.dtapp.net/goip/geoip/download_url.go b/vendor/go.dtapp.net/goip/geoip/download_url.go new file mode 100644 index 0000000..5fb70aa --- /dev/null +++ b/vendor/go.dtapp.net/goip/geoip/download_url.go @@ -0,0 +1,31 @@ +package geoip + +import ( + "go.dtapp.net/gostring" +) + +var licenseKey = "" // 许可证密钥 + +func GetGeoLite2AsnDownloadUrl() string { + return gostring.Replace("https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-ASN&license_key=YOUR_LICENSE_KEY&suffix=tar.gz", "YOUR_LICENSE_KEY", licenseKey) +} + +//func GetGeoLite2AsnCsvDownloadUrl() string { +// return gostring.Replace("https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-ASN-CSV&license_key=YOUR_LICENSE_KEY&suffix=zip", "YOUR_LICENSE_KEY", licenseKey) +//} + +func GetGeoLite2CityDownloadUrl() string { + return gostring.Replace("https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=YOUR_LICENSE_KEY&suffix=tar.gz", "YOUR_LICENSE_KEY", licenseKey) +} + +//func GetGeoLite2CityCsvDownloadUrl() string { +// return gostring.Replace("https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City-CSV&license_key=YOUR_LICENSE_KEY&suffix=zip", "YOUR_LICENSE_KEY", licenseKey) +//} + +func GetGeoLite2CountryDownloadUrl() string { + return gostring.Replace("https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=YOUR_LICENSE_KEY&suffix=tar.gz", "YOUR_LICENSE_KEY", licenseKey) +} + +//func GetGeoLite2CountryCsvDownloadUrl() string { +// return gostring.Replace("https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&license_key=YOUR_LICENSE_KEY&suffix=zip", "YOUR_LICENSE_KEY", licenseKey) +//} diff --git a/vendor/go.dtapp.net/goip/geoip/query.go b/vendor/go.dtapp.net/goip/geoip/query.go new file mode 100644 index 0000000..e9b34a8 --- /dev/null +++ b/vendor/go.dtapp.net/goip/geoip/query.go @@ -0,0 +1,66 @@ +package geoip + +import ( + _ "embed" + "net" +) + +// QueryCityResult 返回 +type QueryCityResult struct { + Ip string `json:"ip,omitempty"` // ip + Continent struct { + Code string `json:"code,omitempty"` // 大陆代码 + Name string `json:"name,omitempty"` // 大陆名称 + } `json:"continent,omitempty"` + Country struct { + Code string `json:"code,omitempty"` // 国家代码 + Name string `json:"name,omitempty"` // 国家名称 + } `json:"country,omitempty"` + Province struct { + Code string `json:"code,omitempty"` // 省份代码 + Name string `json:"name,omitempty"` // 省份名称 + } `json:"province,omitempty"` + City struct { + Name string `json:"name,omitempty"` // 城市名称 + } `json:"city,omitempty"` + Location struct { + TimeZone string `json:"time_zone,omitempty"` // 位置时区 + Latitude float64 `json:"latitude,omitempty"` // 坐标纬度 + Longitude float64 `json:"longitude,omitempty"` // 坐标经度 + } `json:"location,omitempty"` +} + +func (c *Client) QueryCity(ipAddress net.IP) (result QueryCityResult, err error) { + + record, err := c.cityDb.City(ipAddress) + if err != nil { + return QueryCityResult{}, err + } + + // ip + result.Ip = ipAddress.String() + + // 大陆 + result.Continent.Code = record.Continent.Code + result.Continent.Name = record.Continent.Names["zh-CN"] + + // 国家 + result.Country.Code = record.Country.IsoCode + result.Country.Name = record.Country.Names["zh-CN"] + + // 省份 + if len(record.Subdivisions) > 0 { + result.Province.Code = record.Subdivisions[0].IsoCode + result.Province.Name = record.Subdivisions[0].Names["zh-CN"] + } + + // 城市 + result.City.Name = record.City.Names["zh-CN"] + + // 位置 + result.Location.TimeZone = record.Location.TimeZone + result.Location.Latitude = record.Location.Latitude + result.Location.Longitude = record.Location.Longitude + + return result, err +} diff --git a/vendor/go.dtapp.net/goip/goip.go b/vendor/go.dtapp.net/goip/goip.go deleted file mode 100644 index 818d629..0000000 --- a/vendor/go.dtapp.net/goip/goip.go +++ /dev/null @@ -1,63 +0,0 @@ -package goip - -import ( - "go.dtapp.net/goip/ip2region" - v4 "go.dtapp.net/goip/v4" - v6 "go.dtapp.net/goip/v6" - "log" - "strings" -) - -type Client struct { - V4Region ip2region.Ip2Region // IPV4 - V4db v4.Pointer // IPV4 - V6db v6.Pointer // IPV6 -} - -// NewIp 实例化 -func NewIp() *Client { - app := &Client{} - v4Num := app.V4db.InitIPV4Data() - log.Printf("IPV4 库加载完成 共加载:%d 条 IP 记录\n", v4Num) - v6Num := app.V6db.InitIPV4Data() - log.Printf("IPV6 库加载完成 共加载:%d 条 IP 记录\n", v6Num) - return app -} - -func (c *Client) Ipv4(ip string) (res v4.Result, resInfo ip2region.IpInfo) { - res = c.V4db.Find(ip) - resInfo, _ = c.V4Region.MemorySearch(ip) - return res, resInfo -} - -func (c *Client) Ipv6(ip string) (res v6.Result) { - res = c.V6db.Find(ip) - return res -} - -func (c *Client) isIpv4OrIpv6(ip string) string { - if len(ip) < 7 { - return "" - } - arrIpv4 := strings.Split(ip, ".") - if len(arrIpv4) == 4 { - //. 判断IPv4 - for _, val := range arrIpv4 { - if !c.CheckIpv4(val) { - return "" - } - } - return ipv4 - } - arrIpv6 := strings.Split(ip, ":") - if len(arrIpv6) == 8 { - // 判断Ipv6 - for _, val := range arrIpv6 { - if !c.CheckIpv6(val) { - return "Neither" - } - } - return ipv6 - } - return "" -} diff --git a/vendor/go.dtapp.net/goip/ip.go b/vendor/go.dtapp.net/goip/ip.go index 28613e9..d2c1cd5 100644 --- a/vendor/go.dtapp.net/goip/ip.go +++ b/vendor/go.dtapp.net/goip/ip.go @@ -4,11 +4,13 @@ import ( "context" "encoding/json" "go.dtapp.net/gorequest" + "log" "net" ) // GetInsideIp 内网ip func GetInsideIp(ctx context.Context) string { + conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { panic(err) @@ -47,30 +49,35 @@ func Ips(ctx context.Context) (map[string]string, error) { return ips, nil } -var respGetOutsideIp struct { - Data struct { - Ip string `json:"ip"` - } `json:"data"` -} - // GetOutsideIp 外网ip -func GetOutsideIp(ctx context.Context) (ip string) { - ip = "0.0.0.0" - get := gorequest.NewHttp() - get.SetUri("https://api.dtapp.net/ip") - response, err := get.Get(ctx) +func GetOutsideIp(ctx context.Context) string { + + // 返回结果 + type respGetOutsideIp struct { + Data struct { + Ip string `json:"ip,omitempty"` + } `json:"data"` + } + + // 请求 + getHttp := gorequest.NewHttp() + getHttp.SetUri("https://api.dtapp.net/ip") + response, err := getHttp.Get(ctx) if err != nil { - return + log.Printf("[GetOutsideIp]getHttp.Get:%s\n", err) + return "0.0.0.0" } - err = json.Unmarshal(response.ResponseBody, &respGetOutsideIp) + // 解析 + var responseJson respGetOutsideIp + err = json.Unmarshal(response.ResponseBody, &responseJson) if err != nil { - return + log.Printf("[GetOutsideIp]json.Unmarshal:%s\n", err) + return "0.0.0.0" } - if respGetOutsideIp.Data.Ip == "" { - return + if responseJson.Data.Ip == "" { + responseJson.Data.Ip = "0.0.0.0" } - ip = respGetOutsideIp.Data.Ip - return respGetOutsideIp.Data.Ip + return responseJson.Data.Ip } // GetMacAddr 获取Mac地址 diff --git a/vendor/go.dtapp.net/goip/ip2region/client.go b/vendor/go.dtapp.net/goip/ip2region/client.go new file mode 100644 index 0000000..19c13c6 --- /dev/null +++ b/vendor/go.dtapp.net/goip/ip2region/client.go @@ -0,0 +1,103 @@ +package ip2region + +import ( + _ "embed" + "errors" + "go.dtapp.net/gostring" + "os" + "strconv" + "strings" +) + +const ( + IndexBlockLength = 12 +) + +//go:embed ip2region.db +var dbBuff []byte + +type Client struct { + // db file handler + dbFileHandler *os.File + + //header block info + + headerSip []int64 + headerPtr []int64 + headerLen int64 + + // super block index info + firstIndexPtr int64 + lastIndexPtr int64 + totalBlocks int64 + + // for memory mode only + // the original db binary string + + dbFile string +} + +func New() *Client { + + c := &Client{} + + return c +} + +// 获取Ip信息 +func getIpInfo(ipStr string, cityId int64, line []byte) (result QueryResult) { + + lineSlice := strings.Split(string(line), "|") + length := len(lineSlice) + result.CityId = cityId + if length < 5 { + for i := 0; i <= 5-length; i++ { + lineSlice = append(lineSlice, "") + } + } + + if lineSlice[0] != "0" { + result.Country = gostring.SpaceAndLineBreak(lineSlice[0]) + } + if lineSlice[1] != "0" { + result.Region = gostring.SpaceAndLineBreak(lineSlice[1]) + } + if lineSlice[2] != "0" { + result.Province = gostring.SpaceAndLineBreak(lineSlice[2]) + } + if lineSlice[3] != "0" { + result.City = gostring.SpaceAndLineBreak(lineSlice[3]) + } + if lineSlice[4] != "0" { + result.Isp = gostring.SpaceAndLineBreak(lineSlice[4]) + } + + result.Ip = ipStr + return result +} + +func getLong(b []byte, offset int64) int64 { + + val := int64(b[offset]) | + int64(b[offset+1])<<8 | + int64(b[offset+2])<<16 | + int64(b[offset+3])<<24 + + return val + +} + +func ip2long(IpStr string) (int64, error) { + bits := strings.Split(IpStr, ".") + if len(bits) != 4 { + return 0, errors.New("ip format error") + } + + var sum int64 + for i, n := range bits { + bit, _ := strconv.ParseInt(n, 10, 64) + sum += bit << uint(24-8*i) + } + + return sum, nil +} diff --git a/vendor/go.dtapp.net/goip/ip2region/download.go b/vendor/go.dtapp.net/goip/ip2region/download.go index 2e95e61..e45bb73 100644 --- a/vendor/go.dtapp.net/goip/ip2region/download.go +++ b/vendor/go.dtapp.net/goip/ip2region/download.go @@ -2,16 +2,22 @@ package ip2region import ( "io/ioutil" + "log" "net/http" ) -func getOnline() ([]byte, error) { - resp, err := http.Get("https://ghproxy.com/?q=https://github.com/lionsoul2014/ip2region/blob/master/data/ip2region.db?raw=true") +func OnlineDownload() { + resp, err := http.Get("https://ghproxy.com/?q=https://github.com/lionsoul2014/ip2region/blob/master/v1.0/data/ip2region.db?raw=true") if err != nil { - return nil, err + panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) - return body, err + + err = ioutil.WriteFile("./ip2region.db", body, 0644) + if err != nil { + panic(err) + } + log.Printf("已下载最新 ip2region 数据库 %s ", "./ip2region.db") } diff --git a/vendor/go.dtapp.net/goip/ip2region/ip.db b/vendor/go.dtapp.net/goip/ip2region/ip2region.db similarity index 100% rename from vendor/go.dtapp.net/goip/ip2region/ip.db rename to vendor/go.dtapp.net/goip/ip2region/ip2region.db diff --git a/vendor/go.dtapp.net/goip/ip2region/ip2region.go b/vendor/go.dtapp.net/goip/ip2region/ip2region.go deleted file mode 100644 index cef1492..0000000 --- a/vendor/go.dtapp.net/goip/ip2region/ip2region.go +++ /dev/null @@ -1,183 +0,0 @@ -package ip2region - -import ( - _ "embed" - "errors" - "go.dtapp.net/gostring" - "io/ioutil" - "log" - "net" - "os" - "strconv" - "strings" -) - -const ( - IndexBlockLength = 12 -) - -type Ip2Region struct { - // db file handler - dbFileHandler *os.File - - //header block info - - headerSip []int64 - headerPtr []int64 - headerLen int64 - - // super block index info - firstIndexPtr int64 - lastIndexPtr int64 - totalBlocks int64 - - // for memory mode only - // the original db binary string - - dbFile string -} - -//go:embed ip.db -var dbBinStr []byte - -type IpInfo struct { - IP string `json:"ip,omitempty"` // 输入的ip地址 - CityID int64 `json:"city_id,omitempty"` // 城市ID - Country string `json:"country,omitempty"` // 国家 - Region string `json:"region,omitempty"` // 区域 - Province string `json:"province,omitempty"` // 省份 - City string `json:"city,omitempty"` // 城市 - ISP string `json:"isp,omitempty"` // 运营商 -} - -func (ip IpInfo) String() string { - return ip.IP + "|" + strconv.FormatInt(ip.CityID, 10) + "|" + ip.Country + "|" + ip.Region + "|" + ip.Province + "|" + ip.City + "|" + ip.ISP -} - -// 获取Ip信息 -func getIpInfo(ipStr string, cityId int64, line []byte) (ipInfo IpInfo) { - - lineSlice := strings.Split(string(line), "|") - length := len(lineSlice) - ipInfo.CityID = cityId - if length < 5 { - for i := 0; i <= 5-length; i++ { - lineSlice = append(lineSlice, "") - } - } - - if lineSlice[0] != "0" { - ipInfo.Country = gostring.SpaceAndLineBreak(lineSlice[0]) - } - if lineSlice[1] != "0" { - ipInfo.Region = gostring.SpaceAndLineBreak(lineSlice[1]) - } - if lineSlice[2] != "0" { - ipInfo.Province = gostring.SpaceAndLineBreak(lineSlice[2]) - } - if lineSlice[3] != "0" { - ipInfo.City = gostring.SpaceAndLineBreak(lineSlice[3]) - } - if lineSlice[4] != "0" { - ipInfo.ISP = gostring.SpaceAndLineBreak(lineSlice[4]) - } - - ipInfo.IP = ipStr - return ipInfo -} - -// MemorySearch memory算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内 -func (r *Ip2Region) MemorySearch(ipStr string) (ipInfo IpInfo, err error) { - - ipInfo.IP = ipStr - if net.ParseIP(ipStr).To4() == nil { - if net.ParseIP(ipStr).To16() == nil { - return ipInfo, err - } - } - - if r.totalBlocks == 0 { - - if err != nil { - - return ipInfo, err - } - - r.firstIndexPtr = getLong(dbBinStr, 0) - r.lastIndexPtr = getLong(dbBinStr, 4) - r.totalBlocks = (r.lastIndexPtr-r.firstIndexPtr)/IndexBlockLength + 1 - } - - ip, err := ip2long(ipStr) - if err != nil { - return ipInfo, err - } - - h := r.totalBlocks - var dataPtr, l int64 - for l <= h { - - m := (l + h) >> 1 - p := r.firstIndexPtr + m*IndexBlockLength - sip := getLong(dbBinStr, p) - if ip < sip { - h = m - 1 - } else { - eip := getLong(dbBinStr, p+4) - if ip > eip { - l = m + 1 - } else { - dataPtr = getLong(dbBinStr, p+8) - break - } - } - } - if dataPtr == 0 { - return ipInfo, errors.New("not found") - } - - dataLen := (dataPtr >> 24) & 0xFF - dataPtr = dataPtr & 0x00FFFFFF - ipInfo = getIpInfo(ipStr, getLong(dbBinStr, dataPtr), dbBinStr[(dataPtr)+4:dataPtr+dataLen]) - return ipInfo, nil - -} - -func getLong(b []byte, offset int64) int64 { - - val := int64(b[offset]) | - int64(b[offset+1])<<8 | - int64(b[offset+2])<<16 | - int64(b[offset+3])<<24 - - return val - -} - -func ip2long(IpStr string) (int64, error) { - bits := strings.Split(IpStr, ".") - if len(bits) != 4 { - return 0, errors.New("ip format error") - } - - var sum int64 - for i, n := range bits { - bit, _ := strconv.ParseInt(n, 10, 64) - sum += bit << uint(24-8*i) - } - - return sum, nil -} - -func (r *Ip2Region) OnlineDownload() (err error) { - tmpData, err := getOnline() - if err != nil { - return errors.New("下载失败 %s" + err.Error()) - } - if err := ioutil.WriteFile("./ip2region.db", tmpData, 0644); err == nil { - log.Printf("已下载最新 ip2region 数据库 %s ", "./ip2region.db") - } else { - return errors.New("保存失败") - } - return nil -} diff --git a/vendor/go.dtapp.net/goip/ip2region/qqery.go b/vendor/go.dtapp.net/goip/ip2region/qqery.go new file mode 100644 index 0000000..330dedc --- /dev/null +++ b/vendor/go.dtapp.net/goip/ip2region/qqery.go @@ -0,0 +1,73 @@ +package ip2region + +import ( + "errors" + "net" + "strconv" +) + +type QueryResult struct { + Ip string `json:"ip,omitempty"` // ip + CityId int64 `json:"city_id,omitempty"` // 城市代码 + Country string `json:"country,omitempty"` // 国家 + Region string `json:"region,omitempty"` // 区域 + Province string `json:"province,omitempty"` // 省份 + City string `json:"city,omitempty"` // 城市 + Isp string `json:"isp,omitempty"` // 运营商 +} + +func (ip QueryResult) String() string { + return ip.Ip + "|" + strconv.FormatInt(ip.CityId, 10) + "|" + ip.Country + "|" + ip.Region + "|" + ip.Province + "|" + ip.City + "|" + ip.Isp +} + +// Query memory算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内 +func (c *Client) Query(ipAddress net.IP) (result QueryResult, err error) { + + result.Ip = ipAddress.String() + + if c.totalBlocks == 0 { + + if err != nil { + + return QueryResult{}, err + } + + c.firstIndexPtr = getLong(dbBuff, 0) + c.lastIndexPtr = getLong(dbBuff, 4) + c.totalBlocks = (c.lastIndexPtr-c.firstIndexPtr)/IndexBlockLength + 1 + } + + ip, err := ip2long(result.Ip) + if err != nil { + return QueryResult{}, err + } + + h := c.totalBlocks + var dataPtr, l int64 + for l <= h { + + m := (l + h) >> 1 + p := c.firstIndexPtr + m*IndexBlockLength + sip := getLong(dbBuff, p) + if ip < sip { + h = m - 1 + } else { + eip := getLong(dbBuff, p+4) + if ip > eip { + l = m + 1 + } else { + dataPtr = getLong(dbBuff, p+8) + break + } + } + } + if dataPtr == 0 { + return QueryResult{}, errors.New("not found") + } + + dataLen := (dataPtr >> 24) & 0xFF + dataPtr = dataPtr & 0x00FFFFFF + result = getIpInfo(result.Ip, getLong(dbBuff, dataPtr), dbBuff[(dataPtr)+4:dataPtr+dataLen]) + + return result, nil +} diff --git a/vendor/go.dtapp.net/goip/ip2region_v2/client.go b/vendor/go.dtapp.net/goip/ip2region_v2/client.go new file mode 100644 index 0000000..9213643 --- /dev/null +++ b/vendor/go.dtapp.net/goip/ip2region_v2/client.go @@ -0,0 +1,26 @@ +package ip2region_v2 + +import _ "embed" + +//go:embed ip2region.xdb +var cBuff []byte + +type Client struct { + db *Searcher +} + +func New() (*Client, error) { + + var err error + c := &Client{} + + // 1、从 dbPath 加载整个 xdb 到内存 + + // 2、用全局的 cBuff 创建完全基于内存的查询对象。 + c.db, err = NewWithBuffer(cBuff) + if err != nil { + return nil, err + } + + return c, err +} diff --git a/vendor/go.dtapp.net/goip/ip2region_v2/download.go b/vendor/go.dtapp.net/goip/ip2region_v2/download.go new file mode 100644 index 0000000..0f84054 --- /dev/null +++ b/vendor/go.dtapp.net/goip/ip2region_v2/download.go @@ -0,0 +1,23 @@ +package ip2region_v2 + +import ( + "io/ioutil" + "log" + "net/http" +) + +func OnlineDownload() { + resp, err := http.Get("https://ghproxy.com/?q=https://github.com/lionsoul2014/ip2region/blob/master/data/ip2region.xdb?raw=true") + if err != nil { + panic(err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + + err = ioutil.WriteFile("./ip2region.xdb", body, 0644) + if err != nil { + panic(err) + } + log.Printf("已下载最新 ip2region.xdb 数据库 %s ", "./ip2region.xdb") +} diff --git a/vendor/go.dtapp.net/goip/ip2region_v2/ip2region.xdb b/vendor/go.dtapp.net/goip/ip2region_v2/ip2region.xdb new file mode 100644 index 0000000..31f96a1 Binary files /dev/null and b/vendor/go.dtapp.net/goip/ip2region_v2/ip2region.xdb differ diff --git a/vendor/go.dtapp.net/goip/ip2region_v2/query.go b/vendor/go.dtapp.net/goip/ip2region_v2/query.go new file mode 100644 index 0000000..de90582 --- /dev/null +++ b/vendor/go.dtapp.net/goip/ip2region_v2/query.go @@ -0,0 +1,52 @@ +package ip2region_v2 + +import ( + _ "embed" + "go.dtapp.net/gostring" + "net" +) + +// QueryResult 返回 +type QueryResult struct { + Ip string `json:"ip,omitempty"` // ip + Country string `json:"country,omitempty"` // 国家 + Province string `json:"province,omitempty"` // 省份 + City string `json:"city,omitempty"` // 城市 + Operator string `json:"operator,omitempty"` // 运营商 +} + +func (c *Client) Query(ipAddress net.IP) (result QueryResult, err error) { + + // 备注:并发使用,用整个 xdb 缓存创建的 searcher 对象可以安全用于并发。 + + str, err := c.db.SearchByStr(ipAddress.String()) + if err != nil { + return QueryResult{}, err + } + + split := gostring.Split(str, "|") + if len(split) <= 0 { + return QueryResult{}, err + } + + result.Ip = ipAddress.String() + + result.Country = split[0] + if result.Country == "0" { + result.Country = "" + } + result.Province = split[2] + if result.Province == "0" { + result.Province = "" + } + result.City = split[3] + if result.City == "0" { + result.City = "" + } + result.Operator = split[4] + if result.Operator == "0" { + result.Operator = "" + } + + return result, err +} diff --git a/vendor/go.dtapp.net/goip/ip2region_v2/searcher.go b/vendor/go.dtapp.net/goip/ip2region_v2/searcher.go new file mode 100644 index 0000000..7d5e9a3 --- /dev/null +++ b/vendor/go.dtapp.net/goip/ip2region_v2/searcher.go @@ -0,0 +1,240 @@ +package ip2region_v2 + +import ( + "encoding/binary" + "fmt" + "os" +) + +const ( + HeaderInfoLength = 256 + VectorIndexRows = 256 + VectorIndexCols = 256 + VectorIndexSize = 8 + SegmentIndexBlockSize = 14 +) + +// --- Index policy define + +type IndexPolicy int + +const ( + VectorIndexPolicy IndexPolicy = 1 + BTreeIndexPolicy IndexPolicy = 2 +) + +func (i IndexPolicy) String() string { + switch i { + case VectorIndexPolicy: + return "VectorIndex" + case BTreeIndexPolicy: + return "BtreeIndex" + default: + return "unknown" + } +} + +// --- Header define + +type Header struct { + // data []byte + Version uint16 + IndexPolicy IndexPolicy + CreatedAt uint32 + StartIndexPtr uint32 + EndIndexPtr uint32 +} + +func NewHeader(input []byte) (*Header, error) { + if len(input) < 16 { + return nil, fmt.Errorf("invalid input buffer") + } + + return &Header{ + Version: binary.LittleEndian.Uint16(input), + IndexPolicy: IndexPolicy(binary.LittleEndian.Uint16(input[2:])), + CreatedAt: binary.LittleEndian.Uint32(input[4:]), + StartIndexPtr: binary.LittleEndian.Uint32(input[8:]), + EndIndexPtr: binary.LittleEndian.Uint32(input[12:]), + }, nil +} + +// --- searcher implementation + +type Searcher struct { + handle *os.File + + // header info + header *Header + ioCount int + + // use it only when this feature enabled. + // Preload the vector index will reduce the number of IO operations + // thus speedup the search process + vectorIndex []byte + + // content buffer. + // running with the whole xdb file cached + contentBuff []byte +} + +func baseNew(dbFile string, vIndex []byte, cBuff []byte) (*Searcher, error) { + var err error + + // content buff first + if cBuff != nil { + return &Searcher{ + vectorIndex: nil, + contentBuff: cBuff, + }, nil + } + + // open the xdb binary file + handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600) + if err != nil { + return nil, err + } + + return &Searcher{ + handle: handle, + vectorIndex: vIndex, + }, nil +} + +func NewWithFileOnly(dbFile string) (*Searcher, error) { + return baseNew(dbFile, nil, nil) +} + +func NewWithVectorIndex(dbFile string, vIndex []byte) (*Searcher, error) { + return baseNew(dbFile, vIndex, nil) +} + +func NewWithBuffer(cBuff []byte) (*Searcher, error) { + return baseNew("", nil, cBuff) +} + +func (s *Searcher) Close() { + if s.handle != nil { + err := s.handle.Close() + if err != nil { + return + } + } +} + +// GetIOCount return the global io count for the last search +func (s *Searcher) GetIOCount() int { + return s.ioCount +} + +// SearchByStr find the region for the specified ip string +func (s *Searcher) SearchByStr(str string) (string, error) { + ip, err := CheckIP(str) + if err != nil { + return "", err + } + + return s.Search(ip) +} + +// Search find the region for the specified long ip +func (s *Searcher) Search(ip uint32) (string, error) { + // reset the global ioCount + s.ioCount = 0 + + // locate the segment index block based on the vector index + var il0 = (ip >> 24) & 0xFF + var il1 = (ip >> 16) & 0xFF + var idx = il0*VectorIndexCols*VectorIndexSize + il1*VectorIndexSize + var sPtr, ePtr = uint32(0), uint32(0) + if s.vectorIndex != nil { + sPtr = binary.LittleEndian.Uint32(s.vectorIndex[idx:]) + ePtr = binary.LittleEndian.Uint32(s.vectorIndex[idx+4:]) + } else if s.contentBuff != nil { + sPtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx:]) + ePtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx+4:]) + } else { + // read the vector index block + var buff = make([]byte, VectorIndexSize) + err := s.read(int64(HeaderInfoLength+idx), buff) + if err != nil { + return "", fmt.Errorf("read vector index block at %d: %w", HeaderInfoLength+idx, err) + } + + sPtr = binary.LittleEndian.Uint32(buff) + ePtr = binary.LittleEndian.Uint32(buff[4:]) + } + + // fmt.Printf("sPtr=%d, ePtr=%d", sPtr, ePtr) + + // binary search the segment index to get the region + var dataLen, dataPtr = 0, uint32(0) + var buff = make([]byte, SegmentIndexBlockSize) + var l, h = 0, int((ePtr - sPtr) / SegmentIndexBlockSize) + for l <= h { + m := (l + h) >> 1 + p := sPtr + uint32(m*SegmentIndexBlockSize) + err := s.read(int64(p), buff) + if err != nil { + return "", fmt.Errorf("read segment index at %d: %w", p, err) + } + + // decode the data step by step to reduce the unnecessary operations + sip := binary.LittleEndian.Uint32(buff) + if ip < sip { + h = m - 1 + } else { + eip := binary.LittleEndian.Uint32(buff[4:]) + if ip > eip { + l = m + 1 + } else { + dataLen = int(binary.LittleEndian.Uint16(buff[8:])) + dataPtr = binary.LittleEndian.Uint32(buff[10:]) + break + } + } + } + + //fmt.Printf("dataLen: %d, dataPtr: %d", dataLen, dataPtr) + if dataLen == 0 { + return "", nil + } + + // load and return the region data + var regionBuff = make([]byte, dataLen) + err := s.read(int64(dataPtr), regionBuff) + if err != nil { + return "", fmt.Errorf("read region at %d: %w", dataPtr, err) + } + + return string(regionBuff), nil +} + +// do the data read operation based on the setting. +// content buffer first or will read from the file. +// this operation will invoke the Seek for file based read. +func (s *Searcher) read(offset int64, buff []byte) error { + if s.contentBuff != nil { + cLen := copy(buff, s.contentBuff[offset:]) + if cLen != len(buff) { + return fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) + } + } else { + _, err := s.handle.Seek(offset, 0) + if err != nil { + return fmt.Errorf("seek to %d: %w", offset, err) + } + + s.ioCount++ + rLen, err := s.handle.Read(buff) + if err != nil { + return fmt.Errorf("handle read: %w", err) + } + + if rLen != len(buff) { + return fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) + } + } + + return nil +} diff --git a/vendor/go.dtapp.net/goip/ip2region_v2/util.go b/vendor/go.dtapp.net/goip/ip2region_v2/util.go new file mode 100644 index 0000000..b981585 --- /dev/null +++ b/vendor/go.dtapp.net/goip/ip2region_v2/util.go @@ -0,0 +1,165 @@ +package ip2region_v2 + +import ( + "fmt" + "os" + "strconv" + "strings" +) + +var shiftIndex = []int{24, 16, 8, 0} + +func CheckIP(ip string) (uint32, error) { + var ps = strings.Split(ip, ".") + if len(ps) != 4 { + return 0, fmt.Errorf("invalid ip address `%s`", ip) + } + + var val = uint32(0) + for i, s := range ps { + d, err := strconv.Atoi(s) + if err != nil { + return 0, fmt.Errorf("the %dth part `%s` is not an integer", i, s) + } + + if d < 0 || d > 255 { + return 0, fmt.Errorf("the %dth part `%s` should be an integer bettween 0 and 255", i, s) + } + + val |= uint32(d) << shiftIndex[i] + } + + // convert the ip to integer + return val, nil +} + +func Long2IP(ip uint32) string { + return fmt.Sprintf("%d.%d.%d.%d", (ip>>24)&0xFF, (ip>>16)&0xFF, (ip>>8)&0xFF, ip&0xFF) +} + +func MidIP(sip uint32, eip uint32) uint32 { + return uint32((uint64(sip) + uint64(eip)) >> 1) +} + +// LoadHeader load the header info from the specified handle +func LoadHeader(handle *os.File) (*Header, error) { + _, err := handle.Seek(0, 0) + if err != nil { + return nil, fmt.Errorf("seek to the header: %w", err) + } + + var buff = make([]byte, HeaderInfoLength) + rLen, err := handle.Read(buff) + if err != nil { + return nil, err + } + + if rLen != len(buff) { + return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) + } + + return NewHeader(buff) +} + +// LoadHeaderFromFile load header info from the specified db file path +func LoadHeaderFromFile(dbFile string) (*Header, error) { + handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600) + if err != nil { + return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err) + } + + header, err := LoadHeader(handle) + if err != nil { + return nil, err + } + + _ = handle.Close() + return header, nil +} + +// LoadHeaderFromBuff wrap the header info from the content buffer +func LoadHeaderFromBuff(cBuff []byte) (*Header, error) { + return NewHeader(cBuff[0:256]) +} + +// LoadVectorIndex util function to load the vector index from the specified file handle +func LoadVectorIndex(handle *os.File) ([]byte, error) { + // load all the vector index block + _, err := handle.Seek(HeaderInfoLength, 0) + if err != nil { + return nil, fmt.Errorf("seek to vector index: %w", err) + } + + var buff = make([]byte, VectorIndexRows*VectorIndexCols*VectorIndexSize) + rLen, err := handle.Read(buff) + if err != nil { + return nil, err + } + + if rLen != len(buff) { + return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) + } + + return buff, nil +} + +// LoadVectorIndexFromFile load vector index from a specified file path +func LoadVectorIndexFromFile(dbFile string) ([]byte, error) { + handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600) + if err != nil { + return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err) + } + + vIndex, err := LoadVectorIndex(handle) + if err != nil { + return nil, err + } + + _ = handle.Close() + return vIndex, nil +} + +// LoadContent load the whole xdb content from the specified file handle +func LoadContent(handle *os.File) ([]byte, error) { + // get file size + fi, err := handle.Stat() + if err != nil { + return nil, fmt.Errorf("stat: %w", err) + } + + size := fi.Size() + + // seek to the head of the file + _, err = handle.Seek(0, 0) + if err != nil { + return nil, fmt.Errorf("seek to get xdb file length: %w", err) + } + + var buff = make([]byte, size) + rLen, err := handle.Read(buff) + if err != nil { + return nil, err + } + + if rLen != len(buff) { + return nil, fmt.Errorf("incomplete read: readed bytes should be %d", len(buff)) + } + + return buff, nil +} + +// LoadContentFromFile load the whole xdb content from the specified db file path +func LoadContentFromFile(dbFile string) ([]byte, error) { + handle, err := os.OpenFile(dbFile, os.O_RDONLY, 0600) + if err != nil { + return nil, fmt.Errorf("open xdb file `%s`: %w", dbFile, err) + } + + cBuff, err := LoadContent(handle) + if err != nil { + return nil, err + } + + _ = handle.Close() + return cBuff, nil +} diff --git a/vendor/go.dtapp.net/goip/ipv6wry/client.go b/vendor/go.dtapp.net/goip/ipv6wry/client.go new file mode 100644 index 0000000..f07ca91 --- /dev/null +++ b/vendor/go.dtapp.net/goip/ipv6wry/client.go @@ -0,0 +1,138 @@ +package ipv6wry + +import ( + _ "embed" + "encoding/binary" + "log" +) + +var ( + header []byte + country []byte + area []byte + v6ip uint64 + offset uint32 + start uint32 + end uint32 +) + +//go:embed ipv6wry.db +var datBuff []byte + +type Client struct { + Offset uint32 + ItemLen uint32 + IndexLen uint32 +} + +func New() *Client { + + c := &Client{} + + buf := datBuff[0:8] + start := binary.LittleEndian.Uint32(buf[:4]) + end := binary.LittleEndian.Uint32(buf[4:]) + + num := int64((end-start)/7 + 1) + log.Printf("ipv6wry.db 共加载:%d 条ip记录\n", num) + + return c +} + +// ReadData 从文件中读取数据 +func (c *Client) readData(length uint32) (rs []byte) { + end := c.Offset + length + dataNum := uint32(len(datBuff)) + if c.Offset > dataNum { + return nil + } + + if end > dataNum { + end = dataNum + } + rs = datBuff[c.Offset:end] + c.Offset = end + return rs +} + +func (c *Client) getAddr() ([]byte, []byte) { + mode := c.readData(1)[0] + if mode == 0x01 { + // [IP][0x01][国家和地区信息的绝对偏移地址] + c.Offset = byteToUInt32(c.readData(3)) + return c.getAddr() + } + // [IP][0x02][信息的绝对偏移][...] or [IP][国家][...] + _offset := c.Offset - 1 + c1 := c.readArea(_offset) + if mode == 0x02 { + c.Offset = 4 + _offset + } else { + c.Offset = _offset + uint32(1+len(c1)) + } + c2 := c.readArea(c.Offset) + return c1, c2 +} + +func (c *Client) readArea(offset uint32) []byte { + c.Offset = offset + mode := c.readData(1)[0] + if mode == 0x01 || mode == 0x02 { + return c.readArea(byteToUInt32(c.readData(3))) + } + c.Offset = offset + return c.readString() +} + +func (c *Client) readString() []byte { + data := make([]byte, 0) + for { + buf := c.readData(1) + if buf[0] == 0 { + break + } + data = append(data, buf[0]) + } + return data +} + +func (c *Client) searchIndex(ip uint64) uint32 { + + c.ItemLen = 8 + c.IndexLen = 11 + + header = datBuff[8:24] + start = binary.LittleEndian.Uint32(header[8:]) + counts := binary.LittleEndian.Uint32(header[:8]) + end = start + counts*c.IndexLen + + buf := make([]byte, c.IndexLen) + + for { + mid := start + c.IndexLen*(((end-start)/c.IndexLen)>>1) + buf = datBuff[mid : mid+c.IndexLen] + _ip := binary.LittleEndian.Uint64(buf[:c.ItemLen]) + + if end-start == c.IndexLen { + if ip >= binary.LittleEndian.Uint64(datBuff[end:end+c.ItemLen]) { + buf = datBuff[end : end+c.IndexLen] + } + return byteToUInt32(buf[c.ItemLen:]) + } + + if _ip > ip { + end = mid + } else if _ip < ip { + start = mid + } else if _ip == ip { + return byteToUInt32(buf[c.ItemLen:]) + } + } +} + +func byteToUInt32(data []byte) uint32 { + i := uint32(data[0]) & 0xff + i |= (uint32(data[1]) << 8) & 0xff00 + i |= (uint32(data[2]) << 16) & 0xff0000 + return i +} diff --git a/vendor/go.dtapp.net/goip/v6/download.go b/vendor/go.dtapp.net/goip/ipv6wry/download.go similarity index 76% rename from vendor/go.dtapp.net/goip/v6/download.go rename to vendor/go.dtapp.net/goip/ipv6wry/download.go index 84dc073..9a3339d 100644 --- a/vendor/go.dtapp.net/goip/v6/download.go +++ b/vendor/go.dtapp.net/goip/ipv6wry/download.go @@ -1,4 +1,4 @@ -package v6 +package ipv6wry import ( "github.com/saracen/go7z" @@ -9,28 +9,39 @@ import ( "os" ) -func getOnline() (data []byte, err error) { +func OnlineDownload() { resp, err := http.Get("https://ip.zxinc.org/ip.7z") if err != nil { - return nil, err + panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, err + panic(err) } file7z, err := ioutil.TempFile("", "*") if err != nil { - return nil, err + panic(err) } defer os.Remove(file7z.Name()) - if err := ioutil.WriteFile(file7z.Name(), body, 0644); err == nil { - return Un7z(file7z.Name()) + err = ioutil.WriteFile(file7z.Name(), body, 0644) + if err != nil { + panic(err) + } + + tmpData, err := Un7z(file7z.Name()) + if err != nil { + panic(err) + } + + err = ioutil.WriteFile("./ipv6wry.db", tmpData, 0644) + if err != nil { + panic(err) } - return + log.Printf("已下载最新 ZX IPv6数据库 %s ", "./ipv6wry.db") } func Un7z(filePath string) (data []byte, err error) { diff --git a/vendor/go.dtapp.net/goip/v6/ip.db b/vendor/go.dtapp.net/goip/ipv6wry/ipv6wry.db similarity index 100% rename from vendor/go.dtapp.net/goip/v6/ip.db rename to vendor/go.dtapp.net/goip/ipv6wry/ipv6wry.db diff --git a/vendor/go.dtapp.net/goip/ipv6wry/query.go b/vendor/go.dtapp.net/goip/ipv6wry/query.go new file mode 100644 index 0000000..332629b --- /dev/null +++ b/vendor/go.dtapp.net/goip/ipv6wry/query.go @@ -0,0 +1,82 @@ +package ipv6wry + +import ( + "go.dtapp.net/gostring" + "math/big" + "net" + "strings" +) + +// QueryResult 返回 +type QueryResult struct { + Ip string `json:"ip,omitempty"` // ip + Country string `json:"country,omitempty"` // 国家 + Province string `json:"province,omitempty"` // 省份 + City string `json:"city,omitempty"` // 城市 + Area string `json:"area,omitempty"` // 区域 + Isp string `json:"isp,omitempty"` // 运营商 +} + +// Query ip地址查询对应归属地信息 +func (c *Client) Query(ipAddress net.IP) (result QueryResult) { + + result.Ip = ipAddress.String() + + c.Offset = 0 + + tp := big.NewInt(0) + op := big.NewInt(0) + tp.SetBytes(ipAddress.To16()) + op.SetString("18446744073709551616", 10) + op.Div(tp, op) + tp.SetString("FFFFFFFFFFFFFFFF", 16) + op.And(op, tp) + + v6ip = op.Uint64() + offset = c.searchIndex(v6ip) + c.Offset = offset + + country, area = c.getAddr() + + // 解析地区数据 + info := strings.Split(string(country), "\t") + if len(info) > 0 { + i := 1 + for { + if i > len(info) { + break + } + switch i { + case 1: + result.Country = info[i-1] + result.Country = gostring.SpaceAndLineBreak(result.Country) + case 2: + result.Province = info[i-1] + result.Province = gostring.SpaceAndLineBreak(result.Province) + case 3: + result.City = info[i-1] + result.City = gostring.SpaceAndLineBreak(result.City) + case 4: + result.Area = info[i-1] + result.Area = gostring.SpaceAndLineBreak(result.Area) + } + i++ // 自增 + } + } else { + result.Country = string(country) + result.Country = gostring.SpaceAndLineBreak(result.Country) + } + // 运营商 + result.Isp = string(area) + + // Delete ZX (防止不相关的信息产生干扰) + if result.Isp == "ZX" || result.Isp == "" { + result.Isp = "" + } else { + result.Isp = " " + result.Isp + } + + result.Isp = gostring.SpaceAndLineBreak(result.Isp) + + return result +} diff --git a/vendor/go.dtapp.net/goip/is.go b/vendor/go.dtapp.net/goip/is.go new file mode 100644 index 0000000..da49c9c --- /dev/null +++ b/vendor/go.dtapp.net/goip/is.go @@ -0,0 +1,35 @@ +package goip + +import "strings" + +var ( + ipv4 = "IPV4" + ipv6 = "IPV6" +) + +func (c *Client) isIpv4OrIpv6(ip string) string { + if len(ip) < 7 { + return "" + } + arrIpv4 := strings.Split(ip, ".") + if len(arrIpv4) == 4 { + //. 判断IPv4 + for _, val := range arrIpv4 { + if !c.CheckIpv4(val) { + return "" + } + } + return ipv4 + } + arrIpv6 := strings.Split(ip, ":") + if len(arrIpv6) == 8 { + // 判断Ipv6 + for _, val := range arrIpv6 { + if !c.CheckIpv6(val) { + return "Neither" + } + } + return ipv6 + } + return "" +} diff --git a/vendor/go.dtapp.net/goip/qqwry/client.go b/vendor/go.dtapp.net/goip/qqwry/client.go new file mode 100644 index 0000000..3b51445 --- /dev/null +++ b/vendor/go.dtapp.net/goip/qqwry/client.go @@ -0,0 +1,139 @@ +package qqwry + +import ( + _ "embed" + "encoding/binary" + "log" +) + +var ( + header []byte + country []byte + area []byte + offset uint32 + start uint32 + end uint32 +) + +//go:embed qqwry.dat +var datBuff []byte + +type Client struct { + Offset uint32 + ItemLen uint32 + IndexLen uint32 +} + +func New() *Client { + + c := &Client{} + + buf := datBuff[0:8] + start := binary.LittleEndian.Uint32(buf[:4]) + end := binary.LittleEndian.Uint32(buf[4:]) + + num := int64((end-start)/7 + 1) + log.Printf("qqwry.dat 共加载:%d 条ip记录\n", num) + + return c +} + +// ReadData 从文件中读取数据 +func (c *Client) readData(length uint32) (rs []byte) { + end := c.Offset + length + dataNum := uint32(len(datBuff)) + if c.Offset > dataNum { + return nil + } + + if end > dataNum { + end = dataNum + } + rs = datBuff[c.Offset:end] + c.Offset = end + return rs +} + +// 获取地址信息 +func (c *Client) getAddr() ([]byte, []byte) { + mode := c.readData(1)[0] + if mode == 0x01 { + // [IP][0x01][国家和地区信息的绝对偏移地址] + c.Offset = byteToUInt32(c.readData(3)) + return c.getAddr() + } + // [IP][0x02][信息的绝对偏移][...] or [IP][国家][...] + _offset := c.Offset - 1 + c1 := c.readArea(_offset) + if mode == 0x02 { + c.Offset = 4 + _offset + } else { + c.Offset = _offset + uint32(1+len(c1)) + } + c2 := c.readArea(c.Offset) + return c1, c2 +} + +// 读取区 +func (c *Client) readArea(offset uint32) []byte { + c.Offset = offset + mode := c.readData(1)[0] + if mode == 0x01 || mode == 0x02 { + return c.readArea(byteToUInt32(c.readData(3))) + } + c.Offset = offset + return c.readString() +} + +// 读取字符串 +func (c *Client) readString() []byte { + data := make([]byte, 0) + for { + buf := c.readData(1) + if buf[0] == 0 { + break + } + data = append(data, buf[0]) + } + return data +} + +// 搜索索引 +func (c *Client) searchIndex(ip uint32) uint32 { + c.ItemLen = 4 + c.IndexLen = 7 + header = datBuff[0:8] + start = binary.LittleEndian.Uint32(header[:4]) + end = binary.LittleEndian.Uint32(header[4:]) + + buf := make([]byte, c.IndexLen) + + for { + mid := start + c.IndexLen*(((end-start)/c.IndexLen)>>1) + buf = datBuff[mid : mid+c.IndexLen] + _ip := binary.LittleEndian.Uint32(buf[:c.ItemLen]) + + if end-start == c.IndexLen { + if ip >= binary.LittleEndian.Uint32(datBuff[end:end+c.ItemLen]) { + buf = datBuff[end : end+c.IndexLen] + } + return byteToUInt32(buf[c.ItemLen:]) + } + + if _ip > ip { + end = mid + } else if _ip < ip { + start = mid + } else if _ip == ip { + return byteToUInt32(buf[c.ItemLen:]) + } + } +} + +// 字节转UInt32 +func byteToUInt32(data []byte) uint32 { + i := uint32(data[0]) & 0xff + i |= (uint32(data[1]) << 8) & 0xff00 + i |= (uint32(data[2]) << 16) & 0xff0000 + return i +} diff --git a/vendor/go.dtapp.net/goip/v4/download.go b/vendor/go.dtapp.net/goip/qqwry/download.go similarity index 51% rename from vendor/go.dtapp.net/goip/v4/download.go rename to vendor/go.dtapp.net/goip/qqwry/download.go index f6e3d7b..6126330 100644 --- a/vendor/go.dtapp.net/goip/v4/download.go +++ b/vendor/go.dtapp.net/goip/qqwry/download.go @@ -1,10 +1,11 @@ -package v4 +package qqwry import ( "bytes" "compress/zlib" "encoding/binary" "io/ioutil" + "log" "net/http" ) @@ -25,34 +26,45 @@ func getKey() (uint32, error) { } } -// 在线获取内容 -func getOnline() ([]byte, error) { +func OnlineDownload() { resp, err := http.Get("https://update.cz88.net/ip/qqwry.rar") if err != nil { - return nil, err + panic(err) } defer resp.Body.Close() - if body, err := ioutil.ReadAll(resp.Body); err != nil { - return nil, err - } else { - if key, err := getKey(); err != nil { - return nil, err - } else { - for i := 0; i < 0x200; i++ { - key = key * 0x805 - key++ - key = key & 0xff + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + key, err := getKey() + if err != nil { + panic(err) + } + + for i := 0; i < 0x200; i++ { + key = key * 0x805 + key++ + key = key & 0xff - body[i] = byte(uint32(body[i]) ^ key) - } + body[i] = byte(uint32(body[i]) ^ key) + } + + reader, err := zlib.NewReader(bytes.NewReader(body)) + if err != nil { + panic(err) + } - reader, err := zlib.NewReader(bytes.NewReader(body)) - if err != nil { - return nil, err - } + tmpData, err := ioutil.ReadAll(reader) + if err != nil { + panic(err) + } - return ioutil.ReadAll(reader) - } + err = ioutil.WriteFile("./qqwry.dat", tmpData, 0644) + if err != nil { + panic(err) } + + log.Printf("已下载最新 纯真 IPv4数据库 %s ", "./qqwry.dat") } diff --git a/vendor/go.dtapp.net/goip/v4/ip.dat b/vendor/go.dtapp.net/goip/qqwry/qqwry.dat similarity index 100% rename from vendor/go.dtapp.net/goip/v4/ip.dat rename to vendor/go.dtapp.net/goip/qqwry/qqwry.dat diff --git a/vendor/go.dtapp.net/goip/qqwry/query.go b/vendor/go.dtapp.net/goip/qqwry/query.go new file mode 100644 index 0000000..2e1d7bb --- /dev/null +++ b/vendor/go.dtapp.net/goip/qqwry/query.go @@ -0,0 +1,53 @@ +package qqwry + +import ( + "encoding/binary" + "errors" + "go.dtapp.net/gostring" + "golang.org/x/text/encoding/simplifiedchinese" + "net" +) + +// QueryResult 返回 +type QueryResult struct { + Ip string `json:"ip,omitempty"` // ip + Country string `json:"country,omitempty"` // 国家或地区 + Area string `json:"area,omitempty"` // 区域 +} + +// Query ip地址查询对应归属地信息 +func (c *Client) Query(ipAddress net.IP) (result QueryResult, err error) { + + c.Offset = 0 + + // 偏移 + offset = c.searchIndex(binary.BigEndian.Uint32(ipAddress.To4())) + if offset <= 0 { + return QueryResult{}, errors.New("搜索失败") + } + + result.Ip = ipAddress.String() + + c.Offset = offset + c.ItemLen + + country, area = c.getAddr() + + enc := simplifiedchinese.GBK.NewDecoder() + + result.Country, _ = enc.String(string(country)) + + result.Country = gostring.SpaceAndLineBreak(result.Country) + + result.Area, _ = enc.String(string(area)) + + // Delete CZ88.NET (防止不相关的信息产生干扰) + if result.Area == " CZ88.NET" || result.Area == "" { + result.Area = "" + } else { + result.Area = " " + result.Area + } + + result.Area = gostring.SpaceAndLineBreak(result.Area) + + return result, nil +} diff --git a/vendor/go.dtapp.net/goip/query.go b/vendor/go.dtapp.net/goip/query.go new file mode 100644 index 0000000..d6f6763 --- /dev/null +++ b/vendor/go.dtapp.net/goip/query.go @@ -0,0 +1,87 @@ +package goip + +import ( + "errors" + "go.dtapp.net/goip/geoip" + "go.dtapp.net/goip/ip2region" + "go.dtapp.net/goip/ip2region_v2" + "go.dtapp.net/goip/ipv6wry" + "go.dtapp.net/goip/qqwry" + "net" +) + +var ( + QueryIncorrect = errors.New("ip地址不正确") +) + +// QueryQqWry 纯真IP库 +// https://www.cz88.net/ +func (c *Client) QueryQqWry(ipAddress net.IP) (result qqwry.QueryResult, err error) { + if ipAddress.To4() == nil { + return result, QueryIncorrect + } + + query, err := c.qqwryClient.Query(ipAddress) + if err != nil { + return qqwry.QueryResult{}, err + } + + return query, err +} + +// QueryIp2Region ip2region +// https://github.com/lionsoul2014/ip2region +func (c *Client) QueryIp2Region(ipAddress net.IP) (result ip2region.QueryResult, err error) { + if ipAddress.To4() == nil { + return result, QueryIncorrect + } + + query, err := c.ip2regionClient.Query(ipAddress) + if err != nil { + return ip2region.QueryResult{}, err + } + + return query, err +} + +// QueryIp2RegionV2 ip2region +// https://github.com/lionsoul2014/ip2region +func (c *Client) QueryIp2RegionV2(ipAddress net.IP) (result ip2region_v2.QueryResult, err error) { + if ipAddress.To4() == nil { + return result, QueryIncorrect + } + + query, err := c.ip2regionV2Client.Query(ipAddress) + if err != nil { + return ip2region_v2.QueryResult{}, err + } + + return query, nil +} + +// QueryGeoIp ip2region +// https://www.maxmind.com/ +func (c *Client) QueryGeoIp(ipAddress net.IP) (result geoip.QueryCityResult, err error) { + if ipAddress.String() == "" { + return result, QueryIncorrect + } + + query, err := c.geoIpClient.QueryCity(ipAddress) + if err != nil { + return geoip.QueryCityResult{}, err + } + + return query, nil +} + +// QueryIpv6wry ip2region +// https://ip.zxinc.org +func (c *Client) QueryIpv6wry(ipAddress net.IP) (result ipv6wry.QueryResult, err error) { + if ipAddress.To16() == nil { + return result, QueryIncorrect + } + + query := c.ipv6wryClient.Query(ipAddress) + + return query, nil +} diff --git a/vendor/go.dtapp.net/goip/v4/ipv4.go b/vendor/go.dtapp.net/goip/v4/ipv4.go deleted file mode 100644 index 1ca739e..0000000 --- a/vendor/go.dtapp.net/goip/v4/ipv4.go +++ /dev/null @@ -1,201 +0,0 @@ -package v4 - -import ( - _ "embed" - "encoding/binary" - "errors" - "go.dtapp.net/gostring" - "golang.org/x/text/encoding/simplifiedchinese" - "io/ioutil" - "log" - "net" -) - -var ( - header []byte - country []byte - area []byte - offset uint32 - start uint32 - end uint32 -) - -//go:embed ip.dat -var dat []byte - -type Pointer struct { - Offset uint32 - ItemLen uint32 - IndexLen uint32 -} - -// Result 返回 -type Result struct { - IP string `json:"ip,omitempty"` // 输入的ip地址 - Country string `json:"country,omitempty"` // 国家或地区 - Area string `json:"area,omitempty"` // 区域 -} - -// InitIPV4Data 加载 -func (q *Pointer) InitIPV4Data() int64 { - buf := dat[0:8] - start := binary.LittleEndian.Uint32(buf[:4]) - end := binary.LittleEndian.Uint32(buf[4:]) - - return int64((end-start)/7 + 1) -} - -// ReadData 从文件中读取数据 -func (q *Pointer) readData(length uint32) (rs []byte) { - end := q.Offset + length - dataNum := uint32(len(dat)) - if q.Offset > dataNum { - return nil - } - - if end > dataNum { - end = dataNum - } - rs = dat[q.Offset:end] - q.Offset = end - return rs -} - -// Find ip地址查询对应归属地信息 -func (q *Pointer) Find(ipStr string) (res Result) { - - // 赋值 - res.IP = ipStr - if net.ParseIP(ipStr).To4() == nil { - // 不是ip地址 - return res - } - - q.Offset = 0 - - // 偏移 - offset = q.searchIndex(binary.BigEndian.Uint32(net.ParseIP(ipStr).To4())) - if offset <= 0 { - return - } - - q.Offset = offset + q.ItemLen - - country, area = q.getAddr() - - enc := simplifiedchinese.GBK.NewDecoder() - - res.Country, _ = enc.String(string(country)) - res.Country = gostring.SpaceAndLineBreak(res.Country) - - res.Area, _ = enc.String(string(area)) - - // Delete CZ88.NET (防止不相关的信息产生干扰) - if res.Area == " CZ88.NET" || res.Area == "" { - res.Area = "" - } else { - res.Area = " " + res.Area - } - - res.Area = gostring.SpaceAndLineBreak(res.Area) - - return -} - -// 获取地址信息 -func (q *Pointer) getAddr() ([]byte, []byte) { - mode := q.readData(1)[0] - if mode == 0x01 { - // [IP][0x01][国家和地区信息的绝对偏移地址] - q.Offset = byteToUInt32(q.readData(3)) - return q.getAddr() - } - // [IP][0x02][信息的绝对偏移][...] or [IP][国家][...] - _offset := q.Offset - 1 - c1 := q.readArea(_offset) - if mode == 0x02 { - q.Offset = 4 + _offset - } else { - q.Offset = _offset + uint32(1+len(c1)) - } - c2 := q.readArea(q.Offset) - return c1, c2 -} - -// 读取区 -func (q *Pointer) readArea(offset uint32) []byte { - q.Offset = offset - mode := q.readData(1)[0] - if mode == 0x01 || mode == 0x02 { - return q.readArea(byteToUInt32(q.readData(3))) - } - q.Offset = offset - return q.readString() -} - -// 读取字符串 -func (q *Pointer) readString() []byte { - data := make([]byte, 0) - for { - buf := q.readData(1) - if buf[0] == 0 { - break - } - data = append(data, buf[0]) - } - return data -} - -// 搜索索引 -func (q *Pointer) searchIndex(ip uint32) uint32 { - q.ItemLen = 4 - q.IndexLen = 7 - header = dat[0:8] - start = binary.LittleEndian.Uint32(header[:4]) - end = binary.LittleEndian.Uint32(header[4:]) - - buf := make([]byte, q.IndexLen) - - for { - mid := start + q.IndexLen*(((end-start)/q.IndexLen)>>1) - buf = dat[mid : mid+q.IndexLen] - _ip := binary.LittleEndian.Uint32(buf[:q.ItemLen]) - - if end-start == q.IndexLen { - if ip >= binary.LittleEndian.Uint32(dat[end:end+q.ItemLen]) { - buf = dat[end : end+q.IndexLen] - } - return byteToUInt32(buf[q.ItemLen:]) - } - - if _ip > ip { - end = mid - } else if _ip < ip { - start = mid - } else if _ip == ip { - return byteToUInt32(buf[q.ItemLen:]) - } - } -} - -// 字节转UInt32 -func byteToUInt32(data []byte) uint32 { - i := uint32(data[0]) & 0xff - i |= (uint32(data[1]) << 8) & 0xff00 - i |= (uint32(data[2]) << 16) & 0xff0000 - return i -} - -// OnlineDownload 在线下载 -func (q *Pointer) OnlineDownload() (err error) { - tmpData, err := getOnline() - if err != nil { - return errors.New("下载失败") - } - if err := ioutil.WriteFile("./qqwry.dat", tmpData, 0644); err == nil { - log.Printf("已下载最新 纯真 IPv4数据库 %s ", "./qqwry.dat") - } else { - return errors.New("保存失败") - } - return nil -} diff --git a/vendor/go.dtapp.net/goip/v6/ipv6.go b/vendor/go.dtapp.net/goip/v6/ipv6.go deleted file mode 100644 index 024d1ff..0000000 --- a/vendor/go.dtapp.net/goip/v6/ipv6.go +++ /dev/null @@ -1,230 +0,0 @@ -package v6 - -import ( - _ "embed" - "encoding/binary" - "errors" - "go.dtapp.net/gostring" - "io/ioutil" - "log" - "math/big" - "net" - "strings" -) - -var ( - header []byte - country []byte - area []byte - v6ip uint64 - offset uint32 - start uint32 - end uint32 -) - -type Result struct { - IP string `json:"ip,omitempty"` // 输入的ip地址 - Country string `json:"country,omitempty"` // 国家 - Province string `json:"province,omitempty"` // 省份 - City string `json:"city,omitempty"` // 城市 - Area string `json:"area,omitempty"` // 区域 - Isp string `json:"isp,omitempty"` // 运营商 -} - -//go:embed ip.db -var dat []byte - -type Pointer struct { - Offset uint32 - ItemLen uint32 - IndexLen uint32 -} - -// InitIPV4Data 加载 -func (q *Pointer) InitIPV4Data() int64 { - buf := dat[0:8] - start := binary.LittleEndian.Uint32(buf[:4]) - end := binary.LittleEndian.Uint32(buf[4:]) - - return int64((end-start)/7 + 1) -} - -// ReadData 从文件中读取数据 -func (q *Pointer) readData(length uint32) (rs []byte) { - end := q.Offset + length - dataNum := uint32(len(dat)) - if q.Offset > dataNum { - return nil - } - - if end > dataNum { - end = dataNum - } - rs = dat[q.Offset:end] - q.Offset = end - return rs -} - -// Find ip地址查询对应归属地信息 -func (q *Pointer) Find(ipStr string) (res Result) { - - res = Result{} - res.IP = ipStr - if net.ParseIP(ipStr).To16() == nil { - return Result{} - } - - q.Offset = 0 - - tp := big.NewInt(0) - op := big.NewInt(0) - tp.SetBytes(net.ParseIP(ipStr).To16()) - op.SetString("18446744073709551616", 10) - op.Div(tp, op) - tp.SetString("FFFFFFFFFFFFFFFF", 16) - op.And(op, tp) - - v6ip = op.Uint64() - offset = q.searchIndex(v6ip) - q.Offset = offset - - country, area = q.getAddr() - - // 解析地区数据 - info := strings.Split(string(country), "\t") - if len(info) > 0 { - i := 1 - for { - if i > len(info) { - break - } - switch i { - case 1: - res.Country = info[i-1] - res.Country = gostring.SpaceAndLineBreak(res.Country) - case 2: - res.Province = info[i-1] - res.Province = gostring.SpaceAndLineBreak(res.Province) - case 3: - res.City = info[i-1] - res.City = gostring.SpaceAndLineBreak(res.City) - case 4: - res.Area = info[i-1] - res.Area = gostring.SpaceAndLineBreak(res.Area) - } - i++ // 自增 - } - } else { - res.Country = string(country) - res.Country = gostring.SpaceAndLineBreak(res.Country) - } - // 运营商 - res.Isp = string(area) - - // Delete ZX (防止不相关的信息产生干扰) - if res.Isp == "ZX" || res.Isp == "" { - res.Isp = "" - } else { - res.Isp = " " + res.Isp - } - - res.Isp = gostring.SpaceAndLineBreak(res.Isp) - - return -} - -func (q *Pointer) getAddr() ([]byte, []byte) { - mode := q.readData(1)[0] - if mode == 0x01 { - // [IP][0x01][国家和地区信息的绝对偏移地址] - q.Offset = byteToUInt32(q.readData(3)) - return q.getAddr() - } - // [IP][0x02][信息的绝对偏移][...] or [IP][国家][...] - _offset := q.Offset - 1 - c1 := q.readArea(_offset) - if mode == 0x02 { - q.Offset = 4 + _offset - } else { - q.Offset = _offset + uint32(1+len(c1)) - } - c2 := q.readArea(q.Offset) - return c1, c2 -} - -func (q *Pointer) readArea(offset uint32) []byte { - q.Offset = offset - mode := q.readData(1)[0] - if mode == 0x01 || mode == 0x02 { - return q.readArea(byteToUInt32(q.readData(3))) - } - q.Offset = offset - return q.readString() -} - -func (q *Pointer) readString() []byte { - data := make([]byte, 0) - for { - buf := q.readData(1) - if buf[0] == 0 { - break - } - data = append(data, buf[0]) - } - return data -} - -func (q *Pointer) searchIndex(ip uint64) uint32 { - - q.ItemLen = 8 - q.IndexLen = 11 - - header = dat[8:24] - start = binary.LittleEndian.Uint32(header[8:]) - counts := binary.LittleEndian.Uint32(header[:8]) - end = start + counts*q.IndexLen - - buf := make([]byte, q.IndexLen) - - for { - mid := start + q.IndexLen*(((end-start)/q.IndexLen)>>1) - buf = dat[mid : mid+q.IndexLen] - _ip := binary.LittleEndian.Uint64(buf[:q.ItemLen]) - - if end-start == q.IndexLen { - if ip >= binary.LittleEndian.Uint64(dat[end:end+q.ItemLen]) { - buf = dat[end : end+q.IndexLen] - } - return byteToUInt32(buf[q.ItemLen:]) - } - - if _ip > ip { - end = mid - } else if _ip < ip { - start = mid - } else if _ip == ip { - return byteToUInt32(buf[q.ItemLen:]) - } - } -} - -func byteToUInt32(data []byte) uint32 { - i := uint32(data[0]) & 0xff - i |= (uint32(data[1]) << 8) & 0xff00 - i |= (uint32(data[2]) << 16) & 0xff0000 - return i -} - -// OnlineDownload 在线下载 -func (q *Pointer) OnlineDownload() (err error) { - tmpData, err := getOnline() - if err != nil { - return errors.New("下载失败") - } - if err := ioutil.WriteFile("./ipv6wry.db", tmpData, 0644); err == nil { - log.Printf("已下载最新 ZX IPv6数据库 %s ", "./ipv6wry.db") - } else { - return errors.New("保存失败") - } - return nil -} diff --git a/vendor/go.dtapp.net/golog/.gitignore b/vendor/go.dtapp.net/golog/.gitignore index c1823b5..5c75b7d 100644 --- a/vendor/go.dtapp.net/golog/.gitignore +++ b/vendor/go.dtapp.net/golog/.gitignore @@ -6,3 +6,4 @@ *.log gomod.sh *_test.go +/vendor/ diff --git a/vendor/go.dtapp.net/golog/api.go b/vendor/go.dtapp.net/golog/api.go index d24e022..3e8458e 100644 --- a/vendor/go.dtapp.net/golog/api.go +++ b/vendor/go.dtapp.net/golog/api.go @@ -6,62 +6,47 @@ import ( "go.dtapp.net/dorm" "go.dtapp.net/goip" "go.dtapp.net/gorequest" - "os" - "runtime" ) +// ApiClientFun *ApiClient 驱动 +type ApiClientFun func() *ApiClient + // ApiClient 接口 type ApiClient struct { gormClient *dorm.GormClient // 数据库驱动 mongoClient *dorm.MongoClient // 数据库驱动 zapLog *ZapLog // 日志服务 logDebug bool // 日志开关 - currentIp string // 当前ip - gormConfig struct { + config struct { + systemHostName string // 主机名 + systemInsideIp string // 内网ip + systemOs string // 系统类型 + systemArch string // 系统架构 + goVersion string // go版本 + sdkVersion string // sdk版本 + systemOutsideIp string // 外网ip + } + gormConfig struct { + stats bool // 状态 tableName string // 表名 - insideIp string // 内网ip - hostname string // 主机名 - goVersion string // go版本 } mongoConfig struct { + stats bool // 状态 databaseName string // 库名 collectionName string // 表名 - insideIp string // 内网ip - hostname string // 主机名 - goVersion string // go版本 - } - log struct { - gorm bool // 日志开关 - mongo bool // 日志开关 - } - config struct { - os string // 系统类型 - arch string // 系统架构 - maxProCs int // CPU核数 } } -// client 数据库服务 -// string 表名 -type apiGormClientFun func() (*dorm.GormClient, string) - -// client 数据库服务 -// string 库名 -// string 表名 -type apiMongoClientFun func() (*dorm.MongoClient, string, string) - // ApiClientConfig 接口实例配置 type ApiClientConfig struct { - GormClientFun apiGormClientFun // 日志配置 - MongoClientFun apiMongoClientFun // 日志配置 - Debug bool // 日志开关 - ZapLog *ZapLog // 日志服务 - CurrentIp string // 当前ip + GormClientFun dorm.GormClientTableFun // 日志配置 + MongoClientFun dorm.MongoClientCollectionFun // 日志配置 + Debug bool // 日志开关 + ZapLog *ZapLog // 日志服务 + CurrentIp string // 当前ip } // NewApiClient 创建接口实例化 -// client 数据库服务 -// tableName 表名 func NewApiClient(config *ApiClientConfig) (*ApiClient, error) { var ctx = context.Background() @@ -76,63 +61,56 @@ func NewApiClient(config *ApiClientConfig) (*ApiClient, error) { config.CurrentIp = goip.GetOutsideIp(ctx) } if config.CurrentIp != "" && config.CurrentIp != "0.0.0.0" { - c.currentIp = config.CurrentIp + c.config.systemOutsideIp = config.CurrentIp + } + + if c.config.systemOutsideIp == "" { + return nil, currentIpNoConfig } - c.config.os = runtime.GOOS - c.config.arch = runtime.GOARCH - c.config.maxProCs = runtime.GOMAXPROCS(0) + // 配置信息 + c.setConfig(ctx) gormClient, gormTableName := config.GormClientFun() mongoClient, mongoDatabaseName, mongoCollectionName := config.MongoClientFun() if (gormClient == nil || gormClient.Db == nil) || (mongoClient == nil || mongoClient.Db == nil) { - return nil, errors.New("没有设置驱动") + return nil, dbClientFunNoConfig } - hostname, _ := os.Hostname() - + // 配置关系数据库 if gormClient != nil || gormClient.Db != nil { c.gormClient = gormClient if gormTableName == "" { return nil, errors.New("没有设置表名") - } - c.gormConfig.tableName = gormTableName - - err := c.gormAutoMigrate() - if err != nil { - return nil, errors.New("创建表失败:" + err.Error()) + } else { + c.gormConfig.tableName = gormTableName } - c.gormConfig.hostname = hostname - c.gormConfig.insideIp = goip.GetInsideIp(ctx) - c.gormConfig.goVersion = runtime.Version() - - c.log.gorm = true + // 创建模型 + c.gormAutoMigrate(ctx) + c.gormConfig.stats = true } + // 配置非关系数据库 if mongoClient != nil || mongoClient.Db != nil { c.mongoClient = mongoClient if mongoDatabaseName == "" { return nil, errors.New("没有设置库名") + } else { + c.mongoConfig.databaseName = mongoDatabaseName } - c.mongoConfig.databaseName = mongoDatabaseName if mongoCollectionName == "" { return nil, errors.New("没有设置表名") + } else { + c.mongoConfig.collectionName = mongoCollectionName } - c.mongoConfig.collectionName = mongoCollectionName - - c.mongoConfig.hostname = hostname - c.mongoConfig.insideIp = goip.GetInsideIp(ctx) - c.mongoConfig.goVersion = runtime.Version() - - c.log.mongo = true // 创建时间序列集合 c.mongoCreateCollection(ctx) @@ -140,6 +118,7 @@ func NewApiClient(config *ApiClientConfig) (*ApiClient, error) { // 创建索引 c.mongoCreateIndexes(ctx) + c.mongoConfig.stats = true } return c, nil @@ -147,30 +126,30 @@ func NewApiClient(config *ApiClientConfig) (*ApiClient, error) { // Middleware 中间件 func (c *ApiClient) Middleware(ctx context.Context, request gorequest.Response, sdkVersion string) { - if c.log.gorm { - c.GormMiddleware(ctx, request, sdkVersion) + if c.gormConfig.stats { + c.gormMiddleware(ctx, request, sdkVersion) } - if c.log.mongo { - c.MongoMiddleware(ctx, request, sdkVersion) + if c.mongoConfig.stats { + c.mongoMiddleware(ctx, request, sdkVersion) } } // MiddlewareXml 中间件 func (c *ApiClient) MiddlewareXml(ctx context.Context, request gorequest.Response, sdkVersion string) { - if c.log.gorm { - c.GormMiddlewareXml(ctx, request, sdkVersion) + if c.gormConfig.stats { + c.gormMiddlewareXml(ctx, request, sdkVersion) } - if c.log.mongo { - c.MongoMiddlewareXml(ctx, request, sdkVersion) + if c.mongoConfig.stats { + c.mongoMiddlewareXml(ctx, request, sdkVersion) } } // MiddlewareCustom 中间件 func (c *ApiClient) MiddlewareCustom(ctx context.Context, api string, request gorequest.Response, sdkVersion string) { - if c.log.gorm { - c.GormMiddlewareCustom(ctx, api, request, sdkVersion) + if c.gormConfig.stats { + c.gormMiddlewareCustom(ctx, api, request, sdkVersion) } - if c.log.mongo { - c.MongoMiddlewareCustom(ctx, api, request, sdkVersion) + if c.mongoConfig.stats { + c.mongoMiddlewareCustom(ctx, api, request, sdkVersion) } } diff --git a/vendor/go.dtapp.net/golog/api_cofing.go b/vendor/go.dtapp.net/golog/api_cofing.go new file mode 100644 index 0000000..8dc6c17 --- /dev/null +++ b/vendor/go.dtapp.net/golog/api_cofing.go @@ -0,0 +1,18 @@ +package golog + +import ( + "context" + "go.dtapp.net/goip" + "os" + "runtime" +) + +func (c *ApiClient) setConfig(ctx context.Context) { + c.config.sdkVersion = Version + c.config.systemOs = runtime.GOOS + c.config.systemArch = runtime.GOARCH + c.config.goVersion = runtime.Version() + c.config.systemInsideIp = goip.GetInsideIp(ctx) + hostname, _ := os.Hostname() + c.config.systemHostName = hostname +} diff --git a/vendor/go.dtapp.net/golog/api_gorm.go b/vendor/go.dtapp.net/golog/api_gorm.go index 344c177..24ac455 100644 --- a/vendor/go.dtapp.net/golog/api_gorm.go +++ b/vendor/go.dtapp.net/golog/api_gorm.go @@ -2,151 +2,77 @@ package golog import ( "context" - "errors" "go.dtapp.net/dorm" - "go.dtapp.net/goip" "go.dtapp.net/gorequest" "go.dtapp.net/gotime" "go.dtapp.net/gotrace_id" "go.dtapp.net/gourl" - "gorm.io/gorm" - "os" - "runtime" "time" "unicode/utf8" ) -// ApiGormClientConfig 接口实例配置 -type ApiGormClientConfig struct { - GormClientFun apiGormClientFun // 日志配置 - Debug bool // 日志开关 - ZapLog *ZapLog // 日志服务 - CurrentIp string // 当前ip -} - -// NewApiGormClient 创建接口实例化 -// client 数据库服务 -// tableName 表名 -func NewApiGormClient(config *ApiGormClientConfig) (*ApiClient, error) { - - var ctx = context.Background() - - c := &ApiClient{} - - c.zapLog = config.ZapLog - - c.logDebug = config.Debug - - if config.CurrentIp == "" { - config.CurrentIp = goip.GetOutsideIp(ctx) - } - if config.CurrentIp != "" && config.CurrentIp != "0.0.0.0" { - c.currentIp = config.CurrentIp - } - - client, tableName := config.GormClientFun() - - if client == nil || client.Db == nil { - return nil, errors.New("没有设置驱动") - } - - c.gormClient = client - - if tableName == "" { - return nil, errors.New("没有设置表名") - } - c.gormConfig.tableName = tableName - - err := c.gormAutoMigrate() - if err != nil { - return nil, errors.New("创建表失败:" + err.Error()) - } - - hostname, _ := os.Hostname() - - c.gormConfig.hostname = hostname - c.gormConfig.insideIp = goip.GetInsideIp(ctx) - c.gormConfig.goVersion = runtime.Version() - - c.log.gorm = true - - return c, nil +// 模型 +type apiPostgresqlLog struct { + LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号 + TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号 + RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间 + RequestUri string `gorm:"comment:【请求】链接" json:"request_uri,omitempty"` //【请求】链接 + RequestUrl string `gorm:"comment:【请求】链接" json:"request_url,omitempty"` //【请求】链接 + RequestApi string `gorm:"index;comment:【请求】接口" json:"request_api,omitempty"` //【请求】接口 + RequestMethod string `gorm:"index;comment:【请求】方式" json:"request_method,omitempty"` //【请求】方式 + RequestParams string `gorm:"comment:【请求】参数" json:"request_params,omitempty"` //【请求】参数 + RequestHeader string `gorm:"comment:【请求】头部" json:"request_header,omitempty"` //【请求】头部 + RequestIp string `gorm:"default:0.0.0.0;index;comment:【请求】请求Ip" json:"request_ip,omitempty"` //【请求】请求Ip + ResponseHeader string `gorm:"comment:【返回】头部" json:"response_header,omitempty"` //【返回】头部 + ResponseStatusCode int `gorm:"index;comment:【返回】状态码" json:"response_status_code,omitempty"` //【返回】状态码 + ResponseBody string `gorm:"comment:【返回】数据" json:"response_content,omitempty"` //【返回】数据 + ResponseContentLength int64 `gorm:"comment:【返回】大小" json:"response_content_length,omitempty"` //【返回】大小 + ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间 + SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名 + SystemInsideIp string `gorm:"default:0.0.0.0;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip + SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型 + SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构 + GoVersion string `gorm:"comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本 + SdkVersion string `gorm:"comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本 } // 创建模型 -func (c *ApiClient) gormAutoMigrate() (err error) { - err = c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&apiPostgresqlLog{}) +func (c *ApiClient) gormAutoMigrate(ctx context.Context) { + err := c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&apiPostgresqlLog{}) if err != nil { - c.zapLog.WithLogger().Sugar().Infof("[golog.api.gormAutoMigrate]:%s", err) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("创建模型:%s", err) } - return -} - -// 模型结构体 -type apiPostgresqlLog struct { - LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号 - TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号 - RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间 - RequestUri string `gorm:"comment:【请求】链接" json:"request_uri,omitempty"` //【请求】链接 - RequestUrl string `gorm:"comment:【请求】链接" json:"request_url,omitempty"` //【请求】链接 - RequestApi string `gorm:"index;comment:【请求】接口" json:"request_api,omitempty"` //【请求】接口 - RequestMethod string `gorm:"index;comment:【请求】方式" json:"request_method,omitempty"` //【请求】方式 - RequestParams string `gorm:"comment:【请求】参数" json:"request_params,omitempty"` //【请求】参数 - RequestHeader string `gorm:"comment:【请求】头部" json:"request_header,omitempty"` //【请求】头部 - RequestIp string `gorm:"index;comment:【请求】请求Ip" json:"request_ip,omitempty"` //【请求】请求Ip - ResponseHeader string `gorm:"comment:【返回】头部" json:"response_header,omitempty"` //【返回】头部 - ResponseStatusCode int `gorm:"index;comment:【返回】状态码" json:"response_status_code,omitempty"` //【返回】状态码 - ResponseBody string `gorm:"comment:【返回】数据" json:"response_content,omitempty"` //【返回】数据 - ResponseContentLength int64 `gorm:"comment:【返回】大小" json:"response_content_length,omitempty"` //【返回】大小 - ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间 - SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名 - SystemInsideIp string `gorm:"index;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip - SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型 - SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构 - SystemCpuQuantity int `gorm:"index;comment:【系统】CPU核数" json:"system_cpu_quantity,omitempty"` //【系统】CPU核数 - GoVersion string `gorm:"index;comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本 - SdkVersion string `gorm:"index;comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本 } // 记录日志 -func (c *ApiClient) gormRecord(ctx context.Context, postgresqlLog apiPostgresqlLog) (err error) { +func (c *ApiClient) gormRecord(ctx context.Context, data apiPostgresqlLog) (err error) { - if utf8.ValidString(postgresqlLog.ResponseBody) == false { - postgresqlLog.ResponseBody = "" + if utf8.ValidString(data.ResponseBody) == false { + data.ResponseBody = "" } - postgresqlLog.SystemHostName = c.gormConfig.hostname - postgresqlLog.SystemInsideIp = c.gormConfig.insideIp - postgresqlLog.GoVersion = c.gormConfig.goVersion - - postgresqlLog.TraceId = gotrace_id.GetTraceIdContext(ctx) - - postgresqlLog.RequestIp = c.currentIp + data.SystemHostName = c.config.systemHostName //【系统】主机名 + data.SystemInsideIp = c.config.systemInsideIp //【系统】内网ip + data.GoVersion = c.config.goVersion //【程序】Go版本 + data.TraceId = gotrace_id.GetTraceIdContext(ctx) //【记录】跟踪编号 + data.RequestIp = c.config.systemOutsideIp //【请求】请求Ip + data.SystemOs = c.config.systemOs //【系统】系统类型 + data.SystemArch = c.config.systemArch //【系统】系统架构 - postgresqlLog.SystemOs = c.config.os - postgresqlLog.SystemArch = c.config.arch - postgresqlLog.SystemCpuQuantity = c.config.maxProCs - - err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&postgresqlLog).Error + err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&data).Error if err != nil { - c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.gormRecord]:%s", err) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("记录日志失败:%s", err) } - return } -// GormQuery 查询 -func (c *ApiClient) GormQuery(ctx context.Context) *gorm.DB { - return c.gormClient.Db.Table(c.gormConfig.tableName) -} - // GormDelete 删除 func (c *ApiClient) GormDelete(ctx context.Context, hour int64) error { return c.gormClient.Db.Table(c.gormConfig.tableName).Where("request_time < ?", gotime.Current().BeforeHour(hour).Format()).Delete(&apiPostgresqlLog{}).Error } -// GormMiddleware 中间件 -func (c *ApiClient) GormMiddleware(ctx context.Context, request gorequest.Response, sdkVersion string) { +// 中间件 +func (c *ApiClient) gormMiddleware(ctx context.Context, request gorequest.Response, sdkVersion string) { data := apiPostgresqlLog{ RequestTime: request.RequestTime, //【请求】时间 RequestUri: request.RequestUri, //【请求】链接 @@ -162,29 +88,29 @@ func (c *ApiClient) GormMiddleware(ctx context.Context, request gorequest.Respon SdkVersion: sdkVersion, //【程序】Sdk版本 } if request.HeaderIsImg() { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddleware.isimg]:%s,%s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddleware.isimg]:%s,%s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) } else { if len(request.ResponseBody) > 0 { data.ResponseBody = dorm.JsonEncodeNoError(dorm.JsonDecodeNoError(request.ResponseBody)) //【返回】数据 } else { if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddleware.len]:%s,%s", data.RequestUri, request.ResponseBody) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddleware.len]:%s,%s", data.RequestUri, request.ResponseBody) } } } if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddleware.data]:%+v", data) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddleware.data]:%+v", data) } err := c.gormRecord(ctx, data) if err != nil { - c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.GormMiddleware]:%s", err.Error()) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.gormMiddleware]:%s", err.Error()) } } -// GormMiddlewareXml 中间件 -func (c *ApiClient) GormMiddlewareXml(ctx context.Context, request gorequest.Response, sdkVersion string) { +// 中间件 +func (c *ApiClient) gormMiddlewareXml(ctx context.Context, request gorequest.Response, sdkVersion string) { data := apiPostgresqlLog{ RequestTime: request.RequestTime, //【请求】时间 RequestUri: request.RequestUri, //【请求】链接 @@ -200,29 +126,29 @@ func (c *ApiClient) GormMiddlewareXml(ctx context.Context, request gorequest.Res SdkVersion: sdkVersion, //【程序】Sdk版本 } if request.HeaderIsImg() { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddlewareXml.isimg]:%s,%s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddlewareXml.isimg]:%s,%s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) } else { if len(request.ResponseBody) > 0 { data.ResponseBody = dorm.JsonEncodeNoError(request.ResponseBody) //【返回】内容 } else { if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddlewareXml.len]:%s,%s", data.RequestUri, request.ResponseBody) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddlewareXml.len]:%s,%s", data.RequestUri, request.ResponseBody) } } } if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddlewareXml.data]:%+v", data) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddlewareXml.data]:%+v", data) } err := c.gormRecord(ctx, data) if err != nil { - c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.GormMiddlewareXml]:%s", err.Error()) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.gormMiddlewareXml]:%s", err.Error()) } } -// GormMiddlewareCustom 中间件 -func (c *ApiClient) GormMiddlewareCustom(ctx context.Context, api string, request gorequest.Response, sdkVersion string) { +// 中间件 +func (c *ApiClient) gormMiddlewareCustom(ctx context.Context, api string, request gorequest.Response, sdkVersion string) { data := apiPostgresqlLog{ RequestTime: request.RequestTime, //【请求】时间 RequestUri: request.RequestUri, //【请求】链接 @@ -238,23 +164,23 @@ func (c *ApiClient) GormMiddlewareCustom(ctx context.Context, api string, reques SdkVersion: sdkVersion, //【程序】Sdk版本 } if request.HeaderIsImg() { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddlewareCustom.isimg]:%s,%s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddlewareCustom.isimg]:%s,%s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) } else { if len(request.ResponseBody) > 0 { data.ResponseBody = dorm.JsonEncodeNoError(dorm.JsonDecodeNoError(request.ResponseBody)) //【返回】数据 } else { if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddlewareCustom.len]:%s,%s", data.RequestUri, request.ResponseBody) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddlewareCustom.len]:%s,%s", data.RequestUri, request.ResponseBody) } } } if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.GormMiddlewareCustom.data]:%+v", data) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.gormMiddlewareCustom.data]:%+v", data) } err := c.gormRecord(ctx, data) if err != nil { - c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.GormMiddlewareCustom]:%s", err.Error()) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.gormMiddlewareCustom]:%s", err.Error()) } } diff --git a/vendor/go.dtapp.net/golog/api_mongo.go b/vendor/go.dtapp.net/golog/api_mongo.go index 27684cf..5bcfb8e 100644 --- a/vendor/go.dtapp.net/golog/api_mongo.go +++ b/vendor/go.dtapp.net/golog/api_mongo.go @@ -2,9 +2,7 @@ package golog import ( "context" - "errors" "go.dtapp.net/dorm" - "go.dtapp.net/goip" "go.dtapp.net/gorequest" "go.dtapp.net/gotime" "go.dtapp.net/gotrace_id" @@ -13,137 +11,12 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "os" - "runtime" ) -// ApiMongoClientConfig 接口实例配置 -type ApiMongoClientConfig struct { - MongoClientFun apiMongoClientFun // 日志配置 - Debug bool // 日志开关 - ZapLog *ZapLog // 日志服务 - CurrentIp string // 当前ip -} - -// NewApiMongoClient 创建接口实例化 -// client 数据库服务 -// databaseName 库名 -// collectionName 表名 -func NewApiMongoClient(config *ApiMongoClientConfig) (*ApiClient, error) { - - var ctx = context.Background() - - c := &ApiClient{} - - c.zapLog = config.ZapLog - - c.logDebug = config.Debug - - if config.CurrentIp == "" { - config.CurrentIp = goip.GetOutsideIp(ctx) - } - if config.CurrentIp != "" && config.CurrentIp != "0.0.0.0" { - c.currentIp = config.CurrentIp - } - - client, databaseName, collectionName := config.MongoClientFun() - - if client == nil || client.Db == nil { - return nil, errors.New("没有设置驱动") - } - - c.mongoClient = client - - if databaseName == "" { - return nil, errors.New("没有设置库名") - } - c.mongoConfig.databaseName = databaseName - - if collectionName == "" { - return nil, errors.New("没有设置表名") - } - c.mongoConfig.collectionName = collectionName - - hostname, _ := os.Hostname() - - c.mongoConfig.hostname = hostname - c.mongoConfig.insideIp = goip.GetInsideIp(ctx) - c.mongoConfig.goVersion = runtime.Version() - - c.log.mongo = true - - // 创建时间序列集合 - c.mongoCreateCollection(ctx) - - // 创建索引 - c.mongoCreateIndexes(ctx) - - return c, nil -} - -// 创建时间序列集合 -func (c *ApiClient) mongoCreateCollection(ctx context.Context) { - var commandResult bson.M - commandErr := c.mongoClient.Db.Database(c.mongoConfig.databaseName).RunCommand(ctx, bson.D{{ - "listCollections", 1, - }}).Decode(&commandResult) - if commandErr != nil { - c.zapLog.WithLogger().Sugar().Errorf("检查时间序列集合:%s", commandErr) - } else { - err := c.mongoClient.Db.Database(c.mongoConfig.databaseName).CreateCollection(ctx, c.mongoConfig.collectionName, options.CreateCollection().SetTimeSeriesOptions(options.TimeSeries().SetTimeField("log_time"))) - if err != nil { - c.zapLog.WithLogger().Sugar().Errorf("创建时间序列集合:%s", err) - } - } -} - -// 创建索引 -func (c *ApiClient) mongoCreateIndexes(ctx context.Context) { - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"trace_id", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"log_time", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"request_time", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"request_method", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"response_status_code", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"response_time", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"system_host_name", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"system_inside_ip", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"system_os", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"system_arch", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"system_cpu_quantity", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"go_version", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{Keys: bson.D{ - {"sdk_version", -1}, - }})) -} - // 模型结构体 type apiMongolLog struct { LogId primitive.ObjectID `json:"log_id,omitempty" bson:"_id,omitempty"` //【记录】编号 - LogTime primitive.DateTime `json:"log_time,omitempty" bson:"log_time,omitempty"` //【记录】时间 + LogTime primitive.DateTime `json:"log_time,omitempty" bson:"log_time"` //【记录】时间 TraceId string `json:"trace_id,omitempty" bson:"trace_id,omitempty"` //【记录】跟踪编号 RequestTime dorm.BsonTime `json:"request_time,omitempty" bson:"request_time,omitempty"` //【请求】时间 RequestUri string `json:"request_uri,omitempty" bson:"request_uri,omitempty"` //【请求】链接 @@ -162,48 +35,63 @@ type apiMongolLog struct { SystemInsideIp string `json:"system_inside_ip,omitempty" bson:"system_inside_ip,omitempty"` //【系统】内网ip SystemOs string `json:"system_os,omitempty" bson:"system_os,omitempty"` //【系统】系统类型 SystemArch string `json:"system_arch,omitempty" bson:"system_arch,omitempty"` //【系统】系统架构 - SystemCpuQuantity int `json:"system_cpu_quantity,omitempty" bson:"system_cpu_quantity,omitempty"` //【系统】CPU核数 GoVersion string `json:"go_version,omitempty" bson:"go_version,omitempty"` //【程序】Go版本 SdkVersion string `json:"sdk_version,omitempty" bson:"sdk_version,omitempty"` //【程序】Sdk版本 } +// 创建时间序列集合 +func (c *ApiClient) mongoCreateCollection(ctx context.Context) { + err := c.mongoClient.Database(c.mongoConfig.databaseName).CreateCollection(ctx, c.mongoConfig.collectionName, options.CreateCollection().SetTimeSeriesOptions(options.TimeSeries().SetTimeField("log_time"))) + if err != nil { + c.zapLog.WithTraceId(ctx).Sugar().Errorf("创建时间序列集合:%s", err) + } +} + +// 创建索引 +func (c *ApiClient) mongoCreateIndexes(ctx context.Context) { + indexes, err := c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).CreateManyIndexes(ctx, []mongo.IndexModel{ + { + Keys: bson.D{{ + Key: "log_time", + Value: -1, + }}, + }}) + if err != nil { + c.zapLog.WithTraceId(ctx).Sugar().Errorf("创建索引:%s", err) + } + c.zapLog.WithTraceId(ctx).Sugar().Infof("创建索引:%s", indexes) +} + // 记录日志 func (c *ApiClient) mongoRecord(ctx context.Context, mongoLog apiMongolLog) (err error) { - mongoLog.SystemHostName = c.mongoConfig.hostname //【系统】主机名 - mongoLog.SystemInsideIp = c.mongoConfig.insideIp //【系统】内网ip - mongoLog.GoVersion = c.mongoConfig.goVersion //【程序】Go版本 + mongoLog.SystemHostName = c.config.systemHostName //【系统】主机名 + mongoLog.SystemInsideIp = c.config.systemInsideIp //【系统】内网ip + mongoLog.GoVersion = c.config.goVersion //【程序】Go版本 mongoLog.TraceId = gotrace_id.GetTraceIdContext(ctx) //【记录】跟踪编号 - mongoLog.RequestIp = c.currentIp //【请求】请求Ip - mongoLog.SystemOs = c.config.os //【系统】系统类型 - mongoLog.SystemArch = c.config.arch //【系统】系统架构 - mongoLog.SystemCpuQuantity = c.config.maxProCs //【系统】CPU核数 + mongoLog.RequestIp = c.config.systemOutsideIp //【请求】请求Ip + mongoLog.SystemOs = c.config.systemOs //【系统】系统类型 + mongoLog.SystemArch = c.config.systemArch //【系统】系统架构 mongoLog.LogId = primitive.NewObjectID() //【记录】编号 - _, err = c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).InsertOne(mongoLog) + _, err = c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).InsertOne(ctx, mongoLog) if err != nil { - c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.mongoRecord]:%s", err) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("记录日志失败:%s", err) } - return err } -// MongoQuery 查询 -func (c *ApiClient) MongoQuery(ctx context.Context) *mongo.Collection { - return c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName) -} - // MongoDelete 删除 func (c *ApiClient) MongoDelete(ctx context.Context, hour int64) (*mongo.DeleteResult, error) { filter := bson.D{{"log_time", bson.D{{"$lt", primitive.NewDateTimeFromTime(gotime.Current().BeforeHour(hour).Time)}}}} return c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).DeleteMany(ctx, filter) } -// MongoMiddleware 中间件 -func (c *ApiClient) MongoMiddleware(ctx context.Context, request gorequest.Response, sdkVersion string) { +// 中间件 +func (c *ApiClient) mongoMiddleware(ctx context.Context, request gorequest.Response, sdkVersion string) { data := apiMongolLog{ LogTime: primitive.NewDateTimeFromTime(request.RequestTime), //【记录】时间 - RequestTime: dorm.BsonTime(request.RequestTime), //【请求】时间 + RequestTime: dorm.NewBsonTimeFromTime(request.RequestTime), //【请求】时间 RequestUri: request.RequestUri, //【请求】链接 RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接 RequestApi: gourl.UriParse(request.RequestUri).Path, //【请求】接口 @@ -213,36 +101,36 @@ func (c *ApiClient) MongoMiddleware(ctx context.Context, request gorequest.Respo ResponseHeader: request.ResponseHeader, //【返回】头部 ResponseStatusCode: request.ResponseStatusCode, //【返回】状态码 ResponseContentLength: request.ResponseContentLength, //【返回】大小 - ResponseTime: dorm.BsonTime(request.ResponseTime), //【返回】时间 + ResponseTime: dorm.NewBsonTimeFromTime(request.ResponseTime), //【返回】时间 SdkVersion: sdkVersion, //【程序】Sdk版本 } - if request.ResponseHeader.Get("Content-Type") == "image/jpeg" || request.ResponseHeader.Get("Content-Type") == "image/png" || request.ResponseHeader.Get("Content-Type") == "image/jpg" { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddleware.type]:%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) + if request.HeaderIsImg() { + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddleware.type]:%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) } else { if len(request.ResponseBody) > 0 { data.ResponseBody = dorm.JsonDecodeNoError(request.ResponseBody) //【返回】内容 } else { if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddleware.len]:%s %s", data.RequestUri, request.ResponseBody) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddleware.len]:%s %s", data.RequestUri, request.ResponseBody) } } } if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddleware.data]:%+v", data) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddleware.data]:%+v", data) } err := c.mongoRecord(ctx, data) if err != nil { - c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.MongoMiddleware]:%s", err.Error()) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.mongoMiddleware]:%s", err.Error()) } } -// MongoMiddlewareXml 中间件 -func (c *ApiClient) MongoMiddlewareXml(ctx context.Context, request gorequest.Response, sdkVersion string) { +// 中间件 +func (c *ApiClient) mongoMiddlewareXml(ctx context.Context, request gorequest.Response, sdkVersion string) { data := apiMongolLog{ LogTime: primitive.NewDateTimeFromTime(request.RequestTime), //【记录】时间 - RequestTime: dorm.BsonTime(request.RequestTime), //【请求】时间 + RequestTime: dorm.NewBsonTimeFromTime(request.RequestTime), //【请求】时间 RequestUri: request.RequestUri, //【请求】链接 RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接 RequestApi: gourl.UriParse(request.RequestUri).Path, //【请求】接口 @@ -252,36 +140,36 @@ func (c *ApiClient) MongoMiddlewareXml(ctx context.Context, request gorequest.Re ResponseHeader: request.ResponseHeader, //【返回】头部 ResponseStatusCode: request.ResponseStatusCode, //【返回】状态码 ResponseContentLength: request.ResponseContentLength, //【返回】大小 - ResponseTime: dorm.BsonTime(request.ResponseTime), //【返回】时间 + ResponseTime: dorm.NewBsonTimeFromTime(request.ResponseTime), //【返回】时间 SdkVersion: sdkVersion, //【程序】Sdk版本 } - if request.ResponseHeader.Get("Content-Type") == "image/jpeg" || request.ResponseHeader.Get("Content-Type") == "image/png" || request.ResponseHeader.Get("Content-Type") == "image/jpg" { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareXml.type]:%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) + if request.HeaderIsImg() { + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddlewareXml.type]:%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) } else { if len(request.ResponseBody) > 0 { data.ResponseBody = dorm.XmlDecodeNoError(request.ResponseBody) //【返回】内容 } else { if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareXml]:%s %s", data.RequestUri, request.ResponseBody) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddlewareXml]:%s %s", data.RequestUri, request.ResponseBody) } } } if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareXml.data]:%+v", data) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddlewareXml.data]:%+v", data) } err := c.mongoRecord(ctx, data) if err != nil { - c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.MongoMiddlewareXml]:%s", err.Error()) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.mongoMiddlewareXml]:%s", err.Error()) } } -// MongoMiddlewareCustom 中间件 -func (c *ApiClient) MongoMiddlewareCustom(ctx context.Context, api string, request gorequest.Response, sdkVersion string) { +// 中间件 +func (c *ApiClient) mongoMiddlewareCustom(ctx context.Context, api string, request gorequest.Response, sdkVersion string) { data := apiMongolLog{ LogTime: primitive.NewDateTimeFromTime(request.RequestTime), //【记录】时间 - RequestTime: dorm.BsonTime(request.RequestTime), //【请求】时间 + RequestTime: dorm.NewBsonTimeFromTime(request.RequestTime), //【请求】时间 RequestUri: request.RequestUri, //【请求】链接 RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接 RequestApi: api, //【请求】接口 @@ -291,27 +179,27 @@ func (c *ApiClient) MongoMiddlewareCustom(ctx context.Context, api string, reque ResponseHeader: request.ResponseHeader, //【返回】头部 ResponseStatusCode: request.ResponseStatusCode, //【返回】状态码 ResponseContentLength: request.ResponseContentLength, //【返回】大小 - ResponseTime: dorm.BsonTime(request.ResponseTime), //【返回】时间 + ResponseTime: dorm.NewBsonTimeFromTime(request.ResponseTime), //【返回】时间 SdkVersion: sdkVersion, //【程序】Sdk版本 } - if request.ResponseHeader.Get("Content-Type") == "image/jpeg" || request.ResponseHeader.Get("Content-Type") == "image/png" || request.ResponseHeader.Get("Content-Type") == "image/jpg" { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareCustom.type]:%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) + if request.HeaderIsImg() { + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddlewareCustom.type]:%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type")) } else { if len(request.ResponseBody) > 0 { data.ResponseBody = dorm.JsonDecodeNoError(request.ResponseBody) //【返回】内容 } else { if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareCustom]:%s %s", data.RequestUri, request.ResponseBody) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddlewareCustom]:%s %s", data.RequestUri, request.ResponseBody) } } } if c.logDebug { - c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoRecordJson.data]:%+v", data) + c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoMiddlewareCustom.data]:%+v", data) } err := c.mongoRecord(ctx, data) if err != nil { - c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.MongoMiddlewareCustom]:%s", err.Error()) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.mongoMiddlewareCustom]:%s", err.Error()) } } diff --git a/vendor/go.dtapp.net/golog/const.go b/vendor/go.dtapp.net/golog/const.go index f7144db..d302d0c 100644 --- a/vendor/go.dtapp.net/golog/const.go +++ b/vendor/go.dtapp.net/golog/const.go @@ -1,5 +1,5 @@ package golog const ( - Version = "1.0.73" + Version = "1.0.88" ) diff --git a/vendor/go.dtapp.net/golog/error.go b/vendor/go.dtapp.net/golog/error.go new file mode 100644 index 0000000..85f4fda --- /dev/null +++ b/vendor/go.dtapp.net/golog/error.go @@ -0,0 +1,8 @@ +package golog + +import "errors" + +var ( + currentIpNoConfig = errors.New("请配置 CurrentIp") + dbClientFunNoConfig = errors.New("请配置 GormClientFun 或 MongoClientFun") +) diff --git a/vendor/go.dtapp.net/golog/gin.go b/vendor/go.dtapp.net/golog/gin.go index 4236597..910123d 100644 --- a/vendor/go.dtapp.net/golog/gin.go +++ b/vendor/go.dtapp.net/golog/gin.go @@ -12,11 +12,11 @@ import ( "go.dtapp.net/gotime" "go.dtapp.net/gotrace_id" "io/ioutil" - "net" - "os" - "runtime" ) +// GinClientFun *GinClient 驱动 +type GinClientFun func() *GinClient + // GinClient 框架 type GinClient struct { gormClient *dorm.GormClient // 数据库驱动 @@ -24,52 +24,36 @@ type GinClient struct { ipService *goip.Client // ip服务 zapLog *ZapLog // 日志服务 logDebug bool // 日志开关 - gormConfig struct { + config struct { + systemHostName string // 主机名 + systemInsideIp string // 内网ip + systemOs string // 系统类型 + systemArch string // 系统架构 + goVersion string // go版本 + sdkVersion string // sdk版本 + systemOutsideIp string // 外网ip + } + gormConfig struct { + stats bool // 状态 tableName string // 表名 - insideIp string // 内网ip - hostname string // 主机名 - goVersion string // go版本 } mongoConfig struct { + stats bool // 状态 databaseName string // 库名 collectionName string // 表名 - insideIp string // 内网ip - hostname string // 主机名 - goVersion string // go版本 - } - log struct { - gorm bool // 日志开关 - mongo bool // 日志开关 - } - config struct { - os string // 系统类型 - arch string // 系统架构 - maxProCs int // CPU核数 } } -// client 数据库服务 -// string 表名 -type ginGormClientFun func() (*dorm.GormClient, string) - -// client 数据库服务 -// string 库名 -// string 表名 -type ginMongoClientFun func() (*dorm.MongoClient, string, string) - // GinClientConfig 框架实例配置 type GinClientConfig struct { - IpService *goip.Client // ip服务 - GormClientFun ginGormClientFun // 日志配置 - MongoClientFun apiMongoClientFun // 日志配置 - Debug bool // 日志开关 - ZapLog *ZapLog // 日志服务 + IpService *goip.Client // ip服务 + GormClientFun dorm.GormClientTableFun // 日志配置 + MongoClientFun dorm.MongoClientCollectionFun // 日志配置 + Debug bool // 日志开关 + ZapLog *ZapLog // 日志服务 } // NewGinClient 创建框架实例化 -// client 数据库服务 -// tableName 表名 -// ipService ip服务 func NewGinClient(config *GinClientConfig) (*GinClient, error) { var ctx = context.Background() @@ -80,64 +64,50 @@ func NewGinClient(config *GinClientConfig) (*GinClient, error) { c.logDebug = config.Debug - c.config.os = runtime.GOOS - c.config.arch = runtime.GOARCH - c.config.maxProCs = runtime.GOMAXPROCS(0) + c.ipService = config.IpService + + // 配置信息 + c.setConfig(ctx) gormClient, gormTableName := config.GormClientFun() mongoClient, mongoDatabaseName, mongoCollectionName := config.MongoClientFun() if (gormClient == nil || gormClient.Db == nil) || (mongoClient == nil || mongoClient.Db == nil) { - return nil, errors.New("没有设置驱动") + return nil, dbClientFunNoConfig } - hostname, _ := os.Hostname() - + // 配置关系数据库 if gormClient != nil || gormClient.Db != nil { c.gormClient = gormClient if gormTableName == "" { return nil, errors.New("没有设置表名") + } else { + c.gormConfig.tableName = gormTableName } - c.gormConfig.tableName = gormTableName - c.ipService = config.IpService - - err := c.gormAutoMigrate() - if err != nil { - return nil, errors.New("创建表失败:" + err.Error()) - } - - c.gormConfig.hostname = hostname - c.gormConfig.insideIp = goip.GetInsideIp(ctx) - c.gormConfig.goVersion = runtime.Version() - - c.log.gorm = true + c.gormAutoMigrate(ctx) + c.gormConfig.stats = true } + // 配置非关系数据库 if mongoClient != nil || mongoClient.Db != nil { c.mongoClient = mongoClient if mongoDatabaseName == "" { return nil, errors.New("没有设置库名") + } else { + c.mongoConfig.databaseName = mongoDatabaseName } - c.mongoConfig.databaseName = mongoDatabaseName if mongoCollectionName == "" { return nil, errors.New("没有设置表名") + } else { + c.mongoConfig.collectionName = mongoCollectionName } - c.mongoConfig.collectionName = mongoCollectionName - - c.ipService = config.IpService - - c.mongoConfig.hostname = hostname - c.mongoConfig.insideIp = goip.GetInsideIp(ctx) - c.mongoConfig.goVersion = runtime.Version() - - c.log.mongo = true // 创建时间序列集合 c.mongoCreateCollection(ctx) @@ -145,6 +115,7 @@ func NewGinClient(config *GinClientConfig) (*GinClient, error) { // 创建索引 c.mongoCreateIndexes(ctx) + c.mongoConfig.stats = true } return c, nil @@ -214,53 +185,49 @@ func (c *GinClient) Middleware() gin.HandlerFunc { clientIp := gorequest.ClientIp(ginCtx.Request) - requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp := "", "", "", "", "" + var requestClientIpCountry string + var requestClientIpProvince string + var requestClientIpCity string + var requestClientIpIsp string + var requestClientIpLocationLatitude float64 + var requestClientIpLocationLongitude float64 if c.ipService != nil { - if net.ParseIP(clientIp).To4() != nil { - // IPv4 - _, info := c.ipService.Ipv4(clientIp) - requestClientIpCountry = info.Country - requestClientIpRegion = info.Region - requestClientIpProvince = info.Province - requestClientIpCity = info.City - requestClientIpIsp = info.ISP - } else if net.ParseIP(clientIp).To16() != nil { - // IPv6 - info := c.ipService.Ipv6(clientIp) - requestClientIpCountry = info.Country - requestClientIpProvince = info.Province - requestClientIpCity = info.City - } + info := c.ipService.Analyse(clientIp) + requestClientIpCountry = info.Country + requestClientIpProvince = info.Province + requestClientIpCity = info.City + requestClientIpIsp = info.Isp + requestClientIpLocationLatitude = info.LocationLatitude + requestClientIpLocationLongitude = info.LocationLongitude } var traceId = gotrace_id.GetGinTraceId(ginCtx) // 记录 - if c.log.gorm { + if c.gormConfig.stats { if dataJson { if c.logDebug { c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{gormRecordJson}保存数据:%s", data) } - c.gormRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp) + c.gormRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude) } else { if c.logDebug { c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{gormRecordXml}保存数据:%s", data) } - c.gormRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp) + c.gormRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude) } } - // 记录 - if c.log.mongo { + if c.mongoConfig.stats { if dataJson { if c.logDebug { c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{mongoRecordJson}保存数据:%s", data) } - c.mongoRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp) + c.mongoRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude) } else { if c.logDebug { c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{mongoRecordXml}保存数据:%s", data) } - c.mongoRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp) + c.mongoRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude) } } }() diff --git a/vendor/go.dtapp.net/golog/gin_cofing.go b/vendor/go.dtapp.net/golog/gin_cofing.go new file mode 100644 index 0000000..fd91196 --- /dev/null +++ b/vendor/go.dtapp.net/golog/gin_cofing.go @@ -0,0 +1,18 @@ +package golog + +import ( + "context" + "go.dtapp.net/goip" + "os" + "runtime" +) + +func (c *GinClient) setConfig(ctx context.Context) { + c.config.sdkVersion = Version + c.config.systemOs = runtime.GOOS + c.config.systemArch = runtime.GOARCH + c.config.goVersion = runtime.Version() + c.config.systemInsideIp = goip.GetInsideIp(ctx) + hostname, _ := os.Hostname() + c.config.systemHostName = hostname +} diff --git a/vendor/go.dtapp.net/golog/gin_gorm.go b/vendor/go.dtapp.net/golog/gin_gorm.go index 1edfdff..dff60a1 100644 --- a/vendor/go.dtapp.net/golog/gin_gorm.go +++ b/vendor/go.dtapp.net/golog/gin_gorm.go @@ -1,170 +1,102 @@ package golog import ( - "bytes" "context" - "encoding/json" - "errors" "github.com/gin-gonic/gin" "go.dtapp.net/dorm" - "go.dtapp.net/goip" - "go.dtapp.net/gorequest" "go.dtapp.net/gotime" - "go.dtapp.net/gotrace_id" "go.dtapp.net/gourl" - "gorm.io/gorm" - "io/ioutil" - "net" - "os" - "runtime" "time" ) -// GinGormClientConfig 框架实例配置 -type GinGormClientConfig struct { - IpService *goip.Client // ip服务 - GormClientFun ginGormClientFun // 日志配置 - Debug bool // 日志开关 - ZapLog *ZapLog // 日志服务 -} - -// NewGinGormClient 创建框架实例化 -// client 数据库服务 -// tableName 表名 -// ipService ip服务 -func NewGinGormClient(config *GinGormClientConfig) (*GinClient, error) { - - var ctx = context.Background() - - c := &GinClient{} - - c.zapLog = config.ZapLog - - c.logDebug = config.Debug - - client, tableName := config.GormClientFun() - - if client == nil || client.Db == nil { - return nil, errors.New("没有设置驱动") - } - - c.gormClient = client - - if tableName == "" { - return nil, errors.New("没有设置表名") - } - c.gormConfig.tableName = tableName - - c.ipService = config.IpService - - err := c.gormAutoMigrate() - if err != nil { - return nil, errors.New("创建表失败:" + err.Error()) - } - - hostname, _ := os.Hostname() - - c.gormConfig.hostname = hostname - c.gormConfig.insideIp = goip.GetInsideIp(ctx) - c.gormConfig.goVersion = runtime.Version() - - c.log.gorm = true - - return c, nil +// 模型 +type ginPostgresqlLog struct { + LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号 + TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号 + RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间 + RequestUri string `gorm:"comment:【请求】请求链接 域名+路径+参数" json:"request_uri,omitempty"` //【请求】请求链接 域名+路径+参数 + RequestUrl string `gorm:"comment:【请求】请求链接 域名+路径" json:"request_url,omitempty"` //【请求】请求链接 域名+路径 + RequestApi string `gorm:"index;comment:【请求】请求接口 路径" json:"request_api,omitempty"` //【请求】请求接口 路径 + RequestMethod string `gorm:"index;comment:【请求】请求方式" json:"request_method,omitempty"` //【请求】请求方式 + RequestProto string `gorm:"comment:【请求】请求协议" json:"request_proto,omitempty"` //【请求】请求协议 + RequestUa string `gorm:"comment:【请求】请求UA" json:"request_ua,omitempty"` //【请求】请求UA + RequestReferer string `gorm:"comment:【请求】请求referer" json:"request_referer,omitempty"` //【请求】请求referer + RequestBody string `gorm:"comment:【请求】请求主体" json:"request_body,omitempty"` //【请求】请求主体 + RequestUrlQuery string `gorm:"comment:【请求】请求URL参数" json:"request_url_query,omitempty"` //【请求】请求URL参数 + RequestIp string `gorm:"default:0.0.0.0;index;comment:【请求】请求客户端Ip" json:"request_ip,omitempty"` //【请求】请求客户端Ip + RequestIpCountry string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_country,omitempty"` //【请求】请求客户端城市 + RequestIpProvince string `gorm:"index;comment:【请求】请求客户端省份" json:"request_ip_province,omitempty"` //【请求】请求客户端省份 + RequestIpCity string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_city,omitempty"` //【请求】请求客户端城市 + RequestIpIsp string `gorm:"index;comment:【请求】请求客户端运营商" json:"request_ip_isp,omitempty"` //【请求】请求客户端运营商 + RequestIpLongitude float64 `gorm:"index;comment:【请求】请求客户端经度" json:"request_ip_longitude,omitempty"` //【请求】请求客户端经度 + RequestIpLatitude float64 `gorm:"index;comment:【请求】请求客户端纬度" json:"request_ip_latitude,omitempty"` //【请求】请求客户端纬度 + RequestHeader string `gorm:"comment:【请求】请求头" json:"request_header,omitempty"` //【请求】请求头 + ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间 + ResponseCode int `gorm:"index;comment:【返回】状态码" json:"response_code,omitempty"` //【返回】状态码 + ResponseMsg string `gorm:"comment:【返回】描述" json:"response_msg,omitempty"` //【返回】描述 + ResponseData string `gorm:"comment:【返回】数据" json:"response_data,omitempty"` //【返回】数据 + CostTime int64 `gorm:"comment:【系统】花费时间" json:"cost_time,omitempty"` //【系统】花费时间 + SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名 + SystemInsideIp string `gorm:"default:0.0.0.0;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip + SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型 + SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构 + GoVersion string `gorm:"comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本 + SdkVersion string `gorm:"comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本 } // 创建模型 -func (c *GinClient) gormAutoMigrate() (err error) { - err = c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&ginPostgresqlLog{}) +func (c *GinClient) gormAutoMigrate(ctx context.Context) { + err := c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&ginPostgresqlLog{}) if err != nil { - c.zapLog.WithLogger().Sugar().Infof("[golog.gin.gormAutoMigrate]:%s", err) + c.zapLog.WithTraceId(ctx).Sugar().Errorf("创建模型:%s", err) } - return err -} - -// 模型结构体 -type ginPostgresqlLog struct { - LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号 - TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号 - RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间 - RequestUri string `gorm:"comment:【请求】请求链接 域名+路径+参数" json:"request_uri,omitempty"` //【请求】请求链接 域名+路径+参数 - RequestUrl string `gorm:"comment:【请求】请求链接 域名+路径" json:"request_url,omitempty"` //【请求】请求链接 域名+路径 - RequestApi string `gorm:"index;comment:【请求】请求接口 路径" json:"request_api,omitempty"` //【请求】请求接口 路径 - RequestMethod string `gorm:"index;comment:【请求】请求方式" json:"request_method,omitempty"` //【请求】请求方式 - RequestProto string `gorm:"comment:【请求】请求协议" json:"request_proto,omitempty"` //【请求】请求协议 - RequestUa string `gorm:"comment:【请求】请求UA" json:"request_ua,omitempty"` //【请求】请求UA - RequestReferer string `gorm:"comment:【请求】请求referer" json:"request_referer,omitempty"` //【请求】请求referer - RequestBody string `gorm:"comment:【请求】请求主体" json:"request_body,omitempty"` //【请求】请求主体 - RequestUrlQuery string `gorm:"comment:【请求】请求URL参数" json:"request_url_query,omitempty"` //【请求】请求URL参数 - RequestIp string `gorm:"index;comment:【请求】请求客户端Ip" json:"request_ip,omitempty"` //【请求】请求客户端Ip - RequestIpCountry string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_country,omitempty"` //【请求】请求客户端城市 - RequestIpRegion string `gorm:"index;comment:【请求】请求客户端区域" json:"request_ip_region,omitempty"` //【请求】请求客户端区域 - RequestIpProvince string `gorm:"index;comment:【请求】请求客户端省份" json:"request_ip_province,omitempty"` //【请求】请求客户端省份 - RequestIpCity string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_city,omitempty"` //【请求】请求客户端城市 - RequestIpIsp string `gorm:"index;comment:【请求】请求客户端运营商" json:"request_ip_isp,omitempty"` //【请求】请求客户端运营商 - RequestHeader string `gorm:"comment:【请求】请求头" json:"request_header,omitempty"` //【请求】请求头 - ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间 - ResponseCode int `gorm:"index;comment:【返回】状态码" json:"response_code,omitempty"` //【返回】状态码 - ResponseMsg string `gorm:"comment:【返回】描述" json:"response_msg,omitempty"` //【返回】描述 - ResponseData string `gorm:"comment:【返回】数据" json:"response_data,omitempty"` //【返回】数据 - CostTime int64 `gorm:"comment:【系统】花费时间" json:"cost_time,omitempty"` //【系统】花费时间 - SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名 - SystemInsideIp string `gorm:"index;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip - SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型 - SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构 - SystemCpuQuantity int `gorm:"index;comment:【系统】CPU核数" json:"system_cpu_quantity,omitempty"` //【系统】CPU核数 - GoVersion string `gorm:"index;comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本 - SdkVersion string `gorm:"index;comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本 } // gormRecord 记录日志 -func (c *GinClient) gormRecord(postgresqlLog ginPostgresqlLog) (err error) { - - postgresqlLog.SystemHostName = c.gormConfig.hostname - postgresqlLog.SystemInsideIp = c.gormConfig.insideIp - postgresqlLog.GoVersion = c.gormConfig.goVersion - - postgresqlLog.SdkVersion = Version +func (c *GinClient) gormRecord(data ginPostgresqlLog) (err error) { - postgresqlLog.SystemOs = c.config.os - postgresqlLog.SystemArch = c.config.arch - postgresqlLog.SystemCpuQuantity = c.config.maxProCs + data.SystemHostName = c.config.systemHostName //【系统】主机名 + data.SystemInsideIp = c.config.systemInsideIp //【系统】内网ip + data.GoVersion = c.config.goVersion //【程序】Go版本 + data.SdkVersion = c.config.sdkVersion //【程序】Sdk版本 + data.SystemOs = c.config.systemOs //【系统】系统类型 + data.SystemArch = c.config.systemArch //【系统】系统架构 - err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&postgresqlLog).Error + err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&data).Error if err != nil { - c.zapLog.WithTraceIdStr(postgresqlLog.TraceId).Sugar().Errorf("[golog.gin.gormRecord]:%s", err) + c.zapLog.WithTraceIdStr(data.TraceId).Sugar().Errorf("记录日志失败:%s", err) } - return } -func (c *GinClient) gormRecordJson(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string) { +func (c *GinClient) gormRecordJson(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string, requestClientIpLocationLatitude, requestClientIpLocationLongitude float64) { if c.logDebug { c.zapLog.WithLogger().Sugar().Infof("[golog.gin.gormRecordJson]收到保存数据要求:%s", c.gormConfig.tableName) } data := ginPostgresqlLog{ - TraceId: traceId, //【系统】跟踪编号 - RequestTime: requestTime, //【请求】时间 - RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接 - RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口 - RequestMethod: ginCtx.Request.Method, //【请求】请求方式 - RequestProto: ginCtx.Request.Proto, //【请求】请求协议 - RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA - RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer - RequestUrlQuery: dorm.JsonEncodeNoError(ginCtx.Request.URL.Query()), //【请求】请求URL参数 - RequestIp: clientIp, //【请求】请求客户端Ip - RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市 - RequestIpRegion: requestClientIpRegion, //【请求】请求客户端区域 - RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份 - RequestIpCity: requestClientIpCity, //【请求】请求客户端城市 - RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商 - RequestHeader: dorm.JsonEncodeNoError(ginCtx.Request.Header), //【请求】请求头 - ResponseTime: gotime.Current().Time, //【返回】时间 - ResponseCode: responseCode, //【返回】状态码 - ResponseData: responseBody, //【返回】数据 - CostTime: endTime - startTime, //【系统】花费时间 + TraceId: traceId, //【系统】跟踪编号 + RequestTime: requestTime, //【请求】时间 + RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接 + RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口 + RequestMethod: ginCtx.Request.Method, //【请求】请求方式 + RequestProto: ginCtx.Request.Proto, //【请求】请求协议 + RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA + RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer + RequestUrlQuery: dorm.JsonEncodeNoError(ginCtx.Request.URL.Query()), //【请求】请求URL参数 + RequestIp: clientIp, //【请求】请求客户端Ip + RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市 + RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份 + RequestIpCity: requestClientIpCity, //【请求】请求客户端城市 + RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商 + RequestIpLatitude: requestClientIpLocationLatitude, // 【请求】请求客户端纬度 + RequestIpLongitude: requestClientIpLocationLongitude, // 【请求】请求客户端经度 + RequestHeader: dorm.JsonEncodeNoError(ginCtx.Request.Header), //【请求】请求头 + ResponseTime: gotime.Current().Time, //【返回】时间 + ResponseCode: responseCode, //【返回】状态码 + ResponseData: responseBody, //【返回】数据 + CostTime: endTime - startTime, //【系统】花费时间 } if ginCtx.Request.TLS == nil { data.RequestUri = "http://" + ginCtx.Request.Host + ginCtx.Request.RequestURI //【请求】请求链接 @@ -192,33 +124,34 @@ func (c *GinClient) gormRecordJson(ginCtx *gin.Context, traceId string, requestT } } -func (c *GinClient) gormRecordXml(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string) { +func (c *GinClient) gormRecordXml(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string, requestClientIpLocationLatitude, requestClientIpLocationLongitude float64) { if c.logDebug { c.zapLog.WithLogger().Sugar().Infof("[golog.gin.gormRecordXml]收到保存数据要求:%s", c.gormConfig.tableName) } data := ginPostgresqlLog{ - TraceId: traceId, //【系统】跟踪编号 - RequestTime: requestTime, //【请求】时间 - RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接 - RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口 - RequestMethod: ginCtx.Request.Method, //【请求】请求方式 - RequestProto: ginCtx.Request.Proto, //【请求】请求协议 - RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA - RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer - RequestUrlQuery: dorm.JsonEncodeNoError(ginCtx.Request.URL.Query()), //【请求】请求URL参数 - RequestIp: clientIp, //【请求】请求客户端Ip - RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市 - RequestIpRegion: requestClientIpRegion, //【请求】请求客户端区域 - RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份 - RequestIpCity: requestClientIpCity, //【请求】请求客户端城市 - RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商 - RequestHeader: dorm.JsonEncodeNoError(ginCtx.Request.Header), //【请求】请求头 - ResponseTime: gotime.Current().Time, //【返回】时间 - ResponseCode: responseCode, //【返回】状态码 - ResponseData: responseBody, //【返回】数据 - CostTime: endTime - startTime, //【系统】花费时间 + TraceId: traceId, //【系统】跟踪编号 + RequestTime: requestTime, //【请求】时间 + RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接 + RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口 + RequestMethod: ginCtx.Request.Method, //【请求】请求方式 + RequestProto: ginCtx.Request.Proto, //【请求】请求协议 + RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA + RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer + RequestUrlQuery: dorm.JsonEncodeNoError(ginCtx.Request.URL.Query()), //【请求】请求URL参数 + RequestIp: clientIp, //【请求】请求客户端Ip + RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市 + RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份 + RequestIpCity: requestClientIpCity, //【请求】请求客户端城市 + RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商 + RequestIpLatitude: requestClientIpLocationLatitude, // 【请求】请求客户端纬度 + RequestIpLongitude: requestClientIpLocationLongitude, // 【请求】请求客户端经度 + RequestHeader: dorm.JsonEncodeNoError(ginCtx.Request.Header), //【请求】请求头 + ResponseTime: gotime.Current().Time, //【返回】时间 + ResponseCode: responseCode, //【返回】状态码 + ResponseData: responseBody, //【返回】数据 + CostTime: endTime - startTime, //【系统】花费时间 } if ginCtx.Request.TLS == nil { data.RequestUri = "http://" + ginCtx.Request.Host + ginCtx.Request.RequestURI //【请求】请求链接 @@ -247,100 +180,7 @@ func (c *GinClient) gormRecordXml(ginCtx *gin.Context, traceId string, requestTi } } -// GormQuery 查询 -func (c *GinClient) GormQuery(ctx context.Context) *gorm.DB { - return c.gormClient.Db.Table(c.gormConfig.tableName) -} - // GormDelete 删除 func (c *GinClient) GormDelete(ctx context.Context, hour int64) error { return c.gormClient.Db.Table(c.gormConfig.tableName).Where("request_time < ?", gotime.Current().BeforeHour(hour).Format()).Delete(&ginPostgresqlLog{}).Error } - -// GormMiddleware 中间件 -func (c *GinClient) GormMiddleware() gin.HandlerFunc { - return func(ginCtx *gin.Context) { - - // 开始时间 - startTime := gotime.Current().TimestampWithMillisecond() - requestTime := gotime.Current().Time - - // 获取 - data, _ := ioutil.ReadAll(ginCtx.Request.Body) - - if c.logDebug { - c.zapLog.WithLogger().Sugar().Infof("[golog.gin.GormMiddleware]:%s", data) - } - - // 复用 - ginCtx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - - blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: ginCtx.Writer} - ginCtx.Writer = blw - - // 处理请求 - ginCtx.Next() - - // 响应 - responseCode := ginCtx.Writer.Status() - responseBody := blw.body.String() - - //结束时间 - endTime := gotime.Current().TimestampWithMillisecond() - - go func() { - - var dataJson = true - - // 解析请求内容 - var jsonBody map[string]interface{} - - // 判断是否有内容 - if len(data) > 0 { - err := json.Unmarshal(data, &jsonBody) - if err != nil { - dataJson = false - } - } - - clientIp := gorequest.ClientIp(ginCtx.Request) - - requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp := "", "", "", "", "" - if c.ipService != nil { - if net.ParseIP(clientIp).To4() != nil { - // IPv4 - _, info := c.ipService.Ipv4(clientIp) - requestClientIpCountry = info.Country - requestClientIpRegion = info.Region - requestClientIpProvince = info.Province - requestClientIpCity = info.City - requestClientIpIsp = info.ISP - } else if net.ParseIP(clientIp).To16() != nil { - // IPv6 - info := c.ipService.Ipv6(clientIp) - requestClientIpCountry = info.Country - requestClientIpProvince = info.Province - requestClientIpCity = info.City - } - } - - // 记录 - if c.gormClient != nil && c.gormClient.Db != nil { - - var traceId = gotrace_id.GetGinTraceId(ginCtx) - - if dataJson { - if c.logDebug { - c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.GormMiddleware]准备使用{gormRecordJson}保存数据:%s", data) - } - c.gormRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp) - } else { - if c.logDebug { - c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.GormMiddleware]准备使用{gormRecordXml}保存数据:%s", data) - } - c.gormRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp) - } - } - }() - } -} diff --git a/vendor/go.dtapp.net/golog/gin_mongo.go b/vendor/go.dtapp.net/golog/gin_mongo.go index 77ed3e7..057dfb4 100644 --- a/vendor/go.dtapp.net/golog/gin_mongo.go +++ b/vendor/go.dtapp.net/golog/gin_mongo.go @@ -1,14 +1,9 @@ package golog import ( - "bytes" "context" - "encoding/json" - "errors" "github.com/gin-gonic/gin" "go.dtapp.net/dorm" - "go.dtapp.net/goip" - "go.dtapp.net/gorequest" "go.dtapp.net/gotime" "go.dtapp.net/gotrace_id" "go.dtapp.net/gourl" @@ -16,177 +11,18 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "io/ioutil" - "net" - "os" - "runtime" "time" ) -// GinMongoClientConfig 框架实例配置 -type GinMongoClientConfig struct { - IpService *goip.Client // ip服务 - MongoClientFun ginMongoClientFun // 日志配置 - Debug bool // 日志开关 - ZapLog *ZapLog // 日志服务 -} - -// NewGinMongoClient 创建框架实例化 -// client 数据库服务 -// databaseName 库名 -// collectionName 表名 -// ipService ip服务 -func NewGinMongoClient(config *GinMongoClientConfig) (*GinClient, error) { - - var ctx = context.Background() - - c := &GinClient{} - - c.zapLog = config.ZapLog - - c.logDebug = config.Debug - - client, databaseName, collectionName := config.MongoClientFun() - - if client == nil || client.Db == nil { - return nil, errors.New("没有设置驱动") - } - - c.mongoClient = client - - if databaseName == "" { - return nil, errors.New("没有设置库名") - } - c.mongoConfig.databaseName = databaseName - - if collectionName == "" { - return nil, errors.New("没有设置表名") - } - c.mongoConfig.collectionName = collectionName - - c.ipService = config.IpService - - hostname, _ := os.Hostname() - - c.mongoConfig.hostname = hostname - c.mongoConfig.insideIp = goip.GetInsideIp(ctx) - c.mongoConfig.goVersion = runtime.Version() - - c.log.mongo = true - - // 创建时间序列集合 - c.mongoCreateCollection(ctx) - - // 创建索引 - c.mongoCreateIndexes(ctx) - - return c, nil -} - -// 创建时间序列集合 -func (c *GinClient) mongoCreateCollection(ctx context.Context) { - var commandResult bson.M - commandErr := c.mongoClient.Db.Database(c.mongoConfig.databaseName).RunCommand(ctx, bson.D{{ - "listCollections", 1, - }}).Decode(&commandResult) - if commandErr != nil { - c.zapLog.WithLogger().Sugar().Error("检查时间序列集合:", commandErr) - } else { - err := c.mongoClient.Db.Database(c.mongoConfig.databaseName).CreateCollection(ctx, c.mongoConfig.collectionName, options.CreateCollection().SetTimeSeriesOptions(options.TimeSeries().SetTimeField("log_time"))) - if err != nil { - c.zapLog.WithLogger().Sugar().Error("创建时间序列集合:", err) - } - } -} - -// 创建索引 -func (c *GinClient) mongoCreateIndexes(ctx context.Context) { - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"trace_id", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"log_time", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_time", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_method", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_proto", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_ip", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_ip_country", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_ip_region", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_ip_province", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_ip_city", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"request_ip_isp", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"response_time", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"response_code", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"system_host_name", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"system_inside_ip", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"system_os", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"system_arch", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"system_cpu_quantity", 1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"go_version", -1}, - }})) - c.zapLog.WithLogger().Sugar().Infof(c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).Indexes().CreateOne(ctx, mongo.IndexModel{ - Keys: bson.D{ - {"sdk_version", -1}, - }})) +type ginMongoLogRequestIpLocationLocation struct { + Type string `json:"type,omitempty" bson:"type,omitempty"` // GeoJSON类型 + Coordinates []float64 `json:"coordinates,omitempty" bson:"coordinates,omitempty"` // 经度,纬度 } // 模型结构体 type ginMongoLog struct { LogId primitive.ObjectID `json:"log_id,omitempty" bson:"_id,omitempty"` //【记录】编号 - LogTime primitive.DateTime `json:"log_time,omitempty" bson:"log_time,omitempty"` //【记录】时间 + LogTime primitive.DateTime `json:"log_time,omitempty" bson:"log_time"` //【记录】时间 TraceId string `json:"trace_id,omitempty" bson:"trace_id,omitempty"` //【记录】跟踪编号 RequestTime dorm.BsonTime `json:"request_time,omitempty" bson:"request_time,omitempty"` //【请求】时间 RequestUri string `json:"request_uri,omitempty" bson:"request_uri,omitempty"` //【请求】请求链接 域名+路径+参数 @@ -199,11 +35,11 @@ type ginMongoLog struct { RequestBody interface{} `json:"request_body,omitempty" bson:"request_body,omitempty"` //【请求】请求主体 RequestUrlQuery interface{} `json:"request_url_query,omitempty" bson:"request_url_query,omitempty"` //【请求】请求URL参数 RequestIp string `json:"request_ip,omitempty" bson:"request_ip,omitempty"` //【请求】请求客户端Ip - RequestIpCountry string `json:"request_ip_country,omitempty" bson:"request_ip_country,omitempty"` //【请求】请求客户端城市 - RequestIpRegion string `json:"request_ip_region,omitempty" bson:"request_ip_region,omitempty"` //【请求】请求客户端区域 + RequestIpCountry string `json:"request_ip_country,omitempty" bson:"request_ip_country,omitempty"` //【请求】请求客户端国家 RequestIpProvince string `json:"request_ip_province,omitempty" bson:"request_ip_province,omitempty"` //【请求】请求客户端省份 RequestIpCity string `json:"request_ip_city,omitempty" bson:"request_ip_city,omitempty"` //【请求】请求客户端城市 RequestIpIsp string `json:"request_ip_isp,omitempty" bson:"request_ip_isp,omitempty"` //【请求】请求客户端运营商 + RequestIpLocation interface{} `json:"request_ip_location,omitempty" bson:"request_ip_location,omitempty"` //【请求】请求客户端位置 RequestHeader interface{} `json:"request_header,omitempty" bson:"request_header,omitempty"` //【请求】请求头 ResponseTime dorm.BsonTime `json:"response_time,omitempty" bson:"response_time,omitempty"` //【返回】时间 ResponseCode int `json:"response_code,omitempty" bson:"response_code,omitempty"` //【返回】状态码 @@ -214,32 +50,128 @@ type ginMongoLog struct { SystemInsideIp string `json:"system_inside_ip,omitempty" bson:"system_inside_ip,omitempty"` //【系统】内网ip SystemOs string `json:"system_os,omitempty" bson:"system_os,omitempty"` //【系统】系统类型 SystemArch string `json:"system_arch,omitempty" bson:"system_arch,omitempty"` //【系统】系统架构 - SystemCpuQuantity int `json:"system_cpu_quantity,omitempty" bson:"system_cpu_quantity,omitempty"` //【系统】CPU核数 GoVersion string `json:"go_version,omitempty" bson:"go_version,omitempty"` //【程序】Go版本 SdkVersion string `json:"sdk_version,omitempty" bson:"sdk_version,omitempty"` //【程序】Sdk版本 } +// 创建集合 +func (c *GinClient) mongoCreateCollection(ctx context.Context) { + err := c.mongoClient.Database(c.mongoConfig.databaseName).CreateCollection(ctx, c.mongoConfig.collectionName, options.CreateCollection().SetCollation(&options.Collation{ + Locale: "request_time", + Strength: -1, + })) + if err != nil { + c.zapLog.WithTraceId(ctx).Sugar().Error("创建集合:", err) + } +} + +// 创建索引 +func (c *GinClient) mongoCreateIndexes(ctx context.Context) { + indexes, err := c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).CreateManyIndexes(ctx, []mongo.IndexModel{ + { + Keys: bson.D{{ + Key: "trace_id", + Value: -1, + }}, + }, { + Keys: bson.D{{ + Key: "request_method", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "request_ip", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "request_ip_country", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "request_ip_province", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "request_ip_city", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "request_ip_isp", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "response_time", + Value: -1, + }}, + }, { + Keys: bson.D{{ + Key: "response_code", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "system_host_name", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "system_os", + Value: 1, + }}, + }, { + Keys: bson.D{{ + Key: "system_arch", + Value: -1, + }}, + }, { + Keys: bson.D{{ + Key: "go_version", + Value: -1, + }}, + }, { + Keys: bson.D{{ + Key: "sdk_version", + Value: -1, + }}, + }, { + Keys: bson.D{{ + Key: "request_ip_location", + Value: "2dsphere", + }}, + }, + }) + if err != nil { + c.zapLog.WithTraceId(ctx).Sugar().Errorf("创建索引:%s", err) + } + c.zapLog.WithTraceId(ctx).Sugar().Infof("创建索引:%s", indexes) +} + // 记录日志 -func (c *GinClient) mongoRecord(mongoLog ginMongoLog) (err error) { +func (c *GinClient) mongoRecord(ctx context.Context, mongoLog ginMongoLog) (err error) { - mongoLog.SystemHostName = c.mongoConfig.hostname //【系统】主机名 - mongoLog.SystemInsideIp = c.mongoConfig.insideIp //【系统】内网ip - mongoLog.GoVersion = c.mongoConfig.goVersion //【程序】Go版本 - mongoLog.SdkVersion = Version //【程序】Sdk版本 - mongoLog.SystemOs = c.config.os //【系统】系统类型 - mongoLog.SystemArch = c.config.arch //【系统】系统架构 - mongoLog.SystemCpuQuantity = c.config.maxProCs //【系统】CPU核数 - mongoLog.LogId = primitive.NewObjectID() //【记录】编号 + mongoLog.SystemHostName = c.config.systemHostName //【系统】主机名 + mongoLog.SystemInsideIp = c.config.systemInsideIp //【系统】内网ip + mongoLog.GoVersion = c.config.goVersion //【程序】Go版本 + mongoLog.SdkVersion = c.config.sdkVersion //【程序】Sdk版本 + mongoLog.SystemOs = c.config.systemOs //【系统】系统类型 + mongoLog.SystemArch = c.config.systemArch //【系统】系统架构 + mongoLog.LogId = primitive.NewObjectID() //【记录】编号 - _, err = c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).InsertOne(mongoLog) + _, err = c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).InsertOne(ctx, mongoLog) if err != nil { - c.zapLog.WithTraceIdStr(mongoLog.TraceId).Sugar().Errorf("[golog.gin.mongoRecord]:%s", err) + c.zapLog.WithTraceIdStr(mongoLog.TraceId).Sugar().Errorf("记录日志失败:%s", err) } - return err } -func (c *GinClient) mongoRecordJson(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string) { +func (c *GinClient) mongoRecordJson(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string, requestClientIpLocationLatitude, requestClientIpLocationLongitude float64) { + + var ctx = gotrace_id.SetGinTraceIdContext(context.Background(), ginCtx) if c.logDebug { c.zapLog.WithLogger().Sugar().Infof("[golog.gin.mongoRecordJson]收到保存数据要求:%s,%s", c.mongoConfig.databaseName, c.mongoConfig.collectionName) @@ -248,7 +180,7 @@ func (c *GinClient) mongoRecordJson(ginCtx *gin.Context, traceId string, request data := ginMongoLog{ TraceId: traceId, //【记录】跟踪编号 LogTime: primitive.NewDateTimeFromTime(requestTime), //【记录】时间 - RequestTime: dorm.BsonTime(requestTime), //【请求】时间 + RequestTime: dorm.NewBsonTimeFromTime(requestTime), //【请求】时间 RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接 RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口 RequestMethod: ginCtx.Request.Method, //【请求】请求方式 @@ -257,13 +189,12 @@ func (c *GinClient) mongoRecordJson(ginCtx *gin.Context, traceId string, request RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer RequestUrlQuery: ginCtx.Request.URL.Query(), //【请求】请求URL参数 RequestIp: clientIp, //【请求】请求客户端Ip - RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市 - RequestIpRegion: requestClientIpRegion, //【请求】请求客户端区域 + RequestIpCountry: requestClientIpCountry, //【请求】请求客户端国家 RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份 RequestIpCity: requestClientIpCity, //【请求】请求客户端城市 RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商 RequestHeader: ginCtx.Request.Header, //【请求】请求头 - ResponseTime: dorm.BsonTime(gotime.Current().Time), //【返回】时间 + ResponseTime: dorm.NewBsonTimeCurrent(), //【返回】时间 ResponseCode: responseCode, //【返回】状态码 ResponseData: c.jsonUnmarshal(responseBody), //【返回】数据 CostTime: endTime - startTime, //【系统】花费时间 @@ -282,17 +213,26 @@ func (c *GinClient) mongoRecordJson(ginCtx *gin.Context, traceId string, request } } + if requestClientIpLocationLatitude != 0 && requestClientIpLocationLongitude != 0 { + data.RequestIpLocation = ginMongoLogRequestIpLocationLocation{ + Type: "Point", + Coordinates: []float64{requestClientIpLocationLongitude, requestClientIpLocationLatitude}, + } + } + if c.logDebug { c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.mongoRecordJson.data]:%+v", data) } - err := c.mongoRecord(data) + err := c.mongoRecord(ctx, data) if err != nil { c.zapLog.WithTraceIdStr(traceId).Sugar().Errorf("[golog.gin.mongoRecordJson]:%s", err) } } -func (c *GinClient) mongoRecordXml(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string) { +func (c *GinClient) mongoRecordXml(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string, requestClientIpLocationLatitude, requestClientIpLocationLongitude float64) { + + var ctx = gotrace_id.SetGinTraceIdContext(context.Background(), ginCtx) if c.logDebug { c.zapLog.WithLogger().Sugar().Infof("[golog.gin.mongoRecordXml]收到保存数据要求:%s,%s", c.mongoConfig.databaseName, c.mongoConfig.collectionName) @@ -301,7 +241,7 @@ func (c *GinClient) mongoRecordXml(ginCtx *gin.Context, traceId string, requestT data := ginMongoLog{ TraceId: traceId, //【记录】跟踪编号 LogTime: primitive.NewDateTimeFromTime(requestTime), //【记录】时间 - RequestTime: dorm.BsonTime(requestTime), //【请求】时间 + RequestTime: dorm.NewBsonTimeFromTime(requestTime), //【请求】时间 RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接 RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口 RequestMethod: ginCtx.Request.Method, //【请求】请求方式 @@ -310,13 +250,12 @@ func (c *GinClient) mongoRecordXml(ginCtx *gin.Context, traceId string, requestT RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer RequestUrlQuery: ginCtx.Request.URL.Query(), //【请求】请求URL参数 RequestIp: clientIp, //【请求】请求客户端Ip - RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市 - RequestIpRegion: requestClientIpRegion, //【请求】请求客户端区域 + RequestIpCountry: requestClientIpCountry, //【请求】请求客户端国家 RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份 RequestIpCity: requestClientIpCity, //【请求】请求客户端城市 RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商 RequestHeader: ginCtx.Request.Header, //【请求】请求头 - ResponseTime: dorm.BsonTime(gotime.Current().Time), //【返回】时间 + ResponseTime: dorm.NewBsonTimeCurrent(), //【返回】时间 ResponseCode: responseCode, //【返回】状态码 ResponseData: c.jsonUnmarshal(responseBody), //【返回】数据 CostTime: endTime - startTime, //【系统】花费时间 @@ -335,111 +274,25 @@ func (c *GinClient) mongoRecordXml(ginCtx *gin.Context, traceId string, requestT } } + if requestClientIpLocationLatitude != 0 && requestClientIpLocationLongitude != 0 { + data.RequestIpLocation = ginMongoLogRequestIpLocationLocation{ + Type: "Point", + Coordinates: []float64{requestClientIpLocationLongitude, requestClientIpLocationLatitude}, + } + } + if c.logDebug { c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.mongoRecordXml.data]:%+v", data) } - err := c.mongoRecord(data) + err := c.mongoRecord(ctx, data) if err != nil { c.zapLog.WithTraceIdStr(traceId).Sugar().Errorf("[golog.gin.mongoRecordXml]:%s", err) } } -// MongoQuery 查询 -func (c *GinClient) MongoQuery(ctx context.Context) *mongo.Collection { - return c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName) -} - // MongoDelete 删除 func (c *GinClient) MongoDelete(ctx context.Context, hour int64) (*mongo.DeleteResult, error) { filter := bson.D{{"log_time", bson.D{{"$lt", primitive.NewDateTimeFromTime(gotime.Current().BeforeHour(hour).Time)}}}} return c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).DeleteMany(ctx, filter) } - -// MongoMiddleware 中间件 -func (c *GinClient) MongoMiddleware() gin.HandlerFunc { - return func(ginCtx *gin.Context) { - - // 开始时间 - startTime := gotime.Current().TimestampWithMillisecond() - requestTime := gotime.Current().Time - - // 获取 - data, _ := ioutil.ReadAll(ginCtx.Request.Body) - - if c.logDebug { - c.zapLog.WithLogger().Sugar().Infof("[golog.gin.MongoMiddleware] %s", data) - } - - // 复用 - ginCtx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) - - blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: ginCtx.Writer} - ginCtx.Writer = blw - - // 处理请求 - ginCtx.Next() - - // 响应 - responseCode := ginCtx.Writer.Status() - responseBody := blw.body.String() - - //结束时间 - endTime := gotime.Current().TimestampWithMillisecond() - - go func() { - - var dataJson = true - - // 解析请求内容 - var jsonBody map[string]interface{} - - // 判断是否有内容 - if len(data) > 0 { - err := json.Unmarshal(data, &jsonBody) - if err != nil { - dataJson = false - } - } - - clientIp := gorequest.ClientIp(ginCtx.Request) - - requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp := "", "", "", "", "" - if c.ipService != nil { - if net.ParseIP(clientIp).To4() != nil { - // IPv4 - _, info := c.ipService.Ipv4(clientIp) - requestClientIpCountry = info.Country - requestClientIpRegion = info.Region - requestClientIpProvince = info.Province - requestClientIpCity = info.City - requestClientIpIsp = info.ISP - } else if net.ParseIP(clientIp).To16() != nil { - // IPv6 - info := c.ipService.Ipv6(clientIp) - requestClientIpCountry = info.Country - requestClientIpProvince = info.Province - requestClientIpCity = info.City - } - } - - // 记录 - if c.mongoClient != nil && c.mongoClient.Db != nil { - - var traceId = gotrace_id.GetGinTraceId(ginCtx) - - if dataJson { - if c.logDebug { - c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.MongoMiddleware]准备使用{mongoRecordJson}保存数据:%s", data) - } - c.mongoRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp) - } else { - if c.logDebug { - c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.MongoMiddleware]准备使用{mongoRecordXml}保存数据:%s", data) - } - c.mongoRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpRegion, requestClientIpProvince, requestClientIpCity, requestClientIpIsp) - } - } - }() - } -} diff --git a/vendor/golang.org/x/net/http2/h2c/h2c.go b/vendor/golang.org/x/net/http2/h2c/h2c.go index c3df711..2b77ffd 100644 --- a/vendor/golang.org/x/net/http2/h2c/h2c.go +++ b/vendor/golang.org/x/net/http2/h2c/h2c.go @@ -70,6 +70,15 @@ func NewHandler(h http.Handler, s *http2.Server) http.Handler { } } +// extractServer extracts existing http.Server instance from http.Request or create an empty http.Server +func extractServer(r *http.Request) *http.Server { + server, ok := r.Context().Value(http.ServerContextKey).(*http.Server) + if ok { + return server + } + return new(http.Server) +} + // ServeHTTP implement the h2c support that is enabled by h2c.GetH2CHandler. func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Handle h2c with prior knowledge (RFC 7540 Section 3.4) @@ -87,6 +96,7 @@ func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer conn.Close() s.s.ServeConn(conn, &http2.ServeConnOpts{ Context: r.Context(), + BaseConfig: extractServer(r), Handler: s.Handler, SawClientPreface: true, }) @@ -104,6 +114,7 @@ func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer conn.Close() s.s.ServeConn(conn, &http2.ServeConnOpts{ Context: r.Context(), + BaseConfig: extractServer(r), Handler: s.Handler, UpgradeRequest: r, Settings: settings, diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go index fd873b9..d2e52f3 100644 --- a/vendor/golang.org/x/net/http2/server.go +++ b/vendor/golang.org/x/net/http2/server.go @@ -2099,12 +2099,6 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol)) } - bodyOpen := !f.StreamEnded() - if rp.method == "HEAD" && bodyOpen { - // HEAD requests can't have bodies - return nil, nil, sc.countError("head_body", streamError(f.StreamID, ErrCodeProtocol)) - } - rp.header = make(http.Header) for _, hf := range f.RegularFields() { rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value) @@ -2117,6 +2111,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res if err != nil { return nil, nil, err } + bodyOpen := !f.StreamEnded() if bodyOpen { if vv, ok := rp.header["Content-Length"]; ok { if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil { diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh index 3b2335d..1b2b424 100644 --- a/vendor/golang.org/x/sys/unix/mkall.sh +++ b/vendor/golang.org/x/sys/unix/mkall.sh @@ -214,11 +214,6 @@ esac if [ "$GOOSARCH" == "aix_ppc64" ]; then # aix/ppc64 script generates files instead of writing to stdin. echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ; - elif [ "$GOOS" == "darwin" ]; then - # 1.12 and later, syscalls via libSystem - echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; - # 1.13 and later, syscalls via libSystem (including syscallPtr) - echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go"; elif [ "$GOOS" == "illumos" ]; then # illumos code generation requires a --illumos switch echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go"; diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go b/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go deleted file mode 100644 index b009860..0000000 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && go1.12 && !go1.13 -// +build darwin,go1.12,!go1.13 - -package unix - -import ( - "unsafe" -) - -const _SYS_GETDIRENTRIES64 = 344 - -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - // To implement this using libSystem we'd need syscall_syscallPtr for - // fdopendir. However, syscallPtr was only added in Go 1.13, so we fall - // back to raw syscalls for this func on Go 1.12. - var p unsafe.Pointer - if len(buf) > 0 { - p = unsafe.Pointer(&buf[0]) - } else { - p = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(_SYS_GETDIRENTRIES64, uintptr(fd), uintptr(p), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) - n = int(r0) - if e1 != 0 { - return n, errnoErr(e1) - } - return n, nil -} diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go b/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go deleted file mode 100644 index 1259f6d..0000000 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && go1.13 -// +build darwin,go1.13 - -package unix - -import "unsafe" - -//sys closedir(dir uintptr) (err error) -//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) - -func fdopendir(fd int) (dir uintptr, err error) { - r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0) - dir = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_fdopendir_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib" - -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - // Simulate Getdirentries using fdopendir/readdir_r/closedir. - // We store the number of entries to skip in the seek - // offset of fd. See issue #31368. - // It's not the full required semantics, but should handle the case - // of calling Getdirentries or ReadDirent repeatedly. - // It won't handle assigning the results of lseek to *basep, or handle - // the directory being edited underfoot. - skip, err := Seek(fd, 0, 1 /* SEEK_CUR */) - if err != nil { - return 0, err - } - - // We need to duplicate the incoming file descriptor - // because the caller expects to retain control of it, but - // fdopendir expects to take control of its argument. - // Just Dup'ing the file descriptor is not enough, as the - // result shares underlying state. Use Openat to make a really - // new file descriptor referring to the same directory. - fd2, err := Openat(fd, ".", O_RDONLY, 0) - if err != nil { - return 0, err - } - d, err := fdopendir(fd2) - if err != nil { - Close(fd2) - return 0, err - } - defer closedir(d) - - var cnt int64 - for { - var entry Dirent - var entryp *Dirent - e := readdir_r(d, &entry, &entryp) - if e != 0 { - return n, errnoErr(e) - } - if entryp == nil { - break - } - if skip > 0 { - skip-- - cnt++ - continue - } - - reclen := int(entry.Reclen) - if reclen > len(buf) { - // Not enough room. Return for now. - // The counter will let us know where we should start up again. - // Note: this strategy for suspending in the middle and - // restarting is O(n^2) in the length of the directory. Oh well. - break - } - - // Copy entry into return buffer. - s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen) - copy(buf, s) - - buf = buf[reclen:] - n += reclen - cnt++ - } - // Set the seek offset of the input fd to record - // how many files we've already returned. - _, err = Seek(fd, cnt, 0 /* SEEK_SET */) - if err != nil { - return n, err - } - - return n, nil -} diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 4f87f16..1f63382 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -19,6 +19,96 @@ import ( "unsafe" ) +//sys closedir(dir uintptr) (err error) +//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) + +func fdopendir(fd int) (dir uintptr, err error) { + r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0) + dir = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fdopendir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib" + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + // Simulate Getdirentries using fdopendir/readdir_r/closedir. + // We store the number of entries to skip in the seek + // offset of fd. See issue #31368. + // It's not the full required semantics, but should handle the case + // of calling Getdirentries or ReadDirent repeatedly. + // It won't handle assigning the results of lseek to *basep, or handle + // the directory being edited underfoot. + skip, err := Seek(fd, 0, 1 /* SEEK_CUR */) + if err != nil { + return 0, err + } + + // We need to duplicate the incoming file descriptor + // because the caller expects to retain control of it, but + // fdopendir expects to take control of its argument. + // Just Dup'ing the file descriptor is not enough, as the + // result shares underlying state. Use Openat to make a really + // new file descriptor referring to the same directory. + fd2, err := Openat(fd, ".", O_RDONLY, 0) + if err != nil { + return 0, err + } + d, err := fdopendir(fd2) + if err != nil { + Close(fd2) + return 0, err + } + defer closedir(d) + + var cnt int64 + for { + var entry Dirent + var entryp *Dirent + e := readdir_r(d, &entry, &entryp) + if e != 0 { + return n, errnoErr(e) + } + if entryp == nil { + break + } + if skip > 0 { + skip-- + cnt++ + continue + } + + reclen := int(entry.Reclen) + if reclen > len(buf) { + // Not enough room. Return for now. + // The counter will let us know where we should start up again. + // Note: this strategy for suspending in the middle and + // restarting is O(n^2) in the length of the directory. Oh well. + break + } + + // Copy entry into return buffer. + s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen) + copy(buf, s) + + buf = buf[reclen:] + n += reclen + cnt++ + } + // Set the seek offset of the input fd to record + // how many files we've already returned. + _, err = Seek(fd, cnt, 0 /* SEEK_SET */) + if err != nil { + return n, err + } + + return n, nil +} + // SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. type SockaddrDatalink struct { Len uint8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go deleted file mode 100644 index a06eb09..0000000 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go +++ /dev/null @@ -1,40 +0,0 @@ -// go run mksyscall.go -tags darwin,amd64,go1.13 syscall_darwin.1_13.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build darwin && amd64 && go1.13 -// +build darwin,amd64,go1.13 - -package unix - -import ( - "syscall" - "unsafe" -) - -var _ syscall.Errno - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func closedir(dir uintptr) (err error) { - _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_closedir_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { - r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) - res = Errno(r0) - return -} - -var libc_readdir_r_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s deleted file mode 100644 index f5bb40e..0000000 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s +++ /dev/null @@ -1,25 +0,0 @@ -// go run mkasm.go darwin amd64 -// Code generated by the command above; DO NOT EDIT. - -//go:build go1.13 -// +build go1.13 - -#include "textflag.h" - -TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_fdopendir(SB) - -GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 -DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) - -TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_closedir(SB) - -GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 -DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) - -TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_readdir_r(SB) - -GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 -DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index 467deed..c2461c4 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -1,8 +1,8 @@ -// go run mksyscall.go -tags darwin,amd64,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go +// go run mksyscall.go -tags darwin,amd64 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. -//go:build darwin && amd64 && go1.12 -// +build darwin,amd64,go1.12 +//go:build darwin && amd64 +// +build darwin,amd64 package unix @@ -463,6 +463,32 @@ var libc_munlockall_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func closedir(dir uintptr) (err error) { + _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_closedir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { + r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) + res = Errno(r0) + return +} + +var libc_readdir_r_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]int32) (err error) { _, _, e1 := syscall_rawSyscall(libc_pipe_trampoline_addr, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index b41467a..95fe4c0 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -1,11 +1,14 @@ // go run mkasm.go darwin amd64 // Code generated by the command above; DO NOT EDIT. -//go:build go1.12 -// +build go1.12 - #include "textflag.h" +TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fdopendir(SB) + +GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) + TEXT libc_getgroups_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) @@ -174,6 +177,18 @@ TEXT libc_munlockall_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_munlockall_trampoline_addr(SB), RODATA, $8 DATA ·libc_munlockall_trampoline_addr(SB)/8, $libc_munlockall_trampoline<>(SB) +TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_closedir(SB) + +GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) + +TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readdir_r(SB) + +GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) + TEXT libc_pipe_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pipe(SB) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go deleted file mode 100644 index cec595d..0000000 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go +++ /dev/null @@ -1,40 +0,0 @@ -// go run mksyscall.go -tags darwin,arm64,go1.13 syscall_darwin.1_13.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build darwin && arm64 && go1.13 -// +build darwin,arm64,go1.13 - -package unix - -import ( - "syscall" - "unsafe" -) - -var _ syscall.Errno - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func closedir(dir uintptr) (err error) { - _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_closedir_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { - r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) - res = Errno(r0) - return -} - -var libc_readdir_r_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s deleted file mode 100644 index 0c3f76b..0000000 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s +++ /dev/null @@ -1,25 +0,0 @@ -// go run mkasm.go darwin arm64 -// Code generated by the command above; DO NOT EDIT. - -//go:build go1.13 -// +build go1.13 - -#include "textflag.h" - -TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_fdopendir(SB) - -GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 -DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) - -TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_closedir(SB) - -GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 -DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) - -TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_readdir_r(SB) - -GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 -DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index 35938d3..26a0fdc 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -1,8 +1,8 @@ -// go run mksyscall.go -tags darwin,arm64,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go +// go run mksyscall.go -tags darwin,arm64 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go // Code generated by the command above; see README.md. DO NOT EDIT. -//go:build darwin && arm64 && go1.12 -// +build darwin,arm64,go1.12 +//go:build darwin && arm64 +// +build darwin,arm64 package unix @@ -463,6 +463,32 @@ var libc_munlockall_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func closedir(dir uintptr) (err error) { + _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_closedir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { + r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) + res = Errno(r0) + return +} + +var libc_readdir_r_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]int32) (err error) { _, _, e1 := syscall_rawSyscall(libc_pipe_trampoline_addr, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index e1f9204..efa5b4c 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -1,11 +1,14 @@ // go run mkasm.go darwin arm64 // Code generated by the command above; DO NOT EDIT. -//go:build go1.12 -// +build go1.12 - #include "textflag.h" +TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fdopendir(SB) + +GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) + TEXT libc_getgroups_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) @@ -174,6 +177,18 @@ TEXT libc_munlockall_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_munlockall_trampoline_addr(SB), RODATA, $8 DATA ·libc_munlockall_trampoline_addr(SB)/8, $libc_munlockall_trampoline<>(SB) +TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_closedir(SB) + +GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) + +TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readdir_r(SB) + +GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) + TEXT libc_pipe_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pipe(SB) diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 29737b2..3f2cbb6 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -442,6 +442,10 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys RtlAddFunctionTable(functionTable *RUNTIME_FUNCTION, entryCount uint32, baseAddress uintptr) (ret bool) = ntdll.RtlAddFunctionTable //sys RtlDeleteFunctionTable(functionTable *RUNTIME_FUNCTION) (ret bool) = ntdll.RtlDeleteFunctionTable +// Desktop Window Manager API (Dwmapi) +//sys DwmGetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) = dwmapi.DwmGetWindowAttribute +//sys DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) = dwmapi.DwmSetWindowAttribute + // syscall interface implementation for other packages // GetCurrentProcess returns the handle for the current process. diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index ef489f5..0c4add9 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -3232,3 +3232,29 @@ type GUIThreadInfo struct { CaretHandle HWND CaretRect Rect } + +const ( + DWMWA_NCRENDERING_ENABLED = 1 + DWMWA_NCRENDERING_POLICY = 2 + DWMWA_TRANSITIONS_FORCEDISABLED = 3 + DWMWA_ALLOW_NCPAINT = 4 + DWMWA_CAPTION_BUTTON_BOUNDS = 5 + DWMWA_NONCLIENT_RTL_LAYOUT = 6 + DWMWA_FORCE_ICONIC_REPRESENTATION = 7 + DWMWA_FLIP3D_POLICY = 8 + DWMWA_EXTENDED_FRAME_BOUNDS = 9 + DWMWA_HAS_ICONIC_BITMAP = 10 + DWMWA_DISALLOW_PEEK = 11 + DWMWA_EXCLUDED_FROM_PEEK = 12 + DWMWA_CLOAK = 13 + DWMWA_CLOAKED = 14 + DWMWA_FREEZE_REPRESENTATION = 15 + DWMWA_PASSIVE_UPDATE_MODE = 16 + DWMWA_USE_HOSTBACKDROPBRUSH = 17 + DWMWA_USE_IMMERSIVE_DARK_MODE = 20 + DWMWA_WINDOW_CORNER_PREFERENCE = 33 + DWMWA_BORDER_COLOR = 34 + DWMWA_CAPTION_COLOR = 35 + DWMWA_TEXT_COLOR = 36 + DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37 +) diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 6c6f27b..96ba855 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -40,6 +40,7 @@ var ( modadvapi32 = NewLazySystemDLL("advapi32.dll") modcrypt32 = NewLazySystemDLL("crypt32.dll") moddnsapi = NewLazySystemDLL("dnsapi.dll") + moddwmapi = NewLazySystemDLL("dwmapi.dll") modiphlpapi = NewLazySystemDLL("iphlpapi.dll") modkernel32 = NewLazySystemDLL("kernel32.dll") modmswsock = NewLazySystemDLL("mswsock.dll") @@ -175,6 +176,8 @@ var ( procDnsNameCompare_W = moddnsapi.NewProc("DnsNameCompare_W") procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W") procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree") + procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute") + procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute") procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo") procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx") @@ -1534,6 +1537,22 @@ func DnsRecordListFree(rl *DNSRecord, freetype uint32) { return } +func DwmGetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) { + r0, _, _ := syscall.Syscall6(procDwmGetWindowAttribute.Addr(), 4, uintptr(hwnd), uintptr(attribute), uintptr(value), uintptr(size), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + +func DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) { + r0, _, _ := syscall.Syscall6(procDwmSetWindowAttribute.Addr(), 4, uintptr(hwnd), uintptr(attribute), uintptr(value), uintptr(size), 0, 0) + if r0 != 0 { + ret = syscall.Errno(r0) + } + return +} + func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) if r0 != 0 { diff --git a/vendor/gorm.io/driver/postgres/migrator.go b/vendor/gorm.io/driver/postgres/migrator.go index 5eb0acc..9877d7c 100644 --- a/vendor/gorm.io/driver/postgres/migrator.go +++ b/vendor/gorm.io/driver/postgres/migrator.go @@ -436,14 +436,25 @@ func (m Migrator) ColumnTypes(value interface{}) (columnTypes []gorm.ColumnType, // check primary, unique field { - columnTypeRows, err := m.DB.Raw("SELECT c.column_name, constraint_type FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = ? AND c.table_schema = ? AND c.table_name = ?", currentDatabase, currentSchema, table).Rows() + columnTypeRows, err := m.DB.Raw("SELECT constraint_name FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = ? AND c.table_schema = ? AND c.table_name = ? AND constraint_type = ?", currentDatabase, currentSchema, table, "UNIQUE").Rows() if err != nil { return err } + uniqueContraints := map[string]int{} + for columnTypeRows.Next() { + var constraintName string + columnTypeRows.Scan(&constraintName) + uniqueContraints[constraintName]++ + } + columnTypeRows.Close() + columnTypeRows, err = m.DB.Raw("SELECT c.column_name, constraint_name, constraint_type FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage AS ccu USING (constraint_schema, constraint_name) JOIN information_schema.columns AS c ON c.table_schema = tc.constraint_schema AND tc.table_name = c.table_name AND ccu.column_name = c.column_name WHERE constraint_type IN ('PRIMARY KEY', 'UNIQUE') AND c.table_catalog = ? AND c.table_schema = ? AND c.table_name = ?", currentDatabase, currentSchema, table).Rows() + if err != nil { + return err + } for columnTypeRows.Next() { - var name, columnType string - columnTypeRows.Scan(&name, &columnType) + var name, constraintName, columnType string + columnTypeRows.Scan(&name, &constraintName, &columnType) for _, c := range columnTypes { mc := c.(*migrator.ColumnType) if mc.NameValue.String == name { @@ -451,7 +462,9 @@ func (m Migrator) ColumnTypes(value interface{}) (columnTypes []gorm.ColumnType, case "PRIMARY KEY": mc.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true} case "UNIQUE": - mc.UniqueValue = sql.NullBool{Bool: true, Valid: true} + if uniqueContraints[constraintName] == 1 { + mc.UniqueValue = sql.NullBool{Bool: true, Valid: true} + } } break } @@ -463,7 +476,7 @@ func (m Migrator) ColumnTypes(value interface{}) (columnTypes []gorm.ColumnType, // check column type { dataTypeRows, err := m.DB.Raw(`SELECT a.attname as column_name, format_type(a.atttypid, a.atttypmod) AS data_type - FROM pg_attribute a JOIN pg_class b ON a.attrelid = b.relfilenode AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = ?) + FROM pg_attribute a JOIN pg_class b ON a.attrelid = b.oid AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = ?) WHERE a.attnum > 0 -- hide internal columns AND NOT a.attisdropped -- hide deleted columns AND b.relname = ?`, currentSchema, table).Rows() diff --git a/vendor/gorm.io/gorm/.gitignore b/vendor/gorm.io/gorm/.gitignore index 45505cc..7273332 100644 --- a/vendor/gorm.io/gorm/.gitignore +++ b/vendor/gorm.io/gorm/.gitignore @@ -3,4 +3,5 @@ documents coverage.txt _book .idea -vendor \ No newline at end of file +vendor +.vscode diff --git a/vendor/gorm.io/gorm/association.go b/vendor/gorm.io/gorm/association.go index 35e10dd..06229ca 100644 --- a/vendor/gorm.io/gorm/association.go +++ b/vendor/gorm.io/gorm/association.go @@ -507,7 +507,9 @@ func (association *Association) buildCondition() *DB { joinStmt.AddClause(queryClause) } joinStmt.Build("WHERE") - tx.Clauses(clause.Expr{SQL: strings.Replace(joinStmt.SQL.String(), "WHERE ", "", 1), Vars: joinStmt.Vars}) + if len(joinStmt.SQL.String()) > 0 { + tx.Clauses(clause.Expr{SQL: strings.Replace(joinStmt.SQL.String(), "WHERE ", "", 1), Vars: joinStmt.Vars}) + } } tx = tx.Session(&Session{QueryFields: true}).Clauses(clause.From{Joins: []clause.Join{{ diff --git a/vendor/gorm.io/gorm/callbacks/associations.go b/vendor/gorm.io/gorm/callbacks/associations.go index 4a50e6c..00e00fc 100644 --- a/vendor/gorm.io/gorm/callbacks/associations.go +++ b/vendor/gorm.io/gorm/callbacks/associations.go @@ -206,7 +206,7 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) { } } - cacheKey := utils.ToStringKey(relPrimaryValues) + cacheKey := utils.ToStringKey(relPrimaryValues...) if len(relPrimaryValues) != len(rel.FieldSchema.PrimaryFields) || !identityMap[cacheKey] { identityMap[cacheKey] = true if isPtr { @@ -292,7 +292,7 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) { } } - cacheKey := utils.ToStringKey(relPrimaryValues) + cacheKey := utils.ToStringKey(relPrimaryValues...) if len(relPrimaryValues) != len(rel.FieldSchema.PrimaryFields) || !identityMap[cacheKey] { identityMap[cacheKey] = true distinctElems = reflect.Append(distinctElems, elem) diff --git a/vendor/gorm.io/gorm/callbacks/update.go b/vendor/gorm.io/gorm/callbacks/update.go index 42ffe2f..b596df9 100644 --- a/vendor/gorm.io/gorm/callbacks/update.go +++ b/vendor/gorm.io/gorm/callbacks/update.go @@ -70,10 +70,12 @@ func Update(config *Config) func(db *gorm.DB) { if db.Statement.SQL.Len() == 0 { db.Statement.SQL.Grow(180) db.Statement.AddClauseIfNotExists(clause.Update{}) - if set := ConvertToAssignments(db.Statement); len(set) != 0 { - db.Statement.AddClause(set) - } else if _, ok := db.Statement.Clauses["SET"]; !ok { - return + if _, ok := db.Statement.Clauses["SET"]; !ok { + if set := ConvertToAssignments(db.Statement); len(set) != 0 { + db.Statement.AddClause(set) + } else { + return + } } db.Statement.Build(db.Statement.BuildClauses...) @@ -158,21 +160,21 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) { switch stmt.ReflectValue.Kind() { case reflect.Slice, reflect.Array: if size := stmt.ReflectValue.Len(); size > 0 { - var primaryKeyExprs []clause.Expression + var isZero bool for i := 0; i < size; i++ { - exprs := make([]clause.Expression, len(stmt.Schema.PrimaryFields)) - var notZero bool - for idx, field := range stmt.Schema.PrimaryFields { - value, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue.Index(i)) - exprs[idx] = clause.Eq{Column: field.DBName, Value: value} - notZero = notZero || !isZero - } - if notZero { - primaryKeyExprs = append(primaryKeyExprs, clause.And(exprs...)) + for _, field := range stmt.Schema.PrimaryFields { + _, isZero = field.ValueOf(stmt.Context, stmt.ReflectValue.Index(i)) + if !isZero { + break + } } } - stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.And(clause.Or(primaryKeyExprs...))}}) + if !isZero { + _, primaryValues := schema.GetIdentityFieldValuesMap(stmt.Context, stmt.ReflectValue, stmt.Schema.PrimaryFields) + column, values := schema.ToQueryValues("", stmt.Schema.PrimaryFieldDBNames, primaryValues) + stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}}) + } } case reflect.Struct: for _, field := range stmt.Schema.PrimaryFields { diff --git a/vendor/gorm.io/gorm/finisher_api.go b/vendor/gorm.io/gorm/finisher_api.go index 7a3f27b..835a698 100644 --- a/vendor/gorm.io/gorm/finisher_api.go +++ b/vendor/gorm.io/gorm/finisher_api.go @@ -13,7 +13,7 @@ import ( "gorm.io/gorm/utils" ) -// Create insert the value into database +// Create inserts value, returning the inserted data's primary key in value's id func (db *DB) Create(value interface{}) (tx *DB) { if db.CreateBatchSize > 0 { return db.CreateInBatches(value, db.CreateBatchSize) @@ -24,7 +24,7 @@ func (db *DB) Create(value interface{}) (tx *DB) { return tx.callbacks.Create().Execute(tx) } -// CreateInBatches insert the value in batches into database +// CreateInBatches inserts value in batches of batchSize func (db *DB) CreateInBatches(value interface{}, batchSize int) (tx *DB) { reflectValue := reflect.Indirect(reflect.ValueOf(value)) @@ -68,7 +68,7 @@ func (db *DB) CreateInBatches(value interface{}, batchSize int) (tx *DB) { return } -// Save update value in database, if the value doesn't have primary key, will insert it +// Save updates value in database. If value doesn't contain a matching primary key, value is inserted. func (db *DB) Save(value interface{}) (tx *DB) { tx = db.getInstance() tx.Statement.Dest = value @@ -114,7 +114,7 @@ func (db *DB) Save(value interface{}) (tx *DB) { return } -// First find first record that match given conditions, order by primary key +// First finds the first record ordered by primary key, matching given conditions conds func (db *DB) First(dest interface{}, conds ...interface{}) (tx *DB) { tx = db.Limit(1).Order(clause.OrderByColumn{ Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, @@ -129,7 +129,7 @@ func (db *DB) First(dest interface{}, conds ...interface{}) (tx *DB) { return tx.callbacks.Query().Execute(tx) } -// Take return a record that match given conditions, the order will depend on the database implementation +// Take finds the first record returned by the database in no specified order, matching given conditions conds func (db *DB) Take(dest interface{}, conds ...interface{}) (tx *DB) { tx = db.Limit(1) if len(conds) > 0 { @@ -142,7 +142,7 @@ func (db *DB) Take(dest interface{}, conds ...interface{}) (tx *DB) { return tx.callbacks.Query().Execute(tx) } -// Last find last record that match given conditions, order by primary key +// Last finds the last record ordered by primary key, matching given conditions conds func (db *DB) Last(dest interface{}, conds ...interface{}) (tx *DB) { tx = db.Limit(1).Order(clause.OrderByColumn{ Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, @@ -158,7 +158,7 @@ func (db *DB) Last(dest interface{}, conds ...interface{}) (tx *DB) { return tx.callbacks.Query().Execute(tx) } -// Find find records that match given conditions +// Find finds all records matching given conditions conds func (db *DB) Find(dest interface{}, conds ...interface{}) (tx *DB) { tx = db.getInstance() if len(conds) > 0 { @@ -170,7 +170,7 @@ func (db *DB) Find(dest interface{}, conds ...interface{}) (tx *DB) { return tx.callbacks.Query().Execute(tx) } -// FindInBatches find records in batches +// FindInBatches finds all records in batches of batchSize func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, batch int) error) *DB { var ( tx = db.Order(clause.OrderByColumn{ @@ -202,7 +202,9 @@ func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, bat batch++ if result.Error == nil && result.RowsAffected != 0 { - tx.AddError(fc(result, batch)) + fcTx := result.Session(&Session{NewDB: true}) + fcTx.RowsAffected = result.RowsAffected + tx.AddError(fc(fcTx, batch)) } else if result.Error != nil { tx.AddError(result.Error) } @@ -284,7 +286,8 @@ func (db *DB) assignInterfacesToValue(values ...interface{}) { } } -// FirstOrInit gets the first matched record or initialize a new instance with given conditions (only works with struct or map conditions) +// FirstOrInit finds the first matching record, otherwise if not found initializes a new instance with given conds. +// Each conds must be a struct or map. func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB) { queryTx := db.Limit(1).Order(clause.OrderByColumn{ Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, @@ -310,7 +313,8 @@ func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB) { return } -// FirstOrCreate gets the first matched record or create a new one with given conditions (only works with struct, map conditions) +// FirstOrCreate finds the first matching record, otherwise if not found creates a new instance with given conds. +// Each conds must be a struct or map. func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) (tx *DB) { tx = db.getInstance() queryTx := db.Session(&Session{}).Limit(1).Order(clause.OrderByColumn{ @@ -358,14 +362,14 @@ func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) (tx *DB) { return tx } -// Update update attributes with callbacks, refer: https://gorm.io/docs/update.html#Update-Changed-Fields +// Update updates column with value using callbacks. Reference: https://gorm.io/docs/update.html#Update-Changed-Fields func (db *DB) Update(column string, value interface{}) (tx *DB) { tx = db.getInstance() tx.Statement.Dest = map[string]interface{}{column: value} return tx.callbacks.Update().Execute(tx) } -// Updates update attributes with callbacks, refer: https://gorm.io/docs/update.html#Update-Changed-Fields +// Updates updates attributes using callbacks. values must be a struct or map. Reference: https://gorm.io/docs/update.html#Update-Changed-Fields func (db *DB) Updates(values interface{}) (tx *DB) { tx = db.getInstance() tx.Statement.Dest = values @@ -386,7 +390,9 @@ func (db *DB) UpdateColumns(values interface{}) (tx *DB) { return tx.callbacks.Update().Execute(tx) } -// Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition +// Delete deletes value matching given conditions. If value contains primary key it is included in the conditions. If +// value includes a deleted_at field, then Delete performs a soft delete instead by setting deleted_at with the current +// time if null. func (db *DB) Delete(value interface{}, conds ...interface{}) (tx *DB) { tx = db.getInstance() if len(conds) > 0 { @@ -480,7 +486,7 @@ func (db *DB) Rows() (*sql.Rows, error) { return rows, tx.Error } -// Scan scan value to a struct +// Scan scans selected value to the struct dest func (db *DB) Scan(dest interface{}) (tx *DB) { config := *db.Config currentLogger, newLogger := config.Logger, logger.Recorder.New() @@ -505,7 +511,7 @@ func (db *DB) Scan(dest interface{}) (tx *DB) { return } -// Pluck used to query single column from a model as a map +// Pluck queries a single column from a model, returning in the slice dest. E.g.: // var ages []int64 // db.Model(&users).Pluck("age", &ages) func (db *DB) Pluck(column string, dest interface{}) (tx *DB) { @@ -548,7 +554,8 @@ func (db *DB) ScanRows(rows *sql.Rows, dest interface{}) error { return tx.Error } -// Connection use a db conn to execute Multiple commands,this conn will put conn pool after it is executed. +// Connection uses a db connection to execute an arbitrary number of commands in fc. When finished, the connection is +// returned to the connection pool. func (db *DB) Connection(fc func(tx *DB) error) (err error) { if db.Error != nil { return db.Error @@ -570,7 +577,9 @@ func (db *DB) Connection(fc func(tx *DB) error) (err error) { return fc(tx) } -// Transaction start a transaction as a block, return error will rollback, otherwise to commit. +// Transaction start a transaction as a block, return error will rollback, otherwise to commit. Transaction executes an +// arbitrary number of commands in fc within a transaction. On success the changes are committed; if an error occurs +// they are rolled back. func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) { panicked := true @@ -613,7 +622,7 @@ func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err er return } -// Begin begins a transaction +// Begin begins a transaction with any transaction options opts func (db *DB) Begin(opts ...*sql.TxOptions) *DB { var ( // clone statement @@ -642,7 +651,7 @@ func (db *DB) Begin(opts ...*sql.TxOptions) *DB { return tx } -// Commit commit a transaction +// Commit commits the changes in a transaction func (db *DB) Commit() *DB { if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil && !reflect.ValueOf(committer).IsNil() { db.AddError(committer.Commit()) @@ -652,7 +661,7 @@ func (db *DB) Commit() *DB { return db } -// Rollback rollback a transaction +// Rollback rollbacks the changes in a transaction func (db *DB) Rollback() *DB { if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil { if !reflect.ValueOf(committer).IsNil() { @@ -682,7 +691,7 @@ func (db *DB) RollbackTo(name string) *DB { return db } -// Exec execute raw sql +// Exec executes raw sql func (db *DB) Exec(sql string, values ...interface{}) (tx *DB) { tx = db.getInstance() tx.Statement.SQL = strings.Builder{} diff --git a/vendor/gorm.io/gorm/gorm.go b/vendor/gorm.io/gorm/gorm.go index 6a6bb03..1f1dac2 100644 --- a/vendor/gorm.io/gorm/gorm.go +++ b/vendor/gorm.io/gorm/gorm.go @@ -300,7 +300,8 @@ func (db *DB) WithContext(ctx context.Context) *DB { // Debug start debug mode func (db *DB) Debug() (tx *DB) { - return db.Session(&Session{ + tx = db.getInstance() + return tx.Session(&Session{ Logger: db.Logger.LogMode(logger.Info), }) } @@ -412,7 +413,7 @@ func (db *DB) SetupJoinTable(model interface{}, field string, joinTable interfac relation, ok := modelSchema.Relationships.Relations[field] isRelation := ok && relation.JoinTable != nil if !isRelation { - return fmt.Errorf("failed to found relation: %s", field) + return fmt.Errorf("failed to find relation: %s", field) } for _, ref := range relation.References { diff --git a/vendor/gorm.io/gorm/logger/logger.go b/vendor/gorm.io/gorm/logger/logger.go index 2ffd28d..ce08856 100644 --- a/vendor/gorm.io/gorm/logger/logger.go +++ b/vendor/gorm.io/gorm/logger/logger.go @@ -4,7 +4,7 @@ import ( "context" "errors" "fmt" - "io/ioutil" + "io" "log" "os" "time" @@ -68,8 +68,8 @@ type Interface interface { } var ( - // Discard Discard logger will print any log to ioutil.Discard - Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), Config{}) + // Discard Discard logger will print any log to io.Discard + Discard = New(log.New(io.Discard, "", log.LstdFlags), Config{}) // Default Default logger Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), Config{ SlowThreshold: 200 * time.Millisecond, diff --git a/vendor/gorm.io/gorm/logger/sql.go b/vendor/gorm.io/gorm/logger/sql.go index c8b194c..bcacc7c 100644 --- a/vendor/gorm.io/gorm/logger/sql.go +++ b/vendor/gorm.io/gorm/logger/sql.go @@ -30,6 +30,8 @@ func isPrintable(s string) bool { var convertibleTypes = []reflect.Type{reflect.TypeOf(time.Time{}), reflect.TypeOf(false), reflect.TypeOf([]byte{})} +var numericPlaceholderRe = regexp.MustCompile(`\$\d+\$`) + // ExplainSQL generate SQL string with given parameters, the generated SQL is expected to be used in logger, execute it might introduce a SQL injection vulnerability func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, avars ...interface{}) string { var ( @@ -138,9 +140,18 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a sql = newSQL.String() } else { sql = numericPlaceholder.ReplaceAllString(sql, "$$$1$$") - for idx, v := range vars { - sql = strings.Replace(sql, "$"+strconv.Itoa(idx+1)+"$", v, 1) - } + + sql = numericPlaceholderRe.ReplaceAllStringFunc(sql, func(v string) string { + num := v[1 : len(v)-1] + n, _ := strconv.Atoi(num) + + // position var start from 1 ($1, $2) + n -= 1 + if n >= 0 && n <= len(vars)-1 { + return vars[n] + } + return v + }) } return sql diff --git a/vendor/gorm.io/gorm/migrator/migrator.go b/vendor/gorm.io/gorm/migrator/migrator.go index 87ac774..e6782a1 100644 --- a/vendor/gorm.io/gorm/migrator/migrator.go +++ b/vendor/gorm.io/gorm/migrator/migrator.go @@ -15,7 +15,7 @@ import ( ) var ( - regFullDataType = regexp.MustCompile(`[^\d]*(\d+)[^\d]?`) + regFullDataType = regexp.MustCompile(`\D*(\d+)\D?`) ) // Migrator m struct @@ -135,12 +135,12 @@ func (m Migrator) AutoMigrate(values ...interface{}) error { } } } + } - for _, chk := range stmt.Schema.ParseCheckConstraints() { - if !tx.Migrator().HasConstraint(value, chk.Name) { - if err := tx.Migrator().CreateConstraint(value, chk.Name); err != nil { - return err - } + for _, chk := range stmt.Schema.ParseCheckConstraints() { + if !tx.Migrator().HasConstraint(value, chk.Name) { + if err := tx.Migrator().CreateConstraint(value, chk.Name); err != nil { + return err } } } diff --git a/vendor/gorm.io/gorm/scan.go b/vendor/gorm.io/gorm/scan.go index 6250fb5..2db4316 100644 --- a/vendor/gorm.io/gorm/scan.go +++ b/vendor/gorm.io/gorm/scan.go @@ -66,30 +66,32 @@ func (db *DB) scanIntoStruct(rows Rows, reflectValue reflect.Value, values []int db.RowsAffected++ db.AddError(rows.Scan(values...)) - joinedSchemaMap := make(map[*schema.Field]interface{}, 0) + joinedSchemaMap := make(map[*schema.Field]interface{}) for idx, field := range fields { - if field != nil { - if len(joinFields) == 0 || joinFields[idx][0] == nil { - db.AddError(field.Set(db.Statement.Context, reflectValue, values[idx])) - } else { - joinSchema := joinFields[idx][0] - relValue := joinSchema.ReflectValueOf(db.Statement.Context, reflectValue) - if relValue.Kind() == reflect.Ptr { - if _, ok := joinedSchemaMap[joinSchema]; !ok { - if value := reflect.ValueOf(values[idx]).Elem(); value.Kind() == reflect.Ptr && value.IsNil() { - continue - } + if field == nil { + continue + } - relValue.Set(reflect.New(relValue.Type().Elem())) - joinedSchemaMap[joinSchema] = nil + if len(joinFields) == 0 || joinFields[idx][0] == nil { + db.AddError(field.Set(db.Statement.Context, reflectValue, values[idx])) + } else { + joinSchema := joinFields[idx][0] + relValue := joinSchema.ReflectValueOf(db.Statement.Context, reflectValue) + if relValue.Kind() == reflect.Ptr { + if _, ok := joinedSchemaMap[joinSchema]; !ok { + if value := reflect.ValueOf(values[idx]).Elem(); value.Kind() == reflect.Ptr && value.IsNil() { + continue } + + relValue.Set(reflect.New(relValue.Type().Elem())) + joinedSchemaMap[joinSchema] = nil } - db.AddError(joinFields[idx][1].Set(db.Statement.Context, relValue, values[idx])) } - - // release data to pool - field.NewValuePool.Put(values[idx]) + db.AddError(joinFields[idx][1].Set(db.Statement.Context, relValue, values[idx])) } + + // release data to pool + field.NewValuePool.Put(values[idx]) } } diff --git a/vendor/gorm.io/gorm/schema/field.go b/vendor/gorm.io/gorm/schema/field.go index d4dfbd6..1589d98 100644 --- a/vendor/gorm.io/gorm/schema/field.go +++ b/vendor/gorm.io/gorm/schema/field.go @@ -403,18 +403,14 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field { } if ef.PrimaryKey { - if val, ok := ef.TagSettings["PRIMARYKEY"]; ok && utils.CheckTruth(val) { - ef.PrimaryKey = true - } else if val, ok := ef.TagSettings["PRIMARY_KEY"]; ok && utils.CheckTruth(val) { - ef.PrimaryKey = true - } else { + if !utils.CheckTruth(ef.TagSettings["PRIMARYKEY"], ef.TagSettings["PRIMARY_KEY"]) { ef.PrimaryKey = false if val, ok := ef.TagSettings["AUTOINCREMENT"]; !ok || !utils.CheckTruth(val) { ef.AutoIncrement = false } - if ef.DefaultValue == "" { + if !ef.AutoIncrement && ef.DefaultValue == "" { ef.HasDefaultValue = false } } @@ -472,9 +468,6 @@ func (field *Field) setupValuerAndSetter() { oldValuerOf := field.ValueOf field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) { value, zero := oldValuerOf(ctx, v) - if zero { - return value, zero - } s, ok := value.(SerializerValuerInterface) if !ok { @@ -487,7 +480,7 @@ func (field *Field) setupValuerAndSetter() { Destination: v, Context: ctx, fieldValue: value, - }, false + }, zero } } diff --git a/vendor/gorm.io/gorm/schema/schema.go b/vendor/gorm.io/gorm/schema/schema.go index eca113e..3791237 100644 --- a/vendor/gorm.io/gorm/schema/schema.go +++ b/vendor/gorm.io/gorm/schema/schema.go @@ -112,7 +112,7 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam schemaCacheKey = modelType } - // Load exist schmema cache, return if exists + // Load exist schema cache, return if exists if v, ok := cacheStore.Load(schemaCacheKey); ok { s := v.(*Schema) // Wait for the initialization of other goroutines to complete @@ -146,7 +146,7 @@ func ParseWithSpecialTableName(dest interface{}, cacheStore *sync.Map, namer Nam // When the schema initialization is completed, the channel will be closed defer close(schema.initialized) - // Load exist schmema cache, return if exists + // Load exist schema cache, return if exists if v, ok := cacheStore.Load(schemaCacheKey); ok { s := v.(*Schema) // Wait for the initialization of other goroutines to complete diff --git a/vendor/gorm.io/gorm/schema/serializer.go b/vendor/gorm.io/gorm/schema/serializer.go index 758a642..00a4f85 100644 --- a/vendor/gorm.io/gorm/schema/serializer.go +++ b/vendor/gorm.io/gorm/schema/serializer.go @@ -88,7 +88,9 @@ func (JSONSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, return fmt.Errorf("failed to unmarshal JSONB value: %#v", dbValue) } - err = json.Unmarshal(bytes, fieldValue.Interface()) + if len(bytes) > 0 { + err = json.Unmarshal(bytes, fieldValue.Interface()) + } } field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem()) @@ -117,9 +119,15 @@ func (UnixSecondSerializer) Scan(ctx context.Context, field *Field, dst reflect. // Value implements serializer interface func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (result interface{}, err error) { + rv := reflect.ValueOf(fieldValue) switch v := fieldValue.(type) { - case int64, int, uint, uint64, int32, uint32, int16, uint16, *int64, *int, *uint, *uint64, *int32, *uint32, *int16, *uint16: - result = time.Unix(reflect.Indirect(reflect.ValueOf(v)).Int(), 0) + case int64, int, uint, uint64, int32, uint32, int16, uint16: + result = time.Unix(reflect.Indirect(rv).Int(), 0) + case *int64, *int, *uint, *uint64, *int32, *uint32, *int16, *uint16: + if rv.IsZero() { + return nil, nil + } + result = time.Unix(reflect.Indirect(rv).Int(), 0) default: err = fmt.Errorf("invalid field type %#v for UnixSecondSerializer, only int, uint supported", v) } @@ -142,8 +150,10 @@ func (GobSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, default: return fmt.Errorf("failed to unmarshal gob value: %#v", dbValue) } - decoder := gob.NewDecoder(bytes.NewBuffer(bytesValue)) - err = decoder.Decode(fieldValue.Interface()) + if len(bytesValue) > 0 { + decoder := gob.NewDecoder(bytes.NewBuffer(bytesValue)) + err = decoder.Decode(fieldValue.Interface()) + } } field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem()) return diff --git a/vendor/gorm.io/gorm/statement.go b/vendor/gorm.io/gorm/statement.go index 850af6c..cc26fe3 100644 --- a/vendor/gorm.io/gorm/statement.go +++ b/vendor/gorm.io/gorm/statement.go @@ -650,7 +650,7 @@ func (stmt *Statement) Changed(fields ...string) bool { return false } -var nameMatcher = regexp.MustCompile(`^[\W]?(?:[a-z_0-9]+?)[\W]?\.[\W]?([a-z_0-9]+?)[\W]?$`) +var nameMatcher = regexp.MustCompile(`^(?:\W?(\w+?)\W?\.)?\W?(\w+?)\W?$`) // SelectAndOmitColumns get select and omit columns, select -> true, omit -> false func (stmt *Statement) SelectAndOmitColumns(requireCreate, requireUpdate bool) (map[string]bool, bool) { @@ -672,8 +672,8 @@ func (stmt *Statement) SelectAndOmitColumns(requireCreate, requireUpdate bool) ( } } else if field := stmt.Schema.LookUpField(column); field != nil && field.DBName != "" { results[field.DBName] = true - } else if matches := nameMatcher.FindStringSubmatch(column); len(matches) == 2 { - results[matches[1]] = true + } else if matches := nameMatcher.FindStringSubmatch(column); len(matches) == 3 && (matches[1] == stmt.Table || matches[1] == "") { + results[matches[2]] = true } else { results[column] = true } diff --git a/vendor/modules.txt b/vendor/modules.txt index 6ac8a81..72d1c43 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -32,7 +32,7 @@ github.com/go-playground/locales/currency # github.com/go-playground/universal-translator v0.18.0 ## explicit; go 1.13 github.com/go-playground/universal-translator -# github.com/go-playground/validator/v10 v10.11.0 +# github.com/go-playground/validator/v10 v10.11.1 ## explicit; go 1.13 github.com/go-playground/validator/v10 # github.com/go-redis/redis/v9 v9.0.0-beta.2 @@ -59,8 +59,6 @@ github.com/goccy/go-json/internal/encoder/vm_color_indent github.com/goccy/go-json/internal/encoder/vm_indent github.com/goccy/go-json/internal/errors github.com/goccy/go-json/internal/runtime -# github.com/golang-sql/sqlexp v0.1.0 -## explicit; go 1.16 # github.com/golang/snappy v0.0.4 ## explicit github.com/golang/snappy @@ -105,8 +103,8 @@ github.com/jinzhu/now # github.com/json-iterator/go v1.1.12 ## explicit; go 1.12 github.com/json-iterator/go -# github.com/klauspost/compress v1.15.9 -## explicit; go 1.16 +# github.com/klauspost/compress v1.15.10 +## explicit; go 1.17 github.com/klauspost/compress github.com/klauspost/compress/fse github.com/klauspost/compress/huff0 @@ -137,6 +135,12 @@ github.com/montanaflynn/stats # github.com/natefinch/lumberjack v2.0.0+incompatible ## explicit github.com/natefinch/lumberjack +# github.com/oschwald/geoip2-golang v1.8.0 +## explicit; go 1.18 +github.com/oschwald/geoip2-golang +# github.com/oschwald/maxminddb-golang v1.10.0 +## explicit; go 1.18 +github.com/oschwald/maxminddb-golang # github.com/pelletier/go-toml/v2 v2.0.5 ## explicit; go 1.16 github.com/pelletier/go-toml/v2 @@ -242,16 +246,18 @@ github.com/xdg-go/stringprep # github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a ## explicit; go 1.12 github.com/youmark/pkcs8 -# go.dtapp.net/dorm v1.0.33 +# go.dtapp.net/dorm v1.0.38 ## explicit; go 1.19 go.dtapp.net/dorm -# go.dtapp.net/goip v1.0.30 +# go.dtapp.net/goip v1.0.36 ## explicit; go 1.19 go.dtapp.net/goip +go.dtapp.net/goip/geoip go.dtapp.net/goip/ip2region -go.dtapp.net/goip/v4 -go.dtapp.net/goip/v6 -# go.dtapp.net/golog v1.0.73 +go.dtapp.net/goip/ip2region_v2 +go.dtapp.net/goip/ipv6wry +go.dtapp.net/goip/qqwry +# go.dtapp.net/golog v1.0.88 ## explicit; go 1.19 go.dtapp.net/golog # go.dtapp.net/gorandom v1.0.1 @@ -272,8 +278,6 @@ go.dtapp.net/gotrace_id # go.dtapp.net/gourl v1.0.0 ## explicit; go 1.19 go.dtapp.net/gourl -# go.dtapp.net/goxml v1.0.1 -## explicit; go 1.18 # go.mongodb.org/mongo-driver v1.10.2 ## explicit; go 1.10 go.mongodb.org/mongo-driver/bson @@ -326,7 +330,7 @@ go.uber.org/zap/internal/bufferpool go.uber.org/zap/internal/color go.uber.org/zap/internal/exit go.uber.org/zap/zapcore -# golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 +# golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 ## explicit; go 1.17 golang.org/x/crypto/ocsp golang.org/x/crypto/pbkdf2 @@ -335,7 +339,7 @@ golang.org/x/crypto/sha3 # golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 ## explicit; go 1.17 golang.org/x/mod/semver -# golang.org/x/net v0.0.0-20220909164309-bea034e7d591 +# golang.org/x/net v0.0.0-20220920152717-4a395b0a80a1 ## explicit; go 1.17 golang.org/x/net/html golang.org/x/net/html/atom @@ -348,7 +352,7 @@ golang.org/x/net/idna # golang.org/x/sync v0.0.0-20220907140024-f12130a52804 ## explicit golang.org/x/sync/errgroup -# golang.org/x/sys v0.0.0-20220913175220-63ea55921009 +# golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 ## explicit; go 1.17 golang.org/x/sys/cpu golang.org/x/sys/internal/unsafeheader @@ -398,16 +402,14 @@ google.golang.org/protobuf/runtime/protoiface # gopkg.in/yaml.v2 v2.4.0 ## explicit; go 1.15 gopkg.in/yaml.v2 -# gorm.io/datatypes v1.0.7 -## explicit; go 1.14 # gorm.io/driver/mysql v1.3.6 ## explicit; go 1.14 gorm.io/driver/mysql -# gorm.io/driver/postgres v1.3.9 +# gorm.io/driver/postgres v1.3.10 ## explicit; go 1.14 gorm.io/driver/postgres -# gorm.io/gorm v1.23.8 -## explicit; go 1.14 +# gorm.io/gorm v1.23.9 +## explicit; go 1.16 gorm.io/gorm gorm.io/gorm/callbacks gorm.io/gorm/clause