Updating dependancies. (#9303)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
347ee1d205
Коммит
61e27beabc
99
Gopkg.lock
сгенерированный
99
Gopkg.lock
сгенерированный
@@ -17,7 +17,7 @@
|
|||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/avct/uasurfer"
|
name = "github.com/avct/uasurfer"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "c4be5581ec9617d04f5c5e02b893903ead0b1eed"
|
revision = "dc0ec4fd1e875e7ad39d8c932a198d41dd7637d0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/davecgh/go-spew"
|
name = "github.com/davecgh/go-spew"
|
||||||
packages = ["spew"]
|
packages = ["spew"]
|
||||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||||
version = "v1.1.0"
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -46,8 +46,8 @@
|
|||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/disintegration/imaging"
|
name = "github.com/disintegration/imaging"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "bbcee2f5c9d5e94ca42c8b50ec847fec64a6c134"
|
revision = "0bd5694c78c9c3d9a3cd06a706a8f3c59296a9ac"
|
||||||
version = "v1.4.2"
|
version = "v1.5.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -70,8 +70,8 @@
|
|||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/go-ini/ini"
|
name = "github.com/go-ini/ini"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "358ee7663966325963d4e8b2e1fbd570c5195153"
|
revision = "5cf292cae48347c2490ac1a58fe36735fb78df7e"
|
||||||
version = "v1.38.1"
|
version = "v1.38.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/go-ldap/ldap"
|
name = "github.com/go-ldap/ldap"
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
"internal/singleflight",
|
"internal/singleflight",
|
||||||
"internal/util"
|
"internal/util"
|
||||||
]
|
]
|
||||||
revision = "83fb42932f6145ce52df09860384a4653d2d332a"
|
revision = "1614e579ed966441b8e0c3ccea1dd0fbbd93a6ae"
|
||||||
version = "v6.12.0"
|
version = "v6.14.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -119,8 +119,8 @@
|
|||||||
"ptypes/duration",
|
"ptypes/duration",
|
||||||
"ptypes/timestamp"
|
"ptypes/timestamp"
|
||||||
]
|
]
|
||||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||||
version = "v1.1.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/context"
|
name = "github.com/gorilla/context"
|
||||||
@@ -131,8 +131,8 @@
|
|||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/handlers"
|
name = "github.com/gorilla/handlers"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "90663712d74cb411cbef281bc1e08c19d1a76145"
|
revision = "7e0847f9db758cdebd26c149d0ae9d5d0b9c98ce"
|
||||||
version = "v1.3.0"
|
version = "v1.4.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/mux"
|
name = "github.com/gorilla/mux"
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/gorilla/websocket"
|
name = "github.com/gorilla/websocket"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "5ed622c449da6d44c3c8329331ff47a9e5844f71"
|
revision = "b378caee5b2a673abe3897c40fde529bff7b986e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -159,10 +159,10 @@
|
|||||||
revision = "7b7ae1e72eade09dbc9c2cfba3e6c4bae7b8bcac"
|
revision = "7b7ae1e72eade09dbc9c2cfba3e6c4bae7b8bcac"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
name = "github.com/hashicorp/errwrap"
|
name = "github.com/hashicorp/errwrap"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "d6c0cd88035724dd42e0f335ae30161c20575ecc"
|
revision = "8a6fb523712970c966eefc6b39ed2c5e74880354"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/hashicorp/go-hclog"
|
name = "github.com/hashicorp/go-hclog"
|
||||||
@@ -182,10 +182,10 @@
|
|||||||
revision = "fa3f63826f7c23912c15263591e65d54d080b458"
|
revision = "fa3f63826f7c23912c15263591e65d54d080b458"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
name = "github.com/hashicorp/go-multierror"
|
name = "github.com/hashicorp/go-multierror"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "3d5d8f294aa03d8e98859feac328afbdf1ae0703"
|
revision = "886a7fbe3eb1c874d46f623bfa70af45f425b3d1"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/hashicorp/go-plugin"
|
name = "github.com/hashicorp/go-plugin"
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/hashicorp/memberlist"
|
name = "github.com/hashicorp/memberlist"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "2288bf30e9c8d7b5f6549bf62e07120d72fd4b6c"
|
revision = "b195c8e4fcc6284fff1583fd6ab09e68ca207551"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -261,13 +261,13 @@
|
|||||||
revision = "1d33003b386959af197ba96475f198c114627b5e"
|
revision = "1d33003b386959af197ba96475f198c114627b5e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
name = "github.com/lib/pq"
|
name = "github.com/lib/pq"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"oid"
|
"oid"
|
||||||
]
|
]
|
||||||
revision = "90697d60dd844d5ef6ff15135d0203f65d2f53b8"
|
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/magiconair/properties"
|
name = "github.com/magiconair/properties"
|
||||||
@@ -284,7 +284,7 @@
|
|||||||
"jlexer",
|
"jlexer",
|
||||||
"jwriter"
|
"jwriter"
|
||||||
]
|
]
|
||||||
revision = "efc7eb8984d6655c26b5c9d2e65c024e5767c37c"
|
revision = "60711f1a8329503b04e1c88535f419d0bb440bff"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -312,8 +312,8 @@
|
|||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/mattn/go-runewidth"
|
name = "github.com/mattn/go-runewidth"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
|
revision = "ce7b0b5c7b45a81508558cd1dba6bb1e4ddb51bb"
|
||||||
version = "v0.0.2"
|
version = "v0.0.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/mattn/go-sqlite3"
|
name = "github.com/mattn/go-sqlite3"
|
||||||
@@ -347,10 +347,10 @@
|
|||||||
version = "v6.0.5"
|
version = "v6.0.5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
name = "github.com/mitchellh/go-homedir"
|
name = "github.com/mitchellh/go-homedir"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
|
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -359,10 +359,10 @@
|
|||||||
revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28"
|
revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
name = "github.com/mitchellh/mapstructure"
|
name = "github.com/mitchellh/mapstructure"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "f15292f7a699fcc1a38a80977f80a046874ba8ac"
|
revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/nicksnyder/go-i18n"
|
name = "github.com/nicksnyder/go-i18n"
|
||||||
@@ -434,7 +434,7 @@
|
|||||||
"internal/bitbucket.org/ww/goautoneg",
|
"internal/bitbucket.org/ww/goautoneg",
|
||||||
"model"
|
"model"
|
||||||
]
|
]
|
||||||
revision = "7600349dcfe1abd18d72d3a1770870d9800a7801"
|
revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -445,13 +445,13 @@
|
|||||||
"nfs",
|
"nfs",
|
||||||
"xfs"
|
"xfs"
|
||||||
]
|
]
|
||||||
revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a"
|
revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/rs/cors"
|
name = "github.com/rs/cors"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "ca016a06a5753f8ba03029c0aa5e54afb1bf713f"
|
revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f"
|
||||||
version = "v1.4.0"
|
version = "v1.5.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "go1"
|
branch = "go1"
|
||||||
@@ -483,8 +483,8 @@
|
|||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/sirupsen/logrus"
|
name = "github.com/sirupsen/logrus"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
|
||||||
version = "v1.0.5"
|
version = "v1.0.6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/spf13/afero"
|
name = "github.com/spf13/afero"
|
||||||
@@ -511,13 +511,13 @@
|
|||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/spf13/jwalterweatherman"
|
name = "github.com/spf13/jwalterweatherman"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
|
revision = "14d3d4c518341bea657dd8a226f5121c0ff8c9f2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/spf13/pflag"
|
name = "github.com/spf13/pflag"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
||||||
version = "v1.0.1"
|
version = "v1.0.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -585,8 +585,8 @@
|
|||||||
"internal/exit",
|
"internal/exit",
|
||||||
"zapcore"
|
"zapcore"
|
||||||
]
|
]
|
||||||
revision = "4d45f9617f7d90f7a663ff21c7a4321dbe78098b"
|
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
|
||||||
version = "v1.9.0"
|
version = "v1.9.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -602,7 +602,7 @@
|
|||||||
"ed25519/internal/edwards25519",
|
"ed25519/internal/edwards25519",
|
||||||
"ssh/terminal"
|
"ssh/terminal"
|
||||||
]
|
]
|
||||||
revision = "a2144134853fc9a27a7b1e3eb4f19f1a76df13c9"
|
revision = "614d502a4dac94afa3a6ce146bd1736da82514c6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -636,7 +636,7 @@
|
|||||||
"ipv6",
|
"ipv6",
|
||||||
"trace"
|
"trace"
|
||||||
]
|
]
|
||||||
revision = "a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1"
|
revision = "faa378e6dbaed88bd8100f8bcf09939375c6e8fa"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@@ -646,7 +646,7 @@
|
|||||||
"unix",
|
"unix",
|
||||||
"windows"
|
"windows"
|
||||||
]
|
]
|
||||||
revision = "ac767d655b305d4e9612f5f6e33120b9176c4ad4"
|
revision = "4910a1d54f876d7b22162a85f4d066d3ee649450"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
@@ -691,7 +691,7 @@
|
|||||||
branch = "master"
|
branch = "master"
|
||||||
name = "google.golang.org/genproto"
|
name = "google.golang.org/genproto"
|
||||||
packages = ["googleapis/rpc/status"]
|
packages = ["googleapis/rpc/status"]
|
||||||
revision = "fedd2861243fd1a8152376292b921b394c7bef7e"
|
revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "google.golang.org/grpc"
|
name = "google.golang.org/grpc"
|
||||||
@@ -711,7 +711,9 @@
|
|||||||
"internal",
|
"internal",
|
||||||
"internal/backoff",
|
"internal/backoff",
|
||||||
"internal/channelz",
|
"internal/channelz",
|
||||||
|
"internal/envconfig",
|
||||||
"internal/grpcrand",
|
"internal/grpcrand",
|
||||||
|
"internal/transport",
|
||||||
"keepalive",
|
"keepalive",
|
||||||
"metadata",
|
"metadata",
|
||||||
"naming",
|
"naming",
|
||||||
@@ -721,11 +723,10 @@
|
|||||||
"resolver/passthrough",
|
"resolver/passthrough",
|
||||||
"stats",
|
"stats",
|
||||||
"status",
|
"status",
|
||||||
"tap",
|
"tap"
|
||||||
"transport"
|
|
||||||
]
|
]
|
||||||
revision = "168a6198bcb0ef175f7dacec0b8691fc141dc9b8"
|
revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455"
|
||||||
version = "v1.13.0"
|
version = "v1.14.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "v3"
|
branch = "v3"
|
||||||
@@ -758,8 +759,8 @@
|
|||||||
"config",
|
"config",
|
||||||
"uritemplates"
|
"uritemplates"
|
||||||
]
|
]
|
||||||
revision = "52741dc2ce53629cbe1e673869040d886cba2cd5"
|
revision = "d94782c1eadecb8e1d3dcd5f38ba533b66992ff2"
|
||||||
version = "v5.0.70"
|
version = "v5.0.74"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
|
|||||||
3
vendor/github.com/avct/uasurfer/browser.go
сгенерированный
поставляемый
3
vendor/github.com/avct/uasurfer/browser.go
сгенерированный
поставляемый
@@ -28,6 +28,9 @@ func (u *UserAgent) evalBrowserName(ua string) bool {
|
|||||||
|
|
||||||
if strings.Contains(ua, "applewebkit") {
|
if strings.Contains(ua, "applewebkit") {
|
||||||
switch {
|
switch {
|
||||||
|
case strings.Contains(ua, "googlebot"):
|
||||||
|
u.Browser.Name = BrowserGoogleBot
|
||||||
|
|
||||||
case strings.Contains(ua, "opr/") || strings.Contains(ua, "opios/"):
|
case strings.Contains(ua, "opr/") || strings.Contains(ua, "opios/"):
|
||||||
u.Browser.Name = BrowserOpera
|
u.Browser.Name = BrowserOpera
|
||||||
|
|
||||||
|
|||||||
2
vendor/github.com/avct/uasurfer/device.go
сгенерированный
поставляемый
2
vendor/github.com/avct/uasurfer/device.go
сгенерированный
поставляемый
@@ -21,7 +21,7 @@ func (u *UserAgent) evalDevice(ua string) {
|
|||||||
u.DeviceType = DevicePhone
|
u.DeviceType = DevicePhone
|
||||||
|
|
||||||
// long list of smarttv and tv dongle identifiers
|
// long list of smarttv and tv dongle identifiers
|
||||||
case strings.Contains(ua, "tv") || strings.Contains(ua, "crkey") || strings.Contains(ua, "googletv") || strings.Contains(ua, "aftb") || strings.Contains(ua, "adt-") || strings.Contains(ua, "roku") || strings.Contains(ua, "viera") || strings.Contains(ua, "aquos") || strings.Contains(ua, "dtv") || strings.Contains(ua, "appletv") || strings.Contains(ua, "smarttv") || strings.Contains(ua, "tuner") || strings.Contains(ua, "smart-tv") || strings.Contains(ua, "hbbtv") || strings.Contains(ua, "netcast") || strings.Contains(ua, "vizio"):
|
case strings.Contains(ua, "tv") || strings.Contains(ua, "crkey") || strings.Contains(ua, "googletv") || strings.Contains(ua, "aftb") || strings.Contains(ua, "aftt") || strings.Contains(ua, "aftm") || strings.Contains(ua, "adt-") || strings.Contains(ua, "roku") || strings.Contains(ua, "viera") || strings.Contains(ua, "aquos") || strings.Contains(ua, "dtv") || strings.Contains(ua, "appletv") || strings.Contains(ua, "smarttv") || strings.Contains(ua, "tuner") || strings.Contains(ua, "smart-tv") || strings.Contains(ua, "hbbtv") || strings.Contains(ua, "netcast") || strings.Contains(ua, "vizio"):
|
||||||
u.DeviceType = DeviceTV
|
u.DeviceType = DeviceTV
|
||||||
|
|
||||||
case u.OS.Name == OSAndroid:
|
case u.OS.Name == OSAndroid:
|
||||||
|
|||||||
2
vendor/github.com/davecgh/go-spew/LICENSE
сгенерированный
поставляемый
2
vendor/github.com/davecgh/go-spew/LICENSE
сгенерированный
поставляемый
@@ -2,7 +2,7 @@ ISC License
|
|||||||
|
|
||||||
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
|
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
copyright notice and this permission notice appear in all copies.
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
|||||||
183
vendor/github.com/davecgh/go-spew/spew/bypass.go
сгенерированный
поставляемый
183
vendor/github.com/davecgh/go-spew/spew/bypass.go
сгенерированный
поставляемый
@@ -16,7 +16,9 @@
|
|||||||
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
||||||
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
||||||
// tag is deprecated and thus should not be used.
|
// tag is deprecated and thus should not be used.
|
||||||
// +build !js,!appengine,!safe,!disableunsafe
|
// Go versions prior to 1.4 are disabled because they use a different layout
|
||||||
|
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
||||||
|
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
||||||
|
|
||||||
package spew
|
package spew
|
||||||
|
|
||||||
@@ -34,80 +36,49 @@ const (
|
|||||||
ptrSize = unsafe.Sizeof((*byte)(nil))
|
ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
type flag uintptr
|
||||||
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
|
|
||||||
// internal reflect.Value fields. These values are valid before golang
|
|
||||||
// commit ecccf07e7f9d which changed the format. The are also valid
|
|
||||||
// after commit 82f48826c6c7 which changed the format again to mirror
|
|
||||||
// the original format. Code in the init function updates these offsets
|
|
||||||
// as necessary.
|
|
||||||
offsetPtr = uintptr(ptrSize)
|
|
||||||
offsetScalar = uintptr(0)
|
|
||||||
offsetFlag = uintptr(ptrSize * 2)
|
|
||||||
|
|
||||||
// flagKindWidth and flagKindShift indicate various bits that the
|
var (
|
||||||
// reflect package uses internally to track kind information.
|
// flagRO indicates whether the value field of a reflect.Value
|
||||||
//
|
// is read-only.
|
||||||
// flagRO indicates whether or not the value field of a reflect.Value is
|
flagRO flag
|
||||||
// read-only.
|
|
||||||
//
|
// flagAddr indicates whether the address of the reflect.Value's
|
||||||
// flagIndir indicates whether the value field of a reflect.Value is
|
// value may be taken.
|
||||||
// the actual data or a pointer to the data.
|
flagAddr flag
|
||||||
//
|
|
||||||
// These values are valid before golang commit 90a7c3c86944 which
|
|
||||||
// changed their positions. Code in the init function updates these
|
|
||||||
// flags as necessary.
|
|
||||||
flagKindWidth = uintptr(5)
|
|
||||||
flagKindShift = uintptr(flagKindWidth - 1)
|
|
||||||
flagRO = uintptr(1 << 0)
|
|
||||||
flagIndir = uintptr(1 << 1)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
// flagKindMask holds the bits that make up the kind
|
||||||
// Older versions of reflect.Value stored small integers directly in the
|
// part of the flags field. In all the supported versions,
|
||||||
// ptr field (which is named val in the older versions). Versions
|
// it is in the lower 5 bits.
|
||||||
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
|
const flagKindMask = flag(0x1f)
|
||||||
// scalar for this purpose which unfortunately came before the flag
|
|
||||||
// field, so the offset of the flag field is different for those
|
|
||||||
// versions.
|
|
||||||
//
|
|
||||||
// This code constructs a new reflect.Value from a known small integer
|
|
||||||
// and checks if the size of the reflect.Value struct indicates it has
|
|
||||||
// the scalar field. When it does, the offsets are updated accordingly.
|
|
||||||
vv := reflect.ValueOf(0xf00)
|
|
||||||
if unsafe.Sizeof(vv) == (ptrSize * 4) {
|
|
||||||
offsetScalar = ptrSize * 2
|
|
||||||
offsetFlag = ptrSize * 3
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit 90a7c3c86944 changed the flag positions such that the low
|
// Different versions of Go have used different
|
||||||
// order bits are the kind. This code extracts the kind from the flags
|
// bit layouts for the flags type. This table
|
||||||
// field and ensures it's the correct type. When it's not, the flag
|
// records the known combinations.
|
||||||
// order has been changed to the newer format, so the flags are updated
|
var okFlags = []struct {
|
||||||
// accordingly.
|
ro, addr flag
|
||||||
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
|
}{{
|
||||||
upfv := *(*uintptr)(upf)
|
// From Go 1.4 to 1.5
|
||||||
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
|
ro: 1 << 5,
|
||||||
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
|
addr: 1 << 7,
|
||||||
flagKindShift = 0
|
}, {
|
||||||
flagRO = 1 << 5
|
// Up to Go tip.
|
||||||
flagIndir = 1 << 6
|
ro: 1<<5 | 1<<6,
|
||||||
|
addr: 1 << 8,
|
||||||
|
}}
|
||||||
|
|
||||||
// Commit adf9b30e5594 modified the flags to separate the
|
var flagValOffset = func() uintptr {
|
||||||
// flagRO flag into two bits which specifies whether or not the
|
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||||
// field is embedded. This causes flagIndir to move over a bit
|
if !ok {
|
||||||
// and means that flagRO is the combination of either of the
|
panic("reflect.Value has no flag field")
|
||||||
// original flagRO bit and the new bit.
|
|
||||||
//
|
|
||||||
// This code detects the change by extracting what used to be
|
|
||||||
// the indirect bit to ensure it's set. When it's not, the flag
|
|
||||||
// order has been changed to the newer format, so the flags are
|
|
||||||
// updated accordingly.
|
|
||||||
if upfv&flagIndir == 0 {
|
|
||||||
flagRO = 3 << 5
|
|
||||||
flagIndir = 1 << 7
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return field.Offset
|
||||||
|
}()
|
||||||
|
|
||||||
|
// flagField returns a pointer to the flag field of a reflect.Value.
|
||||||
|
func flagField(v *reflect.Value) *flag {
|
||||||
|
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
||||||
@@ -119,34 +90,56 @@ func init() {
|
|||||||
// This allows us to check for implementations of the Stringer and error
|
// This allows us to check for implementations of the Stringer and error
|
||||||
// interfaces to be used for pretty printing ordinarily unaddressable and
|
// interfaces to be used for pretty printing ordinarily unaddressable and
|
||||||
// inaccessible values such as unexported struct fields.
|
// inaccessible values such as unexported struct fields.
|
||||||
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
|
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
||||||
indirects := 1
|
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
|
||||||
vt := v.Type()
|
return v
|
||||||
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
|
|
||||||
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
|
|
||||||
if rvf&flagIndir != 0 {
|
|
||||||
vt = reflect.PtrTo(v.Type())
|
|
||||||
indirects++
|
|
||||||
} else if offsetScalar != 0 {
|
|
||||||
// The value is in the scalar field when it's not one of the
|
|
||||||
// reference types.
|
|
||||||
switch vt.Kind() {
|
|
||||||
case reflect.Uintptr:
|
|
||||||
case reflect.Chan:
|
|
||||||
case reflect.Func:
|
|
||||||
case reflect.Map:
|
|
||||||
case reflect.Ptr:
|
|
||||||
case reflect.UnsafePointer:
|
|
||||||
default:
|
|
||||||
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
|
|
||||||
offsetScalar)
|
|
||||||
}
|
}
|
||||||
|
flagFieldPtr := flagField(&v)
|
||||||
|
*flagFieldPtr &^= flagRO
|
||||||
|
*flagFieldPtr |= flagAddr
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
pv := reflect.NewAt(vt, upv)
|
// Sanity checks against future reflect package changes
|
||||||
rv = pv
|
// to the type or semantics of the Value.flag field.
|
||||||
for i := 0; i < indirects; i++ {
|
func init() {
|
||||||
rv = rv.Elem()
|
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||||
|
if !ok {
|
||||||
|
panic("reflect.Value has no flag field")
|
||||||
}
|
}
|
||||||
return rv
|
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
|
||||||
|
panic("reflect.Value flag field has changed kind")
|
||||||
|
}
|
||||||
|
type t0 int
|
||||||
|
var t struct {
|
||||||
|
A t0
|
||||||
|
// t0 will have flagEmbedRO set.
|
||||||
|
t0
|
||||||
|
// a will have flagStickyRO set
|
||||||
|
a t0
|
||||||
|
}
|
||||||
|
vA := reflect.ValueOf(t).FieldByName("A")
|
||||||
|
va := reflect.ValueOf(t).FieldByName("a")
|
||||||
|
vt0 := reflect.ValueOf(t).FieldByName("t0")
|
||||||
|
|
||||||
|
// Infer flagRO from the difference between the flags
|
||||||
|
// for the (otherwise identical) fields in t.
|
||||||
|
flagPublic := *flagField(&vA)
|
||||||
|
flagWithRO := *flagField(&va) | *flagField(&vt0)
|
||||||
|
flagRO = flagPublic ^ flagWithRO
|
||||||
|
|
||||||
|
// Infer flagAddr from the difference between a value
|
||||||
|
// taken from a pointer and not.
|
||||||
|
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
|
||||||
|
flagNoPtr := *flagField(&vA)
|
||||||
|
flagPtr := *flagField(&vPtrA)
|
||||||
|
flagAddr = flagNoPtr ^ flagPtr
|
||||||
|
|
||||||
|
// Check that the inferred flags tally with one of the known versions.
|
||||||
|
for _, f := range okFlags {
|
||||||
|
if flagRO == f.ro && flagAddr == f.addr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("reflect.Value read-only flag has changed semantics")
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
сгенерированный
поставляемый
2
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
сгенерированный
поставляемый
@@ -16,7 +16,7 @@
|
|||||||
// when the code is running on Google App Engine, compiled by GopherJS, or
|
// when the code is running on Google App Engine, compiled by GopherJS, or
|
||||||
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
||||||
// tag is deprecated and thus should not be used.
|
// tag is deprecated and thus should not be used.
|
||||||
// +build js appengine safe disableunsafe
|
// +build js appengine safe disableunsafe !go1.4
|
||||||
|
|
||||||
package spew
|
package spew
|
||||||
|
|
||||||
|
|||||||
2
vendor/github.com/davecgh/go-spew/spew/common.go
сгенерированный
поставляемый
2
vendor/github.com/davecgh/go-spew/spew/common.go
сгенерированный
поставляемый
@@ -180,7 +180,7 @@ func printComplex(w io.Writer, c complex128, floatPrecision int) {
|
|||||||
w.Write(closeParenBytes)
|
w.Write(closeParenBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
|
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
|
||||||
// prefix to Writer w.
|
// prefix to Writer w.
|
||||||
func printHexPtr(w io.Writer, p uintptr) {
|
func printHexPtr(w io.Writer, p uintptr) {
|
||||||
// Null pointer.
|
// Null pointer.
|
||||||
|
|||||||
10
vendor/github.com/davecgh/go-spew/spew/dump.go
сгенерированный
поставляемый
10
vendor/github.com/davecgh/go-spew/spew/dump.go
сгенерированный
поставляемый
@@ -35,16 +35,16 @@ var (
|
|||||||
|
|
||||||
// cCharRE is a regular expression that matches a cgo char.
|
// cCharRE is a regular expression that matches a cgo char.
|
||||||
// It is used to detect character arrays to hexdump them.
|
// It is used to detect character arrays to hexdump them.
|
||||||
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
|
cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
|
||||||
|
|
||||||
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
||||||
// char. It is used to detect unsigned character arrays to hexdump
|
// char. It is used to detect unsigned character arrays to hexdump
|
||||||
// them.
|
// them.
|
||||||
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
|
cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
|
||||||
|
|
||||||
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
||||||
// It is used to detect uint8_t arrays to hexdump them.
|
// It is used to detect uint8_t arrays to hexdump them.
|
||||||
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
|
cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// dumpState contains information about the state of a dump operation.
|
// dumpState contains information about the state of a dump operation.
|
||||||
@@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
|
|||||||
// Display dereferenced value.
|
// Display dereferenced value.
|
||||||
d.w.Write(openParenBytes)
|
d.w.Write(openParenBytes)
|
||||||
switch {
|
switch {
|
||||||
case nilFound == true:
|
case nilFound:
|
||||||
d.w.Write(nilAngleBytes)
|
d.w.Write(nilAngleBytes)
|
||||||
|
|
||||||
case cycleFound == true:
|
case cycleFound:
|
||||||
d.w.Write(circularBytes)
|
d.w.Write(circularBytes)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
4
vendor/github.com/davecgh/go-spew/spew/format.go
сгенерированный
поставляемый
4
vendor/github.com/davecgh/go-spew/spew/format.go
сгенерированный
поставляемый
@@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) {
|
|||||||
|
|
||||||
// Display dereferenced value.
|
// Display dereferenced value.
|
||||||
switch {
|
switch {
|
||||||
case nilFound == true:
|
case nilFound:
|
||||||
f.fs.Write(nilAngleBytes)
|
f.fs.Write(nilAngleBytes)
|
||||||
|
|
||||||
case cycleFound == true:
|
case cycleFound:
|
||||||
f.fs.Write(circularShortBytes)
|
f.fs.Write(circularShortBytes)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
36
vendor/github.com/disintegration/imaging/effects.go
сгенерированный
поставляемый
36
vendor/github.com/disintegration/imaging/effects.go
сгенерированный
поставляемый
@@ -38,9 +38,13 @@ func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
|
|||||||
|
|
||||||
parallel(0, src.h, func(ys <-chan int) {
|
parallel(0, src.h, func(ys <-chan int) {
|
||||||
scanLine := make([]uint8, src.w*4)
|
scanLine := make([]uint8, src.w*4)
|
||||||
|
scanLineF := make([]float64, len(scanLine))
|
||||||
for y := range ys {
|
for y := range ys {
|
||||||
src.scan(0, y, src.w, y+1, scanLine)
|
src.scan(0, y, src.w, y+1, scanLine)
|
||||||
for x := 0; x < src.w; x++ {
|
for i, v := range scanLine {
|
||||||
|
scanLineF[i] = float64(v)
|
||||||
|
}
|
||||||
|
for x, idx := 0, 0; x < src.w; x, idx = x+1, idx+4 {
|
||||||
min := x - radius
|
min := x - radius
|
||||||
if min < 0 {
|
if min < 0 {
|
||||||
min = 0
|
min = 0
|
||||||
@@ -55,10 +59,10 @@ func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
|
|||||||
i := ix * 4
|
i := ix * 4
|
||||||
weight := kernel[absint(x-ix)]
|
weight := kernel[absint(x-ix)]
|
||||||
wsum += weight
|
wsum += weight
|
||||||
wa := float64(scanLine[i+3]) * weight
|
wa := scanLineF[i+3] * weight
|
||||||
r += float64(scanLine[i+0]) * wa
|
r += scanLineF[i+0] * wa
|
||||||
g += float64(scanLine[i+1]) * wa
|
g += scanLineF[i+1] * wa
|
||||||
b += float64(scanLine[i+2]) * wa
|
b += scanLineF[i+2] * wa
|
||||||
a += wa
|
a += wa
|
||||||
}
|
}
|
||||||
if a != 0 {
|
if a != 0 {
|
||||||
@@ -67,12 +71,12 @@ func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
|
|||||||
b /= a
|
b /= a
|
||||||
}
|
}
|
||||||
|
|
||||||
j := y*dst.Stride + x*4
|
scanLine[idx+0] = clamp(r)
|
||||||
dst.Pix[j+0] = clamp(r)
|
scanLine[idx+1] = clamp(g)
|
||||||
dst.Pix[j+1] = clamp(g)
|
scanLine[idx+2] = clamp(b)
|
||||||
dst.Pix[j+2] = clamp(b)
|
scanLine[idx+3] = clamp(a / wsum)
|
||||||
dst.Pix[j+3] = clamp(a / wsum)
|
|
||||||
}
|
}
|
||||||
|
copy(dst.Pix[y*dst.Stride:], scanLine)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -86,8 +90,12 @@ func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
|
|||||||
|
|
||||||
parallel(0, src.w, func(xs <-chan int) {
|
parallel(0, src.w, func(xs <-chan int) {
|
||||||
scanLine := make([]uint8, src.h*4)
|
scanLine := make([]uint8, src.h*4)
|
||||||
|
scanLineF := make([]float64, len(scanLine))
|
||||||
for x := range xs {
|
for x := range xs {
|
||||||
src.scan(x, 0, x+1, src.h, scanLine)
|
src.scan(x, 0, x+1, src.h, scanLine)
|
||||||
|
for i, v := range scanLine {
|
||||||
|
scanLineF[i] = float64(v)
|
||||||
|
}
|
||||||
for y := 0; y < src.h; y++ {
|
for y := 0; y < src.h; y++ {
|
||||||
min := y - radius
|
min := y - radius
|
||||||
if min < 0 {
|
if min < 0 {
|
||||||
@@ -103,10 +111,10 @@ func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
|
|||||||
i := iy * 4
|
i := iy * 4
|
||||||
weight := kernel[absint(y-iy)]
|
weight := kernel[absint(y-iy)]
|
||||||
wsum += weight
|
wsum += weight
|
||||||
wa := float64(scanLine[i+3]) * weight
|
wa := scanLineF[i+3] * weight
|
||||||
r += float64(scanLine[i+0]) * wa
|
r += scanLineF[i+0] * wa
|
||||||
g += float64(scanLine[i+1]) * wa
|
g += scanLineF[i+1] * wa
|
||||||
b += float64(scanLine[i+2]) * wa
|
b += scanLineF[i+2] * wa
|
||||||
a += wa
|
a += wa
|
||||||
}
|
}
|
||||||
if a != 0 {
|
if a != 0 {
|
||||||
|
|||||||
272
vendor/github.com/disintegration/imaging/helpers.go
сгенерированный
поставляемый
272
vendor/github.com/disintegration/imaging/helpers.go
сгенерированный
поставляемый
@@ -1,272 +0,0 @@
|
|||||||
package imaging
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
"image/draw"
|
|
||||||
"image/gif"
|
|
||||||
"image/jpeg"
|
|
||||||
"image/png"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/image/bmp"
|
|
||||||
"golang.org/x/image/tiff"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Format is an image file format.
|
|
||||||
type Format int
|
|
||||||
|
|
||||||
// Image file formats.
|
|
||||||
const (
|
|
||||||
JPEG Format = iota
|
|
||||||
PNG
|
|
||||||
GIF
|
|
||||||
TIFF
|
|
||||||
BMP
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f Format) String() string {
|
|
||||||
switch f {
|
|
||||||
case JPEG:
|
|
||||||
return "JPEG"
|
|
||||||
case PNG:
|
|
||||||
return "PNG"
|
|
||||||
case GIF:
|
|
||||||
return "GIF"
|
|
||||||
case TIFF:
|
|
||||||
return "TIFF"
|
|
||||||
case BMP:
|
|
||||||
return "BMP"
|
|
||||||
default:
|
|
||||||
return "Unsupported"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var formatFromExt = map[string]Format{
|
|
||||||
".jpg": JPEG,
|
|
||||||
".jpeg": JPEG,
|
|
||||||
".png": PNG,
|
|
||||||
".tif": TIFF,
|
|
||||||
".tiff": TIFF,
|
|
||||||
".bmp": BMP,
|
|
||||||
".gif": GIF,
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatFromFilename parses image format from filename extension:
|
|
||||||
// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
|
|
||||||
func FormatFromFilename(filename string) (Format, error) {
|
|
||||||
ext := strings.ToLower(filepath.Ext(filename))
|
|
||||||
if f, ok := formatFromExt[ext]; ok {
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
return -1, ErrUnsupportedFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrUnsupportedFormat means the given image format (or file extension) is unsupported.
|
|
||||||
ErrUnsupportedFormat = errors.New("imaging: unsupported image format")
|
|
||||||
)
|
|
||||||
|
|
||||||
type fileSystem interface {
|
|
||||||
Create(string) (io.WriteCloser, error)
|
|
||||||
Open(string) (io.ReadCloser, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type localFS struct{}
|
|
||||||
|
|
||||||
func (localFS) Create(name string) (io.WriteCloser, error) { return os.Create(name) }
|
|
||||||
func (localFS) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
|
|
||||||
|
|
||||||
var fs fileSystem = localFS{}
|
|
||||||
|
|
||||||
// Decode reads an image from r.
|
|
||||||
func Decode(r io.Reader) (image.Image, error) {
|
|
||||||
img, _, err := image.Decode(r)
|
|
||||||
return img, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open loads an image from file
|
|
||||||
func Open(filename string) (image.Image, error) {
|
|
||||||
file, err := fs.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
return Decode(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
type encodeConfig struct {
|
|
||||||
jpegQuality int
|
|
||||||
gifNumColors int
|
|
||||||
gifQuantizer draw.Quantizer
|
|
||||||
gifDrawer draw.Drawer
|
|
||||||
pngCompressionLevel png.CompressionLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultEncodeConfig = encodeConfig{
|
|
||||||
jpegQuality: 95,
|
|
||||||
gifNumColors: 256,
|
|
||||||
gifQuantizer: nil,
|
|
||||||
gifDrawer: nil,
|
|
||||||
pngCompressionLevel: png.DefaultCompression,
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeOption sets an optional parameter for the Encode and Save functions.
|
|
||||||
type EncodeOption func(*encodeConfig)
|
|
||||||
|
|
||||||
// JPEGQuality returns an EncodeOption that sets the output JPEG quality.
|
|
||||||
// Quality ranges from 1 to 100 inclusive, higher is better. Default is 95.
|
|
||||||
func JPEGQuality(quality int) EncodeOption {
|
|
||||||
return func(c *encodeConfig) {
|
|
||||||
c.jpegQuality = quality
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GIFNumColors returns an EncodeOption that sets the maximum number of colors
|
|
||||||
// used in the GIF-encoded image. It ranges from 1 to 256. Default is 256.
|
|
||||||
func GIFNumColors(numColors int) EncodeOption {
|
|
||||||
return func(c *encodeConfig) {
|
|
||||||
c.gifNumColors = numColors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce
|
|
||||||
// a palette of the GIF-encoded image.
|
|
||||||
func GIFQuantizer(quantizer draw.Quantizer) EncodeOption {
|
|
||||||
return func(c *encodeConfig) {
|
|
||||||
c.gifQuantizer = quantizer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GIFDrawer returns an EncodeOption that sets the drawer that is used to convert
|
|
||||||
// the source image to the desired palette of the GIF-encoded image.
|
|
||||||
func GIFDrawer(drawer draw.Drawer) EncodeOption {
|
|
||||||
return func(c *encodeConfig) {
|
|
||||||
c.gifDrawer = drawer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PNGCompressionLevel returns an EncodeOption that sets the compression level
|
|
||||||
// of the PNG-encoded image. Default is png.DefaultCompression.
|
|
||||||
func PNGCompressionLevel(level png.CompressionLevel) EncodeOption {
|
|
||||||
return func(c *encodeConfig) {
|
|
||||||
c.pngCompressionLevel = level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP).
|
|
||||||
func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error {
|
|
||||||
cfg := defaultEncodeConfig
|
|
||||||
for _, option := range opts {
|
|
||||||
option(&cfg)
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
switch format {
|
|
||||||
case JPEG:
|
|
||||||
var rgba *image.RGBA
|
|
||||||
if nrgba, ok := img.(*image.NRGBA); ok {
|
|
||||||
if nrgba.Opaque() {
|
|
||||||
rgba = &image.RGBA{
|
|
||||||
Pix: nrgba.Pix,
|
|
||||||
Stride: nrgba.Stride,
|
|
||||||
Rect: nrgba.Rect,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if rgba != nil {
|
|
||||||
err = jpeg.Encode(w, rgba, &jpeg.Options{Quality: cfg.jpegQuality})
|
|
||||||
} else {
|
|
||||||
err = jpeg.Encode(w, img, &jpeg.Options{Quality: cfg.jpegQuality})
|
|
||||||
}
|
|
||||||
|
|
||||||
case PNG:
|
|
||||||
enc := png.Encoder{CompressionLevel: cfg.pngCompressionLevel}
|
|
||||||
err = enc.Encode(w, img)
|
|
||||||
|
|
||||||
case GIF:
|
|
||||||
err = gif.Encode(w, img, &gif.Options{
|
|
||||||
NumColors: cfg.gifNumColors,
|
|
||||||
Quantizer: cfg.gifQuantizer,
|
|
||||||
Drawer: cfg.gifDrawer,
|
|
||||||
})
|
|
||||||
|
|
||||||
case TIFF:
|
|
||||||
err = tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true})
|
|
||||||
|
|
||||||
case BMP:
|
|
||||||
err = bmp.Encode(w, img)
|
|
||||||
|
|
||||||
default:
|
|
||||||
err = ErrUnsupportedFormat
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save saves the image to file with the specified filename.
|
|
||||||
// The format is determined from the filename extension: "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
|
|
||||||
//
|
|
||||||
// Examples:
|
|
||||||
//
|
|
||||||
// // Save the image as PNG.
|
|
||||||
// err := imaging.Save(img, "out.png")
|
|
||||||
//
|
|
||||||
// // Save the image as JPEG with optional quality parameter set to 80.
|
|
||||||
// err := imaging.Save(img, "out.jpg", imaging.JPEGQuality(80))
|
|
||||||
//
|
|
||||||
func Save(img image.Image, filename string, opts ...EncodeOption) (err error) {
|
|
||||||
f, err := FormatFromFilename(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
file, err := fs.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
cerr := file.Close()
|
|
||||||
if err == nil {
|
|
||||||
err = cerr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return Encode(file, img, f, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new image with the specified width and height, and fills it with the specified color.
|
|
||||||
func New(width, height int, fillColor color.Color) *image.NRGBA {
|
|
||||||
if width <= 0 || height <= 0 {
|
|
||||||
return &image.NRGBA{}
|
|
||||||
}
|
|
||||||
|
|
||||||
c := color.NRGBAModel.Convert(fillColor).(color.NRGBA)
|
|
||||||
if (c == color.NRGBA{0, 0, 0, 0}) {
|
|
||||||
return image.NewNRGBA(image.Rect(0, 0, width, height))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &image.NRGBA{
|
|
||||||
Pix: bytes.Repeat([]byte{c.R, c.G, c.B, c.A}, width*height),
|
|
||||||
Stride: 4 * width,
|
|
||||||
Rect: image.Rect(0, 0, width, height),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a copy of the given image.
|
|
||||||
func Clone(img image.Image) *image.NRGBA {
|
|
||||||
src := newScanner(img)
|
|
||||||
dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
|
|
||||||
size := src.w * 4
|
|
||||||
parallel(0, src.h, func(ys <-chan int) {
|
|
||||||
for y := range ys {
|
|
||||||
i := y * dst.Stride
|
|
||||||
src.scan(0, y, src.w, y+1, dst.Pix[i:i+size])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return dst
|
|
||||||
}
|
|
||||||
463
vendor/github.com/disintegration/imaging/io.go
сгенерированный
поставляемый
Обычный файл
463
vendor/github.com/disintegration/imaging/io.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,463 @@
|
|||||||
|
package imaging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"image"
|
||||||
|
"image/draw"
|
||||||
|
"image/gif"
|
||||||
|
"image/jpeg"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/image/bmp"
|
||||||
|
"golang.org/x/image/tiff"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Format is an image file format.
|
||||||
|
type Format int
|
||||||
|
|
||||||
|
// Image file formats.
|
||||||
|
const (
|
||||||
|
JPEG Format = iota
|
||||||
|
PNG
|
||||||
|
GIF
|
||||||
|
TIFF
|
||||||
|
BMP
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f Format) String() string {
|
||||||
|
switch f {
|
||||||
|
case JPEG:
|
||||||
|
return "JPEG"
|
||||||
|
case PNG:
|
||||||
|
return "PNG"
|
||||||
|
case GIF:
|
||||||
|
return "GIF"
|
||||||
|
case TIFF:
|
||||||
|
return "TIFF"
|
||||||
|
case BMP:
|
||||||
|
return "BMP"
|
||||||
|
default:
|
||||||
|
return "Unsupported"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var formatFromExt = map[string]Format{
|
||||||
|
"jpg": JPEG,
|
||||||
|
"jpeg": JPEG,
|
||||||
|
"png": PNG,
|
||||||
|
"tif": TIFF,
|
||||||
|
"tiff": TIFF,
|
||||||
|
"bmp": BMP,
|
||||||
|
"gif": GIF,
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatFromExtension parses image format from extension:
|
||||||
|
// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
|
||||||
|
func FormatFromExtension(ext string) (Format, error) {
|
||||||
|
if f, ok := formatFromExt[strings.ToLower(strings.TrimPrefix(ext, "."))]; ok {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
return -1, ErrUnsupportedFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatFromFilename parses image format from filename extension:
|
||||||
|
// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
|
||||||
|
func FormatFromFilename(filename string) (Format, error) {
|
||||||
|
ext := filepath.Ext(filename)
|
||||||
|
return FormatFromExtension(ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrUnsupportedFormat means the given image format (or file extension) is unsupported.
|
||||||
|
ErrUnsupportedFormat = errors.New("imaging: unsupported image format")
|
||||||
|
)
|
||||||
|
|
||||||
|
type fileSystem interface {
|
||||||
|
Create(string) (io.WriteCloser, error)
|
||||||
|
Open(string) (io.ReadCloser, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type localFS struct{}
|
||||||
|
|
||||||
|
func (localFS) Create(name string) (io.WriteCloser, error) { return os.Create(name) }
|
||||||
|
func (localFS) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
|
||||||
|
|
||||||
|
var fs fileSystem = localFS{}
|
||||||
|
|
||||||
|
type decodeConfig struct {
|
||||||
|
autoOrientation bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultDecodeConfig = decodeConfig{
|
||||||
|
autoOrientation: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeOption sets an optional parameter for the Decode and Open functions.
|
||||||
|
type DecodeOption func(*decodeConfig)
|
||||||
|
|
||||||
|
// AutoOrientation returns a DecodeOption that sets the auto-orientation mode.
|
||||||
|
// If auto-orientation is enabled, the image will be transformed after decoding
|
||||||
|
// according to the EXIF orientation tag (if present). By default it's disabled.
|
||||||
|
func AutoOrientation(enabled bool) DecodeOption {
|
||||||
|
return func(c *decodeConfig) {
|
||||||
|
c.autoOrientation = enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode reads an image from r.
|
||||||
|
func Decode(r io.Reader, opts ...DecodeOption) (image.Image, error) {
|
||||||
|
cfg := defaultDecodeConfig
|
||||||
|
for _, option := range opts {
|
||||||
|
option(&cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cfg.autoOrientation {
|
||||||
|
img, _, err := image.Decode(r)
|
||||||
|
return img, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var orient orientation
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
r = io.TeeReader(r, pw)
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
orient = readOrientation(pr)
|
||||||
|
io.Copy(ioutil.Discard, pr)
|
||||||
|
}()
|
||||||
|
|
||||||
|
img, _, err := image.Decode(r)
|
||||||
|
pw.Close()
|
||||||
|
<-done
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fixOrientation(img, orient), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open loads an image from file.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// // Load an image from file.
|
||||||
|
// img, err := imaging.Open("test.jpg")
|
||||||
|
//
|
||||||
|
// // Load an image and transform it depending on the EXIF orientation tag (if present).
|
||||||
|
// img, err := imaging.Open("test.jpg", imaging.AutoOrientation(true))
|
||||||
|
//
|
||||||
|
func Open(filename string, opts ...DecodeOption) (image.Image, error) {
|
||||||
|
file, err := fs.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return Decode(file, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type encodeConfig struct {
|
||||||
|
jpegQuality int
|
||||||
|
gifNumColors int
|
||||||
|
gifQuantizer draw.Quantizer
|
||||||
|
gifDrawer draw.Drawer
|
||||||
|
pngCompressionLevel png.CompressionLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultEncodeConfig = encodeConfig{
|
||||||
|
jpegQuality: 95,
|
||||||
|
gifNumColors: 256,
|
||||||
|
gifQuantizer: nil,
|
||||||
|
gifDrawer: nil,
|
||||||
|
pngCompressionLevel: png.DefaultCompression,
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeOption sets an optional parameter for the Encode and Save functions.
|
||||||
|
type EncodeOption func(*encodeConfig)
|
||||||
|
|
||||||
|
// JPEGQuality returns an EncodeOption that sets the output JPEG quality.
|
||||||
|
// Quality ranges from 1 to 100 inclusive, higher is better. Default is 95.
|
||||||
|
func JPEGQuality(quality int) EncodeOption {
|
||||||
|
return func(c *encodeConfig) {
|
||||||
|
c.jpegQuality = quality
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GIFNumColors returns an EncodeOption that sets the maximum number of colors
|
||||||
|
// used in the GIF-encoded image. It ranges from 1 to 256. Default is 256.
|
||||||
|
func GIFNumColors(numColors int) EncodeOption {
|
||||||
|
return func(c *encodeConfig) {
|
||||||
|
c.gifNumColors = numColors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce
|
||||||
|
// a palette of the GIF-encoded image.
|
||||||
|
func GIFQuantizer(quantizer draw.Quantizer) EncodeOption {
|
||||||
|
return func(c *encodeConfig) {
|
||||||
|
c.gifQuantizer = quantizer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GIFDrawer returns an EncodeOption that sets the drawer that is used to convert
|
||||||
|
// the source image to the desired palette of the GIF-encoded image.
|
||||||
|
func GIFDrawer(drawer draw.Drawer) EncodeOption {
|
||||||
|
return func(c *encodeConfig) {
|
||||||
|
c.gifDrawer = drawer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PNGCompressionLevel returns an EncodeOption that sets the compression level
|
||||||
|
// of the PNG-encoded image. Default is png.DefaultCompression.
|
||||||
|
func PNGCompressionLevel(level png.CompressionLevel) EncodeOption {
|
||||||
|
return func(c *encodeConfig) {
|
||||||
|
c.pngCompressionLevel = level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP).
|
||||||
|
func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error {
|
||||||
|
cfg := defaultEncodeConfig
|
||||||
|
for _, option := range opts {
|
||||||
|
option(&cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
switch format {
|
||||||
|
case JPEG:
|
||||||
|
var rgba *image.RGBA
|
||||||
|
if nrgba, ok := img.(*image.NRGBA); ok {
|
||||||
|
if nrgba.Opaque() {
|
||||||
|
rgba = &image.RGBA{
|
||||||
|
Pix: nrgba.Pix,
|
||||||
|
Stride: nrgba.Stride,
|
||||||
|
Rect: nrgba.Rect,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rgba != nil {
|
||||||
|
err = jpeg.Encode(w, rgba, &jpeg.Options{Quality: cfg.jpegQuality})
|
||||||
|
} else {
|
||||||
|
err = jpeg.Encode(w, img, &jpeg.Options{Quality: cfg.jpegQuality})
|
||||||
|
}
|
||||||
|
|
||||||
|
case PNG:
|
||||||
|
enc := png.Encoder{CompressionLevel: cfg.pngCompressionLevel}
|
||||||
|
err = enc.Encode(w, img)
|
||||||
|
|
||||||
|
case GIF:
|
||||||
|
err = gif.Encode(w, img, &gif.Options{
|
||||||
|
NumColors: cfg.gifNumColors,
|
||||||
|
Quantizer: cfg.gifQuantizer,
|
||||||
|
Drawer: cfg.gifDrawer,
|
||||||
|
})
|
||||||
|
|
||||||
|
case TIFF:
|
||||||
|
err = tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true})
|
||||||
|
|
||||||
|
case BMP:
|
||||||
|
err = bmp.Encode(w, img)
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = ErrUnsupportedFormat
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save saves the image to file with the specified filename.
|
||||||
|
// The format is determined from the filename extension:
|
||||||
|
// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// // Save the image as PNG.
|
||||||
|
// err := imaging.Save(img, "out.png")
|
||||||
|
//
|
||||||
|
// // Save the image as JPEG with optional quality parameter set to 80.
|
||||||
|
// err := imaging.Save(img, "out.jpg", imaging.JPEGQuality(80))
|
||||||
|
//
|
||||||
|
func Save(img image.Image, filename string, opts ...EncodeOption) (err error) {
|
||||||
|
f, err := FormatFromFilename(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
file, err := fs.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
cerr := file.Close()
|
||||||
|
if err == nil {
|
||||||
|
err = cerr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return Encode(file, img, f, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// orientation is an EXIF flag that specifies the transformation
|
||||||
|
// that should be applied to image to display it correctly.
|
||||||
|
type orientation int
|
||||||
|
|
||||||
|
const (
|
||||||
|
orientationUnspecified = 0
|
||||||
|
orientationNormal = 1
|
||||||
|
orientationFlipH = 2
|
||||||
|
orientationRotate180 = 3
|
||||||
|
orientationFlipV = 4
|
||||||
|
orientationTranspose = 5
|
||||||
|
orientationRotate270 = 6
|
||||||
|
orientationTransverse = 7
|
||||||
|
orientationRotate90 = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// readOrientation tries to read the orientation EXIF flag from image data in r.
|
||||||
|
// If the EXIF data block is not found or the orientation flag is not found
|
||||||
|
// or any other error occures while reading the data, it returns the
|
||||||
|
// orientationUnspecified (0) value.
|
||||||
|
func readOrientation(r io.Reader) orientation {
|
||||||
|
const (
|
||||||
|
markerSOI = 0xffd8
|
||||||
|
markerAPP1 = 0xffe1
|
||||||
|
exifHeader = 0x45786966
|
||||||
|
byteOrderBE = 0x4d4d
|
||||||
|
byteOrderLE = 0x4949
|
||||||
|
orientationTag = 0x0112
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check if JPEG SOI marker is present.
|
||||||
|
var soi uint16
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &soi); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
if soi != markerSOI {
|
||||||
|
return orientationUnspecified // Missing JPEG SOI marker.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find JPEG APP1 marker.
|
||||||
|
for {
|
||||||
|
var marker, size uint16
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &marker); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &size); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
if marker>>8 != 0xff {
|
||||||
|
return orientationUnspecified // Invalid JPEG marker.
|
||||||
|
}
|
||||||
|
if marker == markerAPP1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if size < 2 {
|
||||||
|
return orientationUnspecified // Invalid block size.
|
||||||
|
}
|
||||||
|
if _, err := io.CopyN(ioutil.Discard, r, int64(size-2)); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if EXIF header is present.
|
||||||
|
var header uint32
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &header); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
if header != exifHeader {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
if _, err := io.CopyN(ioutil.Discard, r, 2); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read byte order information.
|
||||||
|
var (
|
||||||
|
byteOrderTag uint16
|
||||||
|
byteOrder binary.ByteOrder
|
||||||
|
)
|
||||||
|
if err := binary.Read(r, binary.BigEndian, &byteOrderTag); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
switch byteOrderTag {
|
||||||
|
case byteOrderBE:
|
||||||
|
byteOrder = binary.BigEndian
|
||||||
|
case byteOrderLE:
|
||||||
|
byteOrder = binary.LittleEndian
|
||||||
|
default:
|
||||||
|
return orientationUnspecified // Invalid byte order flag.
|
||||||
|
}
|
||||||
|
if _, err := io.CopyN(ioutil.Discard, r, 2); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the EXIF offset.
|
||||||
|
var offset uint32
|
||||||
|
if err := binary.Read(r, byteOrder, &offset); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
if offset < 8 {
|
||||||
|
return orientationUnspecified // Invalid offset value.
|
||||||
|
}
|
||||||
|
if _, err := io.CopyN(ioutil.Discard, r, int64(offset-8)); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the number of tags.
|
||||||
|
var numTags uint16
|
||||||
|
if err := binary.Read(r, byteOrder, &numTags); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the orientation tag.
|
||||||
|
for i := 0; i < int(numTags); i++ {
|
||||||
|
var tag uint16
|
||||||
|
if err := binary.Read(r, byteOrder, &tag); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
if tag != orientationTag {
|
||||||
|
if _, err := io.CopyN(ioutil.Discard, r, 10); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err := io.CopyN(ioutil.Discard, r, 6); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
var val uint16
|
||||||
|
if err := binary.Read(r, byteOrder, &val); err != nil {
|
||||||
|
return orientationUnspecified
|
||||||
|
}
|
||||||
|
if val < 1 || val > 8 {
|
||||||
|
return orientationUnspecified // Invalid tag value.
|
||||||
|
}
|
||||||
|
return orientation(val)
|
||||||
|
}
|
||||||
|
return orientationUnspecified // Missing orientation tag.
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixOrientation applies a transform to img corresponding to the given orientation flag.
|
||||||
|
func fixOrientation(img image.Image, o orientation) image.Image {
|
||||||
|
switch o {
|
||||||
|
case orientationNormal:
|
||||||
|
case orientationFlipH:
|
||||||
|
img = FlipH(img)
|
||||||
|
case orientationFlipV:
|
||||||
|
img = FlipV(img)
|
||||||
|
case orientationRotate90:
|
||||||
|
img = Rotate90(img)
|
||||||
|
case orientationRotate180:
|
||||||
|
img = Rotate180(img)
|
||||||
|
case orientationRotate270:
|
||||||
|
img = Rotate270(img)
|
||||||
|
case orientationTranspose:
|
||||||
|
img = Transpose(img)
|
||||||
|
case orientationTransverse:
|
||||||
|
img = Transverse(img)
|
||||||
|
}
|
||||||
|
return img
|
||||||
|
}
|
||||||
34
vendor/github.com/disintegration/imaging/tools.go
сгенерированный
поставляемый
34
vendor/github.com/disintegration/imaging/tools.go
сгенерированный
поставляемый
@@ -1,10 +1,44 @@
|
|||||||
package imaging
|
package imaging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// New creates a new image with the specified width and height, and fills it with the specified color.
|
||||||
|
func New(width, height int, fillColor color.Color) *image.NRGBA {
|
||||||
|
if width <= 0 || height <= 0 {
|
||||||
|
return &image.NRGBA{}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := color.NRGBAModel.Convert(fillColor).(color.NRGBA)
|
||||||
|
if (c == color.NRGBA{0, 0, 0, 0}) {
|
||||||
|
return image.NewNRGBA(image.Rect(0, 0, width, height))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &image.NRGBA{
|
||||||
|
Pix: bytes.Repeat([]byte{c.R, c.G, c.B, c.A}, width*height),
|
||||||
|
Stride: 4 * width,
|
||||||
|
Rect: image.Rect(0, 0, width, height),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone returns a copy of the given image.
|
||||||
|
func Clone(img image.Image) *image.NRGBA {
|
||||||
|
src := newScanner(img)
|
||||||
|
dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
|
||||||
|
size := src.w * 4
|
||||||
|
parallel(0, src.h, func(ys <-chan int) {
|
||||||
|
for y := range ys {
|
||||||
|
i := y * dst.Stride
|
||||||
|
src.scan(0, y, src.w, y+1, dst.Pix[i:i+size])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
// Anchor is the anchor point for image alignment.
|
// Anchor is the anchor point for image alignment.
|
||||||
type Anchor int
|
type Anchor int
|
||||||
|
|
||||||
|
|||||||
29
vendor/github.com/go-ini/ini/file.go
сгенерированный
поставляемый
29
vendor/github.com/go-ini/ini/file.go
сгенерированный
поставляемый
@@ -237,15 +237,20 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
|
|||||||
for i, sname := range f.sectionList {
|
for i, sname := range f.sectionList {
|
||||||
sec := f.Section(sname)
|
sec := f.Section(sname)
|
||||||
if len(sec.Comment) > 0 {
|
if len(sec.Comment) > 0 {
|
||||||
if sec.Comment[0] != '#' && sec.Comment[0] != ';' {
|
// Support multiline comments
|
||||||
sec.Comment = "; " + sec.Comment
|
lines := strings.Split(sec.Comment, LineBreak)
|
||||||
|
for i := range lines {
|
||||||
|
if lines[i][0] != '#' && lines[i][0] != ';' {
|
||||||
|
lines[i] = "; " + lines[i]
|
||||||
} else {
|
} else {
|
||||||
sec.Comment = sec.Comment[:1] + " " + strings.TrimSpace(sec.Comment[1:])
|
lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:])
|
||||||
}
|
}
|
||||||
if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil {
|
|
||||||
|
if _, err := buf.WriteString(lines[i] + LineBreak); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if i > 0 || DefaultHeader {
|
if i > 0 || DefaultHeader {
|
||||||
if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
|
if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
|
||||||
@@ -300,19 +305,21 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
|
|||||||
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
||||||
buf.WriteString(indent)
|
buf.WriteString(indent)
|
||||||
}
|
}
|
||||||
if key.Comment[0] != '#' && key.Comment[0] != ';' {
|
|
||||||
key.Comment = "; " + key.Comment
|
|
||||||
} else {
|
|
||||||
key.Comment = key.Comment[:1] + " " + strings.TrimSpace(key.Comment[1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support multiline comments
|
// Support multiline comments
|
||||||
key.Comment = strings.Replace(key.Comment, "\n", "\n; ", -1)
|
lines := strings.Split(key.Comment, LineBreak)
|
||||||
|
for i := range lines {
|
||||||
|
if lines[i][0] != '#' && lines[i][0] != ';' {
|
||||||
|
lines[i] = "; " + lines[i]
|
||||||
|
} else {
|
||||||
|
lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:])
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := buf.WriteString(key.Comment + LineBreak); err != nil {
|
if _, err := buf.WriteString(lines[i] + LineBreak); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
||||||
buf.WriteString(indent)
|
buf.WriteString(indent)
|
||||||
|
|||||||
4
vendor/github.com/go-ini/ini/ini.go
сгенерированный
поставляемый
4
vendor/github.com/go-ini/ini/ini.go
сгенерированный
поставляемый
@@ -34,7 +34,7 @@ const (
|
|||||||
|
|
||||||
// Maximum allowed depth when recursively substituing variable names.
|
// Maximum allowed depth when recursively substituing variable names.
|
||||||
_DEPTH_VALUES = 99
|
_DEPTH_VALUES = 99
|
||||||
_VERSION = "1.38.1"
|
_VERSION = "1.38.2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version returns current package version literal.
|
// Version returns current package version literal.
|
||||||
@@ -204,7 +204,7 @@ func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) {
|
|||||||
return LoadSources(LoadOptions{Insensitive: true}, source, others...)
|
return LoadSources(LoadOptions{Insensitive: true}, source, others...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsensitiveLoad has exactly same functionality as Load function
|
// ShadowLoad has exactly same functionality as Load function
|
||||||
// except it allows have shadow keys.
|
// except it allows have shadow keys.
|
||||||
func ShadowLoad(source interface{}, others ...interface{}) (*File, error) {
|
func ShadowLoad(source interface{}, others ...interface{}) (*File, error) {
|
||||||
return LoadSources(LoadOptions{AllowShadows: true}, source, others...)
|
return LoadSources(LoadOptions{AllowShadows: true}, source, others...)
|
||||||
|
|||||||
21
vendor/github.com/go-redis/redis/CHANGELOG.md
сгенерированный
поставляемый
Обычный файл
21
vendor/github.com/go-redis/redis/CHANGELOG.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,21 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 6.14
|
||||||
|
|
||||||
|
- Added Options.MinIdleConns.
|
||||||
|
- Added Options.MaxConnAge.
|
||||||
|
- PoolStats.FreeConns is renamed to PoolStats.IdleConns.
|
||||||
|
- Add Client.Do to simplify creating custom commands.
|
||||||
|
- Add Cmd.String, Cmd.Int, Cmd.Int64, Cmd.Uint64, Cmd.Float64, and Cmd.Bool helpers.
|
||||||
|
- Lower memory usage.
|
||||||
|
|
||||||
|
## v6.13
|
||||||
|
|
||||||
|
- Ring got new options called `HashReplicas` and `Hash`. It is recommended to set `HashReplicas = 1000` for better keys distribution between shards.
|
||||||
|
- Cluster client was optimized to use much less memory when reloading cluster state.
|
||||||
|
- PubSub.ReceiveMessage is re-worked to not use ReceiveTimeout so it does not lose data when timeout occurres. In most cases it is recommended to use PubSub.Channel instead.
|
||||||
|
- Dialer.KeepAlive is set to 5 minutes by default.
|
||||||
|
|
||||||
|
## v6.12
|
||||||
|
|
||||||
|
- ClusterClient got new option called `ClusterSlots` which allows to build cluster of normal Redis Servers that don't have cluster mode enabled. See https://godoc.org/github.com/go-redis/redis#example-NewClusterClient--ManualSetup
|
||||||
13
vendor/github.com/go-redis/redis/README.md
сгенерированный
поставляемый
13
vendor/github.com/go-redis/redis/README.md
сгенерированный
поставляемый
@@ -15,6 +15,7 @@ Supports:
|
|||||||
- [Timeouts](https://godoc.org/github.com/go-redis/redis#Options).
|
- [Timeouts](https://godoc.org/github.com/go-redis/redis#Options).
|
||||||
- [Redis Sentinel](https://godoc.org/github.com/go-redis/redis#NewFailoverClient).
|
- [Redis Sentinel](https://godoc.org/github.com/go-redis/redis#NewFailoverClient).
|
||||||
- [Redis Cluster](https://godoc.org/github.com/go-redis/redis#NewClusterClient).
|
- [Redis Cluster](https://godoc.org/github.com/go-redis/redis#NewClusterClient).
|
||||||
|
- [Cluster of Redis Servers](https://godoc.org/github.com/go-redis/redis#example-NewClusterClient--ManualSetup) without using cluster mode and Redis Sentinel.
|
||||||
- [Ring](https://godoc.org/github.com/go-redis/redis#NewRing).
|
- [Ring](https://godoc.org/github.com/go-redis/redis#NewRing).
|
||||||
- [Instrumentation](https://godoc.org/github.com/go-redis/redis#ex-package--Instrumentation).
|
- [Instrumentation](https://godoc.org/github.com/go-redis/redis#ex-package--Instrumentation).
|
||||||
- [Cache friendly](https://github.com/go-redis/cache).
|
- [Cache friendly](https://github.com/go-redis/cache).
|
||||||
@@ -86,13 +87,14 @@ Please go through [examples](https://godoc.org/github.com/go-redis/redis#pkg-exa
|
|||||||
|
|
||||||
Some corner cases:
|
Some corner cases:
|
||||||
|
|
||||||
SET key value EX 10 NX
|
```go
|
||||||
|
// SET key value EX 10 NX
|
||||||
set, err := client.SetNX("key", "value", 10*time.Second).Result()
|
set, err := client.SetNX("key", "value", 10*time.Second).Result()
|
||||||
|
|
||||||
SORT list LIMIT 0 2 ASC
|
// SORT list LIMIT 0 2 ASC
|
||||||
vals, err := client.Sort("list", redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result()
|
vals, err := client.Sort("list", redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result()
|
||||||
|
|
||||||
ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2
|
// ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2
|
||||||
vals, err := client.ZRangeByScoreWithScores("zset", redis.ZRangeBy{
|
vals, err := client.ZRangeByScoreWithScores("zset", redis.ZRangeBy{
|
||||||
Min: "-inf",
|
Min: "-inf",
|
||||||
Max: "+inf",
|
Max: "+inf",
|
||||||
@@ -100,11 +102,12 @@ Some corner cases:
|
|||||||
Count: 2,
|
Count: 2,
|
||||||
}).Result()
|
}).Result()
|
||||||
|
|
||||||
ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM
|
// ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM
|
||||||
vals, err := client.ZInterStore("out", redis.ZStore{Weights: []int64{2, 3}}, "zset1", "zset2").Result()
|
vals, err := client.ZInterStore("out", redis.ZStore{Weights: []int64{2, 3}}, "zset1", "zset2").Result()
|
||||||
|
|
||||||
EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello"
|
// EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello"
|
||||||
vals, err := client.Eval("return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result()
|
vals, err := client.Eval("return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result()
|
||||||
|
```
|
||||||
|
|
||||||
## Benchmark
|
## Benchmark
|
||||||
|
|
||||||
|
|||||||
305
vendor/github.com/go-redis/redis/cluster.go
сгенерированный
поставляемый
305
vendor/github.com/go-redis/redis/cluster.go
сгенерированный
поставляемый
@@ -8,7 +8,8 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -30,7 +31,7 @@ type ClusterOptions struct {
|
|||||||
|
|
||||||
// The maximum number of retries before giving up. Command is retried
|
// The maximum number of retries before giving up. Command is retried
|
||||||
// on network errors and MOVED/ASK redirects.
|
// on network errors and MOVED/ASK redirects.
|
||||||
// Default is 8.
|
// Default is 8 retries.
|
||||||
MaxRedirects int
|
MaxRedirects int
|
||||||
|
|
||||||
// Enables read-only commands on slave nodes.
|
// Enables read-only commands on slave nodes.
|
||||||
@@ -39,16 +40,25 @@ type ClusterOptions struct {
|
|||||||
// It automatically enables ReadOnly.
|
// It automatically enables ReadOnly.
|
||||||
RouteByLatency bool
|
RouteByLatency bool
|
||||||
// Allows routing read-only commands to the random master or slave node.
|
// Allows routing read-only commands to the random master or slave node.
|
||||||
|
// It automatically enables ReadOnly.
|
||||||
RouteRandomly bool
|
RouteRandomly bool
|
||||||
|
|
||||||
|
// Optional function that returns cluster slots information.
|
||||||
|
// It is useful to manually create cluster of standalone Redis servers
|
||||||
|
// and load-balance read/write operations between master and slaves.
|
||||||
|
// It can use service like ZooKeeper to maintain configuration information
|
||||||
|
// and Cluster.ReloadState to manually trigger state reloading.
|
||||||
|
ClusterSlots func() ([]ClusterSlot, error)
|
||||||
|
|
||||||
// Following options are copied from Options struct.
|
// Following options are copied from Options struct.
|
||||||
|
|
||||||
OnConnect func(*Conn) error
|
OnConnect func(*Conn) error
|
||||||
|
|
||||||
|
Password string
|
||||||
|
|
||||||
MaxRetries int
|
MaxRetries int
|
||||||
MinRetryBackoff time.Duration
|
MinRetryBackoff time.Duration
|
||||||
MaxRetryBackoff time.Duration
|
MaxRetryBackoff time.Duration
|
||||||
Password string
|
|
||||||
|
|
||||||
DialTimeout time.Duration
|
DialTimeout time.Duration
|
||||||
ReadTimeout time.Duration
|
ReadTimeout time.Duration
|
||||||
@@ -56,6 +66,8 @@ type ClusterOptions struct {
|
|||||||
|
|
||||||
// PoolSize applies per cluster node and not for the whole cluster.
|
// PoolSize applies per cluster node and not for the whole cluster.
|
||||||
PoolSize int
|
PoolSize int
|
||||||
|
MinIdleConns int
|
||||||
|
MaxConnAge time.Duration
|
||||||
PoolTimeout time.Duration
|
PoolTimeout time.Duration
|
||||||
IdleTimeout time.Duration
|
IdleTimeout time.Duration
|
||||||
IdleCheckFrequency time.Duration
|
IdleCheckFrequency time.Duration
|
||||||
@@ -70,10 +82,14 @@ func (opt *ClusterOptions) init() {
|
|||||||
opt.MaxRedirects = 8
|
opt.MaxRedirects = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.RouteByLatency {
|
if opt.RouteByLatency || opt.RouteRandomly {
|
||||||
opt.ReadOnly = true
|
opt.ReadOnly = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opt.PoolSize == 0 {
|
||||||
|
opt.PoolSize = 5 * runtime.NumCPU()
|
||||||
|
}
|
||||||
|
|
||||||
switch opt.ReadTimeout {
|
switch opt.ReadTimeout {
|
||||||
case -1:
|
case -1:
|
||||||
opt.ReadTimeout = 0
|
opt.ReadTimeout = 0
|
||||||
@@ -118,9 +134,10 @@ func (opt *ClusterOptions) clientOptions() *Options {
|
|||||||
WriteTimeout: opt.WriteTimeout,
|
WriteTimeout: opt.WriteTimeout,
|
||||||
|
|
||||||
PoolSize: opt.PoolSize,
|
PoolSize: opt.PoolSize,
|
||||||
|
MinIdleConns: opt.MinIdleConns,
|
||||||
|
MaxConnAge: opt.MaxConnAge,
|
||||||
PoolTimeout: opt.PoolTimeout,
|
PoolTimeout: opt.PoolTimeout,
|
||||||
IdleTimeout: opt.IdleTimeout,
|
IdleTimeout: opt.IdleTimeout,
|
||||||
|
|
||||||
IdleCheckFrequency: disableIdleCheck,
|
IdleCheckFrequency: disableIdleCheck,
|
||||||
|
|
||||||
TLSConfig: opt.TLSConfig,
|
TLSConfig: opt.TLSConfig,
|
||||||
@@ -160,10 +177,6 @@ func (n *clusterNode) Close() error {
|
|||||||
return n.Client.Close()
|
return n.Client.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *clusterNode) Test() error {
|
|
||||||
return n.Client.ClusterInfo().Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *clusterNode) updateLatency() {
|
func (n *clusterNode) updateLatency() {
|
||||||
const probes = 10
|
const probes = 10
|
||||||
|
|
||||||
@@ -330,7 +343,7 @@ func (c *clusterNodes) GetOrCreate(addr string) (*clusterNode, error) {
|
|||||||
|
|
||||||
v, err := c.nodeCreateGroup.Do(addr, func() (interface{}, error) {
|
v, err := c.nodeCreateGroup.Do(addr, func() (interface{}, error) {
|
||||||
node := newClusterNode(c.opt, addr)
|
node := newClusterNode(c.opt, addr)
|
||||||
return node, node.Test()
|
return node, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
@@ -383,12 +396,31 @@ func (c *clusterNodes) Random() (*clusterNode, error) {
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type clusterSlot struct {
|
||||||
|
start, end int
|
||||||
|
nodes []*clusterNode
|
||||||
|
}
|
||||||
|
|
||||||
|
type clusterSlotSlice []*clusterSlot
|
||||||
|
|
||||||
|
func (p clusterSlotSlice) Len() int {
|
||||||
|
return len(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p clusterSlotSlice) Less(i, j int) bool {
|
||||||
|
return p[i].start < p[j].start
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p clusterSlotSlice) Swap(i, j int) {
|
||||||
|
p[i], p[j] = p[j], p[i]
|
||||||
|
}
|
||||||
|
|
||||||
type clusterState struct {
|
type clusterState struct {
|
||||||
nodes *clusterNodes
|
nodes *clusterNodes
|
||||||
Masters []*clusterNode
|
Masters []*clusterNode
|
||||||
Slaves []*clusterNode
|
Slaves []*clusterNode
|
||||||
|
|
||||||
slots [][]*clusterNode
|
slots []*clusterSlot
|
||||||
|
|
||||||
generation uint32
|
generation uint32
|
||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
@@ -400,19 +432,21 @@ func newClusterState(
|
|||||||
c := clusterState{
|
c := clusterState{
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
|
|
||||||
slots: make([][]*clusterNode, hashtag.SlotNumber),
|
slots: make([]*clusterSlot, 0, len(slots)),
|
||||||
|
|
||||||
generation: nodes.NextGeneration(),
|
generation: nodes.NextGeneration(),
|
||||||
createdAt: time.Now(),
|
createdAt: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoopbackOrigin := isLoopbackAddr(origin)
|
originHost, _, _ := net.SplitHostPort(origin)
|
||||||
|
isLoopbackOrigin := isLoopback(originHost)
|
||||||
|
|
||||||
for _, slot := range slots {
|
for _, slot := range slots {
|
||||||
var nodes []*clusterNode
|
var nodes []*clusterNode
|
||||||
for i, slotNode := range slot.Nodes {
|
for i, slotNode := range slot.Nodes {
|
||||||
addr := slotNode.Addr
|
addr := slotNode.Addr
|
||||||
if !isLoopbackOrigin && useOriginAddr(origin, addr) {
|
if !isLoopbackOrigin {
|
||||||
addr = origin
|
addr = replaceLoopbackHost(addr, originHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := c.nodes.GetOrCreate(addr)
|
node, err := c.nodes.GetOrCreate(addr)
|
||||||
@@ -430,11 +464,15 @@ func newClusterState(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := slot.Start; i <= slot.End; i++ {
|
c.slots = append(c.slots, &clusterSlot{
|
||||||
c.slots[i] = nodes
|
start: slot.Start,
|
||||||
}
|
end: slot.End,
|
||||||
|
nodes: nodes,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Sort(clusterSlotSlice(c.slots))
|
||||||
|
|
||||||
time.AfterFunc(time.Minute, func() {
|
time.AfterFunc(time.Minute, func() {
|
||||||
nodes.GC(c.generation)
|
nodes.GC(c.generation)
|
||||||
})
|
})
|
||||||
@@ -442,6 +480,33 @@ func newClusterState(
|
|||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func replaceLoopbackHost(nodeAddr, originHost string) string {
|
||||||
|
nodeHost, nodePort, err := net.SplitHostPort(nodeAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nodeAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeIP := net.ParseIP(nodeHost)
|
||||||
|
if nodeIP == nil {
|
||||||
|
return nodeAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
if !nodeIP.IsLoopback() {
|
||||||
|
return nodeAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use origin host which is not loopback and node port.
|
||||||
|
return net.JoinHostPort(originHost, nodePort)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isLoopback(host string) bool {
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return ip.IsLoopback()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *clusterState) slotMasterNode(slot int) (*clusterNode, error) {
|
func (c *clusterState) slotMasterNode(slot int) (*clusterNode, error) {
|
||||||
nodes := c.slotNodes(slot)
|
nodes := c.slotNodes(slot)
|
||||||
if len(nodes) > 0 {
|
if len(nodes) > 0 {
|
||||||
@@ -502,33 +567,25 @@ func (c *clusterState) slotRandomNode(slot int) *clusterNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *clusterState) slotNodes(slot int) []*clusterNode {
|
func (c *clusterState) slotNodes(slot int) []*clusterNode {
|
||||||
if slot >= 0 && slot < len(c.slots) {
|
i := sort.Search(len(c.slots), func(i int) bool {
|
||||||
return c.slots[slot]
|
return c.slots[i].end >= slot
|
||||||
|
})
|
||||||
|
if i >= len(c.slots) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
x := c.slots[i]
|
||||||
|
if slot >= x.start && slot <= x.end {
|
||||||
|
return x.nodes
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *clusterState) IsConsistent() bool {
|
func (c *clusterState) IsConsistent() bool {
|
||||||
if len(c.Masters) > len(c.Slaves) {
|
if c.nodes.opt.ClusterSlots != nil {
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, master := range c.Masters {
|
|
||||||
s := master.Client.Info("replication").Val()
|
|
||||||
if !strings.Contains(s, "role:master") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, slave := range c.Slaves {
|
|
||||||
s := slave.Client.Info("replication").Val()
|
|
||||||
if !strings.Contains(s, "role:slave") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
return len(c.Masters) <= len(c.Slaves)
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -555,7 +612,7 @@ func (c *clusterStateHolder) Reload() (*clusterState, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !state.IsConsistent() {
|
if !state.IsConsistent() {
|
||||||
c.LazyReload()
|
time.AfterFunc(time.Second, c.LazyReload)
|
||||||
}
|
}
|
||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
@@ -614,6 +671,14 @@ func (c *clusterStateHolder) Get() (*clusterState, error) {
|
|||||||
return nil, errors.New("redis: cluster has no state")
|
return nil, errors.New("redis: cluster has no state")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *clusterStateHolder) ReloadOrGet() (*clusterState, error) {
|
||||||
|
state, err := c.Reload()
|
||||||
|
if err == nil {
|
||||||
|
return state, nil
|
||||||
|
}
|
||||||
|
return c.Get()
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// ClusterClient is a Redis Cluster client representing a pool of zero
|
// ClusterClient is a Redis Cluster client representing a pool of zero
|
||||||
@@ -653,6 +718,8 @@ func NewClusterClient(opt *ClusterOptions) *ClusterClient {
|
|||||||
c.init()
|
c.init()
|
||||||
|
|
||||||
_, _ = c.state.Reload()
|
_, _ = c.state.Reload()
|
||||||
|
_, _ = c.cmdsInfoCache.Get()
|
||||||
|
|
||||||
if opt.IdleCheckFrequency > 0 {
|
if opt.IdleCheckFrequency > 0 {
|
||||||
go c.reaper(opt.IdleCheckFrequency)
|
go c.reaper(opt.IdleCheckFrequency)
|
||||||
}
|
}
|
||||||
@@ -660,6 +727,13 @@ func NewClusterClient(opt *ClusterOptions) *ClusterClient {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReloadState reloads cluster state. It calls ClusterSlots func
|
||||||
|
// to get cluster slots information.
|
||||||
|
func (c *ClusterClient) ReloadState() error {
|
||||||
|
_, err := c.state.Reload()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) init() {
|
func (c *ClusterClient) init() {
|
||||||
c.cmdable.setProcessor(c.Process)
|
c.cmdable.setProcessor(c.Process)
|
||||||
}
|
}
|
||||||
@@ -818,6 +892,7 @@ func (c *ClusterClient) Watch(fn func(*Tx) error, keys ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if internal.IsRetryableError(err, true) {
|
if internal.IsRetryableError(err, true) {
|
||||||
|
c.state.LazyReload()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,6 +928,13 @@ func (c *ClusterClient) Close() error {
|
|||||||
return c.nodes.Close()
|
return c.nodes.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do creates a Cmd from the args and processes the cmd.
|
||||||
|
func (c *ClusterClient) Do(args ...interface{}) *Cmd {
|
||||||
|
cmd := NewCmd(args...)
|
||||||
|
c.Process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) WrapProcess(
|
func (c *ClusterClient) WrapProcess(
|
||||||
fn func(oldProcess func(Cmder) error) func(Cmder) error,
|
fn func(oldProcess func(Cmder) error) func(Cmder) error,
|
||||||
) {
|
) {
|
||||||
@@ -904,12 +986,14 @@ func (c *ClusterClient) defaultProcess(cmd Cmder) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if internal.IsRetryableError(err, true) {
|
if internal.IsRetryableError(err, true) {
|
||||||
// Firstly retry the same node.
|
c.state.LazyReload()
|
||||||
|
|
||||||
|
// First retry the same node.
|
||||||
if attempt == 0 {
|
if attempt == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Secondly try random node.
|
// Second try random node.
|
||||||
node, err = c.nodes.Random()
|
node, err = c.nodes.Random()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
@@ -944,13 +1028,10 @@ func (c *ClusterClient) defaultProcess(cmd Cmder) error {
|
|||||||
// ForEachMaster concurrently calls the fn on each master node in the cluster.
|
// ForEachMaster concurrently calls the fn on each master node in the cluster.
|
||||||
// It returns the first error if any.
|
// It returns the first error if any.
|
||||||
func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error {
|
func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error {
|
||||||
state, err := c.state.Reload()
|
state, err := c.state.ReloadOrGet()
|
||||||
if err != nil {
|
|
||||||
state, err = c.state.Get()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
@@ -980,13 +1061,10 @@ func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error {
|
|||||||
// ForEachSlave concurrently calls the fn on each slave node in the cluster.
|
// ForEachSlave concurrently calls the fn on each slave node in the cluster.
|
||||||
// It returns the first error if any.
|
// It returns the first error if any.
|
||||||
func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error {
|
func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error {
|
||||||
state, err := c.state.Reload()
|
state, err := c.state.ReloadOrGet()
|
||||||
if err != nil {
|
|
||||||
state, err = c.state.Get()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
@@ -1016,13 +1094,10 @@ func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error {
|
|||||||
// ForEachNode concurrently calls the fn on each known node in the cluster.
|
// ForEachNode concurrently calls the fn on each known node in the cluster.
|
||||||
// It returns the first error if any.
|
// It returns the first error if any.
|
||||||
func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error {
|
func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error {
|
||||||
state, err := c.state.Reload()
|
state, err := c.state.ReloadOrGet()
|
||||||
if err != nil {
|
|
||||||
state, err = c.state.Get()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
@@ -1071,7 +1146,7 @@ func (c *ClusterClient) PoolStats() *PoolStats {
|
|||||||
acc.Timeouts += s.Timeouts
|
acc.Timeouts += s.Timeouts
|
||||||
|
|
||||||
acc.TotalConns += s.TotalConns
|
acc.TotalConns += s.TotalConns
|
||||||
acc.FreeConns += s.FreeConns
|
acc.IdleConns += s.IdleConns
|
||||||
acc.StaleConns += s.StaleConns
|
acc.StaleConns += s.StaleConns
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1082,7 +1157,7 @@ func (c *ClusterClient) PoolStats() *PoolStats {
|
|||||||
acc.Timeouts += s.Timeouts
|
acc.Timeouts += s.Timeouts
|
||||||
|
|
||||||
acc.TotalConns += s.TotalConns
|
acc.TotalConns += s.TotalConns
|
||||||
acc.FreeConns += s.FreeConns
|
acc.IdleConns += s.IdleConns
|
||||||
acc.StaleConns += s.StaleConns
|
acc.StaleConns += s.StaleConns
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,6 +1165,14 @@ func (c *ClusterClient) PoolStats() *PoolStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) loadState() (*clusterState, error) {
|
func (c *ClusterClient) loadState() (*clusterState, error) {
|
||||||
|
if c.opt.ClusterSlots != nil {
|
||||||
|
slots, err := c.opt.ClusterSlots()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newClusterState(c.nodes, slots, "")
|
||||||
|
}
|
||||||
|
|
||||||
addrs, err := c.nodes.Addrs()
|
addrs, err := c.nodes.Addrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1196,7 +1279,7 @@ func (c *ClusterClient) defaultProcessPipeline(cmds []Cmder) error {
|
|||||||
cmdsMap = failedCmds
|
cmdsMap = failedCmds
|
||||||
}
|
}
|
||||||
|
|
||||||
return firstCmdsErr(cmds)
|
return cmdsFirstErr(cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, error) {
|
func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, error) {
|
||||||
@@ -1207,9 +1290,16 @@ func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmdsMap := make(map[*clusterNode][]Cmder)
|
cmdsMap := make(map[*clusterNode][]Cmder)
|
||||||
|
cmdsAreReadOnly := c.cmdsAreReadOnly(cmds)
|
||||||
for _, cmd := range cmds {
|
for _, cmd := range cmds {
|
||||||
|
var node *clusterNode
|
||||||
|
var err error
|
||||||
|
if cmdsAreReadOnly {
|
||||||
|
_, node, err = c.cmdSlotAndNode(cmd)
|
||||||
|
} else {
|
||||||
slot := c.cmdSlot(cmd)
|
slot := c.cmdSlot(cmd)
|
||||||
node, err := state.slotMasterNode(slot)
|
node, err = state.slotMasterNode(slot)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1218,6 +1308,16 @@ func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, e
|
|||||||
return cmdsMap, nil
|
return cmdsMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ClusterClient) cmdsAreReadOnly(cmds []Cmder) bool {
|
||||||
|
for _, cmd := range cmds {
|
||||||
|
cmdInfo := c.cmdInfo(cmd.Name())
|
||||||
|
if cmdInfo == nil || !cmdInfo.ReadOnly {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) remapCmds(cmds []Cmder, failedCmds map[*clusterNode][]Cmder) {
|
func (c *ClusterClient) remapCmds(cmds []Cmder, failedCmds map[*clusterNode][]Cmder) {
|
||||||
remappedCmds, err := c.mapCmdsByNode(cmds)
|
remappedCmds, err := c.mapCmdsByNode(cmds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1233,26 +1333,26 @@ func (c *ClusterClient) remapCmds(cmds []Cmder, failedCmds map[*clusterNode][]Cm
|
|||||||
func (c *ClusterClient) pipelineProcessCmds(
|
func (c *ClusterClient) pipelineProcessCmds(
|
||||||
node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
||||||
) error {
|
) error {
|
||||||
_ = cn.SetWriteTimeout(c.opt.WriteTimeout)
|
err := cn.WithWriter(c.opt.WriteTimeout, func(wr *proto.Writer) error {
|
||||||
|
return writeCmd(wr, cmds...)
|
||||||
err := writeCmd(cn, cmds...)
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setCmdsErr(cmds, err)
|
setCmdsErr(cmds, err)
|
||||||
failedCmds[node] = cmds
|
failedCmds[node] = cmds
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set read timeout for all commands.
|
err = cn.WithReader(c.opt.ReadTimeout, func(rd *proto.Reader) error {
|
||||||
_ = cn.SetReadTimeout(c.opt.ReadTimeout)
|
return c.pipelineReadCmds(rd, cmds, failedCmds)
|
||||||
|
})
|
||||||
return c.pipelineReadCmds(cn, cmds, failedCmds)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) pipelineReadCmds(
|
func (c *ClusterClient) pipelineReadCmds(
|
||||||
cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
rd *proto.Reader, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
||||||
) error {
|
) error {
|
||||||
for _, cmd := range cmds {
|
for _, cmd := range cmds {
|
||||||
err := cmd.readReply(cn)
|
err := cmd.readReply(rd)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1361,7 +1461,7 @@ func (c *ClusterClient) defaultProcessTxPipeline(cmds []Cmder) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return firstCmdsErr(cmds)
|
return cmdsFirstErr(cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) map[int][]Cmder {
|
func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) map[int][]Cmder {
|
||||||
@@ -1376,35 +1476,37 @@ func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) map[int][]Cmder {
|
|||||||
func (c *ClusterClient) txPipelineProcessCmds(
|
func (c *ClusterClient) txPipelineProcessCmds(
|
||||||
node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
||||||
) error {
|
) error {
|
||||||
cn.SetWriteTimeout(c.opt.WriteTimeout)
|
err := cn.WithWriter(c.opt.WriteTimeout, func(wr *proto.Writer) error {
|
||||||
if err := txPipelineWriteMulti(cn, cmds); err != nil {
|
return txPipelineWriteMulti(wr, cmds)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
setCmdsErr(cmds, err)
|
setCmdsErr(cmds, err)
|
||||||
failedCmds[node] = cmds
|
failedCmds[node] = cmds
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set read timeout for all commands.
|
err = cn.WithReader(c.opt.ReadTimeout, func(rd *proto.Reader) error {
|
||||||
cn.SetReadTimeout(c.opt.ReadTimeout)
|
err := c.txPipelineReadQueued(rd, cmds, failedCmds)
|
||||||
|
if err != nil {
|
||||||
if err := c.txPipelineReadQueued(cn, cmds, failedCmds); err != nil {
|
|
||||||
setCmdsErr(cmds, err)
|
setCmdsErr(cmds, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return pipelineReadCmds(rd, cmds)
|
||||||
return pipelineReadCmds(cn, cmds)
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) txPipelineReadQueued(
|
func (c *ClusterClient) txPipelineReadQueued(
|
||||||
cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
rd *proto.Reader, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
||||||
) error {
|
) error {
|
||||||
// Parse queued replies.
|
// Parse queued replies.
|
||||||
var statusCmd StatusCmd
|
var statusCmd StatusCmd
|
||||||
if err := statusCmd.readReply(cn); err != nil {
|
if err := statusCmd.readReply(rd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cmd := range cmds {
|
for _, cmd := range cmds {
|
||||||
err := statusCmd.readReply(cn)
|
err := statusCmd.readReply(rd)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1417,7 +1519,7 @@ func (c *ClusterClient) txPipelineReadQueued(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse number of replies.
|
// Parse number of replies.
|
||||||
line, err := cn.Rd.ReadLine()
|
line, err := rd.ReadLine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == Nil {
|
if err == Nil {
|
||||||
err = TxFailedErr
|
err = TxFailedErr
|
||||||
@@ -1445,11 +1547,9 @@ func (c *ClusterClient) txPipelineReadQueued(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) pubSub(channels []string) *PubSub {
|
func (c *ClusterClient) pubSub(channels []string) *PubSub {
|
||||||
opt := c.opt.clientOptions()
|
|
||||||
|
|
||||||
var node *clusterNode
|
var node *clusterNode
|
||||||
return &PubSub{
|
pubsub := &PubSub{
|
||||||
opt: opt,
|
opt: c.opt.clientOptions(),
|
||||||
|
|
||||||
newConn: func(channels []string) (*pool.Conn, error) {
|
newConn: func(channels []string) (*pool.Conn, error) {
|
||||||
if node == nil {
|
if node == nil {
|
||||||
@@ -1472,6 +1572,8 @@ func (c *ClusterClient) pubSub(channels []string) *PubSub {
|
|||||||
return node.Client.connPool.CloseConn(cn)
|
return node.Client.connPool.CloseConn(cn)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
pubsub.init()
|
||||||
|
return pubsub
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe subscribes the client to the specified channels.
|
// Subscribe subscribes the client to the specified channels.
|
||||||
@@ -1494,43 +1596,6 @@ func (c *ClusterClient) PSubscribe(channels ...string) *PubSub {
|
|||||||
return pubsub
|
return pubsub
|
||||||
}
|
}
|
||||||
|
|
||||||
func useOriginAddr(originAddr, nodeAddr string) bool {
|
|
||||||
nodeHost, nodePort, err := net.SplitHostPort(nodeAddr)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeIP := net.ParseIP(nodeHost)
|
|
||||||
if nodeIP == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !nodeIP.IsLoopback() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
_, originPort, err := net.SplitHostPort(originAddr)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodePort == originPort
|
|
||||||
}
|
|
||||||
|
|
||||||
func isLoopbackAddr(addr string) bool {
|
|
||||||
host, _, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
ip := net.ParseIP(host)
|
|
||||||
if ip == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return ip.IsLoopback()
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendUniqueNode(nodes []*clusterNode, node *clusterNode) []*clusterNode {
|
func appendUniqueNode(nodes []*clusterNode, node *clusterNode) []*clusterNode {
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
if n == node {
|
if n == node {
|
||||||
|
|||||||
954
vendor/github.com/go-redis/redis/command.go
сгенерированный
поставляемый
954
vendor/github.com/go-redis/redis/command.go
сгенерированный
поставляемый
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
296
vendor/github.com/go-redis/redis/commands.go
сгенерированный
поставляемый
296
vendor/github.com/go-redis/redis/commands.go
сгенерированный
поставляемый
@@ -62,6 +62,7 @@ type Cmdable interface {
|
|||||||
TxPipelined(fn func(Pipeliner) error) ([]Cmder, error)
|
TxPipelined(fn func(Pipeliner) error) ([]Cmder, error)
|
||||||
TxPipeline() Pipeliner
|
TxPipeline() Pipeliner
|
||||||
|
|
||||||
|
Command() *CommandsInfoCmd
|
||||||
ClientGetName() *StringCmd
|
ClientGetName() *StringCmd
|
||||||
Echo(message interface{}) *StringCmd
|
Echo(message interface{}) *StringCmd
|
||||||
Ping() *StatusCmd
|
Ping() *StatusCmd
|
||||||
@@ -171,6 +172,26 @@ type Cmdable interface {
|
|||||||
SRem(key string, members ...interface{}) *IntCmd
|
SRem(key string, members ...interface{}) *IntCmd
|
||||||
SUnion(keys ...string) *StringSliceCmd
|
SUnion(keys ...string) *StringSliceCmd
|
||||||
SUnionStore(destination string, keys ...string) *IntCmd
|
SUnionStore(destination string, keys ...string) *IntCmd
|
||||||
|
XAdd(a *XAddArgs) *StringCmd
|
||||||
|
XLen(stream string) *IntCmd
|
||||||
|
XRange(stream, start, stop string) *XMessageSliceCmd
|
||||||
|
XRangeN(stream, start, stop string, count int64) *XMessageSliceCmd
|
||||||
|
XRevRange(stream string, start, stop string) *XMessageSliceCmd
|
||||||
|
XRevRangeN(stream string, start, stop string, count int64) *XMessageSliceCmd
|
||||||
|
XRead(a *XReadArgs) *XStreamSliceCmd
|
||||||
|
XReadStreams(streams ...string) *XStreamSliceCmd
|
||||||
|
XGroupCreate(stream, group, start string) *StatusCmd
|
||||||
|
XGroupSetID(stream, group, start string) *StatusCmd
|
||||||
|
XGroupDestroy(stream, group string) *IntCmd
|
||||||
|
XGroupDelConsumer(stream, group, consumer string) *IntCmd
|
||||||
|
XReadGroup(a *XReadGroupArgs) *XStreamSliceCmd
|
||||||
|
XAck(stream, group string, ids ...string) *IntCmd
|
||||||
|
XPending(stream, group string) *XPendingCmd
|
||||||
|
XPendingExt(a *XPendingExtArgs) *XPendingExtCmd
|
||||||
|
XClaim(a *XClaimArgs) *XMessageSliceCmd
|
||||||
|
XClaimJustID(a *XClaimArgs) *StringSliceCmd
|
||||||
|
XTrim(key string, maxLen int64) *IntCmd
|
||||||
|
XTrimApprox(key string, maxLen int64) *IntCmd
|
||||||
ZAdd(key string, members ...Z) *IntCmd
|
ZAdd(key string, members ...Z) *IntCmd
|
||||||
ZAddNX(key string, members ...Z) *IntCmd
|
ZAddNX(key string, members ...Z) *IntCmd
|
||||||
ZAddXX(key string, members ...Z) *IntCmd
|
ZAddXX(key string, members ...Z) *IntCmd
|
||||||
@@ -209,6 +230,7 @@ type Cmdable interface {
|
|||||||
BgRewriteAOF() *StatusCmd
|
BgRewriteAOF() *StatusCmd
|
||||||
BgSave() *StatusCmd
|
BgSave() *StatusCmd
|
||||||
ClientKill(ipPort string) *StatusCmd
|
ClientKill(ipPort string) *StatusCmd
|
||||||
|
ClientKillByFilter(keys ...string) *IntCmd
|
||||||
ClientList() *StringCmd
|
ClientList() *StringCmd
|
||||||
ClientPause(dur time.Duration) *BoolCmd
|
ClientPause(dur time.Duration) *BoolCmd
|
||||||
ConfigGet(parameter string) *SliceCmd
|
ConfigGet(parameter string) *SliceCmd
|
||||||
@@ -265,9 +287,9 @@ type Cmdable interface {
|
|||||||
GeoRadiusByMemberRO(key, member string, query *GeoRadiusQuery) *GeoLocationCmd
|
GeoRadiusByMemberRO(key, member string, query *GeoRadiusQuery) *GeoLocationCmd
|
||||||
GeoDist(key string, member1, member2, unit string) *FloatCmd
|
GeoDist(key string, member1, member2, unit string) *FloatCmd
|
||||||
GeoHash(key string, members ...string) *StringSliceCmd
|
GeoHash(key string, members ...string) *StringSliceCmd
|
||||||
Command() *CommandsInfoCmd
|
|
||||||
ReadOnly() *StatusCmd
|
ReadOnly() *StatusCmd
|
||||||
ReadWrite() *StatusCmd
|
ReadWrite() *StatusCmd
|
||||||
|
MemoryUsage(key string, samples ...int) *IntCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatefulCmdable interface {
|
type StatefulCmdable interface {
|
||||||
@@ -345,6 +367,12 @@ func (c *statefulCmdable) SwapDB(index1, index2 int) *StatusCmd {
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (c *cmdable) Command() *CommandsInfoCmd {
|
||||||
|
cmd := NewCommandsInfoCmd("command")
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
func (c *cmdable) Del(keys ...string) *IntCmd {
|
func (c *cmdable) Del(keys ...string) *IntCmd {
|
||||||
args := make([]interface{}, 1+len(keys))
|
args := make([]interface{}, 1+len(keys))
|
||||||
args[0] = "del"
|
args[0] = "del"
|
||||||
@@ -411,7 +439,7 @@ func (c *cmdable) Migrate(host, port, key string, db int64, timeout time.Duratio
|
|||||||
db,
|
db,
|
||||||
formatMs(timeout),
|
formatMs(timeout),
|
||||||
)
|
)
|
||||||
cmd.setReadTimeout(readTimeout(timeout))
|
cmd.setReadTimeout(timeout)
|
||||||
c.process(cmd)
|
c.process(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@@ -985,7 +1013,7 @@ func (c *cmdable) BLPop(timeout time.Duration, keys ...string) *StringSliceCmd {
|
|||||||
}
|
}
|
||||||
args[len(args)-1] = formatSec(timeout)
|
args[len(args)-1] = formatSec(timeout)
|
||||||
cmd := NewStringSliceCmd(args...)
|
cmd := NewStringSliceCmd(args...)
|
||||||
cmd.setReadTimeout(readTimeout(timeout))
|
cmd.setReadTimeout(timeout)
|
||||||
c.process(cmd)
|
c.process(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@@ -998,7 +1026,7 @@ func (c *cmdable) BRPop(timeout time.Duration, keys ...string) *StringSliceCmd {
|
|||||||
}
|
}
|
||||||
args[len(keys)+1] = formatSec(timeout)
|
args[len(keys)+1] = formatSec(timeout)
|
||||||
cmd := NewStringSliceCmd(args...)
|
cmd := NewStringSliceCmd(args...)
|
||||||
cmd.setReadTimeout(readTimeout(timeout))
|
cmd.setReadTimeout(timeout)
|
||||||
c.process(cmd)
|
c.process(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1038,7 @@ func (c *cmdable) BRPopLPush(source, destination string, timeout time.Duration)
|
|||||||
destination,
|
destination,
|
||||||
formatSec(timeout),
|
formatSec(timeout),
|
||||||
)
|
)
|
||||||
cmd.setReadTimeout(readTimeout(timeout))
|
cmd.setReadTimeout(timeout)
|
||||||
c.process(cmd)
|
c.process(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@@ -1282,6 +1310,239 @@ func (c *cmdable) SUnionStore(destination string, keys ...string) *IntCmd {
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type XAddArgs struct {
|
||||||
|
Stream string
|
||||||
|
MaxLen int64 // MAXLEN N
|
||||||
|
MaxLenApprox int64 // MAXLEN ~ N
|
||||||
|
ID string
|
||||||
|
Values map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XAdd(a *XAddArgs) *StringCmd {
|
||||||
|
args := make([]interface{}, 0, 6+len(a.Values)*2)
|
||||||
|
args = append(args, "xadd")
|
||||||
|
args = append(args, a.Stream)
|
||||||
|
if a.MaxLen > 0 {
|
||||||
|
args = append(args, "maxlen", a.MaxLen)
|
||||||
|
} else if a.MaxLenApprox > 0 {
|
||||||
|
args = append(args, "maxlen", "~", a.MaxLenApprox)
|
||||||
|
}
|
||||||
|
if a.ID != "" {
|
||||||
|
args = append(args, a.ID)
|
||||||
|
} else {
|
||||||
|
args = append(args, "*")
|
||||||
|
}
|
||||||
|
for k, v := range a.Values {
|
||||||
|
args = append(args, k)
|
||||||
|
args = append(args, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := NewStringCmd(args...)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XLen(stream string) *IntCmd {
|
||||||
|
cmd := NewIntCmd("xlen", stream)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XRange(stream, start, stop string) *XMessageSliceCmd {
|
||||||
|
cmd := NewXMessageSliceCmd("xrange", stream, start, stop)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XRangeN(stream, start, stop string, count int64) *XMessageSliceCmd {
|
||||||
|
cmd := NewXMessageSliceCmd("xrange", stream, start, stop, "count", count)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XRevRange(stream, start, stop string) *XMessageSliceCmd {
|
||||||
|
cmd := NewXMessageSliceCmd("xrevrange", stream, start, stop)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XRevRangeN(stream, start, stop string, count int64) *XMessageSliceCmd {
|
||||||
|
cmd := NewXMessageSliceCmd("xrevrange", stream, start, stop, "count", count)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type XReadArgs struct {
|
||||||
|
Streams []string
|
||||||
|
Count int64
|
||||||
|
Block time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XRead(a *XReadArgs) *XStreamSliceCmd {
|
||||||
|
args := make([]interface{}, 0, 5+len(a.Streams))
|
||||||
|
args = append(args, "xread")
|
||||||
|
if a.Count > 0 {
|
||||||
|
args = append(args, "count")
|
||||||
|
args = append(args, a.Count)
|
||||||
|
}
|
||||||
|
if a.Block >= 0 {
|
||||||
|
args = append(args, "block")
|
||||||
|
args = append(args, int64(a.Block/time.Millisecond))
|
||||||
|
}
|
||||||
|
args = append(args, "streams")
|
||||||
|
for _, s := range a.Streams {
|
||||||
|
args = append(args, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := NewXStreamSliceCmd(args...)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XReadStreams(streams ...string) *XStreamSliceCmd {
|
||||||
|
return c.XRead(&XReadArgs{
|
||||||
|
Streams: streams,
|
||||||
|
Block: -1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XGroupCreate(stream, group, start string) *StatusCmd {
|
||||||
|
cmd := NewStatusCmd("xgroup", "create", stream, group, start)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XGroupSetID(stream, group, start string) *StatusCmd {
|
||||||
|
cmd := NewStatusCmd("xgroup", "setid", stream, group, start)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XGroupDestroy(stream, group string) *IntCmd {
|
||||||
|
cmd := NewIntCmd("xgroup", "destroy", stream, group)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XGroupDelConsumer(stream, group, consumer string) *IntCmd {
|
||||||
|
cmd := NewIntCmd("xgroup", "delconsumer", stream, group, consumer)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type XReadGroupArgs struct {
|
||||||
|
Group string
|
||||||
|
Consumer string
|
||||||
|
Streams []string
|
||||||
|
Count int64
|
||||||
|
Block time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XReadGroup(a *XReadGroupArgs) *XStreamSliceCmd {
|
||||||
|
args := make([]interface{}, 0, 8+len(a.Streams))
|
||||||
|
args = append(args, "xreadgroup", "group", a.Group, a.Consumer)
|
||||||
|
if a.Count > 0 {
|
||||||
|
args = append(args, "count", a.Count)
|
||||||
|
}
|
||||||
|
if a.Block >= 0 {
|
||||||
|
args = append(args, "block", int64(a.Block/time.Millisecond))
|
||||||
|
}
|
||||||
|
args = append(args, "streams")
|
||||||
|
for _, s := range a.Streams {
|
||||||
|
args = append(args, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := NewXStreamSliceCmd(args...)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XAck(stream, group string, ids ...string) *IntCmd {
|
||||||
|
args := []interface{}{"xack", stream, group}
|
||||||
|
for _, id := range ids {
|
||||||
|
args = append(args, id)
|
||||||
|
}
|
||||||
|
cmd := NewIntCmd(args...)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XPending(stream, group string) *XPendingCmd {
|
||||||
|
cmd := NewXPendingCmd("xpending", stream, group)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type XPendingExtArgs struct {
|
||||||
|
Stream string
|
||||||
|
Group string
|
||||||
|
Start string
|
||||||
|
End string
|
||||||
|
Count int64
|
||||||
|
Consumer string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XPendingExt(a *XPendingExtArgs) *XPendingExtCmd {
|
||||||
|
args := make([]interface{}, 0, 7)
|
||||||
|
args = append(args, "xpending", a.Stream, a.Group, a.Start, a.End, a.Count)
|
||||||
|
if a.Consumer != "" {
|
||||||
|
args = append(args, a.Consumer)
|
||||||
|
}
|
||||||
|
cmd := NewXPendingExtCmd(args...)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type XClaimArgs struct {
|
||||||
|
Stream string
|
||||||
|
Group string
|
||||||
|
Consumer string
|
||||||
|
MinIdle time.Duration
|
||||||
|
Messages []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XClaim(a *XClaimArgs) *XMessageSliceCmd {
|
||||||
|
args := xClaimArgs(a)
|
||||||
|
cmd := NewXMessageSliceCmd(args...)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XClaimJustID(a *XClaimArgs) *StringSliceCmd {
|
||||||
|
args := xClaimArgs(a)
|
||||||
|
args = append(args, "justid")
|
||||||
|
cmd := NewStringSliceCmd(args...)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func xClaimArgs(a *XClaimArgs) []interface{} {
|
||||||
|
args := make([]interface{}, 0, 4+len(a.Messages))
|
||||||
|
args = append(args,
|
||||||
|
"xclaim",
|
||||||
|
a.Stream,
|
||||||
|
a.Group, a.Consumer,
|
||||||
|
int64(a.MinIdle/time.Millisecond))
|
||||||
|
for _, id := range a.Messages {
|
||||||
|
args = append(args, id)
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XTrim(key string, maxLen int64) *IntCmd {
|
||||||
|
cmd := NewIntCmd("xtrim", key, "maxlen", maxLen)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmdable) XTrimApprox(key string, maxLen int64) *IntCmd {
|
||||||
|
cmd := NewIntCmd("xtrim", key, "maxlen", "~", maxLen)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Z represents sorted set member.
|
// Z represents sorted set member.
|
||||||
type Z struct {
|
type Z struct {
|
||||||
Score float64
|
Score float64
|
||||||
@@ -1682,6 +1943,20 @@ func (c *cmdable) ClientKill(ipPort string) *StatusCmd {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClientKillByFilter is new style synx, while the ClientKill is old
|
||||||
|
// CLIENT KILL <option> [value] ... <option> [value]
|
||||||
|
func (c *cmdable) ClientKillByFilter(keys ...string) *IntCmd {
|
||||||
|
args := make([]interface{}, 2+len(keys))
|
||||||
|
args[0] = "client"
|
||||||
|
args[1] = "kill"
|
||||||
|
for i, key := range keys {
|
||||||
|
args[2+i] = key
|
||||||
|
}
|
||||||
|
cmd := NewIntCmd(args...)
|
||||||
|
c.process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
func (c *cmdable) ClientList() *StringCmd {
|
func (c *cmdable) ClientList() *StringCmd {
|
||||||
cmd := NewStringCmd("client", "list")
|
cmd := NewStringCmd("client", "list")
|
||||||
c.process(cmd)
|
c.process(cmd)
|
||||||
@@ -2168,8 +2443,15 @@ func (c *cmdable) GeoPos(key string, members ...string) *GeoPosCmd {
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
func (c *cmdable) Command() *CommandsInfoCmd {
|
func (c *cmdable) MemoryUsage(key string, samples ...int) *IntCmd {
|
||||||
cmd := NewCommandsInfoCmd("command")
|
args := []interface{}{"memory", "usage", key}
|
||||||
|
if len(samples) > 0 {
|
||||||
|
if len(samples) != 1 {
|
||||||
|
panic("MemoryUsage expects single sample count")
|
||||||
|
}
|
||||||
|
args = append(args, "SAMPLES", samples[0])
|
||||||
|
}
|
||||||
|
cmd := NewIntCmd(args...)
|
||||||
c.process(cmd)
|
c.process(cmd)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
29
vendor/github.com/go-redis/redis/internal/error.go
сгенерированный
поставляемый
29
vendor/github.com/go-redis/redis/internal/error.go
сгенерированный
поставляемый
@@ -8,9 +8,15 @@ import (
|
|||||||
"github.com/go-redis/redis/internal/proto"
|
"github.com/go-redis/redis/internal/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IsRetryableError(err error, retryNetError bool) bool {
|
func IsRetryableError(err error, retryTimeout bool) bool {
|
||||||
if IsNetworkError(err) {
|
if err == io.EOF {
|
||||||
return retryNetError
|
return true
|
||||||
|
}
|
||||||
|
if netErr, ok := err.(net.Error); ok {
|
||||||
|
if netErr.Timeout() {
|
||||||
|
return retryTimeout
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
s := err.Error()
|
s := err.Error()
|
||||||
if s == "ERR max number of clients reached" {
|
if s == "ERR max number of clients reached" {
|
||||||
@@ -19,6 +25,9 @@ func IsRetryableError(err error, retryNetError bool) bool {
|
|||||||
if strings.HasPrefix(s, "LOADING ") {
|
if strings.HasPrefix(s, "LOADING ") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(s, "READONLY ") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if strings.HasPrefix(s, "CLUSTERDOWN ") {
|
if strings.HasPrefix(s, "CLUSTERDOWN ") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -30,24 +39,12 @@ func IsRedisError(err error) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsNetworkError(err error) bool {
|
|
||||||
if err == io.EOF {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
_, ok := err.(net.Error)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsReadOnlyError(err error) bool {
|
|
||||||
return strings.HasPrefix(err.Error(), "READONLY ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsBadConn(err error, allowTimeout bool) bool {
|
func IsBadConn(err error, allowTimeout bool) bool {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if IsRedisError(err) {
|
if IsRedisError(err) {
|
||||||
return false
|
return strings.HasPrefix(err.Error(), "READONLY ")
|
||||||
}
|
}
|
||||||
if allowTimeout {
|
if allowTimeout {
|
||||||
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||||
|
|||||||
6
vendor/github.com/go-redis/redis/internal/hashtag/hashtag.go
сгенерированный
поставляемый
6
vendor/github.com/go-redis/redis/internal/hashtag/hashtag.go
сгенерированный
поставляемый
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SlotNumber = 16384
|
const slotNumber = 16384
|
||||||
|
|
||||||
// CRC16 implementation according to CCITT standards.
|
// CRC16 implementation according to CCITT standards.
|
||||||
// Copyright 2001-2010 Georges Menie (www.menie.org)
|
// Copyright 2001-2010 Georges Menie (www.menie.org)
|
||||||
@@ -56,7 +56,7 @@ func Key(key string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RandomSlot() int {
|
func RandomSlot() int {
|
||||||
return rand.Intn(SlotNumber)
|
return rand.Intn(slotNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashSlot returns a consistent slot number between 0 and 16383
|
// hashSlot returns a consistent slot number between 0 and 16383
|
||||||
@@ -66,7 +66,7 @@ func Slot(key string) int {
|
|||||||
return RandomSlot()
|
return RandomSlot()
|
||||||
}
|
}
|
||||||
key = Key(key)
|
key = Key(key)
|
||||||
return int(crc16sum(key)) % SlotNumber
|
return int(crc16sum(key)) % slotNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
func crc16sum(key string) (crc uint16) {
|
func crc16sum(key string) (crc uint16) {
|
||||||
|
|||||||
39
vendor/github.com/go-redis/redis/internal/pool/conn.go
сгенерированный
поставляемый
39
vendor/github.com/go-redis/redis/internal/pool/conn.go
сгенерированный
поставляемый
@@ -13,19 +13,21 @@ var noDeadline = time.Time{}
|
|||||||
type Conn struct {
|
type Conn struct {
|
||||||
netConn net.Conn
|
netConn net.Conn
|
||||||
|
|
||||||
Rd *proto.Reader
|
rd *proto.Reader
|
||||||
Wb *proto.WriteBuffer
|
rdLocked bool
|
||||||
|
wr *proto.Writer
|
||||||
|
|
||||||
Inited bool
|
InitedAt time.Time
|
||||||
|
pooled bool
|
||||||
usedAt atomic.Value
|
usedAt atomic.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConn(netConn net.Conn) *Conn {
|
func NewConn(netConn net.Conn) *Conn {
|
||||||
cn := &Conn{
|
cn := &Conn{
|
||||||
netConn: netConn,
|
netConn: netConn,
|
||||||
Wb: proto.NewWriteBuffer(),
|
|
||||||
}
|
}
|
||||||
cn.Rd = proto.NewReader(cn.netConn)
|
cn.rd = proto.NewReader(netConn)
|
||||||
|
cn.wr = proto.NewWriter(netConn)
|
||||||
cn.SetUsedAt(time.Now())
|
cn.SetUsedAt(time.Now())
|
||||||
return cn
|
return cn
|
||||||
}
|
}
|
||||||
@@ -40,14 +42,11 @@ func (cn *Conn) SetUsedAt(tm time.Time) {
|
|||||||
|
|
||||||
func (cn *Conn) SetNetConn(netConn net.Conn) {
|
func (cn *Conn) SetNetConn(netConn net.Conn) {
|
||||||
cn.netConn = netConn
|
cn.netConn = netConn
|
||||||
cn.Rd.Reset(netConn)
|
cn.rd.Reset(netConn)
|
||||||
|
cn.wr.Reset(netConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cn *Conn) IsStale(timeout time.Duration) bool {
|
func (cn *Conn) setReadTimeout(timeout time.Duration) error {
|
||||||
return timeout > 0 && time.Since(cn.UsedAt()) > timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cn *Conn) SetReadTimeout(timeout time.Duration) error {
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
cn.SetUsedAt(now)
|
cn.SetUsedAt(now)
|
||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
@@ -56,7 +55,7 @@ func (cn *Conn) SetReadTimeout(timeout time.Duration) error {
|
|||||||
return cn.netConn.SetReadDeadline(noDeadline)
|
return cn.netConn.SetReadDeadline(noDeadline)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cn *Conn) SetWriteTimeout(timeout time.Duration) error {
|
func (cn *Conn) setWriteTimeout(timeout time.Duration) error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
cn.SetUsedAt(now)
|
cn.SetUsedAt(now)
|
||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
@@ -73,6 +72,22 @@ func (cn *Conn) RemoteAddr() net.Addr {
|
|||||||
return cn.netConn.RemoteAddr()
|
return cn.netConn.RemoteAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cn *Conn) WithReader(timeout time.Duration, fn func(rd *proto.Reader) error) error {
|
||||||
|
_ = cn.setReadTimeout(timeout)
|
||||||
|
return fn(cn.rd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cn *Conn) WithWriter(timeout time.Duration, fn func(wr *proto.Writer) error) error {
|
||||||
|
_ = cn.setWriteTimeout(timeout)
|
||||||
|
|
||||||
|
firstErr := fn(cn.wr)
|
||||||
|
err := cn.wr.Flush()
|
||||||
|
if err != nil && firstErr == nil {
|
||||||
|
firstErr = err
|
||||||
|
}
|
||||||
|
return firstErr
|
||||||
|
}
|
||||||
|
|
||||||
func (cn *Conn) Close() error {
|
func (cn *Conn) Close() error {
|
||||||
return cn.netConn.Close()
|
return cn.netConn.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
126
vendor/github.com/go-redis/redis/internal/pool/pool.go
сгенерированный
поставляемый
126
vendor/github.com/go-redis/redis/internal/pool/pool.go
сгенерированный
поставляемый
@@ -28,7 +28,6 @@ type Stats struct {
|
|||||||
Timeouts uint32 // number of times a wait timeout occurred
|
Timeouts uint32 // number of times a wait timeout occurred
|
||||||
|
|
||||||
TotalConns uint32 // number of total connections in the pool
|
TotalConns uint32 // number of total connections in the pool
|
||||||
FreeConns uint32 // deprecated - use IdleConns
|
|
||||||
IdleConns uint32 // number of idle connections in the pool
|
IdleConns uint32 // number of idle connections in the pool
|
||||||
StaleConns uint32 // number of stale connections removed from the pool
|
StaleConns uint32 // number of stale connections removed from the pool
|
||||||
}
|
}
|
||||||
@@ -53,6 +52,8 @@ type Options struct {
|
|||||||
OnClose func(*Conn) error
|
OnClose func(*Conn) error
|
||||||
|
|
||||||
PoolSize int
|
PoolSize int
|
||||||
|
MinIdleConns int
|
||||||
|
MaxConnAge time.Duration
|
||||||
PoolTimeout time.Duration
|
PoolTimeout time.Duration
|
||||||
IdleTimeout time.Duration
|
IdleTimeout time.Duration
|
||||||
IdleCheckFrequency time.Duration
|
IdleCheckFrequency time.Duration
|
||||||
@@ -63,16 +64,16 @@ type ConnPool struct {
|
|||||||
|
|
||||||
dialErrorsNum uint32 // atomic
|
dialErrorsNum uint32 // atomic
|
||||||
|
|
||||||
lastDialError error
|
|
||||||
lastDialErrorMu sync.RWMutex
|
lastDialErrorMu sync.RWMutex
|
||||||
|
lastDialError error
|
||||||
|
|
||||||
queue chan struct{}
|
queue chan struct{}
|
||||||
|
|
||||||
connsMu sync.Mutex
|
connsMu sync.Mutex
|
||||||
conns []*Conn
|
conns []*Conn
|
||||||
|
|
||||||
idleConnsMu sync.RWMutex
|
|
||||||
idleConns []*Conn
|
idleConns []*Conn
|
||||||
|
poolSize int
|
||||||
|
idleConnsLen int
|
||||||
|
|
||||||
stats Stats
|
stats Stats
|
||||||
|
|
||||||
@@ -90,6 +91,10 @@ func NewConnPool(opt *Options) *ConnPool {
|
|||||||
idleConns: make([]*Conn, 0, opt.PoolSize),
|
idleConns: make([]*Conn, 0, opt.PoolSize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := 0; i < opt.MinIdleConns; i++ {
|
||||||
|
p.checkMinIdleConns()
|
||||||
|
}
|
||||||
|
|
||||||
if opt.IdleTimeout > 0 && opt.IdleCheckFrequency > 0 {
|
if opt.IdleTimeout > 0 && opt.IdleCheckFrequency > 0 {
|
||||||
go p.reaper(opt.IdleCheckFrequency)
|
go p.reaper(opt.IdleCheckFrequency)
|
||||||
}
|
}
|
||||||
@@ -97,19 +102,53 @@ func NewConnPool(opt *Options) *ConnPool {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ConnPool) checkMinIdleConns() {
|
||||||
|
if p.opt.MinIdleConns == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.poolSize < p.opt.PoolSize && p.idleConnsLen < p.opt.MinIdleConns {
|
||||||
|
p.poolSize++
|
||||||
|
p.idleConnsLen++
|
||||||
|
go p.addIdleConn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ConnPool) addIdleConn() {
|
||||||
|
cn, err := p.newConn(true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.connsMu.Lock()
|
||||||
|
p.conns = append(p.conns, cn)
|
||||||
|
p.idleConns = append(p.idleConns, cn)
|
||||||
|
p.connsMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ConnPool) NewConn() (*Conn, error) {
|
func (p *ConnPool) NewConn() (*Conn, error) {
|
||||||
cn, err := p.newConn()
|
return p._NewConn(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ConnPool) _NewConn(pooled bool) (*Conn, error) {
|
||||||
|
cn, err := p.newConn(pooled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p.connsMu.Lock()
|
p.connsMu.Lock()
|
||||||
p.conns = append(p.conns, cn)
|
p.conns = append(p.conns, cn)
|
||||||
|
if pooled {
|
||||||
|
if p.poolSize < p.opt.PoolSize {
|
||||||
|
p.poolSize++
|
||||||
|
} else {
|
||||||
|
cn.pooled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
p.connsMu.Unlock()
|
p.connsMu.Unlock()
|
||||||
return cn, nil
|
return cn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ConnPool) newConn() (*Conn, error) {
|
func (p *ConnPool) newConn(pooled bool) (*Conn, error) {
|
||||||
if p.closed() {
|
if p.closed() {
|
||||||
return nil, ErrClosed
|
return nil, ErrClosed
|
||||||
}
|
}
|
||||||
@@ -127,7 +166,9 @@ func (p *ConnPool) newConn() (*Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewConn(netConn), nil
|
cn := NewConn(netConn)
|
||||||
|
cn.pooled = pooled
|
||||||
|
return cn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ConnPool) tryDial() {
|
func (p *ConnPool) tryDial() {
|
||||||
@@ -174,16 +215,16 @@ func (p *ConnPool) Get() (*Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
p.idleConnsMu.Lock()
|
p.connsMu.Lock()
|
||||||
cn := p.popIdle()
|
cn := p.popIdle()
|
||||||
p.idleConnsMu.Unlock()
|
p.connsMu.Unlock()
|
||||||
|
|
||||||
if cn == nil {
|
if cn == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if cn.IsStale(p.opt.IdleTimeout) {
|
if p.isStaleConn(cn) {
|
||||||
p.CloseConn(cn)
|
_ = p.CloseConn(cn)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +234,7 @@ func (p *ConnPool) Get() (*Conn, error) {
|
|||||||
|
|
||||||
atomic.AddUint32(&p.stats.Misses, 1)
|
atomic.AddUint32(&p.stats.Misses, 1)
|
||||||
|
|
||||||
newcn, err := p.NewConn()
|
newcn, err := p._NewConn(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.freeTurn()
|
p.freeTurn()
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -241,21 +282,21 @@ func (p *ConnPool) popIdle() *Conn {
|
|||||||
idx := len(p.idleConns) - 1
|
idx := len(p.idleConns) - 1
|
||||||
cn := p.idleConns[idx]
|
cn := p.idleConns[idx]
|
||||||
p.idleConns = p.idleConns[:idx]
|
p.idleConns = p.idleConns[:idx]
|
||||||
|
p.idleConnsLen--
|
||||||
|
p.checkMinIdleConns()
|
||||||
return cn
|
return cn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ConnPool) Put(cn *Conn) {
|
func (p *ConnPool) Put(cn *Conn) {
|
||||||
buf := cn.Rd.PeekBuffered()
|
if !cn.pooled {
|
||||||
if buf != nil {
|
|
||||||
internal.Logf("connection has unread data: %.100q", buf)
|
|
||||||
p.Remove(cn)
|
p.Remove(cn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p.idleConnsMu.Lock()
|
p.connsMu.Lock()
|
||||||
p.idleConns = append(p.idleConns, cn)
|
p.idleConns = append(p.idleConns, cn)
|
||||||
p.idleConnsMu.Unlock()
|
p.idleConnsLen++
|
||||||
|
p.connsMu.Unlock()
|
||||||
p.freeTurn()
|
p.freeTurn()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +316,10 @@ func (p *ConnPool) removeConn(cn *Conn) {
|
|||||||
for i, c := range p.conns {
|
for i, c := range p.conns {
|
||||||
if c == cn {
|
if c == cn {
|
||||||
p.conns = append(p.conns[:i], p.conns[i+1:]...)
|
p.conns = append(p.conns[:i], p.conns[i+1:]...)
|
||||||
|
if cn.pooled {
|
||||||
|
p.poolSize--
|
||||||
|
p.checkMinIdleConns()
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,17 +336,17 @@ func (p *ConnPool) closeConn(cn *Conn) error {
|
|||||||
// Len returns total number of connections.
|
// Len returns total number of connections.
|
||||||
func (p *ConnPool) Len() int {
|
func (p *ConnPool) Len() int {
|
||||||
p.connsMu.Lock()
|
p.connsMu.Lock()
|
||||||
l := len(p.conns)
|
n := len(p.conns)
|
||||||
p.connsMu.Unlock()
|
p.connsMu.Unlock()
|
||||||
return l
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// FreeLen returns number of idle connections.
|
// IdleLen returns number of idle connections.
|
||||||
func (p *ConnPool) IdleLen() int {
|
func (p *ConnPool) IdleLen() int {
|
||||||
p.idleConnsMu.RLock()
|
p.connsMu.Lock()
|
||||||
l := len(p.idleConns)
|
n := p.idleConnsLen
|
||||||
p.idleConnsMu.RUnlock()
|
p.connsMu.Unlock()
|
||||||
return l
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ConnPool) Stats() *Stats {
|
func (p *ConnPool) Stats() *Stats {
|
||||||
@@ -312,7 +357,6 @@ func (p *ConnPool) Stats() *Stats {
|
|||||||
Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
|
Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
|
||||||
|
|
||||||
TotalConns: uint32(p.Len()),
|
TotalConns: uint32(p.Len()),
|
||||||
FreeConns: uint32(idleLen),
|
|
||||||
IdleConns: uint32(idleLen),
|
IdleConns: uint32(idleLen),
|
||||||
StaleConns: atomic.LoadUint32(&p.stats.StaleConns),
|
StaleConns: atomic.LoadUint32(&p.stats.StaleConns),
|
||||||
}
|
}
|
||||||
@@ -349,11 +393,10 @@ func (p *ConnPool) Close() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.conns = nil
|
p.conns = nil
|
||||||
p.connsMu.Unlock()
|
p.poolSize = 0
|
||||||
|
|
||||||
p.idleConnsMu.Lock()
|
|
||||||
p.idleConns = nil
|
p.idleConns = nil
|
||||||
p.idleConnsMu.Unlock()
|
p.idleConnsLen = 0
|
||||||
|
p.connsMu.Unlock()
|
||||||
|
|
||||||
return firstErr
|
return firstErr
|
||||||
}
|
}
|
||||||
@@ -364,11 +407,12 @@ func (p *ConnPool) reapStaleConn() *Conn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cn := p.idleConns[0]
|
cn := p.idleConns[0]
|
||||||
if !cn.IsStale(p.opt.IdleTimeout) {
|
if !p.isStaleConn(cn) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...)
|
p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...)
|
||||||
|
p.idleConnsLen--
|
||||||
|
|
||||||
return cn
|
return cn
|
||||||
}
|
}
|
||||||
@@ -378,9 +422,9 @@ func (p *ConnPool) ReapStaleConns() (int, error) {
|
|||||||
for {
|
for {
|
||||||
p.getTurn()
|
p.getTurn()
|
||||||
|
|
||||||
p.idleConnsMu.Lock()
|
p.connsMu.Lock()
|
||||||
cn := p.reapStaleConn()
|
cn := p.reapStaleConn()
|
||||||
p.idleConnsMu.Unlock()
|
p.connsMu.Unlock()
|
||||||
|
|
||||||
if cn != nil {
|
if cn != nil {
|
||||||
p.removeConn(cn)
|
p.removeConn(cn)
|
||||||
@@ -414,3 +458,19 @@ func (p *ConnPool) reaper(frequency time.Duration) {
|
|||||||
atomic.AddUint32(&p.stats.StaleConns, uint32(n))
|
atomic.AddUint32(&p.stats.StaleConns, uint32(n))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ConnPool) isStaleConn(cn *Conn) bool {
|
||||||
|
if p.opt.IdleTimeout == 0 && p.opt.MaxConnAge == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
if p.opt.IdleTimeout > 0 && now.Sub(cn.UsedAt()) >= p.opt.IdleTimeout {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if p.opt.MaxConnAge > 0 && now.Sub(cn.InitedAt) >= p.opt.MaxConnAge {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
214
vendor/github.com/go-redis/redis/internal/proto/reader.go
сгенерированный
поставляемый
214
vendor/github.com/go-redis/redis/internal/proto/reader.go
сгенерированный
поставляемый
@@ -9,8 +9,6 @@ import (
|
|||||||
"github.com/go-redis/redis/internal/util"
|
"github.com/go-redis/redis/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const bytesAllocLimit = 1024 * 1024 // 1mb
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ErrorReply = '-'
|
ErrorReply = '-'
|
||||||
StatusReply = '+'
|
StatusReply = '+'
|
||||||
@@ -32,40 +30,23 @@ func (e RedisError) Error() string { return string(e) }
|
|||||||
type MultiBulkParse func(*Reader, int64) (interface{}, error)
|
type MultiBulkParse func(*Reader, int64) (interface{}, error)
|
||||||
|
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
src *bufio.Reader
|
rd *bufio.Reader
|
||||||
buf []byte
|
_buf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReader(rd io.Reader) *Reader {
|
func NewReader(rd io.Reader) *Reader {
|
||||||
return &Reader{
|
return &Reader{
|
||||||
src: bufio.NewReader(rd),
|
rd: bufio.NewReader(rd),
|
||||||
buf: make([]byte, 4096),
|
_buf: make([]byte, 64),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) Reset(rd io.Reader) {
|
func (r *Reader) Reset(rd io.Reader) {
|
||||||
r.src.Reset(rd)
|
r.rd.Reset(rd)
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) PeekBuffered() []byte {
|
|
||||||
if n := r.src.Buffered(); n != 0 {
|
|
||||||
b, _ := r.src.Peek(n)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) ReadN(n int) ([]byte, error) {
|
|
||||||
b, err := readN(r.src, r.buf, n)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r.buf = b
|
|
||||||
return b, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) ReadLine() ([]byte, error) {
|
func (r *Reader) ReadLine() ([]byte, error) {
|
||||||
line, isPrefix, err := r.src.ReadLine()
|
line, isPrefix, err := r.rd.ReadLine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -91,11 +72,11 @@ func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) {
|
|||||||
case ErrorReply:
|
case ErrorReply:
|
||||||
return nil, ParseErrorReply(line)
|
return nil, ParseErrorReply(line)
|
||||||
case StatusReply:
|
case StatusReply:
|
||||||
return parseStatusValue(line), nil
|
return string(line[1:]), nil
|
||||||
case IntReply:
|
case IntReply:
|
||||||
return util.ParseInt(line[1:], 10, 64)
|
return util.ParseInt(line[1:], 10, 64)
|
||||||
case StringReply:
|
case StringReply:
|
||||||
return r.readTmpBytesValue(line)
|
return r.readStringReply(line)
|
||||||
case ArrayReply:
|
case ArrayReply:
|
||||||
n, err := parseArrayLen(line)
|
n, err := parseArrayLen(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -121,47 +102,42 @@ func (r *Reader) ReadIntReply() (int64, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) ReadTmpBytesReply() ([]byte, error) {
|
func (r *Reader) ReadString() (string, error) {
|
||||||
line, err := r.ReadLine()
|
line, err := r.ReadLine()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch line[0] {
|
|
||||||
case ErrorReply:
|
|
||||||
return nil, ParseErrorReply(line)
|
|
||||||
case StringReply:
|
|
||||||
return r.readTmpBytesValue(line)
|
|
||||||
case StatusReply:
|
|
||||||
return parseStatusValue(line), nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("redis: can't parse string reply: %.100q", line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) ReadBytesReply() ([]byte, error) {
|
|
||||||
b, err := r.ReadTmpBytesReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cp := make([]byte, len(b))
|
|
||||||
copy(cp, b)
|
|
||||||
return cp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) ReadStringReply() (string, error) {
|
|
||||||
b, err := r.ReadTmpBytesReply()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(b), nil
|
switch line[0] {
|
||||||
|
case ErrorReply:
|
||||||
|
return "", ParseErrorReply(line)
|
||||||
|
case StringReply:
|
||||||
|
return r.readStringReply(line)
|
||||||
|
case StatusReply:
|
||||||
|
return string(line[1:]), nil
|
||||||
|
case IntReply:
|
||||||
|
return string(line[1:]), nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("redis: can't parse reply=%.100q reading string", line)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) ReadFloatReply() (float64, error) {
|
func (r *Reader) readStringReply(line []byte) (string, error) {
|
||||||
b, err := r.ReadTmpBytesReply()
|
if isNilReply(line) {
|
||||||
if err != nil {
|
return "", Nil
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
return util.ParseFloat(b, 64)
|
|
||||||
|
replyLen, err := strconv.Atoi(string(line[1:]))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, replyLen+2)
|
||||||
|
_, err = io.ReadFull(r.rd, b)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.BytesToString(b[:replyLen]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) ReadArrayReply(m MultiBulkParse) (interface{}, error) {
|
func (r *Reader) ReadArrayReply(m MultiBulkParse) (interface{}, error) {
|
||||||
@@ -219,7 +195,7 @@ func (r *Reader) ReadScanReply() ([]string, uint64, error) {
|
|||||||
|
|
||||||
keys := make([]string, n)
|
keys := make([]string, n)
|
||||||
for i := int64(0); i < n; i++ {
|
for i := int64(0); i < n; i++ {
|
||||||
key, err := r.ReadStringReply()
|
key, err := r.ReadString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@@ -229,7 +205,48 @@ func (r *Reader) ReadScanReply() ([]string, uint64, error) {
|
|||||||
return keys, cursor, err
|
return keys, cursor, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) readTmpBytesValue(line []byte) ([]byte, error) {
|
func (r *Reader) ReadInt() (int64, error) {
|
||||||
|
b, err := r.readTmpBytesReply()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return util.ParseInt(b, 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) ReadUint() (uint64, error) {
|
||||||
|
b, err := r.readTmpBytesReply()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return util.ParseUint(b, 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) ReadFloatReply() (float64, error) {
|
||||||
|
b, err := r.readTmpBytesReply()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return util.ParseFloat(b, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) readTmpBytesReply() ([]byte, error) {
|
||||||
|
line, err := r.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch line[0] {
|
||||||
|
case ErrorReply:
|
||||||
|
return nil, ParseErrorReply(line)
|
||||||
|
case StringReply:
|
||||||
|
return r._readTmpBytesReply(line)
|
||||||
|
case StatusReply:
|
||||||
|
return line[1:], nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("redis: can't parse string reply: %.100q", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) _readTmpBytesReply(line []byte) ([]byte, error) {
|
||||||
if isNilReply(line) {
|
if isNilReply(line) {
|
||||||
return nil, Nil
|
return nil, Nil
|
||||||
}
|
}
|
||||||
@@ -239,71 +256,20 @@ func (r *Reader) readTmpBytesValue(line []byte) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := r.ReadN(replyLen + 2)
|
buf := r.buf(replyLen + 2)
|
||||||
|
_, err = io.ReadFull(r.rd, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return b[:replyLen], nil
|
|
||||||
|
return buf[:replyLen], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reader) ReadInt() (int64, error) {
|
func (r *Reader) buf(n int) []byte {
|
||||||
b, err := r.ReadTmpBytesReply()
|
if d := n - cap(r._buf); d > 0 {
|
||||||
if err != nil {
|
r._buf = append(r._buf, make([]byte, d)...)
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
return util.ParseInt(b, 10, 64)
|
return r._buf[:n]
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reader) ReadUint() (uint64, error) {
|
|
||||||
b, err := r.ReadTmpBytesReply()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return util.ParseUint(b, 10, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
|
||||||
|
|
||||||
func readN(r io.Reader, b []byte, n int) ([]byte, error) {
|
|
||||||
if n == 0 && b == nil {
|
|
||||||
return make([]byte, 0), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if cap(b) >= n {
|
|
||||||
b = b[:n]
|
|
||||||
_, err := io.ReadFull(r, b)
|
|
||||||
return b, err
|
|
||||||
}
|
|
||||||
b = b[:cap(b)]
|
|
||||||
|
|
||||||
pos := 0
|
|
||||||
for pos < n {
|
|
||||||
diff := n - len(b)
|
|
||||||
if diff > bytesAllocLimit {
|
|
||||||
diff = bytesAllocLimit
|
|
||||||
}
|
|
||||||
b = append(b, make([]byte, diff)...)
|
|
||||||
|
|
||||||
nn, err := io.ReadFull(r, b[pos:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pos += nn
|
|
||||||
}
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatInt(n int64) string {
|
|
||||||
return strconv.FormatInt(n, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatUint(u uint64) string {
|
|
||||||
return strconv.FormatUint(u, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatFloat(f float64) string {
|
|
||||||
return strconv.FormatFloat(f, 'f', -1, 64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isNilReply(b []byte) bool {
|
func isNilReply(b []byte) bool {
|
||||||
@@ -316,10 +282,6 @@ func ParseErrorReply(line []byte) error {
|
|||||||
return RedisError(string(line[1:]))
|
return RedisError(string(line[1:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseStatusValue(line []byte) []byte {
|
|
||||||
return line[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseArrayLen(line []byte) (int64, error) {
|
func parseArrayLen(line []byte) (int64, error) {
|
||||||
if isNilReply(line) {
|
if isNilReply(line) {
|
||||||
return 0, Nil
|
return 0, Nil
|
||||||
|
|||||||
101
vendor/github.com/go-redis/redis/internal/proto/write_buffer.go
сгенерированный
поставляемый
101
vendor/github.com/go-redis/redis/internal/proto/write_buffer.go
сгенерированный
поставляемый
@@ -1,101 +0,0 @@
|
|||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type WriteBuffer struct {
|
|
||||||
b []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewWriteBuffer() *WriteBuffer {
|
|
||||||
return &WriteBuffer{
|
|
||||||
b: make([]byte, 0, 4096),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WriteBuffer) Len() int { return len(w.b) }
|
|
||||||
func (w *WriteBuffer) Bytes() []byte { return w.b }
|
|
||||||
func (w *WriteBuffer) Reset() { w.b = w.b[:0] }
|
|
||||||
|
|
||||||
func (w *WriteBuffer) Append(args []interface{}) error {
|
|
||||||
w.b = append(w.b, ArrayReply)
|
|
||||||
w.b = strconv.AppendUint(w.b, uint64(len(args)), 10)
|
|
||||||
w.b = append(w.b, '\r', '\n')
|
|
||||||
|
|
||||||
for _, arg := range args {
|
|
||||||
if err := w.append(arg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WriteBuffer) append(val interface{}) error {
|
|
||||||
switch v := val.(type) {
|
|
||||||
case nil:
|
|
||||||
w.AppendString("")
|
|
||||||
case string:
|
|
||||||
w.AppendString(v)
|
|
||||||
case []byte:
|
|
||||||
w.AppendBytes(v)
|
|
||||||
case int:
|
|
||||||
w.AppendString(formatInt(int64(v)))
|
|
||||||
case int8:
|
|
||||||
w.AppendString(formatInt(int64(v)))
|
|
||||||
case int16:
|
|
||||||
w.AppendString(formatInt(int64(v)))
|
|
||||||
case int32:
|
|
||||||
w.AppendString(formatInt(int64(v)))
|
|
||||||
case int64:
|
|
||||||
w.AppendString(formatInt(v))
|
|
||||||
case uint:
|
|
||||||
w.AppendString(formatUint(uint64(v)))
|
|
||||||
case uint8:
|
|
||||||
w.AppendString(formatUint(uint64(v)))
|
|
||||||
case uint16:
|
|
||||||
w.AppendString(formatUint(uint64(v)))
|
|
||||||
case uint32:
|
|
||||||
w.AppendString(formatUint(uint64(v)))
|
|
||||||
case uint64:
|
|
||||||
w.AppendString(formatUint(v))
|
|
||||||
case float32:
|
|
||||||
w.AppendString(formatFloat(float64(v)))
|
|
||||||
case float64:
|
|
||||||
w.AppendString(formatFloat(v))
|
|
||||||
case bool:
|
|
||||||
if v {
|
|
||||||
w.AppendString("1")
|
|
||||||
} else {
|
|
||||||
w.AppendString("0")
|
|
||||||
}
|
|
||||||
case encoding.BinaryMarshaler:
|
|
||||||
b, err := v.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.AppendBytes(b)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf(
|
|
||||||
"redis: can't marshal %T (consider implementing encoding.BinaryMarshaler)", val)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WriteBuffer) AppendString(s string) {
|
|
||||||
w.b = append(w.b, StringReply)
|
|
||||||
w.b = strconv.AppendUint(w.b, uint64(len(s)), 10)
|
|
||||||
w.b = append(w.b, '\r', '\n')
|
|
||||||
w.b = append(w.b, s...)
|
|
||||||
w.b = append(w.b, '\r', '\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WriteBuffer) AppendBytes(p []byte) {
|
|
||||||
w.b = append(w.b, StringReply)
|
|
||||||
w.b = strconv.AppendUint(w.b, uint64(len(p)), 10)
|
|
||||||
w.b = append(w.b, '\r', '\n')
|
|
||||||
w.b = append(w.b, p...)
|
|
||||||
w.b = append(w.b, '\r', '\n')
|
|
||||||
}
|
|
||||||
159
vendor/github.com/go-redis/redis/internal/proto/writer.go
сгенерированный
поставляемый
Обычный файл
159
vendor/github.com/go-redis/redis/internal/proto/writer.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,159 @@
|
|||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Writer struct {
|
||||||
|
wr *bufio.Writer
|
||||||
|
|
||||||
|
lenBuf []byte
|
||||||
|
numBuf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWriter(wr io.Writer) *Writer {
|
||||||
|
return &Writer{
|
||||||
|
wr: bufio.NewWriter(wr),
|
||||||
|
|
||||||
|
lenBuf: make([]byte, 64),
|
||||||
|
numBuf: make([]byte, 64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) WriteArgs(args []interface{}) error {
|
||||||
|
err := w.wr.WriteByte(ArrayReply)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.writeLen(len(args))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range args {
|
||||||
|
err := w.writeArg(arg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) writeLen(n int) error {
|
||||||
|
w.lenBuf = strconv.AppendUint(w.lenBuf[:0], uint64(n), 10)
|
||||||
|
w.lenBuf = append(w.lenBuf, '\r', '\n')
|
||||||
|
_, err := w.wr.Write(w.lenBuf)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) writeArg(v interface{}) error {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case nil:
|
||||||
|
return w.string("")
|
||||||
|
case string:
|
||||||
|
return w.string(v)
|
||||||
|
case []byte:
|
||||||
|
return w.bytes(v)
|
||||||
|
case int:
|
||||||
|
return w.int(int64(v))
|
||||||
|
case int8:
|
||||||
|
return w.int(int64(v))
|
||||||
|
case int16:
|
||||||
|
return w.int(int64(v))
|
||||||
|
case int32:
|
||||||
|
return w.int(int64(v))
|
||||||
|
case int64:
|
||||||
|
return w.int(v)
|
||||||
|
case uint:
|
||||||
|
return w.uint(uint64(v))
|
||||||
|
case uint8:
|
||||||
|
return w.uint(uint64(v))
|
||||||
|
case uint16:
|
||||||
|
return w.uint(uint64(v))
|
||||||
|
case uint32:
|
||||||
|
return w.uint(uint64(v))
|
||||||
|
case uint64:
|
||||||
|
return w.uint(v)
|
||||||
|
case float32:
|
||||||
|
return w.float(float64(v))
|
||||||
|
case float64:
|
||||||
|
return w.float(v)
|
||||||
|
case bool:
|
||||||
|
if v {
|
||||||
|
return w.int(1)
|
||||||
|
} else {
|
||||||
|
return w.int(0)
|
||||||
|
}
|
||||||
|
case encoding.BinaryMarshaler:
|
||||||
|
b, err := v.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return w.bytes(b)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf(
|
||||||
|
"redis: can't marshal %T (implement encoding.BinaryMarshaler)", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) bytes(b []byte) error {
|
||||||
|
err := w.wr.WriteByte(StringReply)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.writeLen(len(b))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.wr.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.crlf()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) string(s string) error {
|
||||||
|
return w.bytes(util.StringToBytes(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) uint(n uint64) error {
|
||||||
|
w.numBuf = strconv.AppendUint(w.numBuf[:0], n, 10)
|
||||||
|
return w.bytes(w.numBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) int(n int64) error {
|
||||||
|
w.numBuf = strconv.AppendInt(w.numBuf[:0], n, 10)
|
||||||
|
return w.bytes(w.numBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) float(f float64) error {
|
||||||
|
w.numBuf = strconv.AppendFloat(w.numBuf[:0], f, 'f', -1, 64)
|
||||||
|
return w.bytes(w.numBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) crlf() error {
|
||||||
|
err := w.wr.WriteByte('\r')
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return w.wr.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) Reset(wr io.Writer) {
|
||||||
|
w.wr.Reset(wr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) Flush() error {
|
||||||
|
return w.wr.Flush()
|
||||||
|
}
|
||||||
4
vendor/github.com/go-redis/redis/internal/util/safe.go
сгенерированный
поставляемый
4
vendor/github.com/go-redis/redis/internal/util/safe.go
сгенерированный
поставляемый
@@ -5,3 +5,7 @@ package util
|
|||||||
func BytesToString(b []byte) string {
|
func BytesToString(b []byte) string {
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StringToBytes(s string) []byte {
|
||||||
|
return []byte(s)
|
||||||
|
}
|
||||||
|
|||||||
10
vendor/github.com/go-redis/redis/internal/util/unsafe.go
сгенерированный
поставляемый
10
vendor/github.com/go-redis/redis/internal/util/unsafe.go
сгенерированный
поставляемый
@@ -10,3 +10,13 @@ import (
|
|||||||
func BytesToString(b []byte) string {
|
func BytesToString(b []byte) string {
|
||||||
return *(*string)(unsafe.Pointer(&b))
|
return *(*string)(unsafe.Pointer(&b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StringToBytes converts string to byte slice.
|
||||||
|
func StringToBytes(s string) []byte {
|
||||||
|
return *(*[]byte)(unsafe.Pointer(
|
||||||
|
&struct {
|
||||||
|
string
|
||||||
|
Cap int
|
||||||
|
}{s, len(s)},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|||||||
29
vendor/github.com/go-redis/redis/options.go
сгенерированный
поставляемый
29
vendor/github.com/go-redis/redis/options.go
сгенерированный
поставляемый
@@ -59,16 +59,24 @@ type Options struct {
|
|||||||
// Maximum number of socket connections.
|
// Maximum number of socket connections.
|
||||||
// Default is 10 connections per every CPU as reported by runtime.NumCPU.
|
// Default is 10 connections per every CPU as reported by runtime.NumCPU.
|
||||||
PoolSize int
|
PoolSize int
|
||||||
|
// Minimum number of idle connections which is useful when establishing
|
||||||
|
// new connection is slow.
|
||||||
|
MinIdleConns int
|
||||||
|
// Connection age at which client retires (closes) the connection.
|
||||||
|
// Default is to not close aged connections.
|
||||||
|
MaxConnAge time.Duration
|
||||||
// Amount of time client waits for connection if all connections
|
// Amount of time client waits for connection if all connections
|
||||||
// are busy before returning an error.
|
// are busy before returning an error.
|
||||||
// Default is ReadTimeout + 1 second.
|
// Default is ReadTimeout + 1 second.
|
||||||
PoolTimeout time.Duration
|
PoolTimeout time.Duration
|
||||||
// Amount of time after which client closes idle connections.
|
// Amount of time after which client closes idle connections.
|
||||||
// Should be less than server's timeout.
|
// Should be less than server's timeout.
|
||||||
// Default is 5 minutes.
|
// Default is 5 minutes. -1 disables idle timeout check.
|
||||||
IdleTimeout time.Duration
|
IdleTimeout time.Duration
|
||||||
// Frequency of idle checks.
|
// Frequency of idle checks made by idle connections reaper.
|
||||||
// Default is 1 minute. -1 disables idle check.
|
// Default is 1 minute. -1 disables idle connections reaper,
|
||||||
|
// but idle connections are still discarded by the client
|
||||||
|
// if IdleTimeout is set.
|
||||||
IdleCheckFrequency time.Duration
|
IdleCheckFrequency time.Duration
|
||||||
|
|
||||||
// Enables read only queries on slave nodes.
|
// Enables read only queries on slave nodes.
|
||||||
@@ -84,12 +92,15 @@ func (opt *Options) init() {
|
|||||||
}
|
}
|
||||||
if opt.Dialer == nil {
|
if opt.Dialer == nil {
|
||||||
opt.Dialer = func() (net.Conn, error) {
|
opt.Dialer = func() (net.Conn, error) {
|
||||||
conn, err := net.DialTimeout(opt.Network, opt.Addr, opt.DialTimeout)
|
netDialer := &net.Dialer{
|
||||||
if opt.TLSConfig == nil || err != nil {
|
Timeout: opt.DialTimeout,
|
||||||
return conn, err
|
KeepAlive: 5 * time.Minute,
|
||||||
|
}
|
||||||
|
if opt.TLSConfig == nil {
|
||||||
|
return netDialer.Dial(opt.Network, opt.Addr)
|
||||||
|
} else {
|
||||||
|
return tls.DialWithDialer(netDialer, opt.Network, opt.Addr, opt.TLSConfig)
|
||||||
}
|
}
|
||||||
t := tls.Client(conn, opt.TLSConfig)
|
|
||||||
return t, t.Handshake()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if opt.PoolSize == 0 {
|
if opt.PoolSize == 0 {
|
||||||
@@ -192,6 +203,8 @@ func newConnPool(opt *Options) *pool.ConnPool {
|
|||||||
return pool.NewConnPool(&pool.Options{
|
return pool.NewConnPool(&pool.Options{
|
||||||
Dialer: opt.Dialer,
|
Dialer: opt.Dialer,
|
||||||
PoolSize: opt.PoolSize,
|
PoolSize: opt.PoolSize,
|
||||||
|
MinIdleConns: opt.MinIdleConns,
|
||||||
|
MaxConnAge: opt.MaxConnAge,
|
||||||
PoolTimeout: opt.PoolTimeout,
|
PoolTimeout: opt.PoolTimeout,
|
||||||
IdleTimeout: opt.IdleTimeout,
|
IdleTimeout: opt.IdleTimeout,
|
||||||
IdleCheckFrequency: opt.IdleCheckFrequency,
|
IdleCheckFrequency: opt.IdleCheckFrequency,
|
||||||
|
|||||||
394
vendor/github.com/go-redis/redis/parser.go
сгенерированный
поставляемый
394
vendor/github.com/go-redis/redis/parser.go
сгенерированный
поставляемый
@@ -1,394 +0,0 @@
|
|||||||
package redis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-redis/redis/internal/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func sliceParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
vals := make([]interface{}, 0, n)
|
|
||||||
for i := int64(0); i < n; i++ {
|
|
||||||
v, err := rd.ReadReply(sliceParser)
|
|
||||||
if err != nil {
|
|
||||||
if err == Nil {
|
|
||||||
vals = append(vals, nil)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err, ok := err.(proto.RedisError); ok {
|
|
||||||
vals = append(vals, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v := v.(type) {
|
|
||||||
case []byte:
|
|
||||||
vals = append(vals, string(v))
|
|
||||||
default:
|
|
||||||
vals = append(vals, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vals, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func boolSliceParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
bools := make([]bool, 0, n)
|
|
||||||
for i := int64(0); i < n; i++ {
|
|
||||||
n, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
bools = append(bools, n == 1)
|
|
||||||
}
|
|
||||||
return bools, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func stringSliceParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
ss := make([]string, 0, n)
|
|
||||||
for i := int64(0); i < n; i++ {
|
|
||||||
s, err := rd.ReadStringReply()
|
|
||||||
if err == Nil {
|
|
||||||
ss = append(ss, "")
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
ss = append(ss, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ss, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func stringStringMapParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
m := make(map[string]string, n/2)
|
|
||||||
for i := int64(0); i < n; i += 2 {
|
|
||||||
key, err := rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
value, err := rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
m[key] = value
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func stringIntMapParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
m := make(map[string]int64, n/2)
|
|
||||||
for i := int64(0); i < n; i += 2 {
|
|
||||||
key, err := rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
m[key] = n
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func stringStructMapParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
m := make(map[string]struct{}, n)
|
|
||||||
for i := int64(0); i < n; i++ {
|
|
||||||
key, err := rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
m[key] = struct{}{}
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func zSliceParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
zz := make([]Z, n/2)
|
|
||||||
for i := int64(0); i < n; i += 2 {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
z := &zz[i/2]
|
|
||||||
|
|
||||||
z.Member, err = rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
z.Score, err = rd.ReadFloatReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return zz, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func clusterSlotsParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
slots := make([]ClusterSlot, n)
|
|
||||||
for i := 0; i < len(slots); i++ {
|
|
||||||
n, err := rd.ReadArrayLen()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n < 2 {
|
|
||||||
err := fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
start, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
end, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes := make([]ClusterNode, n-2)
|
|
||||||
for j := 0; j < len(nodes); j++ {
|
|
||||||
n, err := rd.ReadArrayLen()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n != 2 && n != 3 {
|
|
||||||
err := fmt.Errorf("got %d elements in cluster info address, expected 2 or 3", n)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ip, err := rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
port, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nodes[j].Addr = net.JoinHostPort(ip, strconv.FormatInt(port, 10))
|
|
||||||
|
|
||||||
if n == 3 {
|
|
||||||
id, err := rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nodes[j].Id = id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slots[i] = ClusterSlot{
|
|
||||||
Start: int(start),
|
|
||||||
End: int(end),
|
|
||||||
Nodes: nodes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return slots, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newGeoLocationParser(q *GeoRadiusQuery) proto.MultiBulkParse {
|
|
||||||
return func(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
var loc GeoLocation
|
|
||||||
var err error
|
|
||||||
|
|
||||||
loc.Name, err = rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if q.WithDist {
|
|
||||||
loc.Dist, err = rd.ReadFloatReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if q.WithGeoHash {
|
|
||||||
loc.GeoHash, err = rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if q.WithCoord {
|
|
||||||
n, err := rd.ReadArrayLen()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n != 2 {
|
|
||||||
return nil, fmt.Errorf("got %d coordinates, expected 2", n)
|
|
||||||
}
|
|
||||||
|
|
||||||
loc.Longitude, err = rd.ReadFloatReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
loc.Latitude, err = rd.ReadFloatReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &loc, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newGeoLocationSliceParser(q *GeoRadiusQuery) proto.MultiBulkParse {
|
|
||||||
return func(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
locs := make([]GeoLocation, 0, n)
|
|
||||||
for i := int64(0); i < n; i++ {
|
|
||||||
v, err := rd.ReadReply(newGeoLocationParser(q))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch vv := v.(type) {
|
|
||||||
case []byte:
|
|
||||||
locs = append(locs, GeoLocation{
|
|
||||||
Name: string(vv),
|
|
||||||
})
|
|
||||||
case *GeoLocation:
|
|
||||||
locs = append(locs, *vv)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("got %T, expected string or *GeoLocation", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return locs, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func geoPosParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
var pos GeoPos
|
|
||||||
var err error
|
|
||||||
|
|
||||||
pos.Longitude, err = rd.ReadFloatReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pos.Latitude, err = rd.ReadFloatReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &pos, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func geoPosSliceParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
positions := make([]*GeoPos, 0, n)
|
|
||||||
for i := int64(0); i < n; i++ {
|
|
||||||
v, err := rd.ReadReply(geoPosParser)
|
|
||||||
if err != nil {
|
|
||||||
if err == Nil {
|
|
||||||
positions = append(positions, nil)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch v := v.(type) {
|
|
||||||
case *GeoPos:
|
|
||||||
positions = append(positions, v)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("got %T, expected *GeoPos", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return positions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
var cmd CommandInfo
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if n != 6 {
|
|
||||||
return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 6", n)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Name, err = rd.ReadStringReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
arity, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cmd.Arity = int8(arity)
|
|
||||||
|
|
||||||
flags, err := rd.ReadReply(stringSliceParser)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cmd.Flags = flags.([]string)
|
|
||||||
|
|
||||||
firstKeyPos, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cmd.FirstKeyPos = int8(firstKeyPos)
|
|
||||||
|
|
||||||
lastKeyPos, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cmd.LastKeyPos = int8(lastKeyPos)
|
|
||||||
|
|
||||||
stepCount, err := rd.ReadIntReply()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cmd.StepCount = int8(stepCount)
|
|
||||||
|
|
||||||
for _, flag := range cmd.Flags {
|
|
||||||
if flag == "readonly" {
|
|
||||||
cmd.ReadOnly = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cmd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func commandInfoSliceParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
m := make(map[string]*CommandInfo, n)
|
|
||||||
for i := int64(0); i < n; i++ {
|
|
||||||
v, err := rd.ReadReply(commandInfoParser)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
vv := v.(*CommandInfo)
|
|
||||||
m[vv.Name] = vv
|
|
||||||
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements proto.MultiBulkParse
|
|
||||||
func timeParser(rd *proto.Reader, n int64) (interface{}, error) {
|
|
||||||
if n != 2 {
|
|
||||||
return nil, fmt.Errorf("got %d elements, expected 2", n)
|
|
||||||
}
|
|
||||||
|
|
||||||
sec, err := rd.ReadInt()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
microsec, err := rd.ReadInt()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return time.Unix(sec, microsec*1000), nil
|
|
||||||
}
|
|
||||||
1
vendor/github.com/go-redis/redis/pipeline.go
сгенерированный
поставляемый
1
vendor/github.com/go-redis/redis/pipeline.go
сгенерированный
поставляемый
@@ -31,6 +31,7 @@ type Pipeline struct {
|
|||||||
closed bool
|
closed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process queues the cmd for later execution.
|
||||||
func (c *Pipeline) Process(cmd Cmder) error {
|
func (c *Pipeline) Process(cmd Cmder) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.cmds = append(c.cmds, cmd)
|
c.cmds = append(c.cmds, cmd)
|
||||||
|
|||||||
292
vendor/github.com/go-redis/redis/pubsub.go
сгенерированный
поставляемый
292
vendor/github.com/go-redis/redis/pubsub.go
сгенерированный
поставляемый
@@ -2,20 +2,20 @@ package redis
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-redis/redis/internal"
|
"github.com/go-redis/redis/internal"
|
||||||
"github.com/go-redis/redis/internal/pool"
|
"github.com/go-redis/redis/internal/pool"
|
||||||
|
"github.com/go-redis/redis/internal/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PubSub implements Pub/Sub commands as described in
|
// PubSub implements Pub/Sub commands bas described in
|
||||||
// http://redis.io/topics/pubsub. It's NOT safe for concurrent use by
|
// http://redis.io/topics/pubsub. Message receiving is NOT safe
|
||||||
// multiple goroutines.
|
// for concurrent use by multiple goroutines.
|
||||||
//
|
//
|
||||||
// PubSub automatically resubscribes to the channels and patterns
|
// PubSub automatically reconnects to Redis Server and resubscribes
|
||||||
// when Redis becomes unavailable.
|
// to the channels in case of network errors.
|
||||||
type PubSub struct {
|
type PubSub struct {
|
||||||
opt *Options
|
opt *Options
|
||||||
|
|
||||||
@@ -27,11 +27,17 @@ type PubSub struct {
|
|||||||
channels map[string]struct{}
|
channels map[string]struct{}
|
||||||
patterns map[string]struct{}
|
patterns map[string]struct{}
|
||||||
closed bool
|
closed bool
|
||||||
|
exit chan struct{}
|
||||||
|
|
||||||
cmd *Cmd
|
cmd *Cmd
|
||||||
|
|
||||||
chOnce sync.Once
|
chOnce sync.Once
|
||||||
ch chan *Message
|
ch chan *Message
|
||||||
|
ping chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PubSub) init() {
|
||||||
|
c.exit = make(chan struct{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PubSub) conn() (*pool.Conn, error) {
|
func (c *PubSub) conn() (*pool.Conn, error) {
|
||||||
@@ -41,7 +47,7 @@ func (c *PubSub) conn() (*pool.Conn, error) {
|
|||||||
return cn, err
|
return cn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PubSub) _conn(channels []string) (*pool.Conn, error) {
|
func (c *PubSub) _conn(newChannels []string) (*pool.Conn, error) {
|
||||||
if c.closed {
|
if c.closed {
|
||||||
return nil, pool.ErrClosed
|
return nil, pool.ErrClosed
|
||||||
}
|
}
|
||||||
@@ -50,6 +56,9 @@ func (c *PubSub) _conn(channels []string) (*pool.Conn, error) {
|
|||||||
return c.cn, nil
|
return c.cn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channels := mapKeys(c.channels)
|
||||||
|
channels = append(channels, newChannels...)
|
||||||
|
|
||||||
cn, err := c.newConn(channels)
|
cn, err := c.newConn(channels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -64,61 +73,81 @@ func (c *PubSub) _conn(channels []string) (*pool.Conn, error) {
|
|||||||
return cn, nil
|
return cn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *PubSub) writeCmd(cn *pool.Conn, cmd Cmder) error {
|
||||||
|
return cn.WithWriter(c.opt.WriteTimeout, func(wr *proto.Writer) error {
|
||||||
|
return writeCmd(wr, cmd)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (c *PubSub) resubscribe(cn *pool.Conn) error {
|
func (c *PubSub) resubscribe(cn *pool.Conn) error {
|
||||||
var firstErr error
|
var firstErr error
|
||||||
|
|
||||||
if len(c.channels) > 0 {
|
if len(c.channels) > 0 {
|
||||||
channels := make([]string, len(c.channels))
|
err := c._subscribe(cn, "subscribe", mapKeys(c.channels))
|
||||||
i := 0
|
if err != nil && firstErr == nil {
|
||||||
for channel := range c.channels {
|
|
||||||
channels[i] = channel
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if err := c._subscribe(cn, "subscribe", channels...); err != nil && firstErr == nil {
|
|
||||||
firstErr = err
|
firstErr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.patterns) > 0 {
|
if len(c.patterns) > 0 {
|
||||||
patterns := make([]string, len(c.patterns))
|
err := c._subscribe(cn, "psubscribe", mapKeys(c.patterns))
|
||||||
i := 0
|
if err != nil && firstErr == nil {
|
||||||
for pattern := range c.patterns {
|
|
||||||
patterns[i] = pattern
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if err := c._subscribe(cn, "psubscribe", patterns...); err != nil && firstErr == nil {
|
|
||||||
firstErr = err
|
firstErr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return firstErr
|
return firstErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PubSub) _subscribe(cn *pool.Conn, redisCmd string, channels ...string) error {
|
func mapKeys(m map[string]struct{}) []string {
|
||||||
args := make([]interface{}, 1+len(channels))
|
s := make([]string, len(m))
|
||||||
args[0] = redisCmd
|
i := 0
|
||||||
for i, channel := range channels {
|
for k := range m {
|
||||||
args[1+i] = channel
|
s[i] = k
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PubSub) _subscribe(
|
||||||
|
cn *pool.Conn, redisCmd string, channels []string,
|
||||||
|
) error {
|
||||||
|
args := make([]interface{}, 0, 1+len(channels))
|
||||||
|
args = append(args, redisCmd)
|
||||||
|
for _, channel := range channels {
|
||||||
|
args = append(args, channel)
|
||||||
}
|
}
|
||||||
cmd := NewSliceCmd(args...)
|
cmd := NewSliceCmd(args...)
|
||||||
|
return c.writeCmd(cn, cmd)
|
||||||
cn.SetWriteTimeout(c.opt.WriteTimeout)
|
|
||||||
return writeCmd(cn, cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PubSub) releaseConn(cn *pool.Conn, err error) {
|
func (c *PubSub) releaseConn(cn *pool.Conn, err error, allowTimeout bool) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c._releaseConn(cn, err)
|
c._releaseConn(cn, err, allowTimeout)
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PubSub) _releaseConn(cn *pool.Conn, err error) {
|
func (c *PubSub) _releaseConn(cn *pool.Conn, err error, allowTimeout bool) {
|
||||||
if c.cn != cn {
|
if c.cn != cn {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if internal.IsBadConn(err, true) {
|
if internal.IsBadConn(err, allowTimeout) {
|
||||||
_ = c.closeTheCn()
|
c._reconnect(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PubSub) closeTheCn() error {
|
func (c *PubSub) _reconnect(reason error) {
|
||||||
|
_ = c._closeTheCn(reason)
|
||||||
|
_, _ = c._conn(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PubSub) _closeTheCn(reason error) error {
|
||||||
|
if c.cn == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !c.closed {
|
||||||
|
internal.Logf("redis: discarding bad PubSub connection: %s", reason)
|
||||||
|
}
|
||||||
err := c.closeConn(c.cn)
|
err := c.closeConn(c.cn)
|
||||||
c.cn = nil
|
c.cn = nil
|
||||||
return err
|
return err
|
||||||
@@ -132,25 +161,25 @@ func (c *PubSub) Close() error {
|
|||||||
return pool.ErrClosed
|
return pool.ErrClosed
|
||||||
}
|
}
|
||||||
c.closed = true
|
c.closed = true
|
||||||
|
close(c.exit)
|
||||||
|
|
||||||
if c.cn != nil {
|
err := c._closeTheCn(pool.ErrClosed)
|
||||||
return c.closeTheCn()
|
return err
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe the client to the specified channels. It returns
|
// Subscribe the client to the specified channels. It returns
|
||||||
// empty subscription if there are no channels.
|
// empty subscription if there are no channels.
|
||||||
func (c *PubSub) Subscribe(channels ...string) error {
|
func (c *PubSub) Subscribe(channels ...string) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
err := c.subscribe("subscribe", channels...)
|
err := c.subscribe("subscribe", channels...)
|
||||||
if c.channels == nil {
|
if c.channels == nil {
|
||||||
c.channels = make(map[string]struct{})
|
c.channels = make(map[string]struct{})
|
||||||
}
|
}
|
||||||
for _, channel := range channels {
|
for _, s := range channels {
|
||||||
c.channels[channel] = struct{}{}
|
c.channels[s] = struct{}{}
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,14 +187,15 @@ func (c *PubSub) Subscribe(channels ...string) error {
|
|||||||
// empty subscription if there are no patterns.
|
// empty subscription if there are no patterns.
|
||||||
func (c *PubSub) PSubscribe(patterns ...string) error {
|
func (c *PubSub) PSubscribe(patterns ...string) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
err := c.subscribe("psubscribe", patterns...)
|
err := c.subscribe("psubscribe", patterns...)
|
||||||
if c.patterns == nil {
|
if c.patterns == nil {
|
||||||
c.patterns = make(map[string]struct{})
|
c.patterns = make(map[string]struct{})
|
||||||
}
|
}
|
||||||
for _, pattern := range patterns {
|
for _, s := range patterns {
|
||||||
c.patterns[pattern] = struct{}{}
|
c.patterns[s] = struct{}{}
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,11 +203,12 @@ func (c *PubSub) PSubscribe(patterns ...string) error {
|
|||||||
// them if none is given.
|
// them if none is given.
|
||||||
func (c *PubSub) Unsubscribe(channels ...string) error {
|
func (c *PubSub) Unsubscribe(channels ...string) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
err := c.subscribe("unsubscribe", channels...)
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
delete(c.channels, channel)
|
delete(c.channels, channel)
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
err := c.subscribe("unsubscribe", channels...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,11 +216,12 @@ func (c *PubSub) Unsubscribe(channels ...string) error {
|
|||||||
// them if none is given.
|
// them if none is given.
|
||||||
func (c *PubSub) PUnsubscribe(patterns ...string) error {
|
func (c *PubSub) PUnsubscribe(patterns ...string) error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
err := c.subscribe("punsubscribe", patterns...)
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
for _, pattern := range patterns {
|
for _, pattern := range patterns {
|
||||||
delete(c.patterns, pattern)
|
delete(c.patterns, pattern)
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
err := c.subscribe("punsubscribe", patterns...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,8 +231,8 @@ func (c *PubSub) subscribe(redisCmd string, channels ...string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c._subscribe(cn, redisCmd, channels...)
|
err = c._subscribe(cn, redisCmd, channels)
|
||||||
c._releaseConn(cn, err)
|
c._releaseConn(cn, err, false)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,9 +248,8 @@ func (c *PubSub) Ping(payload ...string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cn.SetWriteTimeout(c.opt.WriteTimeout)
|
err = c.writeCmd(cn, cmd)
|
||||||
err = writeCmd(cn, cmd)
|
c.releaseConn(cn, err, false)
|
||||||
c.releaseConn(cn, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,8 +328,8 @@ func (c *PubSub) newMessage(reply interface{}) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReceiveTimeout acts like Receive but returns an error if message
|
// ReceiveTimeout acts like Receive but returns an error if message
|
||||||
// is not received in time. This is low-level API and most clients
|
// is not received in time. This is low-level API and in most cases
|
||||||
// should use ReceiveMessage.
|
// Channel should be used instead.
|
||||||
func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) {
|
func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) {
|
||||||
if c.cmd == nil {
|
if c.cmd == nil {
|
||||||
c.cmd = NewCmd()
|
c.cmd = NewCmd()
|
||||||
@@ -309,9 +340,11 @@ func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cn.SetReadTimeout(timeout)
|
err = cn.WithReader(timeout, func(rd *proto.Reader) error {
|
||||||
err = c.cmd.readReply(cn)
|
return c.cmd.readReply(rd)
|
||||||
c.releaseConn(cn, err)
|
})
|
||||||
|
|
||||||
|
c.releaseConn(cn, err, timeout > 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -320,49 +353,23 @@ func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Receive returns a message as a Subscription, Message, Pong or error.
|
// Receive returns a message as a Subscription, Message, Pong or error.
|
||||||
// See PubSub example for details. This is low-level API and most clients
|
// See PubSub example for details. This is low-level API and in most cases
|
||||||
// should use ReceiveMessage.
|
// Channel should be used instead.
|
||||||
func (c *PubSub) Receive() (interface{}, error) {
|
func (c *PubSub) Receive() (interface{}, error) {
|
||||||
return c.ReceiveTimeout(0)
|
return c.ReceiveTimeout(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReceiveMessage returns a Message or error ignoring Subscription or Pong
|
// ReceiveMessage returns a Message or error ignoring Subscription and Pong
|
||||||
// messages. It automatically reconnects to Redis Server and resubscribes
|
// messages. This is low-level API and in most cases Channel should be used
|
||||||
// to channels in case of network errors.
|
// instead.
|
||||||
func (c *PubSub) ReceiveMessage() (*Message, error) {
|
func (c *PubSub) ReceiveMessage() (*Message, error) {
|
||||||
return c.receiveMessage(5 * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PubSub) receiveMessage(timeout time.Duration) (*Message, error) {
|
|
||||||
var errNum uint
|
|
||||||
for {
|
for {
|
||||||
msgi, err := c.ReceiveTimeout(timeout)
|
msg, err := c.Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !internal.IsNetworkError(err) {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
errNum++
|
switch msg := msg.(type) {
|
||||||
if errNum < 3 {
|
|
||||||
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
|
||||||
err := c.Ping()
|
|
||||||
if err != nil {
|
|
||||||
internal.Logf("PubSub.Ping failed: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 3 consequent errors - connection is broken or
|
|
||||||
// Redis Server is down.
|
|
||||||
// Sleep to not exceed max number of open connections.
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset error number, because we received a message.
|
|
||||||
errNum = 0
|
|
||||||
|
|
||||||
switch msg := msgi.(type) {
|
|
||||||
case *Subscription:
|
case *Subscription:
|
||||||
// Ignore.
|
// Ignore.
|
||||||
case *Pong:
|
case *Pong:
|
||||||
@@ -370,30 +377,93 @@ func (c *PubSub) receiveMessage(timeout time.Duration) (*Message, error) {
|
|||||||
case *Message:
|
case *Message:
|
||||||
return msg, nil
|
return msg, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("redis: unknown message: %T", msgi)
|
err := fmt.Errorf("redis: unknown message: %T", msg)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Channel returns a Go channel for concurrently receiving messages.
|
// Channel returns a Go channel for concurrently receiving messages.
|
||||||
// The channel is closed with PubSub. Receive or ReceiveMessage APIs
|
// It periodically sends Ping messages to test connection health.
|
||||||
// can not be used after channel is created.
|
// The channel is closed with PubSub. Receive* APIs can not be used
|
||||||
|
// after channel is created.
|
||||||
func (c *PubSub) Channel() <-chan *Message {
|
func (c *PubSub) Channel() <-chan *Message {
|
||||||
c.chOnce.Do(func() {
|
c.chOnce.Do(c.initChannel)
|
||||||
c.ch = make(chan *Message, 100)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
msg, err := c.ReceiveMessage()
|
|
||||||
if err != nil {
|
|
||||||
if err == pool.ErrClosed {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
c.ch <- msg
|
|
||||||
}
|
|
||||||
close(c.ch)
|
|
||||||
}()
|
|
||||||
})
|
|
||||||
return c.ch
|
return c.ch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *PubSub) initChannel() {
|
||||||
|
c.ch = make(chan *Message, 100)
|
||||||
|
c.ping = make(chan struct{}, 10)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var errCount int
|
||||||
|
for {
|
||||||
|
msg, err := c.Receive()
|
||||||
|
if err != nil {
|
||||||
|
if err == pool.ErrClosed {
|
||||||
|
close(c.ch)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if errCount > 0 {
|
||||||
|
time.Sleep(c.retryBackoff(errCount))
|
||||||
|
}
|
||||||
|
errCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
errCount = 0
|
||||||
|
|
||||||
|
// Any message is as good as a ping.
|
||||||
|
select {
|
||||||
|
case c.ping <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case *Subscription:
|
||||||
|
// Ignore.
|
||||||
|
case *Pong:
|
||||||
|
// Ignore.
|
||||||
|
case *Message:
|
||||||
|
c.ch <- msg
|
||||||
|
default:
|
||||||
|
internal.Logf("redis: unknown message: %T", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
const timeout = 5 * time.Second
|
||||||
|
|
||||||
|
timer := time.NewTimer(timeout)
|
||||||
|
timer.Stop()
|
||||||
|
|
||||||
|
healthy := true
|
||||||
|
var pingErr error
|
||||||
|
for {
|
||||||
|
timer.Reset(timeout)
|
||||||
|
select {
|
||||||
|
case <-c.ping:
|
||||||
|
healthy = true
|
||||||
|
if !timer.Stop() {
|
||||||
|
<-timer.C
|
||||||
|
}
|
||||||
|
case <-timer.C:
|
||||||
|
pingErr = c.Ping()
|
||||||
|
if healthy {
|
||||||
|
healthy = false
|
||||||
|
} else {
|
||||||
|
c.mu.Lock()
|
||||||
|
c._reconnect(pingErr)
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
case <-c.exit:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PubSub) retryBackoff(attempt int) time.Duration {
|
||||||
|
return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
|
||||||
|
}
|
||||||
|
|||||||
87
vendor/github.com/go-redis/redis/redis.go
сгенерированный
поставляемый
87
vendor/github.com/go-redis/redis/redis.go
сгенерированный
поставляемый
@@ -50,7 +50,7 @@ func (c *baseClient) newConn() (*pool.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cn.Inited {
|
if cn.InitedAt.IsZero() {
|
||||||
if err := c.initConn(cn); err != nil {
|
if err := c.initConn(cn); err != nil {
|
||||||
_ = c.connPool.CloseConn(cn)
|
_ = c.connPool.CloseConn(cn)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -66,7 +66,7 @@ func (c *baseClient) getConn() (*pool.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cn.Inited {
|
if cn.InitedAt.IsZero() {
|
||||||
err := c.initConn(cn)
|
err := c.initConn(cn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.connPool.Remove(cn)
|
c.connPool.Remove(cn)
|
||||||
@@ -88,7 +88,7 @@ func (c *baseClient) releaseConn(cn *pool.Conn, err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseClient) initConn(cn *pool.Conn) error {
|
func (c *baseClient) initConn(cn *pool.Conn) error {
|
||||||
cn.Inited = true
|
cn.InitedAt = time.Now()
|
||||||
|
|
||||||
if c.opt.Password == "" &&
|
if c.opt.Password == "" &&
|
||||||
c.opt.DB == 0 &&
|
c.opt.DB == 0 &&
|
||||||
@@ -123,8 +123,17 @@ func (c *baseClient) initConn(cn *pool.Conn) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do creates a Cmd from the args and processes the cmd.
|
||||||
|
func (c *baseClient) Do(args ...interface{}) *Cmd {
|
||||||
|
cmd := NewCmd(args...)
|
||||||
|
c.Process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
// WrapProcess wraps function that processes Redis commands.
|
// WrapProcess wraps function that processes Redis commands.
|
||||||
func (c *baseClient) WrapProcess(fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error) {
|
func (c *baseClient) WrapProcess(
|
||||||
|
fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error,
|
||||||
|
) {
|
||||||
c.process = fn(c.process)
|
c.process = fn(c.process)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,8 +156,10 @@ func (c *baseClient) defaultProcess(cmd Cmder) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cn.SetWriteTimeout(c.opt.WriteTimeout)
|
err = cn.WithWriter(c.opt.WriteTimeout, func(wr *proto.Writer) error {
|
||||||
if err := writeCmd(cn, cmd); err != nil {
|
return writeCmd(wr, cmd)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
c.releaseConn(cn, err)
|
c.releaseConn(cn, err)
|
||||||
cmd.setErr(err)
|
cmd.setErr(err)
|
||||||
if internal.IsRetryableError(err, true) {
|
if internal.IsRetryableError(err, true) {
|
||||||
@@ -157,8 +168,9 @@ func (c *baseClient) defaultProcess(cmd Cmder) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cn.SetReadTimeout(c.cmdTimeout(cmd))
|
err = cn.WithReader(c.cmdTimeout(cmd), func(rd *proto.Reader) error {
|
||||||
err = cmd.readReply(cn)
|
return cmd.readReply(rd)
|
||||||
|
})
|
||||||
c.releaseConn(cn, err)
|
c.releaseConn(cn, err)
|
||||||
if err != nil && internal.IsRetryableError(err, cmd.readTimeout() == nil) {
|
if err != nil && internal.IsRetryableError(err, cmd.readTimeout() == nil) {
|
||||||
continue
|
continue
|
||||||
@@ -176,9 +188,8 @@ func (c *baseClient) retryBackoff(attempt int) time.Duration {
|
|||||||
|
|
||||||
func (c *baseClient) cmdTimeout(cmd Cmder) time.Duration {
|
func (c *baseClient) cmdTimeout(cmd Cmder) time.Duration {
|
||||||
if timeout := cmd.readTimeout(); timeout != nil {
|
if timeout := cmd.readTimeout(); timeout != nil {
|
||||||
return *timeout
|
return readTimeout(*timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.opt.ReadTimeout
|
return c.opt.ReadTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,24 +255,27 @@ func (c *baseClient) generalProcessPipeline(cmds []Cmder, p pipelineProcessor) e
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return firstCmdsErr(cmds)
|
return cmdsFirstErr(cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseClient) pipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, error) {
|
func (c *baseClient) pipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, error) {
|
||||||
cn.SetWriteTimeout(c.opt.WriteTimeout)
|
err := cn.WithWriter(c.opt.WriteTimeout, func(wr *proto.Writer) error {
|
||||||
if err := writeCmd(cn, cmds...); err != nil {
|
return writeCmd(wr, cmds...)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
setCmdsErr(cmds, err)
|
setCmdsErr(cmds, err)
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set read timeout for all commands.
|
err = cn.WithReader(c.opt.ReadTimeout, func(rd *proto.Reader) error {
|
||||||
cn.SetReadTimeout(c.opt.ReadTimeout)
|
return pipelineReadCmds(rd, cmds)
|
||||||
return true, pipelineReadCmds(cn, cmds)
|
})
|
||||||
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineReadCmds(cn *pool.Conn, cmds []Cmder) error {
|
func pipelineReadCmds(rd *proto.Reader, cmds []Cmder) error {
|
||||||
for _, cmd := range cmds {
|
for _, cmd := range cmds {
|
||||||
err := cmd.readReply(cn)
|
err := cmd.readReply(rd)
|
||||||
if err != nil && !internal.IsRedisError(err) {
|
if err != nil && !internal.IsRedisError(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -270,47 +284,50 @@ func pipelineReadCmds(cn *pool.Conn, cmds []Cmder) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseClient) txPipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, error) {
|
func (c *baseClient) txPipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, error) {
|
||||||
cn.SetWriteTimeout(c.opt.WriteTimeout)
|
err := cn.WithWriter(c.opt.WriteTimeout, func(wr *proto.Writer) error {
|
||||||
if err := txPipelineWriteMulti(cn, cmds); err != nil {
|
return txPipelineWriteMulti(wr, cmds)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
setCmdsErr(cmds, err)
|
setCmdsErr(cmds, err)
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set read timeout for all commands.
|
err = cn.WithReader(c.opt.ReadTimeout, func(rd *proto.Reader) error {
|
||||||
cn.SetReadTimeout(c.opt.ReadTimeout)
|
err := txPipelineReadQueued(rd, cmds)
|
||||||
|
if err != nil {
|
||||||
if err := c.txPipelineReadQueued(cn, cmds); err != nil {
|
|
||||||
setCmdsErr(cmds, err)
|
setCmdsErr(cmds, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return pipelineReadCmds(rd, cmds)
|
||||||
|
})
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, pipelineReadCmds(cn, cmds)
|
func txPipelineWriteMulti(wr *proto.Writer, cmds []Cmder) error {
|
||||||
}
|
|
||||||
|
|
||||||
func txPipelineWriteMulti(cn *pool.Conn, cmds []Cmder) error {
|
|
||||||
multiExec := make([]Cmder, 0, len(cmds)+2)
|
multiExec := make([]Cmder, 0, len(cmds)+2)
|
||||||
multiExec = append(multiExec, NewStatusCmd("MULTI"))
|
multiExec = append(multiExec, NewStatusCmd("MULTI"))
|
||||||
multiExec = append(multiExec, cmds...)
|
multiExec = append(multiExec, cmds...)
|
||||||
multiExec = append(multiExec, NewSliceCmd("EXEC"))
|
multiExec = append(multiExec, NewSliceCmd("EXEC"))
|
||||||
return writeCmd(cn, multiExec...)
|
return writeCmd(wr, multiExec...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseClient) txPipelineReadQueued(cn *pool.Conn, cmds []Cmder) error {
|
func txPipelineReadQueued(rd *proto.Reader, cmds []Cmder) error {
|
||||||
// Parse queued replies.
|
// Parse queued replies.
|
||||||
var statusCmd StatusCmd
|
var statusCmd StatusCmd
|
||||||
if err := statusCmd.readReply(cn); err != nil {
|
err := statusCmd.readReply(rd)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _ = range cmds {
|
for _ = range cmds {
|
||||||
err := statusCmd.readReply(cn)
|
err = statusCmd.readReply(rd)
|
||||||
if err != nil && !internal.IsRedisError(err) {
|
if err != nil && !internal.IsRedisError(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse number of replies.
|
// Parse number of replies.
|
||||||
line, err := cn.Rd.ReadLine()
|
line, err := rd.ReadLine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == Nil {
|
if err == Nil {
|
||||||
err = TxFailedErr
|
err = TxFailedErr
|
||||||
@@ -424,7 +441,7 @@ func (c *Client) TxPipeline() Pipeliner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) pubSub() *PubSub {
|
func (c *Client) pubSub() *PubSub {
|
||||||
return &PubSub{
|
pubsub := &PubSub{
|
||||||
opt: c.opt,
|
opt: c.opt,
|
||||||
|
|
||||||
newConn: func(channels []string) (*pool.Conn, error) {
|
newConn: func(channels []string) (*pool.Conn, error) {
|
||||||
@@ -432,6 +449,8 @@ func (c *Client) pubSub() *PubSub {
|
|||||||
},
|
},
|
||||||
closeConn: c.connPool.CloseConn,
|
closeConn: c.connPool.CloseConn,
|
||||||
}
|
}
|
||||||
|
pubsub.init()
|
||||||
|
return pubsub
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe subscribes the client to the specified channels.
|
// Subscribe subscribes the client to the specified channels.
|
||||||
|
|||||||
2
vendor/github.com/go-redis/redis/result.go
сгенерированный
поставляемый
2
vendor/github.com/go-redis/redis/result.go
сгенерированный
поставляемый
@@ -53,7 +53,7 @@ func NewBoolResult(val bool, err error) *BoolCmd {
|
|||||||
// NewStringResult returns a StringCmd initialised with val and err for testing
|
// NewStringResult returns a StringCmd initialised with val and err for testing
|
||||||
func NewStringResult(val string, err error) *StringCmd {
|
func NewStringResult(val string, err error) *StringCmd {
|
||||||
var cmd StringCmd
|
var cmd StringCmd
|
||||||
cmd.val = []byte(val)
|
cmd.val = val
|
||||||
cmd.setErr(err)
|
cmd.setErr(err)
|
||||||
return &cmd
|
return &cmd
|
||||||
}
|
}
|
||||||
|
|||||||
79
vendor/github.com/go-redis/redis/ring.go
сгенерированный
поставляемый
79
vendor/github.com/go-redis/redis/ring.go
сгенерированный
поставляемый
@@ -16,7 +16,8 @@ import (
|
|||||||
"github.com/go-redis/redis/internal/pool"
|
"github.com/go-redis/redis/internal/pool"
|
||||||
)
|
)
|
||||||
|
|
||||||
const nreplicas = 100
|
// Hash is type of hash function used in consistent hash.
|
||||||
|
type Hash consistenthash.Hash
|
||||||
|
|
||||||
var errRingShardsDown = errors.New("redis: all ring shards are down")
|
var errRingShardsDown = errors.New("redis: all ring shards are down")
|
||||||
|
|
||||||
@@ -30,6 +31,27 @@ type RingOptions struct {
|
|||||||
// Shard is considered down after 3 subsequent failed checks.
|
// Shard is considered down after 3 subsequent failed checks.
|
||||||
HeartbeatFrequency time.Duration
|
HeartbeatFrequency time.Duration
|
||||||
|
|
||||||
|
// Hash function used in consistent hash.
|
||||||
|
// Default is crc32.ChecksumIEEE.
|
||||||
|
Hash Hash
|
||||||
|
|
||||||
|
// Number of replicas in consistent hash.
|
||||||
|
// Default is 100 replicas.
|
||||||
|
//
|
||||||
|
// Higher number of replicas will provide less deviation, that is keys will be
|
||||||
|
// distributed to nodes more evenly.
|
||||||
|
//
|
||||||
|
// Following is deviation for common nreplicas:
|
||||||
|
// --------------------------------------------------------
|
||||||
|
// | nreplicas | standard error | 99% confidence interval |
|
||||||
|
// | 10 | 0.3152 | (0.37, 1.98) |
|
||||||
|
// | 100 | 0.0997 | (0.76, 1.28) |
|
||||||
|
// | 1000 | 0.0316 | (0.92, 1.09) |
|
||||||
|
// --------------------------------------------------------
|
||||||
|
//
|
||||||
|
// See https://arxiv.org/abs/1406.2294 for reference
|
||||||
|
HashReplicas int
|
||||||
|
|
||||||
// Following options are copied from Options struct.
|
// Following options are copied from Options struct.
|
||||||
|
|
||||||
OnConnect func(*Conn) error
|
OnConnect func(*Conn) error
|
||||||
@@ -46,6 +68,8 @@ type RingOptions struct {
|
|||||||
WriteTimeout time.Duration
|
WriteTimeout time.Duration
|
||||||
|
|
||||||
PoolSize int
|
PoolSize int
|
||||||
|
MinIdleConns int
|
||||||
|
MaxConnAge time.Duration
|
||||||
PoolTimeout time.Duration
|
PoolTimeout time.Duration
|
||||||
IdleTimeout time.Duration
|
IdleTimeout time.Duration
|
||||||
IdleCheckFrequency time.Duration
|
IdleCheckFrequency time.Duration
|
||||||
@@ -56,6 +80,10 @@ func (opt *RingOptions) init() {
|
|||||||
opt.HeartbeatFrequency = 500 * time.Millisecond
|
opt.HeartbeatFrequency = 500 * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opt.HashReplicas == 0 {
|
||||||
|
opt.HashReplicas = 100
|
||||||
|
}
|
||||||
|
|
||||||
switch opt.MinRetryBackoff {
|
switch opt.MinRetryBackoff {
|
||||||
case -1:
|
case -1:
|
||||||
opt.MinRetryBackoff = 0
|
opt.MinRetryBackoff = 0
|
||||||
@@ -82,6 +110,8 @@ func (opt *RingOptions) clientOptions() *Options {
|
|||||||
WriteTimeout: opt.WriteTimeout,
|
WriteTimeout: opt.WriteTimeout,
|
||||||
|
|
||||||
PoolSize: opt.PoolSize,
|
PoolSize: opt.PoolSize,
|
||||||
|
MinIdleConns: opt.MinIdleConns,
|
||||||
|
MaxConnAge: opt.MaxConnAge,
|
||||||
PoolTimeout: opt.PoolTimeout,
|
PoolTimeout: opt.PoolTimeout,
|
||||||
IdleTimeout: opt.IdleTimeout,
|
IdleTimeout: opt.IdleTimeout,
|
||||||
IdleCheckFrequency: opt.IdleCheckFrequency,
|
IdleCheckFrequency: opt.IdleCheckFrequency,
|
||||||
@@ -133,16 +163,21 @@ func (shard *ringShard) Vote(up bool) bool {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
type ringShards struct {
|
type ringShards struct {
|
||||||
|
opt *RingOptions
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
hash *consistenthash.Map
|
hash *consistenthash.Map
|
||||||
shards map[string]*ringShard // read only
|
shards map[string]*ringShard // read only
|
||||||
list []*ringShard // read only
|
list []*ringShard // read only
|
||||||
|
len int
|
||||||
closed bool
|
closed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRingShards() *ringShards {
|
func newRingShards(opt *RingOptions) *ringShards {
|
||||||
return &ringShards{
|
return &ringShards{
|
||||||
hash: consistenthash.New(nreplicas, nil),
|
opt: opt,
|
||||||
|
|
||||||
|
hash: newConsistentHash(opt),
|
||||||
shards: make(map[string]*ringShard),
|
shards: make(map[string]*ringShard),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,18 +273,28 @@ func (c *ringShards) Heartbeat(frequency time.Duration) {
|
|||||||
|
|
||||||
// rebalance removes dead shards from the Ring.
|
// rebalance removes dead shards from the Ring.
|
||||||
func (c *ringShards) rebalance() {
|
func (c *ringShards) rebalance() {
|
||||||
hash := consistenthash.New(nreplicas, nil)
|
hash := newConsistentHash(c.opt)
|
||||||
|
var shardsNum int
|
||||||
for name, shard := range c.shards {
|
for name, shard := range c.shards {
|
||||||
if shard.IsUp() {
|
if shard.IsUp() {
|
||||||
hash.Add(name)
|
hash.Add(name)
|
||||||
|
shardsNum++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.hash = hash
|
c.hash = hash
|
||||||
|
c.len = shardsNum
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ringShards) Len() int {
|
||||||
|
c.mu.RLock()
|
||||||
|
l := c.len
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ringShards) Close() error {
|
func (c *ringShards) Close() error {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
@@ -305,7 +350,7 @@ func NewRing(opt *RingOptions) *Ring {
|
|||||||
|
|
||||||
ring := &Ring{
|
ring := &Ring{
|
||||||
opt: opt,
|
opt: opt,
|
||||||
shards: newRingShards(),
|
shards: newRingShards(opt),
|
||||||
}
|
}
|
||||||
ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo)
|
ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo)
|
||||||
|
|
||||||
@@ -363,11 +408,16 @@ func (c *Ring) PoolStats() *PoolStats {
|
|||||||
acc.Misses += s.Misses
|
acc.Misses += s.Misses
|
||||||
acc.Timeouts += s.Timeouts
|
acc.Timeouts += s.Timeouts
|
||||||
acc.TotalConns += s.TotalConns
|
acc.TotalConns += s.TotalConns
|
||||||
acc.FreeConns += s.FreeConns
|
acc.IdleConns += s.IdleConns
|
||||||
}
|
}
|
||||||
return &acc
|
return &acc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Len returns the current number of shards in the ring.
|
||||||
|
func (c *Ring) Len() int {
|
||||||
|
return c.shards.Len()
|
||||||
|
}
|
||||||
|
|
||||||
// Subscribe subscribes the client to the specified channels.
|
// Subscribe subscribes the client to the specified channels.
|
||||||
func (c *Ring) Subscribe(channels ...string) *PubSub {
|
func (c *Ring) Subscribe(channels ...string) *PubSub {
|
||||||
if len(channels) == 0 {
|
if len(channels) == 0 {
|
||||||
@@ -466,7 +516,16 @@ func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) {
|
|||||||
return c.shards.GetByKey(firstKey)
|
return c.shards.GetByKey(firstKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ring) WrapProcess(fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error) {
|
// Do creates a Cmd from the args and processes the cmd.
|
||||||
|
func (c *Ring) Do(args ...interface{}) *Cmd {
|
||||||
|
cmd := NewCmd(args...)
|
||||||
|
c.Process(cmd)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ring) WrapProcess(
|
||||||
|
fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error,
|
||||||
|
) {
|
||||||
c.ForEachShard(func(c *Client) error {
|
c.ForEachShard(func(c *Client) error {
|
||||||
c.WrapProcess(fn)
|
c.WrapProcess(fn)
|
||||||
return nil
|
return nil
|
||||||
@@ -552,7 +611,7 @@ func (c *Ring) defaultProcessPipeline(cmds []Cmder) error {
|
|||||||
cmdsMap = failedCmdsMap
|
cmdsMap = failedCmdsMap
|
||||||
}
|
}
|
||||||
|
|
||||||
return firstCmdsErr(cmds)
|
return cmdsFirstErr(cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ring) TxPipeline() Pipeliner {
|
func (c *Ring) TxPipeline() Pipeliner {
|
||||||
@@ -570,3 +629,7 @@ func (c *Ring) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
|||||||
func (c *Ring) Close() error {
|
func (c *Ring) Close() error {
|
||||||
return c.shards.Close()
|
return c.shards.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newConsistentHash(opt *RingOptions) *consistenthash.Map {
|
||||||
|
return consistenthash.New(opt.HashReplicas, consistenthash.Hash(opt.Hash))
|
||||||
|
}
|
||||||
|
|||||||
68
vendor/github.com/go-redis/redis/sentinel.go
сгенерированный
поставляемый
68
vendor/github.com/go-redis/redis/sentinel.go
сгенерированный
поставляемый
@@ -30,12 +30,16 @@ type FailoverOptions struct {
|
|||||||
DB int
|
DB int
|
||||||
|
|
||||||
MaxRetries int
|
MaxRetries int
|
||||||
|
MinRetryBackoff time.Duration
|
||||||
|
MaxRetryBackoff time.Duration
|
||||||
|
|
||||||
DialTimeout time.Duration
|
DialTimeout time.Duration
|
||||||
ReadTimeout time.Duration
|
ReadTimeout time.Duration
|
||||||
WriteTimeout time.Duration
|
WriteTimeout time.Duration
|
||||||
|
|
||||||
PoolSize int
|
PoolSize int
|
||||||
|
MinIdleConns int
|
||||||
|
MaxConnAge time.Duration
|
||||||
PoolTimeout time.Duration
|
PoolTimeout time.Duration
|
||||||
IdleTimeout time.Duration
|
IdleTimeout time.Duration
|
||||||
IdleCheckFrequency time.Duration
|
IdleCheckFrequency time.Duration
|
||||||
@@ -92,7 +96,7 @@ func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
c.baseClient.init()
|
c.baseClient.init()
|
||||||
c.setProcessor(c.Process)
|
c.cmdable.setProcessor(c.Process)
|
||||||
|
|
||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
@@ -116,7 +120,7 @@ func NewSentinelClient(opt *Options) *SentinelClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *SentinelClient) PubSub() *PubSub {
|
func (c *SentinelClient) PubSub() *PubSub {
|
||||||
return &PubSub{
|
pubsub := &PubSub{
|
||||||
opt: c.opt,
|
opt: c.opt,
|
||||||
|
|
||||||
newConn: func(channels []string) (*pool.Conn, error) {
|
newConn: func(channels []string) (*pool.Conn, error) {
|
||||||
@@ -124,6 +128,8 @@ func (c *SentinelClient) PubSub() *PubSub {
|
|||||||
},
|
},
|
||||||
closeConn: c.connPool.CloseConn,
|
closeConn: c.connPool.CloseConn,
|
||||||
}
|
}
|
||||||
|
pubsub.init()
|
||||||
|
return pubsub
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SentinelClient) GetMasterAddrByName(name string) *StringSliceCmd {
|
func (c *SentinelClient) GetMasterAddrByName(name string) *StringSliceCmd {
|
||||||
@@ -180,10 +186,7 @@ func (d *sentinelFailover) MasterAddr() (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
d._switchMaster(addr)
|
||||||
if d._masterAddr != addr {
|
|
||||||
d.switchMaster(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
@@ -194,11 +197,11 @@ func (d *sentinelFailover) masterAddr() (string, error) {
|
|||||||
addr, err := d.sentinel.GetMasterAddrByName(d.masterName).Result()
|
addr, err := d.sentinel.GetMasterAddrByName(d.masterName).Result()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
addr := net.JoinHostPort(addr[0], addr[1])
|
addr := net.JoinHostPort(addr[0], addr[1])
|
||||||
internal.Logf("sentinel: master=%q addr=%q", d.masterName, addr)
|
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.Logf("sentinel: GetMasterAddrByName name=%q failed: %s", d.masterName, err)
|
internal.Logf("sentinel: GetMasterAddrByName name=%q failed: %s",
|
||||||
|
d.masterName, err)
|
||||||
d._resetSentinel()
|
d._resetSentinel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,15 +237,23 @@ func (d *sentinelFailover) masterAddr() (string, error) {
|
|||||||
return "", errors.New("redis: all sentinels are unreachable")
|
return "", errors.New("redis: all sentinels are unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *sentinelFailover) switchMaster(masterAddr string) {
|
func (c *sentinelFailover) switchMaster(addr string) {
|
||||||
internal.Logf(
|
c.mu.Lock()
|
||||||
"sentinel: new master=%q addr=%q",
|
c._switchMaster(addr)
|
||||||
d.masterName, masterAddr,
|
c.mu.Unlock()
|
||||||
)
|
}
|
||||||
_ = d.Pool().Filter(func(cn *pool.Conn) bool {
|
|
||||||
return cn.RemoteAddr().String() != masterAddr
|
func (c *sentinelFailover) _switchMaster(addr string) {
|
||||||
|
if c._masterAddr == addr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
internal.Logf("sentinel: new master=%q addr=%q",
|
||||||
|
c.masterName, addr)
|
||||||
|
_ = c.Pool().Filter(func(cn *pool.Conn) bool {
|
||||||
|
return cn.RemoteAddr().String() != addr
|
||||||
})
|
})
|
||||||
d._masterAddr = masterAddr
|
c._masterAddr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *sentinelFailover) setSentinel(sentinel *SentinelClient) {
|
func (d *sentinelFailover) setSentinel(sentinel *SentinelClient) {
|
||||||
@@ -292,28 +303,26 @@ func (d *sentinelFailover) discoverSentinels(sentinel *SentinelClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *sentinelFailover) listen(sentinel *SentinelClient) {
|
func (d *sentinelFailover) listen(sentinel *SentinelClient) {
|
||||||
var pubsub *PubSub
|
pubsub := sentinel.PubSub()
|
||||||
for {
|
defer pubsub.Close()
|
||||||
if pubsub == nil {
|
|
||||||
pubsub = sentinel.PubSub()
|
|
||||||
|
|
||||||
if err := pubsub.Subscribe("+switch-master"); err != nil {
|
err := pubsub.Subscribe("+switch-master")
|
||||||
|
if err != nil {
|
||||||
internal.Logf("sentinel: Subscribe failed: %s", err)
|
internal.Logf("sentinel: Subscribe failed: %s", err)
|
||||||
pubsub.Close()
|
|
||||||
d.resetSentinel()
|
d.resetSentinel()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
for {
|
||||||
msg, err := pubsub.ReceiveMessage()
|
msg, err := pubsub.ReceiveMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != pool.ErrClosed {
|
if err == pool.ErrClosed {
|
||||||
internal.Logf("sentinel: ReceiveMessage failed: %s", err)
|
|
||||||
pubsub.Close()
|
|
||||||
}
|
|
||||||
d.resetSentinel()
|
d.resetSentinel()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
internal.Logf("sentinel: ReceiveMessage failed: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch msg.Channel {
|
switch msg.Channel {
|
||||||
case "+switch-master":
|
case "+switch-master":
|
||||||
@@ -323,13 +332,8 @@ func (d *sentinelFailover) listen(sentinel *SentinelClient) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
addr := net.JoinHostPort(parts[3], parts[4])
|
addr := net.JoinHostPort(parts[3], parts[4])
|
||||||
|
|
||||||
d.mu.Lock()
|
|
||||||
if d._masterAddr != addr {
|
|
||||||
d.switchMaster(addr)
|
d.switchMaster(addr)
|
||||||
}
|
}
|
||||||
d.mu.Unlock()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
vendor/github.com/go-redis/redis/tx.go
сгенерированный
поставляемый
12
vendor/github.com/go-redis/redis/tx.go
сгенерированный
поставляемый
@@ -29,6 +29,10 @@ func (c *Client) newTx() *Tx {
|
|||||||
return &tx
|
return &tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watch prepares a transcaction and marks the keys to be watched
|
||||||
|
// for conditional execution if there are any keys.
|
||||||
|
//
|
||||||
|
// The transaction is automatically closed when the fn exits.
|
||||||
func (c *Client) Watch(fn func(*Tx) error, keys ...string) error {
|
func (c *Client) Watch(fn func(*Tx) error, keys ...string) error {
|
||||||
tx := c.newTx()
|
tx := c.newTx()
|
||||||
if len(keys) > 0 {
|
if len(keys) > 0 {
|
||||||
@@ -74,6 +78,7 @@ func (c *Tx) Unwatch(keys ...string) *StatusCmd {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pipeline creates a new pipeline. It is more convenient to use Pipelined.
|
||||||
func (c *Tx) Pipeline() Pipeliner {
|
func (c *Tx) Pipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.processTxPipeline,
|
exec: c.processTxPipeline,
|
||||||
@@ -82,23 +87,24 @@ func (c *Tx) Pipeline() Pipeliner {
|
|||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pipelined executes commands queued in the fn in a transaction
|
// Pipelined executes commands queued in the fn in a transaction.
|
||||||
// and restores the connection state to normal.
|
|
||||||
//
|
//
|
||||||
// When using WATCH, EXEC will execute commands only if the watched keys
|
// When using WATCH, EXEC will execute commands only if the watched keys
|
||||||
// were not modified, allowing for a check-and-set mechanism.
|
// were not modified, allowing for a check-and-set mechanism.
|
||||||
//
|
//
|
||||||
// Exec always returns list of commands. If transaction fails
|
// Exec always returns list of commands. If transaction fails
|
||||||
// TxFailedErr is returned. Otherwise Exec returns error of the first
|
// TxFailedErr is returned. Otherwise Exec returns an error of the first
|
||||||
// failed command or nil.
|
// failed command or nil.
|
||||||
func (c *Tx) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
func (c *Tx) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
return c.Pipeline().Pipelined(fn)
|
return c.Pipeline().Pipelined(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxPipelined is an alias for Pipelined.
|
||||||
func (c *Tx) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
func (c *Tx) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
return c.Pipelined(fn)
|
return c.Pipelined(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxPipeline is an alias for Pipeline.
|
||||||
func (c *Tx) TxPipeline() Pipeliner {
|
func (c *Tx) TxPipeline() Pipeliner {
|
||||||
return c.Pipeline()
|
return c.Pipeline()
|
||||||
}
|
}
|
||||||
|
|||||||
78
vendor/github.com/go-redis/redis/universal.go
сгенерированный
поставляемый
78
vendor/github.com/go-redis/redis/universal.go
сгенерированный
поставляемый
@@ -12,35 +12,38 @@ type UniversalOptions struct {
|
|||||||
// of cluster/sentinel nodes.
|
// of cluster/sentinel nodes.
|
||||||
Addrs []string
|
Addrs []string
|
||||||
|
|
||||||
// The sentinel master name.
|
|
||||||
// Only failover clients.
|
|
||||||
MasterName string
|
|
||||||
|
|
||||||
// Database to be selected after connecting to the server.
|
// Database to be selected after connecting to the server.
|
||||||
// Only single-node and failover clients.
|
// Only single-node and failover clients.
|
||||||
DB int
|
DB int
|
||||||
|
|
||||||
// Only cluster clients.
|
// Common options.
|
||||||
|
|
||||||
// Enables read only queries on slave nodes.
|
|
||||||
ReadOnly bool
|
|
||||||
|
|
||||||
MaxRedirects int
|
|
||||||
RouteByLatency bool
|
|
||||||
|
|
||||||
// Common options
|
|
||||||
|
|
||||||
OnConnect func(*Conn) error
|
OnConnect func(*Conn) error
|
||||||
MaxRetries int
|
|
||||||
Password string
|
Password string
|
||||||
|
MaxRetries int
|
||||||
|
MinRetryBackoff time.Duration
|
||||||
|
MaxRetryBackoff time.Duration
|
||||||
DialTimeout time.Duration
|
DialTimeout time.Duration
|
||||||
ReadTimeout time.Duration
|
ReadTimeout time.Duration
|
||||||
WriteTimeout time.Duration
|
WriteTimeout time.Duration
|
||||||
PoolSize int
|
PoolSize int
|
||||||
|
MinIdleConns int
|
||||||
|
MaxConnAge time.Duration
|
||||||
PoolTimeout time.Duration
|
PoolTimeout time.Duration
|
||||||
IdleTimeout time.Duration
|
IdleTimeout time.Duration
|
||||||
IdleCheckFrequency time.Duration
|
IdleCheckFrequency time.Duration
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
|
|
||||||
|
// Only cluster clients.
|
||||||
|
|
||||||
|
MaxRedirects int
|
||||||
|
ReadOnly bool
|
||||||
|
RouteByLatency bool
|
||||||
|
RouteRandomly bool
|
||||||
|
|
||||||
|
// The sentinel master name.
|
||||||
|
// Only failover clients.
|
||||||
|
MasterName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *UniversalOptions) cluster() *ClusterOptions {
|
func (o *UniversalOptions) cluster() *ClusterOptions {
|
||||||
@@ -50,20 +53,29 @@ func (o *UniversalOptions) cluster() *ClusterOptions {
|
|||||||
|
|
||||||
return &ClusterOptions{
|
return &ClusterOptions{
|
||||||
Addrs: o.Addrs,
|
Addrs: o.Addrs,
|
||||||
MaxRedirects: o.MaxRedirects,
|
|
||||||
RouteByLatency: o.RouteByLatency,
|
|
||||||
ReadOnly: o.ReadOnly,
|
|
||||||
|
|
||||||
OnConnect: o.OnConnect,
|
OnConnect: o.OnConnect,
|
||||||
MaxRetries: o.MaxRetries,
|
|
||||||
Password: o.Password,
|
Password: o.Password,
|
||||||
|
|
||||||
|
MaxRedirects: o.MaxRedirects,
|
||||||
|
ReadOnly: o.ReadOnly,
|
||||||
|
RouteByLatency: o.RouteByLatency,
|
||||||
|
RouteRandomly: o.RouteRandomly,
|
||||||
|
|
||||||
|
MaxRetries: o.MaxRetries,
|
||||||
|
MinRetryBackoff: o.MinRetryBackoff,
|
||||||
|
MaxRetryBackoff: o.MaxRetryBackoff,
|
||||||
|
|
||||||
DialTimeout: o.DialTimeout,
|
DialTimeout: o.DialTimeout,
|
||||||
ReadTimeout: o.ReadTimeout,
|
ReadTimeout: o.ReadTimeout,
|
||||||
WriteTimeout: o.WriteTimeout,
|
WriteTimeout: o.WriteTimeout,
|
||||||
PoolSize: o.PoolSize,
|
PoolSize: o.PoolSize,
|
||||||
|
MinIdleConns: o.MinIdleConns,
|
||||||
|
MaxConnAge: o.MaxConnAge,
|
||||||
PoolTimeout: o.PoolTimeout,
|
PoolTimeout: o.PoolTimeout,
|
||||||
IdleTimeout: o.IdleTimeout,
|
IdleTimeout: o.IdleTimeout,
|
||||||
IdleCheckFrequency: o.IdleCheckFrequency,
|
IdleCheckFrequency: o.IdleCheckFrequency,
|
||||||
|
|
||||||
TLSConfig: o.TLSConfig,
|
TLSConfig: o.TLSConfig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,18 +88,26 @@ func (o *UniversalOptions) failover() *FailoverOptions {
|
|||||||
return &FailoverOptions{
|
return &FailoverOptions{
|
||||||
SentinelAddrs: o.Addrs,
|
SentinelAddrs: o.Addrs,
|
||||||
MasterName: o.MasterName,
|
MasterName: o.MasterName,
|
||||||
DB: o.DB,
|
|
||||||
|
|
||||||
OnConnect: o.OnConnect,
|
OnConnect: o.OnConnect,
|
||||||
MaxRetries: o.MaxRetries,
|
|
||||||
|
DB: o.DB,
|
||||||
Password: o.Password,
|
Password: o.Password,
|
||||||
|
|
||||||
|
MaxRetries: o.MaxRetries,
|
||||||
|
MinRetryBackoff: o.MinRetryBackoff,
|
||||||
|
MaxRetryBackoff: o.MaxRetryBackoff,
|
||||||
|
|
||||||
DialTimeout: o.DialTimeout,
|
DialTimeout: o.DialTimeout,
|
||||||
ReadTimeout: o.ReadTimeout,
|
ReadTimeout: o.ReadTimeout,
|
||||||
WriteTimeout: o.WriteTimeout,
|
WriteTimeout: o.WriteTimeout,
|
||||||
|
|
||||||
PoolSize: o.PoolSize,
|
PoolSize: o.PoolSize,
|
||||||
|
MinIdleConns: o.MinIdleConns,
|
||||||
|
MaxConnAge: o.MaxConnAge,
|
||||||
PoolTimeout: o.PoolTimeout,
|
PoolTimeout: o.PoolTimeout,
|
||||||
IdleTimeout: o.IdleTimeout,
|
IdleTimeout: o.IdleTimeout,
|
||||||
IdleCheckFrequency: o.IdleCheckFrequency,
|
IdleCheckFrequency: o.IdleCheckFrequency,
|
||||||
|
|
||||||
TLSConfig: o.TLSConfig,
|
TLSConfig: o.TLSConfig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,18 +120,26 @@ func (o *UniversalOptions) simple() *Options {
|
|||||||
|
|
||||||
return &Options{
|
return &Options{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
DB: o.DB,
|
|
||||||
|
|
||||||
OnConnect: o.OnConnect,
|
OnConnect: o.OnConnect,
|
||||||
MaxRetries: o.MaxRetries,
|
|
||||||
|
DB: o.DB,
|
||||||
Password: o.Password,
|
Password: o.Password,
|
||||||
|
|
||||||
|
MaxRetries: o.MaxRetries,
|
||||||
|
MinRetryBackoff: o.MinRetryBackoff,
|
||||||
|
MaxRetryBackoff: o.MaxRetryBackoff,
|
||||||
|
|
||||||
DialTimeout: o.DialTimeout,
|
DialTimeout: o.DialTimeout,
|
||||||
ReadTimeout: o.ReadTimeout,
|
ReadTimeout: o.ReadTimeout,
|
||||||
WriteTimeout: o.WriteTimeout,
|
WriteTimeout: o.WriteTimeout,
|
||||||
|
|
||||||
PoolSize: o.PoolSize,
|
PoolSize: o.PoolSize,
|
||||||
|
MinIdleConns: o.MinIdleConns,
|
||||||
|
MaxConnAge: o.MaxConnAge,
|
||||||
PoolTimeout: o.PoolTimeout,
|
PoolTimeout: o.PoolTimeout,
|
||||||
IdleTimeout: o.IdleTimeout,
|
IdleTimeout: o.IdleTimeout,
|
||||||
IdleCheckFrequency: o.IdleCheckFrequency,
|
IdleCheckFrequency: o.IdleCheckFrequency,
|
||||||
|
|
||||||
TLSConfig: o.TLSConfig,
|
TLSConfig: o.TLSConfig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
vendor/github.com/golang/protobuf/LICENSE
сгенерированный
поставляемый
3
vendor/github.com/golang/protobuf/LICENSE
сгенерированный
поставляемый
@@ -1,7 +1,4 @@
|
|||||||
Go support for Protocol Buffers - Google's data interchange format
|
|
||||||
|
|
||||||
Copyright 2010 The Go Authors. All rights reserved.
|
Copyright 2010 The Go Authors. All rights reserved.
|
||||||
https://github.com/golang/protobuf
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
|||||||
18
vendor/github.com/golang/protobuf/proto/encode.go
сгенерированный
поставляемый
18
vendor/github.com/golang/protobuf/proto/encode.go
сгенерированный
поставляемый
@@ -37,27 +37,9 @@ package proto
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequiredNotSetError is the error returned if Marshal is called with
|
|
||||||
// a protocol buffer struct whose required fields have not
|
|
||||||
// all been initialized. It is also the error returned if Unmarshal is
|
|
||||||
// called with an encoded protocol buffer that does not include all the
|
|
||||||
// required fields.
|
|
||||||
//
|
|
||||||
// When printed, RequiredNotSetError reports the first unset required field in a
|
|
||||||
// message. If the field cannot be precisely determined, it is reported as
|
|
||||||
// "{Unknown}".
|
|
||||||
type RequiredNotSetError struct {
|
|
||||||
field string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *RequiredNotSetError) Error() string {
|
|
||||||
return fmt.Sprintf("proto: required field %q not set", e.field)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// errRepeatedHasNil is the error returned if Marshal is called with
|
// errRepeatedHasNil is the error returned if Marshal is called with
|
||||||
// a struct with a repeated field containing a nil element.
|
// a struct with a repeated field containing a nil element.
|
||||||
|
|||||||
62
vendor/github.com/golang/protobuf/proto/lib.go
сгенерированный
поставляемый
62
vendor/github.com/golang/protobuf/proto/lib.go
сгенерированный
поставляемый
@@ -265,7 +265,6 @@ package proto
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -274,7 +273,66 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errInvalidUTF8 = errors.New("proto: invalid UTF-8 string")
|
// RequiredNotSetError is an error type returned by either Marshal or Unmarshal.
|
||||||
|
// Marshal reports this when a required field is not initialized.
|
||||||
|
// Unmarshal reports this when a required field is missing from the wire data.
|
||||||
|
type RequiredNotSetError struct{ field string }
|
||||||
|
|
||||||
|
func (e *RequiredNotSetError) Error() string {
|
||||||
|
if e.field == "" {
|
||||||
|
return fmt.Sprintf("proto: required field not set")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("proto: required field %q not set", e.field)
|
||||||
|
}
|
||||||
|
func (e *RequiredNotSetError) RequiredNotSet() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type invalidUTF8Error struct{ field string }
|
||||||
|
|
||||||
|
func (e *invalidUTF8Error) Error() string {
|
||||||
|
if e.field == "" {
|
||||||
|
return "proto: invalid UTF-8 detected"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field)
|
||||||
|
}
|
||||||
|
func (e *invalidUTF8Error) InvalidUTF8() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8.
|
||||||
|
// This error should not be exposed to the external API as such errors should
|
||||||
|
// be recreated with the field information.
|
||||||
|
var errInvalidUTF8 = &invalidUTF8Error{}
|
||||||
|
|
||||||
|
// isNonFatal reports whether the error is either a RequiredNotSet error
|
||||||
|
// or a InvalidUTF8 error.
|
||||||
|
func isNonFatal(err error) bool {
|
||||||
|
if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonFatal struct{ E error }
|
||||||
|
|
||||||
|
// Merge merges err into nf and reports whether it was successful.
|
||||||
|
// Otherwise it returns false for any fatal non-nil errors.
|
||||||
|
func (nf *nonFatal) Merge(err error) (ok bool) {
|
||||||
|
if err == nil {
|
||||||
|
return true // not an error
|
||||||
|
}
|
||||||
|
if !isNonFatal(err) {
|
||||||
|
return false // fatal error
|
||||||
|
}
|
||||||
|
if nf.E == nil {
|
||||||
|
nf.E = err // store first instance of non-fatal error
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Message is implemented by generated protocol buffer messages.
|
// Message is implemented by generated protocol buffer messages.
|
||||||
type Message interface {
|
type Message interface {
|
||||||
|
|||||||
14
vendor/github.com/golang/protobuf/proto/properties.go
сгенерированный
поставляемый
14
vendor/github.com/golang/protobuf/proto/properties.go
сгенерированный
поставляемый
@@ -139,7 +139,7 @@ type Properties struct {
|
|||||||
Repeated bool
|
Repeated bool
|
||||||
Packed bool // relevant for repeated primitives only
|
Packed bool // relevant for repeated primitives only
|
||||||
Enum string // set for enum types only
|
Enum string // set for enum types only
|
||||||
proto3 bool // whether this is known to be a proto3 field; set for []byte only
|
proto3 bool // whether this is known to be a proto3 field
|
||||||
oneof bool // whether this is a oneof field
|
oneof bool // whether this is a oneof field
|
||||||
|
|
||||||
Default string // default value
|
Default string // default value
|
||||||
@@ -149,8 +149,8 @@ type Properties struct {
|
|||||||
sprop *StructProperties // set for struct types only
|
sprop *StructProperties // set for struct types only
|
||||||
|
|
||||||
mtype reflect.Type // set for map types only
|
mtype reflect.Type // set for map types only
|
||||||
mkeyprop *Properties // set for map types only
|
MapKeyProp *Properties // set for map types only
|
||||||
mvalprop *Properties // set for map types only
|
MapValProp *Properties // set for map types only
|
||||||
}
|
}
|
||||||
|
|
||||||
// String formats the properties in the protobuf struct field tag style.
|
// String formats the properties in the protobuf struct field tag style.
|
||||||
@@ -275,16 +275,16 @@ func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, loc
|
|||||||
|
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
p.mtype = t1
|
p.mtype = t1
|
||||||
p.mkeyprop = &Properties{}
|
p.MapKeyProp = &Properties{}
|
||||||
p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
|
p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
|
||||||
p.mvalprop = &Properties{}
|
p.MapValProp = &Properties{}
|
||||||
vtype := p.mtype.Elem()
|
vtype := p.mtype.Elem()
|
||||||
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
|
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
|
||||||
// The value type is not a message (*T) or bytes ([]byte),
|
// The value type is not a message (*T) or bytes ([]byte),
|
||||||
// so we need encoders for the pointer to this type.
|
// so we need encoders for the pointer to this type.
|
||||||
vtype = reflect.PtrTo(vtype)
|
vtype = reflect.PtrTo(vtype)
|
||||||
}
|
}
|
||||||
p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
|
p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.stype != nil {
|
if p.stype != nil {
|
||||||
|
|||||||
190
vendor/github.com/golang/protobuf/proto/table_marshal.go
сгенерированный
поставляемый
190
vendor/github.com/golang/protobuf/proto/table_marshal.go
сгенерированный
поставляемый
@@ -231,7 +231,7 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
|
|||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var err, errreq error
|
var err, errLater error
|
||||||
// The old marshaler encodes extensions at beginning.
|
// The old marshaler encodes extensions at beginning.
|
||||||
if u.extensions.IsValid() {
|
if u.extensions.IsValid() {
|
||||||
e := ptr.offset(u.extensions).toExtensions()
|
e := ptr.offset(u.extensions).toExtensions()
|
||||||
@@ -252,11 +252,13 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, f := range u.fields {
|
for _, f := range u.fields {
|
||||||
if f.required && errreq == nil {
|
if f.required {
|
||||||
if ptr.offset(f.field).getPointer().isNil() {
|
if ptr.offset(f.field).getPointer().isNil() {
|
||||||
// Required field is not set.
|
// Required field is not set.
|
||||||
// We record the error but keep going, to give a complete marshaling.
|
// We record the error but keep going, to give a complete marshaling.
|
||||||
errreq = &RequiredNotSetError{f.name}
|
if errLater == nil {
|
||||||
|
errLater = &RequiredNotSetError{f.name}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,14 +271,21 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
|
|||||||
if err1, ok := err.(*RequiredNotSetError); ok {
|
if err1, ok := err.(*RequiredNotSetError); ok {
|
||||||
// Required field in submessage is not set.
|
// Required field in submessage is not set.
|
||||||
// We record the error but keep going, to give a complete marshaling.
|
// We record the error but keep going, to give a complete marshaling.
|
||||||
if errreq == nil {
|
if errLater == nil {
|
||||||
errreq = &RequiredNotSetError{f.name + "." + err1.field}
|
errLater = &RequiredNotSetError{f.name + "." + err1.field}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err == errRepeatedHasNil {
|
if err == errRepeatedHasNil {
|
||||||
err = errors.New("proto: repeated field " + f.name + " has nil element")
|
err = errors.New("proto: repeated field " + f.name + " has nil element")
|
||||||
}
|
}
|
||||||
|
if err == errInvalidUTF8 {
|
||||||
|
if errLater == nil {
|
||||||
|
fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
|
||||||
|
errLater = &invalidUTF8Error{fullName}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,7 +293,7 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
|
|||||||
s := *ptr.offset(u.unrecognized).toBytes()
|
s := *ptr.offset(u.unrecognized).toBytes()
|
||||||
b = append(b, s...)
|
b = append(b, s...)
|
||||||
}
|
}
|
||||||
return b, errreq
|
return b, errLater
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeMarshalInfo initializes the marshal info.
|
// computeMarshalInfo initializes the marshal info.
|
||||||
@@ -530,6 +539,7 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
|
|||||||
|
|
||||||
packed := false
|
packed := false
|
||||||
proto3 := false
|
proto3 := false
|
||||||
|
validateUTF8 := true
|
||||||
for i := 2; i < len(tags); i++ {
|
for i := 2; i < len(tags); i++ {
|
||||||
if tags[i] == "packed" {
|
if tags[i] == "packed" {
|
||||||
packed = true
|
packed = true
|
||||||
@@ -538,6 +548,7 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
|
|||||||
proto3 = true
|
proto3 = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
validateUTF8 = validateUTF8 && proto3
|
||||||
|
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
@@ -735,6 +746,18 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
|
|||||||
}
|
}
|
||||||
return sizeFloat64Value, appendFloat64Value
|
return sizeFloat64Value, appendFloat64Value
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
|
if validateUTF8 {
|
||||||
|
if pointer {
|
||||||
|
return sizeStringPtr, appendUTF8StringPtr
|
||||||
|
}
|
||||||
|
if slice {
|
||||||
|
return sizeStringSlice, appendUTF8StringSlice
|
||||||
|
}
|
||||||
|
if nozero {
|
||||||
|
return sizeStringValueNoZero, appendUTF8StringValueNoZero
|
||||||
|
}
|
||||||
|
return sizeStringValue, appendUTF8StringValue
|
||||||
|
}
|
||||||
if pointer {
|
if pointer {
|
||||||
return sizeStringPtr, appendStringPtr
|
return sizeStringPtr, appendStringPtr
|
||||||
}
|
}
|
||||||
@@ -1984,9 +2007,6 @@ func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byt
|
|||||||
}
|
}
|
||||||
func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
v := *ptr.toString()
|
v := *ptr.toString()
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
b = appendVarint(b, wiretag)
|
b = appendVarint(b, wiretag)
|
||||||
b = appendVarint(b, uint64(len(v)))
|
b = appendVarint(b, uint64(len(v)))
|
||||||
b = append(b, v...)
|
b = append(b, v...)
|
||||||
@@ -1997,9 +2017,6 @@ func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]b
|
|||||||
if v == "" {
|
if v == "" {
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
b = appendVarint(b, wiretag)
|
b = appendVarint(b, wiretag)
|
||||||
b = appendVarint(b, uint64(len(v)))
|
b = appendVarint(b, uint64(len(v)))
|
||||||
b = append(b, v...)
|
b = append(b, v...)
|
||||||
@@ -2011,9 +2028,6 @@ func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, err
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
v := *p
|
v := *p
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
b = appendVarint(b, wiretag)
|
b = appendVarint(b, wiretag)
|
||||||
b = appendVarint(b, uint64(len(v)))
|
b = appendVarint(b, uint64(len(v)))
|
||||||
b = append(b, v...)
|
b = append(b, v...)
|
||||||
@@ -2022,12 +2036,74 @@ func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, err
|
|||||||
func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
s := *ptr.toStringSlice()
|
s := *ptr.toStringSlice()
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
|
b = appendVarint(b, wiretag)
|
||||||
|
b = appendVarint(b, uint64(len(v)))
|
||||||
|
b = append(b, v...)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
var invalidUTF8 bool
|
||||||
|
v := *ptr.toString()
|
||||||
if !utf8.ValidString(v) {
|
if !utf8.ValidString(v) {
|
||||||
return nil, errInvalidUTF8
|
invalidUTF8 = true
|
||||||
}
|
}
|
||||||
b = appendVarint(b, wiretag)
|
b = appendVarint(b, wiretag)
|
||||||
b = appendVarint(b, uint64(len(v)))
|
b = appendVarint(b, uint64(len(v)))
|
||||||
b = append(b, v...)
|
b = append(b, v...)
|
||||||
|
if invalidUTF8 {
|
||||||
|
return b, errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
var invalidUTF8 bool
|
||||||
|
v := *ptr.toString()
|
||||||
|
if v == "" {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
invalidUTF8 = true
|
||||||
|
}
|
||||||
|
b = appendVarint(b, wiretag)
|
||||||
|
b = appendVarint(b, uint64(len(v)))
|
||||||
|
b = append(b, v...)
|
||||||
|
if invalidUTF8 {
|
||||||
|
return b, errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
var invalidUTF8 bool
|
||||||
|
p := *ptr.toStringPtr()
|
||||||
|
if p == nil {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
v := *p
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
invalidUTF8 = true
|
||||||
|
}
|
||||||
|
b = appendVarint(b, wiretag)
|
||||||
|
b = appendVarint(b, uint64(len(v)))
|
||||||
|
b = append(b, v...)
|
||||||
|
if invalidUTF8 {
|
||||||
|
return b, errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
|
||||||
|
var invalidUTF8 bool
|
||||||
|
s := *ptr.toStringSlice()
|
||||||
|
for _, v := range s {
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
invalidUTF8 = true
|
||||||
|
}
|
||||||
|
b = appendVarint(b, wiretag)
|
||||||
|
b = appendVarint(b, uint64(len(v)))
|
||||||
|
b = append(b, v...)
|
||||||
|
}
|
||||||
|
if invalidUTF8 {
|
||||||
|
return b, errInvalidUTF8
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
@@ -2107,7 +2183,8 @@ func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
|
|||||||
},
|
},
|
||||||
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
|
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
|
||||||
s := ptr.getPointerSlice()
|
s := ptr.getPointerSlice()
|
||||||
var err, errreq error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
if v.isNil() {
|
if v.isNil() {
|
||||||
return b, errRepeatedHasNil
|
return b, errRepeatedHasNil
|
||||||
@@ -2115,22 +2192,14 @@ func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
|
|||||||
b = appendVarint(b, wiretag) // start group
|
b = appendVarint(b, wiretag) // start group
|
||||||
b, err = u.marshal(b, v, deterministic)
|
b, err = u.marshal(b, v, deterministic)
|
||||||
b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group
|
b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
if _, ok := err.(*RequiredNotSetError); ok {
|
|
||||||
// Required field in submessage is not set.
|
|
||||||
// We record the error but keep going, to give a complete marshaling.
|
|
||||||
if errreq == nil {
|
|
||||||
errreq = err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err == ErrNil {
|
if err == ErrNil {
|
||||||
err = errRepeatedHasNil
|
err = errRepeatedHasNil
|
||||||
}
|
}
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, errreq
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2174,7 +2243,8 @@ func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
|
|||||||
},
|
},
|
||||||
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
|
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
|
||||||
s := ptr.getPointerSlice()
|
s := ptr.getPointerSlice()
|
||||||
var err, errreq error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
if v.isNil() {
|
if v.isNil() {
|
||||||
return b, errRepeatedHasNil
|
return b, errRepeatedHasNil
|
||||||
@@ -2184,22 +2254,14 @@ func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
|
|||||||
b = appendVarint(b, uint64(siz))
|
b = appendVarint(b, uint64(siz))
|
||||||
b, err = u.marshal(b, v, deterministic)
|
b, err = u.marshal(b, v, deterministic)
|
||||||
|
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
if _, ok := err.(*RequiredNotSetError); ok {
|
|
||||||
// Required field in submessage is not set.
|
|
||||||
// We record the error but keep going, to give a complete marshaling.
|
|
||||||
if errreq == nil {
|
|
||||||
errreq = err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err == ErrNil {
|
if err == ErrNil {
|
||||||
err = errRepeatedHasNil
|
err = errRepeatedHasNil
|
||||||
}
|
}
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, errreq
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2223,6 +2285,25 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
|
|||||||
// value.
|
// value.
|
||||||
// Key cannot be pointer-typed.
|
// Key cannot be pointer-typed.
|
||||||
valIsPtr := valType.Kind() == reflect.Ptr
|
valIsPtr := valType.Kind() == reflect.Ptr
|
||||||
|
|
||||||
|
// If value is a message with nested maps, calling
|
||||||
|
// valSizer in marshal may be quadratic. We should use
|
||||||
|
// cached version in marshal (but not in size).
|
||||||
|
// If value is not message type, we don't have size cache,
|
||||||
|
// but it cannot be nested either. Just use valSizer.
|
||||||
|
valCachedSizer := valSizer
|
||||||
|
if valIsPtr && valType.Elem().Kind() == reflect.Struct {
|
||||||
|
u := getMarshalInfo(valType.Elem())
|
||||||
|
valCachedSizer = func(ptr pointer, tagsize int) int {
|
||||||
|
// Same as message sizer, but use cache.
|
||||||
|
p := ptr.getPointer()
|
||||||
|
if p.isNil() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
siz := u.cachedsize(p)
|
||||||
|
return siz + SizeVarint(uint64(siz)) + tagsize
|
||||||
|
}
|
||||||
|
}
|
||||||
return func(ptr pointer, tagsize int) int {
|
return func(ptr pointer, tagsize int) int {
|
||||||
m := ptr.asPointerTo(t).Elem() // the map
|
m := ptr.asPointerTo(t).Elem() // the map
|
||||||
n := 0
|
n := 0
|
||||||
@@ -2243,24 +2324,26 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
|
|||||||
if len(keys) > 1 && deterministic {
|
if len(keys) > 1 && deterministic {
|
||||||
sort.Sort(mapKeys(keys))
|
sort.Sort(mapKeys(keys))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nerr nonFatal
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
ki := k.Interface()
|
ki := k.Interface()
|
||||||
vi := m.MapIndex(k).Interface()
|
vi := m.MapIndex(k).Interface()
|
||||||
kaddr := toAddrPointer(&ki, false) // pointer to key
|
kaddr := toAddrPointer(&ki, false) // pointer to key
|
||||||
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
|
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
|
||||||
b = appendVarint(b, tag)
|
b = appendVarint(b, tag)
|
||||||
siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
|
siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
|
||||||
b = appendVarint(b, uint64(siz))
|
b = appendVarint(b, uint64(siz))
|
||||||
b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic)
|
b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
b, err = valMarshaler(b, vaddr, valWireTag, deterministic)
|
b, err = valMarshaler(b, vaddr, valWireTag, deterministic)
|
||||||
if err != nil && err != ErrNil { // allow nil value in map
|
if err != ErrNil && !nerr.Merge(err) { // allow nil value in map
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2333,6 +2416,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
|
|
||||||
// Fast-path for common cases: zero or one extensions.
|
// Fast-path for common cases: zero or one extensions.
|
||||||
// Don't bother sorting the keys.
|
// Don't bother sorting the keys.
|
||||||
@@ -2352,11 +2436,11 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the keys to provide a deterministic encoding.
|
// Sort the keys to provide a deterministic encoding.
|
||||||
@@ -2383,11 +2467,11 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// message set format is:
|
// message set format is:
|
||||||
@@ -2444,6 +2528,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
|
|
||||||
// Fast-path for common cases: zero or one extensions.
|
// Fast-path for common cases: zero or one extensions.
|
||||||
// Don't bother sorting the keys.
|
// Don't bother sorting the keys.
|
||||||
@@ -2470,12 +2555,12 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
b = append(b, 1<<3|WireEndGroup)
|
b = append(b, 1<<3|WireEndGroup)
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the keys to provide a deterministic encoding.
|
// Sort the keys to provide a deterministic encoding.
|
||||||
@@ -2509,11 +2594,11 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
|
|||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
|
||||||
b = append(b, 1<<3|WireEndGroup)
|
b = append(b, 1<<3|WireEndGroup)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// sizeV1Extensions computes the size of encoded data for a V1-API extension field.
|
// sizeV1Extensions computes the size of encoded data for a V1-API extension field.
|
||||||
@@ -2556,6 +2641,7 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
|
|||||||
sort.Ints(keys)
|
sort.Ints(keys)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
e := m[int32(k)]
|
e := m[int32(k)]
|
||||||
if e.value == nil || e.desc == nil {
|
if e.value == nil || e.desc == nil {
|
||||||
@@ -2572,11 +2658,11 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
|
|||||||
v := e.value
|
v := e.value
|
||||||
p := toAddrPointer(&v, ei.isptr)
|
p := toAddrPointer(&v, ei.isptr)
|
||||||
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
|
|
||||||
// newMarshaler is the interface representing objects that can marshal themselves.
|
// newMarshaler is the interface representing objects that can marshal themselves.
|
||||||
|
|||||||
144
vendor/github.com/golang/protobuf/proto/table_unmarshal.go
сгенерированный
поставляемый
144
vendor/github.com/golang/protobuf/proto/table_unmarshal.go
сгенерированный
поставляемый
@@ -97,6 +97,8 @@ type unmarshalFieldInfo struct {
|
|||||||
|
|
||||||
// if a required field, contains a single set bit at this field's index in the required field list.
|
// if a required field, contains a single set bit at this field's index in the required field list.
|
||||||
reqMask uint64
|
reqMask uint64
|
||||||
|
|
||||||
|
name string // name of the field, for error reporting
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -137,7 +139,7 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
|
|||||||
return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
|
return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
|
||||||
}
|
}
|
||||||
var reqMask uint64 // bitmask of required fields we've seen.
|
var reqMask uint64 // bitmask of required fields we've seen.
|
||||||
var rnse *RequiredNotSetError // an instance of a RequiredNotSetError returned by a submessage.
|
var errLater error
|
||||||
for len(b) > 0 {
|
for len(b) > 0 {
|
||||||
// Read tag and wire type.
|
// Read tag and wire type.
|
||||||
// Special case 1 and 2 byte varints.
|
// Special case 1 and 2 byte varints.
|
||||||
@@ -176,11 +178,20 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
|
|||||||
if r, ok := err.(*RequiredNotSetError); ok {
|
if r, ok := err.(*RequiredNotSetError); ok {
|
||||||
// Remember this error, but keep parsing. We need to produce
|
// Remember this error, but keep parsing. We need to produce
|
||||||
// a full parse even if a required field is missing.
|
// a full parse even if a required field is missing.
|
||||||
rnse = r
|
if errLater == nil {
|
||||||
|
errLater = r
|
||||||
|
}
|
||||||
reqMask |= f.reqMask
|
reqMask |= f.reqMask
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != errInternalBadWireType {
|
if err != errInternalBadWireType {
|
||||||
|
if err == errInvalidUTF8 {
|
||||||
|
if errLater == nil {
|
||||||
|
fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
|
||||||
|
errLater = &invalidUTF8Error{fullName}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Fragments with bad wire type are treated as unknown fields.
|
// Fragments with bad wire type are treated as unknown fields.
|
||||||
@@ -239,20 +250,16 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
|
|||||||
emap[int32(tag)] = e
|
emap[int32(tag)] = e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rnse != nil {
|
if reqMask != u.reqMask && errLater == nil {
|
||||||
// A required field of a submessage/group is missing. Return that error.
|
|
||||||
return rnse
|
|
||||||
}
|
|
||||||
if reqMask != u.reqMask {
|
|
||||||
// A required field of this message is missing.
|
// A required field of this message is missing.
|
||||||
for _, n := range u.reqFields {
|
for _, n := range u.reqFields {
|
||||||
if reqMask&1 == 0 {
|
if reqMask&1 == 0 {
|
||||||
return &RequiredNotSetError{n}
|
errLater = &RequiredNotSetError{n}
|
||||||
}
|
}
|
||||||
reqMask >>= 1
|
reqMask >>= 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return errLater
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeUnmarshalInfo fills in u with information for use
|
// computeUnmarshalInfo fills in u with information for use
|
||||||
@@ -351,7 +358,7 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store the info in the correct slot in the message.
|
// Store the info in the correct slot in the message.
|
||||||
u.setTag(tag, toField(&f), unmarshal, reqMask)
|
u.setTag(tag, toField(&f), unmarshal, reqMask, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find any types associated with oneof fields.
|
// Find any types associated with oneof fields.
|
||||||
@@ -366,10 +373,17 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
|
|
||||||
f := typ.Field(0) // oneof implementers have one field
|
f := typ.Field(0) // oneof implementers have one field
|
||||||
baseUnmarshal := fieldUnmarshaler(&f)
|
baseUnmarshal := fieldUnmarshaler(&f)
|
||||||
tagstr := strings.Split(f.Tag.Get("protobuf"), ",")[1]
|
tags := strings.Split(f.Tag.Get("protobuf"), ",")
|
||||||
tag, err := strconv.Atoi(tagstr)
|
fieldNum, err := strconv.Atoi(tags[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("protobuf tag field not an integer: " + tagstr)
|
panic("protobuf tag field not an integer: " + tags[1])
|
||||||
|
}
|
||||||
|
var name string
|
||||||
|
for _, tag := range tags {
|
||||||
|
if strings.HasPrefix(tag, "name=") {
|
||||||
|
name = strings.TrimPrefix(tag, "name=")
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the oneof field that this struct implements.
|
// Find the oneof field that this struct implements.
|
||||||
@@ -380,7 +394,7 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
// That lets us know where this struct should be stored
|
// That lets us know where this struct should be stored
|
||||||
// when we encounter it during unmarshaling.
|
// when we encounter it during unmarshaling.
|
||||||
unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
|
unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal)
|
||||||
u.setTag(tag, of.field, unmarshal, 0)
|
u.setTag(fieldNum, of.field, unmarshal, 0, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,7 +415,7 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
// [0 0] is [tag=0/wiretype=varint varint-encoded-0].
|
// [0 0] is [tag=0/wiretype=varint varint-encoded-0].
|
||||||
u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) {
|
u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w)
|
return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w)
|
||||||
}, 0)
|
}, 0, "")
|
||||||
|
|
||||||
// Set mask for required field check.
|
// Set mask for required field check.
|
||||||
u.reqMask = uint64(1)<<uint(len(u.reqFields)) - 1
|
u.reqMask = uint64(1)<<uint(len(u.reqFields)) - 1
|
||||||
@@ -413,8 +427,9 @@ func (u *unmarshalInfo) computeUnmarshalInfo() {
|
|||||||
// tag = tag # for field
|
// tag = tag # for field
|
||||||
// field/unmarshal = unmarshal info for that field.
|
// field/unmarshal = unmarshal info for that field.
|
||||||
// reqMask = if required, bitmask for field position in required field list. 0 otherwise.
|
// reqMask = if required, bitmask for field position in required field list. 0 otherwise.
|
||||||
func (u *unmarshalInfo) setTag(tag int, field field, unmarshal unmarshaler, reqMask uint64) {
|
// name = short name of the field.
|
||||||
i := unmarshalFieldInfo{field: field, unmarshal: unmarshal, reqMask: reqMask}
|
func (u *unmarshalInfo) setTag(tag int, field field, unmarshal unmarshaler, reqMask uint64, name string) {
|
||||||
|
i := unmarshalFieldInfo{field: field, unmarshal: unmarshal, reqMask: reqMask, name: name}
|
||||||
n := u.typ.NumField()
|
n := u.typ.NumField()
|
||||||
if tag >= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here?
|
if tag >= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here?
|
||||||
for len(u.dense) <= tag {
|
for len(u.dense) <= tag {
|
||||||
@@ -442,11 +457,17 @@ func typeUnmarshaler(t reflect.Type, tags string) unmarshaler {
|
|||||||
tagArray := strings.Split(tags, ",")
|
tagArray := strings.Split(tags, ",")
|
||||||
encoding := tagArray[0]
|
encoding := tagArray[0]
|
||||||
name := "unknown"
|
name := "unknown"
|
||||||
|
proto3 := false
|
||||||
|
validateUTF8 := true
|
||||||
for _, tag := range tagArray[3:] {
|
for _, tag := range tagArray[3:] {
|
||||||
if strings.HasPrefix(tag, "name=") {
|
if strings.HasPrefix(tag, "name=") {
|
||||||
name = tag[5:]
|
name = tag[5:]
|
||||||
}
|
}
|
||||||
|
if tag == "proto3" {
|
||||||
|
proto3 = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
validateUTF8 = validateUTF8 && proto3
|
||||||
|
|
||||||
// Figure out packaging (pointer, slice, or both)
|
// Figure out packaging (pointer, slice, or both)
|
||||||
slice := false
|
slice := false
|
||||||
@@ -594,6 +615,15 @@ func typeUnmarshaler(t reflect.Type, tags string) unmarshaler {
|
|||||||
}
|
}
|
||||||
return unmarshalBytesValue
|
return unmarshalBytesValue
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
|
if validateUTF8 {
|
||||||
|
if pointer {
|
||||||
|
return unmarshalUTF8StringPtr
|
||||||
|
}
|
||||||
|
if slice {
|
||||||
|
return unmarshalUTF8StringSlice
|
||||||
|
}
|
||||||
|
return unmarshalUTF8StringValue
|
||||||
|
}
|
||||||
if pointer {
|
if pointer {
|
||||||
return unmarshalStringPtr
|
return unmarshalStringPtr
|
||||||
}
|
}
|
||||||
@@ -1448,9 +1478,6 @@ func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) {
|
|||||||
return nil, io.ErrUnexpectedEOF
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
v := string(b[:x])
|
v := string(b[:x])
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
*f.toString() = v
|
*f.toString() = v
|
||||||
return b[x:], nil
|
return b[x:], nil
|
||||||
}
|
}
|
||||||
@@ -1468,9 +1495,6 @@ func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) {
|
|||||||
return nil, io.ErrUnexpectedEOF
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
v := string(b[:x])
|
v := string(b[:x])
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
*f.toStringPtr() = &v
|
*f.toStringPtr() = &v
|
||||||
return b[x:], nil
|
return b[x:], nil
|
||||||
}
|
}
|
||||||
@@ -1488,14 +1512,72 @@ func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) {
|
|||||||
return nil, io.ErrUnexpectedEOF
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
v := string(b[:x])
|
v := string(b[:x])
|
||||||
if !utf8.ValidString(v) {
|
|
||||||
return nil, errInvalidUTF8
|
|
||||||
}
|
|
||||||
s := f.toStringSlice()
|
s := f.toStringSlice()
|
||||||
*s = append(*s, v)
|
*s = append(*s, v)
|
||||||
return b[x:], nil
|
return b[x:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
|
if w != WireBytes {
|
||||||
|
return b, errInternalBadWireType
|
||||||
|
}
|
||||||
|
x, n := decodeVarint(b)
|
||||||
|
if n == 0 {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b = b[n:]
|
||||||
|
if x > uint64(len(b)) {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
v := string(b[:x])
|
||||||
|
*f.toString() = v
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
return b[x:], errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b[x:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
|
if w != WireBytes {
|
||||||
|
return b, errInternalBadWireType
|
||||||
|
}
|
||||||
|
x, n := decodeVarint(b)
|
||||||
|
if n == 0 {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b = b[n:]
|
||||||
|
if x > uint64(len(b)) {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
v := string(b[:x])
|
||||||
|
*f.toStringPtr() = &v
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
return b[x:], errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b[x:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
|
if w != WireBytes {
|
||||||
|
return b, errInternalBadWireType
|
||||||
|
}
|
||||||
|
x, n := decodeVarint(b)
|
||||||
|
if n == 0 {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b = b[n:]
|
||||||
|
if x > uint64(len(b)) {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
v := string(b[:x])
|
||||||
|
s := f.toStringSlice()
|
||||||
|
*s = append(*s, v)
|
||||||
|
if !utf8.ValidString(v) {
|
||||||
|
return b[x:], errInvalidUTF8
|
||||||
|
}
|
||||||
|
return b[x:], nil
|
||||||
|
}
|
||||||
|
|
||||||
var emptyBuf [0]byte
|
var emptyBuf [0]byte
|
||||||
|
|
||||||
func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) {
|
func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) {
|
||||||
@@ -1674,6 +1756,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
|
|||||||
// Maps will be somewhat slow. Oh well.
|
// Maps will be somewhat slow. Oh well.
|
||||||
|
|
||||||
// Read key and value from data.
|
// Read key and value from data.
|
||||||
|
var nerr nonFatal
|
||||||
k := reflect.New(kt)
|
k := reflect.New(kt)
|
||||||
v := reflect.New(vt)
|
v := reflect.New(vt)
|
||||||
for len(b) > 0 {
|
for len(b) > 0 {
|
||||||
@@ -1694,7 +1777,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
|
|||||||
err = errInternalBadWireType // skip unknown tag
|
err = errInternalBadWireType // skip unknown tag
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if nerr.Merge(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != errInternalBadWireType {
|
if err != errInternalBadWireType {
|
||||||
@@ -1717,7 +1800,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
|
|||||||
// Insert into map.
|
// Insert into map.
|
||||||
m.SetMapIndex(k.Elem(), v.Elem())
|
m.SetMapIndex(k.Elem(), v.Elem())
|
||||||
|
|
||||||
return r, nil
|
return r, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1743,15 +1826,16 @@ func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshal
|
|||||||
// Unmarshal data into holder.
|
// Unmarshal data into holder.
|
||||||
// We unmarshal into the first field of the holder object.
|
// We unmarshal into the first field of the holder object.
|
||||||
var err error
|
var err error
|
||||||
|
var nerr nonFatal
|
||||||
b, err = unmarshal(b, valToPointer(v).offset(field0), w)
|
b, err = unmarshal(b, valToPointer(v).offset(field0), w)
|
||||||
if err != nil {
|
if !nerr.Merge(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write pointer to holder into target field.
|
// Write pointer to holder into target field.
|
||||||
f.asPointerTo(ityp).Elem().Set(v)
|
f.asPointerTo(ityp).Elem().Set(v)
|
||||||
|
|
||||||
return b, nil
|
return b, nerr.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
vendor/github.com/golang/protobuf/proto/text.go
сгенерированный
поставляемый
4
vendor/github.com/golang/protobuf/proto/text.go
сгенерированный
поставляемый
@@ -353,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := tm.writeAny(w, key, props.mkeyprop); err != nil {
|
if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.WriteByte('\n'); err != nil {
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
@@ -370,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := tm.writeAny(w, val, props.mvalprop); err != nil {
|
if err := tm.writeAny(w, val, props.MapValProp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.WriteByte('\n'); err != nil {
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
|||||||
6
vendor/github.com/golang/protobuf/proto/text_parser.go
сгенерированный
поставляемый
6
vendor/github.com/golang/protobuf/proto/text_parser.go
сгенерированный
поставляемый
@@ -630,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
|||||||
if err := p.consumeToken(":"); err != nil {
|
if err := p.consumeToken(":"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := p.readAny(key, props.mkeyprop); err != nil {
|
if err := p.readAny(key, props.MapKeyProp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "value":
|
case "value":
|
||||||
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
|
if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := p.readAny(val, props.mvalprop); err != nil {
|
if err := p.readAny(val, props.MapValProp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
|||||||
10
vendor/github.com/golang/protobuf/ptypes/any.go
сгенерированный
поставляемый
10
vendor/github.com/golang/protobuf/ptypes/any.go
сгенерированный
поставляемый
@@ -130,10 +130,12 @@ func UnmarshalAny(any *any.Any, pb proto.Message) error {
|
|||||||
|
|
||||||
// Is returns true if any value contains a given message type.
|
// Is returns true if any value contains a given message type.
|
||||||
func Is(any *any.Any, pb proto.Message) bool {
|
func Is(any *any.Any, pb proto.Message) bool {
|
||||||
aname, err := AnyMessageName(any)
|
// The following is equivalent to AnyMessageName(any) == proto.MessageName(pb),
|
||||||
if err != nil {
|
// but it avoids scanning TypeUrl for the slash.
|
||||||
|
if any == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
name := proto.MessageName(pb)
|
||||||
return aname == proto.MessageName(pb)
|
prefix := len(any.TypeUrl) - len(name)
|
||||||
|
return prefix >= 1 && any.TypeUrl[prefix-1] == '/' && any.TypeUrl[prefix:] == name
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
сгенерированный
поставляемый
2
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
сгенерированный
поставляемый
@@ -121,7 +121,7 @@ type Any struct {
|
|||||||
// Schemes other than `http`, `https` (or the empty scheme) might be
|
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||||
// used with implementation specific semantics.
|
// used with implementation specific semantics.
|
||||||
//
|
//
|
||||||
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"`
|
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"`
|
||||||
// Must be a valid serialized protocol buffer of the above specified type.
|
// Must be a valid serialized protocol buffer of the above specified type.
|
||||||
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
|
|||||||
4
vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
сгенерированный
поставляемый
4
vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
сгенерированный
поставляемый
@@ -82,14 +82,14 @@ type Duration struct {
|
|||||||
// Signed seconds of the span of time. Must be from -315,576,000,000
|
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||||
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||||
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||||
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
|
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||||
// Signed fractions of a second at nanosecond resolution of the span
|
// Signed fractions of a second at nanosecond resolution of the span
|
||||||
// of time. Durations less than one second are represented with a 0
|
// of time. Durations less than one second are represented with a 0
|
||||||
// `seconds` field and a positive or negative `nanos` field. For durations
|
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||||
// of one second or more, a non-zero value for the `nanos` field must be
|
// of one second or more, a non-zero value for the `nanos` field must be
|
||||||
// of the same sign as the `seconds` field. Must be from -999,999,999
|
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||||
// to +999,999,999 inclusive.
|
// to +999,999,999 inclusive.
|
||||||
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
|
Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
XXX_unrecognized []byte `json:"-"`
|
XXX_unrecognized []byte `json:"-"`
|
||||||
XXX_sizecache int32 `json:"-"`
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
|||||||
4
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
сгенерированный
поставляемый
4
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
сгенерированный
поставляемый
@@ -100,12 +100,12 @@ type Timestamp struct {
|
|||||||
// Represents seconds of UTC time since Unix epoch
|
// Represents seconds of UTC time since Unix epoch
|
||||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||||
// 9999-12-31T23:59:59Z inclusive.
|
// 9999-12-31T23:59:59Z inclusive.
|
||||||
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
|
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||||
// second values with fractions must still have non-negative nanos values
|
// second values with fractions must still have non-negative nanos values
|
||||||
// that count forward in time. Must be from 0 to 999,999,999
|
// that count forward in time. Must be from 0 to 999,999,999
|
||||||
// inclusive.
|
// inclusive.
|
||||||
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
|
Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||||
XXX_unrecognized []byte `json:"-"`
|
XXX_unrecognized []byte `json:"-"`
|
||||||
XXX_sizecache int32 `json:"-"`
|
XXX_sizecache int32 `json:"-"`
|
||||||
|
|||||||
15
vendor/github.com/gorilla/handlers/cors.go
сгенерированный
поставляемый
15
vendor/github.com/gorilla/handlers/cors.go
сгенерированный
поставляемый
@@ -48,7 +48,10 @@ const (
|
|||||||
func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
origin := r.Header.Get(corsOriginHeader)
|
origin := r.Header.Get(corsOriginHeader)
|
||||||
if !ch.isOriginAllowed(origin) {
|
if !ch.isOriginAllowed(origin) {
|
||||||
|
if r.Method != corsOptionMethod || ch.ignoreOptions {
|
||||||
ch.h.ServeHTTP(w, r)
|
ch.h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,15 +114,19 @@ func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
returnOrigin := origin
|
returnOrigin := origin
|
||||||
|
if ch.allowedOriginValidator == nil && len(ch.allowedOrigins) == 0 {
|
||||||
|
returnOrigin = "*"
|
||||||
|
} else {
|
||||||
for _, o := range ch.allowedOrigins {
|
for _, o := range ch.allowedOrigins {
|
||||||
// A configuration of * is different than explicitly setting an allowed
|
// A configuration of * is different than explicitly setting an allowed
|
||||||
// origin. Returning arbitrary origin headers an an access control allow
|
// origin. Returning arbitrary origin headers in an access control allow
|
||||||
// origin header is unsafe and is not required by any use case.
|
// origin header is unsafe and is not required by any use case.
|
||||||
if o == corsOriginMatchAll {
|
if o == corsOriginMatchAll {
|
||||||
returnOrigin = "*"
|
returnOrigin = "*"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
w.Header().Set(corsAllowOriginHeader, returnOrigin)
|
w.Header().Set(corsAllowOriginHeader, returnOrigin)
|
||||||
|
|
||||||
if r.Method == corsOptionMethod {
|
if r.Method == corsOptionMethod {
|
||||||
@@ -159,7 +166,7 @@ func parseCORSOptions(opts ...CORSOption) *cors {
|
|||||||
ch := &cors{
|
ch := &cors{
|
||||||
allowedMethods: defaultCorsMethods,
|
allowedMethods: defaultCorsMethods,
|
||||||
allowedHeaders: defaultCorsHeaders,
|
allowedHeaders: defaultCorsHeaders,
|
||||||
allowedOrigins: []string{corsOriginMatchAll},
|
allowedOrigins: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, option := range opts {
|
for _, option := range opts {
|
||||||
@@ -307,6 +314,10 @@ func (ch *cors) isOriginAllowed(origin string) bool {
|
|||||||
return ch.allowedOriginValidator(origin)
|
return ch.allowedOriginValidator(origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(ch.allowedOrigins) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
for _, allowedOrigin := range ch.allowedOrigins {
|
for _, allowedOrigin := range ch.allowedOrigins {
|
||||||
if allowedOrigin == origin || allowedOrigin == corsOriginMatchAll {
|
if allowedOrigin == origin || allowedOrigin == corsOriginMatchAll {
|
||||||
return true
|
return true
|
||||||
|
|||||||
225
vendor/github.com/gorilla/handlers/handlers.go
сгенерированный
поставляемый
225
vendor/github.com/gorilla/handlers/handlers.go
сгенерированный
поставляемый
@@ -7,15 +7,10 @@ package handlers
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MethodHandler is an http.Handler that dispatches to a handler whose key in the
|
// MethodHandler is an http.Handler that dispatches to a handler whose key in the
|
||||||
@@ -48,59 +43,6 @@ func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its
|
|
||||||
// friends
|
|
||||||
type loggingHandler struct {
|
|
||||||
writer io.Writer
|
|
||||||
handler http.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// combinedLoggingHandler is the http.Handler implementation for LoggingHandlerTo
|
|
||||||
// and its friends
|
|
||||||
type combinedLoggingHandler struct {
|
|
||||||
writer io.Writer
|
|
||||||
handler http.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
||||||
t := time.Now()
|
|
||||||
logger := makeLogger(w)
|
|
||||||
url := *req.URL
|
|
||||||
h.handler.ServeHTTP(logger, req)
|
|
||||||
writeLog(h.writer, req, url, t, logger.Status(), logger.Size())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h combinedLoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
||||||
t := time.Now()
|
|
||||||
logger := makeLogger(w)
|
|
||||||
url := *req.URL
|
|
||||||
h.handler.ServeHTTP(logger, req)
|
|
||||||
writeCombinedLog(h.writer, req, url, t, logger.Status(), logger.Size())
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeLogger(w http.ResponseWriter) loggingResponseWriter {
|
|
||||||
var logger loggingResponseWriter = &responseLogger{w: w, status: http.StatusOK}
|
|
||||||
if _, ok := w.(http.Hijacker); ok {
|
|
||||||
logger = &hijackLogger{responseLogger{w: w, status: http.StatusOK}}
|
|
||||||
}
|
|
||||||
h, ok1 := logger.(http.Hijacker)
|
|
||||||
c, ok2 := w.(http.CloseNotifier)
|
|
||||||
if ok1 && ok2 {
|
|
||||||
return hijackCloseNotifier{logger, h, c}
|
|
||||||
}
|
|
||||||
if ok2 {
|
|
||||||
return &closeNotifyWriter{logger, c}
|
|
||||||
}
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type commonLoggingResponseWriter interface {
|
|
||||||
http.ResponseWriter
|
|
||||||
http.Flusher
|
|
||||||
Status() int
|
|
||||||
Size() int
|
|
||||||
}
|
|
||||||
|
|
||||||
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP
|
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP
|
||||||
// status code and body size
|
// status code and body size
|
||||||
type responseLogger struct {
|
type responseLogger struct {
|
||||||
@@ -165,173 +107,6 @@ type hijackCloseNotifier struct {
|
|||||||
http.CloseNotifier
|
http.CloseNotifier
|
||||||
}
|
}
|
||||||
|
|
||||||
const lowerhex = "0123456789abcdef"
|
|
||||||
|
|
||||||
func appendQuoted(buf []byte, s string) []byte {
|
|
||||||
var runeTmp [utf8.UTFMax]byte
|
|
||||||
for width := 0; len(s) > 0; s = s[width:] {
|
|
||||||
r := rune(s[0])
|
|
||||||
width = 1
|
|
||||||
if r >= utf8.RuneSelf {
|
|
||||||
r, width = utf8.DecodeRuneInString(s)
|
|
||||||
}
|
|
||||||
if width == 1 && r == utf8.RuneError {
|
|
||||||
buf = append(buf, `\x`...)
|
|
||||||
buf = append(buf, lowerhex[s[0]>>4])
|
|
||||||
buf = append(buf, lowerhex[s[0]&0xF])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if r == rune('"') || r == '\\' { // always backslashed
|
|
||||||
buf = append(buf, '\\')
|
|
||||||
buf = append(buf, byte(r))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strconv.IsPrint(r) {
|
|
||||||
n := utf8.EncodeRune(runeTmp[:], r)
|
|
||||||
buf = append(buf, runeTmp[:n]...)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch r {
|
|
||||||
case '\a':
|
|
||||||
buf = append(buf, `\a`...)
|
|
||||||
case '\b':
|
|
||||||
buf = append(buf, `\b`...)
|
|
||||||
case '\f':
|
|
||||||
buf = append(buf, `\f`...)
|
|
||||||
case '\n':
|
|
||||||
buf = append(buf, `\n`...)
|
|
||||||
case '\r':
|
|
||||||
buf = append(buf, `\r`...)
|
|
||||||
case '\t':
|
|
||||||
buf = append(buf, `\t`...)
|
|
||||||
case '\v':
|
|
||||||
buf = append(buf, `\v`...)
|
|
||||||
default:
|
|
||||||
switch {
|
|
||||||
case r < ' ':
|
|
||||||
buf = append(buf, `\x`...)
|
|
||||||
buf = append(buf, lowerhex[s[0]>>4])
|
|
||||||
buf = append(buf, lowerhex[s[0]&0xF])
|
|
||||||
case r > utf8.MaxRune:
|
|
||||||
r = 0xFFFD
|
|
||||||
fallthrough
|
|
||||||
case r < 0x10000:
|
|
||||||
buf = append(buf, `\u`...)
|
|
||||||
for s := 12; s >= 0; s -= 4 {
|
|
||||||
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
buf = append(buf, `\U`...)
|
|
||||||
for s := 28; s >= 0; s -= 4 {
|
|
||||||
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildCommonLogLine builds a log entry for req in Apache Common Log Format.
|
|
||||||
// ts is the timestamp with which the entry should be logged.
|
|
||||||
// status and size are used to provide the response HTTP status and size.
|
|
||||||
func buildCommonLogLine(req *http.Request, url url.URL, ts time.Time, status int, size int) []byte {
|
|
||||||
username := "-"
|
|
||||||
if url.User != nil {
|
|
||||||
if name := url.User.Username(); name != "" {
|
|
||||||
username = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
host = req.RemoteAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
uri := req.RequestURI
|
|
||||||
|
|
||||||
// Requests using the CONNECT method over HTTP/2.0 must use
|
|
||||||
// the authority field (aka r.Host) to identify the target.
|
|
||||||
// Refer: https://httpwg.github.io/specs/rfc7540.html#CONNECT
|
|
||||||
if req.ProtoMajor == 2 && req.Method == "CONNECT" {
|
|
||||||
uri = req.Host
|
|
||||||
}
|
|
||||||
if uri == "" {
|
|
||||||
uri = url.RequestURI()
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, 0, 3*(len(host)+len(username)+len(req.Method)+len(uri)+len(req.Proto)+50)/2)
|
|
||||||
buf = append(buf, host...)
|
|
||||||
buf = append(buf, " - "...)
|
|
||||||
buf = append(buf, username...)
|
|
||||||
buf = append(buf, " ["...)
|
|
||||||
buf = append(buf, ts.Format("02/Jan/2006:15:04:05 -0700")...)
|
|
||||||
buf = append(buf, `] "`...)
|
|
||||||
buf = append(buf, req.Method...)
|
|
||||||
buf = append(buf, " "...)
|
|
||||||
buf = appendQuoted(buf, uri)
|
|
||||||
buf = append(buf, " "...)
|
|
||||||
buf = append(buf, req.Proto...)
|
|
||||||
buf = append(buf, `" `...)
|
|
||||||
buf = append(buf, strconv.Itoa(status)...)
|
|
||||||
buf = append(buf, " "...)
|
|
||||||
buf = append(buf, strconv.Itoa(size)...)
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeLog writes a log entry for req to w in Apache Common Log Format.
|
|
||||||
// ts is the timestamp with which the entry should be logged.
|
|
||||||
// status and size are used to provide the response HTTP status and size.
|
|
||||||
func writeLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) {
|
|
||||||
buf := buildCommonLogLine(req, url, ts, status, size)
|
|
||||||
buf = append(buf, '\n')
|
|
||||||
w.Write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeCombinedLog writes a log entry for req to w in Apache Combined Log Format.
|
|
||||||
// ts is the timestamp with which the entry should be logged.
|
|
||||||
// status and size are used to provide the response HTTP status and size.
|
|
||||||
func writeCombinedLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) {
|
|
||||||
buf := buildCommonLogLine(req, url, ts, status, size)
|
|
||||||
buf = append(buf, ` "`...)
|
|
||||||
buf = appendQuoted(buf, req.Referer())
|
|
||||||
buf = append(buf, `" "`...)
|
|
||||||
buf = appendQuoted(buf, req.UserAgent())
|
|
||||||
buf = append(buf, '"', '\n')
|
|
||||||
w.Write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CombinedLoggingHandler return a http.Handler that wraps h and logs requests to out in
|
|
||||||
// Apache Combined Log Format.
|
|
||||||
//
|
|
||||||
// See http://httpd.apache.org/docs/2.2/logs.html#combined for a description of this format.
|
|
||||||
//
|
|
||||||
// LoggingHandler always sets the ident field of the log to -
|
|
||||||
func CombinedLoggingHandler(out io.Writer, h http.Handler) http.Handler {
|
|
||||||
return combinedLoggingHandler{out, h}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoggingHandler return a http.Handler that wraps h and logs requests to out in
|
|
||||||
// Apache Common Log Format (CLF).
|
|
||||||
//
|
|
||||||
// See http://httpd.apache.org/docs/2.2/logs.html#common for a description of this format.
|
|
||||||
//
|
|
||||||
// LoggingHandler always sets the ident field of the log to -
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// r := mux.NewRouter()
|
|
||||||
// r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// w.Write([]byte("This is a catch-all route"))
|
|
||||||
// })
|
|
||||||
// loggedRouter := handlers.LoggingHandler(os.Stdout, r)
|
|
||||||
// http.ListenAndServe(":1123", loggedRouter)
|
|
||||||
//
|
|
||||||
func LoggingHandler(out io.Writer, h http.Handler) http.Handler {
|
|
||||||
return loggingHandler{out, h}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isContentType validates the Content-Type header matches the supplied
|
// isContentType validates the Content-Type header matches the supplied
|
||||||
// contentType. That is, its type and subtype match.
|
// contentType. That is, its type and subtype match.
|
||||||
func isContentType(h http.Header, contentType string) bool {
|
func isContentType(h http.Header, contentType string) bool {
|
||||||
|
|||||||
252
vendor/github.com/gorilla/handlers/logging.go
сгенерированный
поставляемый
Обычный файл
252
vendor/github.com/gorilla/handlers/logging.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,252 @@
|
|||||||
|
// Copyright 2013 The Gorilla Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
|
||||||
|
// FormatterParams is the structure any formatter will be handed when time to log comes
|
||||||
|
type LogFormatterParams struct {
|
||||||
|
Request *http.Request
|
||||||
|
URL url.URL
|
||||||
|
TimeStamp time.Time
|
||||||
|
StatusCode int
|
||||||
|
Size int
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogFormatter gives the signature of the formatter function passed to CustomLoggingHandler
|
||||||
|
type LogFormatter func(writer io.Writer, params LogFormatterParams)
|
||||||
|
|
||||||
|
// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its
|
||||||
|
// friends
|
||||||
|
|
||||||
|
type loggingHandler struct {
|
||||||
|
writer io.Writer
|
||||||
|
handler http.Handler
|
||||||
|
formatter LogFormatter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
t := time.Now()
|
||||||
|
logger := makeLogger(w)
|
||||||
|
url := *req.URL
|
||||||
|
|
||||||
|
h.handler.ServeHTTP(logger, req)
|
||||||
|
|
||||||
|
params := LogFormatterParams{
|
||||||
|
Request: req,
|
||||||
|
URL: url,
|
||||||
|
TimeStamp: t,
|
||||||
|
StatusCode: logger.Status(),
|
||||||
|
Size: logger.Size(),
|
||||||
|
}
|
||||||
|
|
||||||
|
h.formatter(h.writer, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeLogger(w http.ResponseWriter) loggingResponseWriter {
|
||||||
|
var logger loggingResponseWriter = &responseLogger{w: w, status: http.StatusOK}
|
||||||
|
if _, ok := w.(http.Hijacker); ok {
|
||||||
|
logger = &hijackLogger{responseLogger{w: w, status: http.StatusOK}}
|
||||||
|
}
|
||||||
|
h, ok1 := logger.(http.Hijacker)
|
||||||
|
c, ok2 := w.(http.CloseNotifier)
|
||||||
|
if ok1 && ok2 {
|
||||||
|
return hijackCloseNotifier{logger, h, c}
|
||||||
|
}
|
||||||
|
if ok2 {
|
||||||
|
return &closeNotifyWriter{logger, c}
|
||||||
|
}
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonLoggingResponseWriter interface {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Flusher
|
||||||
|
Status() int
|
||||||
|
Size() int
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerhex = "0123456789abcdef"
|
||||||
|
|
||||||
|
func appendQuoted(buf []byte, s string) []byte {
|
||||||
|
var runeTmp [utf8.UTFMax]byte
|
||||||
|
for width := 0; len(s) > 0; s = s[width:] {
|
||||||
|
r := rune(s[0])
|
||||||
|
width = 1
|
||||||
|
if r >= utf8.RuneSelf {
|
||||||
|
r, width = utf8.DecodeRuneInString(s)
|
||||||
|
}
|
||||||
|
if width == 1 && r == utf8.RuneError {
|
||||||
|
buf = append(buf, `\x`...)
|
||||||
|
buf = append(buf, lowerhex[s[0]>>4])
|
||||||
|
buf = append(buf, lowerhex[s[0]&0xF])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r == rune('"') || r == '\\' { // always backslashed
|
||||||
|
buf = append(buf, '\\')
|
||||||
|
buf = append(buf, byte(r))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strconv.IsPrint(r) {
|
||||||
|
n := utf8.EncodeRune(runeTmp[:], r)
|
||||||
|
buf = append(buf, runeTmp[:n]...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case '\a':
|
||||||
|
buf = append(buf, `\a`...)
|
||||||
|
case '\b':
|
||||||
|
buf = append(buf, `\b`...)
|
||||||
|
case '\f':
|
||||||
|
buf = append(buf, `\f`...)
|
||||||
|
case '\n':
|
||||||
|
buf = append(buf, `\n`...)
|
||||||
|
case '\r':
|
||||||
|
buf = append(buf, `\r`...)
|
||||||
|
case '\t':
|
||||||
|
buf = append(buf, `\t`...)
|
||||||
|
case '\v':
|
||||||
|
buf = append(buf, `\v`...)
|
||||||
|
default:
|
||||||
|
switch {
|
||||||
|
case r < ' ':
|
||||||
|
buf = append(buf, `\x`...)
|
||||||
|
buf = append(buf, lowerhex[s[0]>>4])
|
||||||
|
buf = append(buf, lowerhex[s[0]&0xF])
|
||||||
|
case r > utf8.MaxRune:
|
||||||
|
r = 0xFFFD
|
||||||
|
fallthrough
|
||||||
|
case r < 0x10000:
|
||||||
|
buf = append(buf, `\u`...)
|
||||||
|
for s := 12; s >= 0; s -= 4 {
|
||||||
|
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
buf = append(buf, `\U`...)
|
||||||
|
for s := 28; s >= 0; s -= 4 {
|
||||||
|
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildCommonLogLine builds a log entry for req in Apache Common Log Format.
|
||||||
|
// ts is the timestamp with which the entry should be logged.
|
||||||
|
// status and size are used to provide the response HTTP status and size.
|
||||||
|
func buildCommonLogLine(req *http.Request, url url.URL, ts time.Time, status int, size int) []byte {
|
||||||
|
username := "-"
|
||||||
|
if url.User != nil {
|
||||||
|
if name := url.User.Username(); name != "" {
|
||||||
|
username = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
host = req.RemoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := req.RequestURI
|
||||||
|
|
||||||
|
// Requests using the CONNECT method over HTTP/2.0 must use
|
||||||
|
// the authority field (aka r.Host) to identify the target.
|
||||||
|
// Refer: https://httpwg.github.io/specs/rfc7540.html#CONNECT
|
||||||
|
if req.ProtoMajor == 2 && req.Method == "CONNECT" {
|
||||||
|
uri = req.Host
|
||||||
|
}
|
||||||
|
if uri == "" {
|
||||||
|
uri = url.RequestURI()
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, 0, 3*(len(host)+len(username)+len(req.Method)+len(uri)+len(req.Proto)+50)/2)
|
||||||
|
buf = append(buf, host...)
|
||||||
|
buf = append(buf, " - "...)
|
||||||
|
buf = append(buf, username...)
|
||||||
|
buf = append(buf, " ["...)
|
||||||
|
buf = append(buf, ts.Format("02/Jan/2006:15:04:05 -0700")...)
|
||||||
|
buf = append(buf, `] "`...)
|
||||||
|
buf = append(buf, req.Method...)
|
||||||
|
buf = append(buf, " "...)
|
||||||
|
buf = appendQuoted(buf, uri)
|
||||||
|
buf = append(buf, " "...)
|
||||||
|
buf = append(buf, req.Proto...)
|
||||||
|
buf = append(buf, `" `...)
|
||||||
|
buf = append(buf, strconv.Itoa(status)...)
|
||||||
|
buf = append(buf, " "...)
|
||||||
|
buf = append(buf, strconv.Itoa(size)...)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeLog writes a log entry for req to w in Apache Common Log Format.
|
||||||
|
// ts is the timestamp with which the entry should be logged.
|
||||||
|
// status and size are used to provide the response HTTP status and size.
|
||||||
|
func writeLog(writer io.Writer, params LogFormatterParams) {
|
||||||
|
buf := buildCommonLogLine(params.Request, params.URL, params.TimeStamp, params.StatusCode, params.Size)
|
||||||
|
buf = append(buf, '\n')
|
||||||
|
writer.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeCombinedLog writes a log entry for req to w in Apache Combined Log Format.
|
||||||
|
// ts is the timestamp with which the entry should be logged.
|
||||||
|
// status and size are used to provide the response HTTP status and size.
|
||||||
|
func writeCombinedLog(writer io.Writer, params LogFormatterParams) {
|
||||||
|
buf := buildCommonLogLine(params.Request, params.URL, params.TimeStamp, params.StatusCode, params.Size)
|
||||||
|
buf = append(buf, ` "`...)
|
||||||
|
buf = appendQuoted(buf, params.Request.Referer())
|
||||||
|
buf = append(buf, `" "`...)
|
||||||
|
buf = appendQuoted(buf, params.Request.UserAgent())
|
||||||
|
buf = append(buf, '"', '\n')
|
||||||
|
writer.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CombinedLoggingHandler return a http.Handler that wraps h and logs requests to out in
|
||||||
|
// Apache Combined Log Format.
|
||||||
|
//
|
||||||
|
// See http://httpd.apache.org/docs/2.2/logs.html#combined for a description of this format.
|
||||||
|
//
|
||||||
|
// LoggingHandler always sets the ident field of the log to -
|
||||||
|
func CombinedLoggingHandler(out io.Writer, h http.Handler) http.Handler {
|
||||||
|
return loggingHandler{out, h, writeCombinedLog}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoggingHandler return a http.Handler that wraps h and logs requests to out in
|
||||||
|
// Apache Common Log Format (CLF).
|
||||||
|
//
|
||||||
|
// See http://httpd.apache.org/docs/2.2/logs.html#common for a description of this format.
|
||||||
|
//
|
||||||
|
// LoggingHandler always sets the ident field of the log to -
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// r := mux.NewRouter()
|
||||||
|
// r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// w.Write([]byte("This is a catch-all route"))
|
||||||
|
// })
|
||||||
|
// loggedRouter := handlers.LoggingHandler(os.Stdout, r)
|
||||||
|
// http.ListenAndServe(":1123", loggedRouter)
|
||||||
|
//
|
||||||
|
func LoggingHandler(out io.Writer, h http.Handler) http.Handler {
|
||||||
|
return loggingHandler{out, h, writeLog}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomLoggingHandler provides a way to supply a custom log formatter
|
||||||
|
// while taking advantage of the mechanisms in this package
|
||||||
|
func CustomLoggingHandler(out io.Writer, h http.Handler, f LogFormatter) http.Handler {
|
||||||
|
return loggingHandler{out, h, f}
|
||||||
|
}
|
||||||
3
vendor/github.com/gorilla/websocket/.travis.yml
сгенерированный
поставляемый
3
vendor/github.com/gorilla/websocket/.travis.yml
сгенерированный
поставляемый
@@ -3,9 +3,6 @@ sudo: false
|
|||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- go: 1.4
|
|
||||||
- go: 1.5.x
|
|
||||||
- go: 1.6.x
|
|
||||||
- go: 1.7.x
|
- go: 1.7.x
|
||||||
- go: 1.8.x
|
- go: 1.8.x
|
||||||
- go: 1.9.x
|
- go: 1.9.x
|
||||||
|
|||||||
13
vendor/github.com/gorilla/websocket/client.go
сгенерированный
поставляемый
13
vendor/github.com/gorilla/websocket/client.go
сгенерированный
поставляемый
@@ -69,6 +69,17 @@ type Dialer struct {
|
|||||||
// do not limit the size of the messages that can be sent or received.
|
// do not limit the size of the messages that can be sent or received.
|
||||||
ReadBufferSize, WriteBufferSize int
|
ReadBufferSize, WriteBufferSize int
|
||||||
|
|
||||||
|
// WriteBufferPool is a pool of buffers for write operations. If the value
|
||||||
|
// is not set, then write buffers are allocated to the connection for the
|
||||||
|
// lifetime of the connection.
|
||||||
|
//
|
||||||
|
// A pool is most useful when the application has a modest volume of writes
|
||||||
|
// across a large number of connections.
|
||||||
|
//
|
||||||
|
// Applications should use a single pool for each unique value of
|
||||||
|
// WriteBufferSize.
|
||||||
|
WriteBufferPool BufferPool
|
||||||
|
|
||||||
// Subprotocols specifies the client's requested subprotocols.
|
// Subprotocols specifies the client's requested subprotocols.
|
||||||
Subprotocols []string
|
Subprotocols []string
|
||||||
|
|
||||||
@@ -277,7 +288,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize)
|
conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil)
|
||||||
|
|
||||||
if err := req.Write(netConn); err != nil {
|
if err := req.Write(netConn); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|||||||
98
vendor/github.com/gorilla/websocket/conn.go
сгенерированный
поставляемый
98
vendor/github.com/gorilla/websocket/conn.go
сгенерированный
поставляемый
@@ -223,6 +223,20 @@ func isValidReceivedCloseCode(code int) bool {
|
|||||||
return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999)
|
return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BufferPool represents a pool of buffers. The *sync.Pool type satisfies this
|
||||||
|
// interface. The type of the value stored in a pool is not specified.
|
||||||
|
type BufferPool interface {
|
||||||
|
// Get gets a value from the pool or returns nil if the pool is empty.
|
||||||
|
Get() interface{}
|
||||||
|
// Put adds a value to the pool.
|
||||||
|
Put(interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// writePoolData is the type added to the write buffer pool. This wrapper is
|
||||||
|
// used to prevent applications from peeking at and depending on the values
|
||||||
|
// added to the pool.
|
||||||
|
type writePoolData struct{ buf []byte }
|
||||||
|
|
||||||
// The Conn type represents a WebSocket connection.
|
// The Conn type represents a WebSocket connection.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
@@ -232,6 +246,8 @@ type Conn struct {
|
|||||||
// Write fields
|
// Write fields
|
||||||
mu chan bool // used as mutex to protect write to conn
|
mu chan bool // used as mutex to protect write to conn
|
||||||
writeBuf []byte // frame is constructed in this buffer.
|
writeBuf []byte // frame is constructed in this buffer.
|
||||||
|
writePool BufferPool
|
||||||
|
writeBufSize int
|
||||||
writeDeadline time.Time
|
writeDeadline time.Time
|
||||||
writer io.WriteCloser // the current writer returned to the application
|
writer io.WriteCloser // the current writer returned to the application
|
||||||
isWriting bool // for best-effort concurrent write detection
|
isWriting bool // for best-effort concurrent write detection
|
||||||
@@ -263,64 +279,29 @@ type Conn struct {
|
|||||||
newDecompressionReader func(io.Reader) io.ReadCloser
|
newDecompressionReader func(io.Reader) io.ReadCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn {
|
func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, writeBufferPool BufferPool, br *bufio.Reader, writeBuf []byte) *Conn {
|
||||||
return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
type writeHook struct {
|
|
||||||
p []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wh *writeHook) Write(p []byte) (int, error) {
|
|
||||||
wh.p = p
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn {
|
|
||||||
mu := make(chan bool, 1)
|
|
||||||
mu <- true
|
|
||||||
|
|
||||||
var br *bufio.Reader
|
|
||||||
if readBufferSize == 0 && brw != nil && brw.Reader != nil {
|
|
||||||
// Reuse the supplied bufio.Reader if the buffer has a useful size.
|
|
||||||
// This code assumes that peek on a reader returns
|
|
||||||
// bufio.Reader.buf[:0].
|
|
||||||
brw.Reader.Reset(conn)
|
|
||||||
if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 {
|
|
||||||
br = brw.Reader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if br == nil {
|
if br == nil {
|
||||||
if readBufferSize == 0 {
|
if readBufferSize == 0 {
|
||||||
readBufferSize = defaultReadBufferSize
|
readBufferSize = defaultReadBufferSize
|
||||||
}
|
} else if readBufferSize < maxControlFramePayloadSize {
|
||||||
if readBufferSize < maxControlFramePayloadSize {
|
// must be large enough for control frame
|
||||||
readBufferSize = maxControlFramePayloadSize
|
readBufferSize = maxControlFramePayloadSize
|
||||||
}
|
}
|
||||||
br = bufio.NewReaderSize(conn, readBufferSize)
|
br = bufio.NewReaderSize(conn, readBufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
var writeBuf []byte
|
if writeBufferSize <= 0 {
|
||||||
if writeBufferSize == 0 && brw != nil && brw.Writer != nil {
|
|
||||||
// Use the bufio.Writer's buffer if the buffer has a useful size. This
|
|
||||||
// code assumes that bufio.Writer.buf[:1] is passed to the
|
|
||||||
// bufio.Writer's underlying writer.
|
|
||||||
var wh writeHook
|
|
||||||
brw.Writer.Reset(&wh)
|
|
||||||
brw.Writer.WriteByte(0)
|
|
||||||
brw.Flush()
|
|
||||||
if cap(wh.p) >= maxFrameHeaderSize+256 {
|
|
||||||
writeBuf = wh.p[:cap(wh.p)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if writeBuf == nil {
|
|
||||||
if writeBufferSize == 0 {
|
|
||||||
writeBufferSize = defaultWriteBufferSize
|
writeBufferSize = defaultWriteBufferSize
|
||||||
}
|
}
|
||||||
writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize)
|
writeBufferSize += maxFrameHeaderSize
|
||||||
|
|
||||||
|
if writeBuf == nil && writeBufferPool == nil {
|
||||||
|
writeBuf = make([]byte, writeBufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mu := make(chan bool, 1)
|
||||||
|
mu <- true
|
||||||
c := &Conn{
|
c := &Conn{
|
||||||
isServer: isServer,
|
isServer: isServer,
|
||||||
br: br,
|
br: br,
|
||||||
@@ -328,6 +309,8 @@ func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize in
|
|||||||
mu: mu,
|
mu: mu,
|
||||||
readFinal: true,
|
readFinal: true,
|
||||||
writeBuf: writeBuf,
|
writeBuf: writeBuf,
|
||||||
|
writePool: writeBufferPool,
|
||||||
|
writeBufSize: writeBufferSize,
|
||||||
enableWriteCompression: true,
|
enableWriteCompression: true,
|
||||||
compressionLevel: defaultCompressionLevel,
|
compressionLevel: defaultCompressionLevel,
|
||||||
}
|
}
|
||||||
@@ -370,6 +353,15 @@ func (c *Conn) writeFatal(err error) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Conn) read(n int) ([]byte, error) {
|
||||||
|
p, err := c.br.Peek(n)
|
||||||
|
if err == io.EOF {
|
||||||
|
err = errUnexpectedEOF
|
||||||
|
}
|
||||||
|
c.br.Discard(len(p))
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error {
|
func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error {
|
||||||
<-c.mu
|
<-c.mu
|
||||||
defer func() { c.mu <- true }()
|
defer func() { c.mu <- true }()
|
||||||
@@ -475,9 +467,21 @@ func (c *Conn) prepWrite(messageType int) error {
|
|||||||
c.writeErrMu.Lock()
|
c.writeErrMu.Lock()
|
||||||
err := c.writeErr
|
err := c.writeErr
|
||||||
c.writeErrMu.Unlock()
|
c.writeErrMu.Unlock()
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.writeBuf == nil {
|
||||||
|
wpd, ok := c.writePool.Get().(writePoolData)
|
||||||
|
if ok {
|
||||||
|
c.writeBuf = wpd.buf
|
||||||
|
} else {
|
||||||
|
c.writeBuf = make([]byte, c.writeBufSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// NextWriter returns a writer for the next message to send. The writer's Close
|
// NextWriter returns a writer for the next message to send. The writer's Close
|
||||||
// method flushes the complete message to the network.
|
// method flushes the complete message to the network.
|
||||||
//
|
//
|
||||||
@@ -601,6 +605,10 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
|
|||||||
|
|
||||||
if final {
|
if final {
|
||||||
c.writer = nil
|
c.writer = nil
|
||||||
|
if c.writePool != nil {
|
||||||
|
c.writePool.Put(writePoolData{buf: c.writeBuf})
|
||||||
|
c.writeBuf = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
vendor/github.com/gorilla/websocket/conn_read.go
сгенерированный
поставляемый
18
vendor/github.com/gorilla/websocket/conn_read.go
сгенерированный
поставляемый
@@ -1,18 +0,0 @@
|
|||||||
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build go1.5
|
|
||||||
|
|
||||||
package websocket
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func (c *Conn) read(n int) ([]byte, error) {
|
|
||||||
p, err := c.br.Peek(n)
|
|
||||||
if err == io.EOF {
|
|
||||||
err = errUnexpectedEOF
|
|
||||||
}
|
|
||||||
c.br.Discard(len(p))
|
|
||||||
return p, err
|
|
||||||
}
|
|
||||||
21
vendor/github.com/gorilla/websocket/conn_read_legacy.go
сгенерированный
поставляемый
21
vendor/github.com/gorilla/websocket/conn_read_legacy.go
сгенерированный
поставляемый
@@ -1,21 +0,0 @@
|
|||||||
// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !go1.5
|
|
||||||
|
|
||||||
package websocket
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func (c *Conn) read(n int) ([]byte, error) {
|
|
||||||
p, err := c.br.Peek(n)
|
|
||||||
if err == io.EOF {
|
|
||||||
err = errUnexpectedEOF
|
|
||||||
}
|
|
||||||
if len(p) > 0 {
|
|
||||||
// advance over the bytes just read
|
|
||||||
io.ReadFull(c.br, p)
|
|
||||||
}
|
|
||||||
return p, err
|
|
||||||
}
|
|
||||||
79
vendor/github.com/gorilla/websocket/server.go
сгенерированный
поставляемый
79
vendor/github.com/gorilla/websocket/server.go
сгенерированный
поставляемый
@@ -7,6 +7,7 @@ package websocket
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -33,10 +34,23 @@ type Upgrader struct {
|
|||||||
// or received.
|
// or received.
|
||||||
ReadBufferSize, WriteBufferSize int
|
ReadBufferSize, WriteBufferSize int
|
||||||
|
|
||||||
|
// WriteBufferPool is a pool of buffers for write operations. If the value
|
||||||
|
// is not set, then write buffers are allocated to the connection for the
|
||||||
|
// lifetime of the connection.
|
||||||
|
//
|
||||||
|
// A pool is most useful when the application has a modest volume of writes
|
||||||
|
// across a large number of connections.
|
||||||
|
//
|
||||||
|
// Applications should use a single pool for each unique value of
|
||||||
|
// WriteBufferSize.
|
||||||
|
WriteBufferPool BufferPool
|
||||||
|
|
||||||
// Subprotocols specifies the server's supported protocols in order of
|
// Subprotocols specifies the server's supported protocols in order of
|
||||||
// preference. If this field is set, then the Upgrade method negotiates a
|
// preference. If this field is not nil, then the Upgrade method negotiates a
|
||||||
// subprotocol by selecting the first match in this list with a protocol
|
// subprotocol by selecting the first match in this list with a protocol
|
||||||
// requested by the client.
|
// requested by the client. If there's no match, then no protocol is
|
||||||
|
// negotiated (the Sec-Websocket-Protocol header is not included in the
|
||||||
|
// handshake response).
|
||||||
Subprotocols []string
|
Subprotocols []string
|
||||||
|
|
||||||
// Error specifies the function for generating HTTP error responses. If Error
|
// Error specifies the function for generating HTTP error responses. If Error
|
||||||
@@ -177,7 +191,21 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
|
|||||||
return nil, errors.New("websocket: client sent data before handshake is complete")
|
return nil, errors.New("websocket: client sent data before handshake is complete")
|
||||||
}
|
}
|
||||||
|
|
||||||
c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw)
|
var br *bufio.Reader
|
||||||
|
if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 {
|
||||||
|
// Reuse hijacked buffered reader as connection reader.
|
||||||
|
br = brw.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bufioWriterBuffer(netConn, brw.Writer)
|
||||||
|
|
||||||
|
var writeBuf []byte
|
||||||
|
if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 {
|
||||||
|
// Reuse hijacked write buffer as connection buffer.
|
||||||
|
writeBuf = buf
|
||||||
|
}
|
||||||
|
|
||||||
|
c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf)
|
||||||
c.subprotocol = subprotocol
|
c.subprotocol = subprotocol
|
||||||
|
|
||||||
if compress {
|
if compress {
|
||||||
@@ -185,7 +213,13 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
|
|||||||
c.newDecompressionReader = decompressNoContextTakeover
|
c.newDecompressionReader = decompressNoContextTakeover
|
||||||
}
|
}
|
||||||
|
|
||||||
p := c.writeBuf[:0]
|
// Use larger of hijacked buffer and connection write buffer for header.
|
||||||
|
p := buf
|
||||||
|
if len(c.writeBuf) > len(p) {
|
||||||
|
p = c.writeBuf
|
||||||
|
}
|
||||||
|
p = p[:0]
|
||||||
|
|
||||||
p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
|
p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
|
||||||
p = append(p, computeAcceptKey(challengeKey)...)
|
p = append(p, computeAcceptKey(challengeKey)...)
|
||||||
p = append(p, "\r\n"...)
|
p = append(p, "\r\n"...)
|
||||||
@@ -296,3 +330,40 @@ func IsWebSocketUpgrade(r *http.Request) bool {
|
|||||||
return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
|
return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
|
||||||
tokenListContainsValue(r.Header, "Upgrade", "websocket")
|
tokenListContainsValue(r.Header, "Upgrade", "websocket")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bufioReader size returns the size of a bufio.Reader.
|
||||||
|
func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int {
|
||||||
|
// This code assumes that peek on a reset reader returns
|
||||||
|
// bufio.Reader.buf[:0].
|
||||||
|
// TODO: Use bufio.Reader.Size() after Go 1.10
|
||||||
|
br.Reset(originalReader)
|
||||||
|
if p, err := br.Peek(0); err == nil {
|
||||||
|
return cap(p)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeHook is an io.Writer that records the last slice passed to it vio
|
||||||
|
// io.Writer.Write.
|
||||||
|
type writeHook struct {
|
||||||
|
p []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wh *writeHook) Write(p []byte) (int, error) {
|
||||||
|
wh.p = p
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bufioWriterBuffer grabs the buffer from a bufio.Writer.
|
||||||
|
func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte {
|
||||||
|
// This code assumes that bufio.Writer.buf[:1] is passed to the
|
||||||
|
// bufio.Writer's underlying writer.
|
||||||
|
var wh writeHook
|
||||||
|
bw.Reset(&wh)
|
||||||
|
bw.WriteByte(0)
|
||||||
|
bw.Flush()
|
||||||
|
|
||||||
|
bw.Reset(originalWriter)
|
||||||
|
|
||||||
|
return wh.p[:cap(wh.p)]
|
||||||
|
}
|
||||||
|
|||||||
1
vendor/github.com/hashicorp/errwrap/go.mod
сгенерированный
поставляемый
Обычный файл
1
vendor/github.com/hashicorp/errwrap/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
module github.com/hashicorp/errwrap
|
||||||
3
vendor/github.com/hashicorp/go-multierror/go.mod
сгенерированный
поставляемый
Обычный файл
3
vendor/github.com/hashicorp/go-multierror/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/hashicorp/go-multierror
|
||||||
|
|
||||||
|
require github.com/hashicorp/errwrap v1.0.0
|
||||||
4
vendor/github.com/hashicorp/go-multierror/go.sum
сгенерированный
поставляемый
Обычный файл
4
vendor/github.com/hashicorp/go-multierror/go.sum
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,4 @@
|
|||||||
|
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4=
|
||||||
|
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
2
vendor/github.com/hashicorp/memberlist/Makefile
сгенерированный
поставляемый
2
vendor/github.com/hashicorp/memberlist/Makefile
сгенерированный
поставляемый
@@ -16,4 +16,4 @@ deps:
|
|||||||
go get -d -v ./...
|
go get -d -v ./...
|
||||||
echo $(DEPS) | xargs -n1 go get -d
|
echo $(DEPS) | xargs -n1 go get -d
|
||||||
|
|
||||||
.PNONY: test cov integ
|
.PHONY: test cov integ
|
||||||
|
|||||||
12
vendor/github.com/hashicorp/memberlist/memberlist.go
сгенерированный
поставляемый
12
vendor/github.com/hashicorp/memberlist/memberlist.go
сгенерированный
поставляемый
@@ -15,6 +15,7 @@ multiple routes.
|
|||||||
package memberlist
|
package memberlist
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/list"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@@ -34,6 +35,7 @@ type Memberlist struct {
|
|||||||
sequenceNum uint32 // Local sequence number
|
sequenceNum uint32 // Local sequence number
|
||||||
incarnation uint32 // Local incarnation number
|
incarnation uint32 // Local incarnation number
|
||||||
numNodes uint32 // Number of known nodes (estimate)
|
numNodes uint32 // Number of known nodes (estimate)
|
||||||
|
pushPullReq uint32 // Number of push/pull requests
|
||||||
|
|
||||||
config *Config
|
config *Config
|
||||||
shutdown int32 // Used as an atomic boolean value
|
shutdown int32 // Used as an atomic boolean value
|
||||||
@@ -45,7 +47,11 @@ type Memberlist struct {
|
|||||||
leaveLock sync.Mutex // Serializes calls to Leave
|
leaveLock sync.Mutex // Serializes calls to Leave
|
||||||
|
|
||||||
transport Transport
|
transport Transport
|
||||||
handoff chan msgHandoff
|
|
||||||
|
handoffCh chan struct{}
|
||||||
|
highPriorityMsgQueue *list.List
|
||||||
|
lowPriorityMsgQueue *list.List
|
||||||
|
msgQueueLock sync.Mutex
|
||||||
|
|
||||||
nodeLock sync.RWMutex
|
nodeLock sync.RWMutex
|
||||||
nodes []*nodeState // Known nodes
|
nodes []*nodeState // Known nodes
|
||||||
@@ -164,7 +170,9 @@ func newMemberlist(conf *Config) (*Memberlist, error) {
|
|||||||
shutdownCh: make(chan struct{}),
|
shutdownCh: make(chan struct{}),
|
||||||
leaveBroadcast: make(chan struct{}, 1),
|
leaveBroadcast: make(chan struct{}, 1),
|
||||||
transport: transport,
|
transport: transport,
|
||||||
handoff: make(chan msgHandoff, conf.HandoffQueueDepth),
|
handoffCh: make(chan struct{}, 1),
|
||||||
|
highPriorityMsgQueue: list.New(),
|
||||||
|
lowPriorityMsgQueue: list.New(),
|
||||||
nodeMap: make(map[string]*nodeState),
|
nodeMap: make(map[string]*nodeState),
|
||||||
nodeTimers: make(map[string]*suspicion),
|
nodeTimers: make(map[string]*suspicion),
|
||||||
awareness: newAwareness(conf.AwarenessMaxMultiplier),
|
awareness: newAwareness(conf.AwarenessMaxMultiplier),
|
||||||
|
|||||||
64
vendor/github.com/hashicorp/memberlist/net.go
сгенерированный
поставляемый
64
vendor/github.com/hashicorp/memberlist/net.go
сгенерированный
поставляемый
@@ -8,9 +8,10 @@ import (
|
|||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/armon/go-metrics"
|
metrics "github.com/armon/go-metrics"
|
||||||
"github.com/hashicorp/go-msgpack/codec"
|
"github.com/hashicorp/go-msgpack/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -71,7 +72,8 @@ const (
|
|||||||
compoundOverhead = 2 // Assumed overhead per entry in compoundHeader
|
compoundOverhead = 2 // Assumed overhead per entry in compoundHeader
|
||||||
userMsgOverhead = 1
|
userMsgOverhead = 1
|
||||||
blockingWarning = 10 * time.Millisecond // Warn if a UDP packet takes this long to process
|
blockingWarning = 10 * time.Millisecond // Warn if a UDP packet takes this long to process
|
||||||
maxPushStateBytes = 10 * 1024 * 1024
|
maxPushStateBytes = 20 * 1024 * 1024
|
||||||
|
maxPushPullRequests = 128 // Maximum number of concurrent push/pull requests
|
||||||
)
|
)
|
||||||
|
|
||||||
// ping request sent directly to node
|
// ping request sent directly to node
|
||||||
@@ -238,6 +240,16 @@ func (m *Memberlist) handleConn(conn net.Conn) {
|
|||||||
m.logger.Printf("[ERR] memberlist: Failed to receive user message: %s %s", err, LogConn(conn))
|
m.logger.Printf("[ERR] memberlist: Failed to receive user message: %s %s", err, LogConn(conn))
|
||||||
}
|
}
|
||||||
case pushPullMsg:
|
case pushPullMsg:
|
||||||
|
// Increment counter of pending push/pulls
|
||||||
|
numConcurrent := atomic.AddUint32(&m.pushPullReq, 1)
|
||||||
|
defer atomic.AddUint32(&m.pushPullReq, ^uint32(0))
|
||||||
|
|
||||||
|
// Check if we have too many open push/pull requests
|
||||||
|
if numConcurrent >= maxPushPullRequests {
|
||||||
|
m.logger.Printf("[ERR] memberlist: Too many pending push/pull requests")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
join, remoteNodes, userState, err := m.readRemoteState(bufConn, dec)
|
join, remoteNodes, userState, err := m.readRemoteState(bufConn, dec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.logger.Printf("[ERR] memberlist: Failed to read remote state: %s %s", err, LogConn(conn))
|
m.logger.Printf("[ERR] memberlist: Failed to read remote state: %s %s", err, LogConn(conn))
|
||||||
@@ -357,10 +369,25 @@ func (m *Memberlist) handleCommand(buf []byte, from net.Addr, timestamp time.Tim
|
|||||||
case deadMsg:
|
case deadMsg:
|
||||||
fallthrough
|
fallthrough
|
||||||
case userMsg:
|
case userMsg:
|
||||||
select {
|
// Determine the message queue, prioritize alive
|
||||||
case m.handoff <- msgHandoff{msgType, buf, from}:
|
queue := m.lowPriorityMsgQueue
|
||||||
default:
|
if msgType == aliveMsg {
|
||||||
|
queue = m.highPriorityMsgQueue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for overflow and append if not full
|
||||||
|
m.msgQueueLock.Lock()
|
||||||
|
if queue.Len() >= m.config.HandoffQueueDepth {
|
||||||
m.logger.Printf("[WARN] memberlist: handler queue full, dropping message (%d) %s", msgType, LogAddress(from))
|
m.logger.Printf("[WARN] memberlist: handler queue full, dropping message (%d) %s", msgType, LogAddress(from))
|
||||||
|
} else {
|
||||||
|
queue.PushBack(msgHandoff{msgType, buf, from})
|
||||||
|
}
|
||||||
|
m.msgQueueLock.Unlock()
|
||||||
|
|
||||||
|
// Notify of pending message
|
||||||
|
select {
|
||||||
|
case m.handoffCh <- struct{}{}:
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -368,13 +395,35 @@ func (m *Memberlist) handleCommand(buf []byte, from net.Addr, timestamp time.Tim
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getNextMessage returns the next message to process in priority order, using LIFO
|
||||||
|
func (m *Memberlist) getNextMessage() (msgHandoff, bool) {
|
||||||
|
m.msgQueueLock.Lock()
|
||||||
|
defer m.msgQueueLock.Unlock()
|
||||||
|
|
||||||
|
if el := m.highPriorityMsgQueue.Back(); el != nil {
|
||||||
|
m.highPriorityMsgQueue.Remove(el)
|
||||||
|
msg := el.Value.(msgHandoff)
|
||||||
|
return msg, true
|
||||||
|
} else if el := m.lowPriorityMsgQueue.Back(); el != nil {
|
||||||
|
m.lowPriorityMsgQueue.Remove(el)
|
||||||
|
msg := el.Value.(msgHandoff)
|
||||||
|
return msg, true
|
||||||
|
}
|
||||||
|
return msgHandoff{}, false
|
||||||
|
}
|
||||||
|
|
||||||
// packetHandler is a long running goroutine that processes messages received
|
// packetHandler is a long running goroutine that processes messages received
|
||||||
// over the packet interface, but is decoupled from the listener to avoid
|
// over the packet interface, but is decoupled from the listener to avoid
|
||||||
// blocking the listener which may cause ping/ack messages to be delayed.
|
// blocking the listener which may cause ping/ack messages to be delayed.
|
||||||
func (m *Memberlist) packetHandler() {
|
func (m *Memberlist) packetHandler() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case msg := <-m.handoff:
|
case <-m.handoffCh:
|
||||||
|
for {
|
||||||
|
msg, ok := m.getNextMessage()
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
msgType := msg.msgType
|
msgType := msg.msgType
|
||||||
buf := msg.buf
|
buf := msg.buf
|
||||||
from := msg.from
|
from := msg.from
|
||||||
@@ -391,6 +440,7 @@ func (m *Memberlist) packetHandler() {
|
|||||||
default:
|
default:
|
||||||
m.logger.Printf("[ERR] memberlist: Message type (%d) not supported %s (packet handler)", msgType, LogAddress(from))
|
m.logger.Printf("[ERR] memberlist: Message type (%d) not supported %s (packet handler)", msgType, LogAddress(from))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case <-m.shutdownCh:
|
case <-m.shutdownCh:
|
||||||
return
|
return
|
||||||
@@ -1094,7 +1144,7 @@ func (m *Memberlist) sendPingAndWaitForAck(addr string, ping ping, deadline time
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ack.SeqNo != ping.SeqNo {
|
if ack.SeqNo != ping.SeqNo {
|
||||||
return false, fmt.Errorf("Sequence number from ack (%d) doesn't match ping (%d)", ack.SeqNo, ping.SeqNo, LogConn(conn))
|
return false, fmt.Errorf("Sequence number from ack (%d) doesn't match ping (%d)", ack.SeqNo, ping.SeqNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|||||||
1
vendor/github.com/lib/pq/go.mod
сгенерированный
поставляемый
Обычный файл
1
vendor/github.com/lib/pq/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
module github.com/lib/pq
|
||||||
3
vendor/github.com/lib/pq/notify.go
сгенерированный
поставляемый
3
vendor/github.com/lib/pq/notify.go
сгенерированный
поставляемый
@@ -725,6 +725,9 @@ func (l *Listener) Close() error {
|
|||||||
}
|
}
|
||||||
l.isClosed = true
|
l.isClosed = true
|
||||||
|
|
||||||
|
// Unblock calls to Listen()
|
||||||
|
l.reconnectCond.Broadcast()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
vendor/github.com/mailru/easyjson/jlexer/lexer.go
сгенерированный
поставляемый
13
vendor/github.com/mailru/easyjson/jlexer/lexer.go
сгенерированный
поставляемый
@@ -240,7 +240,7 @@ func (r *Lexer) fetchNumber() {
|
|||||||
|
|
||||||
// findStringLen tries to scan into the string literal for ending quote char to determine required size.
|
// findStringLen tries to scan into the string literal for ending quote char to determine required size.
|
||||||
// The size will be exact if no escapes are present and may be inexact if there are escaped chars.
|
// The size will be exact if no escapes are present and may be inexact if there are escaped chars.
|
||||||
func findStringLen(data []byte) (hasEscapes bool, length int) {
|
func findStringLen(data []byte) (isValid, hasEscapes bool, length int) {
|
||||||
delta := 0
|
delta := 0
|
||||||
|
|
||||||
for i := 0; i < len(data); i++ {
|
for i := 0; i < len(data); i++ {
|
||||||
@@ -252,11 +252,11 @@ func findStringLen(data []byte) (hasEscapes bool, length int) {
|
|||||||
delta++
|
delta++
|
||||||
}
|
}
|
||||||
case '"':
|
case '"':
|
||||||
return (delta > 0), (i - delta)
|
return true, (delta > 0), (i - delta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, len(data)
|
return false, false, len(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
|
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
|
||||||
@@ -342,7 +342,12 @@ func (r *Lexer) fetchString() {
|
|||||||
r.pos++
|
r.pos++
|
||||||
data := r.Data[r.pos:]
|
data := r.Data[r.pos:]
|
||||||
|
|
||||||
hasEscapes, length := findStringLen(data)
|
isValid, hasEscapes, length := findStringLen(data)
|
||||||
|
if !isValid {
|
||||||
|
r.pos += length
|
||||||
|
r.errParse("unterminated string literal")
|
||||||
|
return
|
||||||
|
}
|
||||||
if !hasEscapes {
|
if !hasEscapes {
|
||||||
r.token.byteValue = data[:length]
|
r.token.byteValue = data[:length]
|
||||||
r.pos += length + 1
|
r.pos += length + 1
|
||||||
|
|||||||
14
vendor/github.com/mattn/go-runewidth/runewidth.go
сгенерированный
поставляемый
14
vendor/github.com/mattn/go-runewidth/runewidth.go
сгенерированный
поставляемый
@@ -1,13 +1,24 @@
|
|||||||
package runewidth
|
package runewidth
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// EastAsianWidth will be set true if the current locale is CJK
|
// EastAsianWidth will be set true if the current locale is CJK
|
||||||
EastAsianWidth = IsEastAsian()
|
EastAsianWidth bool
|
||||||
|
|
||||||
// DefaultCondition is a condition in current locale
|
// DefaultCondition is a condition in current locale
|
||||||
DefaultCondition = &Condition{EastAsianWidth}
|
DefaultCondition = &Condition{EastAsianWidth}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
env := os.Getenv("RUNEWIDTH_EASTASIAN")
|
||||||
|
if env == "" {
|
||||||
|
EastAsianWidth = IsEastAsian()
|
||||||
|
} else {
|
||||||
|
EastAsianWidth = env == "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type interval struct {
|
type interval struct {
|
||||||
first rune
|
first rune
|
||||||
last rune
|
last rune
|
||||||
@@ -55,6 +66,7 @@ var private = table{
|
|||||||
var nonprint = table{
|
var nonprint = table{
|
||||||
{0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD},
|
{0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD},
|
||||||
{0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F},
|
{0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F},
|
||||||
|
{0x2028, 0x2029},
|
||||||
{0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
|
{0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
|
||||||
{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
|
{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
|
||||||
}
|
}
|
||||||
|
|||||||
1
vendor/github.com/mitchellh/go-homedir/go.mod
сгенерированный
поставляемый
Обычный файл
1
vendor/github.com/mitchellh/go-homedir/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
module github.com/mitchellh/go-homedir
|
||||||
10
vendor/github.com/mitchellh/go-homedir/homedir.go
сгенерированный
поставляемый
10
vendor/github.com/mitchellh/go-homedir/homedir.go
сгенерированный
поставляемый
@@ -141,14 +141,16 @@ func dirWindows() (string, error) {
|
|||||||
return home, nil
|
return home, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefer standard environment variable USERPROFILE
|
||||||
|
if home := os.Getenv("USERPROFILE"); home != "" {
|
||||||
|
return home, nil
|
||||||
|
}
|
||||||
|
|
||||||
drive := os.Getenv("HOMEDRIVE")
|
drive := os.Getenv("HOMEDRIVE")
|
||||||
path := os.Getenv("HOMEPATH")
|
path := os.Getenv("HOMEPATH")
|
||||||
home := drive + path
|
home := drive + path
|
||||||
if drive == "" || path == "" {
|
if drive == "" || path == "" {
|
||||||
home = os.Getenv("USERPROFILE")
|
return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank")
|
||||||
}
|
|
||||||
if home == "" {
|
|
||||||
return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return home, nil
|
return home, nil
|
||||||
|
|||||||
1
vendor/github.com/mitchellh/mapstructure/go.mod
сгенерированный
поставляемый
Обычный файл
1
vendor/github.com/mitchellh/mapstructure/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
|||||||
|
module github.com/mitchellh/mapstructure
|
||||||
2
vendor/github.com/prometheus/common/expfmt/text_parse.go
сгенерированный
поставляемый
2
vendor/github.com/prometheus/common/expfmt/text_parse.go
сгенерированный
поставляемый
@@ -359,7 +359,7 @@ func (p *TextParser) startLabelValue() stateFn {
|
|||||||
}
|
}
|
||||||
return p.readingValue
|
return p.readingValue
|
||||||
default:
|
default:
|
||||||
p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.Value))
|
p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.GetValue()))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
vendor/github.com/prometheus/procfs/.travis.yml
сгенерированный
поставляемый
3
vendor/github.com/prometheus/procfs/.travis.yml
сгенерированный
поставляемый
@@ -3,11 +3,8 @@ sudo: false
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.7.x
|
|
||||||
- 1.8.x
|
|
||||||
- 1.9.x
|
- 1.9.x
|
||||||
- 1.10.x
|
- 1.10.x
|
||||||
- 1.x
|
|
||||||
|
|
||||||
go_import_path: github.com/prometheus/procfs
|
go_import_path: github.com/prometheus/procfs
|
||||||
|
|
||||||
|
|||||||
8
vendor/github.com/rs/cors/README.md
сгенерированный
поставляемый
8
vendor/github.com/rs/cors/README.md
сгенерированный
поставляемый
@@ -49,6 +49,14 @@ The server now runs on `localhost:8080`:
|
|||||||
|
|
||||||
{"hello": "world"}
|
{"hello": "world"}
|
||||||
|
|
||||||
|
### Allow * With Credentials Security Protection
|
||||||
|
|
||||||
|
This library has been modified to avoid a well known security issue when configured with `AllowedOrigins` to `*` and `AllowCredentials` to `true`. Such setup used to make the library reflects the request `Origin` header value, working around a security protection embedded into the standard that makes clients to refuse such configuration. This behavior has been removed with [#55](https://github.com/rs/cors/issues/55) and [#57](https://github.com/rs/cors/issues/57).
|
||||||
|
|
||||||
|
If you depend on this behavior and understand the implications, you can restore it using the `AllowOriginFunc` with `func(origin string) {return true}`.
|
||||||
|
|
||||||
|
Please refer to [#55](https://github.com/rs/cors/issues/55) for more information about the security implications.
|
||||||
|
|
||||||
### More Examples
|
### More Examples
|
||||||
|
|
||||||
* `net/http`: [examples/nethttp/server.go](https://github.com/rs/cors/blob/master/examples/nethttp/server.go)
|
* `net/http`: [examples/nethttp/server.go](https://github.com/rs/cors/blob/master/examples/nethttp/server.go)
|
||||||
|
|||||||
6
vendor/github.com/rs/cors/cors.go
сгенерированный
поставляемый
6
vendor/github.com/rs/cors/cors.go
сгенерированный
поставляемый
@@ -174,7 +174,7 @@ func AllowAll() *Cors {
|
|||||||
AllowedOrigins: []string{"*"},
|
AllowedOrigins: []string{"*"},
|
||||||
AllowedMethods: []string{"HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"},
|
AllowedMethods: []string{"HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"},
|
||||||
AllowedHeaders: []string{"*"},
|
AllowedHeaders: []string{"*"},
|
||||||
AllowCredentials: true,
|
AllowCredentials: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +269,7 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
|
|||||||
c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders)
|
c.logf(" Preflight aborted: headers '%v' not allowed", reqHeaders)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if c.allowedOriginsAll && !c.allowCredentials {
|
if c.allowedOriginsAll {
|
||||||
headers.Set("Access-Control-Allow-Origin", "*")
|
headers.Set("Access-Control-Allow-Origin", "*")
|
||||||
} else {
|
} else {
|
||||||
headers.Set("Access-Control-Allow-Origin", origin)
|
headers.Set("Access-Control-Allow-Origin", origin)
|
||||||
@@ -321,7 +321,7 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if c.allowedOriginsAll && !c.allowCredentials {
|
if c.allowedOriginsAll {
|
||||||
headers.Set("Access-Control-Allow-Origin", "*")
|
headers.Set("Access-Control-Allow-Origin", "*")
|
||||||
} else {
|
} else {
|
||||||
headers.Set("Access-Control-Allow-Origin", origin)
|
headers.Set("Access-Control-Allow-Origin", origin)
|
||||||
|
|||||||
6
vendor/github.com/sirupsen/logrus/.travis.yml
сгенерированный
поставляемый
6
vendor/github.com/sirupsen/logrus/.travis.yml
сгенерированный
поставляемый
@@ -1,9 +1,7 @@
|
|||||||
language: go
|
language: go
|
||||||
go:
|
go:
|
||||||
- 1.6.x
|
- 1.9.x
|
||||||
- 1.7.x
|
- 1.10.x
|
||||||
- 1.8.x
|
|
||||||
- tip
|
|
||||||
env:
|
env:
|
||||||
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
||||||
install:
|
install:
|
||||||
|
|||||||
60
vendor/github.com/sirupsen/logrus/README.md
сгенерированный
поставляемый
60
vendor/github.com/sirupsen/logrus/README.md
сгенерированный
поставляемый
@@ -241,60 +241,8 @@ func init() {
|
|||||||
```
|
```
|
||||||
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||||
|
|
||||||
| Hook | Description |
|
A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
|
||||||
| ----- | ----------- |
|
|
||||||
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
|
||||||
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
|
||||||
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
|
|
||||||
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
|
||||||
| [Application Insights](https://github.com/jjcollinge/logrus-appinsights) | Hook for logging to [Application Insights](https://azure.microsoft.com/en-us/services/application-insights/)
|
|
||||||
| [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage|
|
|
||||||
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
|
||||||
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
|
||||||
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
|
|
||||||
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
|
||||||
| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/)
|
|
||||||
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
|
||||||
| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
|
|
||||||
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
|
||||||
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
|
||||||
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
|
||||||
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
|
||||||
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
|
|
||||||
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
|
||||||
| [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka |
|
|
||||||
| [Kafka REST Proxy](https://github.com/Nordstrom/logrus-kafka-rest-proxy) | Hook for logging to [Kafka REST Proxy](https://docs.confluent.io/current/kafka-rest/docs) |
|
|
||||||
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
|
||||||
| [Logbeat](https://github.com/macandmia/logbeat) | Hook for logging to [Opbeat](https://opbeat.com/) |
|
|
||||||
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
|
||||||
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
|
||||||
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
|
|
||||||
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
|
||||||
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
|
||||||
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
|
||||||
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
|
|
||||||
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
|
||||||
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
|
|
||||||
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
|
||||||
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
|
||||||
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
|
|
||||||
| [Promrus](https://github.com/weaveworks/promrus) | Expose number of log messages as [Prometheus](https://prometheus.io/) metrics |
|
|
||||||
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
|
|
||||||
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
|
||||||
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
|
||||||
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
|
||||||
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
|
|
||||||
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
|
|
||||||
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
|
||||||
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
|
|
||||||
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
|
||||||
| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
|
||||||
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
|
|
||||||
| [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) |
|
|
||||||
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
|
|
||||||
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
|
||||||
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
|
|
||||||
| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) |
|
|
||||||
|
|
||||||
#### Level logging
|
#### Level logging
|
||||||
|
|
||||||
@@ -372,6 +320,8 @@ The built-in logging formatters are:
|
|||||||
field to `true`. To force no colored output even if there is a TTY set the
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
`DisableColors` field to `true`. For Windows, see
|
`DisableColors` field to `true`. For Windows, see
|
||||||
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
||||||
|
* When colors are enabled, levels are truncated to 4 characters by default. To disable
|
||||||
|
truncation set the `DisableLevelTruncation` field to `true`.
|
||||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
||||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
||||||
@@ -495,7 +445,7 @@ logrus.RegisterExitHandler(handler)
|
|||||||
|
|
||||||
#### Thread safety
|
#### Thread safety
|
||||||
|
|
||||||
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
|
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
|
||||||
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
|
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
|
||||||
|
|
||||||
Situation when locking is not needed includes:
|
Situation when locking is not needed includes:
|
||||||
|
|||||||
24
vendor/github.com/sirupsen/logrus/entry.go
сгенерированный
поставляемый
24
vendor/github.com/sirupsen/logrus/entry.go
сгенерированный
поставляемый
@@ -48,7 +48,7 @@ type Entry struct {
|
|||||||
func NewEntry(logger *Logger) *Entry {
|
func NewEntry(logger *Logger) *Entry {
|
||||||
return &Entry{
|
return &Entry{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
// Default is three fields, give a little extra room
|
// Default is five fields, give a little extra room
|
||||||
Data: make(Fields, 5),
|
Data: make(Fields, 5),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,14 +83,28 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
|||||||
for k, v := range fields {
|
for k, v := range fields {
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
return &Entry{Logger: entry.Logger, Data: data}
|
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overrides the time of the Entry.
|
||||||
|
func (entry *Entry) WithTime(t time.Time) *Entry {
|
||||||
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is not declared with a pointer value because otherwise
|
// This function is not declared with a pointer value because otherwise
|
||||||
// race conditions will occur when using multiple goroutines
|
// race conditions will occur when using multiple goroutines
|
||||||
func (entry Entry) log(level Level, msg string) {
|
func (entry Entry) log(level Level, msg string) {
|
||||||
var buffer *bytes.Buffer
|
var buffer *bytes.Buffer
|
||||||
|
|
||||||
|
// Default to now, but allow users to override if they want.
|
||||||
|
//
|
||||||
|
// We don't have to worry about polluting future calls to Entry#log()
|
||||||
|
// with this assignment because this function is declared with a
|
||||||
|
// non-pointer receiver.
|
||||||
|
if entry.Time.IsZero() {
|
||||||
entry.Time = time.Now()
|
entry.Time = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
entry.Level = level
|
entry.Level = level
|
||||||
entry.Message = msg
|
entry.Message = msg
|
||||||
|
|
||||||
@@ -113,12 +127,10 @@ func (entry Entry) log(level Level, msg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is not declared with a pointer value because otherwise
|
func (entry *Entry) fireHooks() {
|
||||||
// race conditions will occur when using multiple goroutines
|
|
||||||
func (entry Entry) fireHooks() {
|
|
||||||
entry.Logger.mu.Lock()
|
entry.Logger.mu.Lock()
|
||||||
defer entry.Logger.mu.Unlock()
|
defer entry.Logger.mu.Unlock()
|
||||||
err := entry.Logger.Hooks.Fire(entry.Level, &entry)
|
err := entry.Logger.Hooks.Fire(entry.Level, entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|||||||
20
vendor/github.com/sirupsen/logrus/exported.go
сгенерированный
поставляемый
20
vendor/github.com/sirupsen/logrus/exported.go
сгенерированный
поставляемый
@@ -2,6 +2,7 @@ package logrus
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -15,9 +16,7 @@ func StandardLogger() *Logger {
|
|||||||
|
|
||||||
// SetOutput sets the standard logger output.
|
// SetOutput sets the standard logger output.
|
||||||
func SetOutput(out io.Writer) {
|
func SetOutput(out io.Writer) {
|
||||||
std.mu.Lock()
|
std.SetOutput(out)
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Out = out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFormatter sets the standard logger formatter.
|
// SetFormatter sets the standard logger formatter.
|
||||||
@@ -72,6 +71,15 @@ func WithFields(fields Fields) *Entry {
|
|||||||
return std.WithFields(fields)
|
return std.WithFields(fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithTime creats an entry from the standard logger and overrides the time of
|
||||||
|
// logs generated with it.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithTime(t time.Time) *Entry {
|
||||||
|
return std.WithTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
// Debug logs a message at level Debug on the standard logger.
|
// Debug logs a message at level Debug on the standard logger.
|
||||||
func Debug(args ...interface{}) {
|
func Debug(args ...interface{}) {
|
||||||
std.Debug(args...)
|
std.Debug(args...)
|
||||||
@@ -107,7 +115,7 @@ func Panic(args ...interface{}) {
|
|||||||
std.Panic(args...)
|
std.Panic(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal logs a message at level Fatal on the standard logger.
|
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||||
func Fatal(args ...interface{}) {
|
func Fatal(args ...interface{}) {
|
||||||
std.Fatal(args...)
|
std.Fatal(args...)
|
||||||
}
|
}
|
||||||
@@ -147,7 +155,7 @@ func Panicf(format string, args ...interface{}) {
|
|||||||
std.Panicf(format, args...)
|
std.Panicf(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf logs a message at level Fatal on the standard logger.
|
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||||
func Fatalf(format string, args ...interface{}) {
|
func Fatalf(format string, args ...interface{}) {
|
||||||
std.Fatalf(format, args...)
|
std.Fatalf(format, args...)
|
||||||
}
|
}
|
||||||
@@ -187,7 +195,7 @@ func Panicln(args ...interface{}) {
|
|||||||
std.Panicln(args...)
|
std.Panicln(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalln logs a message at level Fatal on the standard logger.
|
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||||
func Fatalln(args ...interface{}) {
|
func Fatalln(args ...interface{}) {
|
||||||
std.Fatalln(args...)
|
std.Fatalln(args...)
|
||||||
}
|
}
|
||||||
|
|||||||
20
vendor/github.com/sirupsen/logrus/formatter.go
сгенерированный
поставляемый
20
vendor/github.com/sirupsen/logrus/formatter.go
сгенерированный
поставляемый
@@ -30,16 +30,22 @@ type Formatter interface {
|
|||||||
//
|
//
|
||||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||||
// avoid code duplication between the two default formatters.
|
// avoid code duplication between the two default formatters.
|
||||||
func prefixFieldClashes(data Fields) {
|
func prefixFieldClashes(data Fields, fieldMap FieldMap) {
|
||||||
if t, ok := data["time"]; ok {
|
timeKey := fieldMap.resolve(FieldKeyTime)
|
||||||
data["fields.time"] = t
|
if t, ok := data[timeKey]; ok {
|
||||||
|
data["fields."+timeKey] = t
|
||||||
|
delete(data, timeKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m, ok := data["msg"]; ok {
|
msgKey := fieldMap.resolve(FieldKeyMsg)
|
||||||
data["fields.msg"] = m
|
if m, ok := data[msgKey]; ok {
|
||||||
|
data["fields."+msgKey] = m
|
||||||
|
delete(data, msgKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if l, ok := data["level"]; ok {
|
levelKey := fieldMap.resolve(FieldKeyLevel)
|
||||||
data["fields.level"] = l
|
if l, ok := data[levelKey]; ok {
|
||||||
|
data["fields."+levelKey] = l
|
||||||
|
delete(data, levelKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
vendor/github.com/sirupsen/logrus/json_formatter.go
сгенерированный
поставляемый
12
vendor/github.com/sirupsen/logrus/json_formatter.go
сгенерированный
поставляемый
@@ -33,6 +33,9 @@ type JSONFormatter struct {
|
|||||||
// DisableTimestamp allows disabling automatic timestamps in output
|
// DisableTimestamp allows disabling automatic timestamps in output
|
||||||
DisableTimestamp bool
|
DisableTimestamp bool
|
||||||
|
|
||||||
|
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
|
||||||
|
DataKey string
|
||||||
|
|
||||||
// FieldMap allows users to customize the names of keys for default fields.
|
// FieldMap allows users to customize the names of keys for default fields.
|
||||||
// As an example:
|
// As an example:
|
||||||
// formatter := &JSONFormatter{
|
// formatter := &JSONFormatter{
|
||||||
@@ -58,7 +61,14 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prefixFieldClashes(data)
|
|
||||||
|
if f.DataKey != "" {
|
||||||
|
newData := make(Fields, 4)
|
||||||
|
newData[f.DataKey] = data
|
||||||
|
data = newData
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixFieldClashes(data, f.FieldMap)
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
timestampFormat := f.TimestampFormat
|
||||||
if timestampFormat == "" {
|
if timestampFormat == "" {
|
||||||
|
|||||||
16
vendor/github.com/sirupsen/logrus/logger.go
сгенерированный
поставляемый
16
vendor/github.com/sirupsen/logrus/logger.go
сгенерированный
поставляемый
@@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
@@ -88,7 +89,7 @@ func (logger *Logger) releaseEntry(entry *Entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Adds a field to the log entry, note that it doesn't log until you call
|
// Adds a field to the log entry, note that it doesn't log until you call
|
||||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
|
||||||
// If you want multiple fields, use `WithFields`.
|
// If you want multiple fields, use `WithFields`.
|
||||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
@@ -112,6 +113,13 @@ func (logger *Logger) WithError(err error) *Entry {
|
|||||||
return entry.WithError(err)
|
return entry.WithError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overrides the time of the log entry.
|
||||||
|
func (logger *Logger) WithTime(t time.Time) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
if logger.level() >= DebugLevel {
|
if logger.level() >= DebugLevel {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
@@ -316,6 +324,12 @@ func (logger *Logger) SetLevel(level Level) {
|
|||||||
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) SetOutput(out io.Writer) {
|
||||||
|
logger.mu.Lock()
|
||||||
|
defer logger.mu.Unlock()
|
||||||
|
logger.Out = out
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) AddHook(hook Hook) {
|
func (logger *Logger) AddHook(hook Hook) {
|
||||||
logger.mu.Lock()
|
logger.mu.Lock()
|
||||||
defer logger.mu.Unlock()
|
defer logger.mu.Unlock()
|
||||||
|
|||||||
31
vendor/github.com/sirupsen/logrus/text_formatter.go
сгенерированный
поставляемый
31
vendor/github.com/sirupsen/logrus/text_formatter.go
сгенерированный
поставляемый
@@ -20,6 +20,7 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
baseTimestamp time.Time
|
baseTimestamp time.Time
|
||||||
|
emptyFieldMap FieldMap
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -50,12 +51,24 @@ type TextFormatter struct {
|
|||||||
// be desired.
|
// be desired.
|
||||||
DisableSorting bool
|
DisableSorting bool
|
||||||
|
|
||||||
|
// Disables the truncation of the level text to 4 characters.
|
||||||
|
DisableLevelTruncation bool
|
||||||
|
|
||||||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||||
QuoteEmptyFields bool
|
QuoteEmptyFields bool
|
||||||
|
|
||||||
// Whether the logger's out is to a terminal
|
// Whether the logger's out is to a terminal
|
||||||
isTerminal bool
|
isTerminal bool
|
||||||
|
|
||||||
|
// FieldMap allows users to customize the names of keys for default fields.
|
||||||
|
// As an example:
|
||||||
|
// formatter := &TextFormatter{
|
||||||
|
// FieldMap: FieldMap{
|
||||||
|
// FieldKeyTime: "@timestamp",
|
||||||
|
// FieldKeyLevel: "@level",
|
||||||
|
// FieldKeyMsg: "@message"}}
|
||||||
|
FieldMap FieldMap
|
||||||
|
|
||||||
sync.Once
|
sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +80,8 @@ func (f *TextFormatter) init(entry *Entry) {
|
|||||||
|
|
||||||
// Format renders a single log entry
|
// Format renders a single log entry
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
var b *bytes.Buffer
|
prefixFieldClashes(entry.Data, f.FieldMap)
|
||||||
|
|
||||||
keys := make([]string, 0, len(entry.Data))
|
keys := make([]string, 0, len(entry.Data))
|
||||||
for k := range entry.Data {
|
for k := range entry.Data {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
@@ -76,14 +90,14 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
if !f.DisableSorting {
|
if !f.DisableSorting {
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var b *bytes.Buffer
|
||||||
if entry.Buffer != nil {
|
if entry.Buffer != nil {
|
||||||
b = entry.Buffer
|
b = entry.Buffer
|
||||||
} else {
|
} else {
|
||||||
b = &bytes.Buffer{}
|
b = &bytes.Buffer{}
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixFieldClashes(entry.Data)
|
|
||||||
|
|
||||||
f.Do(func() { f.init(entry) })
|
f.Do(func() { f.init(entry) })
|
||||||
|
|
||||||
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
|
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
|
||||||
@@ -96,11 +110,11 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
f.printColored(b, entry, keys, timestampFormat)
|
f.printColored(b, entry, keys, timestampFormat)
|
||||||
} else {
|
} else {
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyTime), entry.Time.Format(timestampFormat))
|
||||||
}
|
}
|
||||||
f.appendKeyValue(b, "level", entry.Level.String())
|
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyLevel), entry.Level.String())
|
||||||
if entry.Message != "" {
|
if entry.Message != "" {
|
||||||
f.appendKeyValue(b, "msg", entry.Message)
|
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyMsg), entry.Message)
|
||||||
}
|
}
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
f.appendKeyValue(b, key, entry.Data[key])
|
f.appendKeyValue(b, key, entry.Data[key])
|
||||||
@@ -124,7 +138,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
|||||||
levelColor = blue
|
levelColor = blue
|
||||||
}
|
}
|
||||||
|
|
||||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
levelText := strings.ToUpper(entry.Level.String())
|
||||||
|
if !f.DisableLevelTruncation {
|
||||||
|
levelText = levelText[0:4]
|
||||||
|
}
|
||||||
|
|
||||||
if f.DisableTimestamp {
|
if f.DisableTimestamp {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
|
||||||
|
|||||||
2
vendor/github.com/spf13/jwalterweatherman/README.md
сгенерированный
поставляемый
2
vendor/github.com/spf13/jwalterweatherman/README.md
сгенерированный
поставляемый
@@ -18,7 +18,7 @@ provides a few advantages over using the standard log library alone.
|
|||||||
I really wanted a very straightforward library that could seamlessly do
|
I really wanted a very straightforward library that could seamlessly do
|
||||||
the following things.
|
the following things.
|
||||||
|
|
||||||
1. Replace all the println, printf, etc statements thought my code with
|
1. Replace all the println, printf, etc statements thoughout my code with
|
||||||
something more useful
|
something more useful
|
||||||
2. Allow the user to easily control what levels are printed to stdout
|
2. Allow the user to easily control what levels are printed to stdout
|
||||||
3. Allow the user to easily control what levels are logged
|
3. Allow the user to easily control what levels are logged
|
||||||
|
|||||||
104
vendor/github.com/spf13/pflag/bytes.go
сгенерированный
поставляемый
104
vendor/github.com/spf13/pflag/bytes.go
сгенерированный
поставляемый
@@ -1,6 +1,7 @@
|
|||||||
package pflag
|
package pflag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -9,10 +10,12 @@ import (
|
|||||||
// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
|
// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
|
||||||
type bytesHexValue []byte
|
type bytesHexValue []byte
|
||||||
|
|
||||||
|
// String implements pflag.Value.String.
|
||||||
func (bytesHex bytesHexValue) String() string {
|
func (bytesHex bytesHexValue) String() string {
|
||||||
return fmt.Sprintf("%X", []byte(bytesHex))
|
return fmt.Sprintf("%X", []byte(bytesHex))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set implements pflag.Value.Set.
|
||||||
func (bytesHex *bytesHexValue) Set(value string) error {
|
func (bytesHex *bytesHexValue) Set(value string) error {
|
||||||
bin, err := hex.DecodeString(strings.TrimSpace(value))
|
bin, err := hex.DecodeString(strings.TrimSpace(value))
|
||||||
|
|
||||||
@@ -25,6 +28,7 @@ func (bytesHex *bytesHexValue) Set(value string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type implements pflag.Value.Type.
|
||||||
func (*bytesHexValue) Type() string {
|
func (*bytesHexValue) Type() string {
|
||||||
return "bytesHex"
|
return "bytesHex"
|
||||||
}
|
}
|
||||||
@@ -103,3 +107,103 @@ func BytesHex(name string, value []byte, usage string) *[]byte {
|
|||||||
func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
|
func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
|
||||||
return CommandLine.BytesHexP(name, shorthand, value, usage)
|
return CommandLine.BytesHexP(name, shorthand, value, usage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BytesBase64 adapts []byte for use as a flag. Value of flag is Base64 encoded
|
||||||
|
type bytesBase64Value []byte
|
||||||
|
|
||||||
|
// String implements pflag.Value.String.
|
||||||
|
func (bytesBase64 bytesBase64Value) String() string {
|
||||||
|
return base64.StdEncoding.EncodeToString([]byte(bytesBase64))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implements pflag.Value.Set.
|
||||||
|
func (bytesBase64 *bytesBase64Value) Set(value string) error {
|
||||||
|
bin, err := base64.StdEncoding.DecodeString(strings.TrimSpace(value))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*bytesBase64 = bin
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type implements pflag.Value.Type.
|
||||||
|
func (*bytesBase64Value) Type() string {
|
||||||
|
return "bytesBase64"
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBytesBase64Value(val []byte, p *[]byte) *bytesBase64Value {
|
||||||
|
*p = val
|
||||||
|
return (*bytesBase64Value)(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bytesBase64ValueConv(sval string) (interface{}, error) {
|
||||||
|
|
||||||
|
bin, err := base64.StdEncoding.DecodeString(sval)
|
||||||
|
if err == nil {
|
||||||
|
return bin, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytesBase64 return the []byte value of a flag with the given name
|
||||||
|
func (f *FlagSet) GetBytesBase64(name string) ([]byte, error) {
|
||||||
|
val, err := f.getFlagType(name, "bytesBase64", bytesBase64ValueConv)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return val.([]byte), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesBase64Var defines an []byte flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to an []byte variable in which to store the value of the flag.
|
||||||
|
func (f *FlagSet) BytesBase64Var(p *[]byte, name string, value []byte, usage string) {
|
||||||
|
f.VarP(newBytesBase64Value(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) {
|
||||||
|
f.VarP(newBytesBase64Value(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesBase64Var defines an []byte flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to an []byte variable in which to store the value of the flag.
|
||||||
|
func BytesBase64Var(p *[]byte, name string, value []byte, usage string) {
|
||||||
|
CommandLine.VarP(newBytesBase64Value(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesBase64VarP is like BytesBase64Var, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func BytesBase64VarP(p *[]byte, name, shorthand string, value []byte, usage string) {
|
||||||
|
CommandLine.VarP(newBytesBase64Value(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesBase64 defines an []byte flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of an []byte variable that stores the value of the flag.
|
||||||
|
func (f *FlagSet) BytesBase64(name string, value []byte, usage string) *[]byte {
|
||||||
|
p := new([]byte)
|
||||||
|
f.BytesBase64VarP(p, name, "", value, usage)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte {
|
||||||
|
p := new([]byte)
|
||||||
|
f.BytesBase64VarP(p, name, shorthand, value, usage)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesBase64 defines an []byte flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of an []byte variable that stores the value of the flag.
|
||||||
|
func BytesBase64(name string, value []byte, usage string) *[]byte {
|
||||||
|
return CommandLine.BytesBase64P(name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesBase64P is like BytesBase64, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func BytesBase64P(name, shorthand string, value []byte, usage string) *[]byte {
|
||||||
|
return CommandLine.BytesBase64P(name, shorthand, value, usage)
|
||||||
|
}
|
||||||
|
|||||||
3
vendor/github.com/spf13/pflag/flag.go
сгенерированный
поставляемый
3
vendor/github.com/spf13/pflag/flag.go
сгенерированный
поставляемый
@@ -990,11 +990,12 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) {
|
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) {
|
||||||
|
outArgs = args
|
||||||
|
|
||||||
if strings.HasPrefix(shorthands, "test.") {
|
if strings.HasPrefix(shorthands, "test.") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
outArgs = args
|
|
||||||
outShorts = shorthands[1:]
|
outShorts = shorthands[1:]
|
||||||
c := shorthands[0]
|
c := shorthands[0]
|
||||||
|
|
||||||
|
|||||||
9
vendor/go.uber.org/zap/CHANGELOG.md
сгенерированный
поставляемый
9
vendor/go.uber.org/zap/CHANGELOG.md
сгенерированный
поставляемый
@@ -1,12 +1,18 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.9.1 (06 Aug 2018)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
|
||||||
|
* [#614][]: MapObjectEncoder should not ignore empty slices.
|
||||||
|
|
||||||
## v1.9.0 (19 Jul 2018)
|
## v1.9.0 (19 Jul 2018)
|
||||||
|
|
||||||
Enhancements:
|
Enhancements:
|
||||||
* [#602][]: Reduce number of allocations when logging with reflection.
|
* [#602][]: Reduce number of allocations when logging with reflection.
|
||||||
* [#572][], [#606][]: Expose a registry for third-party logging sinks.
|
* [#572][], [#606][]: Expose a registry for third-party logging sinks.
|
||||||
|
|
||||||
Thanks to @nfarah86, @AlekSi, @JeanMertz, @phillippgille, @etsangsplk, and
|
Thanks to @nfarah86, @AlekSi, @JeanMertz, @philippgille, @etsangsplk, and
|
||||||
@dimroc for their contributions to this release.
|
@dimroc for their contributions to this release.
|
||||||
|
|
||||||
## v1.8.0 (13 Apr 2018)
|
## v1.8.0 (13 Apr 2018)
|
||||||
@@ -296,3 +302,4 @@ upgrade to the upcoming stable release.
|
|||||||
[#602]: https://github.com/uber-go/zap/pull/602
|
[#602]: https://github.com/uber-go/zap/pull/602
|
||||||
[#572]: https://github.com/uber-go/zap/pull/572
|
[#572]: https://github.com/uber-go/zap/pull/572
|
||||||
[#606]: https://github.com/uber-go/zap/pull/606
|
[#606]: https://github.com/uber-go/zap/pull/606
|
||||||
|
[#614]: https://github.com/uber-go/zap/pull/614
|
||||||
|
|||||||
2
vendor/go.uber.org/zap/zapcore/memory_encoder.go
сгенерированный
поставляемый
2
vendor/go.uber.org/zap/zapcore/memory_encoder.go
сгенерированный
поставляемый
@@ -43,7 +43,7 @@ func NewMapObjectEncoder() *MapObjectEncoder {
|
|||||||
|
|
||||||
// AddArray implements ObjectEncoder.
|
// AddArray implements ObjectEncoder.
|
||||||
func (m *MapObjectEncoder) AddArray(key string, v ArrayMarshaler) error {
|
func (m *MapObjectEncoder) AddArray(key string, v ArrayMarshaler) error {
|
||||||
arr := &sliceArrayEncoder{}
|
arr := &sliceArrayEncoder{elems: make([]interface{}, 0)}
|
||||||
err := v.MarshalLogArray(arr)
|
err := v.MarshalLogArray(arr)
|
||||||
m.cur[key] = arr.elems
|
m.cur[key] = arr.elems
|
||||||
return err
|
return err
|
||||||
|
|||||||
13
vendor/golang.org/x/crypto/acme/acme.go
сгенерированный
поставляемый
13
vendor/golang.org/x/crypto/acme/acme.go
сгенерированный
поставляемый
@@ -39,8 +39,18 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
|
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
|
||||||
const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
|
LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
|
||||||
|
|
||||||
|
// ALPNProto is the ALPN protocol name used by a CA server when validating
|
||||||
|
// tls-alpn-01 challenges.
|
||||||
|
//
|
||||||
|
// Package users must ensure their servers can negotiate the ACME ALPN in
|
||||||
|
// order for tls-alpn-01 challenge verifications to succeed.
|
||||||
|
// See the crypto/tls package's Config.NextProtos field.
|
||||||
|
ALPNProto = "acme-tls/1"
|
||||||
|
)
|
||||||
|
|
||||||
// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge.
|
// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge.
|
||||||
var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1}
|
var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1}
|
||||||
@@ -647,6 +657,7 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
|||||||
res, err := c.post(ctx, c.Key, url, req, wantStatus(
|
res, err := c.post(ctx, c.Key, url, req, wantStatus(
|
||||||
http.StatusOK, // updates and deletes
|
http.StatusOK, // updates and deletes
|
||||||
http.StatusCreated, // new account creation
|
http.StatusCreated, // new account creation
|
||||||
|
http.StatusAccepted, // Let's Encrypt divergent implementation
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
91
vendor/golang.org/x/crypto/acme/autocert/autocert.go
сгенерированный
поставляемый
91
vendor/golang.org/x/crypto/acme/autocert/autocert.go
сгенерированный
поставляемый
@@ -44,7 +44,7 @@ var createCertRetryAfter = time.Minute
|
|||||||
var pseudoRand *lockedMathRand
|
var pseudoRand *lockedMathRand
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
src := mathrand.NewSource(timeNow().UnixNano())
|
src := mathrand.NewSource(time.Now().UnixNano())
|
||||||
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
|
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,9 +81,9 @@ func defaultHostPolicy(context.Context, string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Manager is a stateful certificate manager built on top of acme.Client.
|
// Manager is a stateful certificate manager built on top of acme.Client.
|
||||||
// It obtains and refreshes certificates automatically using "tls-sni-01",
|
// It obtains and refreshes certificates automatically using "tls-alpn-01",
|
||||||
// "tls-sni-02" and "http-01" challenge types, as well as providing them
|
// "tls-sni-01", "tls-sni-02" and "http-01" challenge types,
|
||||||
// to a TLS server via tls.Config.
|
// as well as providing them to a TLS server via tls.Config.
|
||||||
//
|
//
|
||||||
// You must specify a cache implementation, such as DirCache,
|
// You must specify a cache implementation, such as DirCache,
|
||||||
// to reuse obtained certificates across program restarts.
|
// to reuse obtained certificates across program restarts.
|
||||||
@@ -177,18 +177,22 @@ type Manager struct {
|
|||||||
// to be provisioned.
|
// to be provisioned.
|
||||||
// The entries are stored for the duration of the authorization flow.
|
// The entries are stored for the duration of the authorization flow.
|
||||||
httpTokens map[string][]byte
|
httpTokens map[string][]byte
|
||||||
// certTokens contains temporary certificates for tls-sni challenges
|
// certTokens contains temporary certificates for tls-sni and tls-alpn challenges
|
||||||
// and is keyed by token domain name, which matches server name of ClientHello.
|
// and is keyed by token domain name, which matches server name of ClientHello.
|
||||||
// Keys always have ".acme.invalid" suffix.
|
// Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names
|
||||||
|
// for tls-alpn.
|
||||||
// The entries are stored for the duration of the authorization flow.
|
// The entries are stored for the duration of the authorization flow.
|
||||||
certTokens map[string]*tls.Certificate
|
certTokens map[string]*tls.Certificate
|
||||||
|
// nowFunc, if not nil, returns the current time. This may be set for
|
||||||
|
// testing purposes.
|
||||||
|
nowFunc func() time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// certKey is the key by which certificates are tracked in state, renewal and cache.
|
// certKey is the key by which certificates are tracked in state, renewal and cache.
|
||||||
type certKey struct {
|
type certKey struct {
|
||||||
domain string // without trailing dot
|
domain string // without trailing dot
|
||||||
isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA)
|
isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA)
|
||||||
isToken bool // tls-sni challenge token cert; key type is undefined regardless of isRSA
|
isToken bool // tls-based challenge token cert; key type is undefined regardless of isRSA
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c certKey) String() string {
|
func (c certKey) String() string {
|
||||||
@@ -201,14 +205,32 @@ func (c certKey) String() string {
|
|||||||
return c.domain
|
return c.domain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TLSConfig creates a new TLS config suitable for net/http.Server servers,
|
||||||
|
// supporting HTTP/2 and the tls-alpn-01 ACME challenge type.
|
||||||
|
func (m *Manager) TLSConfig() *tls.Config {
|
||||||
|
return &tls.Config{
|
||||||
|
GetCertificate: m.GetCertificate,
|
||||||
|
NextProtos: []string{
|
||||||
|
"h2", "http/1.1", // enable HTTP/2
|
||||||
|
acme.ALPNProto, // enable tls-alpn ACME challenges
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetCertificate implements the tls.Config.GetCertificate hook.
|
// GetCertificate implements the tls.Config.GetCertificate hook.
|
||||||
// It provides a TLS certificate for hello.ServerName host, including answering
|
// It provides a TLS certificate for hello.ServerName host, including answering
|
||||||
// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored.
|
// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges.
|
||||||
|
// All other fields of hello are ignored.
|
||||||
//
|
//
|
||||||
// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
|
// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
|
||||||
// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
|
// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
|
||||||
// The error is propagated back to the caller of GetCertificate and is user-visible.
|
// The error is propagated back to the caller of GetCertificate and is user-visible.
|
||||||
// This does not affect cached certs. See HostPolicy field description for more details.
|
// This does not affect cached certs. See HostPolicy field description for more details.
|
||||||
|
//
|
||||||
|
// If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will
|
||||||
|
// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler
|
||||||
|
// for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers
|
||||||
|
// due to security issues in the ecosystem.)
|
||||||
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
if m.Prompt == nil {
|
if m.Prompt == nil {
|
||||||
return nil, errors.New("acme/autocert: Manager.Prompt not set")
|
return nil, errors.New("acme/autocert: Manager.Prompt not set")
|
||||||
@@ -230,10 +252,13 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// check whether this is a token cert requested for TLS-SNI challenge
|
// Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge.
|
||||||
if strings.HasSuffix(name, ".acme.invalid") {
|
if wantsTokenCert(hello) {
|
||||||
m.tokensMu.RLock()
|
m.tokensMu.RLock()
|
||||||
defer m.tokensMu.RUnlock()
|
defer m.tokensMu.RUnlock()
|
||||||
|
// It's ok to use the same token cert key for both tls-sni and tls-alpn
|
||||||
|
// because there's always at most 1 token cert per on-going domain authorization.
|
||||||
|
// See m.verify for details.
|
||||||
if cert := m.certTokens[name]; cert != nil {
|
if cert := m.certTokens[name]; cert != nil {
|
||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
@@ -269,6 +294,17 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
|||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wantsTokenCert reports whether a TLS request with SNI is made by a CA server
|
||||||
|
// for a challenge verification.
|
||||||
|
func wantsTokenCert(hello *tls.ClientHelloInfo) bool {
|
||||||
|
// tls-alpn-01
|
||||||
|
if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// tls-sni-xx
|
||||||
|
return strings.HasSuffix(hello.ServerName, ".acme.invalid")
|
||||||
|
}
|
||||||
|
|
||||||
func supportsECDSA(hello *tls.ClientHelloInfo) bool {
|
func supportsECDSA(hello *tls.ClientHelloInfo) bool {
|
||||||
// The "signature_algorithms" extension, if present, limits the key exchange
|
// The "signature_algorithms" extension, if present, limits the key exchange
|
||||||
// algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1.
|
// algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1.
|
||||||
@@ -328,8 +364,8 @@ func supportsECDSA(hello *tls.ClientHelloInfo) bool {
|
|||||||
// Because the fallback handler is run with unencrypted port 80 requests,
|
// Because the fallback handler is run with unencrypted port 80 requests,
|
||||||
// the fallback should not serve TLS-only requests.
|
// the fallback should not serve TLS-only requests.
|
||||||
//
|
//
|
||||||
// If HTTPHandler is never called, the Manager will only use TLS SNI
|
// If HTTPHandler is never called, the Manager will only use the "tls-alpn-01"
|
||||||
// challenges for domain verification.
|
// challenge for domain verification.
|
||||||
func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
|
func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
|
||||||
m.tokensMu.Lock()
|
m.tokensMu.Lock()
|
||||||
defer m.tokensMu.Unlock()
|
defer m.tokensMu.Unlock()
|
||||||
@@ -447,7 +483,7 @@ func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// verify and create TLS cert
|
// verify and create TLS cert
|
||||||
leaf, err := validCert(ck, pubDER, privKey)
|
leaf, err := validCert(ck, pubDER, privKey, m.now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrCacheMiss
|
return nil, ErrCacheMiss
|
||||||
}
|
}
|
||||||
@@ -542,7 +578,7 @@ func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate,
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, err := validCert(ck, s.cert, s.key); err == nil {
|
if _, err := validCert(ck, s.cert, s.key, m.now()); err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delete(m.state, ck)
|
delete(m.state, ck)
|
||||||
@@ -611,7 +647,7 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck cert
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
leaf, err = validCert(ck, der, key)
|
leaf, err = validCert(ck, der, key, m.now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -635,7 +671,7 @@ func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) {
|
|||||||
func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
|
func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
|
||||||
// The list of challenge types we'll try to fulfill
|
// The list of challenge types we'll try to fulfill
|
||||||
// in this specific order.
|
// in this specific order.
|
||||||
challengeTypes := []string{"tls-sni-02", "tls-sni-01"}
|
challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"}
|
||||||
m.tokensMu.RLock()
|
m.tokensMu.RLock()
|
||||||
if m.tryHTTP01 {
|
if m.tryHTTP01 {
|
||||||
challengeTypes = append(challengeTypes, "http-01")
|
challengeTypes = append(challengeTypes, "http-01")
|
||||||
@@ -691,7 +727,7 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
|
|||||||
}
|
}
|
||||||
return errors.New(errorMsg)
|
return errors.New(errorMsg)
|
||||||
}
|
}
|
||||||
cleanup, err := m.fulfill(ctx, client, chal)
|
cleanup, err := m.fulfill(ctx, client, chal, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs[chal] = err
|
errs[chal] = err
|
||||||
continue
|
continue
|
||||||
@@ -714,8 +750,15 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
|
|||||||
|
|
||||||
// fulfill provisions a response to the challenge chal.
|
// fulfill provisions a response to the challenge chal.
|
||||||
// The cleanup is non-nil only if provisioning succeeded.
|
// The cleanup is non-nil only if provisioning succeeded.
|
||||||
func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge) (cleanup func(), err error) {
|
func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) {
|
||||||
switch chal.Type {
|
switch chal.Type {
|
||||||
|
case "tls-alpn-01":
|
||||||
|
cert, err := client.TLSALPN01ChallengeCert(chal.Token, domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m.putCertToken(ctx, domain, &cert)
|
||||||
|
return func() { go m.deleteCertToken(domain) }, nil
|
||||||
case "tls-sni-01":
|
case "tls-sni-01":
|
||||||
cert, name, err := client.TLSSNI01ChallengeCert(chal.Token)
|
cert, name, err := client.TLSSNI01ChallengeCert(chal.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -948,6 +991,13 @@ func (m *Manager) renewBefore() time.Duration {
|
|||||||
return 720 * time.Hour // 30 days
|
return 720 * time.Hour // 30 days
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) now() time.Time {
|
||||||
|
if m.nowFunc != nil {
|
||||||
|
return m.nowFunc()
|
||||||
|
}
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
// certState is ready when its mutex is unlocked for reading.
|
// certState is ready when its mutex is unlocked for reading.
|
||||||
type certState struct {
|
type certState struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
@@ -1014,7 +1064,7 @@ func parsePrivateKey(der []byte) (crypto.Signer, error) {
|
|||||||
// are valid. It doesn't do any revocation checking.
|
// are valid. It doesn't do any revocation checking.
|
||||||
//
|
//
|
||||||
// The returned value is the verified leaf cert.
|
// The returned value is the verified leaf cert.
|
||||||
func validCert(ck certKey, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) {
|
func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf *x509.Certificate, err error) {
|
||||||
// parse public part(s)
|
// parse public part(s)
|
||||||
var n int
|
var n int
|
||||||
for _, b := range der {
|
for _, b := range der {
|
||||||
@@ -1031,7 +1081,6 @@ func validCert(ck certKey, der [][]byte, key crypto.Signer) (leaf *x509.Certific
|
|||||||
}
|
}
|
||||||
// verify the leaf is not expired and matches the domain name
|
// verify the leaf is not expired and matches the domain name
|
||||||
leaf = x509Cert[0]
|
leaf = x509Cert[0]
|
||||||
now := timeNow()
|
|
||||||
if now.Before(leaf.NotBefore) {
|
if now.Before(leaf.NotBefore) {
|
||||||
return nil, errors.New("acme/autocert: certificate is not valid yet")
|
return nil, errors.New("acme/autocert: certificate is not valid yet")
|
||||||
}
|
}
|
||||||
@@ -1085,8 +1134,6 @@ func (r *lockedMathRand) int63n(max int64) int64 {
|
|||||||
|
|
||||||
// For easier testing.
|
// For easier testing.
|
||||||
var (
|
var (
|
||||||
timeNow = time.Now
|
|
||||||
|
|
||||||
// Called when a state is removed.
|
// Called when a state is removed.
|
||||||
testDidRemoveState = func(certKey) {}
|
testDidRemoveState = func(certKey) {}
|
||||||
)
|
)
|
||||||
|
|||||||
5
vendor/golang.org/x/crypto/acme/autocert/listener.go
сгенерированный
поставляемый
5
vendor/golang.org/x/crypto/acme/autocert/listener.go
сгенерированный
поставляемый
@@ -73,10 +73,7 @@ func NewListener(domains ...string) net.Listener {
|
|||||||
func (m *Manager) Listener() net.Listener {
|
func (m *Manager) Listener() net.Listener {
|
||||||
ln := &listener{
|
ln := &listener{
|
||||||
m: m,
|
m: m,
|
||||||
conf: &tls.Config{
|
conf: m.TLSConfig(),
|
||||||
GetCertificate: m.GetCertificate, // bonus: panic on nil m
|
|
||||||
NextProtos: []string{"h2", "http/1.1"}, // Enable HTTP/2
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
|
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
|
||||||
return ln
|
return ln
|
||||||
|
|||||||
2
vendor/golang.org/x/crypto/acme/autocert/renewal.go
сгенерированный
поставляемый
2
vendor/golang.org/x/crypto/acme/autocert/renewal.go
сгенерированный
поставляемый
@@ -128,7 +128,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
|
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
|
||||||
d := expiry.Sub(timeNow()) - dr.m.renewBefore()
|
d := expiry.Sub(dr.m.now()) - dr.m.renewBefore()
|
||||||
// add a bit of randomness to renew deadline
|
// add a bit of randomness to renew deadline
|
||||||
n := pseudoRand.int63n(int64(renewJitter))
|
n := pseudoRand.int63n(int64(renewJitter))
|
||||||
d -= time.Duration(n)
|
d -= time.Duration(n)
|
||||||
|
|||||||
74
vendor/golang.org/x/net/html/parse.go
сгенерированный
поставляемый
74
vendor/golang.org/x/net/html/parse.go
сгенерированный
поставляемый
@@ -209,27 +209,6 @@ loop:
|
|||||||
p.oe = p.oe[:i+1]
|
p.oe = p.oe[:i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateAllImpliedEndTags pops nodes off the stack of open elements as long as
|
|
||||||
// the top node has a tag name of caption, colgroup, dd, div, dt, li, optgroup, option, p, rb,
|
|
||||||
// rp, rt, rtc, span, tbody, td, tfoot, th, thead or tr.
|
|
||||||
func (p *parser) generateAllImpliedEndTags() {
|
|
||||||
var i int
|
|
||||||
for i = len(p.oe) - 1; i >= 0; i-- {
|
|
||||||
n := p.oe[i]
|
|
||||||
if n.Type == ElementNode {
|
|
||||||
switch n.DataAtom {
|
|
||||||
// TODO: remove this divergence from the HTML5 spec
|
|
||||||
case a.Caption, a.Colgroup, a.Dd, a.Div, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb,
|
|
||||||
a.Rp, a.Rt, a.Rtc, a.Span, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
p.oe = p.oe[:i+1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// addChild adds a child node n to the top element, and pushes n onto the stack
|
// addChild adds a child node n to the top element, and pushes n onto the stack
|
||||||
// of open elements if it is an element node.
|
// of open elements if it is an element node.
|
||||||
func (p *parser) addChild(n *Node) {
|
func (p *parser) addChild(n *Node) {
|
||||||
@@ -679,11 +658,16 @@ func inHeadIM(p *parser) bool {
|
|||||||
if !p.oe.contains(a.Template) {
|
if !p.oe.contains(a.Template) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
p.generateAllImpliedEndTags()
|
// TODO: remove this divergence from the HTML5 spec.
|
||||||
if n := p.oe.top(); n.DataAtom != a.Template {
|
//
|
||||||
return true
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||||
|
p.generateImpliedEndTags()
|
||||||
|
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||||
|
if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
|
||||||
|
p.oe = p.oe[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.popUntil(defaultScope, a.Template)
|
|
||||||
p.clearActiveFormattingElements()
|
p.clearActiveFormattingElements()
|
||||||
p.templateStack.pop()
|
p.templateStack.pop()
|
||||||
p.resetInsertionMode()
|
p.resetInsertionMode()
|
||||||
@@ -1074,13 +1058,7 @@ func inBodyIM(p *parser) bool {
|
|||||||
p.acknowledgeSelfClosingTag()
|
p.acknowledgeSelfClosingTag()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case a.Frame:
|
case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
||||||
// TODO: remove this divergence from the HTML5 spec.
|
|
||||||
if p.oe.contains(a.Template) {
|
|
||||||
p.addElement()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case a.Caption, a.Col, a.Colgroup, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
|
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
default:
|
default:
|
||||||
p.reconstructActiveFormattingElements()
|
p.reconstructActiveFormattingElements()
|
||||||
@@ -1351,9 +1329,6 @@ func textIM(p *parser) bool {
|
|||||||
// Section 12.2.6.4.9.
|
// Section 12.2.6.4.9.
|
||||||
func inTableIM(p *parser) bool {
|
func inTableIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case ErrorToken:
|
|
||||||
// Stop parsing.
|
|
||||||
return true
|
|
||||||
case TextToken:
|
case TextToken:
|
||||||
p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1)
|
p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1)
|
||||||
switch p.oe.top().DataAtom {
|
switch p.oe.top().DataAtom {
|
||||||
@@ -1448,6 +1423,8 @@ func inTableIM(p *parser) bool {
|
|||||||
case DoctypeToken:
|
case DoctypeToken:
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
|
case ErrorToken:
|
||||||
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.fosterParenting = true
|
p.fosterParenting = true
|
||||||
@@ -1550,6 +1527,8 @@ func inColumnGroupIM(p *parser) bool {
|
|||||||
case a.Template:
|
case a.Template:
|
||||||
return inHeadIM(p)
|
return inHeadIM(p)
|
||||||
}
|
}
|
||||||
|
case ErrorToken:
|
||||||
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
if p.oe.top().DataAtom != a.Colgroup {
|
if p.oe.top().DataAtom != a.Colgroup {
|
||||||
return true
|
return true
|
||||||
@@ -1714,9 +1693,6 @@ func inCellIM(p *parser) bool {
|
|||||||
// Section 12.2.6.4.16.
|
// Section 12.2.6.4.16.
|
||||||
func inSelectIM(p *parser) bool {
|
func inSelectIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case ErrorToken:
|
|
||||||
// Stop parsing.
|
|
||||||
return true
|
|
||||||
case TextToken:
|
case TextToken:
|
||||||
p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
|
p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
|
||||||
case StartTagToken:
|
case StartTagToken:
|
||||||
@@ -1780,6 +1756,8 @@ func inSelectIM(p *parser) bool {
|
|||||||
case DoctypeToken:
|
case DoctypeToken:
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
|
case ErrorToken:
|
||||||
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -1846,17 +1824,28 @@ func inTemplateIM(p *parser) bool {
|
|||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
case ErrorToken:
|
||||||
if !p.oe.contains(a.Template) {
|
if !p.oe.contains(a.Template) {
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
p.popUntil(defaultScope, a.Template)
|
// TODO: remove this divergence from the HTML5 spec.
|
||||||
|
//
|
||||||
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||||
|
p.generateImpliedEndTags()
|
||||||
|
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||||
|
if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
|
||||||
|
p.oe = p.oe[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
p.clearActiveFormattingElements()
|
p.clearActiveFormattingElements()
|
||||||
p.templateStack.pop()
|
p.templateStack.pop()
|
||||||
p.resetInsertionMode()
|
p.resetInsertionMode()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Section 12.2.6.4.19.
|
// Section 12.2.6.4.19.
|
||||||
func afterBodyIM(p *parser) bool {
|
func afterBodyIM(p *parser) bool {
|
||||||
@@ -1928,11 +1917,6 @@ func inFramesetIM(p *parser) bool {
|
|||||||
p.acknowledgeSelfClosingTag()
|
p.acknowledgeSelfClosingTag()
|
||||||
case a.Noframes:
|
case a.Noframes:
|
||||||
return inHeadIM(p)
|
return inHeadIM(p)
|
||||||
case a.Template:
|
|
||||||
// TODO: remove this divergence from the HTML5 spec.
|
|
||||||
//
|
|
||||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
|
||||||
return inTemplateIM(p)
|
|
||||||
}
|
}
|
||||||
case EndTagToken:
|
case EndTagToken:
|
||||||
switch p.tok.DataAtom {
|
switch p.tok.DataAtom {
|
||||||
|
|||||||
20
vendor/golang.org/x/net/http2/headermap.go
сгенерированный
поставляемый
20
vendor/golang.org/x/net/http2/headermap.go
сгенерированный
поставляемый
@@ -7,15 +7,21 @@ package http2
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
commonLowerHeader = map[string]string{} // Go-Canonical-Case -> lower-case
|
commonBuildOnce sync.Once
|
||||||
commonCanonHeader = map[string]string{} // lower-case -> Go-Canonical-Case
|
commonLowerHeader map[string]string // Go-Canonical-Case -> lower-case
|
||||||
|
commonCanonHeader map[string]string // lower-case -> Go-Canonical-Case
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func buildCommonHeaderMapsOnce() {
|
||||||
for _, v := range []string{
|
commonBuildOnce.Do(buildCommonHeaderMaps)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildCommonHeaderMaps() {
|
||||||
|
common := []string{
|
||||||
"accept",
|
"accept",
|
||||||
"accept-charset",
|
"accept-charset",
|
||||||
"accept-encoding",
|
"accept-encoding",
|
||||||
@@ -63,7 +69,10 @@ func init() {
|
|||||||
"vary",
|
"vary",
|
||||||
"via",
|
"via",
|
||||||
"www-authenticate",
|
"www-authenticate",
|
||||||
} {
|
}
|
||||||
|
commonLowerHeader = make(map[string]string, len(common))
|
||||||
|
commonCanonHeader = make(map[string]string, len(common))
|
||||||
|
for _, v := range common {
|
||||||
chk := http.CanonicalHeaderKey(v)
|
chk := http.CanonicalHeaderKey(v)
|
||||||
commonLowerHeader[chk] = v
|
commonLowerHeader[chk] = v
|
||||||
commonCanonHeader[v] = chk
|
commonCanonHeader[v] = chk
|
||||||
@@ -71,6 +80,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func lowerHeader(v string) string {
|
func lowerHeader(v string) string {
|
||||||
|
buildCommonHeaderMapsOnce()
|
||||||
if s, ok := commonLowerHeader[v]; ok {
|
if s, ok := commonLowerHeader[v]; ok {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
20
vendor/golang.org/x/net/http2/hpack/huffman.go
сгенерированный
поставляемый
20
vendor/golang.org/x/net/http2/hpack/huffman.go
сгенерированный
поставляемый
@@ -47,6 +47,7 @@ var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
|
|||||||
// If maxLen is greater than 0, attempts to write more to buf than
|
// If maxLen is greater than 0, attempts to write more to buf than
|
||||||
// maxLen bytes will return ErrStringLength.
|
// maxLen bytes will return ErrStringLength.
|
||||||
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
|
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
|
||||||
|
rootHuffmanNode := getRootHuffmanNode()
|
||||||
n := rootHuffmanNode
|
n := rootHuffmanNode
|
||||||
// cur is the bit buffer that has not been fed into n.
|
// cur is the bit buffer that has not been fed into n.
|
||||||
// cbits is the number of low order bits in cur that are valid.
|
// cbits is the number of low order bits in cur that are valid.
|
||||||
@@ -106,7 +107,7 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
|
|||||||
|
|
||||||
type node struct {
|
type node struct {
|
||||||
// children is non-nil for internal nodes
|
// children is non-nil for internal nodes
|
||||||
children []*node
|
children *[256]*node
|
||||||
|
|
||||||
// The following are only valid if children is nil:
|
// The following are only valid if children is nil:
|
||||||
codeLen uint8 // number of bits that led to the output of sym
|
codeLen uint8 // number of bits that led to the output of sym
|
||||||
@@ -114,22 +115,31 @@ type node struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newInternalNode() *node {
|
func newInternalNode() *node {
|
||||||
return &node{children: make([]*node, 256)}
|
return &node{children: new([256]*node)}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootHuffmanNode = newInternalNode()
|
var (
|
||||||
|
buildRootOnce sync.Once
|
||||||
|
lazyRootHuffmanNode *node
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func getRootHuffmanNode() *node {
|
||||||
|
buildRootOnce.Do(buildRootHuffmanNode)
|
||||||
|
return lazyRootHuffmanNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildRootHuffmanNode() {
|
||||||
if len(huffmanCodes) != 256 {
|
if len(huffmanCodes) != 256 {
|
||||||
panic("unexpected size")
|
panic("unexpected size")
|
||||||
}
|
}
|
||||||
|
lazyRootHuffmanNode = newInternalNode()
|
||||||
for i, code := range huffmanCodes {
|
for i, code := range huffmanCodes {
|
||||||
addDecoderNode(byte(i), code, huffmanCodeLen[i])
|
addDecoderNode(byte(i), code, huffmanCodeLen[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addDecoderNode(sym byte, code uint32, codeLen uint8) {
|
func addDecoderNode(sym byte, code uint32, codeLen uint8) {
|
||||||
cur := rootHuffmanNode
|
cur := lazyRootHuffmanNode
|
||||||
for codeLen > 8 {
|
for codeLen > 8 {
|
||||||
codeLen -= 8
|
codeLen -= 8
|
||||||
i := uint8(code >> codeLen)
|
i := uint8(code >> codeLen)
|
||||||
|
|||||||
17
vendor/golang.org/x/net/http2/http2.go
сгенерированный
поставляемый
17
vendor/golang.org/x/net/http2/http2.go
сгенерированный
поставляемый
@@ -201,19 +201,12 @@ func validWireHeaderFieldName(v string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
var httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
for i := 100; i <= 999; i++ {
|
|
||||||
if v := http.StatusText(i); v != "" {
|
|
||||||
httpCodeStringCommon[i] = strconv.Itoa(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func httpCodeString(code int) string {
|
func httpCodeString(code int) string {
|
||||||
if s, ok := httpCodeStringCommon[code]; ok {
|
switch code {
|
||||||
return s
|
case 200:
|
||||||
|
return "200"
|
||||||
|
case 404:
|
||||||
|
return "404"
|
||||||
}
|
}
|
||||||
return strconv.Itoa(code)
|
return strconv.Itoa(code)
|
||||||
}
|
}
|
||||||
|
|||||||
9
vendor/golang.org/x/net/http2/server.go
сгенерированный
поставляемый
9
vendor/golang.org/x/net/http2/server.go
сгенерированный
поставляемый
@@ -663,6 +663,7 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
|
|||||||
|
|
||||||
func (sc *serverConn) canonicalHeader(v string) string {
|
func (sc *serverConn) canonicalHeader(v string) string {
|
||||||
sc.serveG.check()
|
sc.serveG.check()
|
||||||
|
buildCommonHeaderMapsOnce()
|
||||||
cv, ok := commonCanonHeader[v]
|
cv, ok := commonCanonHeader[v]
|
||||||
if ok {
|
if ok {
|
||||||
return cv
|
return cv
|
||||||
@@ -2346,16 +2347,8 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
_, hasContentType := rws.snapHeader["Content-Type"]
|
_, hasContentType := rws.snapHeader["Content-Type"]
|
||||||
if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
|
if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
|
||||||
if cto := rws.snapHeader.Get("X-Content-Type-Options"); strings.EqualFold("nosniff", cto) {
|
|
||||||
// nosniff is an explicit directive not to guess a content-type.
|
|
||||||
// Content-sniffing is no less susceptible to polyglot attacks via
|
|
||||||
// hosted content when done on the server.
|
|
||||||
ctype = "application/octet-stream"
|
|
||||||
rws.conn.logf("http2: WriteHeader called with X-Content-Type-Options:nosniff but no Content-Type")
|
|
||||||
} else {
|
|
||||||
ctype = http.DetectContentType(p)
|
ctype = http.DetectContentType(p)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
var date string
|
var date string
|
||||||
if _, ok := rws.snapHeader["Date"]; !ok {
|
if _, ok := rws.snapHeader["Date"]; !ok {
|
||||||
// TODO(bradfitz): be faster here, like net/http? measure.
|
// TODO(bradfitz): be faster here, like net/http? measure.
|
||||||
|
|||||||
2
vendor/golang.org/x/net/ipv4/doc.go
сгенерированный
поставляемый
2
vendor/golang.org/x/net/ipv4/doc.go
сгенерированный
поставляемый
@@ -55,7 +55,7 @@
|
|||||||
// Multicasting
|
// Multicasting
|
||||||
//
|
//
|
||||||
// The options for multicasting are available for net.UDPConn and
|
// The options for multicasting are available for net.UDPConn and
|
||||||
// net.IPconn which are created as network connections that use the
|
// net.IPConn which are created as network connections that use the
|
||||||
// IPv4 transport. A few network facilities must be prepared before
|
// IPv4 transport. A few network facilities must be prepared before
|
||||||
// you begin multicasting, at a minimum joining network interfaces and
|
// you begin multicasting, at a minimum joining network interfaces and
|
||||||
// multicast groups.
|
// multicast groups.
|
||||||
|
|||||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user