Update dependencies (#886)

This commit is contained in:
Wim 2019-09-07 22:46:58 +02:00 committed by GitHub
parent 1dc93ec4f0
commit a3bee01e0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
145 changed files with 24283 additions and 16572 deletions

View File

@ -85,7 +85,7 @@ func (b *Bsteam) handleEvents() {
func (b *Bsteam) handleLogOnFailed(e *steam.LogOnFailedEvent, myLoginInfo *steam.LogOnDetails) error { func (b *Bsteam) handleLogOnFailed(e *steam.LogOnFailedEvent, myLoginInfo *steam.LogOnDetails) error {
switch e.Result { switch e.Result {
case steamlang.EResult_AccountLogonDeniedNeedTwoFactorCode: case steamlang.EResult_AccountLoginDeniedNeedTwoFactor:
b.Log.Info("Steam guard isn't letting me in! Enter 2FA code:") b.Log.Info("Steam guard isn't letting me in! Enter 2FA code:")
var code string var code string
fmt.Scanf("%s", &code) fmt.Scanf("%s", &code)

View File

@ -9,9 +9,9 @@ fi
# Run the linter. # Run the linter.
golangci-lint run golangci-lint run
if [[ "${GO111MODULE-off}" == "on" ]]; then # if [[ "${GO111MODULE-off}" == "on" ]]; then
# If Go modules are active then check that dependencies are correctly maintained. # # If Go modules are active then check that dependencies are correctly maintained.
go mod tidy # go mod tidy
go mod vendor # go mod vendor
git diff --exit-code --quiet || (echo "Please run 'go mod tidy' to clean up the 'go.mod' and 'go.sum' files."; false) # git diff --exit-code --quiet || (echo "Please run 'go mod tidy' to clean up the 'go.mod' and 'go.sum' files."; false)
fi # fi

26
go.mod
View File

@ -4,11 +4,11 @@ require (
github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
github.com/Jeffail/gabs v1.1.1 // indirect github.com/Jeffail/gabs v1.1.1 // indirect
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a
github.com/bwmarrin/discordgo v0.19.0 github.com/bwmarrin/discordgo v0.19.0
// github.com/bwmarrin/discordgo v0.19.0 // github.com/bwmarrin/discordgo v0.19.0
github.com/d5/tengo v1.24.1 github.com/d5/tengo v1.24.3
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
github.com/fsnotify/fsnotify v1.4.7 github.com/fsnotify/fsnotify v1.4.7
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
@ -16,16 +16,14 @@ require (
github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f // indirect github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f // indirect
github.com/gorilla/schema v1.1.0 github.com/gorilla/schema v1.1.0
github.com/gorilla/websocket v1.4.0 github.com/gorilla/websocket v1.4.1
github.com/hashicorp/golang-lru v0.5.1 github.com/hashicorp/golang-lru v0.5.3
github.com/hpcloud/tail v1.0.0 // indirect github.com/hpcloud/tail v1.0.0 // indirect
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7
github.com/jtolds/gls v4.2.1+incompatible // indirect github.com/jtolds/gls v4.2.1+incompatible // indirect
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2 github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2
github.com/labstack/echo/v4 v4.1.6 github.com/labstack/echo/v4 v4.1.10
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 // indirect
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91
github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea
@ -37,7 +35,7 @@ require (
github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
github.com/nicksnyder/go-i18n v1.4.0 // indirect github.com/nicksnyder/go-i18n v1.4.0 // indirect
github.com/nlopes/slack v0.5.0 github.com/nlopes/slack v0.6.0
github.com/onsi/ginkgo v1.6.0 // indirect github.com/onsi/ginkgo v1.6.0 // indirect
github.com/onsi/gomega v1.4.1 // indirect github.com/onsi/gomega v1.4.1 // indirect
github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
@ -47,11 +45,12 @@ require (
github.com/russross/blackfriday v1.5.2 github.com/russross/blackfriday v1.5.2
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2
github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 // indirect github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 // indirect
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect
github.com/spf13/viper v1.4.0 github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.4.0
github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2 github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2
@ -62,12 +61,17 @@ require (
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe // indirect gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe // indirect
gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638 // indirect gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638 // indirect
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 // indirect golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 // indirect
golang.org/x/image v0.0.0-20190616094056-33659d3de4f5 golang.org/x/image v0.0.0-20190902063713-cb417be4ba39
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect golang.org/x/text v0.3.2 // indirect
gopkg.in/fsnotify.v1 v1.4.7 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/russross/blackfriday.v2 v2.0.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
) )
replace github.com/bwmarrin/discordgo v0.19.0 => github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40 replace github.com/bwmarrin/discordgo v0.19.0 => github.com/matterbridge/discordgo v0.0.0-20190818085008-57c6e0fc2f40
replace gopkg.in/russross/blackfriday.v2 v2.0.1 => github.com/russross/blackfriday/v2 v2.0.1
go 1.13

61
go.sum
View File

@ -8,8 +8,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E= github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E=
github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 h1:xZBoq249G9MSt+XuY7sVQzcfONJ6IQuwpCK+KAaOpnY= github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0 h1:TO7d4rocnNFng6ZQrPe7U6WqHtK5eHEMrgrnnM/72IQ=
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg= github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg=
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA= github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a h1:umvfZW+YE+ynhYwsyheyunB/3xRK68kNFMRNUMQxzJI= github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a h1:umvfZW+YE+ynhYwsyheyunB/3xRK68kNFMRNUMQxzJI=
github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a/go.mod h1:qf/2PQi82Okxw/igghu/oMGzTeUYuKBq1JNo3tdQyNg= github.com/Rhymen/go-whatsapp v0.0.3-0.20190729104911-5c79b2cf277a/go.mod h1:qf/2PQi82Okxw/igghu/oMGzTeUYuKBq1JNo3tdQyNg=
@ -17,6 +17,7 @@ github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/g
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU= github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw= github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM= github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM=
github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e h1:IHXQQIpxASe3m0Jtcd3XongL+lxHNd5nUmvHxJARUmg=
github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@ -31,8 +32,8 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/d5/tengo v1.24.1 h1:b+epGF5Qi0XUkYUUl8y6hVzLxg/eu9FYUAdb4H/KieY= github.com/d5/tengo v1.24.3 h1:wp44VW7fdfzMzIDT19tT5uNeGnm2UMd6s3TLAahrwSU=
github.com/d5/tengo v1.24.1/go.mod h1:gsbjo7lBXzBIWBd6NQp1lRKqqiDDANqBOyhW8rTlFsY= github.com/d5/tengo v1.24.3/go.mod h1:VhLq8Q2QFhCIJO3NhvM934qOThykMqJi9y9Siqd1ocQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -47,6 +48,7 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible h1:i64CCJcSqkRIkm5OSdZQjZq84/gJsk2zNwHWIRYWlKE= github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible h1:i64CCJcSqkRIkm5OSdZQjZq84/gJsk2zNwHWIRYWlKE=
@ -71,13 +73,16 @@ github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f h1:FDM3EtwZLyhW4
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY= github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
@ -106,16 +111,12 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo/v4 v4.1.6 h1:WOvLa4T1KzWCRpANwz0HGgWDelXSSGwIKtKBbFdHTv4= github.com/labstack/echo/v4 v4.1.10 h1:/yhIpO50CBInUbE/nHJtGIyhBv0dJe2cDAYxc3V3uMo=
github.com/labstack/echo/v4 v4.1.6/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE= github.com/labstack/echo/v4 v4.1.10/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/gommon v0.2.9 h1:heVeuAYtevIQVYkGj6A41dtfT91LrvFG220lavpWhrU= github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 h1:BS9tqL0OCiOGuy/CYYk2gc33fxqaqh5/rhqMKu4tcYA= github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 h1:BS9tqL0OCiOGuy/CYYk2gc33fxqaqh5/rhqMKu4tcYA=
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7/go.mod h1:liX5MxHPrwgHaKowoLkYGwbXfYABh1jbZ6FpElbGF1I= github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7/go.mod h1:liX5MxHPrwgHaKowoLkYGwbXfYABh1jbZ6FpElbGF1I=
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 h1:AsEBgzv3DhuYHI/GiQh2HxvTP71HCCE9E/tzGUzGdtU=
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0=
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 h1:iOAVXzZyXtW408TMYejlUPo6BIn92HmOacWtIfNyYns=
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d h1:F+Sr+C0ojSlYQ37BLylQtSFmyQULe3jbAygcyXQ9mVs= github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d h1:F+Sr+C0ojSlYQ37BLylQtSFmyQULe3jbAygcyXQ9mVs=
@ -140,6 +141,8 @@ github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
@ -154,8 +157,8 @@ github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 h1:mp6tU1r0xLostUGL
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9/go.mod h1:A5SRAcpTemjGgIuBq6Kic2yHcoeUFWUinOAlMP/i9xo= github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9/go.mod h1:A5SRAcpTemjGgIuBq6Kic2yHcoeUFWUinOAlMP/i9xo=
github.com/nicksnyder/go-i18n v1.4.0 h1:AgLl+Yq7kg5OYlzCgu9cKTZOyI4tD/NgukKqLqC8E+I= github.com/nicksnyder/go-i18n v1.4.0 h1:AgLl+Yq7kg5OYlzCgu9cKTZOyI4tD/NgukKqLqC8E+I=
github.com/nicksnyder/go-i18n v1.4.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= github.com/nicksnyder/go-i18n v1.4.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -188,6 +191,8 @@ github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zKc9A3BuGYbQAGlEFyPuUA3jeMD0= github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zKc9A3BuGYbQAGlEFyPuUA3jeMD0=
@ -196,7 +201,10 @@ github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 h1:8RLq547MSVc6vhO
github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296/go.mod h1:1GLXsL4esywkpNId3v4QWuMf3THtWGitWvtQ/L3aSA4= github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296/go.mod h1:1GLXsL4esywkpNId3v4QWuMf3THtWGitWvtQ/L3aSA4=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 h1:80VN+vGkqM773Br/uNNTSheo3KatTgV8IpjIKjvVLng= github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 h1:80VN+vGkqM773Br/uNNTSheo3KatTgV8IpjIKjvVLng=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -220,11 +228,9 @@ github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@ -265,12 +271,11 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/image v0.0.0-20190616094056-33659d3de4f5 h1:ngW7cqsJcNIFizl289rKwy+nVvw7TQS8z3ejrra6syo= golang.org/x/image v0.0.0-20190902063713-cb417be4ba39 h1:4dQcAORh9oYBwVSBVIkP489LUPC+f1HBkTYXgmqfR+o=
golang.org/x/image v0.0.0-20190616094056-33659d3de4f5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190902063713-cb417be4ba39/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -280,8 +285,6 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190607181551-461777fb6f67 h1:rJJxsykSlULwd2P2+pg/rtnwN2FrWp4IuCxOSyS0V00=
golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -289,8 +292,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20171017063910-8dbc5d05d6ed/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20171017063910-8dbc5d05d6ed/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -300,9 +301,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190609082536-301114b31cce h1:CQakrGkKbydnUmt7cFIlmQ4lNQiqdTPt6xzXij4nYCc=
golang.org/x/sys v0.0.0-20190609082536-301114b31cce/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
@ -314,7 +312,6 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=

View File

@ -45,19 +45,10 @@ Whether you want to develop your own Steam bot or directly work on go-steam itse
## Updating go-steam to a new SteamKit version ## Updating go-steam to a new SteamKit version
To update go-steam to a new version of SteamKit, do the following: Go source code is generated with code in the `generator` directory.
Look at `generator/README.md` for more information on how to use the generator.
go get github.com/golang/protobuf/protoc-gen-go/ Then, after generating new Go source files, update `go-steam` as necessary.
git submodule init && git submodule update
cd generator
go run generator.go clean proto steamlang
Make sure that `$GOPATH/bin` / `protoc-gen-go` is in your `$PATH`. You'll also need [`protoc`](https://developers.google.com/protocol-buffers/docs/downloads), the protocol buffer compiler. At the moment, we use Protocol Buffers 2.6.1 with `proco-gen-go`-[2402d76](https://github.com/golang/protobuf/tree/2402d76f3d41f928c7902a765dfc872356dd3aad).
To compile the Steam Language files, you also need the [.NET Framework](https://www.microsoft.com/net/downloads)
on Windows or [mono](http://www.go-mono.com/mono-downloads/download.html) on other operating systems.
Apply the protocol changes where necessary.
## License ## License

View File

@ -94,9 +94,6 @@ func (a *Auth) HandlePacket(packet *Packet) {
a.handleUpdateMachineAuth(packet) a.handleUpdateMachineAuth(packet)
case EMsg_ClientAccountInfo: case EMsg_ClientAccountInfo:
a.handleAccountInfo(packet) a.handleAccountInfo(packet)
case EMsg_ClientWalletInfoUpdate:
case EMsg_ClientRequestWebAPIAuthenticateUserNonceResponse:
case EMsg_ClientMarketingMessageUpdate:
} }
} }

View File

@ -133,11 +133,17 @@ func (c *Client) Connected() bool {
// If you want to connect to a specific server, use `ConnectTo`. // If you want to connect to a specific server, use `ConnectTo`.
func (c *Client) Connect() *netutil.PortAddr { func (c *Client) Connect() *netutil.PortAddr {
var server *netutil.PortAddr var server *netutil.PortAddr
// try to initialize the directory cache
if !steamDirectoryCache.IsInitialized() {
_ = steamDirectoryCache.Initialize()
}
if steamDirectoryCache.IsInitialized() { if steamDirectoryCache.IsInitialized() {
server = steamDirectoryCache.GetRandomCM() server = steamDirectoryCache.GetRandomCM()
} else { } else {
server = GetRandomCM() server = GetRandomCM()
} }
c.ConnectTo(server) c.ConnectTo(server)
return server return server
} }

View File

@ -1,6 +1,7 @@
package protocol package protocol
import ( import (
"encoding/hex"
"io" "io"
"math" "math"
"strconv" "strconv"
@ -42,6 +43,7 @@ const EClientPersonaStateFlag_DefaultInfoRequest = EClientPersonaStateFlag_Playe
const DefaultAvatar = "fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb" const DefaultAvatar = "fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb"
func ValidAvatar(avatar string) bool { func ValidAvatar(avatar []byte) bool {
return !(avatar == "0000000000000000000000000000000000000000" || len(avatar) != 40) str := hex.EncodeToString(avatar)
return !(str == "0000000000000000000000000000000000000000" || len(str) != 40)
} }

View File

@ -1,31 +1,60 @@
// Code generated by protoc-gen-go. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: encrypted_app_ticket.proto // source: encrypted_app_ticket.proto
// DO NOT EDIT!
package protobuf package protobuf
import proto "github.com/golang/protobuf/proto" import (
import fmt "fmt" fmt "fmt"
import math "math" proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal var _ = proto.Marshal
var _ = fmt.Errorf var _ = fmt.Errorf
var _ = math.Inf var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package protobuf is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package protobuf to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type EncryptedAppTicket struct { type EncryptedAppTicket struct {
TicketVersionNo *uint32 `protobuf:"varint,1,opt,name=ticket_version_no" json:"ticket_version_no,omitempty"` TicketVersionNo *uint32 `protobuf:"varint,1,opt,name=ticket_version_no" json:"ticket_version_no,omitempty"`
CrcEncryptedticket *uint32 `protobuf:"varint,2,opt,name=crc_encryptedticket" json:"crc_encryptedticket,omitempty"` CrcEncryptedticket *uint32 `protobuf:"varint,2,opt,name=crc_encryptedticket" json:"crc_encryptedticket,omitempty"`
CbEncrypteduserdata *uint32 `protobuf:"varint,3,opt,name=cb_encrypteduserdata" json:"cb_encrypteduserdata,omitempty"` CbEncrypteduserdata *uint32 `protobuf:"varint,3,opt,name=cb_encrypteduserdata" json:"cb_encrypteduserdata,omitempty"`
CbEncryptedAppownershipticket *uint32 `protobuf:"varint,4,opt,name=cb_encrypted_appownershipticket" json:"cb_encrypted_appownershipticket,omitempty"` CbEncryptedAppownershipticket *uint32 `protobuf:"varint,4,opt,name=cb_encrypted_appownershipticket" json:"cb_encrypted_appownershipticket,omitempty"`
EncryptedTicket []byte `protobuf:"bytes,5,opt,name=encrypted_ticket" json:"encrypted_ticket,omitempty"` EncryptedTicket []byte `protobuf:"bytes,5,opt,name=encrypted_ticket" json:"encrypted_ticket,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *EncryptedAppTicket) Reset() { *m = EncryptedAppTicket{} } func (m *EncryptedAppTicket) Reset() { *m = EncryptedAppTicket{} }
func (m *EncryptedAppTicket) String() string { return proto.CompactTextString(m) } func (m *EncryptedAppTicket) String() string { return proto.CompactTextString(m) }
func (*EncryptedAppTicket) ProtoMessage() {} func (*EncryptedAppTicket) ProtoMessage() {}
func (*EncryptedAppTicket) Descriptor() ([]byte, []int) { return app_ticket_fileDescriptor0, []int{0} } func (*EncryptedAppTicket) Descriptor() ([]byte, []int) {
return fileDescriptor_c6d69fd1cac4e8d5, []int{0}
}
func (m *EncryptedAppTicket) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EncryptedAppTicket.Unmarshal(m, b)
}
func (m *EncryptedAppTicket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EncryptedAppTicket.Marshal(b, m, deterministic)
}
func (m *EncryptedAppTicket) XXX_Merge(src proto.Message) {
xxx_messageInfo_EncryptedAppTicket.Merge(m, src)
}
func (m *EncryptedAppTicket) XXX_Size() int {
return xxx_messageInfo_EncryptedAppTicket.Size(m)
}
func (m *EncryptedAppTicket) XXX_DiscardUnknown() {
xxx_messageInfo_EncryptedAppTicket.DiscardUnknown(m)
}
var xxx_messageInfo_EncryptedAppTicket proto.InternalMessageInfo
func (m *EncryptedAppTicket) GetTicketVersionNo() uint32 { func (m *EncryptedAppTicket) GetTicketVersionNo() uint32 {
if m != nil && m.TicketVersionNo != nil { if m != nil && m.TicketVersionNo != nil {
@ -66,17 +95,19 @@ func init() {
proto.RegisterType((*EncryptedAppTicket)(nil), "EncryptedAppTicket") proto.RegisterType((*EncryptedAppTicket)(nil), "EncryptedAppTicket")
} }
var app_ticket_fileDescriptor0 = []byte{ func init() { proto.RegisterFile("encrypted_app_ticket.proto", fileDescriptor_c6d69fd1cac4e8d5) }
// 162 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0xcd, 0x4b, 0x2e, var fileDescriptor_c6d69fd1cac4e8d5 = []byte{
// 164 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0xcd, 0x4b, 0x2e,
0xaa, 0x2c, 0x28, 0x49, 0x4d, 0x89, 0x4f, 0x2c, 0x28, 0x88, 0x2f, 0xc9, 0x4c, 0xce, 0x4e, 0x2d, 0xaa, 0x2c, 0x28, 0x49, 0x4d, 0x89, 0x4f, 0x2c, 0x28, 0x88, 0x2f, 0xc9, 0x4c, 0xce, 0x4e, 0x2d,
0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x5a, 0xcb, 0xc8, 0x25, 0xe4, 0x0a, 0x93, 0x76, 0x2c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x5a, 0xcb, 0xc8, 0x25, 0xe4, 0x0a, 0x93, 0x76, 0x2c,
0x28, 0x08, 0x01, 0x4b, 0x0a, 0x49, 0x72, 0x09, 0x42, 0x94, 0xc5, 0x97, 0xa5, 0x16, 0x15, 0x67, 0x28, 0x08, 0x01, 0x4b, 0x0a, 0x49, 0x72, 0x09, 0x42, 0x94, 0xc5, 0x97, 0xa5, 0x16, 0x15, 0x67,
0xe6, 0xe7, 0xc5, 0xe7, 0xe5, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x0a, 0x49, 0x73, 0x09, 0x27, 0xe6, 0xe7, 0xc5, 0xe7, 0xe5, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x0a, 0x49, 0x73, 0x09, 0x27,
0x17, 0x25, 0xc7, 0xc3, 0xcd, 0x84, 0xa8, 0x93, 0x60, 0x02, 0x4b, 0xca, 0x70, 0x89, 0x24, 0x27, 0x17, 0x25, 0xc7, 0xc3, 0xcd, 0x84, 0xa8, 0x93, 0x60, 0x02, 0x4b, 0xca, 0x70, 0x89, 0x24, 0x27,
0x21, 0xe4, 0x4a, 0x8b, 0x53, 0x8b, 0x52, 0x12, 0x4b, 0x12, 0x25, 0x98, 0xc1, 0xb2, 0xea, 0x5c, 0x21, 0xe4, 0x4a, 0x8b, 0x53, 0x8b, 0x52, 0x12, 0x4b, 0x12, 0x25, 0x98, 0xc1, 0xb2, 0xea, 0x5c,
0xf2, 0xc8, 0xb2, 0x20, 0xd7, 0xe4, 0x97, 0xe7, 0x01, 0x2d, 0xc8, 0xc8, 0x2c, 0x80, 0x1a, 0xc3, 0xf2, 0xc8, 0xb2, 0x20, 0xd7, 0xe4, 0x97, 0xe7, 0xa5, 0x16, 0x15, 0x67, 0x64, 0x16, 0x40, 0x8d,
0x02, 0x56, 0x28, 0xc1, 0x25, 0x80, 0x50, 0x05, 0x95, 0x61, 0x05, 0xca, 0xf0, 0x38, 0xb1, 0x7a, 0x61, 0x01, 0x2b, 0x94, 0xe0, 0x12, 0x40, 0xa8, 0x82, 0xca, 0xb0, 0x2a, 0x30, 0x6a, 0xf0, 0x38,
0x30, 0x36, 0x30, 0x32, 0x00, 0x02, 0x00, 0x00, 0xff, 0xff, 0x03, 0x8c, 0xdb, 0x92, 0xd3, 0x00, 0xb1, 0x7a, 0x30, 0x36, 0x30, 0x32, 0x00, 0x02, 0x00, 0x00, 0xff, 0xff, 0x03, 0x8c, 0xdb, 0x92,
0x00, 0x00, 0xd3, 0x00, 0x00, 0x00,
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,397 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: steammessages_sitelicenseclient.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package protobuf is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package protobuf to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type CMsgClientSiteInfo struct {
SiteId *uint64 `protobuf:"varint,1,opt,name=site_id" json:"site_id,omitempty"`
SiteName *string `protobuf:"bytes,2,opt,name=site_name" json:"site_name,omitempty"`
AllowCachedCredentials *bool `protobuf:"varint,3,opt,name=allow_cached_credentials" json:"allow_cached_credentials,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteInfo) Reset() { *m = CMsgClientSiteInfo{} }
func (m *CMsgClientSiteInfo) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteInfo) ProtoMessage() {}
func (*CMsgClientSiteInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{0}
}
func (m *CMsgClientSiteInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteInfo.Unmarshal(m, b)
}
func (m *CMsgClientSiteInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteInfo.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteInfo.Merge(m, src)
}
func (m *CMsgClientSiteInfo) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteInfo.Size(m)
}
func (m *CMsgClientSiteInfo) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteInfo.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteInfo proto.InternalMessageInfo
func (m *CMsgClientSiteInfo) GetSiteId() uint64 {
if m != nil && m.SiteId != nil {
return *m.SiteId
}
return 0
}
func (m *CMsgClientSiteInfo) GetSiteName() string {
if m != nil && m.SiteName != nil {
return *m.SiteName
}
return ""
}
func (m *CMsgClientSiteInfo) GetAllowCachedCredentials() bool {
if m != nil && m.AllowCachedCredentials != nil {
return *m.AllowCachedCredentials
}
return false
}
type CMsgClientSiteLicenseCheckout struct {
Appid *uint32 `protobuf:"varint,1,opt,name=appid" json:"appid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseCheckout) Reset() { *m = CMsgClientSiteLicenseCheckout{} }
func (m *CMsgClientSiteLicenseCheckout) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteLicenseCheckout) ProtoMessage() {}
func (*CMsgClientSiteLicenseCheckout) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{1}
}
func (m *CMsgClientSiteLicenseCheckout) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseCheckout.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseCheckout) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseCheckout.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseCheckout) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseCheckout.Merge(m, src)
}
func (m *CMsgClientSiteLicenseCheckout) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseCheckout.Size(m)
}
func (m *CMsgClientSiteLicenseCheckout) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseCheckout.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseCheckout proto.InternalMessageInfo
func (m *CMsgClientSiteLicenseCheckout) GetAppid() uint32 {
if m != nil && m.Appid != nil {
return *m.Appid
}
return 0
}
type CMsgClientSiteLicenseCheckoutResponse struct {
Eresult *int32 `protobuf:"varint,1,opt,name=eresult,def=2" json:"eresult,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseCheckoutResponse) Reset() { *m = CMsgClientSiteLicenseCheckoutResponse{} }
func (m *CMsgClientSiteLicenseCheckoutResponse) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteLicenseCheckoutResponse) ProtoMessage() {}
func (*CMsgClientSiteLicenseCheckoutResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{2}
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.Merge(m, src)
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.Size(m)
}
func (m *CMsgClientSiteLicenseCheckoutResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseCheckoutResponse proto.InternalMessageInfo
const Default_CMsgClientSiteLicenseCheckoutResponse_Eresult int32 = 2
func (m *CMsgClientSiteLicenseCheckoutResponse) GetEresult() int32 {
if m != nil && m.Eresult != nil {
return *m.Eresult
}
return Default_CMsgClientSiteLicenseCheckoutResponse_Eresult
}
type CMsgClientSiteLicenseGetAvailableSeats struct {
Appid *uint32 `protobuf:"varint,1,opt,name=appid" json:"appid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) Reset() {
*m = CMsgClientSiteLicenseGetAvailableSeats{}
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteLicenseGetAvailableSeats) ProtoMessage() {}
func (*CMsgClientSiteLicenseGetAvailableSeats) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{3}
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.Merge(m, src)
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.Size(m)
}
func (m *CMsgClientSiteLicenseGetAvailableSeats) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeats proto.InternalMessageInfo
func (m *CMsgClientSiteLicenseGetAvailableSeats) GetAppid() uint32 {
if m != nil && m.Appid != nil {
return *m.Appid
}
return 0
}
type CMsgClientSiteLicenseGetAvailableSeatsResponse struct {
Eresult *int32 `protobuf:"varint,1,opt,name=eresult,def=2" json:"eresult,omitempty"`
Seats *uint32 `protobuf:"varint,2,opt,name=seats" json:"seats,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) Reset() {
*m = CMsgClientSiteLicenseGetAvailableSeatsResponse{}
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) String() string {
return proto.CompactTextString(m)
}
func (*CMsgClientSiteLicenseGetAvailableSeatsResponse) ProtoMessage() {}
func (*CMsgClientSiteLicenseGetAvailableSeatsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{4}
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.Merge(m, src)
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.Size(m)
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseGetAvailableSeatsResponse proto.InternalMessageInfo
const Default_CMsgClientSiteLicenseGetAvailableSeatsResponse_Eresult int32 = 2
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) GetEresult() int32 {
if m != nil && m.Eresult != nil {
return *m.Eresult
}
return Default_CMsgClientSiteLicenseGetAvailableSeatsResponse_Eresult
}
func (m *CMsgClientSiteLicenseGetAvailableSeatsResponse) GetSeats() uint32 {
if m != nil && m.Seats != nil {
return *m.Seats
}
return 0
}
type CMsgClientSiteLicenseGetContentCacheInfo struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) Reset() {
*m = CMsgClientSiteLicenseGetContentCacheInfo{}
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) String() string { return proto.CompactTextString(m) }
func (*CMsgClientSiteLicenseGetContentCacheInfo) ProtoMessage() {}
func (*CMsgClientSiteLicenseGetContentCacheInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{5}
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.Merge(m, src)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.Size(m)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfo) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfo proto.InternalMessageInfo
type CMsgClientSiteLicenseGetContentCacheInfoResponse struct {
UseCache *bool `protobuf:"varint,1,opt,name=use_cache" json:"use_cache,omitempty"`
Ipv4Address *uint32 `protobuf:"varint,2,opt,name=ipv4_address" json:"ipv4_address,omitempty"`
PortNumber *uint32 `protobuf:"varint,3,opt,name=port_number" json:"port_number,omitempty"`
P2PGroup *uint32 `protobuf:"varint,4,opt,name=p2p_group" json:"p2p_group,omitempty"`
IpAddress *string `protobuf:"bytes,5,opt,name=ip_address" json:"ip_address,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) Reset() {
*m = CMsgClientSiteLicenseGetContentCacheInfoResponse{}
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) String() string {
return proto.CompactTextString(m)
}
func (*CMsgClientSiteLicenseGetContentCacheInfoResponse) ProtoMessage() {}
func (*CMsgClientSiteLicenseGetContentCacheInfoResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_0a32817a56a37a6e, []int{6}
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.Unmarshal(m, b)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.Marshal(b, m, deterministic)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.Merge(m, src)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_Size() int {
return xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.Size(m)
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CMsgClientSiteLicenseGetContentCacheInfoResponse proto.InternalMessageInfo
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetUseCache() bool {
if m != nil && m.UseCache != nil {
return *m.UseCache
}
return false
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetIpv4Address() uint32 {
if m != nil && m.Ipv4Address != nil {
return *m.Ipv4Address
}
return 0
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetPortNumber() uint32 {
if m != nil && m.PortNumber != nil {
return *m.PortNumber
}
return 0
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetP2PGroup() uint32 {
if m != nil && m.P2PGroup != nil {
return *m.P2PGroup
}
return 0
}
func (m *CMsgClientSiteLicenseGetContentCacheInfoResponse) GetIpAddress() string {
if m != nil && m.IpAddress != nil {
return *m.IpAddress
}
return ""
}
func init() {
proto.RegisterType((*CMsgClientSiteInfo)(nil), "CMsgClientSiteInfo")
proto.RegisterType((*CMsgClientSiteLicenseCheckout)(nil), "CMsgClientSiteLicenseCheckout")
proto.RegisterType((*CMsgClientSiteLicenseCheckoutResponse)(nil), "CMsgClientSiteLicenseCheckoutResponse")
proto.RegisterType((*CMsgClientSiteLicenseGetAvailableSeats)(nil), "CMsgClientSiteLicenseGetAvailableSeats")
proto.RegisterType((*CMsgClientSiteLicenseGetAvailableSeatsResponse)(nil), "CMsgClientSiteLicenseGetAvailableSeatsResponse")
proto.RegisterType((*CMsgClientSiteLicenseGetContentCacheInfo)(nil), "CMsgClientSiteLicenseGetContentCacheInfo")
proto.RegisterType((*CMsgClientSiteLicenseGetContentCacheInfoResponse)(nil), "CMsgClientSiteLicenseGetContentCacheInfoResponse")
}
func init() {
proto.RegisterFile("steammessages_sitelicenseclient.proto", fileDescriptor_0a32817a56a37a6e)
}
var fileDescriptor_0a32817a56a37a6e = []byte{
// 335 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x41, 0x4b, 0xfb, 0x40,
0x14, 0xc4, 0xff, 0xfb, 0xb7, 0xa1, 0xed, 0xd3, 0x20, 0x5d, 0x3d, 0x04, 0x41, 0x08, 0x81, 0x4a,
0xf0, 0x50, 0xa4, 0x08, 0x82, 0x9e, 0x34, 0x07, 0x15, 0xf4, 0x62, 0x6f, 0x5e, 0xc2, 0x36, 0x79,
0xb6, 0x8b, 0x9b, 0xdd, 0x25, 0x6f, 0x53, 0xaf, 0x7e, 0x0b, 0xbf, 0xae, 0x64, 0x5b, 0x0a, 0x15,
0x2d, 0xbd, 0xee, 0xce, 0x6f, 0x66, 0x98, 0x07, 0x43, 0x72, 0x28, 0xaa, 0x0a, 0x89, 0xc4, 0x0c,
0x29, 0x27, 0xe9, 0x50, 0xc9, 0x02, 0x35, 0x61, 0xa1, 0x24, 0x6a, 0x37, 0xb2, 0xb5, 0x71, 0xe6,
0x24, 0xda, 0x94, 0x4d, 0x05, 0xe1, 0xf2, 0x27, 0x79, 0x05, 0x9e, 0x3d, 0xd3, 0x2c, 0xf3, 0xea,
0x89, 0x74, 0xf8, 0xa8, 0xdf, 0x0c, 0x3f, 0x84, 0x6e, 0x6b, 0x95, 0xcb, 0x32, 0x62, 0x31, 0x4b,
0x3b, 0x7c, 0x00, 0x7d, 0xff, 0xa0, 0x45, 0x85, 0xd1, 0xff, 0x98, 0xa5, 0x7d, 0x1e, 0x43, 0x24,
0x94, 0x32, 0x1f, 0x79, 0x21, 0x8a, 0x39, 0x96, 0x79, 0x51, 0x63, 0x89, 0xda, 0x49, 0xa1, 0x28,
0xda, 0x8b, 0x59, 0xda, 0x4b, 0x46, 0x70, 0xba, 0xe9, 0xfd, 0xb4, 0xac, 0x96, 0xcd, 0xb1, 0x78,
0x37, 0x8d, 0xe3, 0x21, 0x04, 0xc2, 0xda, 0x55, 0x48, 0x98, 0xdc, 0xc0, 0x70, 0xab, 0xfe, 0x05,
0xc9, 0x1a, 0x4d, 0xc8, 0x39, 0x74, 0xb1, 0x46, 0x6a, 0x94, 0xf3, 0x64, 0x70, 0xcd, 0xc6, 0xc9,
0x15, 0x9c, 0xfd, 0x0a, 0xdf, 0xa3, 0xbb, 0x5d, 0x08, 0xa9, 0xc4, 0x54, 0xe1, 0x04, 0x85, 0xa3,
0x9f, 0xa9, 0x13, 0x18, 0xed, 0x06, 0x6e, 0x8b, 0x6f, 0x4d, 0xa9, 0x15, 0xf9, 0x71, 0xc2, 0xe4,
0x1c, 0xd2, 0xbf, 0x4c, 0x33, 0xa3, 0x1d, 0x6a, 0x97, 0xb5, 0xab, 0xb5, 0x63, 0x27, 0x5f, 0x0c,
0x2e, 0x76, 0x15, 0xaf, 0x3b, 0x0c, 0xa0, 0xdf, 0x10, 0x2e, 0xb7, 0xf7, 0x2d, 0x7a, 0xfc, 0x18,
0x0e, 0xa4, 0x5d, 0x5c, 0xe6, 0xa2, 0x2c, 0x6b, 0xa4, 0x55, 0x13, 0x7e, 0x04, 0xfb, 0xd6, 0xd4,
0x2e, 0xd7, 0x4d, 0x35, 0xc5, 0xda, 0x5f, 0x26, 0x6c, 0x69, 0x3b, 0xb6, 0xf9, 0xac, 0x36, 0x8d,
0x8d, 0x3a, 0xfe, 0x89, 0x03, 0x48, 0xbb, 0x66, 0x83, 0xf6, 0xc4, 0x77, 0xc1, 0x03, 0xfb, 0x64,
0xff, 0xbe, 0x03, 0x00, 0x00, 0xff, 0xff, 0x09, 0x2f, 0x9f, 0xe9, 0x65, 0x02, 0x00, 0x00,
}

View File

@ -1,27 +1,56 @@
// Code generated by protoc-gen-go. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: content_manifest.proto // source: content_manifest.proto
// DO NOT EDIT!
package protobuf package protobuf
import proto "github.com/golang/protobuf/proto" import (
import fmt "fmt" fmt "fmt"
import math "math" proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal var _ = proto.Marshal
var _ = fmt.Errorf var _ = fmt.Errorf
var _ = math.Inf var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package protobuf is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package protobuf to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ContentManifestPayload struct { type ContentManifestPayload struct {
Mappings []*ContentManifestPayload_FileMapping `protobuf:"bytes,1,rep,name=mappings" json:"mappings,omitempty"` Mappings []*ContentManifestPayload_FileMapping `protobuf:"bytes,1,rep,name=mappings" json:"mappings,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestPayload) Reset() { *m = ContentManifestPayload{} } func (m *ContentManifestPayload) Reset() { *m = ContentManifestPayload{} }
func (m *ContentManifestPayload) String() string { return proto.CompactTextString(m) } func (m *ContentManifestPayload) String() string { return proto.CompactTextString(m) }
func (*ContentManifestPayload) ProtoMessage() {} func (*ContentManifestPayload) ProtoMessage() {}
func (*ContentManifestPayload) Descriptor() ([]byte, []int) { return content_manifest_fileDescriptor0, []int{0} } func (*ContentManifestPayload) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{0}
}
func (m *ContentManifestPayload) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestPayload.Unmarshal(m, b)
}
func (m *ContentManifestPayload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestPayload.Marshal(b, m, deterministic)
}
func (m *ContentManifestPayload) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestPayload.Merge(m, src)
}
func (m *ContentManifestPayload) XXX_Size() int {
return xxx_messageInfo_ContentManifestPayload.Size(m)
}
func (m *ContentManifestPayload) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestPayload.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestPayload proto.InternalMessageInfo
func (m *ContentManifestPayload) GetMappings() []*ContentManifestPayload_FileMapping { func (m *ContentManifestPayload) GetMappings() []*ContentManifestPayload_FileMapping {
if m != nil { if m != nil {
@ -38,16 +67,36 @@ type ContentManifestPayload_FileMapping struct {
ShaContent []byte `protobuf:"bytes,5,opt,name=sha_content" json:"sha_content,omitempty"` ShaContent []byte `protobuf:"bytes,5,opt,name=sha_content" json:"sha_content,omitempty"`
Chunks []*ContentManifestPayload_FileMapping_ChunkData `protobuf:"bytes,6,rep,name=chunks" json:"chunks,omitempty"` Chunks []*ContentManifestPayload_FileMapping_ChunkData `protobuf:"bytes,6,rep,name=chunks" json:"chunks,omitempty"`
Linktarget *string `protobuf:"bytes,7,opt,name=linktarget" json:"linktarget,omitempty"` Linktarget *string `protobuf:"bytes,7,opt,name=linktarget" json:"linktarget,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestPayload_FileMapping) Reset() { *m = ContentManifestPayload_FileMapping{} } func (m *ContentManifestPayload_FileMapping) Reset() { *m = ContentManifestPayload_FileMapping{} }
func (m *ContentManifestPayload_FileMapping) String() string { return proto.CompactTextString(m) } func (m *ContentManifestPayload_FileMapping) String() string { return proto.CompactTextString(m) }
func (*ContentManifestPayload_FileMapping) ProtoMessage() {} func (*ContentManifestPayload_FileMapping) ProtoMessage() {}
func (*ContentManifestPayload_FileMapping) Descriptor() ([]byte, []int) { func (*ContentManifestPayload_FileMapping) Descriptor() ([]byte, []int) {
return content_manifest_fileDescriptor0, []int{0, 0} return fileDescriptor_e3cda137a29253ba, []int{0, 0}
} }
func (m *ContentManifestPayload_FileMapping) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestPayload_FileMapping.Unmarshal(m, b)
}
func (m *ContentManifestPayload_FileMapping) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestPayload_FileMapping.Marshal(b, m, deterministic)
}
func (m *ContentManifestPayload_FileMapping) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestPayload_FileMapping.Merge(m, src)
}
func (m *ContentManifestPayload_FileMapping) XXX_Size() int {
return xxx_messageInfo_ContentManifestPayload_FileMapping.Size(m)
}
func (m *ContentManifestPayload_FileMapping) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestPayload_FileMapping.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestPayload_FileMapping proto.InternalMessageInfo
func (m *ContentManifestPayload_FileMapping) GetFilename() string { func (m *ContentManifestPayload_FileMapping) GetFilename() string {
if m != nil && m.Filename != nil { if m != nil && m.Filename != nil {
return *m.Filename return *m.Filename
@ -103,7 +152,9 @@ type ContentManifestPayload_FileMapping_ChunkData struct {
Offset *uint64 `protobuf:"varint,3,opt,name=offset" json:"offset,omitempty"` Offset *uint64 `protobuf:"varint,3,opt,name=offset" json:"offset,omitempty"`
CbOriginal *uint32 `protobuf:"varint,4,opt,name=cb_original" json:"cb_original,omitempty"` CbOriginal *uint32 `protobuf:"varint,4,opt,name=cb_original" json:"cb_original,omitempty"`
CbCompressed *uint32 `protobuf:"varint,5,opt,name=cb_compressed" json:"cb_compressed,omitempty"` CbCompressed *uint32 `protobuf:"varint,5,opt,name=cb_compressed" json:"cb_compressed,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestPayload_FileMapping_ChunkData) Reset() { func (m *ContentManifestPayload_FileMapping_ChunkData) Reset() {
@ -114,9 +165,27 @@ func (m *ContentManifestPayload_FileMapping_ChunkData) String() string {
} }
func (*ContentManifestPayload_FileMapping_ChunkData) ProtoMessage() {} func (*ContentManifestPayload_FileMapping_ChunkData) ProtoMessage() {}
func (*ContentManifestPayload_FileMapping_ChunkData) Descriptor() ([]byte, []int) { func (*ContentManifestPayload_FileMapping_ChunkData) Descriptor() ([]byte, []int) {
return content_manifest_fileDescriptor0, []int{0, 0, 0} return fileDescriptor_e3cda137a29253ba, []int{0, 0, 0}
} }
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.Unmarshal(m, b)
}
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.Marshal(b, m, deterministic)
}
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.Merge(m, src)
}
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_Size() int {
return xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.Size(m)
}
func (m *ContentManifestPayload_FileMapping_ChunkData) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestPayload_FileMapping_ChunkData proto.InternalMessageInfo
func (m *ContentManifestPayload_FileMapping_ChunkData) GetSha() []byte { func (m *ContentManifestPayload_FileMapping_ChunkData) GetSha() []byte {
if m != nil { if m != nil {
return m.Sha return m.Sha
@ -162,13 +231,35 @@ type ContentManifestMetadata struct {
UniqueChunks *uint32 `protobuf:"varint,7,opt,name=unique_chunks" json:"unique_chunks,omitempty"` UniqueChunks *uint32 `protobuf:"varint,7,opt,name=unique_chunks" json:"unique_chunks,omitempty"`
CrcEncrypted *uint32 `protobuf:"varint,8,opt,name=crc_encrypted" json:"crc_encrypted,omitempty"` CrcEncrypted *uint32 `protobuf:"varint,8,opt,name=crc_encrypted" json:"crc_encrypted,omitempty"`
CrcClear *uint32 `protobuf:"varint,9,opt,name=crc_clear" json:"crc_clear,omitempty"` CrcClear *uint32 `protobuf:"varint,9,opt,name=crc_clear" json:"crc_clear,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestMetadata) Reset() { *m = ContentManifestMetadata{} } func (m *ContentManifestMetadata) Reset() { *m = ContentManifestMetadata{} }
func (m *ContentManifestMetadata) String() string { return proto.CompactTextString(m) } func (m *ContentManifestMetadata) String() string { return proto.CompactTextString(m) }
func (*ContentManifestMetadata) ProtoMessage() {} func (*ContentManifestMetadata) ProtoMessage() {}
func (*ContentManifestMetadata) Descriptor() ([]byte, []int) { return content_manifest_fileDescriptor0, []int{1} } func (*ContentManifestMetadata) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{1}
}
func (m *ContentManifestMetadata) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestMetadata.Unmarshal(m, b)
}
func (m *ContentManifestMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestMetadata.Marshal(b, m, deterministic)
}
func (m *ContentManifestMetadata) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestMetadata.Merge(m, src)
}
func (m *ContentManifestMetadata) XXX_Size() int {
return xxx_messageInfo_ContentManifestMetadata.Size(m)
}
func (m *ContentManifestMetadata) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestMetadata.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestMetadata proto.InternalMessageInfo
func (m *ContentManifestMetadata) GetDepotId() uint32 { func (m *ContentManifestMetadata) GetDepotId() uint32 {
if m != nil && m.DepotId != nil { if m != nil && m.DepotId != nil {
@ -235,13 +326,35 @@ func (m *ContentManifestMetadata) GetCrcClear() uint32 {
type ContentManifestSignature struct { type ContentManifestSignature struct {
Signature []byte `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"` Signature []byte `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ContentManifestSignature) Reset() { *m = ContentManifestSignature{} } func (m *ContentManifestSignature) Reset() { *m = ContentManifestSignature{} }
func (m *ContentManifestSignature) String() string { return proto.CompactTextString(m) } func (m *ContentManifestSignature) String() string { return proto.CompactTextString(m) }
func (*ContentManifestSignature) ProtoMessage() {} func (*ContentManifestSignature) ProtoMessage() {}
func (*ContentManifestSignature) Descriptor() ([]byte, []int) { return content_manifest_fileDescriptor0, []int{2} } func (*ContentManifestSignature) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{2}
}
func (m *ContentManifestSignature) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentManifestSignature.Unmarshal(m, b)
}
func (m *ContentManifestSignature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentManifestSignature.Marshal(b, m, deterministic)
}
func (m *ContentManifestSignature) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentManifestSignature.Merge(m, src)
}
func (m *ContentManifestSignature) XXX_Size() int {
return xxx_messageInfo_ContentManifestSignature.Size(m)
}
func (m *ContentManifestSignature) XXX_DiscardUnknown() {
xxx_messageInfo_ContentManifestSignature.DiscardUnknown(m)
}
var xxx_messageInfo_ContentManifestSignature proto.InternalMessageInfo
func (m *ContentManifestSignature) GetSignature() []byte { func (m *ContentManifestSignature) GetSignature() []byte {
if m != nil { if m != nil {
@ -250,40 +363,184 @@ func (m *ContentManifestSignature) GetSignature() []byte {
return nil return nil
} }
type ContentDeltaChunks struct {
DepotId *uint32 `protobuf:"varint,1,opt,name=depot_id" json:"depot_id,omitempty"`
ManifestIdSource *uint64 `protobuf:"varint,2,opt,name=manifest_id_source" json:"manifest_id_source,omitempty"`
ManifestIdTarget *uint64 `protobuf:"varint,3,opt,name=manifest_id_target" json:"manifest_id_target,omitempty"`
DeltaChunks []*ContentDeltaChunks_DeltaChunk `protobuf:"bytes,4,rep,name=deltaChunks" json:"deltaChunks,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ContentDeltaChunks) Reset() { *m = ContentDeltaChunks{} }
func (m *ContentDeltaChunks) String() string { return proto.CompactTextString(m) }
func (*ContentDeltaChunks) ProtoMessage() {}
func (*ContentDeltaChunks) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{3}
}
func (m *ContentDeltaChunks) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentDeltaChunks.Unmarshal(m, b)
}
func (m *ContentDeltaChunks) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentDeltaChunks.Marshal(b, m, deterministic)
}
func (m *ContentDeltaChunks) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentDeltaChunks.Merge(m, src)
}
func (m *ContentDeltaChunks) XXX_Size() int {
return xxx_messageInfo_ContentDeltaChunks.Size(m)
}
func (m *ContentDeltaChunks) XXX_DiscardUnknown() {
xxx_messageInfo_ContentDeltaChunks.DiscardUnknown(m)
}
var xxx_messageInfo_ContentDeltaChunks proto.InternalMessageInfo
func (m *ContentDeltaChunks) GetDepotId() uint32 {
if m != nil && m.DepotId != nil {
return *m.DepotId
}
return 0
}
func (m *ContentDeltaChunks) GetManifestIdSource() uint64 {
if m != nil && m.ManifestIdSource != nil {
return *m.ManifestIdSource
}
return 0
}
func (m *ContentDeltaChunks) GetManifestIdTarget() uint64 {
if m != nil && m.ManifestIdTarget != nil {
return *m.ManifestIdTarget
}
return 0
}
func (m *ContentDeltaChunks) GetDeltaChunks() []*ContentDeltaChunks_DeltaChunk {
if m != nil {
return m.DeltaChunks
}
return nil
}
type ContentDeltaChunks_DeltaChunk struct {
ShaSource []byte `protobuf:"bytes,1,opt,name=sha_source" json:"sha_source,omitempty"`
ShaTarget []byte `protobuf:"bytes,2,opt,name=sha_target" json:"sha_target,omitempty"`
SizeOriginal *uint32 `protobuf:"varint,3,opt,name=size_original" json:"size_original,omitempty"`
PatchMethod *uint32 `protobuf:"varint,4,opt,name=patch_method" json:"patch_method,omitempty"`
Chunk []byte `protobuf:"bytes,5,opt,name=chunk" json:"chunk,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ContentDeltaChunks_DeltaChunk) Reset() { *m = ContentDeltaChunks_DeltaChunk{} }
func (m *ContentDeltaChunks_DeltaChunk) String() string { return proto.CompactTextString(m) }
func (*ContentDeltaChunks_DeltaChunk) ProtoMessage() {}
func (*ContentDeltaChunks_DeltaChunk) Descriptor() ([]byte, []int) {
return fileDescriptor_e3cda137a29253ba, []int{3, 0}
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentDeltaChunks_DeltaChunk.Unmarshal(m, b)
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentDeltaChunks_DeltaChunk.Marshal(b, m, deterministic)
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentDeltaChunks_DeltaChunk.Merge(m, src)
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_Size() int {
return xxx_messageInfo_ContentDeltaChunks_DeltaChunk.Size(m)
}
func (m *ContentDeltaChunks_DeltaChunk) XXX_DiscardUnknown() {
xxx_messageInfo_ContentDeltaChunks_DeltaChunk.DiscardUnknown(m)
}
var xxx_messageInfo_ContentDeltaChunks_DeltaChunk proto.InternalMessageInfo
func (m *ContentDeltaChunks_DeltaChunk) GetShaSource() []byte {
if m != nil {
return m.ShaSource
}
return nil
}
func (m *ContentDeltaChunks_DeltaChunk) GetShaTarget() []byte {
if m != nil {
return m.ShaTarget
}
return nil
}
func (m *ContentDeltaChunks_DeltaChunk) GetSizeOriginal() uint32 {
if m != nil && m.SizeOriginal != nil {
return *m.SizeOriginal
}
return 0
}
func (m *ContentDeltaChunks_DeltaChunk) GetPatchMethod() uint32 {
if m != nil && m.PatchMethod != nil {
return *m.PatchMethod
}
return 0
}
func (m *ContentDeltaChunks_DeltaChunk) GetChunk() []byte {
if m != nil {
return m.Chunk
}
return nil
}
func init() { func init() {
proto.RegisterType((*ContentManifestPayload)(nil), "ContentManifestPayload") proto.RegisterType((*ContentManifestPayload)(nil), "ContentManifestPayload")
proto.RegisterType((*ContentManifestPayload_FileMapping)(nil), "ContentManifestPayload.FileMapping") proto.RegisterType((*ContentManifestPayload_FileMapping)(nil), "ContentManifestPayload.FileMapping")
proto.RegisterType((*ContentManifestPayload_FileMapping_ChunkData)(nil), "ContentManifestPayload.FileMapping.ChunkData") proto.RegisterType((*ContentManifestPayload_FileMapping_ChunkData)(nil), "ContentManifestPayload.FileMapping.ChunkData")
proto.RegisterType((*ContentManifestMetadata)(nil), "ContentManifestMetadata") proto.RegisterType((*ContentManifestMetadata)(nil), "ContentManifestMetadata")
proto.RegisterType((*ContentManifestSignature)(nil), "ContentManifestSignature") proto.RegisterType((*ContentManifestSignature)(nil), "ContentManifestSignature")
proto.RegisterType((*ContentDeltaChunks)(nil), "ContentDeltaChunks")
proto.RegisterType((*ContentDeltaChunks_DeltaChunk)(nil), "ContentDeltaChunks.DeltaChunk")
} }
var content_manifest_fileDescriptor0 = []byte{ func init() { proto.RegisterFile("content_manifest.proto", fileDescriptor_e3cda137a29253ba) }
// 409 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x91, 0xbd, 0x8e, 0xd4, 0x30, var fileDescriptor_e3cda137a29253ba = []byte{
0x14, 0x85, 0xc9, 0xfc, 0x26, 0x37, 0x09, 0x5a, 0xbc, 0xb0, 0x58, 0x43, 0x83, 0x96, 0x66, 0x9b, // 508 bytes of a gzipped FileDescriptorProto
0x4d, 0x81, 0x44, 0x49, 0xc3, 0x22, 0x44, 0x33, 0x12, 0x12, 0x0f, 0x10, 0x5d, 0x1c, 0x27, 0x6b, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcd, 0x8e, 0xd3, 0x30,
0x4d, 0x62, 0x07, 0xdb, 0x29, 0x96, 0x8a, 0x17, 0xe1, 0x0d, 0x91, 0x78, 0x05, 0x6c, 0x27, 0x99, 0x10, 0xc7, 0x49, 0xbf, 0x3b, 0x6d, 0x50, 0xf1, 0xb2, 0x8b, 0x55, 0x24, 0x54, 0x95, 0x4b, 0x2f,
0x1d, 0x8d, 0x28, 0x28, 0xcf, 0xf1, 0xb5, 0xcf, 0x77, 0x8f, 0xe1, 0x8a, 0x29, 0x69, 0xb9, 0xb4, 0x9b, 0x03, 0x88, 0x23, 0x17, 0x76, 0x85, 0xb8, 0x54, 0x42, 0xe2, 0x01, 0x2c, 0xd7, 0x76, 0x53,
0x65, 0x87, 0x52, 0xd4, 0xdc, 0xd8, 0xa2, 0xd7, 0xca, 0xaa, 0xeb, 0x3f, 0x0b, 0xb8, 0xba, 0x1b, 0xab, 0x89, 0x1d, 0x6c, 0xe7, 0xb0, 0x9c, 0xb8, 0xf0, 0x18, 0xbc, 0x21, 0x12, 0xaf, 0x80, 0xec,
0x8f, 0xf6, 0xd3, 0xc9, 0x17, 0x7c, 0x68, 0x15, 0x56, 0xe4, 0x1d, 0xc4, 0x1d, 0xf6, 0xbd, 0x90, 0x38, 0x4d, 0x55, 0xf6, 0xb0, 0xb7, 0xcc, 0x47, 0x3c, 0xbf, 0xf9, 0xcf, 0x1f, 0x6e, 0x98, 0x56,
0x8d, 0xa1, 0xd1, 0xeb, 0xe5, 0x4d, 0xfa, 0xf6, 0x4d, 0xf1, 0xef, 0xd1, 0xe2, 0x93, 0x68, 0xf9, 0x4e, 0x28, 0x47, 0x4a, 0xaa, 0xe4, 0x5e, 0x58, 0x97, 0x55, 0x46, 0x3b, 0xbd, 0xfe, 0xdb, 0x83,
0x7e, 0x9c, 0xdd, 0xfd, 0x5a, 0x40, 0x7a, 0xa2, 0xc9, 0x05, 0xc4, 0xb5, 0x93, 0x12, 0x3b, 0xee, 0x9b, 0xbb, 0xa6, 0xb4, 0x8d, 0x95, 0xaf, 0xf4, 0xa1, 0xd0, 0x94, 0xa3, 0x0f, 0x30, 0x29, 0x69,
0x9e, 0x89, 0x6e, 0x12, 0x92, 0xc1, 0xca, 0x88, 0x1f, 0x9c, 0x2e, 0x9c, 0x5a, 0x91, 0x1c, 0xd6, 0x55, 0x49, 0x95, 0x5b, 0x9c, 0xac, 0xfa, 0x9b, 0xd9, 0xbb, 0xb7, 0xd9, 0xe3, 0xad, 0xd9, 0x67,
0x75, 0x8b, 0x2e, 0x63, 0xe9, 0x64, 0x4e, 0x9e, 0x43, 0x66, 0xee, 0xb1, 0x3c, 0x5e, 0x59, 0x39, 0x59, 0x88, 0x6d, 0xd3, 0xbb, 0xfc, 0xdd, 0x83, 0xd9, 0x59, 0x8c, 0x16, 0x30, 0xd9, 0xcb, 0x42,
0x37, 0x23, 0x97, 0x90, 0x7a, 0x77, 0x5a, 0x82, 0xae, 0x83, 0xf9, 0x1e, 0x36, 0xec, 0x7e, 0x90, 0x28, 0x5a, 0x0a, 0x9c, 0xac, 0x92, 0xcd, 0x14, 0xcd, 0x61, 0x60, 0xe5, 0x0f, 0x81, 0x7b, 0xab,
0x07, 0x43, 0x37, 0x01, 0xef, 0xf6, 0x3f, 0xf0, 0x8a, 0x3b, 0x7f, 0xe3, 0x23, 0x5a, 0x24, 0x04, 0x64, 0x33, 0x40, 0x29, 0x0c, 0xf7, 0x05, 0xcd, 0x2d, 0xee, 0xaf, 0x92, 0x4d, 0x8a, 0x5e, 0xc2,
0xa0, 0x15, 0xf2, 0x60, 0x51, 0x37, 0xdc, 0xd2, 0xad, 0x47, 0xdb, 0x21, 0x24, 0x8f, 0x03, 0x29, 0xdc, 0x1e, 0x28, 0x39, 0xfd, 0x32, 0x58, 0x25, 0x9b, 0x39, 0xba, 0x82, 0x99, 0xcf, 0xc6, 0x25,
0x2c, 0x5d, 0x68, 0x80, 0xce, 0xbc, 0x60, 0x9a, 0x05, 0xe6, 0x2d, 0x79, 0x0a, 0x1b, 0x55, 0xd7, 0xf0, 0x30, 0x24, 0x3f, 0xc2, 0x88, 0x1d, 0x6a, 0x75, 0xb4, 0x78, 0x14, 0xf0, 0x6e, 0x9f, 0x80,
0xc6, 0x5d, 0x5b, 0x86, 0x1d, 0x1c, 0x1e, 0xfb, 0x56, 0x2a, 0x2d, 0x1a, 0x21, 0xb1, 0x0d, 0xcc, 0x97, 0xdd, 0xf9, 0x3f, 0xee, 0xa9, 0xa3, 0x08, 0x01, 0x14, 0x52, 0x1d, 0x1d, 0x35, 0xb9, 0x70,
0x39, 0x79, 0x01, 0xb9, 0x33, 0x99, 0xea, 0x7a, 0xcd, 0x8d, 0xe1, 0x55, 0xa0, 0xce, 0xaf, 0x7f, 0x78, 0xec, 0xd1, 0x96, 0x14, 0xa6, 0x5d, 0xc3, 0x0c, 0xfa, 0xf6, 0x40, 0x03, 0xf4, 0xdc, 0x07,
0x47, 0xf0, 0xf2, 0x8c, 0x73, 0xcf, 0x2d, 0x56, 0x3e, 0xd1, 0x75, 0x55, 0xf1, 0x5e, 0xd9, 0x52, 0xcc, 0xb0, 0xc0, 0x3c, 0x46, 0xcf, 0x61, 0xa4, 0xf7, 0x7b, 0x2b, 0x5c, 0x80, 0x1e, 0x78, 0x3c,
0x54, 0x21, 0x36, 0xd4, 0xd1, 0x88, 0xea, 0xf8, 0x6b, 0x53, 0x67, 0xfe, 0x69, 0xcd, 0xd1, 0x0a, 0xb6, 0x23, 0xda, 0xc8, 0x5c, 0x2a, 0x5a, 0x04, 0xe6, 0x14, 0x5d, 0x43, 0xca, 0x76, 0x84, 0xe9,
0x25, 0x4b, 0x2b, 0x5c, 0x4b, 0x63, 0x77, 0xaf, 0xe0, 0x72, 0xee, 0xcd, 0x94, 0x5c, 0x32, 0xfd, 0xb2, 0x32, 0xc2, 0x5a, 0xc1, 0x03, 0x75, 0xba, 0xfe, 0x93, 0xc0, 0xab, 0x0b, 0xce, 0xad, 0x70,
0xd0, 0x5b, 0x97, 0xeb, 0x71, 0x62, 0x42, 0xe1, 0xc2, 0xe1, 0x54, 0xc2, 0x1c, 0x1e, 0x41, 0xd7, 0x94, 0xfb, 0x89, 0x0b, 0x98, 0x70, 0x51, 0x69, 0x47, 0x24, 0x0f, 0x63, 0x83, 0x1c, 0xb9, 0xe4,
0xe1, 0xb5, 0x1d, 0x90, 0xf9, 0xe4, 0x84, 0x76, 0x33, 0x27, 0x0d, 0x52, 0x7c, 0x1f, 0x78, 0x39, 0xa7, 0xab, 0x45, 0xcd, 0xfc, 0xd3, 0x46, 0x50, 0x27, 0xb5, 0x22, 0x4e, 0x96, 0x22, 0x6a, 0xf7,
0x55, 0xbd, 0x3d, 0xee, 0xa6, 0xd9, 0x49, 0x46, 0x1c, 0xec, 0x67, 0x90, 0x78, 0x9b, 0xb5, 0x1c, 0x1a, 0xae, 0x5a, 0xdd, 0x2c, 0x11, 0x8a, 0x99, 0x87, 0xca, 0x09, 0x1e, 0x70, 0x26, 0x08, 0xc3,
0x35, 0x4d, 0xc2, 0xba, 0xb7, 0x40, 0xcf, 0xb6, 0xfd, 0x2a, 0x1a, 0x89, 0x76, 0xd0, 0xdc, 0x8f, 0x82, 0xed, 0x08, 0x97, 0xf6, 0xd8, 0x81, 0x0e, 0xc3, 0x6b, 0x4b, 0x40, 0x6d, 0xe5, 0x8c, 0x76,
0x9b, 0x59, 0x8c, 0x35, 0x7f, 0x58, 0x7f, 0x8e, 0x7e, 0x46, 0x4f, 0xfe, 0x06, 0x00, 0x00, 0xff, 0xd4, 0x4e, 0xaa, 0x95, 0xfc, 0x5e, 0x0b, 0x12, 0xa5, 0x1e, 0x9f, 0x76, 0x33, 0xec, 0x6c, 0xc6,
0xff, 0xc6, 0x87, 0xdb, 0xe6, 0xaf, 0x02, 0x00, 0x00, 0x24, 0xa4, 0x5f, 0xc0, 0xd4, 0xa7, 0x59, 0x21, 0xa8, 0xc1, 0xd3, 0xb0, 0xee, 0x2d, 0xe0, 0x8b,
0x6d, 0xbf, 0xc9, 0x5c, 0x51, 0x57, 0x1b, 0xe1, 0xdb, 0x6d, 0x1b, 0x34, 0x32, 0xaf, 0x7f, 0xf5,
0x00, 0xc5, 0xfe, 0x7b, 0x51, 0x38, 0x1a, 0xae, 0x61, 0x1f, 0x11, 0x66, 0x09, 0xa8, 0x15, 0x85,
0x48, 0x4e, 0xac, 0xae, 0x0d, 0x6b, 0x2d, 0x75, 0x51, 0x8b, 0x17, 0x6e, 0x4e, 0xf5, 0x1e, 0x66,
0xbc, 0x7b, 0x18, 0x0f, 0x82, 0x73, 0xde, 0x64, 0xff, 0xcf, 0xcc, 0xba, 0xef, 0x65, 0x05, 0xd0,
0x45, 0xde, 0x38, 0xde, 0x8c, 0x71, 0x64, 0x63, 0x8f, 0x98, 0x8b, 0xa3, 0x7a, 0x21, 0x77, 0x0d,
0xa9, 0xf7, 0x79, 0x27, 0xf7, 0xc9, 0xe1, 0x15, 0x75, 0xec, 0x40, 0x4a, 0xe1, 0x0e, 0x9a, 0x47,
0xb7, 0xa4, 0x30, 0x0c, 0x0a, 0x37, 0xde, 0xfe, 0x34, 0xfc, 0x92, 0xfc, 0x4c, 0x9e, 0xfd, 0x0b,
0x00, 0x00, 0xff, 0xff, 0x00, 0x92, 0x22, 0xd7, 0xb7, 0x03, 0x00, 0x00,
} }

File diff suppressed because it is too large Load Diff

View File

@ -723,7 +723,7 @@ func (d *MsgClientNewLoginKeyAccepted) Deserialize(r io.Reader) error {
const ( const (
MsgClientLogon_ObfuscationMask uint32 = 0xBAADF00D MsgClientLogon_ObfuscationMask uint32 = 0xBAADF00D
MsgClientLogon_CurrentProtocol uint32 = 65579 MsgClientLogon_CurrentProtocol uint32 = 65580
MsgClientLogon_ProtocolVerMajorMask uint32 = 0xFFFF0000 MsgClientLogon_ProtocolVerMajorMask uint32 = 0xFFFF0000
MsgClientLogon_ProtocolVerMinorMask uint32 = 0xFFFF MsgClientLogon_ProtocolVerMinorMask uint32 = 0xFFFF
MsgClientLogon_ProtocolVerMinorMinGameServers uint16 = 4 MsgClientLogon_ProtocolVerMinorMinGameServers uint16 = 4
@ -744,7 +744,11 @@ const (
MsgClientLogon_ProtocolVerMinorMinForMachineAuth uint16 = 33 MsgClientLogon_ProtocolVerMinorMinForMachineAuth uint16 = 33
MsgClientLogon_ProtocolVerMinorMinForSessionIDLastAnon uint16 = 36 MsgClientLogon_ProtocolVerMinorMinForSessionIDLastAnon uint16 = 36
MsgClientLogon_ProtocolVerMinorMinForEnhancedAppList uint16 = 40 MsgClientLogon_ProtocolVerMinorMinForEnhancedAppList uint16 = 40
MsgClientLogon_ProtocolVerMinorMinForSteamGuardNotificationUI uint16 = 41
MsgClientLogon_ProtocolVerMinorMinForProtoBufServiceModuleCalls uint16 = 42
MsgClientLogon_ProtocolVerMinorMinForGzipMultiMessages uint16 = 43 MsgClientLogon_ProtocolVerMinorMinForGzipMultiMessages uint16 = 43
MsgClientLogon_ProtocolVerMinorMinForNewVoiceCallAuthorize uint16 = 44
MsgClientLogon_ProtocolVerMinorMinForClientInstanceIDs uint16 = 44
) )
type MsgClientLogon struct { type MsgClientLogon struct {
@ -1976,64 +1980,6 @@ func (d *MsgClientChatRoomInfo) Deserialize(r io.Reader) error {
return err return err
} }
type MsgClientGetNumberOfCurrentPlayers struct {
GameID uint64
}
func NewMsgClientGetNumberOfCurrentPlayers() *MsgClientGetNumberOfCurrentPlayers {
return &MsgClientGetNumberOfCurrentPlayers{}
}
func (d *MsgClientGetNumberOfCurrentPlayers) GetEMsg() EMsg {
return EMsg_ClientGetNumberOfCurrentPlayers
}
func (d *MsgClientGetNumberOfCurrentPlayers) Serialize(w io.Writer) error {
var err error
err = binary.Write(w, binary.LittleEndian, d.GameID)
return err
}
func (d *MsgClientGetNumberOfCurrentPlayers) Deserialize(r io.Reader) error {
var err error
d.GameID, err = rwu.ReadUint64(r)
return err
}
type MsgClientGetNumberOfCurrentPlayersResponse struct {
Result EResult
NumPlayers uint32
}
func NewMsgClientGetNumberOfCurrentPlayersResponse() *MsgClientGetNumberOfCurrentPlayersResponse {
return &MsgClientGetNumberOfCurrentPlayersResponse{}
}
func (d *MsgClientGetNumberOfCurrentPlayersResponse) GetEMsg() EMsg {
return EMsg_ClientGetNumberOfCurrentPlayersResponse
}
func (d *MsgClientGetNumberOfCurrentPlayersResponse) Serialize(w io.Writer) error {
var err error
err = binary.Write(w, binary.LittleEndian, d.Result)
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, d.NumPlayers)
return err
}
func (d *MsgClientGetNumberOfCurrentPlayersResponse) Deserialize(r io.Reader) error {
var err error
t0, err := rwu.ReadInt32(r)
if err != nil {
return err
}
d.Result = EResult(t0)
d.NumPlayers, err = rwu.ReadUint32(r)
return err
}
type MsgClientSetIgnoreFriend struct { type MsgClientSetIgnoreFriend struct {
MySteamId steamid.SteamId MySteamId steamid.SteamId
SteamIdFriend steamid.SteamId SteamIdFriend steamid.SteamId
@ -2079,7 +2025,7 @@ func (d *MsgClientSetIgnoreFriend) Deserialize(r io.Reader) error {
} }
type MsgClientSetIgnoreFriendResponse struct { type MsgClientSetIgnoreFriendResponse struct {
Unknown uint64 FriendId steamid.SteamId
Result EResult Result EResult
} }
@ -2093,7 +2039,7 @@ func (d *MsgClientSetIgnoreFriendResponse) GetEMsg() EMsg {
func (d *MsgClientSetIgnoreFriendResponse) Serialize(w io.Writer) error { func (d *MsgClientSetIgnoreFriendResponse) Serialize(w io.Writer) error {
var err error var err error
err = binary.Write(w, binary.LittleEndian, d.Unknown) err = binary.Write(w, binary.LittleEndian, d.FriendId)
if err != nil { if err != nil {
return err return err
} }
@ -2103,12 +2049,13 @@ func (d *MsgClientSetIgnoreFriendResponse) Serialize(w io.Writer) error {
func (d *MsgClientSetIgnoreFriendResponse) Deserialize(r io.Reader) error { func (d *MsgClientSetIgnoreFriendResponse) Deserialize(r io.Reader) error {
var err error var err error
d.Unknown, err = rwu.ReadUint64(r) t0, err := rwu.ReadUint64(r)
if err != nil { if err != nil {
return err return err
} }
t0, err := rwu.ReadInt32(r) d.FriendId = steamid.SteamId(t0)
d.Result = EResult(t0) t1, err := rwu.ReadInt32(r)
d.Result = EResult(t1)
return err return err
} }
@ -2226,73 +2173,6 @@ func (d *MsgClientLogOnResponse) Deserialize(r io.Reader) error {
return err return err
} }
type MsgClientSendGuestPass struct {
GiftId uint64
GiftType uint8
AccountId uint32
}
func NewMsgClientSendGuestPass() *MsgClientSendGuestPass {
return &MsgClientSendGuestPass{}
}
func (d *MsgClientSendGuestPass) GetEMsg() EMsg {
return EMsg_ClientSendGuestPass
}
func (d *MsgClientSendGuestPass) Serialize(w io.Writer) error {
var err error
err = binary.Write(w, binary.LittleEndian, d.GiftId)
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, d.GiftType)
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, d.AccountId)
return err
}
func (d *MsgClientSendGuestPass) Deserialize(r io.Reader) error {
var err error
d.GiftId, err = rwu.ReadUint64(r)
if err != nil {
return err
}
d.GiftType, err = rwu.ReadUint8(r)
if err != nil {
return err
}
d.AccountId, err = rwu.ReadUint32(r)
return err
}
type MsgClientSendGuestPassResponse struct {
Result EResult
}
func NewMsgClientSendGuestPassResponse() *MsgClientSendGuestPassResponse {
return &MsgClientSendGuestPassResponse{}
}
func (d *MsgClientSendGuestPassResponse) GetEMsg() EMsg {
return EMsg_ClientSendGuestPassResponse
}
func (d *MsgClientSendGuestPassResponse) Serialize(w io.Writer) error {
var err error
err = binary.Write(w, binary.LittleEndian, d.Result)
return err
}
func (d *MsgClientSendGuestPassResponse) Deserialize(r io.Reader) error {
var err error
t0, err := rwu.ReadInt32(r)
d.Result = EResult(t0)
return err
}
type MsgClientServerUnavailable struct { type MsgClientServerUnavailable struct {
JobidSent uint64 JobidSent uint64
EMsgSent uint32 EMsgSent uint32

View File

@ -8,135 +8,116 @@ import (
) )
// CMServers contains a list of worlwide servers // CMServers contains a list of worlwide servers
var CMServers = [][]string{ var CMServers = []string{
{ // North American Servers "155.133.248.52:27018",
// Chicago "162.254.197.40:27018",
"162.254.193.44:27018", "162.254.197.180:27019",
"162.254.193.44:27019", "155.133.248.50:27019",
"162.254.193.44:27020", "162.254.197.181:27017",
"162.254.193.44:27021", "162.254.197.42:27019",
"162.254.193.45:27017", "162.254.197.180:27017",
"162.254.193.45:27018", "162.254.197.181:27018",
"162.254.193.45:27019", "162.254.197.42:27018",
"162.254.193.45:27021", "155.133.248.50:27017",
"162.254.193.46:27017", "155.133.248.52:27019",
"162.254.193.46:27018", "155.133.248.51:27019",
"162.254.193.46:27019", "155.133.248.53:27019",
"162.254.193.46:27020", "155.133.248.51:27017",
"162.254.193.46:27021", "155.133.248.53:27017",
"162.254.193.47:27019", "155.133.248.52:27017",
"162.254.193.47:27020", "155.133.248.50:27018",
"162.254.197.180:27018",
// Ashburn "162.254.197.40:27017",
"208.78.164.9:27017", "162.254.197.40:27019",
"208.78.164.9:27018", "162.254.197.42:27017",
"208.78.164.9:27019", "162.254.197.181:27019",
"208.78.164.10:27017", "155.133.248.53:27018",
"208.78.164.10:27018", "155.133.248.51:27018",
"208.78.164.10:27019", "146.66.152.11:27017",
"208.78.164.11:27017", "146.66.152.10:27019",
"208.78.164.11:27018",
"208.78.164.11:27019",
"208.78.164.12:27017",
"208.78.164.12:27018",
"208.78.164.12:27019",
"208.78.164.13:27017",
"208.78.164.13:27018",
"208.78.164.13:27019",
"208.78.164.14:27017",
"208.78.164.14:27018",
"208.78.164.14:27019",
},
{ // Europe Servers
// Luxembourg
"146.66.152.10:27017", "146.66.152.10:27017",
"146.66.152.10:27018", "146.66.152.10:27018",
"146.66.152.10:27019",
"146.66.152.10:27020",
"146.66.152.11:27017",
"146.66.152.11:27018",
"146.66.152.11:27019", "146.66.152.11:27019",
"146.66.152.11:27020", "162.254.198.133:27017",
"162.254.198.133:27018",
// Poland "162.254.198.130:27019",
"155.133.242.8:27017", "162.254.198.130:27017",
"155.133.242.8:27018", "162.254.198.132:27018",
"155.133.242.8:27019", "162.254.198.130:27018",
"155.133.242.8:27020", "162.254.198.132:27017",
"155.133.242.9:27017", "162.254.198.132:27019",
"155.133.242.9:27018", "162.254.198.131:27019",
"155.133.242.9:27019", "162.254.198.131:27017",
"155.133.242.9:27020", "146.66.152.11:27018",
"162.254.198.131:27018",
// Vienna "162.254.198.133:27019",
"146.66.155.8:27017", "185.25.182.77:27017",
"146.66.155.8:27018", "185.25.182.76:27018",
"146.66.155.8:27019", "185.25.182.76:27019",
"146.66.155.8:27020", "185.25.182.77:27018",
"185.25.182.10:27017", "185.25.182.76:27017",
"185.25.182.10:27018", "185.25.182.77:27019",
"185.25.182.10:27019", "162.254.196.67:27019",
"185.25.182.10:27020", "162.254.196.67:27018",
"162.254.196.83:27018",
// London "162.254.196.84:27018",
"162.254.196.40:27017", "162.254.196.83:27017",
"162.254.196.40:27018", "162.254.196.84:27017",
"162.254.196.40:27019", "162.254.196.68:27019",
"162.254.196.40:27020", "162.254.196.68:27017",
"162.254.196.40:27021", "162.254.196.84:27019",
"162.254.196.41:27017", "162.254.196.67:27017",
"162.254.196.41:27018", "162.254.196.83:27019",
"162.254.196.41:27019", "162.254.196.68:27018",
"162.254.196.41:27020", "146.66.155.101:27017",
"162.254.196.41:27021", "146.66.155.101:27018",
"162.254.196.42:27017", "146.66.155.100:27017",
"162.254.196.42:27018", "146.66.155.100:27018",
"162.254.196.42:27019", "146.66.155.101:27019",
"162.254.196.42:27020", "146.66.155.100:27019",
"162.254.196.42:27021", "155.133.230.50:27017",
"162.254.196.43:27017", "155.133.230.34:27018",
"162.254.196.43:27018", "155.133.230.34:27017",
"162.254.196.43:27019", "155.133.230.50:27019",
"162.254.196.43:27020", "155.133.230.34:27019",
"162.254.196.43:27021", "155.133.230.50:27018",
"162.254.192.100:27017",
// Stockholm "162.254.192.108:27017",
"185.25.180.14:27017", "155.133.246.68:27017",
"185.25.180.14:27018", "155.133.246.68:27018",
"185.25.180.14:27019", "155.133.246.68:27019",
"185.25.180.14:27020", "155.133.246.69:27019",
"185.25.180.15:27017", "155.133.246.69:27017",
"185.25.180.15:27018", "155.133.246.69:27018",
"185.25.180.15:27019", "162.254.192.108:27018",
"185.25.180.15:27020", "162.254.192.101:27018",
}, "162.254.192.101:27019",
"162.254.192.109:27018",
"162.254.192.100:27018",
"162.254.192.109:27017",
"162.254.192.109:27019",
"162.254.192.108:27019",
"162.254.192.101:27017",
"162.254.192.100:27019",
"162.254.193.46:27019",
"162.254.193.6:27018",
"162.254.193.47:27018",
"162.254.193.6:27019",
"162.254.193.7:27018",
"162.254.193.7:27017",
"162.254.193.7:27019",
"162.254.193.47:27017",
"162.254.193.47:27019",
"162.254.193.46:27018",
} }
// GetRandomCM returns back a random server anywhere // GetRandomCM returns a random server from a built-in IP list.
//
// Prefer Client.Connect(), which uses IPs from the Steam Directory,
// which is always more up-to-date.
func GetRandomCM() *netutil.PortAddr { func GetRandomCM() *netutil.PortAddr {
rng := rand.New(rand.NewSource(time.Now().UnixNano())) rng := rand.New(rand.NewSource(time.Now().UnixNano()))
servers := append(CMServers[0], CMServers[1]...) addr := netutil.ParsePortAddr(CMServers[rng.Int31n(int32(len(CMServers)))])
addr := netutil.ParsePortAddr(servers[rng.Int31n(int32(len(servers)))])
if addr == nil {
panic("invalid address in CMServers slice")
}
return addr
}
// GetRandomNorthAmericaCM returns back a random server in north america
func GetRandomNorthAmericaCM() *netutil.PortAddr {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
addr := netutil.ParsePortAddr(CMServers[0][rng.Int31n(int32(len(CMServers[0])))])
if addr == nil {
panic("invalid address in CMServers slice")
}
return addr
}
// GetRandomEuropeCM returns back a random server in europe
func GetRandomEuropeCM() *netutil.PortAddr {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
addr := netutil.ParsePortAddr(CMServers[1][rng.Int31n(int32(len(CMServers[1])))])
if addr == nil { if addr == nil {
panic("invalid address in CMServers slice") panic("invalid address in CMServers slice")
} }

View File

@ -3,7 +3,10 @@ package steam
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/hex" "io"
"sync"
"time"
. "github.com/Philipp15b/go-steam/protocol" . "github.com/Philipp15b/go-steam/protocol"
. "github.com/Philipp15b/go-steam/protocol/protobuf" . "github.com/Philipp15b/go-steam/protocol/protobuf"
. "github.com/Philipp15b/go-steam/protocol/steamlang" . "github.com/Philipp15b/go-steam/protocol/steamlang"
@ -11,9 +14,6 @@ import (
"github.com/Philipp15b/go-steam/socialcache" "github.com/Philipp15b/go-steam/socialcache"
. "github.com/Philipp15b/go-steam/steamid" . "github.com/Philipp15b/go-steam/steamid"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"io"
"sync"
"time"
) )
// Provides access to social aspects of Steam. // Provides access to social aspects of Steam.
@ -21,7 +21,7 @@ type Social struct {
mutex sync.RWMutex mutex sync.RWMutex
name string name string
avatar string avatar []byte
personaState EPersonaState personaState EPersonaState
Friends *socialcache.FriendsList Friends *socialcache.FriendsList
@ -41,7 +41,7 @@ func newSocial(client *Client) *Social {
} }
// Gets the local user's avatar // Gets the local user's avatar
func (s *Social) GetAvatar() string { func (s *Social) GetAvatar() []byte {
s.mutex.RLock() s.mutex.RLock()
defer s.mutex.RUnlock() defer s.mutex.RUnlock()
return s.avatar return s.avatar
@ -156,7 +156,7 @@ func (s *Social) RequestProfileInfo(id SteamId) {
// Requests all offline messages and marks them as read // Requests all offline messages and marks them as read
func (s *Social) RequestOfflineMessages() { func (s *Social) RequestOfflineMessages() {
s.client.Write(NewClientMsgProtobuf(EMsg_ClientFSGetFriendMessageHistoryForOfflineMessages, &CMsgClientFSGetFriendMessageHistoryForOfflineMessages{})) s.client.Write(NewClientMsgProtobuf(EMsg_ClientChatGetFriendMessageHistoryForOfflineMessages, &CMsgClientChatGetFriendMessageHistoryForOfflineMessages{}))
} }
// Attempts to join a chat room // Attempts to join a chat room
@ -307,7 +307,7 @@ func (s *Social) handlePersonaState(packet *Packet) {
if friend.GetPlayerName() != "" { if friend.GetPlayerName() != "" {
s.name = friend.GetPlayerName() s.name = friend.GetPlayerName()
} }
avatar := hex.EncodeToString(friend.GetAvatarHash()) avatar := friend.GetAvatarHash()
if ValidAvatar(avatar) { if ValidAvatar(avatar) {
s.avatar = avatar s.avatar = avatar
} }
@ -319,7 +319,7 @@ func (s *Social) handlePersonaState(packet *Packet) {
} }
} }
if (flags & EClientPersonaStateFlag_Presence) == EClientPersonaStateFlag_Presence { if (flags & EClientPersonaStateFlag_Presence) == EClientPersonaStateFlag_Presence {
avatar := hex.EncodeToString(friend.GetAvatarHash()) avatar := friend.GetAvatarHash()
if ValidAvatar(avatar) { if ValidAvatar(avatar) {
s.Friends.SetAvatar(id, avatar) s.Friends.SetAvatar(id, avatar)
} }
@ -338,7 +338,7 @@ func (s *Social) handlePersonaState(packet *Packet) {
} }
} }
if (flags & EClientPersonaStateFlag_Presence) == EClientPersonaStateFlag_Presence { if (flags & EClientPersonaStateFlag_Presence) == EClientPersonaStateFlag_Presence {
avatar := hex.EncodeToString(friend.GetAvatarHash()) avatar := friend.GetAvatarHash()
if ValidAvatar(avatar) { if ValidAvatar(avatar) {
s.Groups.SetAvatar(id, avatar) s.Groups.SetAvatar(id, avatar)
} }
@ -358,7 +358,7 @@ func (s *Social) handlePersonaState(packet *Packet) {
SourceSteamId: SteamId(friend.GetSteamidSource()), SourceSteamId: SteamId(friend.GetSteamidSource()),
GameDataBlob: friend.GetGameDataBlob(), GameDataBlob: friend.GetGameDataBlob(),
Name: friend.GetPlayerName(), Name: friend.GetPlayerName(),
Avatar: hex.EncodeToString(friend.GetAvatarHash()), Avatar: friend.GetAvatarHash(),
LastLogOff: friend.GetLastLogoff(), LastLogOff: friend.GetLastLogoff(),
LastLogOn: friend.GetLastLogon(), LastLogOn: friend.GetLastLogon(),
ClanRank: friend.GetClanRank(), ClanRank: friend.GetClanRank(),
@ -366,8 +366,6 @@ func (s *Social) handlePersonaState(packet *Packet) {
OnlineSessionInstances: friend.GetOnlineSessionInstances(), OnlineSessionInstances: friend.GetOnlineSessionInstances(),
PublishedSessionId: friend.GetPublishedInstanceId(), PublishedSessionId: friend.GetPublishedInstanceId(),
PersonaSetByUser: friend.GetPersonaSetByUser(), PersonaSetByUser: friend.GetPersonaSetByUser(),
FacebookName: friend.GetFacebookName(),
FacebookId: friend.GetFacebookId(),
}) })
} }
} }
@ -376,10 +374,10 @@ func (s *Social) handleClanState(packet *Packet) {
body := new(CMsgClientClanState) body := new(CMsgClientClanState)
packet.ReadProtoMsg(body) packet.ReadProtoMsg(body)
var name string var name string
var avatar string var avatar []byte
if body.GetNameInfo() != nil { if body.GetNameInfo() != nil {
name = body.GetNameInfo().GetClanName() name = body.GetNameInfo().GetClanName()
avatar = hex.EncodeToString(body.GetNameInfo().GetShaAvatar()) avatar = body.GetNameInfo().GetShaAvatar()
} }
var totalCount, onlineCount, chattingCount, ingameCount uint32 var totalCount, onlineCount, chattingCount, ingameCount uint32
if body.GetUserCounts() != nil { if body.GetUserCounts() != nil {
@ -408,18 +406,13 @@ func (s *Social) handleClanState(packet *Packet) {
JustPosted: announce.GetJustPosted(), JustPosted: announce.GetJustPosted(),
}) })
} }
flags := EClientPersonaStateFlag(body.GetMUnStatusFlags())
//Add stuff to group //Add stuff to group
clanid := SteamId(body.GetSteamidClan()) clanid := SteamId(body.GetSteamidClan())
if (flags & EClientPersonaStateFlag_PlayerName) == EClientPersonaStateFlag_PlayerName { if body.NameInfo != nil {
if name != "" { info := body.NameInfo
s.Groups.SetName(clanid, name) s.Groups.SetName(clanid, info.GetClanName())
} s.Groups.SetAvatar(clanid, info.GetShaAvatar())
}
if (flags & EClientPersonaStateFlag_Presence) == EClientPersonaStateFlag_Presence {
if ValidAvatar(avatar) {
s.Groups.SetAvatar(clanid, avatar)
}
} }
if body.GetUserCounts() != nil { if body.GetUserCounts() != nil {
s.Groups.SetMemberTotalCount(clanid, totalCount) s.Groups.SetMemberTotalCount(clanid, totalCount)
@ -428,8 +421,7 @@ func (s *Social) handleClanState(packet *Packet) {
s.Groups.SetMemberInGameCount(clanid, ingameCount) s.Groups.SetMemberInGameCount(clanid, ingameCount)
} }
s.client.Emit(&ClanStateEvent{ s.client.Emit(&ClanStateEvent{
ClandId: clanid, ClanId: clanid,
StateFlags: EClientPersonaStateFlag(body.GetMUnStatusFlags()),
AccountFlags: EAccountFlags(body.GetClanAccountFlags()), AccountFlags: EAccountFlags(body.GetClanAccountFlags()),
ClanName: name, ClanName: name,
Avatar: avatar, Avatar: avatar,
@ -606,7 +598,7 @@ func (s *Social) handleProfileInfoResponse(packet *Packet) {
} }
func (s *Social) handleFriendMessageHistoryResponse(packet *Packet) { func (s *Social) handleFriendMessageHistoryResponse(packet *Packet) {
body := new(CMsgClientFSGetFriendMessageHistoryResponse) body := new(CMsgClientChatGetFriendMessageHistoryResponse)
packet.ReadProtoMsg(body) packet.ReadProtoMsg(body)
steamid := SteamId(body.GetSteamid()) steamid := SteamId(body.GetSteamid())
for _, message := range body.GetMessages() { for _, message := range body.GetMessages() {

View File

@ -1,9 +1,10 @@
package steam package steam
import ( import (
"time"
. "github.com/Philipp15b/go-steam/protocol/steamlang" . "github.com/Philipp15b/go-steam/protocol/steamlang"
. "github.com/Philipp15b/go-steam/steamid" . "github.com/Philipp15b/go-steam/steamid"
"time"
) )
type FriendsListEvent struct{} type FriendsListEvent struct{}
@ -41,7 +42,7 @@ type PersonaStateEvent struct {
SourceSteamId SteamId `json:",string"` SourceSteamId SteamId `json:",string"`
GameDataBlob []byte GameDataBlob []byte
Name string Name string
Avatar string Avatar []byte
LastLogOff uint32 LastLogOff uint32
LastLogOn uint32 LastLogOn uint32
ClanRank uint32 ClanRank uint32
@ -49,17 +50,14 @@ type PersonaStateEvent struct {
OnlineSessionInstances uint32 OnlineSessionInstances uint32
PublishedSessionId uint32 PublishedSessionId uint32
PersonaSetByUser bool PersonaSetByUser bool
FacebookName string
FacebookId uint64 `json:",string"`
} }
// Fired when a clan's state has been changed // Fired when a clan's state has been changed
type ClanStateEvent struct { type ClanStateEvent struct {
ClandId SteamId `json:",string"` ClanId SteamId `json:",string"`
StateFlags EClientPersonaStateFlag
AccountFlags EAccountFlags AccountFlags EAccountFlags
ClanName string ClanName string
Avatar string Avatar []byte
MemberTotalCount uint32 MemberTotalCount uint32
MemberOnlineCount uint32 MemberOnlineCount uint32
MemberChattingCount uint32 MemberChattingCount uint32

View File

@ -2,9 +2,10 @@ package socialcache
import ( import (
"errors" "errors"
"sync"
. "github.com/Philipp15b/go-steam/protocol/steamlang" . "github.com/Philipp15b/go-steam/protocol/steamlang"
. "github.com/Philipp15b/go-steam/steamid" . "github.com/Philipp15b/go-steam/steamid"
"sync"
) )
// Friends list is a thread safe map // Friends list is a thread safe map
@ -76,7 +77,7 @@ func (list *FriendsList) SetName(id SteamId, name string) {
} }
} }
func (list *FriendsList) SetAvatar(id SteamId, hash string) { func (list *FriendsList) SetAvatar(id SteamId, hash []byte) {
list.mutex.Lock() list.mutex.Lock()
defer list.mutex.Unlock() defer list.mutex.Unlock()
if val, ok := list.byId[id]; ok { if val, ok := list.byId[id]; ok {
@ -136,7 +137,7 @@ func (list *FriendsList) SetGameName(id SteamId, name string) {
type Friend struct { type Friend struct {
SteamId SteamId `json:",string"` SteamId SteamId `json:",string"`
Name string Name string
Avatar string Avatar []byte
Relationship EFriendRelationship Relationship EFriendRelationship
PersonaState EPersonaState PersonaState EPersonaState
PersonaStateFlags EPersonaStateFlag PersonaStateFlags EPersonaStateFlag

View File

@ -2,9 +2,10 @@ package socialcache
import ( import (
"errors" "errors"
"sync"
. "github.com/Philipp15b/go-steam/protocol/steamlang" . "github.com/Philipp15b/go-steam/protocol/steamlang"
. "github.com/Philipp15b/go-steam/steamid" . "github.com/Philipp15b/go-steam/steamid"
"sync"
) )
// Groups list is a thread safe map // Groups list is a thread safe map
@ -78,7 +79,7 @@ func (list *GroupsList) SetName(id SteamId, name string) {
} }
} }
func (list *GroupsList) SetAvatar(id SteamId, hash string) { func (list *GroupsList) SetAvatar(id SteamId, hash []byte) {
list.mutex.Lock() list.mutex.Lock()
defer list.mutex.Unlock() defer list.mutex.Unlock()
id = id.ChatToClan() id = id.ChatToClan()
@ -136,7 +137,7 @@ func (list *GroupsList) SetMemberInGameCount(id SteamId, count uint32) {
type Group struct { type Group struct {
SteamId SteamId `json:",string"` SteamId SteamId `json:",string"`
Name string Name string
Avatar string Avatar []byte
Relationship EClanRelationship Relationship EClanRelationship
MemberTotalCount uint32 MemberTotalCount uint32
MemberOnlineCount uint32 MemberOnlineCount uint32

View File

@ -1,13 +1,13 @@
language: go language: go
go: go:
- 1.9 - "1.12"
install: install:
- go get -u golang.org/x/lint/golint - env GO111MODULE=on go get -u golang.org/x/lint/golint
script: script:
- make test - env GO111MODULE=on make test
deploy: deploy:
- provider: script - provider: script

3
vendor/github.com/d5/tengo/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/d5/tengo
go 1.12

View File

@ -1,53 +0,0 @@
// +build ignore
package main
import (
"bytes"
"io/ioutil"
"log"
"regexp"
"strconv"
)
var tengoModFileRE = regexp.MustCompile(`^srcmod_(\w+).tengo$`)
func main() {
modules := make(map[string]string)
// enumerate all Tengo module files
files, err := ioutil.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, file := range files {
m := tengoModFileRE.FindStringSubmatch(file.Name())
if m != nil {
modName := m[1]
src, err := ioutil.ReadFile(file.Name())
if err != nil {
log.Fatalf("file '%s' read error: %s", file.Name(), err.Error())
}
modules[modName] = string(src)
}
}
var out bytes.Buffer
out.WriteString(`// Code generated using gensrcmods.go; DO NOT EDIT.
package stdlib
// SourceModules are source type standard library modules.
var SourceModules = map[string]string{` + "\n")
for modName, modSrc := range modules {
out.WriteString("\t\"" + modName + "\": " + strconv.Quote(modSrc) + ",\n")
}
out.WriteString("}\n")
const target = "source_modules.go"
if err := ioutil.WriteFile(target, out.Bytes(), 0644); err != nil {
log.Fatal(err)
}
}

View File

@ -1,19 +0,0 @@
language: go
sudo: false
matrix:
include:
- go: 1.7.x
- go: 1.8.x
- go: 1.9.x
- go: 1.10.x
- go: 1.11.x
- go: tip
allow_failures:
- go: tip
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- go vet $(go list ./... | grep -v /vendor/)
- go test -v -race ./...

View File

@ -1,11 +1,11 @@
# Gorilla WebSocket # Gorilla WebSocket
[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
[![CircleCI](https://circleci.com/gh/gorilla/websocket.svg?style=svg)](https://circleci.com/gh/gorilla/websocket)
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket)
[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
### Documentation ### Documentation
* [API Reference](http://godoc.org/github.com/gorilla/websocket) * [API Reference](http://godoc.org/github.com/gorilla/websocket)
@ -27,7 +27,7 @@ package API is stable.
### Protocol Compliance ### Protocol Compliance
The Gorilla WebSocket package passes the server tests in the [Autobahn Test The Gorilla WebSocket package passes the server tests in the [Autobahn Test
Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [examples/autobahn
subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn).
### Gorilla WebSocket compared with other packages ### Gorilla WebSocket compared with other packages
@ -40,7 +40,7 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn
</tr> </tr>
<tr> <tr>
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr> <tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr>
<tr><td>Passes <a href="http://autobahn.ws/testsuite/">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr> <tr><td>Passes <a href="https://github.com/crossbario/autobahn-testsuite">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr>
<tr><td>Receive <a href="https://tools.ietf.org/html/rfc6455#section-5.4">fragmented</a> message<td>Yes</td><td><a href="https://code.google.com/p/go/issues/detail?id=7632">No</a>, see note 1</td></tr> <tr><td>Receive <a href="https://tools.ietf.org/html/rfc6455#section-5.4">fragmented</a> message<td>Yes</td><td><a href="https://code.google.com/p/go/issues/detail?id=7632">No</a>, see note 1</td></tr>
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close</a> message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=4588">No</a></td></tr> <tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close</a> message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=4588">No</a></td></tr>
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr> <tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr>

View File

@ -70,7 +70,7 @@ type Dialer struct {
// HandshakeTimeout specifies the duration for the handshake to complete. // HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration HandshakeTimeout time.Duration
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
// size is zero, then a useful default size is used. The I/O buffer sizes // size is zero, then a useful default size is used. The I/O buffer sizes
// 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
@ -140,7 +140,7 @@ var nilDialer = *DefaultDialer
// Use the response.Header to get the selected subprotocol // Use the response.Header to get the selected subprotocol
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). // (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
// //
// The context will be used in the request and in the Dialer // The context will be used in the request and in the Dialer.
// //
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a // If the WebSocket handshake fails, ErrBadHandshake is returned along with a
// non-nil *http.Response so that callers can handle redirects, authentication, // non-nil *http.Response so that callers can handle redirects, authentication,

View File

@ -263,7 +263,9 @@ type Conn struct {
reader io.ReadCloser // the current reader returned to the application reader io.ReadCloser // the current reader returned to the application
readErr error readErr error
br *bufio.Reader br *bufio.Reader
readRemaining int64 // bytes remaining in current frame. // bytes remaining in current frame.
// set setReadRemaining to safely update this value and prevent overflow
readRemaining int64
readFinal bool // true the current message has more frames. readFinal bool // true the current message has more frames.
readLength int64 // Message size. readLength int64 // Message size.
readLimit int64 // Maximum message size. readLimit int64 // Maximum message size.
@ -320,6 +322,17 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int,
return c return c
} }
// setReadRemaining tracks the number of bytes remaining on the connection. If n
// overflows, an ErrReadLimit is returned.
func (c *Conn) setReadRemaining(n int64) error {
if n < 0 {
return ErrReadLimit
}
c.readRemaining = n
return nil
}
// Subprotocol returns the negotiated protocol for the connection. // Subprotocol returns the negotiated protocol for the connection.
func (c *Conn) Subprotocol() string { func (c *Conn) Subprotocol() string {
return c.subprotocol return c.subprotocol
@ -451,7 +464,8 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er
return err return err
} }
func (c *Conn) prepWrite(messageType int) error { // beginMessage prepares a connection and message writer for a new message.
func (c *Conn) beginMessage(mw *messageWriter, messageType int) error {
// Close previous writer if not already closed by the application. It's // Close previous writer if not already closed by the application. It's
// probably better to return an error in this situation, but we cannot // probably better to return an error in this situation, but we cannot
// change this without breaking existing applications. // change this without breaking existing applications.
@ -471,6 +485,10 @@ func (c *Conn) prepWrite(messageType int) error {
return err return err
} }
mw.c = c
mw.frameType = messageType
mw.pos = maxFrameHeaderSize
if c.writeBuf == nil { if c.writeBuf == nil {
wpd, ok := c.writePool.Get().(writePoolData) wpd, ok := c.writePool.Get().(writePoolData)
if ok { if ok {
@ -491,16 +509,11 @@ func (c *Conn) prepWrite(messageType int) error {
// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and // All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
// PongMessage) are supported. // PongMessage) are supported.
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
if err := c.prepWrite(messageType); err != nil { var mw messageWriter
if err := c.beginMessage(&mw, messageType); err != nil {
return nil, err return nil, err
} }
c.writer = &mw
mw := &messageWriter{
c: c,
frameType: messageType,
pos: maxFrameHeaderSize,
}
c.writer = mw
if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) { if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
w := c.newCompressionWriter(c.writer, c.compressionLevel) w := c.newCompressionWriter(c.writer, c.compressionLevel)
mw.compress = true mw.compress = true
@ -517,10 +530,16 @@ type messageWriter struct {
err error err error
} }
func (w *messageWriter) fatal(err error) error { func (w *messageWriter) endMessage(err error) error {
if w.err != nil { if w.err != nil {
return err
}
c := w.c
w.err = err w.err = err
w.c.writer = nil c.writer = nil
if c.writePool != nil {
c.writePool.Put(writePoolData{buf: c.writeBuf})
c.writeBuf = nil
} }
return err return err
} }
@ -534,7 +553,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
// Check for invalid control frames. // Check for invalid control frames.
if isControl(w.frameType) && if isControl(w.frameType) &&
(!final || length > maxControlFramePayloadSize) { (!final || length > maxControlFramePayloadSize) {
return w.fatal(errInvalidControlFrame) return w.endMessage(errInvalidControlFrame)
} }
b0 := byte(w.frameType) b0 := byte(w.frameType)
@ -579,7 +598,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
copy(c.writeBuf[maxFrameHeaderSize-4:], key[:]) copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos]) maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
if len(extra) > 0 { if len(extra) > 0 {
return c.writeFatal(errors.New("websocket: internal error, extra used in client mode")) return w.endMessage(c.writeFatal(errors.New("websocket: internal error, extra used in client mode")))
} }
} }
@ -600,15 +619,11 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error {
c.isWriting = false c.isWriting = false
if err != nil { if err != nil {
return w.fatal(err) return w.endMessage(err)
} }
if final { if final {
c.writer = nil w.endMessage(errWriteClosed)
if c.writePool != nil {
c.writePool.Put(writePoolData{buf: c.writeBuf})
c.writeBuf = nil
}
return nil return nil
} }
@ -706,11 +721,7 @@ func (w *messageWriter) Close() error {
if w.err != nil { if w.err != nil {
return w.err return w.err
} }
if err := w.flushFrame(true, nil); err != nil { return w.flushFrame(true, nil)
return err
}
w.err = errWriteClosed
return nil
} }
// WritePreparedMessage writes prepared message into connection. // WritePreparedMessage writes prepared message into connection.
@ -742,10 +753,10 @@ func (c *Conn) WriteMessage(messageType int, data []byte) error {
if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) { if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) {
// Fast path with no allocations and single frame. // Fast path with no allocations and single frame.
if err := c.prepWrite(messageType); err != nil { var mw messageWriter
if err := c.beginMessage(&mw, messageType); err != nil {
return err return err
} }
mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize}
n := copy(c.writeBuf[mw.pos:], data) n := copy(c.writeBuf[mw.pos:], data)
mw.pos += n mw.pos += n
data = data[n:] data = data[n:]
@ -792,7 +803,7 @@ func (c *Conn) advanceFrame() (int, error) {
final := p[0]&finalBit != 0 final := p[0]&finalBit != 0
frameType := int(p[0] & 0xf) frameType := int(p[0] & 0xf)
mask := p[1]&maskBit != 0 mask := p[1]&maskBit != 0
c.readRemaining = int64(p[1] & 0x7f) c.setReadRemaining(int64(p[1] & 0x7f))
c.readDecompress = false c.readDecompress = false
if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 { if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 {
@ -826,7 +837,17 @@ func (c *Conn) advanceFrame() (int, error) {
return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType)) return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType))
} }
// 3. Read and parse frame length. // 3. Read and parse frame length as per
// https://tools.ietf.org/html/rfc6455#section-5.2
//
// The length of the "Payload data", in bytes: if 0-125, that is the payload
// length.
// - If 126, the following 2 bytes interpreted as a 16-bit unsigned
// integer are the payload length.
// - If 127, the following 8 bytes interpreted as
// a 64-bit unsigned integer (the most significant bit MUST be 0) are the
// payload length. Multibyte length quantities are expressed in network byte
// order.
switch c.readRemaining { switch c.readRemaining {
case 126: case 126:
@ -834,13 +855,19 @@ func (c *Conn) advanceFrame() (int, error) {
if err != nil { if err != nil {
return noFrame, err return noFrame, err
} }
c.readRemaining = int64(binary.BigEndian.Uint16(p))
if err := c.setReadRemaining(int64(binary.BigEndian.Uint16(p))); err != nil {
return noFrame, err
}
case 127: case 127:
p, err := c.read(8) p, err := c.read(8)
if err != nil { if err != nil {
return noFrame, err return noFrame, err
} }
c.readRemaining = int64(binary.BigEndian.Uint64(p))
if err := c.setReadRemaining(int64(binary.BigEndian.Uint64(p))); err != nil {
return noFrame, err
}
} }
// 4. Handle frame masking. // 4. Handle frame masking.
@ -863,6 +890,12 @@ func (c *Conn) advanceFrame() (int, error) {
if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage { if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
c.readLength += c.readRemaining c.readLength += c.readRemaining
// Don't allow readLength to overflow in the presence of a large readRemaining
// counter.
if c.readLength < 0 {
return noFrame, ErrReadLimit
}
if c.readLimit > 0 && c.readLength > c.readLimit { if c.readLimit > 0 && c.readLength > c.readLimit {
c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)) c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait))
return noFrame, ErrReadLimit return noFrame, ErrReadLimit
@ -876,7 +909,7 @@ func (c *Conn) advanceFrame() (int, error) {
var payload []byte var payload []byte
if c.readRemaining > 0 { if c.readRemaining > 0 {
payload, err = c.read(int(c.readRemaining)) payload, err = c.read(int(c.readRemaining))
c.readRemaining = 0 c.setReadRemaining(0)
if err != nil { if err != nil {
return noFrame, err return noFrame, err
} }
@ -949,6 +982,7 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
c.readErr = hideTempErr(err) c.readErr = hideTempErr(err)
break break
} }
if frameType == TextMessage || frameType == BinaryMessage { if frameType == TextMessage || frameType == BinaryMessage {
c.messageReader = &messageReader{c} c.messageReader = &messageReader{c}
c.reader = c.messageReader c.reader = c.messageReader
@ -989,7 +1023,9 @@ func (r *messageReader) Read(b []byte) (int, error) {
if c.isServer { if c.isServer {
c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n]) c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n])
} }
c.readRemaining -= int64(n) rem := c.readRemaining
rem -= int64(n)
c.setReadRemaining(rem)
if c.readRemaining > 0 && c.readErr == io.EOF { if c.readRemaining > 0 && c.readErr == io.EOF {
c.readErr = errUnexpectedEOF c.readErr = errUnexpectedEOF
} }
@ -1041,7 +1077,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t) return c.conn.SetReadDeadline(t)
} }
// SetReadLimit sets the maximum size for a message read from the peer. If a // SetReadLimit sets the maximum size in bytes for a message read from the peer. If a
// message exceeds the limit, the connection sends a close message to the peer // message exceeds the limit, the connection sends a close message to the peer
// and returns ErrReadLimit to the application. // and returns ErrReadLimit to the application.
func (c *Conn) SetReadLimit(limit int64) { func (c *Conn) SetReadLimit(limit int64) {

View File

@ -151,6 +151,53 @@
// checking. The application is responsible for checking the Origin header // checking. The application is responsible for checking the Origin header
// before calling the Upgrade function. // before calling the Upgrade function.
// //
// Buffers
//
// Connections buffer network input and output to reduce the number
// of system calls when reading or writing messages.
//
// Write buffers are also used for constructing WebSocket frames. See RFC 6455,
// Section 5 for a discussion of message framing. A WebSocket frame header is
// written to the network each time a write buffer is flushed to the network.
// Decreasing the size of the write buffer can increase the amount of framing
// overhead on the connection.
//
// The buffer sizes in bytes are specified by the ReadBufferSize and
// WriteBufferSize fields in the Dialer and Upgrader. The Dialer uses a default
// size of 4096 when a buffer size field is set to zero. The Upgrader reuses
// buffers created by the HTTP server when a buffer size field is set to zero.
// The HTTP server buffers have a size of 4096 at the time of this writing.
//
// The buffer sizes do not limit the size of a message that can be read or
// written by a connection.
//
// Buffers are held for the lifetime of the connection by default. If the
// Dialer or Upgrader WriteBufferPool field is set, then a connection holds the
// write buffer only when writing a message.
//
// Applications should tune the buffer sizes to balance memory use and
// performance. Increasing the buffer size uses more memory, but can reduce the
// number of system calls to read or write the network. In the case of writing,
// increasing the buffer size can reduce the number of frame headers written to
// the network.
//
// Some guidelines for setting buffer parameters are:
//
// Limit the buffer sizes to the maximum expected message size. Buffers larger
// than the largest message do not provide any benefit.
//
// Depending on the distribution of message sizes, setting the buffer size to
// to a value less than the maximum expected message size can greatly reduce
// memory use with a small impact on performance. Here's an example: If 99% of
// the messages are smaller than 256 bytes and the maximum message size is 512
// bytes, then a buffer size of 256 bytes will result in 1.01 more system calls
// than a buffer size of 512 bytes. The memory savings is 50%.
//
// A write buffer pool is useful when the application has a modest number
// writes over a large number of connections. when buffers are pooled, a larger
// buffer size has a reduced impact on total memory use and has the benefit of
// reducing system calls and frame overhead.
//
// Compression EXPERIMENTAL // Compression EXPERIMENTAL
// //
// Per message compression extensions (RFC 7692) are experimentally supported // Per message compression extensions (RFC 7692) are experimentally supported

3
vendor/github.com/gorilla/websocket/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/gorilla/websocket
go 1.12

2
vendor/github.com/gorilla/websocket/go.sum generated vendored Normal file
View File

@ -0,0 +1,2 @@
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=

42
vendor/github.com/gorilla/websocket/join.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2019 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.
package websocket
import (
"io"
"strings"
)
// JoinMessages concatenates received messages to create a single io.Reader.
// The string term is appended to each message. The returned reader does not
// support concurrent calls to the Read method.
func JoinMessages(c *Conn, term string) io.Reader {
return &joinReader{c: c, term: term}
}
type joinReader struct {
c *Conn
term string
r io.Reader
}
func (r *joinReader) Read(p []byte) (int, error) {
if r.r == nil {
var err error
_, r.r, err = r.c.NextReader()
if err != nil {
return 0, err
}
if r.term != "" {
r.r = io.MultiReader(r.r, strings.NewReader(r.term))
}
}
n, err := r.r.Read(p)
if err == io.EOF {
err = nil
r.r = nil
}
return n, err
}

View File

@ -22,18 +22,18 @@ func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
func init() { func init() {
proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) { proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
return &httpProxyDialer{proxyURL: proxyURL, fowardDial: forwardDialer.Dial}, nil return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil
}) })
} }
type httpProxyDialer struct { type httpProxyDialer struct {
proxyURL *url.URL proxyURL *url.URL
fowardDial func(network, addr string) (net.Conn, error) forwardDial func(network, addr string) (net.Conn, error)
} }
func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) { func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
hostPort, _ := hostPortNoPort(hpd.proxyURL) hostPort, _ := hostPortNoPort(hpd.proxyURL)
conn, err := hpd.fowardDial(network, hostPort) conn, err := hpd.forwardDial(network, hostPort)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -27,7 +27,7 @@ type Upgrader struct {
// HandshakeTimeout specifies the duration for the handshake to complete. // HandshakeTimeout specifies the duration for the handshake to complete.
HandshakeTimeout time.Duration HandshakeTimeout time.Duration
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
// size is zero, then buffers allocated by the HTTP server are used. The // size is zero, then buffers allocated by the HTTP server are used. The
// I/O buffer sizes do not limit the size of the messages that can be sent // I/O buffer sizes do not limit the size of the messages that can be sent
// or received. // or received.
@ -153,7 +153,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
challengeKey := r.Header.Get("Sec-Websocket-Key") challengeKey := r.Header.Get("Sec-Websocket-Key")
if challengeKey == "" { if challengeKey == "" {
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-WebSocket-Key' header is missing or blank") return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header is missing or blank")
} }
subprotocol := u.selectSubprotocol(r, responseHeader) subprotocol := u.selectSubprotocol(r, responseHeader)

View File

@ -31,68 +31,113 @@ func generateChallengeKey() (string, error) {
return base64.StdEncoding.EncodeToString(p), nil return base64.StdEncoding.EncodeToString(p), nil
} }
// Octet types from RFC 2616. // Token octets per RFC 2616.
var octetTypes [256]byte var isTokenOctet = [256]bool{
'!': true,
const ( '#': true,
isTokenOctet = 1 << iota '$': true,
isSpaceOctet '%': true,
) '&': true,
'\'': true,
func init() { '*': true,
// From RFC 2616 '+': true,
// '-': true,
// OCTET = <any 8-bit sequence of data> '.': true,
// CHAR = <any US-ASCII character (octets 0 - 127)> '0': true,
// CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)> '1': true,
// CR = <US-ASCII CR, carriage return (13)> '2': true,
// LF = <US-ASCII LF, linefeed (10)> '3': true,
// SP = <US-ASCII SP, space (32)> '4': true,
// HT = <US-ASCII HT, horizontal-tab (9)> '5': true,
// <"> = <US-ASCII double-quote mark (34)> '6': true,
// CRLF = CR LF '7': true,
// LWS = [CRLF] 1*( SP | HT ) '8': true,
// TEXT = <any OCTET except CTLs, but including LWS> '9': true,
// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> 'A': true,
// | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT 'B': true,
// token = 1*<any CHAR except CTLs or separators> 'C': true,
// qdtext = <any TEXT except <">> 'D': true,
'E': true,
for c := 0; c < 256; c++ { 'F': true,
var t byte 'G': true,
isCtl := c <= 31 || c == 127 'H': true,
isChar := 0 <= c && c <= 127 'I': true,
isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0 'J': true,
if strings.IndexRune(" \t\r\n", rune(c)) >= 0 { 'K': true,
t |= isSpaceOctet 'L': true,
} 'M': true,
if isChar && !isCtl && !isSeparator { 'N': true,
t |= isTokenOctet 'O': true,
} 'P': true,
octetTypes[c] = t 'Q': true,
} 'R': true,
'S': true,
'T': true,
'U': true,
'W': true,
'V': true,
'X': true,
'Y': true,
'Z': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'|': true,
'~': true,
} }
// skipSpace returns a slice of the string s with all leading RFC 2616 linear
// whitespace removed.
func skipSpace(s string) (rest string) { func skipSpace(s string) (rest string) {
i := 0 i := 0
for ; i < len(s); i++ { for ; i < len(s); i++ {
if octetTypes[s[i]]&isSpaceOctet == 0 { if b := s[i]; b != ' ' && b != '\t' {
break break
} }
} }
return s[i:] return s[i:]
} }
// nextToken returns the leading RFC 2616 token of s and the string following
// the token.
func nextToken(s string) (token, rest string) { func nextToken(s string) (token, rest string) {
i := 0 i := 0
for ; i < len(s); i++ { for ; i < len(s); i++ {
if octetTypes[s[i]]&isTokenOctet == 0 { if !isTokenOctet[s[i]] {
break break
} }
} }
return s[:i], s[i:] return s[:i], s[i:]
} }
// nextTokenOrQuoted returns the leading token or quoted string per RFC 2616
// and the string following the token or quoted string.
func nextTokenOrQuoted(s string) (value string, rest string) { func nextTokenOrQuoted(s string) (value string, rest string) {
if !strings.HasPrefix(s, "\"") { if !strings.HasPrefix(s, "\"") {
return nextToken(s) return nextToken(s)
@ -128,7 +173,8 @@ func nextTokenOrQuoted(s string) (value string, rest string) {
return "", "" return "", ""
} }
// equalASCIIFold returns true if s is equal to t with ASCII case folding. // equalASCIIFold returns true if s is equal to t with ASCII case folding as
// defined in RFC 4790.
func equalASCIIFold(s, t string) bool { func equalASCIIFold(s, t string) bool {
for s != "" && t != "" { for s != "" && t != "" {
sr, size := utf8.DecodeRuneInString(s) sr, size := utf8.DecodeRuneInString(s)

View File

@ -1 +1,3 @@
module github.com/hashicorp/golang-lru module github.com/hashicorp/golang-lru
go 1.12

View File

@ -86,17 +86,35 @@ func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) {
} }
// Remove removes the provided key from the cache. // Remove removes the provided key from the cache.
func (c *Cache) Remove(key interface{}) { func (c *Cache) Remove(key interface{}) (present bool) {
c.lock.Lock() c.lock.Lock()
c.lru.Remove(key) present = c.lru.Remove(key)
c.lock.Unlock() c.lock.Unlock()
return
}
// Resize changes the cache size.
func (c *Cache) Resize(size int) (evicted int) {
c.lock.Lock()
evicted = c.lru.Resize(size)
c.lock.Unlock()
return evicted
} }
// RemoveOldest removes the oldest item from the cache. // RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() { func (c *Cache) RemoveOldest() (key interface{}, value interface{}, ok bool) {
c.lock.Lock() c.lock.Lock()
c.lru.RemoveOldest() key, value, ok = c.lru.RemoveOldest()
c.lock.Unlock() c.lock.Unlock()
return
}
// GetOldest returns the oldest entry
func (c *Cache) GetOldest() (key interface{}, value interface{}, ok bool) {
c.lock.Lock()
key, value, ok = c.lru.GetOldest()
c.lock.Unlock()
return
} }
// Keys returns a slice of the keys in the cache, from oldest to newest. // Keys returns a slice of the keys in the cache, from oldest to newest.

View File

@ -73,6 +73,9 @@ func (c *LRU) Add(key, value interface{}) (evicted bool) {
func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
if ent, ok := c.items[key]; ok { if ent, ok := c.items[key]; ok {
c.evictList.MoveToFront(ent) c.evictList.MoveToFront(ent)
if ent.Value.(*entry) == nil {
return nil, false
}
return ent.Value.(*entry).value, true return ent.Value.(*entry).value, true
} }
return return
@ -142,6 +145,19 @@ func (c *LRU) Len() int {
return c.evictList.Len() return c.evictList.Len()
} }
// Resize changes the cache size.
func (c *LRU) Resize(size int) (evicted int) {
diff := c.Len() - size
if diff < 0 {
diff = 0
}
for i := 0; i < diff; i++ {
c.removeOldest()
}
c.size = size
return diff
}
// removeOldest removes the oldest item from the cache. // removeOldest removes the oldest item from the cache.
func (c *LRU) removeOldest() { func (c *LRU) removeOldest() {
ent := c.evictList.Back() ent := c.evictList.Back()

View File

@ -10,7 +10,7 @@ type LRUCache interface {
// updates the "recently used"-ness of the key. #value, isFound // updates the "recently used"-ness of the key. #value, isFound
Get(key interface{}) (value interface{}, ok bool) Get(key interface{}) (value interface{}, ok bool)
// Check if a key exsists in cache without updating the recent-ness. // Checks if a key exists in cache without updating the recent-ness.
Contains(key interface{}) (ok bool) Contains(key interface{}) (ok bool)
// Returns key's value without updating the "recently used"-ness of the key. // Returns key's value without updating the "recently used"-ness of the key.
@ -31,6 +31,9 @@ type LRUCache interface {
// Returns the number of items in the cache. // Returns the number of items in the cache.
Len() int Len() int
// Clear all cache entries // Clears all cache entries.
Purge() Purge()
// Resizes cache, returning number evicted
Resize(int) int
} }

View File

@ -33,6 +33,17 @@ type (
// Bind implements the `Binder#Bind` function. // Bind implements the `Binder#Bind` function.
func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) { func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
req := c.Request() req := c.Request()
names := c.ParamNames()
values := c.ParamValues()
params := map[string][]string{}
for i, name := range names {
params[name] = []string{values[i]}
}
if err := b.bindData(i, params, "param"); err != nil {
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
if req.ContentLength == 0 { if req.ContentLength == 0 {
if req.Method == http.MethodGet || req.Method == http.MethodDelete { if req.Method == http.MethodGet || req.Method == http.MethodDelete {
if err = b.bindData(i, c.QueryParams(), "query"); err != nil { if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
@ -77,9 +88,19 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
} }
func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error { func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error {
if ptr == nil || len(data) == 0 {
return nil
}
typ := reflect.TypeOf(ptr).Elem() typ := reflect.TypeOf(ptr).Elem()
val := reflect.ValueOf(ptr).Elem() val := reflect.ValueOf(ptr).Elem()
if m, ok := ptr.(*map[string]interface{}); ok {
for k, v := range data {
(*m)[k] = v[0]
}
return nil
}
if typ.Kind() != reflect.Struct { if typ.Kind() != reflect.Struct {
return errors.New("binding element must be a struct") return errors.New("binding element must be a struct")
} }

View File

@ -26,6 +26,9 @@ type (
// SetRequest sets `*http.Request`. // SetRequest sets `*http.Request`.
SetRequest(r *http.Request) SetRequest(r *http.Request)
// SetResponse sets `*Response`.
SetResponse(r *Response)
// Response returns `*Response`. // Response returns `*Response`.
Response() *Response Response() *Response
@ -228,6 +231,10 @@ func (c *context) Response() *Response {
return c.response return c.response
} }
func (c *context) SetResponse(r *Response) {
c.response = r
}
func (c *context) IsTLS() bool { func (c *context) IsTLS() bool {
return c.request.TLS != nil return c.request.TLS != nil
} }

View File

@ -99,9 +99,9 @@ type (
// HTTPError represents an error that occurred while handling a request. // HTTPError represents an error that occurred while handling a request.
HTTPError struct { HTTPError struct {
Code int Code int `json:"-"`
Message interface{} Message interface{} `json:"message"`
Internal error // Stores the error returned by an external dependency Internal error `json:"-"` // Stores the error returned by an external dependency
} }
// MiddlewareFunc defines a function to process middleware. // MiddlewareFunc defines a function to process middleware.
@ -222,11 +222,12 @@ const (
HeaderContentSecurityPolicy = "Content-Security-Policy" HeaderContentSecurityPolicy = "Content-Security-Policy"
HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only" HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
HeaderXCSRFToken = "X-CSRF-Token" HeaderXCSRFToken = "X-CSRF-Token"
HeaderReferrerPolicy = "Referrer-Policy"
) )
const ( const (
// Version of Echo // Version of Echo
Version = "4.1.5" Version = "4.1.10"
website = "https://echo.labstack.com" website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = ` banner = `
@ -340,32 +341,31 @@ func (e *Echo) Routers() map[string]*Router {
// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response // DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
// with status code. // with status code.
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) { func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
var ( he, ok := err.(*HTTPError)
code = http.StatusInternalServerError if ok {
msg interface{}
)
if he, ok := err.(*HTTPError); ok {
code = he.Code
msg = he.Message
if he.Internal != nil { if he.Internal != nil {
err = fmt.Errorf("%v, %v", err, he.Internal) if herr, ok := he.Internal.(*HTTPError); ok {
he = herr
}
} }
} else if e.Debug {
msg = err.Error()
} else { } else {
msg = http.StatusText(code) he = &HTTPError{
Code: http.StatusInternalServerError,
Message: http.StatusText(http.StatusInternalServerError),
} }
if _, ok := msg.(string); ok { }
msg = Map{"message": msg} if e.Debug {
he.Message = err.Error()
} else if m, ok := he.Message.(string); ok {
he.Message = Map{"message": m}
} }
// Send response // Send response
if !c.Response().Committed { if !c.Response().Committed {
if c.Request().Method == http.MethodHead { // Issue #608 if c.Request().Method == http.MethodHead { // Issue #608
err = c.NoContent(code) err = c.NoContent(he.Code)
} else { } else {
err = c.JSON(code, msg) err = c.JSON(he.Code, he.Message)
} }
if err != nil { if err != nil {
e.Logger.Error(err) e.Logger.Error(err)
@ -748,7 +748,7 @@ func NewHTTPError(code int, message ...interface{}) *HTTPError {
// Error makes it compatible with `error` interface. // Error makes it compatible with `error` interface.
func (he *HTTPError) Error() string { func (he *HTTPError) Error() string {
return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message) return fmt.Sprintf("code=%d, message=%v, internal=%v", he.Code, he.Message, he.Internal)
} }
// SetInternal sets error to HTTPError.Internal // SetInternal sets error to HTTPError.Internal
@ -771,6 +771,7 @@ func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
return func(c Context) (err error) { return func(c Context) (err error) {
m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c.SetRequest(r) c.SetRequest(r)
c.SetResponse(NewResponse(w, c.Echo()))
err = next(c) err = next(c)
})).ServeHTTP(c.Response(), c.Request()) })).ServeHTTP(c.Response(), c.Request())
return return

View File

@ -4,12 +4,8 @@ go 1.12
require ( require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/labstack/gommon v0.2.9 github.com/labstack/gommon v0.3.0
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.4.0
github.com/valyala/fasttemplate v1.0.1 github.com/valyala/fasttemplate v1.0.1
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
golang.org/x/net v0.0.0-20190607181551-461777fb6f67 // indirect
golang.org/x/sys v0.0.0-20190609082536-301114b31cce // indirect
golang.org/x/text v0.3.2 // indirect
golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3 // indirect
) )

View File

@ -1,53 +1,34 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0= github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/labstack/gommon v0.2.9 h1:heVeuAYtevIQVYkGj6A41dtfT91LrvFG220lavpWhrU=
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190607181551-461777fb6f67 h1:rJJxsykSlULwd2P2+pg/rtnwN2FrWp4IuCxOSyS0V00=
golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2 h1:T5DasATyLQfmbTpfEXx/IOL9vfjzW6up+ZDkmHvIf2s= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190609082536-301114b31cce/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=

View File

@ -26,6 +26,9 @@ type (
// It may be used to define a custom JWT error. // It may be used to define a custom JWT error.
ErrorHandler JWTErrorHandler ErrorHandler JWTErrorHandler
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
ErrorHandlerWithContext JWTErrorHandlerWithContext
// Signing key to validate token. Used as fallback if SigningKeys has length 0. // Signing key to validate token. Used as fallback if SigningKeys has length 0.
// Required. This or SigningKeys. // Required. This or SigningKeys.
SigningKey interface{} SigningKey interface{}
@ -69,6 +72,9 @@ type (
// JWTErrorHandler defines a function which is executed for an invalid token. // JWTErrorHandler defines a function which is executed for an invalid token.
JWTErrorHandler func(error) error JWTErrorHandler func(error) error
// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
JWTErrorHandlerWithContext func(error, echo.Context) error
jwtExtractor func(echo.Context) (string, error) jwtExtractor func(echo.Context) (string, error)
) )
@ -177,6 +183,10 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
if config.ErrorHandler != nil { if config.ErrorHandler != nil {
return config.ErrorHandler(err) return config.ErrorHandler(err)
} }
if config.ErrorHandlerWithContext != nil {
return config.ErrorHandlerWithContext(err, c)
}
return err return err
} }
token := new(jwt.Token) token := new(jwt.Token)
@ -199,6 +209,9 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
if config.ErrorHandler != nil { if config.ErrorHandler != nil {
return config.ErrorHandler(err) return config.ErrorHandler(err)
} }
if config.ErrorHandlerWithContext != nil {
return config.ErrorHandlerWithContext(err, c)
}
return &echo.HTTPError{ return &echo.HTTPError{
Code: http.StatusUnauthorized, Code: http.StatusUnauthorized,
Message: "invalid or expired jwt", Message: "invalid or expired jwt",

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"io" "io"
"os"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -74,7 +73,6 @@ var (
`"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` + `"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` +
`,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n", `,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n",
CustomTimeFormat: "2006-01-02 15:04:05.00000", CustomTimeFormat: "2006-01-02 15:04:05.00000",
Output: os.Stdout,
colorer: color.New(), colorer: color.New(),
} }
) )
@ -214,6 +212,10 @@ func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
return return
} }
if config.Output == nil {
_, err = c.Logger().Output().Write(buf.Bytes())
return
}
_, err = config.Output.Write(buf.Bytes()) _, err = config.Output.Write(buf.Bytes())
return return
} }

View File

@ -66,6 +66,11 @@ type (
// maintained by Chrome (and used by Firefox and Safari): https://hstspreload.org/ // maintained by Chrome (and used by Firefox and Safari): https://hstspreload.org/
// Optional. Default value false. // Optional. Default value false.
HSTSPreloadEnabled bool `yaml:"hsts_preload_enabled"` HSTSPreloadEnabled bool `yaml:"hsts_preload_enabled"`
// ReferrerPolicy sets the `Referrer-Policy` header providing security against
// leaking potentially sensitive request paths to third parties.
// Optional. Default value "".
ReferrerPolicy string `yaml:"referrer_policy"`
} }
) )
@ -131,6 +136,9 @@ func SecureWithConfig(config SecureConfig) echo.MiddlewareFunc {
res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy) res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
} }
} }
if config.ReferrerPolicy != "" {
res.Header().Set(echo.HeaderReferrerPolicy, config.ReferrerPolicy)
}
return next(c) return next(c)
} }
} }

View File

@ -336,10 +336,14 @@ func (r *Router) Find(method, path string, c Context) {
} }
} }
if l == pl { if l == pl {
// Continue search // Continue search
search = search[l:] search = search[l:]
} else { } else {
if nn == nil { // Issue #1348
return // Not found
}
cn = nn cn = nn
search = ns search = ns
if nk == pkind { if nk == pkind {
@ -347,8 +351,6 @@ func (r *Router) Find(method, path string, c Context) {
} else if nk == akind { } else if nk == akind {
goto Any goto Any
} }
// Not found
return
} }
if search == "" { if search == "" {
@ -398,6 +400,9 @@ func (r *Router) Find(method, path string, c Context) {
if nn != nil { if nn != nil {
cn = nn cn = nn
nn = cn.parent // Next (Issue #954) nn = cn.parent // Next (Issue #954)
if nn != nil {
nk = nn.kind
}
search = ns search = ns
if nk == pkind { if nk == pkind {
goto Param goto Param
@ -405,8 +410,7 @@ func (r *Router) Find(method, path string, c Context) {
goto Any goto Any
} }
} }
// Not found return // Not found
return
} }
pvalues[len(cn.pnames)-1] = search pvalues[len(cn.pnames)-1] = search
break break

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"regexp" "regexp"
"strconv" "strconv"
"strings"
) )
type ( type (
@ -73,7 +74,7 @@ func (*Bytes) Parse(value string) (i int64, err error) {
return 0, fmt.Errorf("error parsing value=%s", value) return 0, fmt.Errorf("error parsing value=%s", value)
} }
bytesString := parts[1] bytesString := parts[1]
multiple := parts[2] multiple := strings.ToUpper(parts[2])
bytes, err := strconv.ParseFloat(bytesString, 64) bytes, err := strconv.ParseFloat(bytesString, 64)
if err != nil { if err != nil {
return return

View File

@ -1,3 +1,3 @@
module github.com/mattn/go-isatty module github.com/mattn/go-isatty
require golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 require golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a

View File

@ -1,2 +1,2 @@
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@ -1,12 +1,9 @@
language: go language: go
go: env:
- 1.7.x - GO111MODULE=on
- 1.8.x
- 1.9.x install: true
- 1.10.x
- 1.11.x
- tip
before_install: before_install:
- export PATH=$HOME/gopath/bin:$PATH - export PATH=$HOME/gopath/bin:$PATH
@ -20,6 +17,19 @@ script:
matrix: matrix:
allow_failures: allow_failures:
- go: tip - go: tip
include:
- go: "1.7.x"
script: go test -v ./...
- go: "1.8.x"
script: go test -v ./...
- go: "1.9.x"
script: go test -v ./...
- go: "1.10.x"
script: go test -v ./...
- go: "1.11.x"
script: go test -v -mod=vendor ./...
- go: "tip"
script: go test -v -mod=vendor ./...
git: git:
depth: 10 depth: 10

View File

@ -1,3 +1,20 @@
### v0.6.0 - August 31, 2019
full differences can be viewed using `git log --oneline --decorate --color v0.5.0..v0.6.0`
thanks to everyone who has contributed since January!
#### Breaking Changes:
- Info struct has had fields removed related to deprecated functionality by slack.
- minor adjustments to some structs.
- some internal default values have changed, usually to be more inline with slack defaults or to correct inability to set a particular value. (Message Parse for example.)
##### Highlights:
- new slacktest package easy mocking for slack client. use, enjoy, please submit PRs for improvements and default behaviours! shamelessly taken from the [slack-test repo](https://github.com/lusis/slack-test) thank you lusis for letting us use it and bring it into the slack repo.
- blocks, blocks, blocks.
- RTM ManagedConnection has undergone a significant cleanup.
in particular handles backoffs gracefully, removed many deadlocks,
and Disconnect is now much more responsive.
### v0.5.0 - January 20, 2019 ### v0.5.0 - January 20, 2019
full differences can be viewed using `git log --oneline --decorate --color v0.4.0..v0.5.0` full differences can be viewed using `git log --oneline --decorate --color v0.4.0..v0.5.0`
- Breaking changes: various old struct fields have been removed or updated to match slack's api. - Breaking changes: various old struct fields have been removed or updated to match slack's api.

View File

@ -1,39 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
name = "github.com/gorilla/websocket"
packages = ["."]
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert"]
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "596fa546322c2a1e9708a10c9f39aca2e04792b477fab86fb2899fbaab776070"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -1,17 +0,0 @@
ignored = ["github.com/lusis/slack-test"]
[[constraint]]
name = "github.com/gorilla/websocket"
version = "1.2.0"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.2.1"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[prune]
go-tests = true
unused-packages = true

View File

@ -35,7 +35,7 @@ func main() {
api := slack.New("YOUR_TOKEN_HERE") api := slack.New("YOUR_TOKEN_HERE")
// If you set debugging, it will log all requests to the console // If you set debugging, it will log all requests to the console
// Useful when encountering issues // Useful when encountering issues
// api.SetDebug(true) // slack.New("YOUR_TOKEN_HERE", slack.OptionDebug(true))
groups, err := api.GetGroups(false) groups, err := api.GetGroups(false)
if err != nil { if err != nil {
fmt.Printf("%s\n", err) fmt.Printf("%s\n", err)

View File

@ -2,28 +2,19 @@ package slack
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"net/url" "net/url"
"strings"
) )
type adminResponse struct { func (api *Client) adminRequest(ctx context.Context, method string, teamName string, values url.Values) error {
OK bool `json:"ok"` resp := &SlackResponse{}
Error string `json:"error"` err := parseAdminResponse(ctx, api.httpclient, method, teamName, values, resp, api)
}
func adminRequest(ctx context.Context, client httpClient, method string, teamName string, values url.Values, d debug) (*adminResponse, error) {
adminResponse := &adminResponse{}
err := parseAdminResponse(ctx, client, method, teamName, values, adminResponse, d)
if err != nil { if err != nil {
return nil, err return err
} }
if !adminResponse.OK { return resp.Err()
return nil, errors.New(adminResponse.Error)
}
return adminResponse, nil
} }
// DisableUser disabled a user account, given a user ID // DisableUser disabled a user account, given a user ID
@ -40,9 +31,8 @@ func (api *Client) DisableUserContext(ctx context.Context, teamName string, uid
"_attempts": {"1"}, "_attempts": {"1"},
} }
_, err := adminRequest(ctx, api.httpclient, "setInactive", teamName, values, api) if err := api.adminRequest(ctx, "setInactive", teamName, values); err != nil {
if err != nil { return fmt.Errorf("failed to disable user with id '%s': %s", uid, err)
return fmt.Errorf("Failed to disable user with id '%s': %s", uid, err)
} }
return nil return nil
@ -67,7 +57,7 @@ func (api *Client) InviteGuestContext(ctx context.Context, teamName, channel, fi
"_attempts": {"1"}, "_attempts": {"1"},
} }
_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api) err := api.adminRequest(ctx, "invite", teamName, values)
if err != nil { if err != nil {
return fmt.Errorf("Failed to invite single-channel guest: %s", err) return fmt.Errorf("Failed to invite single-channel guest: %s", err)
} }
@ -94,7 +84,7 @@ func (api *Client) InviteRestrictedContext(ctx context.Context, teamName, channe
"_attempts": {"1"}, "_attempts": {"1"},
} }
_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api) err := api.adminRequest(ctx, "invite", teamName, values)
if err != nil { if err != nil {
return fmt.Errorf("Failed to restricted account: %s", err) return fmt.Errorf("Failed to restricted account: %s", err)
} }
@ -118,7 +108,7 @@ func (api *Client) InviteToTeamContext(ctx context.Context, teamName, firstName,
"_attempts": {"1"}, "_attempts": {"1"},
} }
_, err := adminRequest(ctx, api.httpclient, "invite", teamName, values, api) err := api.adminRequest(ctx, "invite", teamName, values)
if err != nil { if err != nil {
return fmt.Errorf("Failed to invite to team: %s", err) return fmt.Errorf("Failed to invite to team: %s", err)
} }
@ -140,7 +130,7 @@ func (api *Client) SetRegularContext(ctx context.Context, teamName, user string)
"_attempts": {"1"}, "_attempts": {"1"},
} }
_, err := adminRequest(ctx, api.httpclient, "setRegular", teamName, values, api) err := api.adminRequest(ctx, "setRegular", teamName, values)
if err != nil { if err != nil {
return fmt.Errorf("Failed to change the user (%s) to a regular user: %s", user, err) return fmt.Errorf("Failed to change the user (%s) to a regular user: %s", user, err)
} }
@ -162,7 +152,7 @@ func (api *Client) SendSSOBindingEmailContext(ctx context.Context, teamName, use
"_attempts": {"1"}, "_attempts": {"1"},
} }
_, err := adminRequest(ctx, api.httpclient, "sendSSOBind", teamName, values, api) err := api.adminRequest(ctx, "sendSSOBind", teamName, values)
if err != nil { if err != nil {
return fmt.Errorf("Failed to send SSO binding email for user (%s): %s", user, err) return fmt.Errorf("Failed to send SSO binding email for user (%s): %s", user, err)
} }
@ -185,7 +175,7 @@ func (api *Client) SetUltraRestrictedContext(ctx context.Context, teamName, uid,
"_attempts": {"1"}, "_attempts": {"1"},
} }
_, err := adminRequest(ctx, api.httpclient, "setUltraRestricted", teamName, values, api) err := api.adminRequest(ctx, "setUltraRestricted", teamName, values)
if err != nil { if err != nil {
return fmt.Errorf("Failed to ultra-restrict account: %s", err) return fmt.Errorf("Failed to ultra-restrict account: %s", err)
} }
@ -194,22 +184,23 @@ func (api *Client) SetUltraRestrictedContext(ctx context.Context, teamName, uid,
} }
// SetRestricted converts a user into a restricted account // SetRestricted converts a user into a restricted account
func (api *Client) SetRestricted(teamName, uid string) error { func (api *Client) SetRestricted(teamName, uid string, channelIds ...string) error {
return api.SetRestrictedContext(context.Background(), teamName, uid) return api.SetRestrictedContext(context.Background(), teamName, uid, channelIds...)
} }
// SetRestrictedContext converts a user into a restricted account with a custom context // SetRestrictedContext converts a user into a restricted account with a custom context
func (api *Client) SetRestrictedContext(ctx context.Context, teamName, uid string) error { func (api *Client) SetRestrictedContext(ctx context.Context, teamName, uid string, channelIds ...string) error {
values := url.Values{ values := url.Values{
"user": {uid}, "user": {uid},
"token": {api.token}, "token": {api.token},
"set_active": {"true"}, "set_active": {"true"},
"_attempts": {"1"}, "_attempts": {"1"},
"channels": {strings.Join(channelIds, ",")},
} }
_, err := adminRequest(ctx, api.httpclient, "setRestricted", teamName, values, api) err := api.adminRequest(ctx, "setRestricted", teamName, values)
if err != nil { if err != nil {
return fmt.Errorf("Failed to restrict account: %s", err) return fmt.Errorf("failed to restrict account: %s", err)
} }
return nil return nil

View File

@ -17,7 +17,7 @@ type AttachmentAction struct {
Name string `json:"name"` // Required. Name string `json:"name"` // Required.
Text string `json:"text"` // Required. Text string `json:"text"` // Required.
Style string `json:"style,omitempty"` // Optional. Allowed values: "default", "primary", "danger". Style string `json:"style,omitempty"` // Optional. Allowed values: "default", "primary", "danger".
Type string `json:"type"` // Required. Must be set to "button" or "select". Type actionType `json:"type"` // Required. Must be set to "button" or "select".
Value string `json:"value,omitempty"` // Optional. Value string `json:"value,omitempty"` // Optional.
DataSource string `json:"data_source,omitempty"` // Optional. DataSource string `json:"data_source,omitempty"` // Optional.
MinQueryLength int `json:"min_query_length,omitempty"` // Optional. Default value is 1. MinQueryLength int `json:"min_query_length,omitempty"` // Optional. Default value is 1.
@ -28,6 +28,11 @@ type AttachmentAction struct {
URL string `json:"url,omitempty"` // Optional. URL string `json:"url,omitempty"` // Optional.
} }
// actionType returns the type of the action
func (a AttachmentAction) actionType() actionType {
return a.Type
}
// AttachmentActionOption the individual option to appear in action menu. // AttachmentActionOption the individual option to appear in action menu.
type AttachmentActionOption struct { type AttachmentActionOption struct {
Text string `json:"text"` // Required. Text string `json:"text"` // Required.
@ -45,13 +50,6 @@ type AttachmentActionOptionGroup struct {
// DEPRECATED: use InteractionCallback // DEPRECATED: use InteractionCallback
type AttachmentActionCallback InteractionCallback type AttachmentActionCallback InteractionCallback
// ActionCallback specific fields for the action callback.
type ActionCallback struct {
MessageTs string `json:"message_ts"`
AttachmentID string `json:"attachment_id"`
Actions []AttachmentAction `json:"actions"`
}
// ConfirmationField are used to ask users to confirm actions // ConfirmationField are used to ask users to confirm actions
type ConfirmationField struct { type ConfirmationField struct {
Title string `json:"title,omitempty"` // Optional. Title string `json:"title,omitempty"` // Optional.

View File

@ -12,9 +12,9 @@ type AuthRevokeResponse struct {
} }
// authRequest sends the actual request, and unmarshals the response // authRequest sends the actual request, and unmarshals the response
func authRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*AuthRevokeResponse, error) { func (api *Client) authRequest(ctx context.Context, path string, values url.Values) (*AuthRevokeResponse, error) {
response := &AuthRevokeResponse{} response := &AuthRevokeResponse{}
err := postSlackMethod(ctx, client, path, values, response, d) err := api.postMethod(ctx, path, values, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -36,5 +36,5 @@ func (api *Client) SendAuthRevokeContext(ctx context.Context, token string) (*Au
"token": {token}, "token": {token},
} }
return authRequest(ctx, api.httpclient, "auth.revoke", values, api) return api.authRequest(ctx, "auth.revoke", values)
} }

View File

@ -1,7 +1,6 @@
package slack package slack
import ( import (
"math"
"math/rand" "math/rand"
"time" "time"
) )
@ -14,41 +13,42 @@ import (
// conjunction with the time package. // conjunction with the time package.
type backoff struct { type backoff struct {
attempts int attempts int
//Factor is the multiplying factor for each increment step // Initial value to scale out
Factor float64 Initial time.Duration
//Jitter eases contention by randomizing backoff steps // Jitter value randomizes an additional delay between 0 and Jitter
Jitter bool Jitter time.Duration
//Min and Max are the minimum and maximum values of the counter // Max maximum values of the backoff
Min, Max time.Duration Max time.Duration
} }
// Returns the current value of the counter and then multiplies it // Returns the current value of the counter and then multiplies it
// Factor // Factor
func (b *backoff) Duration() time.Duration { func (b *backoff) Duration() (dur time.Duration) {
//Zero-values are nonsensical, so we use // Zero-values are nonsensical, so we use
//them to apply defaults // them to apply defaults
if b.Min == 0 {
b.Min = 100 * time.Millisecond
}
if b.Max == 0 { if b.Max == 0 {
b.Max = 10 * time.Second b.Max = 10 * time.Second
} }
if b.Factor == 0 {
b.Factor = 2 if b.Initial == 0 {
b.Initial = 100 * time.Millisecond
} }
//calculate this duration
dur := float64(b.Min) * math.Pow(b.Factor, float64(b.attempts)) // calculate this duration
if b.Jitter { if dur = time.Duration(1 << uint(b.attempts)); dur > 0 {
dur = rand.Float64()*(dur-float64(b.Min)) + float64(b.Min) dur = dur * b.Initial
} else {
dur = b.Max
} }
//cap!
if dur > float64(b.Max) { if b.Jitter > 0 {
return b.Max dur = dur + time.Duration(rand.Intn(int(b.Jitter)))
} }
//bump attempts count
// bump attempts count
b.attempts++ b.attempts++
//return as a time.Duration
return time.Duration(dur) return dur
} }
//Resets the current value of the counter back to Min //Resets the current value of the counter back to Min

71
vendor/github.com/nlopes/slack/block.go generated vendored Normal file
View File

@ -0,0 +1,71 @@
package slack
// @NOTE: Blocks are in beta and subject to change.
// More Information: https://api.slack.com/block-kit
// MessageBlockType defines a named string type to define each block type
// as a constant for use within the package.
type MessageBlockType string
const (
MBTSection MessageBlockType = "section"
MBTDivider MessageBlockType = "divider"
MBTImage MessageBlockType = "image"
MBTAction MessageBlockType = "actions"
MBTContext MessageBlockType = "context"
)
// Block defines an interface all block types should implement
// to ensure consistency between blocks.
type Block interface {
BlockType() MessageBlockType
}
// Blocks is a convenience struct defined to allow dynamic unmarshalling of
// the "blocks" value in Slack's JSON response, which varies depending on block type
type Blocks struct {
BlockSet []Block `json:"blocks,omitempty"`
}
// BlockAction is the action callback sent when a block is interacted with
type BlockAction struct {
ActionID string `json:"action_id"`
BlockID string `json:"block_id"`
Type actionType `json:"type"`
Text TextBlockObject `json:"text"`
Value string `json:"value"`
ActionTs string `json:"action_ts"`
SelectedOption OptionBlockObject `json:"selected_option"`
SelectedUser string `json:"selected_user"`
SelectedChannel string `json:"selected_channel"`
SelectedConversation string `json:"selected_conversation"`
SelectedDate string `json:"selected_date"`
InitialOption OptionBlockObject `json:"initial_option"`
InitialUser string `json:"initial_user"`
InitialChannel string `json:"initial_channel"`
InitialConversation string `json:"initial_conversation"`
InitialDate string `json:"initial_date"`
}
// actionType returns the type of the action
func (b BlockAction) actionType() actionType {
return b.Type
}
// NewBlockMessage creates a new Message that contains one or more blocks to be displayed
func NewBlockMessage(blocks ...Block) Message {
return Message{
Msg: Msg{
Blocks: Blocks{
BlockSet: blocks,
},
},
}
}
// AddBlockMessage appends a block to the end of the existing list of blocks
func AddBlockMessage(message Message, newBlk Block) Message {
message.Msg.Blocks.BlockSet = append(message.Msg.Blocks.BlockSet, newBlk)
return message
}

26
vendor/github.com/nlopes/slack/block_action.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
package slack
// ActionBlock defines data that is used to hold interactive elements.
//
// More Information: https://api.slack.com/reference/messaging/blocks#actions
type ActionBlock struct {
Type MessageBlockType `json:"type"`
BlockID string `json:"block_id,omitempty"`
Elements BlockElements `json:"elements"`
}
// BlockType returns the type of the block
func (s ActionBlock) BlockType() MessageBlockType {
return s.Type
}
// NewActionBlock returns a new instance of an Action Block
func NewActionBlock(blockID string, elements ...BlockElement) *ActionBlock {
return &ActionBlock{
Type: MBTAction,
BlockID: blockID,
Elements: BlockElements{
ElementSet: elements,
},
}
}

32
vendor/github.com/nlopes/slack/block_context.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
package slack
// ContextBlock defines data that is used to display message context, which can
// include both images and text.
//
// More Information: https://api.slack.com/reference/messaging/blocks#actions
type ContextBlock struct {
Type MessageBlockType `json:"type"`
BlockID string `json:"block_id,omitempty"`
ContextElements ContextElements `json:"elements"`
}
// BlockType returns the type of the block
func (s ContextBlock) BlockType() MessageBlockType {
return s.Type
}
type ContextElements struct {
Elements []MixedElement
}
// NewContextBlock returns a new instance of a context block
func NewContextBlock(blockID string, mixedElements ...MixedElement) *ContextBlock {
elements := ContextElements{
Elements: mixedElements,
}
return &ContextBlock{
Type: MBTContext,
BlockID: blockID,
ContextElements: elements,
}
}

303
vendor/github.com/nlopes/slack/block_conv.go generated vendored Normal file
View File

@ -0,0 +1,303 @@
package slack
import (
"encoding/json"
"github.com/pkg/errors"
)
type sumtype struct {
TypeVal string `json:"type"`
}
// MarshalJSON implements the Marshaller interface for Blocks so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (b Blocks) MarshalJSON() ([]byte, error) {
bytes, err := json.Marshal(b.BlockSet)
if err != nil {
return nil, err
}
return bytes, nil
}
// UnmarshalJSON implements the Unmarshaller interface for Blocks, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *Blocks) UnmarshalJSON(data []byte) error {
var raw []json.RawMessage
if string(data) == "{}" {
return nil
}
err := json.Unmarshal(data, &raw)
if err != nil {
return err
}
var blocks Blocks
for _, r := range raw {
s := sumtype{}
err := json.Unmarshal(r, &s)
if err != nil {
return err
}
var blockType string
if s.TypeVal != "" {
blockType = s.TypeVal
}
var block Block
switch blockType {
case "actions":
block = &ActionBlock{}
case "context":
block = &ContextBlock{}
case "divider":
block = &DividerBlock{}
case "image":
block = &ImageBlock{}
case "section":
block = &SectionBlock{}
default:
return errors.New("unsupported block type")
}
err = json.Unmarshal(r, block)
if err != nil {
return err
}
blocks.BlockSet = append(blocks.BlockSet, block)
}
*b = blocks
return nil
}
// MarshalJSON implements the Marshaller interface for BlockElements so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (b *BlockElements) MarshalJSON() ([]byte, error) {
bytes, err := json.Marshal(b.ElementSet)
if err != nil {
return nil, err
}
return bytes, nil
}
// UnmarshalJSON implements the Unmarshaller interface for BlockElements, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *BlockElements) UnmarshalJSON(data []byte) error {
var raw []json.RawMessage
if string(data) == "{}" {
return nil
}
err := json.Unmarshal(data, &raw)
if err != nil {
return err
}
var blockElements BlockElements
for _, r := range raw {
s := sumtype{}
err := json.Unmarshal(r, &s)
if err != nil {
return err
}
var blockElementType string
if s.TypeVal != "" {
blockElementType = s.TypeVal
}
var blockElement BlockElement
switch blockElementType {
case "image":
blockElement = &ImageBlockElement{}
case "button":
blockElement = &ButtonBlockElement{}
case "overflow":
blockElement = &OverflowBlockElement{}
case "datepicker":
blockElement = &DatePickerBlockElement{}
case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
blockElement = &SelectBlockElement{}
default:
return errors.New("unsupported block element type")
}
err = json.Unmarshal(r, blockElement)
if err != nil {
return err
}
blockElements.ElementSet = append(blockElements.ElementSet, blockElement)
}
*b = blockElements
return nil
}
// MarshalJSON implements the Marshaller interface for Accessory so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (a *Accessory) MarshalJSON() ([]byte, error) {
bytes, err := json.Marshal(toBlockElement(a))
if err != nil {
return nil, err
}
return bytes, nil
}
// UnmarshalJSON implements the Unmarshaller interface for Accessory, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (a *Accessory) UnmarshalJSON(data []byte) error {
var r json.RawMessage
if string(data) == "{\"accessory\":null}" {
return nil
}
err := json.Unmarshal(data, &r)
if err != nil {
return err
}
s := sumtype{}
err = json.Unmarshal(r, &s)
if err != nil {
return err
}
var blockElementType string
if s.TypeVal != "" {
blockElementType = s.TypeVal
}
switch blockElementType {
case "image":
element, err := unmarshalBlockElement(r, &ImageBlockElement{})
if err != nil {
return err
}
a.ImageElement = element.(*ImageBlockElement)
case "button":
element, err := unmarshalBlockElement(r, &ButtonBlockElement{})
if err != nil {
return err
}
a.ButtonElement = element.(*ButtonBlockElement)
case "overflow":
element, err := unmarshalBlockElement(r, &OverflowBlockElement{})
if err != nil {
return err
}
a.OverflowElement = element.(*OverflowBlockElement)
case "datepicker":
element, err := unmarshalBlockElement(r, &DatePickerBlockElement{})
if err != nil {
return err
}
a.DatePickerElement = element.(*DatePickerBlockElement)
case "static_select":
element, err := unmarshalBlockElement(r, &SelectBlockElement{})
if err != nil {
return err
}
a.SelectElement = element.(*SelectBlockElement)
}
return nil
}
func unmarshalBlockElement(r json.RawMessage, element BlockElement) (BlockElement, error) {
err := json.Unmarshal(r, element)
if err != nil {
return nil, err
}
return element, nil
}
func toBlockElement(element *Accessory) BlockElement {
if element.ImageElement != nil {
return element.ImageElement
}
if element.ButtonElement != nil {
return element.ButtonElement
}
if element.OverflowElement != nil {
return element.OverflowElement
}
if element.DatePickerElement != nil {
return element.DatePickerElement
}
if element.SelectElement != nil {
return element.SelectElement
}
return nil
}
// MarshalJSON implements the Marshaller interface for ContextElements so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (e *ContextElements) MarshalJSON() ([]byte, error) {
bytes, err := json.Marshal(e.Elements)
if err != nil {
return nil, err
}
return bytes, nil
}
// UnmarshalJSON implements the Unmarshaller interface for ContextElements, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (e *ContextElements) UnmarshalJSON(data []byte) error {
var raw []json.RawMessage
if string(data) == "{\"elements\":null}" {
return nil
}
err := json.Unmarshal(data, &raw)
if err != nil {
return err
}
for _, r := range raw {
s := sumtype{}
err := json.Unmarshal(r, &s)
if err != nil {
return err
}
var contextElementType string
if s.TypeVal != "" {
contextElementType = s.TypeVal
}
switch contextElementType {
case PlainTextType, MarkdownType:
elem, err := unmarshalBlockObject(r, &TextBlockObject{})
if err != nil {
return err
}
e.Elements = append(e.Elements, elem.(*TextBlockObject))
case "image":
elem, err := unmarshalBlockElement(r, &ImageBlockElement{})
if err != nil {
return err
}
e.Elements = append(e.Elements, elem.(*ImageBlockElement))
default:
return errors.New("unsupported context element type")
}
}
return nil
}

22
vendor/github.com/nlopes/slack/block_divider.go generated vendored Normal file
View File

@ -0,0 +1,22 @@
package slack
// DividerBlock for displaying a divider line between blocks (similar to <hr> tag in html)
//
// More Information: https://api.slack.com/reference/messaging/blocks#divider
type DividerBlock struct {
Type MessageBlockType `json:"type"`
BlockID string `json:"block_id,omitempty"`
}
// BlockType returns the type of the block
func (s DividerBlock) BlockType() MessageBlockType {
return s.Type
}
// NewDividerBlock returns a new instance of a divider block
func NewDividerBlock() *DividerBlock {
return &DividerBlock{
Type: MBTDivider,
}
}

238
vendor/github.com/nlopes/slack/block_element.go generated vendored Normal file
View File

@ -0,0 +1,238 @@
package slack
// https://api.slack.com/reference/messaging/block-elements
const (
METImage MessageElementType = "image"
METButton MessageElementType = "button"
METOverflow MessageElementType = "overflow"
METDatepicker MessageElementType = "datepicker"
MixedElementImage MixedElementType = "mixed_image"
MixedElementText MixedElementType = "mixed_text"
OptTypeStatic string = "static_select"
OptTypeExternal string = "external_select"
OptTypeUser string = "users_select"
OptTypeConversations string = "conversations_select"
OptTypeChannels string = "channels_select"
)
type MessageElementType string
type MixedElementType string
// BlockElement defines an interface that all block element types should implement.
type BlockElement interface {
ElementType() MessageElementType
}
type MixedElement interface {
MixedElementType() MixedElementType
}
type Accessory struct {
ImageElement *ImageBlockElement
ButtonElement *ButtonBlockElement
OverflowElement *OverflowBlockElement
DatePickerElement *DatePickerBlockElement
SelectElement *SelectBlockElement
}
// NewAccessory returns a new Accessory for a given block element
func NewAccessory(element BlockElement) *Accessory {
switch element.(type) {
case *ImageBlockElement:
return &Accessory{ImageElement: element.(*ImageBlockElement)}
case *ButtonBlockElement:
return &Accessory{ButtonElement: element.(*ButtonBlockElement)}
case *OverflowBlockElement:
return &Accessory{OverflowElement: element.(*OverflowBlockElement)}
case *DatePickerBlockElement:
return &Accessory{DatePickerElement: element.(*DatePickerBlockElement)}
case *SelectBlockElement:
return &Accessory{SelectElement: element.(*SelectBlockElement)}
}
return nil
}
// BlockElements is a convenience struct defined to allow dynamic unmarshalling of
// the "elements" value in Slack's JSON response, which varies depending on BlockElement type
type BlockElements struct {
ElementSet []BlockElement `json:"elements,omitempty"`
}
// ImageBlockElement An element to insert an image - this element can be used
// in section and context blocks only. If you want a block with only an image
// in it, you're looking for the image block.
//
// More Information: https://api.slack.com/reference/messaging/block-elements#image
type ImageBlockElement struct {
Type MessageElementType `json:"type"`
ImageURL string `json:"image_url"`
AltText string `json:"alt_text"`
}
// ElementType returns the type of the Element
func (s ImageBlockElement) ElementType() MessageElementType {
return s.Type
}
func (s ImageBlockElement) MixedElementType() MixedElementType {
return MixedElementImage
}
// NewImageBlockElement returns a new instance of an image block element
func NewImageBlockElement(imageURL, altText string) *ImageBlockElement {
return &ImageBlockElement{
Type: METImage,
ImageURL: imageURL,
AltText: altText,
}
}
type Style string
const (
StyleDefault Style = "default"
StylePrimary Style = "primary"
StyleDanger Style = "danger"
)
// ButtonBlockElement defines an interactive element that inserts a button. The
// button can be a trigger for anything from opening a simple link to starting
// a complex workflow.
//
// More Information: https://api.slack.com/reference/messaging/block-elements#button
type ButtonBlockElement struct {
Type MessageElementType `json:"type,omitempty"`
Text *TextBlockObject `json:"text"`
ActionID string `json:"action_id,omitempty"`
URL string `json:"url,omitempty"`
Value string `json:"value,omitempty"`
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
Style Style `json:"style,omitempty"`
}
// ElementType returns the type of the element
func (s ButtonBlockElement) ElementType() MessageElementType {
return s.Type
}
// add styling to button object
func (s *ButtonBlockElement) WithStyle(style Style) {
s.Style = style
}
// NewButtonBlockElement returns an instance of a new button element to be used within a block
func NewButtonBlockElement(actionID, value string, text *TextBlockObject) *ButtonBlockElement {
return &ButtonBlockElement{
Type: METButton,
ActionID: actionID,
Text: text,
Value: value,
}
}
// SelectBlockElement defines the simplest form of select menu, with a static list
// of options passed in when defining the element.
//
// More Information: https://api.slack.com/reference/messaging/block-elements#select
type SelectBlockElement struct {
Type string `json:"type,omitempty"`
Placeholder *TextBlockObject `json:"placeholder,omitempty"`
ActionID string `json:"action_id,omitempty"`
Options []*OptionBlockObject `json:"options,omitempty"`
OptionGroups []*OptionGroupBlockObject `json:"option_groups,omitempty"`
InitialOption *OptionBlockObject `json:"initial_option,omitempty"`
InitialUser string `json:"initial_user,omitempty"`
InitialConversation string `json:"initial_conversation,omitempty"`
InitialChannel string `json:"initial_channel,omitempty"`
MinQueryLength int `json:"min_query_length,omitempty"`
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
}
// ElementType returns the type of the Element
func (s SelectBlockElement) ElementType() MessageElementType {
return MessageElementType(s.Type)
}
// NewOptionsSelectBlockElement returns a new instance of SelectBlockElement for use with
// the Options object only.
func NewOptionsSelectBlockElement(optType string, placeholder *TextBlockObject, actionID string, options ...*OptionBlockObject) *SelectBlockElement {
return &SelectBlockElement{
Type: optType,
Placeholder: placeholder,
ActionID: actionID,
Options: options,
}
}
// NewOptionsGroupSelectBlockElement returns a new instance of SelectBlockElement for use with
// the Options object only.
func NewOptionsGroupSelectBlockElement(
optType string,
placeholder *TextBlockObject,
actionID string,
optGroups ...*OptionGroupBlockObject,
) *SelectBlockElement {
return &SelectBlockElement{
Type: optType,
Placeholder: placeholder,
ActionID: actionID,
OptionGroups: optGroups,
}
}
// OverflowBlockElement defines the fields needed to use an overflow element.
// And Overflow Element is like a cross between a button and a select menu -
// when a user clicks on this overflow button, they will be presented with a
// list of options to choose from.
//
// More Information: https://api.slack.com/reference/messaging/block-elements#overflow
type OverflowBlockElement struct {
Type MessageElementType `json:"type"`
ActionID string `json:"action_id,omitempty"`
Options []*OptionBlockObject `json:"options"`
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
}
// ElementType returns the type of the Element
func (s OverflowBlockElement) ElementType() MessageElementType {
return s.Type
}
// NewOverflowBlockElement returns an instance of a new Overflow Block Element
func NewOverflowBlockElement(actionID string, options ...*OptionBlockObject) *OverflowBlockElement {
return &OverflowBlockElement{
Type: METOverflow,
ActionID: actionID,
Options: options,
}
}
// DatePickerBlockElement defines an element which lets users easily select a
// date from a calendar style UI. Date picker elements can be used inside of
// section and actions blocks.
//
// More Information: https://api.slack.com/reference/messaging/block-elements#datepicker
type DatePickerBlockElement struct {
Type MessageElementType `json:"type"`
ActionID string `json:"action_id"`
Placeholder *TextBlockObject `json:"placeholder,omitempty"`
InitialDate string `json:"initial_date,omitempty"`
Confirm *ConfirmationBlockObject `json:"confirm,omitempty"`
}
// ElementType returns the type of the Element
func (s DatePickerBlockElement) ElementType() MessageElementType {
return s.Type
}
// NewDatePickerBlockElement returns an instance of a date picker element
func NewDatePickerBlockElement(actionID string) *DatePickerBlockElement {
return &DatePickerBlockElement{
Type: METDatepicker,
ActionID: actionID,
}
}

28
vendor/github.com/nlopes/slack/block_image.go generated vendored Normal file
View File

@ -0,0 +1,28 @@
package slack
// ImageBlock defines data required to display an image as a block element
//
// More Information: https://api.slack.com/reference/messaging/blocks#image
type ImageBlock struct {
Type MessageBlockType `json:"type"`
ImageURL string `json:"image_url"`
AltText string `json:"alt_text"`
BlockID string `json:"block_id,omitempty"`
Title *TextBlockObject `json:"title"`
}
// BlockType returns the type of the block
func (s ImageBlock) BlockType() MessageBlockType {
return s.Type
}
// NewImageBlock returns an instance of a new Image Block type
func NewImageBlock(imageURL, altText, blockID string, title *TextBlockObject) *ImageBlock {
return &ImageBlock{
Type: MBTImage,
ImageURL: imageURL,
AltText: altText,
BlockID: blockID,
Title: title,
}
}

216
vendor/github.com/nlopes/slack/block_object.go generated vendored Normal file
View File

@ -0,0 +1,216 @@
package slack
import (
"encoding/json"
)
// Block Objects are also known as Composition Objects
//
// For more information: https://api.slack.com/reference/messaging/composition-objects
// BlockObject defines an interface that all block object types should
// implement.
// @TODO: Is this interface needed?
// blockObject object types
const (
MarkdownType = "mrkdwn"
PlainTextType = "plain_text"
// The following objects don't actually have types and their corresponding
// const values are just for internal use
motConfirmation = "confirm"
motOption = "option"
motOptionGroup = "option_group"
)
type MessageObjectType string
type blockObject interface {
validateType() MessageObjectType
}
type BlockObjects struct {
TextObjects []*TextBlockObject
ConfirmationObjects []*ConfirmationBlockObject
OptionObjects []*OptionBlockObject
OptionGroupObjects []*OptionGroupBlockObject
}
// UnmarshalJSON implements the Unmarshaller interface for BlockObjects, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *BlockObjects) UnmarshalJSON(data []byte) error {
var raw []json.RawMessage
err := json.Unmarshal(data, &raw)
if err != nil {
return err
}
for _, r := range raw {
var obj map[string]interface{}
err := json.Unmarshal(r, &obj)
if err != nil {
return err
}
blockObjectType := getBlockObjectType(obj)
switch blockObjectType {
case PlainTextType, MarkdownType:
object, err := unmarshalBlockObject(r, &TextBlockObject{})
if err != nil {
return err
}
b.TextObjects = append(b.TextObjects, object.(*TextBlockObject))
case motConfirmation:
object, err := unmarshalBlockObject(r, &ConfirmationBlockObject{})
if err != nil {
return err
}
b.ConfirmationObjects = append(b.ConfirmationObjects, object.(*ConfirmationBlockObject))
case motOption:
object, err := unmarshalBlockObject(r, &OptionBlockObject{})
if err != nil {
return err
}
b.OptionObjects = append(b.OptionObjects, object.(*OptionBlockObject))
case motOptionGroup:
object, err := unmarshalBlockObject(r, &OptionGroupBlockObject{})
if err != nil {
return err
}
b.OptionGroupObjects = append(b.OptionGroupObjects, object.(*OptionGroupBlockObject))
}
}
return nil
}
// Ideally would have a better way to identify the block objects for
// type casting at time of unmarshalling, should be adapted if possible
// to accomplish in a more reliable manner.
func getBlockObjectType(obj map[string]interface{}) string {
if t, ok := obj["type"].(string); ok {
return t
}
if _, ok := obj["confirm"].(string); ok {
return "confirm"
}
if _, ok := obj["options"].(string); ok {
return "option_group"
}
if _, ok := obj["text"].(string); ok {
if _, ok := obj["value"].(string); ok {
return "option"
}
}
return ""
}
func unmarshalBlockObject(r json.RawMessage, object blockObject) (blockObject, error) {
err := json.Unmarshal(r, object)
if err != nil {
return nil, err
}
return object, nil
}
// TextBlockObject defines a text element object to be used with blocks
//
// More Information: https://api.slack.com/reference/messaging/composition-objects#text
type TextBlockObject struct {
Type string `json:"type"`
Text string `json:"text"`
Emoji bool `json:"emoji,omitempty"`
Verbatim bool `json:"verbatim,omitempty"`
}
// validateType enforces block objects for element and block parameters
func (s TextBlockObject) validateType() MessageObjectType {
return MessageObjectType(s.Type)
}
// validateType enforces block objects for element and block parameters
func (s TextBlockObject) MixedElementType() MixedElementType {
return MixedElementText
}
// NewTextBlockObject returns an instance of a new Text Block Object
func NewTextBlockObject(elementType, text string, emoji, verbatim bool) *TextBlockObject {
return &TextBlockObject{
Type: elementType,
Text: text,
Emoji: emoji,
Verbatim: verbatim,
}
}
// ConfirmationBlockObject defines a dialog that provides a confirmation step to
// any interactive element. This dialog will ask the user to confirm their action by
// offering a confirm and deny buttons.
//
// More Information: https://api.slack.com/reference/messaging/composition-objects#confirm
type ConfirmationBlockObject struct {
Title *TextBlockObject `json:"title"`
Text *TextBlockObject `json:"text"`
Confirm *TextBlockObject `json:"confirm"`
Deny *TextBlockObject `json:"deny"`
}
// validateType enforces block objects for element and block parameters
func (s ConfirmationBlockObject) validateType() MessageObjectType {
return motConfirmation
}
// NewConfirmationBlockObject returns an instance of a new Confirmation Block Object
func NewConfirmationBlockObject(title, text, confirm, deny *TextBlockObject) *ConfirmationBlockObject {
return &ConfirmationBlockObject{
Title: title,
Text: text,
Confirm: confirm,
Deny: deny,
}
}
// OptionBlockObject represents a single selectable item in a select menu
//
// More Information: https://api.slack.com/reference/messaging/composition-objects#option
type OptionBlockObject struct {
Text *TextBlockObject `json:"text"`
Value string `json:"value"`
URL string `json:"url"`
}
// NewOptionBlockObject returns an instance of a new Option Block Element
func NewOptionBlockObject(value string, text *TextBlockObject) *OptionBlockObject {
return &OptionBlockObject{
Text: text,
Value: value,
}
}
// validateType enforces block objects for element and block parameters
func (s OptionBlockObject) validateType() MessageObjectType {
return motOption
}
// OptionGroupBlockObject Provides a way to group options in a select menu.
//
// More Information: https://api.slack.com/reference/messaging/composition-objects#option-group
type OptionGroupBlockObject struct {
Label *TextBlockObject `json:"label,omitempty"`
Options []*OptionBlockObject `json:"options"`
}
// validateType enforces block objects for element and block parameters
func (s OptionGroupBlockObject) validateType() MessageObjectType {
return motOptionGroup
}
// NewOptionGroupBlockElement returns an instance of a new option group block element
func NewOptionGroupBlockElement(label *TextBlockObject, options ...*OptionBlockObject) *OptionGroupBlockObject {
return &OptionGroupBlockObject{
Label: label,
Options: options,
}
}

42
vendor/github.com/nlopes/slack/block_section.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
package slack
// SectionBlock defines a new block of type section
//
// More Information: https://api.slack.com/reference/messaging/blocks#section
type SectionBlock struct {
Type MessageBlockType `json:"type"`
Text *TextBlockObject `json:"text,omitempty"`
BlockID string `json:"block_id,omitempty"`
Fields []*TextBlockObject `json:"fields,omitempty"`
Accessory *Accessory `json:"accessory,omitempty"`
}
// BlockType returns the type of the block
func (s SectionBlock) BlockType() MessageBlockType {
return s.Type
}
// SectionBlockOption allows configuration of options for a new section block
type SectionBlockOption func(*SectionBlock)
func SectionBlockOptionBlockID(blockID string) SectionBlockOption {
return func(block *SectionBlock) {
block.BlockID = blockID
}
}
// NewSectionBlock returns a new instance of a section block to be rendered
func NewSectionBlock(textObj *TextBlockObject, fields []*TextBlockObject, accessory *Accessory, options ...SectionBlockOption) *SectionBlock {
block := SectionBlock{
Type: MBTSection,
Text: textObj,
Fields: fields,
Accessory: accessory,
}
for _, option := range options {
option(&block)
}
return &block
}

View File

@ -2,7 +2,6 @@ package slack
import ( import (
"context" "context"
"errors"
"net/url" "net/url"
) )
@ -19,15 +18,17 @@ type botResponseFull struct {
SlackResponse SlackResponse
} }
func botRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*botResponseFull, error) { func (api *Client) botRequest(ctx context.Context, path string, values url.Values) (*botResponseFull, error) {
response := &botResponseFull{} response := &botResponseFull{}
err := postSlackMethod(ctx, client, path, values, response, d) err := api.postMethod(ctx, path, values, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !response.Ok {
return nil, errors.New(response.Error) if err := response.Err(); err != nil {
return nil, err
} }
return response, nil return response, nil
} }
@ -40,10 +41,13 @@ func (api *Client) GetBotInfo(bot string) (*Bot, error) {
func (api *Client) GetBotInfoContext(ctx context.Context, bot string) (*Bot, error) { func (api *Client) GetBotInfoContext(ctx context.Context, bot string) (*Bot, error) {
values := url.Values{ values := url.Values{
"token": {api.token}, "token": {api.token},
"bot": {bot},
} }
response, err := botRequest(ctx, api.httpclient, "bots.info", values, api) if bot != "" {
values.Add("bot", bot)
}
response, err := api.botRequest(ctx, "bots.info", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -2,7 +2,6 @@ package slack
import ( import (
"context" "context"
"errors"
"net/url" "net/url"
"strconv" "strconv"
) )
@ -19,23 +18,21 @@ type channelResponseFull struct {
// Channel contains information about the channel // Channel contains information about the channel
type Channel struct { type Channel struct {
groupConversation GroupConversation
IsChannel bool `json:"is_channel"` IsChannel bool `json:"is_channel"`
IsGeneral bool `json:"is_general"` IsGeneral bool `json:"is_general"`
IsMember bool `json:"is_member"` IsMember bool `json:"is_member"`
Locale string `json:"locale"` Locale string `json:"locale"`
} }
func channelRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*channelResponseFull, error) { func (api *Client) channelRequest(ctx context.Context, path string, values url.Values) (*channelResponseFull, error) {
response := &channelResponseFull{} response := &channelResponseFull{}
err := postForm(ctx, client, APIURL+path, values, response, d) err := postForm(ctx, api.httpclient, api.endpoint+path, values, response, api)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !response.Ok {
return nil, errors.New(response.Error) return response, response.Err()
}
return response, nil
} }
type channelsConfig struct { type channelsConfig struct {
@ -75,7 +72,7 @@ func (api *Client) ArchiveChannelContext(ctx context.Context, channelID string)
"channel": {channelID}, "channel": {channelID},
} }
_, err = channelRequest(ctx, api.httpclient, "channels.archive", values, api) _, err = api.channelRequest(ctx, "channels.archive", values)
return err return err
} }
@ -93,7 +90,7 @@ func (api *Client) UnarchiveChannelContext(ctx context.Context, channelID string
"channel": {channelID}, "channel": {channelID},
} }
_, err = channelRequest(ctx, api.httpclient, "channels.unarchive", values, api) _, err = api.channelRequest(ctx, "channels.unarchive", values)
return err return err
} }
@ -111,7 +108,7 @@ func (api *Client) CreateChannelContext(ctx context.Context, channelName string)
"name": {channelName}, "name": {channelName},
} }
response, err := channelRequest(ctx, api.httpclient, "channels.create", values, api) response, err := api.channelRequest(ctx, "channels.create", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -156,7 +153,7 @@ func (api *Client) GetChannelHistoryContext(ctx context.Context, channelID strin
} }
} }
response, err := channelRequest(ctx, api.httpclient, "channels.history", values, api) response, err := api.channelRequest(ctx, "channels.history", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -178,7 +175,7 @@ func (api *Client) GetChannelInfoContext(ctx context.Context, channelID string)
"include_locale": {strconv.FormatBool(true)}, "include_locale": {strconv.FormatBool(true)},
} }
response, err := channelRequest(ctx, api.httpclient, "channels.info", values, api) response, err := api.channelRequest(ctx, "channels.info", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -200,7 +197,7 @@ func (api *Client) InviteUserToChannelContext(ctx context.Context, channelID, us
"user": {user}, "user": {user},
} }
response, err := channelRequest(ctx, api.httpclient, "channels.invite", values, api) response, err := api.channelRequest(ctx, "channels.invite", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -221,7 +218,7 @@ func (api *Client) JoinChannelContext(ctx context.Context, channelName string) (
"name": {channelName}, "name": {channelName},
} }
response, err := channelRequest(ctx, api.httpclient, "channels.join", values, api) response, err := api.channelRequest(ctx, "channels.join", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -242,7 +239,7 @@ func (api *Client) LeaveChannelContext(ctx context.Context, channelID string) (b
"channel": {channelID}, "channel": {channelID},
} }
response, err := channelRequest(ctx, api.httpclient, "channels.leave", values, api) response, err := api.channelRequest(ctx, "channels.leave", values)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -265,7 +262,7 @@ func (api *Client) KickUserFromChannelContext(ctx context.Context, channelID, us
"user": {user}, "user": {user},
} }
_, err = channelRequest(ctx, api.httpclient, "channels.kick", values, api) _, err = api.channelRequest(ctx, "channels.kick", values)
return err return err
} }
@ -283,6 +280,7 @@ func (api *Client) GetChannelsContext(ctx context.Context, excludeArchived bool,
"token": {api.token}, "token": {api.token},
}, },
} }
if excludeArchived { if excludeArchived {
options = append(options, GetChannelsOptionExcludeArchived()) options = append(options, GetChannelsOptionExcludeArchived())
} }
@ -293,7 +291,7 @@ func (api *Client) GetChannelsContext(ctx context.Context, excludeArchived bool,
} }
} }
response, err := channelRequest(ctx, api.httpclient, "channels.list", config.values, api) response, err := api.channelRequest(ctx, "channels.list", config.values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -320,7 +318,7 @@ func (api *Client) SetChannelReadMarkContext(ctx context.Context, channelID, ts
"ts": {ts}, "ts": {ts},
} }
_, err = channelRequest(ctx, api.httpclient, "channels.mark", values, api) _, err = api.channelRequest(ctx, "channels.mark", values)
return err return err
} }
@ -341,7 +339,7 @@ func (api *Client) RenameChannelContext(ctx context.Context, channelID, name str
// XXX: the created entry in this call returns a string instead of a number // XXX: the created entry in this call returns a string instead of a number
// so I may have to do some workaround to solve it. // so I may have to do some workaround to solve it.
response, err := channelRequest(ctx, api.httpclient, "channels.rename", values, api) response, err := api.channelRequest(ctx, "channels.rename", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -363,7 +361,7 @@ func (api *Client) SetChannelPurposeContext(ctx context.Context, channelID, purp
"purpose": {purpose}, "purpose": {purpose},
} }
response, err := channelRequest(ctx, api.httpclient, "channels.setPurpose", values, api) response, err := api.channelRequest(ctx, "channels.setPurpose", values)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -385,7 +383,7 @@ func (api *Client) SetChannelTopicContext(ctx context.Context, channelID, topic
"topic": {topic}, "topic": {topic},
} }
response, err := channelRequest(ctx, api.httpclient, "channels.setTopic", values, api) response, err := api.channelRequest(ctx, "channels.setTopic", values)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -406,7 +404,7 @@ func (api *Client) GetChannelRepliesContext(ctx context.Context, channelID, thre
"channel": {channelID}, "channel": {channelID},
"thread_ts": {thread_ts}, "thread_ts": {thread_ts},
} }
response, err := channelRequest(ctx, api.httpclient, "channels.replies", values, api) response, err := api.channelRequest(ctx, "channels.replies", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,6 +3,7 @@ package slack
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"net/http"
"net/url" "net/url"
"github.com/nlopes/slack/slackutilsx" "github.com/nlopes/slack/slackutilsx"
@ -25,7 +26,7 @@ const (
type chatResponseFull struct { type chatResponseFull struct {
Channel string `json:"channel"` Channel string `json:"channel"`
Timestamp string `json:"ts"` //Regualr message timestamp Timestamp string `json:"ts"` //Regular message timestamp
MessageTimeStamp string `json:"message_ts"` //Ephemeral message timestamp MessageTimeStamp string `json:"message_ts"` //Ephemeral message timestamp
Text string `json:"text"` Text string `json:"text"`
SlackResponse SlackResponse
@ -156,17 +157,18 @@ func (api *Client) SendMessage(channel string, options ...MsgOption) (string, st
} }
// SendMessageContext more flexible method for configuring messages with a custom context. // SendMessageContext more flexible method for configuring messages with a custom context.
func (api *Client) SendMessageContext(ctx context.Context, channelID string, options ...MsgOption) (channel string, timestamp string, text string, err error) { func (api *Client) SendMessageContext(ctx context.Context, channelID string, options ...MsgOption) (_channel string, _timestamp string, _text string, err error) {
var ( var (
config sendConfig req *http.Request
parser func(*chatResponseFull) responseParser
response chatResponseFull response chatResponseFull
) )
if config, err = applyMsgOptions(api.token, channelID, options...); err != nil { if req, parser, err = buildSender(api.endpoint, options...).BuildRequest(api.token, channelID); err != nil {
return "", "", "", err return "", "", "", err
} }
if err = postForm(ctx, api.httpclient, config.endpoint, config.values, &response, api); err != nil { if err = doPost(ctx, api.httpclient, req, parser(&response), api); err != nil {
return "", "", "", err return "", "", "", err
} }
@ -176,14 +178,15 @@ func (api *Client) SendMessageContext(ctx context.Context, channelID string, opt
// UnsafeApplyMsgOptions utility function for debugging/testing chat requests. // UnsafeApplyMsgOptions utility function for debugging/testing chat requests.
// NOTE: USE AT YOUR OWN RISK: No issues relating to the use of this function // NOTE: USE AT YOUR OWN RISK: No issues relating to the use of this function
// will be supported by the library. // will be supported by the library.
func UnsafeApplyMsgOptions(token, channel string, options ...MsgOption) (string, url.Values, error) { func UnsafeApplyMsgOptions(token, channel, apiurl string, options ...MsgOption) (string, url.Values, error) {
config, err := applyMsgOptions(token, channel, options...) config, err := applyMsgOptions(token, channel, apiurl, options...)
return config.endpoint, config.values, err return config.endpoint, config.values, err
} }
func applyMsgOptions(token, channel string, options ...MsgOption) (sendConfig, error) { func applyMsgOptions(token, channel, apiurl string, options ...MsgOption) (sendConfig, error) {
config := sendConfig{ config := sendConfig{
endpoint: APIURL + string(chatPostMessage), apiurl: apiurl,
endpoint: apiurl + string(chatPostMessage),
values: url.Values{ values: url.Values{
"token": {token}, "token": {token},
"channel": {channel}, "channel": {channel},
@ -199,6 +202,13 @@ func applyMsgOptions(token, channel string, options ...MsgOption) (sendConfig, e
return config, nil return config, nil
} }
func buildSender(apiurl string, options ...MsgOption) sendConfig {
return sendConfig{
apiurl: apiurl,
options: options,
}
}
type sendMode string type sendMode string
const ( const (
@ -206,13 +216,68 @@ const (
chatPostMessage sendMode = "chat.postMessage" chatPostMessage sendMode = "chat.postMessage"
chatDelete sendMode = "chat.delete" chatDelete sendMode = "chat.delete"
chatPostEphemeral sendMode = "chat.postEphemeral" chatPostEphemeral sendMode = "chat.postEphemeral"
chatResponse sendMode = "chat.responseURL"
chatMeMessage sendMode = "chat.meMessage" chatMeMessage sendMode = "chat.meMessage"
chatUnfurl sendMode = "chat.unfurl" chatUnfurl sendMode = "chat.unfurl"
) )
type sendConfig struct { type sendConfig struct {
apiurl string
options []MsgOption
mode sendMode
endpoint string endpoint string
values url.Values values url.Values
attachments []Attachment
responseType string
}
func (t sendConfig) BuildRequest(token, channelID string) (req *http.Request, _ func(*chatResponseFull) responseParser, err error) {
if t, err = applyMsgOptions(token, channelID, t.apiurl, t.options...); err != nil {
return nil, nil, err
}
switch t.mode {
case chatResponse:
return responseURLSender{
endpoint: t.endpoint,
values: t.values,
attachments: t.attachments,
responseType: t.responseType,
}.BuildRequest()
default:
return formSender{endpoint: t.endpoint, values: t.values}.BuildRequest()
}
}
type formSender struct {
endpoint string
values url.Values
}
func (t formSender) BuildRequest() (*http.Request, func(*chatResponseFull) responseParser, error) {
req, err := formReq(t.endpoint, t.values)
return req, func(resp *chatResponseFull) responseParser {
return newJSONParser(resp)
}, err
}
type responseURLSender struct {
endpoint string
values url.Values
attachments []Attachment
responseType string
}
func (t responseURLSender) BuildRequest() (*http.Request, func(*chatResponseFull) responseParser, error) {
req, err := jsonReq(t.endpoint, Msg{
Text: t.values.Get("text"),
Timestamp: t.values.Get("ts"),
Attachments: t.attachments,
ResponseType: t.responseType,
})
return req, func(resp *chatResponseFull) responseParser {
return newContentTypeParser(resp)
}, err
} }
// MsgOption option provided when sending a message. // MsgOption option provided when sending a message.
@ -221,7 +286,7 @@ type MsgOption func(*sendConfig) error
// MsgOptionPost posts a messages, this is the default. // MsgOptionPost posts a messages, this is the default.
func MsgOptionPost() MsgOption { func MsgOptionPost() MsgOption {
return func(config *sendConfig) error { return func(config *sendConfig) error {
config.endpoint = APIURL + string(chatPostMessage) config.endpoint = config.apiurl + string(chatPostMessage)
config.values.Del("ts") config.values.Del("ts")
return nil return nil
} }
@ -230,7 +295,7 @@ func MsgOptionPost() MsgOption {
// MsgOptionPostEphemeral - posts an ephemeral message to the provided user. // MsgOptionPostEphemeral - posts an ephemeral message to the provided user.
func MsgOptionPostEphemeral(userID string) MsgOption { func MsgOptionPostEphemeral(userID string) MsgOption {
return func(config *sendConfig) error { return func(config *sendConfig) error {
config.endpoint = APIURL + string(chatPostEphemeral) config.endpoint = config.apiurl + string(chatPostEphemeral)
MsgOptionUser(userID)(config) MsgOptionUser(userID)(config)
config.values.Del("ts") config.values.Del("ts")
@ -241,7 +306,7 @@ func MsgOptionPostEphemeral(userID string) MsgOption {
// MsgOptionMeMessage posts a "me message" type from the calling user // MsgOptionMeMessage posts a "me message" type from the calling user
func MsgOptionMeMessage() MsgOption { func MsgOptionMeMessage() MsgOption {
return func(config *sendConfig) error { return func(config *sendConfig) error {
config.endpoint = APIURL + string(chatMeMessage) config.endpoint = config.apiurl + string(chatMeMessage)
return nil return nil
} }
} }
@ -249,7 +314,7 @@ func MsgOptionMeMessage() MsgOption {
// MsgOptionUpdate updates a message based on the timestamp. // MsgOptionUpdate updates a message based on the timestamp.
func MsgOptionUpdate(timestamp string) MsgOption { func MsgOptionUpdate(timestamp string) MsgOption {
return func(config *sendConfig) error { return func(config *sendConfig) error {
config.endpoint = APIURL + string(chatUpdate) config.endpoint = config.apiurl + string(chatUpdate)
config.values.Add("ts", timestamp) config.values.Add("ts", timestamp)
return nil return nil
} }
@ -258,7 +323,7 @@ func MsgOptionUpdate(timestamp string) MsgOption {
// MsgOptionDelete deletes a message based on the timestamp. // MsgOptionDelete deletes a message based on the timestamp.
func MsgOptionDelete(timestamp string) MsgOption { func MsgOptionDelete(timestamp string) MsgOption {
return func(config *sendConfig) error { return func(config *sendConfig) error {
config.endpoint = APIURL + string(chatDelete) config.endpoint = config.apiurl + string(chatDelete)
config.values.Add("ts", timestamp) config.values.Add("ts", timestamp)
return nil return nil
} }
@ -267,7 +332,7 @@ func MsgOptionDelete(timestamp string) MsgOption {
// MsgOptionUnfurl unfurls a message based on the timestamp. // MsgOptionUnfurl unfurls a message based on the timestamp.
func MsgOptionUnfurl(timestamp string, unfurls map[string]Attachment) MsgOption { func MsgOptionUnfurl(timestamp string, unfurls map[string]Attachment) MsgOption {
return func(config *sendConfig) error { return func(config *sendConfig) error {
config.endpoint = APIURL + string(chatUnfurl) config.endpoint = config.apiurl + string(chatUnfurl)
config.values.Add("ts", timestamp) config.values.Add("ts", timestamp)
unfurlsStr, err := json.Marshal(unfurls) unfurlsStr, err := json.Marshal(unfurls)
if err == nil { if err == nil {
@ -277,6 +342,17 @@ func MsgOptionUnfurl(timestamp string, unfurls map[string]Attachment) MsgOption
} }
} }
// MsgOptionResponseURL supplies a url to use as the endpoint.
func MsgOptionResponseURL(url string, rt string) MsgOption {
return func(config *sendConfig) error {
config.mode = chatResponse
config.endpoint = url
config.responseType = rt
config.values.Del("ts")
return nil
}
}
// MsgOptionAsUser whether or not to send the message as the user. // MsgOptionAsUser whether or not to send the message as the user.
func MsgOptionAsUser(b bool) MsgOption { func MsgOptionAsUser(b bool) MsgOption {
return func(config *sendConfig) error { return func(config *sendConfig) error {
@ -322,9 +398,31 @@ func MsgOptionAttachments(attachments ...Attachment) MsgOption {
return nil return nil
} }
attachments, err := json.Marshal(attachments) config.attachments = attachments
// FIXME: We are setting the attachments on the message twice: above for
// the json version, and below for the html version. The marshalled bytes
// we put into config.values below don't work directly in the Msg version.
attachmentBytes, err := json.Marshal(attachments)
if err == nil { if err == nil {
config.values.Set("attachments", string(attachments)) config.values.Set("attachments", string(attachmentBytes))
}
return err
}
}
// MsgOptionBlocks sets blocks for the message
func MsgOptionBlocks(blocks ...Block) MsgOption {
return func(config *sendConfig) error {
if blocks == nil {
return nil
}
blocks, err := json.Marshal(blocks)
if err == nil {
config.values.Set("blocks", string(blocks))
} }
return err return err
} }
@ -395,15 +493,31 @@ func MsgOptionParse(b bool) MsgOption {
return func(c *sendConfig) error { return func(c *sendConfig) error {
var v string var v string
if b { if b {
v = "1" v = "full"
} else { } else {
v = "0" v = "none"
} }
c.values.Set("parse", v) c.values.Set("parse", v)
return nil return nil
} }
} }
// MsgOptionIconURL sets an icon URL
func MsgOptionIconURL(iconURL string) MsgOption {
return func(c *sendConfig) error {
c.values.Set("icon_url", iconURL)
return nil
}
}
// MsgOptionIconEmoji sets an icon emoji
func MsgOptionIconEmoji(iconEmoji string) MsgOption {
return func(c *sendConfig) error {
c.values.Set("icon_emoji", iconEmoji)
return nil
}
}
// UnsafeMsgOptionEndpoint deliver the message to the specified endpoint. // UnsafeMsgOptionEndpoint deliver the message to the specified endpoint.
// NOTE: USE AT YOUR OWN RISK: No issues relating to the use of this Option // NOTE: USE AT YOUR OWN RISK: No issues relating to the use of this Option
// will be supported by the library, it is subject to change without notice that // will be supported by the library, it is subject to change without notice that
@ -499,7 +613,7 @@ func (api *Client) GetPermalinkContext(ctx context.Context, params *PermalinkPar
Permalink string `json:"permalink"` Permalink string `json:"permalink"`
SlackResponse SlackResponse
}{} }{}
err := getSlackMethod(ctx, api.httpclient, "chat.getPermalink", values, &response, api) err := api.getMethod(ctx, "chat.getPermalink", values, &response)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -2,14 +2,13 @@ package slack
import ( import (
"context" "context"
"errors"
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
) )
// Conversation is the foundation for IM and BaseGroupConversation // Conversation is the foundation for IM and BaseGroupConversation
type conversation struct { type Conversation struct {
ID string `json:"id"` ID string `json:"id"`
Created JSONTime `json:"created"` Created JSONTime `json:"created"`
IsOpen bool `json:"is_open"` IsOpen bool `json:"is_open"`
@ -36,8 +35,8 @@ type conversation struct {
} }
// GroupConversation is the foundation for Group and Channel // GroupConversation is the foundation for Group and Channel
type groupConversation struct { type GroupConversation struct {
conversation Conversation
Name string `json:"name"` Name string `json:"name"`
Creator string `json:"creator"` Creator string `json:"creator"`
IsArchived bool `json:"is_archived"` IsArchived bool `json:"is_archived"`
@ -71,6 +70,7 @@ type GetConversationsForUserParameters struct {
Cursor string Cursor string
Types []string Types []string
Limit int Limit int
ExcludeArchived bool
} }
type responseMetaData struct { type responseMetaData struct {
@ -99,13 +99,16 @@ func (api *Client) GetUsersInConversationContext(ctx context.Context, params *Ge
ResponseMetaData responseMetaData `json:"response_metadata"` ResponseMetaData responseMetaData `json:"response_metadata"`
SlackResponse SlackResponse
}{} }{}
err := postSlackMethod(ctx, api.httpclient, "conversations.members", values, &response, api)
err := api.postMethod(ctx, "conversations.members", values, &response)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
if !response.Ok {
return nil, "", errors.New(response.Error) if err := response.Err(); err != nil {
return nil, "", err
} }
return response.Members, response.ResponseMetaData.NextCursor, nil return response.Members, response.ResponseMetaData.NextCursor, nil
} }
@ -131,12 +134,15 @@ func (api *Client) GetConversationsForUserContext(ctx context.Context, params *G
if params.Types != nil { if params.Types != nil {
values.Add("types", strings.Join(params.Types, ",")) values.Add("types", strings.Join(params.Types, ","))
} }
if params.ExcludeArchived {
values.Add("exclude_archived", "true")
}
response := struct { response := struct {
Channels []Channel `json:"channels"` Channels []Channel `json:"channels"`
ResponseMetaData responseMetaData `json:"response_metadata"` ResponseMetaData responseMetaData `json:"response_metadata"`
SlackResponse SlackResponse
}{} }{}
err = postSlackMethod(ctx, api.httpclient, "users.conversations", values, &response, api) err = api.postMethod(ctx, "users.conversations", values, &response)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -155,8 +161,9 @@ func (api *Client) ArchiveConversationContext(ctx context.Context, channelID str
"token": {api.token}, "token": {api.token},
"channel": {channelID}, "channel": {channelID},
} }
response := SlackResponse{} response := SlackResponse{}
err := postSlackMethod(ctx, api.httpclient, "conversations.archive", values, &response, api) err := api.postMethod(ctx, "conversations.archive", values, &response)
if err != nil { if err != nil {
return err return err
} }
@ -176,7 +183,7 @@ func (api *Client) UnArchiveConversationContext(ctx context.Context, channelID s
"channel": {channelID}, "channel": {channelID},
} }
response := SlackResponse{} response := SlackResponse{}
err := postSlackMethod(ctx, api.httpclient, "conversations.unarchive", values, &response, api) err := api.postMethod(ctx, "conversations.unarchive", values, &response)
if err != nil { if err != nil {
return err return err
} }
@ -200,7 +207,7 @@ func (api *Client) SetTopicOfConversationContext(ctx context.Context, channelID,
SlackResponse SlackResponse
Channel *Channel `json:"channel"` Channel *Channel `json:"channel"`
}{} }{}
err := postSlackMethod(ctx, api.httpclient, "conversations.setTopic", values, &response, api) err := api.postMethod(ctx, "conversations.setTopic", values, &response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -224,7 +231,8 @@ func (api *Client) SetPurposeOfConversationContext(ctx context.Context, channelI
SlackResponse SlackResponse
Channel *Channel `json:"channel"` Channel *Channel `json:"channel"`
}{} }{}
err := postSlackMethod(ctx, api.httpclient, "conversations.setPurpose", values, &response, api)
err := api.postMethod(ctx, "conversations.setPurpose", values, &response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -248,7 +256,8 @@ func (api *Client) RenameConversationContext(ctx context.Context, channelID, cha
SlackResponse SlackResponse
Channel *Channel `json:"channel"` Channel *Channel `json:"channel"`
}{} }{}
err := postSlackMethod(ctx, api.httpclient, "conversations.rename", values, &response, api)
err := api.postMethod(ctx, "conversations.rename", values, &response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -272,7 +281,8 @@ func (api *Client) InviteUsersToConversationContext(ctx context.Context, channel
SlackResponse SlackResponse
Channel *Channel `json:"channel"` Channel *Channel `json:"channel"`
}{} }{}
err := postSlackMethod(ctx, api.httpclient, "conversations.invite", values, &response, api)
err := api.postMethod(ctx, "conversations.invite", values, &response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -292,8 +302,9 @@ func (api *Client) KickUserFromConversationContext(ctx context.Context, channelI
"channel": {channelID}, "channel": {channelID},
"user": {user}, "user": {user},
} }
response := SlackResponse{} response := SlackResponse{}
err := postSlackMethod(ctx, api.httpclient, "conversations.kick", values, &response, api) err := api.postMethod(ctx, "conversations.kick", values, &response)
if err != nil { if err != nil {
return err return err
} }
@ -318,7 +329,7 @@ func (api *Client) CloseConversationContext(ctx context.Context, channelID strin
AlreadyClosed bool `json:"already_closed"` AlreadyClosed bool `json:"already_closed"`
}{} }{}
err = postSlackMethod(ctx, api.httpclient, "conversations.close", values, &response, api) err = api.postMethod(ctx, "conversations.close", values, &response)
if err != nil { if err != nil {
return false, false, err return false, false, err
} }
@ -338,13 +349,12 @@ func (api *Client) CreateConversationContext(ctx context.Context, channelName st
"name": {channelName}, "name": {channelName},
"is_private": {strconv.FormatBool(isPrivate)}, "is_private": {strconv.FormatBool(isPrivate)},
} }
response, err := channelRequest( response, err := api.channelRequest(ctx, "conversations.create", values)
ctx, api.httpclient, "conversations.create", values, api)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &response.Channel, response.Err() return &response.Channel, nil
} }
// GetConversationInfo retrieves information about a conversation // GetConversationInfo retrieves information about a conversation
@ -359,8 +369,7 @@ func (api *Client) GetConversationInfoContext(ctx context.Context, channelID str
"channel": {channelID}, "channel": {channelID},
"include_locale": {strconv.FormatBool(includeLocale)}, "include_locale": {strconv.FormatBool(includeLocale)},
} }
response, err := channelRequest( response, err := api.channelRequest(ctx, "conversations.info", values)
ctx, api.httpclient, "conversations.info", values, api)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -380,7 +389,7 @@ func (api *Client) LeaveConversationContext(ctx context.Context, channelID strin
"channel": {channelID}, "channel": {channelID},
} }
response, err := channelRequest(ctx, api.httpclient, "conversations.leave", values, api) response, err := api.channelRequest(ctx, "conversations.leave", values)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -436,7 +445,7 @@ func (api *Client) GetConversationRepliesContext(ctx context.Context, params *Ge
Messages []Message `json:"messages"` Messages []Message `json:"messages"`
}{} }{}
err = postSlackMethod(ctx, api.httpclient, "conversations.replies", values, &response, api) err = api.postMethod(ctx, "conversations.replies", values, &response)
if err != nil { if err != nil {
return nil, false, "", err return nil, false, "", err
} }
@ -476,7 +485,8 @@ func (api *Client) GetConversationsContext(ctx context.Context, params *GetConve
ResponseMetaData responseMetaData `json:"response_metadata"` ResponseMetaData responseMetaData `json:"response_metadata"`
SlackResponse SlackResponse
}{} }{}
err = postSlackMethod(ctx, api.httpclient, "conversations.list", values, &response, api)
err = api.postMethod(ctx, "conversations.list", values, &response)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -513,7 +523,8 @@ func (api *Client) OpenConversationContext(ctx context.Context, params *OpenConv
AlreadyOpen bool `json:"already_open"` AlreadyOpen bool `json:"already_open"`
SlackResponse SlackResponse
}{} }{}
err := postSlackMethod(ctx, api.httpclient, "conversations.open", values, &response, api)
err := api.postMethod(ctx, "conversations.open", values, &response)
if err != nil { if err != nil {
return nil, false, false, err return nil, false, false, err
} }
@ -537,7 +548,8 @@ func (api *Client) JoinConversationContext(ctx context.Context, channelID string
} `json:"response_metadata"` } `json:"response_metadata"`
SlackResponse SlackResponse
}{} }{}
err := postSlackMethod(ctx, api.httpclient, "conversations.join", values, &response, api)
err := api.postMethod(ctx, "conversations.join", values, &response)
if err != nil { if err != nil {
return nil, "", nil, err return nil, "", nil, err
} }
@ -599,7 +611,7 @@ func (api *Client) GetConversationHistoryContext(ctx context.Context, params *Ge
response := GetConversationHistoryResponse{} response := GetConversationHistoryResponse{}
err := postSlackMethod(ctx, api.httpclient, "conversations.history", values, &response, api) err := api.postMethod(ctx, "conversations.history", values, &response)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,7 +3,7 @@ package slack
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "strings"
) )
// InputType is the type of the dialog input type // InputType is the type of the dialog input type
@ -25,6 +25,7 @@ type DialogInput struct {
Name string `json:"name"` Name string `json:"name"`
Placeholder string `json:"placeholder"` Placeholder string `json:"placeholder"`
Optional bool `json:"optional"` Optional bool `json:"optional"`
Hint string `json:"hint"`
} }
// DialogTrigger ... // DialogTrigger ...
@ -89,7 +90,7 @@ func (api *Client) OpenDialog(triggerID string, dialog Dialog) (err error) {
// EXPERIMENTAL: dialog functionality is currently experimental, api is not considered stable. // EXPERIMENTAL: dialog functionality is currently experimental, api is not considered stable.
func (api *Client) OpenDialogContext(ctx context.Context, triggerID string, dialog Dialog) (err error) { func (api *Client) OpenDialogContext(ctx context.Context, triggerID string, dialog Dialog) (err error) {
if triggerID == "" { if triggerID == "" {
return errors.New("received empty parameters") return ErrParametersMissing
} }
req := DialogTrigger{ req := DialogTrigger{
@ -103,10 +104,15 @@ func (api *Client) OpenDialogContext(ctx context.Context, triggerID string, dial
} }
response := &DialogOpenResponse{} response := &DialogOpenResponse{}
endpoint := APIURL + "dialog.open" endpoint := api.endpoint + "dialog.open"
if err := postJSON(ctx, api.httpclient, endpoint, api.token, encoded, response, api); err != nil { if err := postJSON(ctx, api.httpclient, endpoint, api.token, encoded, response, api); err != nil {
return err return err
} }
if len(response.DialogResponseMetadata.Messages) > 0 {
response.Ok = false
response.Error += "\n" + strings.Join(response.DialogResponseMetadata.Messages, "\n")
}
return response.Err() return response.Err()
} }

View File

@ -21,10 +21,11 @@ type DialogInputSelect struct {
DialogInput DialogInput
Value string `json:"value,omitempty"` //Optional. Value string `json:"value,omitempty"` //Optional.
DataSource SelectDataSource `json:"data_source,omitempty"` //Optional. Allowed values: "users", "channels", "conversations", "external". DataSource SelectDataSource `json:"data_source,omitempty"` //Optional. Allowed values: "users", "channels", "conversations", "external".
SelectedOptions string `json:"selected_options,omitempty"` //Optional. Default value for "external" only SelectedOptions []DialogSelectOption `json:"selected_options,omitempty"` //Optional. May hold at most one element, for use with "external" only.
Options []DialogSelectOption `json:"options,omitempty"` //One of options or option_groups is required. Options []DialogSelectOption `json:"options,omitempty"` //One of options or option_groups is required.
OptionGroups []DialogOptionGroup `json:"option_groups,omitempty"` //Provide up to 100 options. OptionGroups []DialogOptionGroup `json:"option_groups,omitempty"` //Provide up to 100 options.
MinQueryLength int `json:"min_query_length,omitempty"` //Optional. minimum characters before query is sent. MinQueryLength int `json:"min_query_length,omitempty"` //Optional. minimum characters before query is sent.
Hint string `json:"hint,omitempty"` //Optional. Additional hint text.
} }
// DialogSelectOption is an option for the user to select from the menu // DialogSelectOption is an option for the user to select from the menu
@ -54,14 +55,7 @@ func NewStaticSelectDialogInput(name, label string, options []DialogSelectOption
} }
// NewGroupedSelectDialogInput creates grouped options select input for Dialogs. // NewGroupedSelectDialogInput creates grouped options select input for Dialogs.
func NewGroupedSelectDialogInput(name, label string, groups map[string]map[string]string) *DialogInputSelect { func NewGroupedSelectDialogInput(name, label string, options []DialogOptionGroup) *DialogInputSelect {
optionGroups := []DialogOptionGroup{}
for groupName, options := range groups {
optionGroups = append(optionGroups, DialogOptionGroup{
Label: groupName,
Options: optionsFromMap(options),
})
}
return &DialogInputSelect{ return &DialogInputSelect{
DialogInput: DialogInput{ DialogInput: DialogInput{
Type: InputTypeSelect, Type: InputTypeSelect,
@ -69,34 +63,15 @@ func NewGroupedSelectDialogInput(name, label string, groups map[string]map[strin
Label: label, Label: label,
}, },
DataSource: DialogDataSourceStatic, DataSource: DialogDataSourceStatic,
OptionGroups: optionGroups, OptionGroups: options}
}
} }
func optionsFromArray(options []string) []DialogSelectOption { // NewDialogOptionGroup creates a DialogOptionGroup from several select options
selectOptions := make([]DialogSelectOption, len(options)) func NewDialogOptionGroup(label string, options ...DialogSelectOption) DialogOptionGroup {
for idx, value := range options { return DialogOptionGroup{
selectOptions[idx] = DialogSelectOption{ Label: label,
Label: value, Options: options,
Value: value,
} }
}
return selectOptions
}
func optionsFromMap(options map[string]string) []DialogSelectOption {
selectOptions := make([]DialogSelectOption, len(options))
idx := 0
var option DialogSelectOption
for key, value := range options {
option = DialogSelectOption{
Label: key,
Value: value,
}
selectOptions[idx] = option
idx++
}
return selectOptions
} }
// NewConversationsSelect returns a `Conversations` select // NewConversationsSelect returns a `Conversations` select

View File

@ -3,6 +3,9 @@ package slack
// TextInputSubtype Accepts email, number, tel, or url. In some form factors, optimized input is provided for this subtype. // TextInputSubtype Accepts email, number, tel, or url. In some form factors, optimized input is provided for this subtype.
type TextInputSubtype string type TextInputSubtype string
// TextInputOption handle to extra inputs options.
type TextInputOption func(*TextInputElement)
const ( const (
// InputSubtypeEmail email keyboard // InputSubtypeEmail email keyboard
InputSubtypeEmail TextInputSubtype = "email" InputSubtypeEmail TextInputSubtype = "email"
@ -26,8 +29,8 @@ type TextInputElement struct {
} }
// NewTextInput constructor for a `text` input // NewTextInput constructor for a `text` input
func NewTextInput(name, label, text string) *TextInputElement { func NewTextInput(name, label, text string, options ...TextInputOption) *TextInputElement {
return &TextInputElement{ t := &TextInputElement{
DialogInput: DialogInput{ DialogInput: DialogInput{
Type: InputTypeText, Type: InputTypeText,
Name: name, Name: name,
@ -35,6 +38,12 @@ func NewTextInput(name, label, text string) *TextInputElement {
}, },
Value: text, Value: text,
} }
for _, opt := range options {
opt(t)
}
return t
} }
// NewTextAreaInput constructor for a `textarea` input // NewTextAreaInput constructor for a `textarea` input

View File

@ -2,7 +2,6 @@ package slack
import ( import (
"context" "context"
"errors"
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
@ -36,16 +35,14 @@ type dndTeamInfoResponse struct {
SlackResponse SlackResponse
} }
func dndRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*dndResponseFull, error) { func (api *Client) dndRequest(ctx context.Context, path string, values url.Values) (*dndResponseFull, error) {
response := &dndResponseFull{} response := &dndResponseFull{}
err := postSlackMethod(ctx, client, path, values, response, d) err := api.postMethod(ctx, path, values, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !response.Ok {
return nil, errors.New(response.Error) return response, response.Err()
}
return response, nil
} }
// EndDND ends the user's scheduled Do Not Disturb session // EndDND ends the user's scheduled Do Not Disturb session
@ -61,7 +58,7 @@ func (api *Client) EndDNDContext(ctx context.Context) error {
response := &SlackResponse{} response := &SlackResponse{}
if err := postSlackMethod(ctx, api.httpclient, "dnd.endDnd", values, response, api); err != nil { if err := api.postMethod(ctx, "dnd.endDnd", values, response); err != nil {
return err return err
} }
@ -79,7 +76,7 @@ func (api *Client) EndSnoozeContext(ctx context.Context) (*DNDStatus, error) {
"token": {api.token}, "token": {api.token},
} }
response, err := dndRequest(ctx, api.httpclient, "dnd.endSnooze", values, api) response, err := api.dndRequest(ctx, "dnd.endSnooze", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -100,7 +97,7 @@ func (api *Client) GetDNDInfoContext(ctx context.Context, user *string) (*DNDSta
values.Set("user", *user) values.Set("user", *user)
} }
response, err := dndRequest(ctx, api.httpclient, "dnd.info", values, api) response, err := api.dndRequest(ctx, "dnd.info", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -120,13 +117,14 @@ func (api *Client) GetDNDTeamInfoContext(ctx context.Context, users []string) (m
} }
response := &dndTeamInfoResponse{} response := &dndTeamInfoResponse{}
if err := postSlackMethod(ctx, api.httpclient, "dnd.teamInfo", values, response, api); err != nil { if err := api.postMethod(ctx, "dnd.teamInfo", values, response); err != nil {
return nil, err return nil, err
} }
if response.Err() != nil { if response.Err() != nil {
return nil, response.Err() return nil, response.Err()
} }
return response.Users, nil return response.Users, nil
} }
@ -137,7 +135,7 @@ func (api *Client) SetSnooze(minutes int) (*DNDStatus, error) {
return api.SetSnoozeContext(context.Background(), minutes) return api.SetSnoozeContext(context.Background(), minutes)
} }
// SetSnooze adjusts the snooze duration for a user's Do Not Disturb settings with a custom context. // SetSnoozeContext adjusts the snooze duration for a user's Do Not Disturb settings with a custom context.
// For more information see the SetSnooze docs // For more information see the SetSnooze docs
func (api *Client) SetSnoozeContext(ctx context.Context, minutes int) (*DNDStatus, error) { func (api *Client) SetSnoozeContext(ctx context.Context, minutes int) (*DNDStatus, error) {
values := url.Values{ values := url.Values{
@ -145,7 +143,7 @@ func (api *Client) SetSnoozeContext(ctx context.Context, minutes int) (*DNDStatu
"num_minutes": {strconv.Itoa(minutes)}, "num_minutes": {strconv.Itoa(minutes)},
} }
response, err := dndRequest(ctx, api.httpclient, "dnd.setSnooze", values, api) response, err := api.dndRequest(ctx, "dnd.setSnooze", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -2,7 +2,6 @@ package slack
import ( import (
"context" "context"
"errors"
"net/url" "net/url"
) )
@ -23,12 +22,14 @@ func (api *Client) GetEmojiContext(ctx context.Context) (map[string]string, erro
} }
response := &emojiResponseFull{} response := &emojiResponseFull{}
err := postSlackMethod(ctx, api.httpclient, "emoji.list", values, response, api) err := api.postMethod(ctx, "emoji.list", values, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !response.Ok {
return nil, errors.New(response.Error) if response.Err() != nil {
return nil, response.Err()
} }
return response.Emoji, nil return response.Emoji, nil
} }

18
vendor/github.com/nlopes/slack/errors.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
package slack
import "github.com/nlopes/slack/internal/errorsx"
// Errors returned by various methods.
const (
ErrAlreadyDisconnected = errorsx.String("Invalid call to Disconnect - Slack API is already disconnected")
ErrRTMDisconnected = errorsx.String("disconnect received while trying to connect")
ErrParametersMissing = errorsx.String("received empty parameters")
ErrInvalidConfiguration = errorsx.String("invalid configuration")
ErrMissingHeaders = errorsx.String("missing headers")
ErrExpiredTimestamp = errorsx.String("timestamp is too old")
)
// internal errors
const (
errPaginationComplete = errorsx.String("pagination complete")
)

View File

@ -2,7 +2,6 @@ package slack
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"net/url" "net/url"
@ -92,6 +91,7 @@ type File struct {
type Share struct { type Share struct {
Public map[string][]ShareFileInfo `json:"public"` Public map[string][]ShareFileInfo `json:"public"`
Private map[string][]ShareFileInfo `json:"private"`
} }
type ShareFileInfo struct { type ShareFileInfo struct {
@ -134,11 +134,21 @@ type GetFilesParameters struct {
Page int Page int
} }
// ListFilesParameters contains all the parameters necessary (including the optional ones) for a ListFiles() request
type ListFilesParameters struct {
Limit int
User string
Channel string
Types string
Cursor string
}
type fileResponseFull struct { type fileResponseFull struct {
File `json:"file"` File `json:"file"`
Paging `json:"paging"` Paging `json:"paging"`
Comments []Comment `json:"comments"` Comments []Comment `json:"comments"`
Files []File `json:"files"` Files []File `json:"files"`
Metadata ResponseMetadata `json:"response_metadata"`
SlackResponse SlackResponse
} }
@ -156,9 +166,9 @@ func NewGetFilesParameters() GetFilesParameters {
} }
} }
func fileRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*fileResponseFull, error) { func (api *Client) fileRequest(ctx context.Context, path string, values url.Values) (*fileResponseFull, error) {
response := &fileResponseFull{} response := &fileResponseFull{}
err := postForm(ctx, client, APIURL+path, values, response, d) err := api.postMethod(ctx, path, values, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -180,18 +190,57 @@ func (api *Client) GetFileInfoContext(ctx context.Context, fileID string, count,
"page": {strconv.Itoa(page)}, "page": {strconv.Itoa(page)},
} }
response, err := fileRequest(ctx, api.httpclient, "files.info", values, api) response, err := api.fileRequest(ctx, "files.info", values)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
return &response.File, response.Comments, &response.Paging, nil return &response.File, response.Comments, &response.Paging, nil
} }
// GetFile retreives a given file from its private download URL
func (api *Client) GetFile(downloadURL string, writer io.Writer) error {
return downloadFile(api.httpclient, api.token, downloadURL, writer, api)
}
// GetFiles retrieves all files according to the parameters given // GetFiles retrieves all files according to the parameters given
func (api *Client) GetFiles(params GetFilesParameters) ([]File, *Paging, error) { func (api *Client) GetFiles(params GetFilesParameters) ([]File, *Paging, error) {
return api.GetFilesContext(context.Background(), params) return api.GetFilesContext(context.Background(), params)
} }
// ListFiles retrieves all files according to the parameters given. Uses cursor based pagination.
func (api *Client) ListFiles(params ListFilesParameters) ([]File, *ListFilesParameters, error) {
return api.ListFilesContext(context.Background(), params)
}
// ListFilesContext retrieves all files according to the parameters given with a custom context. Uses cursor based pagination.
func (api *Client) ListFilesContext(ctx context.Context, params ListFilesParameters) ([]File, *ListFilesParameters, error) {
values := url.Values{
"token": {api.token},
}
if params.User != DEFAULT_FILES_USER {
values.Add("user", params.User)
}
if params.Channel != DEFAULT_FILES_CHANNEL {
values.Add("channel", params.Channel)
}
if params.Limit != DEFAULT_FILES_COUNT {
values.Add("limit", strconv.Itoa(params.Limit))
}
if params.Cursor != "" {
values.Add("cursor", params.Cursor)
}
response, err := api.fileRequest(ctx, "files.list", values)
if err != nil {
return nil, nil, err
}
params.Cursor = response.Metadata.Cursor
return response.Files, &params, nil
}
// GetFilesContext retrieves all files according to the parameters given with a custom context // GetFilesContext retrieves all files according to the parameters given with a custom context
func (api *Client) GetFilesContext(ctx context.Context, params GetFilesParameters) ([]File, *Paging, error) { func (api *Client) GetFilesContext(ctx context.Context, params GetFilesParameters) ([]File, *Paging, error) {
values := url.Values{ values := url.Values{
@ -219,7 +268,7 @@ func (api *Client) GetFilesContext(ctx context.Context, params GetFilesParameter
values.Add("page", strconv.Itoa(params.Page)) values.Add("page", strconv.Itoa(params.Page))
} }
response, err := fileRequest(ctx, api.httpclient, "files.list", values, api) response, err := api.fileRequest(ctx, "files.list", values)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -239,9 +288,6 @@ func (api *Client) UploadFileContext(ctx context.Context, params FileUploadParam
if err != nil { if err != nil {
return nil, err return nil, err
} }
if params.Filename == "" {
return nil, fmt.Errorf("files.upload: FileUploadParameters.Filename is mandatory")
}
response := &fileResponseFull{} response := &fileResponseFull{}
values := url.Values{ values := url.Values{
"token": {api.token}, "token": {api.token},
@ -266,12 +312,16 @@ func (api *Client) UploadFileContext(ctx context.Context, params FileUploadParam
} }
if params.Content != "" { if params.Content != "" {
values.Add("content", params.Content) values.Add("content", params.Content)
err = postForm(ctx, api.httpclient, APIURL+"files.upload", values, response, api) err = api.postMethod(ctx, "files.upload", values, response)
} else if params.File != "" { } else if params.File != "" {
err = postLocalWithMultipartResponse(ctx, api.httpclient, "files.upload", params.File, "file", values, response, api) err = postLocalWithMultipartResponse(ctx, api.httpclient, api.endpoint+"files.upload", params.File, "file", values, response, api)
} else if params.Reader != nil { } else if params.Reader != nil {
err = postWithMultipartResponse(ctx, api.httpclient, "files.upload", params.Filename, "file", values, params.Reader, response, api) if params.Filename == "" {
return nil, fmt.Errorf("files.upload: FileUploadParameters.Filename is mandatory when using FileUploadParameters.Reader")
} }
err = postWithMultipartResponse(ctx, api.httpclient, api.endpoint+"files.upload", params.Filename, "file", values, params.Reader, response, api)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -287,7 +337,7 @@ func (api *Client) DeleteFileComment(commentID, fileID string) error {
// DeleteFileCommentContext deletes a file's comment with a custom context // DeleteFileCommentContext deletes a file's comment with a custom context
func (api *Client) DeleteFileCommentContext(ctx context.Context, fileID, commentID string) (err error) { func (api *Client) DeleteFileCommentContext(ctx context.Context, fileID, commentID string) (err error) {
if fileID == "" || commentID == "" { if fileID == "" || commentID == "" {
return errors.New("received empty parameters") return ErrParametersMissing
} }
values := url.Values{ values := url.Values{
@ -295,7 +345,7 @@ func (api *Client) DeleteFileCommentContext(ctx context.Context, fileID, comment
"file": {fileID}, "file": {fileID},
"id": {commentID}, "id": {commentID},
} }
_, err = fileRequest(ctx, api.httpclient, "files.comments.delete", values, api) _, err = api.fileRequest(ctx, "files.comments.delete", values)
return err return err
} }
@ -311,7 +361,7 @@ func (api *Client) DeleteFileContext(ctx context.Context, fileID string) (err er
"file": {fileID}, "file": {fileID},
} }
_, err = fileRequest(ctx, api.httpclient, "files.delete", values, api) _, err = api.fileRequest(ctx, "files.delete", values)
return err return err
} }
@ -327,7 +377,7 @@ func (api *Client) RevokeFilePublicURLContext(ctx context.Context, fileID string
"file": {fileID}, "file": {fileID},
} }
response, err := fileRequest(ctx, api.httpclient, "files.revokePublicURL", values, api) response, err := api.fileRequest(ctx, "files.revokePublicURL", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -346,7 +396,7 @@ func (api *Client) ShareFilePublicURLContext(ctx context.Context, fileID string)
"file": {fileID}, "file": {fileID},
} }
response, err := fileRequest(ctx, api.httpclient, "files.sharedPublicURL", values, api) response, err := api.fileRequest(ctx, "files.sharedPublicURL", values)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }

9
vendor/github.com/nlopes/slack/go.mod generated vendored Normal file
View File

@ -0,0 +1,9 @@
module github.com/nlopes/slack
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gorilla/websocket v1.2.0
github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
)

22
vendor/github.com/nlopes/slack/go.sum generated vendored Normal file
View File

@ -0,0 +1,22 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/nlopes/slack v0.1.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM=
github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0=
github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/victorcoder/slack-test v0.0.0-20190131110821-6f9a569c10af h1:JFxr+No3ZWgCtxnnTWCybnB/z0Iy3qLmdj3u2NV5o48=
github.com/victorcoder/slack-test v0.0.0-20190131110821-6f9a569c10af/go.mod h1:dStM4ShMus8J3hiq66ExbbzGLkwyZ+RQJePwFhWCCvQ=
github.com/victorcoder/slack-test v0.0.0-20190131113129-a43b3bb77f43 h1:wtFekkaAAQibpy3iE4Hhx2Gi9pZAbITOSfVP7GXk5eM=
github.com/victorcoder/slack-test v0.0.0-20190131113129-a43b3bb77f43/go.mod h1:dStM4ShMus8J3hiq66ExbbzGLkwyZ+RQJePwFhWCCvQ=
golang.org/x/net v0.0.0-20180108090419-434ec0c7fe37 h1:BkNcmLtAVeWe9h5k0jt24CQgaG5vb4x/doFbAiEC/Ho=
golang.org/x/net v0.0.0-20180108090419-434ec0c7fe37/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View File

@ -8,7 +8,7 @@ import (
// Group contains all the information for a group // Group contains all the information for a group
type Group struct { type Group struct {
groupConversation GroupConversation
IsGroup bool `json:"is_group"` IsGroup bool `json:"is_group"`
} }
@ -27,9 +27,9 @@ type groupResponseFull struct {
SlackResponse SlackResponse
} }
func groupRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*groupResponseFull, error) { func (api *Client) groupRequest(ctx context.Context, path string, values url.Values) (*groupResponseFull, error) {
response := &groupResponseFull{} response := &groupResponseFull{}
err := postForm(ctx, client, APIURL+path, values, response, d) err := api.postMethod(ctx, path, values, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -49,7 +49,7 @@ func (api *Client) ArchiveGroupContext(ctx context.Context, group string) error
"channel": {group}, "channel": {group},
} }
_, err := groupRequest(ctx, api.httpclient, "groups.archive", values, api) _, err := api.groupRequest(ctx, "groups.archive", values)
return err return err
} }
@ -65,7 +65,7 @@ func (api *Client) UnarchiveGroupContext(ctx context.Context, group string) erro
"channel": {group}, "channel": {group},
} }
_, err := groupRequest(ctx, api.httpclient, "groups.unarchive", values, api) _, err := api.groupRequest(ctx, "groups.unarchive", values)
return err return err
} }
@ -81,7 +81,7 @@ func (api *Client) CreateGroupContext(ctx context.Context, group string) (*Group
"name": {group}, "name": {group},
} }
response, err := groupRequest(ctx, api.httpclient, "groups.create", values, api) response, err := api.groupRequest(ctx, "groups.create", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -106,7 +106,7 @@ func (api *Client) CreateChildGroupContext(ctx context.Context, group string) (*
"channel": {group}, "channel": {group},
} }
response, err := groupRequest(ctx, api.httpclient, "groups.createChild", values, api) response, err := api.groupRequest(ctx, "groups.createChild", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -148,7 +148,7 @@ func (api *Client) GetGroupHistoryContext(ctx context.Context, group string, par
} }
} }
response, err := groupRequest(ctx, api.httpclient, "groups.history", values, api) response, err := api.groupRequest(ctx, "groups.history", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -168,7 +168,7 @@ func (api *Client) InviteUserToGroupContext(ctx context.Context, group, user str
"user": {user}, "user": {user},
} }
response, err := groupRequest(ctx, api.httpclient, "groups.invite", values, api) response, err := api.groupRequest(ctx, "groups.invite", values)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
@ -187,7 +187,7 @@ func (api *Client) LeaveGroupContext(ctx context.Context, group string) (err err
"channel": {group}, "channel": {group},
} }
_, err = groupRequest(ctx, api.httpclient, "groups.leave", values, api) _, err = api.groupRequest(ctx, "groups.leave", values)
return err return err
} }
@ -204,7 +204,7 @@ func (api *Client) KickUserFromGroupContext(ctx context.Context, group, user str
"user": {user}, "user": {user},
} }
_, err = groupRequest(ctx, api.httpclient, "groups.kick", values, api) _, err = api.groupRequest(ctx, "groups.kick", values)
return err return err
} }
@ -222,7 +222,7 @@ func (api *Client) GetGroupsContext(ctx context.Context, excludeArchived bool) (
values.Add("exclude_archived", "1") values.Add("exclude_archived", "1")
} }
response, err := groupRequest(ctx, api.httpclient, "groups.list", values, api) response, err := api.groupRequest(ctx, "groups.list", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -242,7 +242,7 @@ func (api *Client) GetGroupInfoContext(ctx context.Context, group string) (*Grou
"include_locale": {strconv.FormatBool(true)}, "include_locale": {strconv.FormatBool(true)},
} }
response, err := groupRequest(ctx, api.httpclient, "groups.info", values, api) response, err := api.groupRequest(ctx, "groups.info", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -267,7 +267,7 @@ func (api *Client) SetGroupReadMarkContext(ctx context.Context, group, ts string
"ts": {ts}, "ts": {ts},
} }
_, err = groupRequest(ctx, api.httpclient, "groups.mark", values, api) _, err = api.groupRequest(ctx, "groups.mark", values)
return err return err
} }
@ -283,7 +283,7 @@ func (api *Client) OpenGroupContext(ctx context.Context, group string) (bool, bo
"channel": {group}, "channel": {group},
} }
response, err := groupRequest(ctx, api.httpclient, "groups.open", values, api) response, err := api.groupRequest(ctx, "groups.open", values)
if err != nil { if err != nil {
return false, false, err return false, false, err
} }
@ -307,7 +307,7 @@ func (api *Client) RenameGroupContext(ctx context.Context, group, name string) (
// XXX: the created entry in this call returns a string instead of a number // XXX: the created entry in this call returns a string instead of a number
// so I may have to do some workaround to solve it. // so I may have to do some workaround to solve it.
response, err := groupRequest(ctx, api.httpclient, "groups.rename", values, api) response, err := api.groupRequest(ctx, "groups.rename", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -327,7 +327,7 @@ func (api *Client) SetGroupPurposeContext(ctx context.Context, group, purpose st
"purpose": {purpose}, "purpose": {purpose},
} }
response, err := groupRequest(ctx, api.httpclient, "groups.setPurpose", values, api) response, err := api.groupRequest(ctx, "groups.setPurpose", values)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -347,7 +347,7 @@ func (api *Client) SetGroupTopicContext(ctx context.Context, group, topic string
"topic": {topic}, "topic": {topic},
} }
response, err := groupRequest(ctx, api.httpclient, "groups.setTopic", values, api) response, err := api.groupRequest(ctx, "groups.setTopic", values)
if err != nil { if err != nil {
return "", err return "", err
} }

18
vendor/github.com/nlopes/slack/im.go generated vendored
View File

@ -22,15 +22,13 @@ type imResponseFull struct {
// IM contains information related to the Direct Message channel // IM contains information related to the Direct Message channel
type IM struct { type IM struct {
conversation Conversation
IsIM bool `json:"is_im"`
User string `json:"user"`
IsUserDeleted bool `json:"is_user_deleted"` IsUserDeleted bool `json:"is_user_deleted"`
} }
func imRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*imResponseFull, error) { func (api *Client) imRequest(ctx context.Context, path string, values url.Values) (*imResponseFull, error) {
response := &imResponseFull{} response := &imResponseFull{}
err := postSlackMethod(ctx, client, path, values, response, d) err := api.postMethod(ctx, path, values, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -50,7 +48,7 @@ func (api *Client) CloseIMChannelContext(ctx context.Context, channel string) (b
"channel": {channel}, "channel": {channel},
} }
response, err := imRequest(ctx, api.httpclient, "im.close", values, api) response, err := api.imRequest(ctx, "im.close", values)
if err != nil { if err != nil {
return false, false, err return false, false, err
} }
@ -71,7 +69,7 @@ func (api *Client) OpenIMChannelContext(ctx context.Context, user string) (bool,
"user": {user}, "user": {user},
} }
response, err := imRequest(ctx, api.httpclient, "im.open", values, api) response, err := api.imRequest(ctx, "im.open", values)
if err != nil { if err != nil {
return false, false, "", err return false, false, "", err
} }
@ -91,7 +89,7 @@ func (api *Client) MarkIMChannelContext(ctx context.Context, channel, ts string)
"ts": {ts}, "ts": {ts},
} }
_, err := imRequest(ctx, api.httpclient, "im.mark", values, api) _, err := api.imRequest(ctx, "im.mark", values)
return err return err
} }
@ -130,7 +128,7 @@ func (api *Client) GetIMHistoryContext(ctx context.Context, channel string, para
} }
} }
response, err := imRequest(ctx, api.httpclient, "im.history", values, api) response, err := api.imRequest(ctx, "im.history", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -148,7 +146,7 @@ func (api *Client) GetIMChannelsContext(ctx context.Context) ([]IM, error) {
"token": {api.token}, "token": {api.token},
} }
response, err := imRequest(ctx, api.httpclient, "im.list", values, api) response, err := api.imRequest(ctx, "im.list", values)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -156,17 +156,12 @@ type Icons struct {
Image72 string `json:"image_72,omitempty"` Image72 string `json:"image_72,omitempty"`
} }
// Info contains various details about Users, Channels, Bots and the authenticated user. // Info contains various details about the authenticated user and team.
// It is returned by StartRTM or included in the "ConnectedEvent" RTM event. // It is returned by StartRTM or included in the "ConnectedEvent" RTM event.
type Info struct { type Info struct {
URL string `json:"url,omitempty"` URL string `json:"url,omitempty"`
User *UserDetails `json:"self,omitempty"` User *UserDetails `json:"self,omitempty"`
Team *Team `json:"team,omitempty"` Team *Team `json:"team,omitempty"`
Users []User `json:"users,omitempty"`
Channels []Channel `json:"channels,omitempty"`
Groups []Group `json:"groups,omitempty"`
Bots []Bot `json:"bots,omitempty"`
IMs []IM `json:"ims,omitempty"`
} }
type infoResponseFull struct { type infoResponseFull struct {
@ -174,52 +169,27 @@ type infoResponseFull struct {
SlackResponse SlackResponse
} }
// GetBotByID returns a bot given a bot id // GetBotByID is deprecated and returns nil
func (info Info) GetBotByID(botID string) *Bot { func (info Info) GetBotByID(botID string) *Bot {
for _, bot := range info.Bots {
if bot.ID == botID {
return &bot
}
}
return nil return nil
} }
// GetUserByID returns a user given a user id // GetUserByID is deprecated and returns nil
func (info Info) GetUserByID(userID string) *User { func (info Info) GetUserByID(userID string) *User {
for _, user := range info.Users {
if user.ID == userID {
return &user
}
}
return nil return nil
} }
// GetChannelByID returns a channel given a channel id // GetChannelByID is deprecated and returns nil
func (info Info) GetChannelByID(channelID string) *Channel { func (info Info) GetChannelByID(channelID string) *Channel {
for _, channel := range info.Channels {
if channel.ID == channelID {
return &channel
}
}
return nil return nil
} }
// GetGroupByID returns a group given a group id // GetGroupByID is deprecated and returns nil
func (info Info) GetGroupByID(groupID string) *Group { func (info Info) GetGroupByID(groupID string) *Group {
for _, group := range info.Groups {
if group.ID == groupID {
return &group
}
}
return nil return nil
} }
// GetIMByID returns an IM given an IM id // GetIMByID is deprecated and returns nil
func (info Info) GetIMByID(imID string) *IM { func (info Info) GetIMByID(imID string) *IM {
for _, im := range info.IMs {
if im.ID == imID {
return &im
}
}
return nil return nil
} }

View File

@ -1,8 +1,20 @@
package slack package slack
import (
"encoding/json"
)
// InteractionType type of interactions // InteractionType type of interactions
type InteractionType string type InteractionType string
// ActionType type represents the type of action (attachment, block, etc.)
type actionType string
// action is an interface that should be implemented by all callback action types
type action interface {
actionType() actionType
}
// Types of interactions that can be received. // Types of interactions that can be received.
const ( const (
InteractionTypeDialogCancellation = InteractionType("dialog_cancellation") InteractionTypeDialogCancellation = InteractionType("dialog_cancellation")
@ -10,6 +22,7 @@ const (
InteractionTypeDialogSuggestion = InteractionType("dialog_suggestion") InteractionTypeDialogSuggestion = InteractionType("dialog_suggestion")
InteractionTypeInteractionMessage = InteractionType("interactive_message") InteractionTypeInteractionMessage = InteractionType("interactive_message")
InteractionTypeMessageAction = InteractionType("message_action") InteractionTypeMessageAction = InteractionType("message_action")
InteractionTypeBlockActions = InteractionType("block_actions")
) )
// InteractionCallback is sent from slack when a user interactions with a button or dialog. // InteractionCallback is sent from slack when a user interactions with a button or dialog.
@ -27,6 +40,59 @@ type InteractionCallback struct {
Message Message `json:"message"` Message Message `json:"message"`
Name string `json:"name"` Name string `json:"name"`
Value string `json:"value"` Value string `json:"value"`
ActionCallback MessageTs string `json:"message_ts"`
AttachmentID string `json:"attachment_id"`
ActionCallback ActionCallbacks `json:"actions"`
DialogSubmissionCallback DialogSubmissionCallback
} }
// ActionCallback is a convenience struct defined to allow dynamic unmarshalling of
// the "actions" value in Slack's JSON response, which varies depending on block type
type ActionCallbacks struct {
AttachmentActions []*AttachmentAction
BlockActions []*BlockAction
}
// UnmarshalJSON implements the Marshaller interface in order to delegate
// marshalling and allow for proper type assertion when decoding the response
func (a *ActionCallbacks) UnmarshalJSON(data []byte) error {
var raw []json.RawMessage
err := json.Unmarshal(data, &raw)
if err != nil {
return err
}
for _, r := range raw {
var obj map[string]interface{}
err := json.Unmarshal(r, &obj)
if err != nil {
return err
}
if _, ok := obj["block_id"].(string); ok {
action, err := unmarshalAction(r, &BlockAction{})
if err != nil {
return err
}
a.BlockActions = append(a.BlockActions, action.(*BlockAction))
return nil
}
action, err := unmarshalAction(r, &AttachmentAction{})
if err != nil {
return err
}
a.AttachmentActions = append(a.AttachmentActions, action.(*AttachmentAction))
}
return nil
}
func unmarshalAction(r json.RawMessage, callbackAction action) (action, error) {
err := json.Unmarshal(r, callbackAction)
if err != nil {
return nil, err
}
return callbackAction, nil
}

View File

@ -0,0 +1,8 @@
package errorsx
// String representing an error, useful for declaring string constants as errors.
type String string
func (t String) Error() string {
return string(t)
}

18
vendor/github.com/nlopes/slack/internal/timex/timex.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
package timex
import "time"
// Max returns the maximum duration
func Max(values ...time.Duration) time.Duration {
var (
max time.Duration
)
for _, v := range values {
if v > max {
max = v
}
}
return max
}

View File

@ -16,6 +16,7 @@ type OutgoingMessage struct {
type Message struct { type Message struct {
Msg Msg
SubMessage *Msg `json:"message,omitempty"` SubMessage *Msg `json:"message,omitempty"`
PreviousMessage *Msg `json:"previous_message,omitempty"`
} }
// Msg contains information about a slack message // Msg contains information about a slack message
@ -92,8 +93,18 @@ type Msg struct {
ResponseType string `json:"response_type,omitempty"` ResponseType string `json:"response_type,omitempty"`
ReplaceOriginal bool `json:"replace_original"` ReplaceOriginal bool `json:"replace_original"`
DeleteOriginal bool `json:"delete_original"` DeleteOriginal bool `json:"delete_original"`
// Block type Message
Blocks Blocks `json:"blocks,omitempty"`
} }
const (
// ResponseTypeInChannel in channel response for slash commands.
ResponseTypeInChannel = "in_channel"
// ResponseTypeEphemeral ephemeral respone for slash commands.
ResponseTypeEphemeral = "ephemeral"
)
// Icon is used for bot messages // Icon is used for bot messages
type Icon struct { type Icon struct {
IconURL string `json:"icon_url,omitempty"` IconURL string `json:"icon_url,omitempty"`

View File

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"mime"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
@ -48,34 +49,98 @@ type statusCodeError struct {
} }
func (t statusCodeError) Error() string { func (t statusCodeError) Error() string {
// TODO: this is a bad error string, should clean it up with a breaking changes return fmt.Sprintf("slack server error: %s", t.Status)
// merger.
return fmt.Sprintf("Slack server error: %s.", t.Status)
} }
func (t statusCodeError) HTTPStatusCode() int { func (t statusCodeError) HTTPStatusCode() int {
return t.Code return t.Code
} }
func (t statusCodeError) Retryable() bool {
if t.Code >= 500 || t.Code == http.StatusTooManyRequests {
return true
}
return false
}
// RateLimitedError represents the rate limit respond from slack
type RateLimitedError struct { type RateLimitedError struct {
RetryAfter time.Duration RetryAfter time.Duration
} }
func (e *RateLimitedError) Error() string { func (e *RateLimitedError) Error() string {
return fmt.Sprintf("Slack rate limit exceeded, retry after %s", e.RetryAfter) return fmt.Sprintf("slack rate limit exceeded, retry after %s", e.RetryAfter)
}
func (e *RateLimitedError) Retryable() bool {
return true
} }
func fileUploadReq(ctx context.Context, path string, values url.Values, r io.Reader) (*http.Request, error) { func fileUploadReq(ctx context.Context, path string, values url.Values, r io.Reader) (*http.Request, error) {
req, err := http.NewRequest("POST", path, r) req, err := http.NewRequest("POST", path, r)
req = req.WithContext(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
req = req.WithContext(ctx)
req.URL.RawQuery = (values).Encode() req.URL.RawQuery = (values).Encode()
return req, nil return req, nil
} }
func downloadFile(client httpClient, token string, downloadURL string, writer io.Writer, d debug) error {
if downloadURL == "" {
return fmt.Errorf("received empty download URL")
}
req, err := http.NewRequest("GET", downloadURL, &bytes.Buffer{})
if err != nil {
return err
}
var bearer = "Bearer " + token
req.Header.Add("Authorization", bearer)
req.WithContext(context.Background())
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
err = checkStatusCode(resp, d)
if err != nil {
return err
}
_, err = io.Copy(writer, resp.Body)
return err
}
func formReq(endpoint string, values url.Values) (req *http.Request, err error) {
if req, err = http.NewRequest("POST", endpoint, strings.NewReader(values.Encode())); err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
return req, nil
}
func jsonReq(endpoint string, body interface{}) (req *http.Request, err error) {
buffer := bytes.NewBuffer([]byte{})
if err = json.NewEncoder(buffer).Encode(body); err != nil {
return nil, err
}
if req, err = http.NewRequest("POST", endpoint, buffer); err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
return req, nil
}
func parseResponseBody(body io.ReadCloser, intf interface{}, d debug) error { func parseResponseBody(body io.ReadCloser, intf interface{}, d debug) error {
response, err := ioutil.ReadAll(body) response, err := ioutil.ReadAll(body)
if err != nil { if err != nil {
@ -89,7 +154,7 @@ func parseResponseBody(body io.ReadCloser, intf interface{}, d debug) error {
return json.Unmarshal(response, intf) return json.Unmarshal(response, intf)
} }
func postLocalWithMultipartResponse(ctx context.Context, client httpClient, path, fpath, fieldname string, values url.Values, intf interface{}, d debug) error { func postLocalWithMultipartResponse(ctx context.Context, client httpClient, method, fpath, fieldname string, values url.Values, intf interface{}, d debug) error {
fullpath, err := filepath.Abs(fpath) fullpath, err := filepath.Abs(fpath)
if err != nil { if err != nil {
return err return err
@ -99,7 +164,8 @@ func postLocalWithMultipartResponse(ctx context.Context, client httpClient, path
return err return err
} }
defer file.Close() defer file.Close()
return postWithMultipartResponse(ctx, client, path, filepath.Base(fpath), fieldname, values, file, intf, d)
return postWithMultipartResponse(ctx, client, method, filepath.Base(fpath), fieldname, values, file, intf, d)
} }
func postWithMultipartResponse(ctx context.Context, client httpClient, path, name, fieldname string, values url.Values, r io.Reader, intf interface{}, d debug) error { func postWithMultipartResponse(ctx context.Context, client httpClient, path, name, fieldname string, values url.Values, r io.Reader, intf interface{}, d debug) error {
@ -123,7 +189,7 @@ func postWithMultipartResponse(ctx context.Context, client httpClient, path, nam
return return
} }
}() }()
req, err := fileUploadReq(ctx, APIURL+path, values, pipeReader) req, err := fileUploadReq(ctx, path, values, pipeReader)
if err != nil { if err != nil {
return err return err
} }
@ -136,28 +202,20 @@ func postWithMultipartResponse(ctx context.Context, client httpClient, path, nam
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode == http.StatusTooManyRequests { err = checkStatusCode(resp, d)
retry, err := strconv.ParseInt(resp.Header.Get("Retry-After"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
return &RateLimitedError{time.Duration(retry) * time.Second}
}
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it.
if resp.StatusCode != http.StatusOK {
logResponse(resp, d)
return statusCodeError{Code: resp.StatusCode, Status: resp.Status}
}
select { select {
case err = <-errc: case err = <-errc:
return err return err
default: default:
return parseResponseBody(resp.Body, intf, d) return newJSONParser(intf)(resp)
} }
} }
func doPost(ctx context.Context, client httpClient, req *http.Request, intf interface{}, d debug) error { func doPost(ctx context.Context, client httpClient, req *http.Request, parser responseParser, d debug) error {
req = req.WithContext(ctx) req = req.WithContext(ctx)
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
@ -165,21 +223,12 @@ func doPost(ctx context.Context, client httpClient, req *http.Request, intf inte
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode == http.StatusTooManyRequests { err = checkStatusCode(resp, d)
retry, err := strconv.ParseInt(resp.Header.Get("Retry-After"), 10, 64)
if err != nil { if err != nil {
return err return err
} }
return &RateLimitedError{time.Duration(retry) * time.Second}
}
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it. return parser(resp)
if resp.StatusCode != http.StatusOK {
logResponse(resp, d)
return statusCodeError{Code: resp.StatusCode, Status: resp.Status}
}
return parseResponseBody(resp.Body, intf, d)
} }
// post JSON. // post JSON.
@ -191,7 +240,8 @@ func postJSON(ctx context.Context, client httpClient, endpoint, token string, js
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
return doPost(ctx, client, req, intf, d)
return doPost(ctx, client, req, newJSONParser(intf), d)
} }
// post a url encoded form. // post a url encoded form.
@ -202,17 +252,7 @@ func postForm(ctx context.Context, client httpClient, endpoint string, values ur
return err return err
} }
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
return doPost(ctx, client, req, intf, d) return doPost(ctx, client, req, newJSONParser(intf), d)
}
// post to a slack web method.
func postSlackMethod(ctx context.Context, client httpClient, path string, values url.Values, intf interface{}, d debug) error {
return postForm(ctx, client, APIURL+path, values, intf, d)
}
// get a slack web method.
func getSlackMethod(ctx context.Context, client httpClient, path string, values url.Values, intf interface{}, d debug) error {
return getResource(ctx, client, APIURL+path, values, intf, d)
} }
func getResource(ctx context.Context, client httpClient, endpoint string, values url.Values, intf interface{}, d debug) error { func getResource(ctx context.Context, client httpClient, endpoint string, values url.Values, intf interface{}, d debug) error {
@ -223,7 +263,7 @@ func getResource(ctx context.Context, client httpClient, endpoint string, values
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.URL.RawQuery = values.Encode() req.URL.RawQuery = values.Encode()
return doPost(ctx, client, req, intf, d) return doPost(ctx, client, req, newJSONParser(intf), d)
} }
func parseAdminResponse(ctx context.Context, client httpClient, method string, teamName string, values url.Values, intf interface{}, d debug) error { func parseAdminResponse(ctx context.Context, client httpClient, method string, teamName string, values url.Values, intf interface{}, d debug) error {
@ -251,12 +291,6 @@ func okJSONHandler(rw http.ResponseWriter, r *http.Request) {
rw.Write(response) rw.Write(response)
} }
type errorString string
func (t errorString) Error() string {
return string(t)
}
// timerReset safely reset a timer, see time.Timer.Reset for details. // timerReset safely reset a timer, see time.Timer.Reset for details.
func timerReset(t *time.Timer, d time.Duration) { func timerReset(t *time.Timer, d time.Duration) {
if !t.Stop() { if !t.Stop() {
@ -264,3 +298,63 @@ func timerReset(t *time.Timer, d time.Duration) {
} }
t.Reset(d) t.Reset(d)
} }
func checkStatusCode(resp *http.Response, d debug) error {
if resp.StatusCode == http.StatusTooManyRequests {
retry, err := strconv.ParseInt(resp.Header.Get("Retry-After"), 10, 64)
if err != nil {
return err
}
return &RateLimitedError{time.Duration(retry) * time.Second}
}
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it.
if resp.StatusCode != http.StatusOK {
logResponse(resp, d)
return statusCodeError{Code: resp.StatusCode, Status: resp.Status}
}
return nil
}
type responseParser func(*http.Response) error
func newJSONParser(dst interface{}) responseParser {
return func(resp *http.Response) error {
return json.NewDecoder(resp.Body).Decode(dst)
}
}
func newTextParser(dst interface{}) responseParser {
return func(resp *http.Response) error {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if !bytes.Equal(b, []byte("ok")) {
return errors.New(string(b))
}
return nil
}
}
func newContentTypeParser(dst interface{}) responseParser {
return func(req *http.Response) (err error) {
var (
ctype string
)
if ctype, _, err = mime.ParseMediaType(req.Header.Get("Content-Type")); err != nil {
return err
}
switch ctype {
case "application/json":
return newJSONParser(dst)(req)
default:
return newTextParser(dst)(req)
}
}
}

View File

@ -57,7 +57,7 @@ func GetOAuthResponseContext(ctx context.Context, client httpClient, clientID, c
"redirect_uri": {redirectURI}, "redirect_uri": {redirectURI},
} }
response := &OAuthResponse{} response := &OAuthResponse{}
if err = postSlackMethod(ctx, client, "oauth.access", values, response, discard{}); err != nil { if err = postForm(ctx, client, APIURL+"oauth.access", values, response, discard{}); err != nil {
return nil, err return nil, err
} }
return response, response.Err() return response, response.Err()

View File

@ -34,7 +34,7 @@ func (api *Client) AddPinContext(ctx context.Context, channel string, item ItemR
} }
response := &SlackResponse{} response := &SlackResponse{}
if err := postSlackMethod(ctx, api.httpclient, "pins.add", values, response, api); err != nil { if err := api.postMethod(ctx, "pins.add", values, response); err != nil {
return err return err
} }
@ -63,7 +63,7 @@ func (api *Client) RemovePinContext(ctx context.Context, channel string, item It
} }
response := &SlackResponse{} response := &SlackResponse{}
if err := postSlackMethod(ctx, api.httpclient, "pins.remove", values, response, api); err != nil { if err := api.postMethod(ctx, "pins.remove", values, response); err != nil {
return err return err
} }
@ -83,7 +83,7 @@ func (api *Client) ListPinsContext(ctx context.Context, channel string) ([]Item,
} }
response := &listPinsResponseFull{} response := &listPinsResponseFull{}
err := postSlackMethod(ctx, api.httpclient, "pins.list", values, response, api) err := api.postMethod(ctx, "pins.list", values, response)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@ -2,7 +2,6 @@ package slack
import ( import (
"context" "context"
"errors"
"net/url" "net/url"
"strconv" "strconv"
) )
@ -155,7 +154,7 @@ func (api *Client) AddReactionContext(ctx context.Context, name string, item Ite
} }
response := &SlackResponse{} response := &SlackResponse{}
if err := postSlackMethod(ctx, api.httpclient, "reactions.add", values, response, api); err != nil { if err := api.postMethod(ctx, "reactions.add", values, response); err != nil {
return err return err
} }
@ -189,7 +188,7 @@ func (api *Client) RemoveReactionContext(ctx context.Context, name string, item
} }
response := &SlackResponse{} response := &SlackResponse{}
if err := postSlackMethod(ctx, api.httpclient, "reactions.remove", values, response, api); err != nil { if err := api.postMethod(ctx, "reactions.remove", values, response); err != nil {
return err return err
} }
@ -223,12 +222,14 @@ func (api *Client) GetReactionsContext(ctx context.Context, item ItemRef, params
} }
response := &getReactionsResponseFull{} response := &getReactionsResponseFull{}
if err := postSlackMethod(ctx, api.httpclient, "reactions.get", values, response, api); err != nil { if err := api.postMethod(ctx, "reactions.get", values, response); err != nil {
return nil, err return nil, err
} }
if !response.Ok {
return nil, errors.New(response.Error) if err := response.Err(); err != nil {
return nil, err
} }
return response.extractReactions(), nil return response.extractReactions(), nil
} }
@ -256,12 +257,14 @@ func (api *Client) ListReactionsContext(ctx context.Context, params ListReaction
} }
response := &listReactionsResponseFull{} response := &listReactionsResponseFull{}
err := postSlackMethod(ctx, api.httpclient, "reactions.list", values, response, api) err := api.postMethod(ctx, "reactions.list", values, response)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if !response.Ok {
return nil, nil, errors.New(response.Error) if err := response.Err(); err != nil {
return nil, nil, err
} }
return response.extractReactedItems(), &response.Paging, nil return response.extractReactedItems(), &response.Paging, nil
} }

View File

@ -23,7 +23,7 @@ type reminderResp struct {
func (api *Client) doReminder(ctx context.Context, path string, values url.Values) (*Reminder, error) { func (api *Client) doReminder(ctx context.Context, path string, values url.Values) (*Reminder, error) {
response := &reminderResp{} response := &reminderResp{}
if err := postSlackMethod(ctx, api.httpclient, path, values, response, api); err != nil { if err := api.postMethod(ctx, path, values, response); err != nil {
return nil, err return nil, err
} }
return &response.Reminder, response.Err() return &response.Reminder, response.Err()
@ -68,7 +68,7 @@ func (api *Client) DeleteReminder(id string) error {
"reminder": {id}, "reminder": {id},
} }
response := &SlackResponse{} response := &SlackResponse{}
if err := postSlackMethod(context.Background(), api.httpclient, "reminders.delete", values, response, api); err != nil { if err := api.postMethod(context.Background(), "reminders.delete", values, response); err != nil {
return err return err
} }
return response.Err() return response.Err()

View File

@ -38,7 +38,7 @@ func (api *Client) StartRTM() (info *Info, websocketURL string, err error) {
// To have a fully managed Websocket connection, use `NewRTM`, and call `ManageConnection()` on it. // To have a fully managed Websocket connection, use `NewRTM`, and call `ManageConnection()` on it.
func (api *Client) StartRTMContext(ctx context.Context) (info *Info, websocketURL string, err error) { func (api *Client) StartRTMContext(ctx context.Context) (info *Info, websocketURL string, err error) {
response := &infoResponseFull{} response := &infoResponseFull{}
err = postSlackMethod(ctx, api.httpclient, "rtm.start", url.Values{"token": {api.token}}, response, api) err = api.postMethod(ctx, "rtm.start", url.Values{"token": {api.token}}, response)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -63,7 +63,7 @@ func (api *Client) ConnectRTM() (info *Info, websocketURL string, err error) {
// To have a fully managed Websocket connection, use `NewRTM`, and call `ManageConnection()` on it. // To have a fully managed Websocket connection, use `NewRTM`, and call `ManageConnection()` on it.
func (api *Client) ConnectRTMContext(ctx context.Context) (info *Info, websocketURL string, err error) { func (api *Client) ConnectRTMContext(ctx context.Context) (info *Info, websocketURL string, err error) {
response := &infoResponseFull{} response := &infoResponseFull{}
err = postSlackMethod(ctx, api.httpclient, "rtm.connect", url.Values{"token": {api.token}}, response, api) err = api.postMethod(ctx, "rtm.connect", url.Values{"token": {api.token}}, response)
if err != nil { if err != nil {
api.Debugf("Failed to connect to RTM: %s", err) api.Debugf("Failed to connect to RTM: %s", err)
return nil, "", err return nil, "", err
@ -112,14 +112,13 @@ func RTMOptionConnParams(connParams url.Values) RTMOption {
func (api *Client) NewRTM(options ...RTMOption) *RTM { func (api *Client) NewRTM(options ...RTMOption) *RTM {
result := &RTM{ result := &RTM{
Client: *api, Client: *api,
wasIntentional: true,
isConnected: false,
IncomingEvents: make(chan RTMEvent, 50), IncomingEvents: make(chan RTMEvent, 50),
outgoingMessages: make(chan OutgoingMessage, 20), outgoingMessages: make(chan OutgoingMessage, 20),
pingInterval: defaultPingInterval, pingInterval: defaultPingInterval,
pingDeadman: time.NewTimer(deadmanDuration(defaultPingInterval)), pingDeadman: time.NewTimer(deadmanDuration(defaultPingInterval)),
killChannel: make(chan bool), killChannel: make(chan bool),
disconnected: make(chan struct{}, 1), disconnected: make(chan struct{}),
disconnectedm: &sync.Once{},
forcePing: make(chan bool), forcePing: make(chan bool),
rawEvents: make(chan json.RawMessage), rawEvents: make(chan json.RawMessage),
idGen: NewSafeID(1), idGen: NewSafeID(1),

View File

@ -41,6 +41,7 @@ type SearchMessage struct {
User string `json:"user"` User string `json:"user"`
Username string `json:"username"` Username string `json:"username"`
Timestamp string `json:"ts"` Timestamp string `json:"ts"`
Blocks Blocks `json:"blocks,omitempty"`
Text string `json:"text"` Text string `json:"text"`
Permalink string `json:"permalink"` Permalink string `json:"permalink"`
Attachments []Attachment `json:"attachments"` Attachments []Attachment `json:"attachments"`
@ -103,7 +104,7 @@ func (api *Client) _search(ctx context.Context, path, query string, params Searc
} }
response = &searchResponseFull{} response = &searchResponseFull{}
err := postSlackMethod(ctx, api.httpclient, path, values, response, api) err := api.postMethod(ctx, path, values, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -4,7 +4,6 @@ import (
"crypto/hmac" "crypto/hmac"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"hash" "hash"
"net/http" "net/http"
@ -34,7 +33,7 @@ func unsafeSignatureVerifier(header http.Header, secret string) (_ SecretsVerifi
stimestamp := header.Get(hTimestamp) stimestamp := header.Get(hTimestamp)
if signature == "" || stimestamp == "" { if signature == "" || stimestamp == "" {
return SecretsVerifier{}, errors.New("missing headers") return SecretsVerifier{}, ErrMissingHeaders
} }
if bsignature, err = hex.DecodeString(strings.TrimPrefix(signature, "v0=")); err != nil { if bsignature, err = hex.DecodeString(strings.TrimPrefix(signature, "v0=")); err != nil {
@ -70,7 +69,7 @@ func NewSecretsVerifier(header http.Header, secret string) (sv SecretsVerifier,
diff := absDuration(time.Since(time.Unix(timestamp, 0))) diff := absDuration(time.Since(time.Unix(timestamp, 0)))
if diff > 5*time.Minute { if diff > 5*time.Minute {
return SecretsVerifier{}, fmt.Errorf("timestamp is too old") return SecretsVerifier{}, ErrExpiredTimestamp
} }
return sv, err return sv, err
@ -88,7 +87,7 @@ func (v SecretsVerifier) Ensure() error {
return nil return nil
} }
return fmt.Errorf("Expected signing signature: %s, but computed: %s", v.signature, computed) return fmt.Errorf("Expected signing signature: %s, but computed: %s", hex.EncodeToString(v.signature), hex.EncodeToString(computed))
} }
func abs64(n int64) int64 { func abs64(n int64) int64 {

View File

@ -9,11 +9,12 @@ import (
"os" "os"
) )
// APIURL added as a var so that we can change this for testing purposes const (
var APIURL = "https://slack.com/api/" // APIURL of the slack api.
APIURL = "https://slack.com/api/"
// WEBAPIURLFormat ... // WEBAPIURLFormat ...
const WEBAPIURLFormat = "https://%s.slack.com/api/users.admin.%s?t=%d" WEBAPIURLFormat = "https://%s.slack.com/api/users.admin.%s?t=%d"
)
// httpClient defines the minimal interface needed for an http.Client to be implemented. // httpClient defines the minimal interface needed for an http.Client to be implemented.
type httpClient interface { type httpClient interface {
@ -40,6 +41,8 @@ type AuthTestResponse struct {
User string `json:"user"` User string `json:"user"`
TeamID string `json:"team_id"` TeamID string `json:"team_id"`
UserID string `json:"user_id"` UserID string `json:"user_id"`
// EnterpriseID is only returned when an enterprise id present
EnterpriseID string `json:"enterprise_id,omitempty"`
} }
type authTestResponseFull struct { type authTestResponseFull struct {
@ -48,8 +51,11 @@ type authTestResponseFull struct {
} }
// Client for the slack api. // Client for the slack api.
type ParamOption func(*url.Values)
type Client struct { type Client struct {
token string token string
endpoint string
debug bool debug bool
log ilogger log ilogger
httpclient httpClient httpclient httpClient
@ -79,10 +85,16 @@ func OptionLog(l logger) func(*Client) {
} }
} }
// OptionAPIURL set the url for the client. only useful for testing.
func OptionAPIURL(u string) func(*Client) {
return func(c *Client) { c.endpoint = u }
}
// New builds a slack client from the provided token and options. // New builds a slack client from the provided token and options.
func New(token string, options ...Option) *Client { func New(token string, options ...Option) *Client {
s := &Client{ s := &Client{
token: token, token: token,
endpoint: APIURL,
httpclient: &http.Client{}, httpclient: &http.Client{},
log: log.New(os.Stderr, "nlopes/slack", log.LstdFlags|log.Lshortfile), log: log.New(os.Stderr, "nlopes/slack", log.LstdFlags|log.Lshortfile),
} }
@ -103,7 +115,7 @@ func (api *Client) AuthTest() (response *AuthTestResponse, error error) {
func (api *Client) AuthTestContext(ctx context.Context) (response *AuthTestResponse, err error) { func (api *Client) AuthTestContext(ctx context.Context) (response *AuthTestResponse, err error) {
api.Debugf("Challenging auth...") api.Debugf("Challenging auth...")
responseFull := &authTestResponseFull{} responseFull := &authTestResponseFull{}
err = postSlackMethod(ctx, api.httpclient, "auth.test", url.Values{"token": {api.token}}, responseFull, api) err = api.postMethod(ctx, "auth.test", url.Values{"token": {api.token}}, responseFull)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -129,3 +141,13 @@ func (api *Client) Debugln(v ...interface{}) {
func (api *Client) Debug() bool { func (api *Client) Debug() bool {
return api.debug return api.debug
} }
// post to a slack web method.
func (api *Client) postMethod(ctx context.Context, path string, values url.Values, intf interface{}) error {
return postForm(ctx, api.httpclient, api.endpoint+path, values, intf, api)
}
// get a slack web method.
func (api *Client) getMethod(ctx context.Context, path string, values url.Values, intf interface{}) error {
return getResource(ctx, api.httpclient, api.endpoint+path, values, intf, api)
}

Some files were not shown because too many files have changed in this diff Show More