1
0
Fork 0

Implement XMPP adapter and basic Inform handler

This implements a XMPP adapter and Inform 7 handler based around Joe
Bot. Lots of work remains.
This commit is contained in:
Alex Palaistras 2020-04-10 14:58:33 +01:00
commit 12606dc9b6
319 changed files with 107379 additions and 0 deletions

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2020 Alex Palaistras
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# InformBot - A Chat Bot for Inform 7 Stories, Built in Go
[![API Documentation][godoc-svg]][godoc-url] [![MIT License][license-svg]][license-url]
This package contains chat-bot for executing and running Inform 7 stories, and built around the [Joe
Bot][joe-url] framework. Any supported chat adapter can be used, and this repository contains an
example integration against a built-in XMPP adapter (which is not currently part of main-line
support).
## Building and Running
You can build the default test deployment of `informbot` (which currently works against an XMPP
server) by running `go get`, e.g.:
```go
go get github.com/deuill/informbot
```
Depending on your server setup, you may need to set up a number of options, as environment
variables, for instance:
``` go
INFORMBOT_JID="[email protected]" INFORMBOT_PASSWORD="123" INFORMBOT_USE_STARTTLS=true INFORMBOT_NO_TLS=true informbot
```
## Status
This package is still in early development, and is neither feature-complete nor bug-free. A large
amount of work remains on improving integration with Inform and Frotz, and optimizing against larger
stories.
## License
All code in this repository is covered by the terms of the MIT License, the full text of which can
be found in the LICENSE file.
[joe-url]: https://github.com/go-joe/joe
[godoc-url]: https://godoc.org/github.com/deuill/informbot
[godoc-svg]: https://godoc.org/github.com/deuill/informbot?status.svg
[license-url]: https://github.com/deuill/informbot/blob/master/LICENSE
[license-svg]: https://img.shields.io/badge/license-MIT-blue.svg

17
go.mod Normal file
View File

@ -0,0 +1,17 @@
module github.com/deuill/informbot
go 1.13
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-joe/file-memory v1.0.0
github.com/go-joe/joe v0.10.0
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.4.0 // indirect
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/multierr v1.2.0 // indirect
go.uber.org/zap v1.10.0
mellium.im/sasl v0.2.2-0.20191005211519-f1882f01d82d
mellium.im/xmlstream v0.15.0
mellium.im/xmpp v0.16.0
)

59
go.sum Normal file
View File

@ -0,0 +1,59 @@
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/go-joe/file-memory v1.0.0 h1:2R9uKk9l+VvaxW/ekQiZsL1XZSNF0G3+j5WDyJPIzFQ=
github.com/go-joe/file-memory v1.0.0/go.mod h1:Le5FS31e5sjnjuxTXqeks0GWHvcM9SCuv78y1FkB464=
github.com/go-joe/joe v0.8.0/go.mod h1:fjDMMKm6GV29+egH/IS57PTKHSBMquckyuM7CmXbUQw=
github.com/go-joe/joe v0.10.0 h1:dEe0EHhHeshTDGy55Y4HGOZgj0L11TdeMlaTn5JOPQg=
github.com/go-joe/joe v0.10.0/go.mod h1:fjDMMKm6GV29+egH/IS57PTKHSBMquckyuM7CmXbUQw=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/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/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.2.0 h1:6I+W7f5VwC5SV9dNrZ3qXrDB9mD0dyGOi/ZJmYw03T4=
go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
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-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
mellium.im/reader v0.1.0 h1:UUEMev16gdvaxxZC7fC08j7IzuDKh310nB6BlwnxTww=
mellium.im/reader v0.1.0/go.mod h1:F+X5HXpkIfJ9EE1zHQG9lM/hO946iYAmU7xjg5dsQHI=
mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w=
mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ=
mellium.im/sasl v0.2.2-0.20191005211519-f1882f01d82d h1:pGcF7i27vUWdsUCx/jjZdIz8++xhFmkVV33tXTJO0ZE=
mellium.im/sasl v0.2.2-0.20191005211519-f1882f01d82d/go.mod h1:i8GDqL2fYwZ6vDJWIBafT8SEOOohlLJkLFDfhcoYg1c=
mellium.im/xmlstream v0.14.0 h1:vTljQmcFQq7LEb+LJQV0VI8wnuFnzBy1AnfUbA4SrL8=
mellium.im/xmlstream v0.14.0/go.mod h1:O7wqreSmFi1LOh4RiK7r2j4H4pYDgzo1qv5ZkYJZ7Ns=
mellium.im/xmlstream v0.15.0 h1:NczJZ5FYsRhaA2asw0/hrQm83K81cSTJszKhHh4s18Q=
mellium.im/xmlstream v0.15.0/go.mod h1:7SUlP7f2qnMczK+Cu/OFgqaIhldMolVjo8np7xG41D0=
mellium.im/xmpp v0.16.0 h1:Qb4e4odzSKFRVTTUuNybVe78ZT3OH5iijVAGqgaIRrw=
mellium.im/xmpp v0.16.0/go.mod h1:/y8pNXeL54Qn86oa4Tg8zzrGiTaKoOyM6KVVZLHFcb0=

View File

@ -0,0 +1,105 @@
package inform
import (
// Standard library
"io/ioutil"
"net/http"
"net/url"
"strings"
// Third-party packages
"github.com/pkg/errors"
)
// Options represent user-configurable values, which are used in processing commands
// and formatting output.
type Options struct {
Prefix string
}
// Default values for options, as assigned to newly created Author instances.
var defaultOptions = Options{
Prefix: "?",
}
type Author struct {
ID string
Options Options
Stories []*Story
}
func (a *Author) GetStory(name string) (*Story, error) {
if name == "" {
return nil, errors.New("story name is empty")
}
for i := range a.Stories {
if a.Stories[i].Name == name {
return a.Stories[i], nil
}
}
return nil, errors.New("no story found with name '" + name + "'")
}
func (a *Author) AddStory(name, path string) (*Story, error) {
var story *Story
if name == "" {
return nil, errors.New("story name is empty")
} else if s, _ := a.GetStory(name); s != nil {
story = s
} else if u, err := url.Parse(path); err != nil || (u.Scheme != "https" && u.Scheme != "http") {
return nil, errors.New("location given is not a valid HTTP URL")
}
resp, err := http.Get(path)
if err != nil {
return nil, errors.New("could not fetch story file from URL given")
}
defer resp.Body.Close()
if body, err := ioutil.ReadAll(resp.Body); err != nil {
return nil, errors.New("could not fetch story file from URL given")
} else if story == nil {
story = NewStory(name, a.ID).WithSource(body)
a.Stories = append(a.Stories, story)
} else {
story.WithSource(body)
}
return story, nil
}
func (a *Author) RemoveStory(name string) error {
if name == "" {
return errors.New("story name is empty")
}
// Find story with given name, and remove from list assigned to author.
for i := range a.Stories {
if a.Stories[i].Name == name {
a.Stories = append(a.Stories[:i], a.Stories[i+1:]...)
return nil
}
}
return errors.New("no story found with name '" + name + "'")
}
func (a *Author) SetOption(name, value string) error {
switch strings.ToLower(name) {
case "prefix":
if value == "" {
return errors.New("cannot set empty prefix value")
}
a.Options.Prefix = value
default:
return errors.New("option name '" + name + "' is unknown")
}
return nil
}
func NewAuthor(id string) *Author {
return &Author{ID: id, Options: defaultOptions}
}

View File

@ -0,0 +1,217 @@
package inform
import (
// Standard library
"bytes"
"context"
"os/exec"
"strings"
"text/template"
// Third-party packages
"github.com/go-joe/joe"
"github.com/pkg/errors"
)
// The prefix used for all keys stored.
const keyPrefix = "org.deuill.informbot"
type Inform struct {
sessions map[string]*Session // A list of open sessions, against their authors.
bot *joe.Bot // The initialized bot to read commands from and send responses to.
config *Config // The configuration for the Inform bot.
}
func (n *Inform) SayTemplate(channel string, template *template.Template, data interface{}) error {
var buf bytes.Buffer
if err := template.Execute(&buf, data); err != nil || buf.Len() == 0 {
n.bot.Say(channel, messageUnknownError)
return err
}
n.bot.Say(channel, buf.String())
return nil
}
func (n *Inform) Handle(ctx context.Context, ev joe.ReceiveMessageEvent) error {
// Validate event data.
if ev.AuthorID == "" {
n.bot.Say(ev.Channel, messageUnknownError)
return nil
}
// Check for stored rule-set against author ID, and send welcome message if none was found.
var author, authorKey = &Author{}, keyPrefix + ".author." + ev.AuthorID
if ok, err := n.bot.Store.Get(authorKey, author); err != nil {
n.bot.Say(ev.Channel, messageUnknownError)
return err
} else if !ok {
if err := n.SayTemplate(ev.Channel, templateWelcome, nil); err != nil {
return errors.Wrap(err, "failed storing author information")
}
// Create and store new Author representation.
author = NewAuthor(ev.AuthorID)
if err := n.bot.Store.Set(authorKey, author); err != nil {
n.bot.Say(ev.Channel, messageUnknownError)
return err
}
}
// Check for open session, and handle command directly if not prefixed.
var cmd = ev.Text
if n.sessions[author.ID] != nil {
if !strings.HasPrefix(ev.Text, author.Options.Prefix) {
if err := n.sessions[author.ID].Run(cmd); err != nil {
n.bot.Say(ev.Channel, messageRunError, err)
return err
}
n.bot.Say(ev.Channel, n.sessions[author.ID].Output())
return nil
} else {
cmd = ev.Text[len(author.Options.Prefix):]
}
}
// Handle meta-commands.
var fields = strings.Fields(cmd)
if len(fields) == 0 {
return nil
} else if len(fields) == 1 {
cmd = fields[0]
} else if len(fields) >= 2 {
cmd = strings.Join(fields[:2], " ")
}
switch strings.ToLower(cmd) {
case "help", "h":
return n.SayTemplate(ev.Channel, templateHelp, nil)
case "story", "stories", "story list", "list stories", "s":
return n.SayTemplate(ev.Channel, templateStoryList, author)
case "story add", "stories add", "add stories":
if len(fields) < 4 {
n.bot.Say(ev.Channel, messageUnknownStory)
} else if story, err := author.AddStory(fields[2], fields[3]); err != nil {
n.bot.Say(ev.Channel, messageInvalidStory, err)
} else if err := story.Compile(ctx, n.config); err != nil {
n.bot.Say(ev.Channel, "TODO: Compilation error: "+err.Error())
return err
} else if err = n.bot.Store.Set(authorKey, author); err != nil {
n.bot.Say(ev.Channel, messageUnknownError)
return err
} else {
n.bot.Say(ev.Channel, messageAddedStory, fields[2])
}
return nil
case "story remove", "stories remove", "story rem", "stories rem":
// TODO: Check for active session.
if len(fields) < 3 {
n.bot.Say(ev.Channel, messageUnknownStory)
} else if err := author.RemoveStory(fields[2]); err != nil {
n.bot.Say(ev.Channel, messageInvalidStory, err)
} else if err = n.bot.Store.Set(authorKey, author); err != nil {
n.bot.Say(ev.Channel, messageUnknownError)
return err
} else {
n.bot.Say(ev.Channel, messageRemovedStory, fields[2])
}
return nil
case "story start", "stories start":
if len(fields) < 3 {
n.bot.Say(ev.Channel, messageUnknownStory)
} else if story, err := author.GetStory(fields[2]); err != nil {
n.bot.Say(ev.Channel, messageInvalidStory, err)
} else if _, ok := n.sessions[author.ID]; ok {
n.bot.Say(ev.Channel, "TODO: Stop session before starting")
} else if sess, err := NewSession(story); err != nil {
n.bot.Say(ev.Channel, messageInvalidSession, err)
return err
} else if err = sess.Start(ctx, n.config); err != nil {
n.bot.Say(ev.Channel, "TODO: Cannot start session: %s", err)
return err
} else {
n.bot.Say(ev.Channel, messageStartedSession, fields[2], author.Options.Prefix)
n.bot.Say(ev.Channel, sess.Output())
n.sessions[author.ID] = sess
}
return nil
case "story end", "stories end":
if n.sessions[author.ID] == nil {
n.bot.Say(ev.Channel, "TODO: No active session")
} else {
n.bot.Say(ev.Channel, "TODO: Stopped session")
delete(n.sessions, author.ID)
}
return nil
case "option", "options", "option list", "list options", "o":
return n.SayTemplate(ev.Channel, templateOptionList, author)
case "option set", "options set", "set option", "set options":
if len(fields) < 4 {
n.bot.Say(ev.Channel, messageUnknownOption)
} else if err := author.SetOption(fields[2], fields[3]); err != nil {
n.bot.Say(ev.Channel, messageInvalidOption, err)
} else if err = n.bot.Store.Set(authorKey, author); err != nil {
n.bot.Say(ev.Channel, messageUnknownError)
return err
} else {
n.bot.Say(ev.Channel, messageSetOption, fields[2], fields[3])
}
return nil
}
return n.SayTemplate(ev.Channel, templateUnknownCommand, cmd)
}
// Default executable names for required runtime dependencies.
const (
defaultInform7 = "/usr/libexec/ni"
defaultInform6 = "/usr/libexec/inform6"
defaultDumbFrotz = "/usr/bin/dfrotz"
)
type Config struct {
// Required attributes.
Bot *joe.Bot // The bot handler.
// Optional attributes.
Inform7 string // The path to the `ni` Inform 7 compiler.
Inform6 string // The path to the `inform6` Inform 6 compiler.
DumbFrotz string // The path to the `dumb-frotz` interpreter.
}
func New(conf Config) (*Inform, error) {
if conf.Bot == nil {
return nil, errors.New("bot given is nil")
} else if conf.Bot.Store == nil {
return nil, errors.New("storage module required")
}
// Set default paths for runtime dependencies, if needed.
if conf.Inform7 == "" {
conf.Inform7 = defaultInform7
}
if conf.Inform6 == "" {
conf.Inform6 = defaultInform6
}
if conf.DumbFrotz == "" {
conf.DumbFrotz = defaultDumbFrotz
}
// Verify and expand paths for runtime dependencies.
if i7, err := exec.LookPath(conf.Inform7); err != nil {
return nil, errors.Wrap(err, "Inform 7 compiler not found")
} else if i6, err := exec.LookPath(conf.Inform6); err != nil {
return nil, errors.Wrap(err, "Inform 6 compiler not found")
} else if frotz, err := exec.LookPath(conf.DumbFrotz); err != nil {
return nil, errors.Wrap(err, "Frotz interpreter not found")
} else {
conf.Inform7, conf.Inform6, conf.DumbFrotz = i7, i6, frotz
}
return &Inform{
bot: conf.Bot,
config: &conf,
sessions: make(map[string]*Session),
}, nil
}

View File

@ -0,0 +1,86 @@
package inform
import (
// Standard library
"text/template"
)
var templateOptionList = parseTemplate("option-list", `
The options currently set for '{{.ID}}' are:
> Prefix: {{with .Options.Prefix}}'{{.}}'{{else}}(None Set){{end}}
Change these options with 'option set <key> <value>'.`)
var templateStoryList = parseTemplate("story-list", `
{{if .Stories}}
The list of active stories for '{{.ID}}' are:
{{- range .Stories}}
> Name: '{{.Name}}'
> Created at: {{.CreatedAt.Format "Mon, 02 Jan 2006 15:04"}}
> Last updated at: {{.CreatedAt.Format "Mon, 02 Jan 2006 15:04"}}
{{end}}
{{else}}
There are currently no active stories available for '{{.ID}}'.
Add a new one with 'story add' or get more information with 'help story' and 'help story add'.
{{end}}`)
var templateWelcome = parseTemplate("welcome", `
Hi! 👋
It seems like this is the first time we've exchanged messages (if not, feel free to skip this), and might need some help getting up-to-speed with what I do. With no further ado:
My name is InformBot, and I'm a chat interface for Inform 7, a system for creating works of interactive fiction, via a natural-language interface. What this means, essentially, is that you can write interactive books (and more) in very much the same language that you use reading them (that is, if you tend to read books written in the English language).
Inform is much, much more useful than just for writing interactive fiction stories for individuals it can be used to implement interactive interfaces of any kind, and keep track of complex worlds with complex state.
That's where I come in, and can help in both defining the rules and performing actions against them, both in direct messages and in group-chats.
For more information on how you can define these rules, and how to converse with me in group-chats, type 'help' and I'll respond with a list of topics you can look further into.`)
var templateHelp = parseTemplate("help", `
Inform itself is a large, complicated system, and help on writing rules way beyond the scope of this help text. You are in luck though, as Inform comes with a large amount of documentation on its website: http://inform7.com/doc
Feel free to ask any questions about, or report any issues with InformBot itself here: https://github.com/deuill/informbot`)
var templateUnknownCommand = parseTemplate("unknown-command", `
I don't understand what '{{.}}' means. Type 'help' for an overview of common commands.`)
var messageInvalidSession = `
I couldn't start the story successfully %s.`
var messageStartedSession = `
Story '%s' successfully started.
Any subsequent meta-commands will have to be given a prefix (currently set to '%s'), and you can end this session by using the 'story end' command. Have fun! 🎉`
var messageAddedStory = `
Story '%s' successfully added to active list.`
var messageRemovedStory = `
Story '%s' successfully removed from active list.`
// TODO FIX THESE TO BE MORE GENERIC
var messageUnknownStory = `
You need to pass in both the story name and URL, e.g. 'story add some-name https://example.com/story.ni'.
Story names need to be one word (though they can contain hyphens or underscores), and not contain any spaces or other white-space characters.`
var messageInvalidStory = `
I couldn't add the story successfully %s.`
var messageSetOption = `
Option '%s' successfully set to '%s'.`
var messageUnknownOption = `
You need to pass in both the option name and value, e.g. 'option set Prefix ?'.`
var messageInvalidOption = `
I couldn't set that option successfully %s.`
var messageRunError = `
I could't run that command %s.`
var messageUnknownError = `
Oops, something went wrong and I was unable to complete that request, give me a moment and try again (or ask whoever set me up for some help).`
func parseTemplate(name, content string) *template.Template {
return template.Must(template.New(name).Parse(content))
}

View File

@ -0,0 +1,161 @@
package inform
import (
// Standard library
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"strings"
"time"
// Third-party packages
"github.com/pkg/errors"
)
// Default arguments for executable dependencies.
var (
// The prefix used for Frotz meta-commands.
frotzMetaPrefix = "\\"
frotzArgs = []string{"-r", "lt", "-r", "cm", "-r", "ch1", "-p", "-m", "-R"}
)
type Session struct {
path string
name string
proc *os.Process
in io.WriteCloser
out io.ReadCloser
err io.ReadCloser
}
func (s *Session) Run(cmd string) error {
switch strings.ToLower(cmd) {
case "restore":
return errors.New("TODO: Implement restoring")
case "save":
return errors.New("TODO: Implement saving")
case "\\x", "quit":
return errors.New("TODO: Implement session stopping")
case "script", "unscript":
return errors.New("transcripts are disabled")
case "\\<", "\\>", "\\^", "\\.": // Cursor motion
case "\\1", "\\2", "\\3", "\\4", "\\5", "\\6", "\\7", "\\8", "\\9", "\\0": // F1 - F10
case "\\n", "\\u": // Frotz hot-keys
default:
if strings.HasPrefix(cmd, frotzMetaPrefix) {
return errors.New("meta-commands are disabled")
}
}
if _, err := s.in.Write(append([]byte(cmd), '\n')); err != nil {
return errors.New("failed writing command")
}
return s.Error()
}
func (s *Session) Output() string {
var buf = bytes.TrimSuffix(readPipe(s.out), []byte{'\n', '>'})
return string(buf)
}
func (s *Session) Error() error {
var buf = bytes.ReplaceAll(readPipe(s.err), []byte{'\n'}, []byte{':', ' '})
if len(buf) > 0 {
return errors.New(string(buf))
}
return nil
}
func (s *Session) Start(ctx context.Context, conf *Config) error {
var err error
var cmd = exec.CommandContext(ctx, conf.DumbFrotz, append(frotzArgs, s.path, s.name)...)
if s.in, err = cmd.StdinPipe(); err != nil {
return errors.Wrap(err, "starting session failed")
} else if s.out, err = cmd.StdoutPipe(); err != nil {
return errors.Wrap(err, "starting session failed")
} else if s.err, err = cmd.StderrPipe(); err != nil {
return errors.Wrap(err, "starting session failed")
} else if err = cmd.Start(); err != nil {
return errors.Wrap(err, "starting session failed")
} else if err := s.Error(); err != nil {
return err
}
s.proc = cmd.Process
return nil
}
func (s *Session) Close() error {
var err error
if s.proc != nil {
err = s.proc.Kill()
s.proc = nil
}
return err
}
func NewSession(story *Story) (*Session, error) {
dir, err := ioutil.TempDir(os.TempDir(), fmt.Sprintf("%s-%s-%s-*", keyPrefix, story.AuthorID, story.Name))
if err != nil {
return nil, errors.Wrap(err, "creating temporary directory failed")
}
f, err := os.Create(path.Join(dir, "output.z8"))
if err != nil {
return nil, errors.Wrap(err, "writing temporary story file failed")
}
defer f.Close()
if _, err = f.Write(story.Build); err != nil {
return nil, errors.Wrap(err, "writing temporary story file failed")
}
return &Session{
path: dir,
name: f.Name(),
}, nil
}
func readPipe(r io.Reader) []byte {
var chunks = make(chan []byte)
go func() {
var chunk = make([]byte, 1024)
for {
n, err := r.Read(chunk)
if err != nil || n == 0 {
close(chunks)
return
}
chunks <- chunk[:n]
if n < 1024 {
close(chunks)
return
}
}
}()
var buf []byte
for {
select {
case chunk, ok := <-chunks:
if !ok {
return buf
}
buf = append(buf, chunk...)
case <-time.After(10 * time.Millisecond):
return buf
}
}
}

View File

@ -0,0 +1,81 @@
package inform
import (
// Standard library
"context"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"time"
// Third-party packages
"github.com/pkg/errors"
)
var (
// Default path for Inform7 data.
inform7DataDir = "/usr/share/inform7/Internal"
// Default arguments for Inform 6 and 7 compilers.
inform7Args = []string{"--noprogress", "--internal", inform7DataDir, "--format=z8"}
inform6Args = []string{"-E2wSDv8F0Cud2"}
)
type Story struct {
Name string // The user-provided name for the story.
AuthorID string // The author ID, corSayTemplates to Author.ID.
CreatedAt time.Time // The UTC timestamp this story was first added on.
UpdatedAt time.Time // The UTC timestamp this story was last updated on.
// Source and compiled Z-Code for story.
Source []byte
Build []byte
}
func (s *Story) Compile(ctx context.Context, conf *Config) error {
dir, err := ioutil.TempDir(os.TempDir(), fmt.Sprintf("%s-%s-%s-*", keyPrefix, s.AuthorID, s.Name))
if err != nil {
return errors.Wrap(err, "creating temporary directory failed")
} else if err := os.Mkdir(path.Join(dir, "Source"), 0755); err != nil {
return errors.Wrap(err, "creating temporary directory failed")
}
if err := ioutil.WriteFile(path.Join(dir, "Source", "story.ni"), s.Source, 0644); err != nil {
return errors.Wrap(err, "writing file for story failed")
}
// TODO: Return verbose output.
err = exec.CommandContext(ctx, conf.Inform7, append(inform7Args, "--project", dir)...).Run()
if err != nil {
return errors.Wrap(err, "compilation failed")
}
err = exec.CommandContext(ctx, conf.Inform6, append(inform6Args, path.Join(dir, "Build", "auto.inf"), path.Join(dir, "Build", "output.z8"))...).Run()
if err != nil {
return errors.Wrap(err, "compilation failed")
}
buf, err := ioutil.ReadFile(path.Join(dir, "Build", "output.z8"))
if err != nil {
return errors.Wrap(err, "compilation failed")
}
s.Build, s.UpdatedAt = buf, time.Now().UTC()
return os.RemoveAll(dir)
}
func (s *Story) WithSource(src []byte) *Story {
s.Source = src
return s
}
func NewStory(name, authorID string) *Story {
return &Story{
Name: name,
AuthorID: authorID,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
}
}

350
joe-xmpp-adapter/xmpp.go Normal file
View File

@ -0,0 +1,350 @@
package xmpp
import (
// Standard library
"context"
"crypto/rand"
"crypto/tls"
"encoding/xml"
"fmt"
"io"
"strings"
// Third-party packages
"github.com/go-joe/joe"
"github.com/pkg/errors"
"go.uber.org/zap"
"mellium.im/sasl"
"mellium.im/xmlstream"
"mellium.im/xmpp"
"mellium.im/xmpp/dial"
"mellium.im/xmpp/jid"
"mellium.im/xmpp/stanza"
)
// DefaultAuthMechanisms represents the list of SASL authentication mechanisms this client is allowed
// to use in server authentication.
var defaultAuthMechanisms = []sasl.Mechanism{
sasl.Plain,
sasl.ScramSha1,
sasl.ScramSha1Plus,
}
// Config represents required and optional configuration values used in setting up the XMPP bot client.
type Config struct {
// Required configuration.
JID string
Password string
// Optional configuration.
NoTLS bool // Whether to disable TLS connection to the XMPP server.
UseStartTLS bool // Whether or not connection will be allowed to be made over StartTLS.
// Other fields.
Logger *zap.Logger // The instance to use for emitting log messages.
}
// Client represents an active XMPP session against a server, and configuration for handling messages
// against a Joe instance.
type Client struct {
brain *joe.Brain // The mediator between this adapter and other handlers.
session *xmpp.Session // The active XMPP session.
logger *zap.Logger // The logger instance to use, defaults to a global logger used by Joe.
}
// Send wraps the given text in a message stanza and sets the recipient to the given channel, which
// is expected to be a JID (bare for direct messages). A error is returned if the channel JID does
// not parse, or if the message fails to send for any reason.
func (c *Client) Send(msg, channel string) error {
jid, err := jid.Parse(channel)
if err != nil {
return errors.Wrap(err, "parsing JID failed")
}
// Determine whether this is a direct or group-chat message from the resource part of the JID,
// which is only set if the message was originally sent as part of a group-chat.
var kind = stanza.ChatMessage
if jid.Resourcepart() != "" {
msg = jid.Resourcepart() + ", " + msg
jid, kind = jid.Bare(), stanza.GroupChatMessage
}
c.logger.Debug("Sending message",
zap.String("jid", jid.String()),
zap.String("type", string(kind)))
return c.session.Send(context.Background(),
xmlstream.Wrap(
xmlstream.Wrap(
xmlstream.Token(xml.CharData(msg)),
xml.StartElement{Name: xml.Name{Local: "body"}},
),
xml.StartElement{
Name: xml.Name{Local: "message"},
Attr: []xml.Attr{
{Name: xml.Name{Local: "id"}, Value: randomID()},
{Name: xml.Name{Local: "to"}, Value: jid.String()},
{Name: xml.Name{Local: "type"}, Value: string(kind)},
},
},
),
)
}
// GroupInfo represents information needed for joining a MUC, either automatically or as part of an
// invite (direct or mediated).
type GroupInfo struct {
Channel jid.JID `xml:"-"`
Password string `xml:"password`
Invite struct {
From jid.JID `xml:"from,attr"`
} `xml:"invite"`
}
// MessageStanza represents an XMPP message stanza, commonly used for transferring chat messages
// among users or group-chats.
type MessageStanza struct {
// Base, common fields.
stanza.Message
Body string `xml:"body"`
// Additional, optional fields.
Group GroupInfo `xml:"x"`
}
// HandleInvite responds to the given invite (direct or mediated) with an 'available' presence,
// which allows the client to participate in MUCs.
func (c *Client) HandleInvite(w xmlstream.TokenWriter, info *GroupInfo) error {
jid, err := info.Channel.WithResource(c.session.LocalAddr().Localpart())
if err != nil {
return errors.Wrap(err, "setting JID for MUC failed")
}
_, err = xmlstream.Copy(w, xmlstream.Wrap(
xmlstream.Wrap(
xmlstream.MultiReader(
xmlstream.Wrap(
xmlstream.Token(xml.CharData(info.Password)),
xml.StartElement{Name: xml.Name{Local: "password"}},
),
xmlstream.Wrap(nil, xml.StartElement{
Name: xml.Name{Local: "history"},
Attr: []xml.Attr{
{Name: xml.Name{Local: "maxchars"}, Value: "0"},
},
}),
),
xml.StartElement{
Name: xml.Name{Local: "x"},
Attr: []xml.Attr{
{Name: xml.Name{Local: "xmlns"}, Value: "http://jabber.org/protocol/muc"},
},
},
),
stanza.Presence{
ID: randomID(),
Type: stanza.AvailablePresence,
To: jid,
}.StartElement(),
))
if err != nil {
return errors.Wrap(err, "setting presence for MUC failed")
}
return nil
}
// HandleMessage parses the given MessageStanza, validating its contents and responding either as a
// direct message, or as a group-chat mention, depending on the intent. HandleMessage will also handle
// invites to group-chats, joining these automatically and with no confirmation needed.
//
// By default, only messages prepended with the local part of the client JID will be responded to in
// group-chats; this is to avoid handling messages where this is not wanted. Such mentions will be,
// in turn, responded to with a mention for the sending user.
//
// Currently, only mediated invites (XEP-0045) are handled, and rooms are not re-joined if the client
// closes its connection to the server.
func (c *Client) HandleMessage(w xmlstream.TokenWriter, msg *MessageStanza) error {
var authorID = msg.From.Bare().String()
var channel = msg.From.Bare().String()
switch msg.Type {
case stanza.GroupChatMessage:
// Don't handle messages that aren't intended for us.
n := strings.ToLower(c.session.LocalAddr().Localpart())
if len(msg.Body) <= len(n) || strings.ToLower(msg.Body[:len(n)]) != n {
return nil
}
channel = msg.From.String()
msg.Body = strings.Trim(msg.Body[len(n):], " ,:")
fallthrough
case stanza.ChatMessage:
// Do not attempt to handle empty or invalid messages.
if msg.Body == "" {
return nil
}
c.brain.Emit(joe.ReceiveMessageEvent{
ID: msg.ID,
Text: msg.Body,
AuthorID: authorID,
Channel: channel,
Data: msg,
})
default:
// Check if message is a mediated MUC invite, and join MUC if so.
if !msg.Group.Invite.From.Equal(jid.JID{}) {
msg.Group.Channel = msg.From.Bare()
return c.HandleInvite(w, &msg.Group)
}
}
return nil
}
// PresenceStanza represents an XMPP presence stanza, commonly used for communicating
// availability.
type PresenceStanza struct {
// Base, common fields.
stanza.Presence
}
// HandlePresence parses the given PresenceStanza and responds (usually to the affirmative),
// depending on the presence type, e.g. for subscription requests, HandlePresence will automatically
// subscribe and respond. Any errors returned in parsing on responding will be returned.
func (c *Client) HandlePresence(w xmlstream.TokenWriter, p *PresenceStanza) error {
var err error
// Handle presence stanza based on type.
switch p.Type {
case stanza.SubscribePresence:
// Respond to subscription requests automatically.
_, err = xmlstream.Copy(w, stanza.Presence{
ID: randomID(),
Type: stanza.SubscribedPresence,
To: p.From,
}.Wrap(nil))
}
if err != nil {
return err
}
return nil
}
// HandleXMPP parses incoming XML tokens and calls a corresponding handler, e.g. HandleMessage, for
// the stanza type represented. Unhandled stanza types will be ignored with no error returned.
func (c *Client) HandleXMPP(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
var stanza interface{}
var err error
switch start.Name.Local {
case "message":
stanza = &MessageStanza{}
case "presence":
stanza = &PresenceStanza{}
default:
c.logger.Debug("Ignoring unknown stanza type", zap.String("type", start.Name.Local))
return nil // Unknown stanza type, do not handle.
}
err = xml.NewTokenDecoder(t).DecodeElement(&stanza, start)
if err != nil && err != io.EOF {
c.logger.Error("Decoding element failed", zap.Error(err))
return nil
}
switch start.Name.Local {
case "message":
if err := c.HandleMessage(t, stanza.(*MessageStanza)); err != nil {
c.logger.Error("Handling message failed", zap.Error(err))
}
case "presence":
if err := c.HandlePresence(t, stanza.(*PresenceStanza)); err != nil {
c.logger.Error("Handling presence failed", zap.Error(err))
}
}
return nil
}
// RegisterAt sets the Joe Brain instance for the XMPP client.
func (c *Client) RegisterAt(brain *joe.Brain) {
c.brain = brain
}
// Close shuts down the active XMPP session and server connection, returning an error if the process
// fails at any point.
func (c *Client) Close() error {
if err := c.session.Close(); err != nil {
return err
}
if err := c.session.Conn().Close(); err != nil {
return err
}
return nil
}
// Adapter initializes an XMPP client connection according to configuration given, and returns a Joe
// module, usable in calls to joe.New(), or an error if any occurs.
func Adapter(conf Config) joe.Module {
return joe.ModuleFunc(func(joeConf *joe.Config) error {
// Parse and set up JID.
id, err := jid.Parse(conf.JID)
if err != nil {
return errors.Wrap(err, "parsing JID failed")
}
var ctx = context.Background()
var dialer = &dial.Dialer{NoTLS: conf.NoTLS}
// Initialze connection according to configuration.
conn, err := dialer.Dial(ctx, "tcp", id)
if err != nil {
return errors.Wrap(err, "establishing connection failed")
}
// Enable optional features and initialize client session, according to configuration.
features := []xmpp.StreamFeature{xmpp.BindResource()}
if conf.UseStartTLS {
features = append(features, xmpp.StartTLS(true, &tls.Config{ServerName: id.Domain().String()}))
}
if conf.Password != "" {
features = append(features, xmpp.SASL("", conf.Password, defaultAuthMechanisms...))
}
sess, err := xmpp.NewClientSession(ctx, id, conn, false, features...)
if err != nil {
return errors.Wrap(err, "establishing session failed")
}
var c = &Client{session: sess, logger: conf.Logger}
if c.logger == nil {
c.logger = joeConf.Logger(id.Network())
}
// Send initial presence to let the server know we want to receive messages.
err = c.session.Send(ctx, stanza.Presence{Type: stanza.AvailablePresence}.Wrap(nil))
if err != nil {
return errors.Wrap(err, "setting initial presence failed")
}
go c.session.Serve(c)
joeConf.SetAdapter(c)
return nil
})
}
// RandomID returns a cryptographically secure, 16-byte random string, useful for adding to stanzas
// for uniquely identifying them.
func randomID() string {
var buf = make([]byte, 16)
rand.Reader.Read(buf)
return fmt.Sprintf("%x", buf)[:16]
}

37
main.go Normal file
View File

@ -0,0 +1,37 @@
package main
import (
// Standard library
"os"
// Internal packages
"github.com/deuill/informbot/joe-inform-handler"
"github.com/deuill/informbot/joe-xmpp-adapter"
// Third-party packages
"github.com/go-joe/file-memory"
"github.com/go-joe/joe"
)
func main() {
bot := joe.New(
"inform",
xmpp.Adapter(xmpp.Config{
JID: os.Getenv("INFORMBOT_JID"),
Password: os.Getenv("INFORMBOT_PASSWORD"),
NoTLS: os.Getenv("INFORMBOT_NO_TLS") == "true",
UseStartTLS: os.Getenv("INFORMBOT_USE_STARTTLS") == "true",
}),
file.Memory("store.json"),
)
in, err := inform.New(inform.Config{Bot: bot})
if err != nil {
bot.Logger.Fatal(err.Error())
}
bot.Brain.RegisterHandler(in.Handle)
if err := bot.Run(); err != nil {
bot.Logger.Fatal(err.Error())
}
}

8
vendor/github.com/go-joe/file-memory/.codecov.yml generated vendored Normal file
View File

@ -0,0 +1,8 @@
# The patch diff coverage report in pull requests is confusing at best so its
# disabled. Note that normal coverage is still collected.
coverage:
status:
patch:
default:
enabled: no

57
vendor/github.com/go-joe/file-memory/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,57 @@
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0
gocyclo:
min-complexity: 10
maligned:
suggest-new: true
goconst:
min-len: 2
min-occurrences: 2
misspell:
locale: US
lll:
line-length: 140
goimports:
local-prefixes: github.com/golangci/golangci-lint
gocritic:
enabled-tags:
- performance
- style
- experimental
- diagnostic
- opinionated
disabled-checks:
- unnamedResult
- hugeParam
linters:
enable-all: true
disable:
- wsl
- gomnd
service:
golangci-lint-version: 1.23.x # use the fixed version to not introduce new linters unexpectedly
prepare:
- GO111MODULE=on go mod vendor # required currently or golangci breaks
issues:
exclude-use-default: false
exclude-rules:
- text: "should have a package comment, unless it's in another file for this package"
linters:
- golint
- text: "Potential file inclusion via variable"
path: "memory\\.go"
- text: "Expect file permissions to be 0600 or less"
path: "memory\\.go"
- text: "Error return value of `os.Remove` is not checked"
linters:
- errcheck
path: "memory_test\\.go"

33
vendor/github.com/go-joe/file-memory/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,33 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
- Nothing so far
## [v1.0.0] - 2020-02-28
- Use error wrapping of standard library instead of github.com/pkg/errors
- Update to Go 1.14
- Release first stable version and start following semantic versioning with regards to backwards compatibility
## [v0.3.1] - 2019-10-01
- Make `Keys()` function deterministic by sorting the output.
## [v0.3.0] - 2019-04-21
- Update to new Joe Memory interface
## [v0.2.0] - 2019-03-18
- Update to the changed Module interface of joe v0.4.0
## [v0.1.0] - 2019-03-03
Initial alpha release
[Unreleased]: https://github.com/go-joe/redis-memory/compare/v1.0.0...HEAD
[v1.0.0]: https://github.com/go-joe/file-memory/compare/v0.3.1...v1.0.0
[v0.3.1]: https://github.com/go-joe/file-memory/compare/v0.3.0...v0.3.1
[v0.3.0]: https://github.com/go-joe/file-memory/compare/v0.2.0...v0.3.0
[v0.2.0]: https://github.com/go-joe/file-memory/compare/v0.1.0...v0.2.0
[v0.1.0]: https://github.com/go-joe/file-memory/releases/tag/v0.1.0

99
vendor/github.com/go-joe/file-memory/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,99 @@
# Contributing
When contributing to this repository, please first discuss the change you wish
to make via an [issue on Github][issues] *before* making a change.
Please note we have a code of conduct. Please follow it in all your interactions
with the project.
## Pull Request Process
0. Everything should start with an issue: ["Talk, then code"][talk-code]
1. Cover all your changes with unit tests, when unsure how, ask for help
2. Run all unit tests with the race detector on
3. Run the linters locally via `golangci-lint run`
4. Update the [CHANGELOG.md](CHANGELOG.md) with the changes you made (in the "Unreleased" section)
5. Consider updating the [README.md](README.md) with details of your changes.
When in doubt, lets discuss the need together in the corresponding Github issue.
6. Consider if you have to increase the version numbers in any examples files and
the README.md to the new version that this Pull Request would represent.
The versioning scheme we use is [SemVer](http://semver.org/).
## Code of Conduct
We follow the **Gopher Code of Conduct** as described at https://golang.org/conduct `\ʕ◔ϖ◔ʔ/`
### Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
### Conflict Resolution
We do not believe that all conflict is bad; healthy debate and disagreement
often yield positive results. However, it is never okay to be disrespectful or
to engage in behavior that violates the projects code of conduct.
If you see someone violating the code of conduct, you are encouraged to address
the behavior directly with those involved. Many issues can be resolved quickly
and easily, and this gives people more control over the outcome of their dispute.
If you are unable to resolve the matter for any reason, or if the behavior is
threatening or harassing, report it. We are dedicated to providing an environment
where participants feel welcome and safe.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[issues]: https://github.com/go-joe/file-memory/issues
[talk-code]: https://dave.cheney.net/2019/02/18/talk-then-code
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

27
vendor/github.com/go-joe/file-memory/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2019, Friedrich Große
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

60
vendor/github.com/go-joe/file-memory/README.md generated vendored Normal file
View File

@ -0,0 +1,60 @@
<h1 align="center">Joe Bot - File Storage</h1>
<p align="center">Basic file storage memory adapater. https://github.com/go-joe/joe</p>
<p align="center">
<a href="https://circleci.com/gh/go-joe/file-memory/tree/master"><img src="https://circleci.com/gh/go-joe/file-memory/tree/master.svg?style=shield"></a>
<a href="https://goreportcard.com/report/github.com/go-joe/file-memory"><img src="https://goreportcard.com/badge/github.com/go-joe/file-memory"></a>
<a href="https://codecov.io/gh/go-joe/file-memory"><img src="https://codecov.io/gh/go-joe/file-memory/branch/master/graph/badge.svg"/></a>
<a href="https://pkg.go.dev/github.com/go-joe/file-memory?tab=doc"><img src="https://img.shields.io/badge/godoc-reference-blue.svg?color=blue"></a>
<a href="https://github.com/go-joe/file-memory/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-BSD--3--Clause-blue.svg"></a>
</p>
---
This repository contains a module for the [Joe Bot library][joe].
## Getting Started
This library is packaged as [Go module][go-modules]. You can get it via:
```
go get github.com/go-joe/file-memory
```
## Example usage
```go
b := &ExampleBot{
Bot: joe.New("example", file.Memory("foobar.json")),
}
```
## Built With
* [testify](https://github.com/stretchr/testify) - A simple unit test library
* [zap](https://github.com/uber-go/zap) - Blazing fast, structured, leveled logging in Go
## Contributing
If you want to hack on this repository, please read the short [CONTRIBUTING.md](CONTRIBUTING.md)
guide first.
## Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available,
see the [tags on this repository][tags].
## Authors
- **Friedrich Große** - *Initial work* - [fgrosse](https://github.com/fgrosse)
- **Stefan Warman** - *Unit tests* - [warmans](https://github.com/warmans)
See also the list of [contributors][contributors] who participated in this project.
## License
This project is licensed under the BSD-3-Clause License - see the [LICENSE](LICENSE) file for details.
[joe]: https://github.com/go-joe/joe
[go-modules]: https://github.com/golang/go/wiki/Modules
[tags]: https://github.com/go-joe/file-memory/tags
[contributors]: https://github.com/go-joe/file-memory/contributors

10
vendor/github.com/go-joe/file-memory/go.mod generated vendored Normal file
View File

@ -0,0 +1,10 @@
module github.com/go-joe/file-memory
go 1.13
require (
github.com/go-joe/joe v0.8.0
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.3.0
go.uber.org/zap v1.9.1
)

18
vendor/github.com/go-joe/file-memory/go.sum generated vendored Normal file
View File

@ -0,0 +1,18 @@
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/go-joe/joe v0.8.0 h1:q/S16mDS31uw9eqatuytylgapOU6tYqxXVmQIa2mDts=
github.com/go-joe/joe v0.8.0/go.mod h1:fjDMMKm6GV29+egH/IS57PTKHSBMquckyuM7CmXbUQw=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/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/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=

189
vendor/github.com/go-joe/file-memory/memory.go generated vendored Normal file
View File

@ -0,0 +1,189 @@
package file
import (
"encoding/json"
"errors"
"fmt"
"os"
"sort"
"github.com/go-joe/joe"
"go.uber.org/zap"
)
// memory is an implementation of a joe.Memory which stores all values as a JSON
// encoded file. Note that there is no need for a joe.Memory to handle
// synchronization for concurrent access (e.g. via locks) because this is
// automatically handled by the joe.Brain.
type memory struct {
path string
logger *zap.Logger
data map[string][]byte
}
// Memory is a joe.Option which is supposed to be passed to joe.New(…) to
// configure a new bot. The path indicates the destination file at which the
// memory will store its values encoded as JSON object. If there is already a
// JSON encoded file at the given path it will be loaded and decoded into memory
// to serve future requests. If the file exists but cannot be opened or does not
// contain a valid JSON object its error will be deferred until the bot is
// actually started via its Run() function.
//
// Example usage:
// b := joe.New("example",
// file.Memory("/tmp/joe.json"),
// …
// )
func Memory(path string) joe.Module {
return joe.ModuleFunc(func(conf *joe.Config) error {
memory, err := NewMemory(path, WithLogger(conf.Logger("memory")))
if err != nil {
return err
}
conf.SetMemory(memory)
return nil
})
}
// NewMemory creates a new Memory instance that persists all values to the given
// path. If there is already a JSON encoded file at the given path it is loaded
// and decoded into memory to serve future requests. An error is returned if the
// file exists but cannot be opened or does not contain a valid JSON object.
func NewMemory(path string, opts ...Option) (joe.Memory, error) {
memory := &memory{
path: path,
data: map[string][]byte{},
}
for _, opt := range opts {
err := opt(memory)
if err != nil {
return nil, err
}
}
if memory.logger == nil {
memory.logger = zap.NewNop()
}
memory.logger.Debug("Opening memory file", zap.String("path", path))
f, err := os.Open(path)
switch {
case os.IsNotExist(err):
memory.logger.Debug("File does not exist. Continuing with empty memory", zap.String("path", path))
case err != nil:
return nil, fmt.Errorf("failed to open file: %w", err)
default:
memory.logger.Debug("Decoding JSON from memory file", zap.String("path", path))
err := json.NewDecoder(f).Decode(&memory.data)
_ = f.Close()
if err != nil {
return nil, fmt.Errorf("failed decode data as JSON: %w", err)
}
}
memory.logger.Info("Memory initialized successfully",
zap.String("path", path),
zap.Int("num_memories", len(memory.data)),
)
return memory, nil
}
// Set assign the key to the value and then saves the updated memory to its JSON
// file. An error is returned if this function is called after the memory was
// closed already or if the file could not be written or updated.
func (m *memory) Set(key string, value []byte) error {
if m.data == nil {
return errors.New("brain was already shut down")
}
m.data[key] = value
return m.persist()
}
// Get returns the value that is associated with the given key. The second
// return value indicates if the key actually existed in the memory.
//
// An error is only returned if this function is called after the memory was
// closed already.
func (m *memory) Get(key string) ([]byte, bool, error) {
if m.data == nil {
return nil, false, errors.New("brain was already shut down")
}
value, ok := m.data[key]
return value, ok, nil
}
// Delete removes any value that might have been assigned to the key earlier.
// The boolean return value indicates if the memory contained the key. If it did
// not contain the key the function does nothing and returns without an error.
// If the key existed it is removed and the corresponding JSON file is updated.
//
// An error is returned if this function is called after the memory was closed
// already or if the file could not be written or updated.
func (m *memory) Delete(key string) (bool, error) {
if m.data == nil {
return false, errors.New("brain was already shut down")
}
_, ok := m.data[key]
if !ok {
return false, nil
}
delete(m.data, key)
return ok, m.persist()
}
// Keys returns a list of all keys known to this memory.
// An error is only returned if this function is called after the memory was
// closed already.
func (m *memory) Keys() ([]string, error) {
if m.data == nil {
return nil, errors.New("brain was already shut down")
}
keys := make([]string, 0, len(m.data))
for k := range m.data {
keys = append(keys, k)
}
// provide a stable result
sort.Strings(keys)
return keys, nil
}
// Close removes all data from the memory. Note that all calls to the memory
// will fail after this function has been called.
func (m *memory) Close() error {
if m.data == nil {
return errors.New("brain was already closed")
}
m.data = nil
return nil
}
func (m *memory) persist() error {
f, err := os.OpenFile(m.path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
if err != nil {
return fmt.Errorf("failed to open file to persist data: %w", err)
}
err = json.NewEncoder(f).Encode(m.data)
if err != nil {
_ = f.Close()
return fmt.Errorf("failed to encode data as JSON: %w", err)
}
err = f.Close()
if err != nil {
return fmt.Errorf("failed to close file; data might not have been fully persisted to disk: %w", err)
}
return nil
}

23
vendor/github.com/go-joe/file-memory/options.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
// Package file implements file based memory for the Joe bot library.
// https://github.com/go-joe/joe
package file
import "go.uber.org/zap"
// Option corresponds to a configuration setting of the file memory.
// All available options are the exported functions of this package that share
// the prefix "With" in their names.
type Option func(*memory) error
// WithLogger is a memory option that allows the caller to set a different
// logger. By default this option is not required because the file.Memory(…)
// function automatically uses the logger of the given joe.Config.
func WithLogger(logger *zap.Logger) Option {
return func(memory *memory) error {
memory.logger = logger
return nil
}
}
// IDEA: encrypted brain?
// IDEA: only decrypt keys on demand?

8
vendor/github.com/go-joe/joe/.codecov.yml generated vendored Normal file
View File

@ -0,0 +1,8 @@
# The patch diff coverage report in pull requests is confusing at best so its
# disabled. Note that normal coverage is still collected.
coverage:
status:
patch:
default:
enabled: no

82
vendor/github.com/go-joe/joe/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,82 @@
linters-settings:
govet:
check-shadowing: false
golint:
min-confidence: 0
gocyclo:
min-complexity: 10
maligned:
suggest-new: true
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
misspell:
locale: US
lll:
line-length: 140
goimports:
local-prefixes: github.com/golangci/golangci-lint
gocritic:
enabled-tags:
- performance
- style
- experimental
- diagnostic
- opinionated
disabled-checks:
- unnamedResult
linters:
enable-all: true
disable:
- maligned
- prealloc
- depguard
- interfacer
service:
golangci-lint-version: 1.19.x # use the fixed version to not introduce new linters unexpectedly
prepare:
- GO111MODULE=on go mod vendor # required currently or golangci breaks
issues:
exclude-use-default: false
exclude-rules:
- text: "G104: Errors unhandled."
path: ".+_test\\.go"
linters:
- gosec
- text: "should have a package comment, unless it's in another file for this package"
linters:
- golint
- text: "Using the variable on range scope `c` in function literal"
path: ".+_test\\.go"
linters:
- scopelint
- text: "`ctx` is a global variable"
path: ".+_test\\.go"
linters:
- gochecknoglobals
- text: "Function 'TestBrain_RegisterHandler' is too long"
path: ".+_test\\.go"
linters:
- funlen
- text: "Line contains TODO/BUG/FIXME"
linters:
- godox
- text: "hugeParam"
linters:
- gocritic
- text: "should have comment or be unexported"
path: "main.go"
linters:
- golint

102
vendor/github.com/go-joe/joe/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,102 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
**THIS SOFTWARE IS STILL IN ALPHA AND THERE ARE NO GUARANTEES REGARDING API STABILITY YET.**
Once we reach the v1.0 release, this project will adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
Nothing so far
## [v0.10.0] - 2019-10-26
- Allow event handlers to also use scalar event types (fixes #14)
- Add new `FinishEventContent(…)` function to finish event processing with multiple handlers early
- **Breaking change:** Message handlers registered via `Bot.Respond(…)` and `Bot.RespondRegex(…)` now abort early if the pattern matches
- This allows users to specify a default response when nothing else matches (see #25)
## [v0.9.0] - 2019-10-22
- Add `Auth.Users()` and `Auth.UserPermissions(…)` functions to allow retrieving all users as well as users permissions.
- Allow adapters to implement the optional `ReactionAwareAdapter` interface if they support emoji reactions
- Add new `reactions` package which contains a compiled list of all officially supported reactions
- Components may now return the new `ErrNotImplemented` if they do not support a feature
- Add new `reactions.Event` that may be emitted by an Adapter so users can listen for it
## [v0.8.0] - 2019-04-21
- Make `Auth.Grant(…)` idempotent and do not unnecessarily add smaller scopes
- Support extending permissions via `Auth.Grant(…)`
- Add boolean return value to `Auth.Grant(…)` to indicate if a new permission was granted
- Add `Auth.Revoke(…)` to remove permissions
- Fix flaky unit test TestBrain_Memory
- Fix flaky TestCLIAdapter_Register test
- Add new `Storage` type which manages encoding/decoding, concurrent access and logging for a `Memory`
- Factor out `Memory` related logic from Brain into new `Storage` type
- Removed `Brain.SetMemory(…)`, `Brain.Set(…)`, `Brain.Get(…)`, `Brain.Delete(…)`, `Brain.Memories(…)`, `Brain.Close(…)`
- All functions above except `Brain.Memories(…)` are now available as functions on the `Bot.Store` field
- The `Auth` type no longer uses the `Memory` interface but instead requires an instance of the new `Storage` type
- Removed the `BrainMemoryEvent` without replacement
- Add `joetest.Storage` type to streamline making assertions on a bots storage/memory
- Change the `Memory` interface to treat values as `[]byte` and not `string`
- Remove `Memories()` function from `Memory` interface and instead add a `Keys()` function
- `NewConfig(…)` now requires an instance of a `Storage`
## [v0.7.0] - 2019-04-18
- Add ReceiveMessageEvent.Data field to allow using the underlying message type of the adapters
- Add ReceiveMessageEvent.AuthorID field to identify the author of the message
- Add Message.Data field which contains a copy of the ReceiveMessageEvent.Data value
- Add Message.AuthorID field which contains a copy of the ReceiveMessageEvent.AuthorID value
- Add Auth.Grant(…) and Auth.CheckPermission(…) functions to allow implementing user permissions
- Add Brain.Close() function to let the brain implement the Memory interface
- Add Brain.SetMemory(…) function to give more control over a joe.Brain
- Fix joetest.Bot.Start(…) function to return only when actually _all_ initialization is done
## [v0.6.0] - 2019-03-30
- implement `NewConfig` function to allow create configuration for unit tests of modules
## [v0.5.0] - 2019-03-18
- Fixed nil pointer panic in slack adapter when context is nil
## [v0.4.0] - 2019-03-18
- Change type of `Module` from function to interface to allow more flexibility
- Introduce new `ModuleFunc` type to migrate old modules to new interface type
## [v0.3.0] - 2019-03-17
- Event handler functions can now accept interfaces instead of structs
- Add new `github.com/go-joe/joe/joetest` package for unit tests
- Add new `joetest.Brain` type
- Add new `WithLogger(…)` option
- Switch license from MIT to BSD-3-Clause
- Move `TestingT` type into new `joetest` package
- Move `TestBot` type into new `joetest` package and rename to `joetest.Bot`
- Fixed flaky unit test of `CLIAdapter`
## [v0.2.0] - 2019-03-10
- Add a lot more unit tests
- Add `TestBot.Start()` and `TestBot.Stop()`to ease synchronously starting and stopping bot in unit tests
- Add `TestBot.EmitSync(…)` to emit events synchronously in unit tests
- Remove obsolete context argument from `NewTest(…)` function
- Errors from passing invalid expressions to `Bot.Respond(…)` are now returned in `Bot.Run()`
- Events are now processed in the exact same order in which they are emitted
- All pending events are now processed before the brain event loop returns
- Replace context argument from `Brain.HandleEvents()` with new `Brain.Shutdown()` function
- `Adapter` interface was simplified again to directly use the `Brain`
- Remove unnecessary `t` argument from `TestBot.EmitSync(…)` function
- Deleted `Brain.Close()` because it was not actually meant to be used to close the brain and is thus confusing
## [v0.1.0] - 2019-03-03
Initial release, note that Joe is still in alpha and the API is not yet considered
stable before the v1.0.0 release.
[Unreleased]: https://github.com/go-joe/joe/compare/v0.10.0...HEAD
[v0.9.0]: https://github.com/go-joe/joe/compare/v0.9.0...v0.10.0
[v0.9.0]: https://github.com/go-joe/joe/compare/v0.8.0...v0.9.0
[v0.8.0]: https://github.com/go-joe/joe/compare/v0.7.0...v0.8.0
[v0.7.0]: https://github.com/go-joe/joe/compare/v0.6.0...v0.7.0
[v0.6.0]: https://github.com/go-joe/joe/compare/v0.5.0...v0.6.0
[v0.5.0]: https://github.com/go-joe/joe/compare/v0.4.0...v0.5.0
[v0.4.0]: https://github.com/go-joe/joe/compare/v0.3.0...v0.4.0
[v0.3.0]: https://github.com/go-joe/joe/compare/v0.2.0...v0.3.0
[v0.2.0]: https://github.com/go-joe/joe/compare/v0.1.0...v0.2.0
[v0.1.0]: https://github.com/go-joe/joe/releases/tag/v0.1.0

97
vendor/github.com/go-joe/joe/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,97 @@
# Contributing
When contributing to this repository, please first discuss the change you wish
to make via an [issue on Github][issues] *before* making a change.
Please note we have a code of conduct. Please follow it in all your interactions
with the project.
## Pull Request Process
0. Everything should start with an issue: ["Talk, then code"][talk-code]
1. Cover all your changes with unit tests, when unsure how, ask for help
2. Run all unit tests with the race detector on
3. Run the linters locally via `golangci-lint run`
4. Update the [CHANGELOG.md](CHANGELOG.md) with the changes you made (in the "Unreleased" section)
5. Consider updating the [README.md](README.md) with details of your changes.
When in doubt, lets discuss the need together in the corresponding Github issue.
6. Check that all examples are up to date and do still compile with the `check` Makefile target in the `_examples` directory.
## Code of Conduct
We follow the **Gopher Code of Conduct** as described at https://golang.org/conduct `\ʕ◔ϖ◔ʔ/`
### Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
### Conflict Resolution
We do not believe that all conflict is bad; healthy debate and disagreement
often yield positive results. However, it is never okay to be disrespectful or
to engage in behavior that violates the projects code of conduct.
If you see someone violating the code of conduct, you are encouraged to address
the behavior directly with those involved. Many issues can be resolved quickly
and easily, and this gives people more control over the outcome of their dispute.
If you are unable to resolve the matter for any reason, or if the behavior is
threatening or harassing, report it. We are dedicated to providing an environment
where participants feel welcome and safe.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[issues]: https://github.com/go-joe/joe/issues
[talk-code]: https://dave.cheney.net/2019/02/18/talk-then-code
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

27
vendor/github.com/go-joe/joe/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2019, Friedrich Große
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

372
vendor/github.com/go-joe/joe/README.md generated vendored Normal file
View File

@ -0,0 +1,372 @@
<h1 align="center">Joe Bot</h1>
<p align="center">A general-purpose bot library inspired by Hubot but written in Go.</p>
<p align="center">
<a href="https://github.com/go-joe/joe/releases"><img src="https://img.shields.io/github/tag/go-joe/joe.svg?label=version&color=brightgreen"></a>
<a href="https://circleci.com/gh/go-joe/joe/tree/master"><img src="https://circleci.com/gh/go-joe/joe/tree/master.svg?style=shield"></a>
<a href="https://goreportcard.com/report/github.com/go-joe/joe"><img src="https://goreportcard.com/badge/github.com/go-joe/joe"></a>
<a href="https://codecov.io/gh/go-joe/joe"><img src="https://codecov.io/gh/go-joe/joe/branch/master/graph/badge.svg"/></a>
<a href="https://godoc.org/github.com/go-joe/joe"><img src="https://img.shields.io/badge/godoc-reference-blue.svg?color=blue"></a>
<a href="https://github.com/go-joe/joe/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-BSD--3--Clause-blue.svg"></a>
</p>
---
Joe is a library used to write chat bots in [the Go programming language][go].
It is very much inspired by the awesome [Hubot][hubot] framework developed by the
folks at Github and brings its power to people who want to implement chat bots using Go.
## Getting Started
**THIS SOFTWARE IS STILL IN ALPHA AND THERE ARE NO GUARANTEES REGARDING API STABILITY YET.**
All significant (e.g. breaking) changes are documented in the [CHANGELOG.md](CHANGELOG.md).
Joe is packaged using the new [Go modules][go-modules]. You can get joe via:
```
go get github.com/go-joe/joe
```
### Minimal example
The simplest chat bot listens for messages on a chat _Adapter_ and then executes
a _Handler_ function if it sees a message directed to the bot that matches a given pattern.
For example a bot that responds to a message "ping" with the answer "PONG" looks like this:
[embedmd]:# (_examples/01_minimal/main.go)
```go
package main
import "github.com/go-joe/joe"
func main() {
b := joe.New("example-bot")
b.Respond("ping", Pong)
err := b.Run()
if err != nil {
b.Logger.Fatal(err.Error())
}
}
func Pong(msg joe.Message) error {
msg.Respond("PONG")
return nil
}
```
### Useful example
Each bot consists of a chat _Adapter_ (e.g. to integrate with Slack), a _Memory_
implementation to remember key-value data (e.g. using Redis) and a _Brain_ which
routes new messages or custom events (e.g. receiving an HTTP call) to the
corresponding registered _handler_ functions.
By default `joe.New(…)` uses the CLI adapter which makes the bot read messages
from stdin and respond on stdout. Additionally the bot will store key value
data in-memory which means it will forget anything you told it when it is restarted.
This default setup is useful for local development without any dependencies but
you will quickly want to add other _Modules_ to extend the bots capabilities.
For instance we can extend the previous example to connect the Bot with a Slack
workspace and store key-value data in Redis. To allow the message handlers to
access the memory we define them as functions on a custom `ExampleBot`type which
embeds the `joe.Bot`.
[embedmd]:# (_examples/02_useful/main.go)
```go
package main
import (
"github.com/go-joe/joe"
"github.com/go-joe/redis-memory"
"github.com/go-joe/slack-adapter"
"github.com/pkg/errors"
)
type ExampleBot struct {
*joe.Bot
}
func main() {
b := &ExampleBot{
Bot: joe.New("example",
redis.Memory("localhost:6379"),
slack.Adapter("xoxb-1452345…"),
),
}
b.Respond("remember (.+) is (.+)", b.Remember)
b.Respond("what is (.+)", b.WhatIs)
err := b.Run()
if err != nil {
b.Logger.Fatal(err.Error())
}
}
func (b *ExampleBot) Remember(msg joe.Message) error {
key, value := msg.Matches[0], msg.Matches[1]
msg.Respond("OK, I'll remember %s is %s", key, value)
return b.Store.Set(key, value)
}
func (b *ExampleBot) WhatIs(msg joe.Message) error {
key := msg.Matches[0]
var value string
ok, err := b.Store.Get(key, &value)
if err != nil {
return errors.Wrapf(err, "failed to retrieve key %q from brain", key)
}
if ok {
msg.Respond("%s is %s", key, value)
} else {
msg.Respond("I do not remember %q", key)
}
return nil
}
```
### Handling custom events
The previous example should give you an idea already on how to write simple chat
bots. It is missing one important part however: how can a bot trigger any
interaction proactively, i.e. without a message from a user.
To solve this problem, joe's Brain implements an event handler that you can hook
into. In fact the `Bot.Respond(…)` function that we used in the earlier examples
is doing exactly that to listen for any `joe.ReceiveMessageEvent` that match the
specified regular expression and then execute the handler function.
Implementing custom events is easy because you can emit any type as event and
register handlers that match only this type. What this exactly means is best
demonstrated with another example:
[embedmd]:# (_examples/03_custom_events/main.go)
```go
package main
import (
"time"
"github.com/go-joe/joe"
)
type ExampleBot struct {
*joe.Bot
Channel string // example for your custom bot configuration
}
type CustomEvent struct {
Data string // just an example of attaching any data with a custom event
}
func main() {
b := &ExampleBot{
Bot: joe.New("example"),
Channel: "CDEADBEAF", // example reference to a slack channel
}
// Register our custom event handler. Joe inspects the function signature to
// understand that this function should be invoked whenever a CustomEvent
// is emitted.
b.Brain.RegisterHandler(b.HandleCustomEvent)
// For example purposes emit a CustomEvent in a second.
time.AfterFunc(time.Second, func() {
b.Brain.Emit(CustomEvent{Data: "Hello World!"})
})
err := b.Run()
if err != nil {
b.Logger.Fatal(err.Error())
}
}
// HandleCustomEvent handles any CustomEvent that is emitted. Joe also supports
// event handlers that return an error or accept a context.Context as first argument.
func (b *ExampleBot) HandleCustomEvent(evt CustomEvent) {
b.Say(b.Channel, "Received custom event: %v", evt.Data)
}
```
### Granting and checking user permissions
Joe supports a simple way to manage user permissions. For instance you may want
to define a message handler that will run an operation which only admins should
be allowed to trigger.
To implement this, joe has a concept of permission scopes. A scope is a string
which is _granted_ to a specific user ID so you can later check if the author of
the event you are handling (e.g. a message from Slack) has this scope or any
scope that _contains_ it.
Scopes are interpreted in a hierarchical way where scope _A_ can contain scope
_B_ if _A_ is a prefix to _B_. For example, you can check if a user is allowed
to read or write from the "Example" API by checking the `api.example.read` or
`api.example.write` scope. When you grant the scope to a user you can now either
decide only to grant the very specific `api.example.read` scope which means the
user will not have write permissions or you can allow people write-only access
via the `api.example.write` scope.
Alternatively you can also grant any access to the Example API via `api.example`
which includes both the read and write scope beneath it. If you want you
could also allow even more general access to everything in the api via the
`api` scope.
Scopes can be granted statically in code or dynamically in a handler like this:
[embedmd]:# (_examples/04_auth/main.go)
```go
package main
import "github.com/go-joe/joe"
type ExampleBot struct {
*joe.Bot
}
func main() {
b := &ExampleBot{
Bot: joe.New("HAL"),
}
// If you know the user ID in advance you may hard-code it at startup.
b.Auth.Grant("api.example", "DAVE")
// An example of a message handler that checks permissions.
b.Respond("open the pod bay doors", b.OpenPodBayDoors)
err := b.Run()
if err != nil {
b.Logger.Fatal(err.Error())
}
}
func (b *ExampleBot) OpenPodBayDoors(msg joe.Message) error {
err := b.Auth.CheckPermission("api.example.admin", msg.AuthorID)
if err != nil {
return msg.RespondE("I'm sorry Dave, I'm afraid I can't do that")
}
return msg.RespondE("OK")
}
```
### Integrating with other applications
You may want to integrate your bot with applications such as Github or Gitlab to
trigger a handler or just send a message to Slack. Usually this is done by
providing an HTTP callback to those applications so they can POST data when
there is an event. We already saw in the previous section that is is very easy
to implement custom events so we will use this feature to implement HTTP
integrations as well. Since this is such a dominant use-case we already provide
the [`github.com/go-joe/http-server`][joe-http] module to make it easy for
everybody to write their own custom integrations.
[embedmd]:# (_examples/05_http/main.go)
```go
package main
import (
"context"
"errors"
joehttp "github.com/go-joe/http-server"
"github.com/go-joe/joe"
)
type ExampleBot struct {
*joe.Bot
}
func main() {
b := &ExampleBot{Bot: joe.New("example",
joehttp.Server(":8080"),
)}
b.Brain.RegisterHandler(b.HandleHTTP)
err := b.Run()
if err != nil {
b.Logger.Fatal(err.Error())
}
}
func (b *ExampleBot) HandleHTTP(context.Context, joehttp.RequestEvent) error {
return errors.New("TODO: Add your custom logic here")
}
```
## Available modules
Joe ships with no third-party modules such as Redis integration to avoid pulling
in more dependencies than you actually require. There are however already some
modules that you can use directly to extend the functionality of your bot without
writing too much code yourself.
If you have written a module and want to share it, please add it to this list and
open a pull request.
### Chat Adapters
- Slack Adapter: https://github.com/go-joe/slack-adapter
- Rocket.Chat Adapter: https://github.com/dwmunster/rocket-adapter
- Telegram Adapter: https://github.com/robertgzr/joe-telegram-adapter
- IRC Adapter: https://github.com/akrennmair/joe-irc-adapter
### Memory Modules
- Redis Memory: https://github.com/go-joe/redis-memory
- File Memory: https://github.com/go-joe/file-memory
- Bolt Memory: https://github.com/robertgzr/joe-bolt-memory
- Sqlite Memory: https://github.com/warmans/sqlite-memory
### Other Modules
- HTTP Server: https://github.com/go-joe/http-server
- Cron Jobs: https://github.com/go-joe/cron
## Built With
* [zap](https://github.com/uber-go/zap) - Blazing fast, structured, leveled logging in Go
* [pkg/errors](https://github.com/pkg/errors) - Simple error handling primitives
* [testify](https://github.com/stretchr/testify) - A simple unit test library
## Contributing
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of
conduct and on the process for submitting pull requests to this repository.
## Versioning
**THIS SOFTWARE IS STILL IN ALPHA AND THERE ARE NO GUARANTEES REGARDING API STABILITY YET.**
After the v1.0 release we plan to use [SemVer](http://semver.org/) for versioning.
For the versions available, see the [tags on this repository][tags].
## Authors
- **Friedrich Große** - *Initial work* - [fgrosse](https://github.com/fgrosse)
See also the list of [contributors][contributors] who participated in this project.
## License
This project is licensed under the BSD-3-Clause License - see the [LICENSE](LICENSE) file for details.
## Acknowledgments
- [Hubot][hubot] and its great community for the inspiration
- [embedmd][embedmd] for a cool tool to embed source code in markdown files
[go]: https://golang.org
[hubot]: https://hubot.github.com/
[go-modules]: https://github.com/golang/go/wiki/Modules
[joe-http]: https://github.com/go-joe/http-server
[tags]: https://github.com/go-joe/joe/tags
[contributors]: https://github.com/go-joe/joe/contributors
[embedmd]: https://github.com/campoy/embedmd

1
vendor/github.com/go-joe/joe/_config.yml generated vendored Normal file
View File

@ -0,0 +1 @@
theme: jekyll-theme-hacker

192
vendor/github.com/go-joe/joe/adapter.go generated vendored Normal file
View File

@ -0,0 +1,192 @@
package joe
import (
"bufio"
"fmt"
"io"
"os"
"sync"
"github.com/go-joe/joe/reactions"
"github.com/pkg/errors"
"go.uber.org/zap"
)
// An Adapter connects the bot with the chat by enabling it to receive and send
// messages. Additionally advanced adapters can emit more events than just the
// ReceiveMessageEvent (e.g. the slack adapter also emits the UserTypingEvent).
// All adapter events must be setup in the RegisterAt function of the Adapter.
//
// Joe provides a default CLIAdapter implementation which connects the bot with
// the local shell to receive messages from stdin and print messages to stdout.
type Adapter interface {
RegisterAt(*Brain)
Send(text, channel string) error
Close() error
}
// ReactionAwareAdapter is an optional interface that Adapters can implement if
// they support reacting to messages with emojis.
type ReactionAwareAdapter interface {
React(reactions.Reaction, Message) error
}
// The CLIAdapter is the default Adapter implementation that the bot uses if no
// other adapter was configured. It emits a ReceiveMessageEvent for each line it
// receives from stdin and prints all sent messages to stdout.
//
// The CLIAdapter does not set the Message.Data field.
type CLIAdapter struct {
Prefix string
Input io.ReadCloser
Output io.Writer
Logger *zap.Logger
Author string // used to set the author of the messages, defaults to os.Getenv("USER)
mu sync.Mutex // protects the Output and closing channel
closing chan chan error
}
// NewCLIAdapter creates a new CLIAdapter. The caller must call Close
// to make the CLIAdapter stop reading messages and emitting events.
func NewCLIAdapter(name string, logger *zap.Logger) *CLIAdapter {
return &CLIAdapter{
Prefix: fmt.Sprintf("%s > ", name),
Input: os.Stdin,
Output: os.Stdout,
Logger: logger,
Author: os.Getenv("USER"),
closing: make(chan chan error),
}
}
// RegisterAt starts the CLIAdapter by reading messages from stdin and emitting
// a ReceiveMessageEvent for each of them. Additionally the adapter hooks into
// the InitEvent to print a nice prefix to stdout to show to the user it is
// ready to accept input.
func (a *CLIAdapter) RegisterAt(brain *Brain) {
brain.RegisterHandler(func(evt InitEvent) {
_ = a.print(a.Prefix)
})
go a.loop(brain)
}
func (a *CLIAdapter) loop(brain *Brain) {
input := a.readLines()
// The adapter loop is built to stay responsive even if the Brain stops
// processing events so we can safely close the CLIAdapter.
//
// We want to print the prefix each time when the Brain has completely
// processed a ReceiveMessageEvent and before we are emitting the next one.
// This gives us a shell-like behavior which signals to the user that she
// can input more data on the CLI. This channel is buffered so we do not
// block the Brain when it executes the callback.
callback := make(chan Event, 1)
callbackFun := func(evt Event) {
callback <- evt
}
var lines = input // channel represents the case that we receive a new message
for {
select {
case msg, ok := <-lines:
if !ok {
// no more input from stdin
lines = nil // disable this case and wait for closing signal
continue
}
lines = nil // disable this case and wait for the callback
brain.Emit(ReceiveMessageEvent{Text: msg, AuthorID: a.Author}, callbackFun)
case <-callback:
// This case is executed after all ReceiveMessageEvent handlers have
// completed and we can continue with the next line.
_ = a.print(a.Prefix)
lines = input // activate first case again
case result := <-a.closing:
if lines == nil {
// We were just waiting for our callback
_ = a.print(a.Prefix)
}
_ = a.print("\n")
result <- a.Input.Close()
return
}
}
}
// ReadLines reads lines from stdin and returns them in a channel.
// All strings in the returned channel will not include the trailing newline.
// The channel is closed automatically when a.Input is closed.
func (a *CLIAdapter) readLines() <-chan string {
r := bufio.NewReader(a.Input)
lines := make(chan string)
go func() {
// This goroutine will exit when we call a.Input.Close() which will make
// r.ReadString(…) return an io.EOF.
for {
line, err := r.ReadString('\n')
switch {
case err == io.EOF:
close(lines)
return
case err != nil:
a.Logger.Error("Failed to read messages from input", zap.Error(err))
return
}
lines <- line[:len(line)-1]
}
}()
return lines
}
// Send implements the Adapter interface by sending the given text to stdout.
// The channel argument is required by the Adapter interface but is otherwise ignored.
func (a *CLIAdapter) Send(text, channel string) error {
return a.print(text + "\n")
}
// React implements the optional ReactionAwareAdapter interface by simply
// printing the given reaction as UTF8 emoji to the CLI.
func (a *CLIAdapter) React(r reactions.Reaction, _ Message) error {
return a.print(r.String() + "\n")
}
// Close makes the CLIAdapter stop emitting any new events or printing any output.
// Calling this function more than once will result in an error.
func (a *CLIAdapter) Close() error {
if a.closing == nil {
return errors.Errorf("already closed")
}
a.Logger.Debug("Closing CLIAdapter")
callback := make(chan error)
a.closing <- callback
err := <-callback
// Mark CLIAdapter as closed by setting its closing channel to nil.
// This will prevent any more output to be printed after this function returns.
a.mu.Lock()
a.closing = nil
a.mu.Unlock()
return err
}
func (a *CLIAdapter) print(msg string) error {
a.mu.Lock()
if a.closing == nil {
return errors.New("adapter is closed")
}
_, err := fmt.Fprint(a.Output, msg)
a.mu.Unlock()
return err
}

230
vendor/github.com/go-joe/joe/auth.go generated vendored Normal file
View File

@ -0,0 +1,230 @@
package joe
import (
"strings"
"github.com/pkg/errors"
"go.uber.org/zap"
)
// ErrNotAllowed is returned if the user is not allowed access to a specific scope.
const ErrNotAllowed = Error("not allowed")
// permissionKeyPrefix is the key prefix in the Storage that all permission keys have.
const permissionKeyPrefix = "joe.permissions."
// Auth implements logic to add user authorization checks to your bot.
type Auth struct {
logger *zap.Logger
store *Storage
}
// NewAuth creates a new Auth instance.
func NewAuth(logger *zap.Logger, store *Storage) *Auth {
return &Auth{
logger: logger,
store: store,
}
}
// CheckPermission checks if a user has permissions to access a resource under a
// given scope. If the user is not permitted access this function returns
// ErrNotAllowed.
//
// Scopes are interpreted in a hierarchical way where scope A can contain scope B
// if A is a prefix to B. For example, you can check if a user is allowed to
// read or write from the "Example" API by checking the "api.example.read" or
// "api.example.write" scope. When you grant the scope to a user you can now
// either decide only to grant the very specific "api.example.read" scope which
// means the user will not have write permissions or you can allow people
// write-only access via "api.example.write".
//
// Alternatively you can also grant any access to the Example API via "api.example"
// which includes both the read and write scope beneath it. If you choose to, you
// could also allow even more general access to everything in the api via the
// "api" scope. The empty scope "" cannot be granted and will thus always return
// an error in the permission check.
func (a *Auth) CheckPermission(scope, userID string) error {
key := a.permissionsKey(userID)
permissions, err := a.loadPermissions(key)
if err != nil {
return errors.WithStack(err)
}
a.logger.Debug("Checking user permissions",
zap.String("requested_scope", scope),
zap.String("user_id", userID),
)
for _, p := range permissions {
if strings.HasPrefix(scope, p) {
return nil
}
}
return ErrNotAllowed
}
// Users returns a list of user IDs having one or more permission scopes.
func (a *Auth) Users() ([]string, error) {
a.logger.Debug("Retrieving all user IDs from storage")
keys, err := a.store.Keys()
if err != nil {
return nil, errors.Wrap(err, "failed to load permissions")
}
var userIDs []string
for _, key := range keys {
if strings.HasPrefix(key, permissionKeyPrefix) {
userID := strings.TrimPrefix(key, permissionKeyPrefix)
userIDs = append(userIDs, userID)
}
}
return userIDs, nil
}
// UserPermissions returns all permission scopes for a specific user.
func (a *Auth) UserPermissions(userID string) ([]string, error) {
a.logger.Debug("Retrieving user permissions from storage",
zap.String("user_id", userID),
)
key := a.permissionsKey(userID)
permissions, err := a.loadPermissions(key)
if err != nil {
return nil, errors.WithStack(err)
}
return permissions, nil
}
func (a *Auth) loadPermissions(key string) ([]string, error) {
var permissions []string
ok, err := a.store.Get(key, &permissions)
if err != nil {
return nil, errors.Wrap(err, "failed to load user permissions")
}
if !ok {
return nil, nil
}
return permissions, nil
}
// Grant adds a permission scope to the given user. When a scope was granted
// to a specific user it can be checked later via CheckPermission(…).
// The returned boolean indicates whether the scope was actually added (i.e. true)
// or the user already had the granted scope (false).
//
// Note that granting a scope is an idempotent operations so granting the same
// scope multiple times is a safe operation and will not change the internal
// permissions that are written to the Memory.
//
// The empty scope cannot be granted and trying to do so will result in an error.
// If you want to grant access to all scopes you should prefix them with a
// common scope such as "root." or "api.".
func (a *Auth) Grant(scope, userID string) (bool, error) {
if scope == "" {
return false, errors.New("scope cannot be empty")
}
key := a.permissionsKey(userID)
oldPermissions, err := a.loadPermissions(key)
if err != nil {
return false, errors.WithStack(err)
}
newPermissions := make([]string, 0, len(oldPermissions)+1)
for _, p := range oldPermissions {
if strings.HasPrefix(scope, p) {
// The user already has this or a scope that "contains" it
return false, nil
}
if !strings.HasPrefix(p, scope) {
newPermissions = append(newPermissions, p)
}
}
a.logger.Info("Granting user permission",
zap.String("userID", userID),
zap.String("scope", scope),
)
newPermissions = append(newPermissions, scope)
err = a.updatePermissions(key, newPermissions)
return true, err
}
// Revoke removes a previously granted permission from a user. If the user does
// not currently have the revoked scope this function returns false and no error.
//
// If you are trying to revoke a permission but the user was previously granted
// a scope that contains the revoked scope this function returns an error.
func (a *Auth) Revoke(scope, userID string) (bool, error) {
if scope == "" {
return false, errors.New("scope cannot be empty")
}
key := a.permissionsKey(userID)
oldPermissions, err := a.loadPermissions(key)
if err != nil {
return false, errors.WithStack(err)
}
if len(oldPermissions) == 0 {
return false, nil
}
var revoked bool
newPermissions := make([]string, 0, len(oldPermissions))
for _, p := range oldPermissions {
if p == scope {
revoked = true
continue
}
if strings.HasPrefix(scope, p) {
return false, errors.Errorf("cannot revoke scope %q because the user still has the more general scope %q", scope, p)
}
newPermissions = append(newPermissions, p)
}
if !revoked {
return false, nil
}
a.logger.Info("Revoking user permission",
zap.String("userID", userID),
zap.String("scope", scope),
)
if len(newPermissions) == 0 {
_, err := a.store.Delete(key)
if err != nil {
return false, errors.Wrap(err, "failed to delete last user permission")
}
return true, nil
}
err = a.updatePermissions(key, newPermissions)
return true, err
}
func (a *Auth) updatePermissions(key string, permissions []string) error {
err := a.store.Set(key, permissions)
if err != nil {
return errors.Wrap(err, "failed to update user permissions")
}
return nil
}
func (a *Auth) permissionsKey(userID string) string {
return permissionKeyPrefix + userID
}

307
vendor/github.com/go-joe/joe/bot.go generated vendored Normal file
View File

@ -0,0 +1,307 @@
// Package joe contains a general purpose bot library inspired by Hubot.
package joe
import (
"context"
"fmt"
"os"
"os/signal"
"regexp"
"strings"
"syscall"
"github.com/pkg/errors"
"go.uber.org/multierr"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// A Bot represents an event based chat bot. For the most simple usage you can
// use the Bot.Respond(…) function to make the bot execute a function when it
// receives a message that matches a given pattern.
//
// More advanced usage includes persisting memory or emitting your own events
// using the Brain of the robot.
type Bot struct {
Name string
Adapter Adapter
Brain *Brain
Store *Storage
Auth *Auth
Logger *zap.Logger
ctx context.Context
initErr error // any error when we created a new bot
}
// A Module is an optional Bot extension that can add new capabilities such as
// a different Memory implementation or Adapter.
type Module interface {
Apply(*Config) error
}
// ModuleFunc is a function implementation of a Module.
type ModuleFunc func(*Config) error
// Apply implements the Module interface.
func (f ModuleFunc) Apply(conf *Config) error {
return f(conf)
}
// New creates a new Bot and initializes it with the given Modules and Options.
// By default the Bot will use an in-memory Storage and a CLI adapter that
// reads messages from stdin and writes to stdout.
//
// The modules can be used to change the Memory or Adapter or register other new
// functionality. Additionally you can pass Options which allow setting some
// simple configuration such as the event handler timeouts or injecting a
// different context. All Options are available as functions in this package
// that start with "With…".
//
// If there was an error initializing a Module it is stored and returned on the
// next call to Bot.Run(). Before you start the bot however you should register
// your custom event handlers.
//
// Example:
// b := joe.New("example",
// redis.Memory("localhost:6379"),
// slack.Adapter("xoxb-58942365423-…"),
// joehttp.Server(":8080"),
// joe.WithHandlerTimeout(time.Second),
// )
//
// b.Respond("ping", b.Pong)
// b.Brain.RegisterHandler(b.Init)
//
// err := b.Run()
// …
func New(name string, modules ...Module) *Bot {
ctx := newContext(modules)
logger := newLogger(modules)
brain := NewBrain(logger.Named("brain"))
store := NewStorage(logger.Named("memory"))
conf := NewConfig(logger, brain, store, NewCLIAdapter(name, logger))
conf.Context = ctx
conf.Name = name
conf.HandlerTimeout = brain.handlerTimeout
logger.Info("Initializing bot", zap.String("name", name))
for _, mod := range modules {
err := mod.Apply(&conf)
if err != nil {
conf.errs = append(conf.errs, err)
}
}
// apply all configuration options
brain.handlerTimeout = conf.HandlerTimeout
return &Bot{
Name: conf.Name,
ctx: conf.Context,
Logger: conf.logger,
Adapter: conf.adapter,
Auth: NewAuth(conf.logger, store),
Brain: brain,
Store: store,
initErr: multierr.Combine(conf.errs...),
}
}
func newContext(modules []Module) context.Context {
var conf Config
for _, mod := range modules {
if x, ok := mod.(loggerModule); ok {
_ = x(&conf)
}
}
if conf.Context != nil {
return conf.Context
}
return cliContext()
}
// cliContext creates the default context.Context that is used by the bot.
// This context is canceled if the bot receives a SIGINT, SIGQUIT or SIGTERM.
func cliContext() context.Context {
ctx, cancel := context.WithCancel(context.Background())
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
go func() {
<-sig
cancel()
}()
return ctx
}
func newLogger(modules []Module) *zap.Logger {
var conf Config
for _, mod := range modules {
if x, ok := mod.(loggerModule); ok {
_ = x(&conf)
}
}
if conf.logger != nil {
return conf.logger
}
cfg := zap.Config{
Level: zap.NewAtomicLevelAt(zap.DebugLevel),
Development: false,
Encoding: "console",
EncoderConfig: zapcore.EncoderConfig{
TimeKey: "T",
LevelKey: "L",
NameKey: "N",
MessageKey: "M",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
},
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
logger, err := cfg.Build()
if err != nil {
panic(err)
}
return logger
}
// Run starts the bot and runs its event handler loop until the bots context
// is canceled (by default via SIGINT, SIGQUIT or SIGTERM). If there was an
// an error when setting up the Bot via New() or when registering the event
// handlers it will be returned immediately.
func (b *Bot) Run() error {
if b.initErr != nil {
return errors.Wrap(b.initErr, "failed to initialize bot")
}
if len(b.Brain.registrationErrs) > 0 {
errs := multierr.Combine(b.Brain.registrationErrs...)
return errors.Wrap(errs, "invalid event handlers")
}
b.Adapter.RegisterAt(b.Brain)
go func() {
// Keep running until the context is canceled via SIGINT.
<-b.ctx.Done()
shutdownCtx := cliContext() // closed upon another SIGINT
b.Brain.Shutdown(shutdownCtx)
}()
b.Logger.Info("Bot initialized and ready to operate", zap.String("name", b.Name))
b.Brain.HandleEvents()
b.Logger.Info("Bot is shutting down", zap.String("name", b.Name))
err := b.Adapter.Close()
if err != nil {
b.Logger.Info("Error while closing adapter", zap.Error(err))
}
err = b.Store.Close()
if err != nil {
b.Logger.Info("Error while closing memory", zap.Error(err))
}
return nil
}
// Respond registers an event handler that listens for the ReceiveMessageEvent
// and executes the given function only if the message text matches the given
// message. The message will be matched against the msg string as regular
// expression that must match the entire message in a case insensitive way.
//
// You can use sub matches in the msg which will be passed to the function via
// Message.Matches.
//
// If you need complete control over the regular expression, e.g. because you
// want the patter to match only a substring of the message but not all of it,
// you can use Bot.RespondRegex(…). For even more control you can also directly
// use Brain.RegisterHandler(…) with a function that accepts ReceiveMessageEvent
// instances.
//
// If multiple matching patterns are registered, only the first registered
// handler is executed.
func (b *Bot) Respond(msg string, fun func(Message) error) {
expr := "^" + msg + "$"
b.RespondRegex(expr, fun)
}
// RespondRegex is like Bot.Respond(…) but gives a little more control over the
// regular expression. However, also with this function messages are matched in
// a case insensitive way.
func (b *Bot) RespondRegex(expr string, fun func(Message) error) {
if expr == "" {
return
}
if expr[0] == '^' {
// String starts with the "^" anchor but does it also have the prefix
// or case insensitive matching?
if !strings.HasPrefix(expr, "^(?i)") { // TODO: strings.ToLower would be easier?
expr = "^(?i)" + expr[1:]
}
} else {
// The string is not starting with "^" but maybe it has the prefix for
// case insensitive matching already?
if !strings.HasPrefix(expr, "(?i)") {
expr = "(?i)" + expr
}
}
regex, err := regexp.Compile(expr)
if err != nil {
caller := firstExternalCaller()
err = errors.Wrap(err, caller)
b.Brain.registrationErrs = append(b.Brain.registrationErrs, err)
return
}
b.Brain.RegisterHandler(func(ctx context.Context, evt ReceiveMessageEvent) error {
matches := regex.FindStringSubmatch(evt.Text)
if len(matches) == 0 {
return nil
}
// If the event text matches our regular expression we can already mark
// the event context as done so the Brain does not run any other handlers
// that might match the received message.
FinishEventContent(ctx)
return fun(Message{
Context: ctx,
ID: evt.ID,
Text: evt.Text,
AuthorID: evt.AuthorID,
Data: evt.Data,
Channel: evt.Channel,
Matches: matches[1:],
adapter: b.Adapter,
})
})
}
// Say is a helper function to makes the Bot output the message via its Adapter
// (e.g. to the CLI or to Slack). If there is at least one vararg the msg and
// args are formatted using fmt.Sprintf.
func (b *Bot) Say(channel, msg string, args ...interface{}) {
if len(args) > 0 {
msg = fmt.Sprintf(msg, args...)
}
err := b.Adapter.Send(msg, channel)
if err != nil {
b.Logger.Error("Failed to send message", zap.Error(err))
}
}

504
vendor/github.com/go-joe/joe/brain.go generated vendored Normal file
View File

@ -0,0 +1,504 @@
package joe
import (
"context"
"fmt"
"reflect"
"runtime"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/pkg/errors"
"go.uber.org/zap"
)
// The Brain contains the core logic of a Bot by implementing an event handling
// system that dispatches events to all registered event handlers.
type Brain struct {
logger *zap.Logger
eventsInput chan Event // input for any new events, the Brain ensures that callers never block when writing to it
eventsLoop chan Event // used in Brain.HandleEvents() to actually process the events
shutdown chan shutdownRequest
mu sync.RWMutex // mu protects concurrent access to the handlers
handlers map[reflect.Type][]eventHandler
handlerTimeout time.Duration // zero means no timeout, defaults to one minute
registrationErrs []error // any errors that occurred during setup (e.g. in Bot.RegisterHandler)
handlingEvents int32 // accessed atomically (non-zero means the event handler was started)
closed int32 // accessed atomically (non-zero means the brain was shutdown already)
}
// An Event represents a concrete event type and optional callbacks that are
// triggered when the event was processed by all registered handlers.
type Event struct {
Data interface{}
Callbacks []func(Event)
AbortEarly bool
}
// The shutdownRequest type is used when signaling shutdown information between
// Brain.Shutdown() and the Brain.HandleEvents loop.
type shutdownRequest struct {
ctx context.Context
callback chan bool
}
// An eventHandler is a function that takes a context and the reflected value
// of a concrete event type.
type eventHandler func(context.Context, reflect.Value) error
// ctxKey is used to pass meta information to event handlers via the context.
type ctxKey string
// ctxKeyEvent is the context key under which we can lookup the internal *Event
// instance in a handler.
const ctxKeyEvent ctxKey = "event"
// FinishEventContent can be called from within your event handler functions
// to indicate that the Brain should not execute any other handlers after the
// calling handler has returned.
func FinishEventContent(ctx context.Context) {
evt, _ := ctx.Value(ctxKeyEvent).(*Event)
if evt != nil {
evt.AbortEarly = true
}
}
// NewBrain creates a new robot Brain. If the passed logger is nil it will
// fallback to the zap.NewNop() logger.
func NewBrain(logger *zap.Logger) *Brain {
if logger == nil {
logger = zap.NewNop()
}
b := &Brain{
logger: logger,
eventsInput: make(chan Event),
eventsLoop: make(chan Event),
shutdown: make(chan shutdownRequest),
handlers: make(map[reflect.Type][]eventHandler),
handlerTimeout: time.Minute,
}
b.consumeEvents()
return b
}
func (b *Brain) isHandlingEvents() bool {
return atomic.LoadInt32(&b.handlingEvents) == 1
}
func (b *Brain) isClosed() bool {
return atomic.LoadInt32(&b.closed) == 1
}
// RegisterHandler registers a function to be executed when a specific event is
// fired. The function signature must comply with the following rules or the bot
// that uses this Brain will return an error on its next Bot.Run() call:
//
// Allowed function signatures:
//
// // AnyType can be any scalar, struct or interface type as long as it is not
// // a pointer.
// func(AnyType)
//
// // You can optionally accept a context as the first argument. The context
// // is used to signal handler timeouts or when the bot is shutting down.
// func(context.Context, AnyType)
//
// // You can optionally return a single error value. Returning any other type
// // or returning more than one value is not possible. If the handler
// // returns an error it will be logged.
// func(AnyType) error
//
// // Event handlers can also accept an interface in which case they will be
// // be called for all events which implement the interface. Consequently,
// // you can register a function which accepts the empty interface which will
// // will receive all emitted events. Such event handlers can optionally also
// // accept a context and/or return an error like other handlers.
// func(context.Context, interface{}) error
//
// The event, that will be dispatched to the passed handler function, corresponds
// directly to the accepted function argument. For instance if you want to emit
// and receive a custom event you can implement it like this:
//
// type CustomEvent struct {}
//
// b := NewBrain(nil)
// b.RegisterHandler(func(evt CustomEvent) {
// …
// })
//
// If multiple handlers are registered for the same event type, then they are
// all executed in the order in which they have been registered.
//
// You should register all handlers before you start the bot via Bot.Run(…).
// While registering handlers later is also possible, any registration errors
// will silently be ignored if you register an invalid handler when the bot is
// already running.
func (b *Brain) RegisterHandler(fun interface{}) {
err := b.registerHandler(fun)
if err != nil {
caller := firstExternalCaller()
err = errors.Wrap(err, caller)
b.registrationErrs = append(b.registrationErrs, err)
}
}
func (b *Brain) registerHandler(fun interface{}) error {
handler := reflect.ValueOf(fun)
handlerType := handler.Type()
if handlerType.Kind() != reflect.Func {
return errors.New("event handler is no function")
}
evtType, withContext, err := checkHandlerParams(handlerType)
if err != nil {
return err
}
returnsErr, err := checkHandlerReturnValues(handlerType)
if err != nil {
return err
}
b.logger.Debug("Registering new event handler",
zap.Stringer("event_type", evtType),
)
handlerFun := newHandlerFunc(handler, withContext, returnsErr)
b.mu.Lock()
b.handlers[evtType] = append(b.handlers[evtType], handlerFun)
b.mu.Unlock()
return nil
}
// Emit sends the first argument as event to the brain from where it is
// dispatched to all registered handlers. The events are dispatched
// asynchronously but in the same order in which they are send to this function.
// Emit does not block until the event is delivered to the registered event
// handlers. If you want to wait until all handlers have processed the event you
// can pass one or more callback functions that will be executed when all
// handlers finished execution of this event.
func (b *Brain) Emit(event interface{}, callbacks ...func(Event)) {
if b.isClosed() {
b.logger.Debug(
"Ignoring new event because brain is currently shutting down or is already closed",
zap.String("type", fmt.Sprintf("%T", event)),
)
return
}
b.eventsInput <- Event{Data: event, Callbacks: callbacks}
}
// HandleEvents starts the event handling loop of the Brain.
// This function blocks until Brain.Shutdown() is called and returned.
func (b *Brain) HandleEvents() {
if b.isClosed() {
b.logger.Error("HandleEvents failed because bot is already closed")
return
}
ctx := context.Background()
var shutdown shutdownRequest // set when Brain.Shutdown() is called
atomic.StoreInt32(&b.handlingEvents, 1)
b.handleEvent(ctx, Event{Data: InitEvent{}})
for {
select {
case evt, ok := <-b.eventsLoop:
if !ok {
// Brain.consumeEvents() is done processing all remaining events
// and we can now safely shutdown the event handler, knowing that
// all pending events have been processed.
b.handleEvent(ctx, Event{Data: ShutdownEvent{}})
shutdown.callback <- true
return
}
b.handleEvent(ctx, evt)
case shutdown = <-b.shutdown:
// The Brain is shutting down. We have to close the input channel so
// we doe no longer accept new events and only process the remaining
// pending events. When the goroutine of Brain.consumeEvents() is
// done it will close the events loop channel and the case above will
// use the shutdown callback and return from this function.
ctx = shutdown.ctx
close(b.eventsInput)
atomic.StoreInt32(&b.handlingEvents, 0)
}
}
}
// consumeEvents continuously reads events from b.eventsInput in a new goroutine
// so emitting an event never blocks on the caller. All events will be returned
// in the result channel of this function in the same order in which they have
// been inserted into b.events. In this sense this function provides an events
// channel with "infinite" capacity. The spawned goroutine stops when the
// b.eventsInput channel is closed.
func (b *Brain) consumeEvents() {
var queue []Event
b.eventsLoop = make(chan Event)
outChan := func() chan Event {
if len(queue) == 0 {
// In case the queue is empty we return a nil channel to disable the
// corresponding select case in the goroutine below.
return nil
}
return b.eventsLoop
}
nextEvt := func() Event {
if len(queue) == 0 {
// Prevent index out of bounds if there is no next event. Note that
// this event is actually never received because the outChan()
// function above will return "nil" in this case which disables the
// corresponding select case.
return Event{}
}
return queue[0]
}
go func() {
for {
select {
case evt, ok := <-b.eventsInput:
if !ok {
// Events input channel was closed because Brain is shutting
// down. Emit all pending events from the queue and then close
// the events loop channel so Brain.HandleEvents() can exit.
for _, evt := range queue {
b.eventsLoop <- evt
}
close(b.eventsLoop)
return
}
queue = append(queue, evt)
case outChan() <- nextEvt(): // disabled if len(queue) == 0
queue = queue[1:]
}
}
}()
}
// handleEvent receives an event and dispatches it to all registered handlers
// using the reflect API. When all applicable handlers are called (maybe none)
// the function runs all event callbacks.
func (b *Brain) handleEvent(ctx context.Context, evt Event) {
event := reflect.ValueOf(evt.Data)
typ := event.Type()
handlers := b.determineHandlers(typ)
b.logger.Debug("Handling new event",
zap.Stringer("event_type", typ),
zap.Int("handlers", len(handlers)),
)
ctx = context.WithValue(ctx, ctxKeyEvent, &evt)
for _, handler := range handlers {
err := b.executeEventHandler(ctx, handler, event)
if err != nil {
b.logger.Error("Event handler failed",
// TODO: somehow log the name of the handler
zap.Error(err),
)
}
if evt.AbortEarly {
// Abort handler execution early instead of running any more
// handlers. The event state may have been changed by a handler, e.g.
// using the FinishEventContent(…) function.
break
}
}
for _, callback := range evt.Callbacks {
callback(evt)
}
}
func (b *Brain) determineHandlers(evtType reflect.Type) []eventHandler {
b.mu.RLock()
defer b.mu.RUnlock()
var handlers []eventHandler
for handlerType, hh := range b.handlers {
if handlerType == evtType {
handlers = append(handlers, hh...)
}
if handlerType.Kind() == reflect.Interface && evtType.Implements(handlerType) {
handlers = append(handlers, hh...)
}
}
return handlers
}
func (b *Brain) executeEventHandler(ctx context.Context, handler eventHandler, event reflect.Value) error {
if b.handlerTimeout > 0 {
var cancel func()
ctx, cancel = context.WithTimeout(ctx, b.handlerTimeout)
defer cancel()
}
done := make(chan error)
go func() {
done <- handler(ctx, event)
}()
select {
case err := <-done:
return err
case <-ctx.Done():
return ctx.Err()
}
}
// Shutdown stops the event handler loop of the Brain and waits until all pending
// events have been processed. After the brain is shutdown, it will no longer
// accept new events. The passed context can be used to stop waiting for any
// pending events or handlers and instead exit immediately (e.g. after a timeout
// or a second SIGTERM).
func (b *Brain) Shutdown(ctx context.Context) {
closing := atomic.CompareAndSwapInt32(&b.closed, 0, 1)
if !closing {
// brain is already shutting down
return
}
if !b.isHandlingEvents() {
// If the event handler loop is not running we must close the inputs
// channel from here and drain all pending requests in order to make
// b.consumeEvents() exit.
close(b.eventsInput)
for {
select {
case _, ok := <-b.eventsLoop:
if !ok {
// The eventsLoop channel is closed in b.consumeEvents after
// all pending messages have been written to it.
return
}
case <-ctx.Done():
// shutdown context is expired so we return without waiting for
// any pending events.
return
}
}
}
// If we got here then the event handler loop is running and we delegate
// proper cleanup and processing of pending messages over there.
req := shutdownRequest{
ctx: ctx,
callback: make(chan bool),
}
b.shutdown <- req
<-req.callback
}
func checkHandlerParams(handlerFunc reflect.Type) (evtType reflect.Type, withContext bool, err error) {
numParams := handlerFunc.NumIn()
if numParams == 0 || numParams > 2 {
err = errors.New("event handler needs one or two arguments")
return
}
evtType = handlerFunc.In(numParams - 1) // last argument must be the event
withContext = numParams == 2
if withContext {
contextInterface := reflect.TypeOf((*context.Context)(nil)).Elem()
if handlerFunc.In(1).Implements(contextInterface) {
err = errors.New("event handler context must be the first argument")
return
}
if !handlerFunc.In(0).Implements(contextInterface) {
err = errors.New("event handler has two arguments but the first is not a context.Context")
return
}
}
if evtType.Kind() == reflect.Ptr {
err = errors.New("event handler argument cannot be a pointer")
return
}
return evtType, withContext, nil
}
func checkHandlerReturnValues(handlerFunc reflect.Type) (returnsError bool, err error) {
switch handlerFunc.NumOut() {
case 0:
return false, nil
case 1:
errorInterface := reflect.TypeOf((*error)(nil)).Elem()
if !handlerFunc.Out(0).Implements(errorInterface) {
err = errors.New("if the event handler has a return value it must implement the error interface")
return
}
return true, nil
default:
return false, errors.Errorf("event handler has more than one return value")
}
}
func newHandlerFunc(handler reflect.Value, withContext, returnsErr bool) eventHandler {
return func(ctx context.Context, evt reflect.Value) (handlerErr error) {
defer func() {
if err := recover(); err != nil {
handlerErr = errors.Errorf("handler panic: %v", err)
}
}()
var args []reflect.Value
if withContext {
args = []reflect.Value{
reflect.ValueOf(ctx),
evt,
}
} else {
args = []reflect.Value{evt}
}
results := handler.Call(args)
if returnsErr && !results[0].IsNil() {
return results[0].Interface().(error)
}
return nil
}
}
func firstExternalCaller() string {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
callers := pcs[0:n]
frames := runtime.CallersFrames(callers)
for frame, more := frames.Next(); more; frame, more = frames.Next() {
if !strings.HasPrefix(frame.Function, "github.com/go-joe/joe.") {
return fmt.Sprintf("%s:%d", frame.File, frame.Line)
}
}
return "unknown caller"
}

111
vendor/github.com/go-joe/joe/config.go generated vendored Normal file
View File

@ -0,0 +1,111 @@
package joe
import (
"context"
"time"
"go.uber.org/zap"
)
// Config is the configuration of a Bot that can be used or changed during setup
// in a Module. Some configuration settings such as the Logger are read only can
// only be accessed via the corresponding getter function of the Config.
type Config struct {
Context context.Context
Name string
HandlerTimeout time.Duration
logger *zap.Logger
brain *Brain
store *Storage
adapter Adapter
errs []error
}
// NewConfig creates a new Config that is used to setup the underlying
// components of a Bot. For the typical use case you do not have to create a
// Config yourself but rather configure a Bot by passing the corresponding
// Modules to joe.New(…).
func NewConfig(logger *zap.Logger, brain *Brain, store *Storage, adapter Adapter) Config {
return Config{
adapter: adapter,
logger: logger,
brain: brain,
store: store,
}
}
// The EventEmitter can be used by a Module by calling Config.EventEmitter().
// Events are emitted asynchronously so every call to Emit is non-blocking.
type EventEmitter interface {
Emit(event interface{}, callbacks ...func(Event))
}
// EventEmitter returns the EventEmitter that can be used to send events to the
// Bot and other modules.
func (c *Config) EventEmitter() EventEmitter {
return c.brain
}
// Logger returns a new named logger.
func (c *Config) Logger(name string) *zap.Logger {
return c.logger.Named(name)
}
// SetMemory can be used to change the Memory implementation of the bot.
func (c *Config) SetMemory(mem Memory) {
c.store.SetMemory(mem)
}
// SetMemoryEncoder can be used to change the MemoryEncoder implementation of
// the bot.
func (c *Config) SetMemoryEncoder(enc MemoryEncoder) {
c.store.SetMemoryEncoder(enc)
}
// SetAdapter can be used to change the Adapter implementation of the Bot.
func (c *Config) SetAdapter(a Adapter) {
c.adapter = a
}
// RegisterHandler can be used to register an event handler in a Module.
func (c *Config) RegisterHandler(fun interface{}) {
c.brain.RegisterHandler(fun)
}
// WithContext is an option to replace the default context of a bot.
func WithContext(ctx context.Context) Module {
return contextModule(func(conf *Config) error {
conf.Context = ctx
return nil
})
}
// WithHandlerTimeout is an option to set a timeout on event handlers functions.
// By default no timeout is enforced.
func WithHandlerTimeout(timeout time.Duration) Module {
return ModuleFunc(func(conf *Config) error {
conf.HandlerTimeout = timeout
return nil
})
}
// WithLogger is an option to replace the default logger of a bot.
func WithLogger(logger *zap.Logger) Module {
return loggerModule(func(conf *Config) error {
conf.logger = logger
return nil
})
}
type contextModule func(*Config) error
func (fun contextModule) Apply(conf *Config) error {
return fun(conf)
}
type loggerModule func(*Config) error
func (fun loggerModule) Apply(conf *Config) error {
return fun(conf)
}

16
vendor/github.com/go-joe/joe/error.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
package joe
// Error is the error type used by Joe. This allows joe errors to be defined as
// constants following https://dave.cheney.net/2016/04/07/constant-errors.
type Error string
// Error implements the "error" interface of the standard library.
func (err Error) Error() string {
return string(err)
}
// ErrNotImplemented is returned if the user tries to use a feature that is not
// implemented on the corresponding components (e.g. the Adapter). For instance,
// not all Adapter implementations may support emoji reactions and trying to
// attach a reaction to a message might return this error.
const ErrNotImplemented = Error("not implemented")

32
vendor/github.com/go-joe/joe/events.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
package joe
// The InitEvent is the first event that is handled by the Brain after the Bot
// is started via Bot.Run().
type InitEvent struct{}
// The ShutdownEvent is the last event that is handled by the Brain before it
// stops handling any events after the bot context is done.
type ShutdownEvent struct{}
// The ReceiveMessageEvent is typically emitted by an Adapter when the Bot sees
// a new message from the chat.
type ReceiveMessageEvent struct {
ID string // The ID of the message, identifying it at least uniquely within the Channel
Text string // The message text.
AuthorID string // A string identifying the author of the message on the adapter.
Channel string // The channel over which the message was received.
// A message may optionally also contain additional information that was
// received by the Adapter (e.g. with the slack adapter this may be the
// *slack.MessageEvent. Each Adapter implementation should document if and
// what information is available here, if any at all.
Data interface{}
}
// The UserTypingEvent is emitted by the Adapter and indicates that the Bot
// sees that a user is typing. This event may not be emitted on all Adapter
// implementations but only when it is actually supported (e.g. on slack).
type UserTypingEvent struct {
User User
Channel string
}

11
vendor/github.com/go-joe/joe/go.mod generated vendored Normal file
View File

@ -0,0 +1,11 @@
module github.com/go-joe/joe
go 1.12
require (
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.3.0
go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0
go.uber.org/zap v1.9.1
)

16
vendor/github.com/go-joe/joe/go.sum generated vendored Normal file
View File

@ -0,0 +1,16 @@
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/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/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/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=

53
vendor/github.com/go-joe/joe/message.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
package joe
import (
"context"
"fmt"
"github.com/go-joe/joe/reactions"
)
// A Message is automatically created from a ReceiveMessageEvent and then passed
// to the RespondFunc that was registered via Bot.Respond(…) or Bot.RespondRegex(…)
// when the message matches the regular expression of the handler.
type Message struct {
Context context.Context
ID string // The ID of the message, identifying it at least uniquely within the Channel
Text string
AuthorID string
Channel string
Matches []string // contains all sub matches of the regular expression that matched the Text
Data interface{} // corresponds to the ReceiveMessageEvent.Data field
adapter Adapter
}
// Respond is a helper function to directly send a response back to the channel
// the message originated from. This function ignores any error when sending the
// response. If you want to handle the error use Message.RespondE instead.
func (msg *Message) Respond(text string, args ...interface{}) {
_ = msg.RespondE(text, args...)
}
// RespondE is a helper function to directly send a response back to the channel
// the message originated from. If there was an error it will be returned from
// this function.
func (msg *Message) RespondE(text string, args ...interface{}) error {
if len(args) > 0 {
text = fmt.Sprintf(text, args...)
}
return msg.adapter.Send(text, msg.Channel)
}
// React attempts to let the Adapter attach the given reaction to this message.
// If the adapter does not support this feature this function will return
// ErrNotImplemented.
func (msg *Message) React(reaction reactions.Reaction) error {
adapter, ok := msg.adapter.(ReactionAwareAdapter)
if !ok {
return ErrNotImplemented
}
return adapter.React(reaction, *msg)
}

10
vendor/github.com/go-joe/joe/reactions/events.go generated vendored Normal file
View File

@ -0,0 +1,10 @@
package reactions
// An Event may be emitted by a chat Adapter to indicate that a message
// received a reaction.
type Event struct {
Reaction Reaction
MessageID string
Channel string
AuthorID string
}

918
vendor/github.com/go-joe/joe/reactions/reactions.go generated vendored Normal file
View File

@ -0,0 +1,918 @@
// Code generated by github.com/go-joe/gen-reactions DO NOT EDIT.
// Package reactions contains a list of generated reactions that are widely used
// in different chat applications on the internet.
package reactions
// A Reaction is an emoji that is attached to chat messages.
type Reaction struct {
Raw string
Shortcode string
}
// People emojis.
var (
PlusOne = Reaction{Raw: "👍", Shortcode: "+1"}
MinusOne = Reaction{Raw: "👎", Shortcode: "-1"}
Alien = Reaction{Raw: "👽", Shortcode: "alien"}
Angel = Reaction{Raw: "👼", Shortcode: "angel"}
Anger = Reaction{Raw: "💢", Shortcode: "anger"}
Angry = Reaction{Raw: "😠", Shortcode: "angry"}
Anguished = Reaction{Raw: "😧", Shortcode: "anguished"}
Astonished = Reaction{Raw: "😲", Shortcode: "astonished"}
Baby = Reaction{Raw: "👶", Shortcode: "baby"}
BlueHeart = Reaction{Raw: "💙", Shortcode: "blue_heart"}
Blush = Reaction{Raw: "😊", Shortcode: "blush"}
Boom = Reaction{Raw: "💥", Shortcode: "boom"}
Bow = Reaction{Raw: "🙇", Shortcode: "bow"}
Bowtie = Reaction{Raw: "", Shortcode: "bowtie"}
Boy = Reaction{Raw: "👦", Shortcode: "boy"}
BrideWithVeil = Reaction{Raw: "👰", Shortcode: "bride_with_veil"}
BrokenHeart = Reaction{Raw: "💔", Shortcode: "broken_heart"}
BustInSilhouette = Reaction{Raw: "👤", Shortcode: "bust_in_silhouette"}
BustsInSilhouette = Reaction{Raw: "👥", Shortcode: "busts_in_silhouette"}
Clap = Reaction{Raw: "👏", Shortcode: "clap"}
ColdSweat = Reaction{Raw: "😰", Shortcode: "cold_sweat"}
Collision = Reaction{Raw: "💥", Shortcode: "collision"}
Confounded = Reaction{Raw: "😖", Shortcode: "confounded"}
Confused = Reaction{Raw: "😕", Shortcode: "confused"}
ConstructionWorker = Reaction{Raw: "👷", Shortcode: "construction_worker"}
Cop = Reaction{Raw: "👮", Shortcode: "cop"}
Couple = Reaction{Raw: "👫", Shortcode: "couple"}
CoupleWithHeart = Reaction{Raw: "💑", Shortcode: "couple_with_heart"}
Couplekiss = Reaction{Raw: "💏", Shortcode: "couplekiss"}
Cry = Reaction{Raw: "😢", Shortcode: "cry"}
CryingCatFace = Reaction{Raw: "😿", Shortcode: "crying_cat_face"}
Cupid = Reaction{Raw: "💘", Shortcode: "cupid"}
Dancer = Reaction{Raw: "💃", Shortcode: "dancer"}
Dancers = Reaction{Raw: "👯", Shortcode: "dancers"}
Dash = Reaction{Raw: "💨", Shortcode: "dash"}
Disappointed = Reaction{Raw: "😞", Shortcode: "disappointed"}
DisappointedRelieved = Reaction{Raw: "😥", Shortcode: "disappointed_relieved"}
Dizzy = Reaction{Raw: "💫", Shortcode: "dizzy"}
DizzyFace = Reaction{Raw: "😵", Shortcode: "dizzy_face"}
Droplet = Reaction{Raw: "💧", Shortcode: "droplet"}
Ear = Reaction{Raw: "👂", Shortcode: "ear"}
Exclamation = Reaction{Raw: "❗", Shortcode: "exclamation"}
Expressionless = Reaction{Raw: "😑", Shortcode: "expressionless"}
Eyes = Reaction{Raw: "👀", Shortcode: "eyes"}
Facepunch = Reaction{Raw: "👊", Shortcode: "facepunch"}
Family = Reaction{Raw: "👪", Shortcode: "family"}
Fearful = Reaction{Raw: "😨", Shortcode: "fearful"}
Feelsgood = Reaction{Raw: "", Shortcode: "feelsgood"}
Feet = Reaction{Raw: "🐾", Shortcode: "feet"}
Finnadie = Reaction{Raw: "", Shortcode: "finnadie"}
Fire = Reaction{Raw: "🔥", Shortcode: "fire"}
Fist = Reaction{Raw: "✊", Shortcode: "fist"}
Flushed = Reaction{Raw: "😳", Shortcode: "flushed"}
Frowning = Reaction{Raw: "😦", Shortcode: "frowning"}
Fu = Reaction{Raw: "🖕", Shortcode: "fu"}
Girl = Reaction{Raw: "👧", Shortcode: "girl"}
Goberserk = Reaction{Raw: "", Shortcode: "goberserk"}
Godmode = Reaction{Raw: "", Shortcode: "godmode"}
GreenHeart = Reaction{Raw: "💚", Shortcode: "green_heart"}
GreyExclamation = Reaction{Raw: "❕", Shortcode: "grey_exclamation"}
GreyQuestion = Reaction{Raw: "❔", Shortcode: "grey_question"}
Grimacing = Reaction{Raw: "😬", Shortcode: "grimacing"}
Grin = Reaction{Raw: "😄", Shortcode: "grin"}
Grinning = Reaction{Raw: "😀", Shortcode: "grinning"}
Guardsman = Reaction{Raw: "💂", Shortcode: "guardsman"}
Haircut = Reaction{Raw: "💇", Shortcode: "haircut"}
Hand = Reaction{Raw: "✋", Shortcode: "hand"}
Hankey = Reaction{Raw: "💩", Shortcode: "hankey"}
HearNoEvil = Reaction{Raw: "🙉", Shortcode: "hear_no_evil"}
Heart = Reaction{Raw: "❤", Shortcode: "heart"}
HeartEyes = Reaction{Raw: "😍", Shortcode: "heart_eyes"}
HeartEyesCat = Reaction{Raw: "😻", Shortcode: "heart_eyes_cat"}
Heartbeat = Reaction{Raw: "💓", Shortcode: "heartbeat"}
Heartpulse = Reaction{Raw: "💗", Shortcode: "heartpulse"}
Hurtrealbad = Reaction{Raw: "", Shortcode: "hurtrealbad"}
Hushed = Reaction{Raw: "😯", Shortcode: "hushed"}
Imp = Reaction{Raw: "👿", Shortcode: "imp"}
InformationDeskPerson = Reaction{Raw: "💁", Shortcode: "information_desk_person"}
Innocent = Reaction{Raw: "😇", Shortcode: "innocent"}
JapaneseGoblin = Reaction{Raw: "👺", Shortcode: "japanese_goblin"}
JapaneseOgre = Reaction{Raw: "👹", Shortcode: "japanese_ogre"}
Joy = Reaction{Raw: "😂", Shortcode: "joy"}
JoyCat = Reaction{Raw: "😹", Shortcode: "joy_cat"}
Kiss = Reaction{Raw: "💏", Shortcode: "kiss"}
Kissing = Reaction{Raw: "😗", Shortcode: "kissing"}
KissingCat = Reaction{Raw: "😽", Shortcode: "kissing_cat"}
KissingClosedEyes = Reaction{Raw: "😚", Shortcode: "kissing_closed_eyes"}
KissingHeart = Reaction{Raw: "😘", Shortcode: "kissing_heart"}
KissingSmilingEyes = Reaction{Raw: "😙", Shortcode: "kissing_smiling_eyes"}
Laughing = Reaction{Raw: "😆", Shortcode: "laughing"}
Lips = Reaction{Raw: "👄", Shortcode: "lips"}
LoveLetter = Reaction{Raw: "💌", Shortcode: "love_letter"}
Man = Reaction{Raw: "👨", Shortcode: "man"}
ManWithGuaPiMao = Reaction{Raw: "👲", Shortcode: "man_with_gua_pi_mao"}
ManWithTurban = Reaction{Raw: "👳", Shortcode: "man_with_turban"}
Mask = Reaction{Raw: "😷", Shortcode: "mask"}
Massage = Reaction{Raw: "💆", Shortcode: "massage"}
Metal = Reaction{Raw: "🤘", Shortcode: "metal"}
Muscle = Reaction{Raw: "💪", Shortcode: "muscle"}
MusicalNote = Reaction{Raw: "🎵", Shortcode: "musical_note"}
NailCare = Reaction{Raw: "💅", Shortcode: "nail_care"}
Neckbeard = Reaction{Raw: "", Shortcode: "neckbeard"}
NeutralFace = Reaction{Raw: "😐", Shortcode: "neutral_face"}
NoGood = Reaction{Raw: "🙅", Shortcode: "no_good"}
NoMouth = Reaction{Raw: "😶", Shortcode: "no_mouth"}
Nose = Reaction{Raw: "👃", Shortcode: "nose"}
Notes = Reaction{Raw: "🎶", Shortcode: "notes"}
OkHand = Reaction{Raw: "👌", Shortcode: "ok_hand"}
OkWoman = Reaction{Raw: "🙆", Shortcode: "ok_woman"}
OlderMan = Reaction{Raw: "👴", Shortcode: "older_man"}
OlderWoman = Reaction{Raw: "👵", Shortcode: "older_woman"}
OpenHands = Reaction{Raw: "👐", Shortcode: "open_hands"}
OpenMouth = Reaction{Raw: "😮", Shortcode: "open_mouth"}
Pensive = Reaction{Raw: "😔", Shortcode: "pensive"}
Persevere = Reaction{Raw: "😣", Shortcode: "persevere"}
PersonFrowning = Reaction{Raw: "🙍", Shortcode: "person_frowning"}
PersonWithBlondHair = Reaction{Raw: "👱", Shortcode: "person_with_blond_hair"}
PersonWithPoutingFace = Reaction{Raw: "🙎", Shortcode: "person_with_pouting_face"}
PointDown = Reaction{Raw: "👇", Shortcode: "point_down"}
PointLeft = Reaction{Raw: "👈", Shortcode: "point_left"}
PointRight = Reaction{Raw: "👉", Shortcode: "point_right"}
PointUp = Reaction{Raw: "☝", Shortcode: "point_up"}
PointUpTwo = Reaction{Raw: "👆", Shortcode: "point_up_2"}
Poop = Reaction{Raw: "💩", Shortcode: "poop"}
PoutingCat = Reaction{Raw: "😾", Shortcode: "pouting_cat"}
Pray = Reaction{Raw: "🙏", Shortcode: "pray"}
Princess = Reaction{Raw: "👸", Shortcode: "princess"}
Punch = Reaction{Raw: "👊", Shortcode: "punch"}
PurpleHeart = Reaction{Raw: "💜", Shortcode: "purple_heart"}
Question = Reaction{Raw: "❓", Shortcode: "question"}
Rage = Reaction{Raw: "😡", Shortcode: "rage"}
RageOne = Reaction{Raw: "", Shortcode: "rage1"}
RageTwo = Reaction{Raw: "", Shortcode: "rage2"}
RageThree = Reaction{Raw: "", Shortcode: "rage3"}
RageFour = Reaction{Raw: "", Shortcode: "rage4"}
RaisedHand = Reaction{Raw: "✋", Shortcode: "raised_hand"}
RaisedHands = Reaction{Raw: "🙌", Shortcode: "raised_hands"}
RaisingHand = Reaction{Raw: "🙋", Shortcode: "raising_hand"}
Relaxed = Reaction{Raw: "☺", Shortcode: "relaxed"}
Relieved = Reaction{Raw: "😌", Shortcode: "relieved"}
RevolvingHearts = Reaction{Raw: "💞", Shortcode: "revolving_hearts"}
Runner = Reaction{Raw: "🏃", Shortcode: "runner"}
Running = Reaction{Raw: "🏃", Shortcode: "running"}
Satisfied = Reaction{Raw: "😆", Shortcode: "satisfied"}
Scream = Reaction{Raw: "😱", Shortcode: "scream"}
ScreamCat = Reaction{Raw: "🙀", Shortcode: "scream_cat"}
SeeNoEvil = Reaction{Raw: "🙈", Shortcode: "see_no_evil"}
Shit = Reaction{Raw: "💩", Shortcode: "shit"}
SimpleSmile = Reaction{Raw: "", Shortcode: "simple_smile"}
Skull = Reaction{Raw: "💀", Shortcode: "skull"}
Sleeping = Reaction{Raw: "😴", Shortcode: "sleeping"}
Sleepy = Reaction{Raw: "😪", Shortcode: "sleepy"}
Smile = Reaction{Raw: "😄", Shortcode: "smile"}
SmileCat = Reaction{Raw: "😸", Shortcode: "smile_cat"}
Smiley = Reaction{Raw: "😃", Shortcode: "smiley"}
SmileyCat = Reaction{Raw: "😺", Shortcode: "smiley_cat"}
SmilingImp = Reaction{Raw: "😈", Shortcode: "smiling_imp"}
Smirk = Reaction{Raw: "😏", Shortcode: "smirk"}
SmirkCat = Reaction{Raw: "😼", Shortcode: "smirk_cat"}
Sob = Reaction{Raw: "😭", Shortcode: "sob"}
Sparkles = Reaction{Raw: "✨", Shortcode: "sparkles"}
SparklingHeart = Reaction{Raw: "💖", Shortcode: "sparkling_heart"}
SpeakNoEvil = Reaction{Raw: "🙊", Shortcode: "speak_no_evil"}
SpeechBalloon = Reaction{Raw: "💬", Shortcode: "speech_balloon"}
Star = Reaction{Raw: "⭐", Shortcode: "star"}
StarTwo = Reaction{Raw: "🌟", Shortcode: "star2"}
StuckOutTongue = Reaction{Raw: "😛", Shortcode: "stuck_out_tongue"}
StuckOutTongueClosedEyes = Reaction{Raw: "😝", Shortcode: "stuck_out_tongue_closed_eyes"}
StuckOutTongueWinkingEye = Reaction{Raw: "😜", Shortcode: "stuck_out_tongue_winking_eye"}
Sunglasses = Reaction{Raw: "🕶", Shortcode: "sunglasses"}
Suspect = Reaction{Raw: "", Shortcode: "suspect"}
Sweat = Reaction{Raw: "😓", Shortcode: "sweat"}
SweatDrops = Reaction{Raw: "💦", Shortcode: "sweat_drops"}
SweatSmile = Reaction{Raw: "😅", Shortcode: "sweat_smile"}
ThoughtBalloon = Reaction{Raw: "💭", Shortcode: "thought_balloon"}
Thumbsdown = Reaction{Raw: "👎", Shortcode: "thumbsdown"}
Thumbsup = Reaction{Raw: "👍", Shortcode: "thumbsup"}
TiredFace = Reaction{Raw: "😫", Shortcode: "tired_face"}
Tongue = Reaction{Raw: "👅", Shortcode: "tongue"}
Triumph = Reaction{Raw: "😤", Shortcode: "triumph"}
Trollface = Reaction{Raw: "", Shortcode: "trollface"}
TwoHearts = Reaction{Raw: "💕", Shortcode: "two_hearts"}
TwoMenHoldingHands = Reaction{Raw: "👬", Shortcode: "two_men_holding_hands"}
TwoWomenHoldingHands = Reaction{Raw: "👭", Shortcode: "two_women_holding_hands"}
Unamused = Reaction{Raw: "😒", Shortcode: "unamused"}
V = Reaction{Raw: "✌", Shortcode: "v"}
Wave = Reaction{Raw: "👋", Shortcode: "wave"}
Weary = Reaction{Raw: "😩", Shortcode: "weary"}
Wink = Reaction{Raw: "😉", Shortcode: "wink"}
Woman = Reaction{Raw: "👩", Shortcode: "woman"}
Worried = Reaction{Raw: "😟", Shortcode: "worried"}
YellowHeart = Reaction{Raw: "💛", Shortcode: "yellow_heart"}
Yum = Reaction{Raw: "😋", Shortcode: "yum"}
Zzz = Reaction{Raw: "💤", Shortcode: "zzz"}
)
// Nature emojis.
var (
Ant = Reaction{Raw: "🐜", Shortcode: "ant"}
BabyChick = Reaction{Raw: "🐤", Shortcode: "baby_chick"}
Bear = Reaction{Raw: "🐻", Shortcode: "bear"}
Beetle = Reaction{Raw: "🐞", Shortcode: "beetle"}
Bird = Reaction{Raw: "🐦", Shortcode: "bird"}
Blossom = Reaction{Raw: "🌼", Shortcode: "blossom"}
Blowfish = Reaction{Raw: "🐡", Shortcode: "blowfish"}
Boar = Reaction{Raw: "🐗", Shortcode: "boar"}
Bouquet = Reaction{Raw: "💐", Shortcode: "bouquet"}
Bug = Reaction{Raw: "🐛", Shortcode: "bug"}
Cactus = Reaction{Raw: "🌵", Shortcode: "cactus"}
Camel = Reaction{Raw: "🐪", Shortcode: "camel"}
Cat = Reaction{Raw: "🐈", Shortcode: "cat"}
CatTwo = Reaction{Raw: "🐈", Shortcode: "cat2"}
CherryBlossom = Reaction{Raw: "🌸", Shortcode: "cherry_blossom"}
Chestnut = Reaction{Raw: "🌰", Shortcode: "chestnut"}
Chicken = Reaction{Raw: "🐔", Shortcode: "chicken"}
Cloud = Reaction{Raw: "☁", Shortcode: "cloud"}
Cow = Reaction{Raw: "🐄", Shortcode: "cow"}
CowTwo = Reaction{Raw: "🐄", Shortcode: "cow2"}
CrescentMoon = Reaction{Raw: "🌙", Shortcode: "crescent_moon"}
Crocodile = Reaction{Raw: "🐊", Shortcode: "crocodile"}
Cyclone = Reaction{Raw: "🌀", Shortcode: "cyclone"}
DeciduousTree = Reaction{Raw: "🌳", Shortcode: "deciduous_tree"}
Dog = Reaction{Raw: "🐕", Shortcode: "dog"}
DogTwo = Reaction{Raw: "🐕", Shortcode: "dog2"}
Dolphin = Reaction{Raw: "🐬", Shortcode: "dolphin"}
Dragon = Reaction{Raw: "🐉", Shortcode: "dragon"}
DragonFace = Reaction{Raw: "🐲", Shortcode: "dragon_face"}
DromedaryCamel = Reaction{Raw: "🐪", Shortcode: "dromedary_camel"}
EarOfRice = Reaction{Raw: "🌾", Shortcode: "ear_of_rice"}
EarthAfrica = Reaction{Raw: "🌍", Shortcode: "earth_africa"}
EarthAmericas = Reaction{Raw: "🌎", Shortcode: "earth_americas"}
EarthAsia = Reaction{Raw: "🌏", Shortcode: "earth_asia"}
Elephant = Reaction{Raw: "🐘", Shortcode: "elephant"}
EvergreenTree = Reaction{Raw: "🌲", Shortcode: "evergreen_tree"}
FallenLeaf = Reaction{Raw: "🍂", Shortcode: "fallen_leaf"}
FirstQuarterMoon = Reaction{Raw: "🌓", Shortcode: "first_quarter_moon"}
FirstQuarterMoonWithFace = Reaction{Raw: "🌛", Shortcode: "first_quarter_moon_with_face"}
Fish = Reaction{Raw: "🐟", Shortcode: "fish"}
Foggy = Reaction{Raw: "🌁", Shortcode: "foggy"}
FourLeafClover = Reaction{Raw: "🍀", Shortcode: "four_leaf_clover"}
Frog = Reaction{Raw: "🐸", Shortcode: "frog"}
FullMoon = Reaction{Raw: "🌕", Shortcode: "full_moon"}
FullMoonWithFace = Reaction{Raw: "🌝", Shortcode: "full_moon_with_face"}
GlobeWithMeridians = Reaction{Raw: "🌐", Shortcode: "globe_with_meridians"}
Goat = Reaction{Raw: "🐐", Shortcode: "goat"}
Hamster = Reaction{Raw: "🐹", Shortcode: "hamster"}
HatchedChick = Reaction{Raw: "🐥", Shortcode: "hatched_chick"}
HatchingChick = Reaction{Raw: "🐣", Shortcode: "hatching_chick"}
Herb = Reaction{Raw: "🌿", Shortcode: "herb"}
Hibiscus = Reaction{Raw: "🌺", Shortcode: "hibiscus"}
Honeybee = Reaction{Raw: "🐝", Shortcode: "honeybee"}
Horse = Reaction{Raw: "🐎", Shortcode: "horse"}
Koala = Reaction{Raw: "🐨", Shortcode: "koala"}
LastQuarterMoon = Reaction{Raw: "🌗", Shortcode: "last_quarter_moon"}
LastQuarterMoonWithFace = Reaction{Raw: "🌜", Shortcode: "last_quarter_moon_with_face"}
Leaves = Reaction{Raw: "🍃", Shortcode: "leaves"}
Leopard = Reaction{Raw: "🐆", Shortcode: "leopard"}
MapleLeaf = Reaction{Raw: "🍁", Shortcode: "maple_leaf"}
MilkyWay = Reaction{Raw: "🌌", Shortcode: "milky_way"}
Monkey = Reaction{Raw: "🐒", Shortcode: "monkey"}
MonkeyFace = Reaction{Raw: "🐵", Shortcode: "monkey_face"}
Mouse = Reaction{Raw: "🐁", Shortcode: "mouse"}
MouseTwo = Reaction{Raw: "🐁", Shortcode: "mouse2"}
Mushroom = Reaction{Raw: "🍄", Shortcode: "mushroom"}
NewMoon = Reaction{Raw: "🌑", Shortcode: "new_moon"}
NewMoonWithFace = Reaction{Raw: "🌚", Shortcode: "new_moon_with_face"}
Ocean = Reaction{Raw: "🌊", Shortcode: "ocean"}
Octocat = Reaction{Raw: "", Shortcode: "octocat"}
Octopus = Reaction{Raw: "🐙", Shortcode: "octopus"}
Ox = Reaction{Raw: "🐂", Shortcode: "ox"}
PalmTree = Reaction{Raw: "🌴", Shortcode: "palm_tree"}
PandaFace = Reaction{Raw: "🐼", Shortcode: "panda_face"}
PartlySunny = Reaction{Raw: "⛅", Shortcode: "partly_sunny"}
PawPrints = Reaction{Raw: "🐾", Shortcode: "paw_prints"}
Penguin = Reaction{Raw: "🐧", Shortcode: "penguin"}
Pig = Reaction{Raw: "🐖", Shortcode: "pig"}
PigTwo = Reaction{Raw: "🐖", Shortcode: "pig2"}
PigNose = Reaction{Raw: "🐽", Shortcode: "pig_nose"}
Poodle = Reaction{Raw: "🐩", Shortcode: "poodle"}
Rabbit = Reaction{Raw: "🐇", Shortcode: "rabbit"}
RabbitTwo = Reaction{Raw: "🐇", Shortcode: "rabbit2"}
Racehorse = Reaction{Raw: "🐎", Shortcode: "racehorse"}
RAM = Reaction{Raw: "🐏", Shortcode: "ram"}
Rat = Reaction{Raw: "🐀", Shortcode: "rat"}
Rooster = Reaction{Raw: "🐓", Shortcode: "rooster"}
Rose = Reaction{Raw: "🌹", Shortcode: "rose"}
Seedling = Reaction{Raw: "🌱", Shortcode: "seedling"}
Sheep = Reaction{Raw: "🐑", Shortcode: "sheep"}
Shell = Reaction{Raw: "🐚", Shortcode: "shell"}
Snail = Reaction{Raw: "🐌", Shortcode: "snail"}
Snake = Reaction{Raw: "🐍", Shortcode: "snake"}
Snowflake = Reaction{Raw: "❄", Shortcode: "snowflake"}
Snowman = Reaction{Raw: "☃", Shortcode: "snowman"}
Squirrel = Reaction{Raw: "", Shortcode: "squirrel"}
SunWithFace = Reaction{Raw: "🌞", Shortcode: "sun_with_face"}
Sunflower = Reaction{Raw: "🌻", Shortcode: "sunflower"}
Sunny = Reaction{Raw: "☀", Shortcode: "sunny"}
Tiger = Reaction{Raw: "🐅", Shortcode: "tiger"}
TigerTwo = Reaction{Raw: "🐅", Shortcode: "tiger2"}
TropicalFish = Reaction{Raw: "🐠", Shortcode: "tropical_fish"}
Tulip = Reaction{Raw: "🌷", Shortcode: "tulip"}
Turtle = Reaction{Raw: "🐢", Shortcode: "turtle"}
Umbrella = Reaction{Raw: "☂", Shortcode: "umbrella"}
Volcano = Reaction{Raw: "🌋", Shortcode: "volcano"}
WaningCrescentMoon = Reaction{Raw: "🌘", Shortcode: "waning_crescent_moon"}
WaningGibbousMoon = Reaction{Raw: "🌖", Shortcode: "waning_gibbous_moon"}
WaterBuffalo = Reaction{Raw: "🐃", Shortcode: "water_buffalo"}
WaxingCrescentMoon = Reaction{Raw: "🌒", Shortcode: "waxing_crescent_moon"}
WaxingGibbousMoon = Reaction{Raw: "🌔", Shortcode: "waxing_gibbous_moon"}
Whale = Reaction{Raw: "🐋", Shortcode: "whale"}
WhaleTwo = Reaction{Raw: "🐋", Shortcode: "whale2"}
Wolf = Reaction{Raw: "🐺", Shortcode: "wolf"}
Zap = Reaction{Raw: "⚡", Shortcode: "zap"}
)
// Objects emojis.
var (
Eightball = Reaction{Raw: "🎱", Shortcode: "8ball"}
AlarmClock = Reaction{Raw: "⏰", Shortcode: "alarm_clock"}
Apple = Reaction{Raw: "🍎", Shortcode: "apple"}
Art = Reaction{Raw: "🎨", Shortcode: "art"}
BabyBottle = Reaction{Raw: "🍼", Shortcode: "baby_bottle"}
Balloon = Reaction{Raw: "🎈", Shortcode: "balloon"}
Bamboo = Reaction{Raw: "🎍", Shortcode: "bamboo"}
Banana = Reaction{Raw: "🍌", Shortcode: "banana"}
BarChart = Reaction{Raw: "📊", Shortcode: "bar_chart"}
Baseball = Reaction{Raw: "⚾", Shortcode: "baseball"}
Basketball = Reaction{Raw: "🏀", Shortcode: "basketball"}
Bath = Reaction{Raw: "🛀", Shortcode: "bath"}
Bathtub = Reaction{Raw: "🛁", Shortcode: "bathtub"}
Battery = Reaction{Raw: "🔋", Shortcode: "battery"}
Beer = Reaction{Raw: "🍺", Shortcode: "beer"}
Beers = Reaction{Raw: "🍻", Shortcode: "beers"}
Bell = Reaction{Raw: "🔔", Shortcode: "bell"}
Bento = Reaction{Raw: "🍱", Shortcode: "bento"}
Bicyclist = Reaction{Raw: "🚴", Shortcode: "bicyclist"}
Bikini = Reaction{Raw: "👙", Shortcode: "bikini"}
Birthday = Reaction{Raw: "🎂", Shortcode: "birthday"}
BlackJoker = Reaction{Raw: "🃏", Shortcode: "black_joker"}
BlackNib = Reaction{Raw: "✒", Shortcode: "black_nib"}
BlueBook = Reaction{Raw: "📘", Shortcode: "blue_book"}
Bomb = Reaction{Raw: "💣", Shortcode: "bomb"}
Book = Reaction{Raw: "📖", Shortcode: "book"}
Bookmark = Reaction{Raw: "🔖", Shortcode: "bookmark"}
BookmarkTabs = Reaction{Raw: "📑", Shortcode: "bookmark_tabs"}
Books = Reaction{Raw: "📚", Shortcode: "books"}
Boot = Reaction{Raw: "👢", Shortcode: "boot"}
Bowling = Reaction{Raw: "🎳", Shortcode: "bowling"}
Bread = Reaction{Raw: "🍞", Shortcode: "bread"}
Briefcase = Reaction{Raw: "💼", Shortcode: "briefcase"}
Bulb = Reaction{Raw: "💡", Shortcode: "bulb"}
Cake = Reaction{Raw: "🍰", Shortcode: "cake"}
Calendar = Reaction{Raw: "📅", Shortcode: "calendar"}
Calling = Reaction{Raw: "📲", Shortcode: "calling"}
Camera = Reaction{Raw: "📷", Shortcode: "camera"}
Candy = Reaction{Raw: "🍬", Shortcode: "candy"}
CardIndex = Reaction{Raw: "📇", Shortcode: "card_index"}
Cd = Reaction{Raw: "💿", Shortcode: "cd"}
ChartWithDownwardsTrend = Reaction{Raw: "📉", Shortcode: "chart_with_downwards_trend"}
ChartWithUpwardsTrend = Reaction{Raw: "📈", Shortcode: "chart_with_upwards_trend"}
Cherries = Reaction{Raw: "🍒", Shortcode: "cherries"}
ChocolateBar = Reaction{Raw: "🍫", Shortcode: "chocolate_bar"}
ChristmasTree = Reaction{Raw: "🎄", Shortcode: "christmas_tree"}
Clapper = Reaction{Raw: "🎬", Shortcode: "clapper"}
Clipboard = Reaction{Raw: "📋", Shortcode: "clipboard"}
ClosedBook = Reaction{Raw: "📕", Shortcode: "closed_book"}
ClosedLockWithKey = Reaction{Raw: "🔐", Shortcode: "closed_lock_with_key"}
ClosedUmbrella = Reaction{Raw: "🌂", Shortcode: "closed_umbrella"}
Clubs = Reaction{Raw: "♣", Shortcode: "clubs"}
Cocktail = Reaction{Raw: "🍸", Shortcode: "cocktail"}
Coffee = Reaction{Raw: "☕", Shortcode: "coffee"}
Computer = Reaction{Raw: "💻", Shortcode: "computer"}
ConfettiBall = Reaction{Raw: "🎊", Shortcode: "confetti_ball"}
Cookie = Reaction{Raw: "🍪", Shortcode: "cookie"}
Corn = Reaction{Raw: "🌽", Shortcode: "corn"}
CreditCard = Reaction{Raw: "💳", Shortcode: "credit_card"}
Crown = Reaction{Raw: "👑", Shortcode: "crown"}
CrystalBall = Reaction{Raw: "🔮", Shortcode: "crystal_ball"}
Curry = Reaction{Raw: "🍛", Shortcode: "curry"}
Custard = Reaction{Raw: "🍮", Shortcode: "custard"}
Dango = Reaction{Raw: "🍡", Shortcode: "dango"}
Dart = Reaction{Raw: "🎯", Shortcode: "dart"}
Date = Reaction{Raw: "📅", Shortcode: "date"}
Diamonds = Reaction{Raw: "♦", Shortcode: "diamonds"}
Dollar = Reaction{Raw: "💵", Shortcode: "dollar"}
Dolls = Reaction{Raw: "🎎", Shortcode: "dolls"}
Door = Reaction{Raw: "🚪", Shortcode: "door"}
Doughnut = Reaction{Raw: "🍩", Shortcode: "doughnut"}
Dress = Reaction{Raw: "👗", Shortcode: "dress"}
Dvd = Reaction{Raw: "📀", Shortcode: "dvd"}
EMinusmail = Reaction{Raw: "📧", Shortcode: "e-mail"}
Egg = Reaction{Raw: "🥚", Shortcode: "egg"}
Eggplant = Reaction{Raw: "🍆", Shortcode: "eggplant"}
ElectricPlug = Reaction{Raw: "🔌", Shortcode: "electric_plug"}
Email = Reaction{Raw: "✉️", Shortcode: "email"}
Envelope = Reaction{Raw: "✉", Shortcode: "envelope"}
Euro = Reaction{Raw: "💶", Shortcode: "euro"}
Eyeglasses = Reaction{Raw: "👓", Shortcode: "eyeglasses"}
Fax = Reaction{Raw: "📠", Shortcode: "fax"}
FileFolder = Reaction{Raw: "📁", Shortcode: "file_folder"}
Fireworks = Reaction{Raw: "🎆", Shortcode: "fireworks"}
FishCake = Reaction{Raw: "🍥", Shortcode: "fish_cake"}
FishingPoleAndFish = Reaction{Raw: "🎣", Shortcode: "fishing_pole_and_fish"}
Flags = Reaction{Raw: "🎏", Shortcode: "flags"}
Flashlight = Reaction{Raw: "🔦", Shortcode: "flashlight"}
FloppyDisk = Reaction{Raw: "💾", Shortcode: "floppy_disk"}
FlowerPlayingCards = Reaction{Raw: "🎴", Shortcode: "flower_playing_cards"}
Football = Reaction{Raw: "🏈", Shortcode: "football"}
ForkAndKnife = Reaction{Raw: "🍴", Shortcode: "fork_and_knife"}
FriedShrimp = Reaction{Raw: "🍤", Shortcode: "fried_shrimp"}
Fries = Reaction{Raw: "🍟", Shortcode: "fries"}
GameDie = Reaction{Raw: "🎲", Shortcode: "game_die"}
Gem = Reaction{Raw: "💎", Shortcode: "gem"}
Ghost = Reaction{Raw: "👻", Shortcode: "ghost"}
Gift = Reaction{Raw: "🎁", Shortcode: "gift"}
GiftHeart = Reaction{Raw: "💝", Shortcode: "gift_heart"}
Golf = Reaction{Raw: "⛳", Shortcode: "golf"}
Grapes = Reaction{Raw: "🍇", Shortcode: "grapes"}
GreenApple = Reaction{Raw: "🍏", Shortcode: "green_apple"}
GreenBook = Reaction{Raw: "📗", Shortcode: "green_book"}
Guitar = Reaction{Raw: "🎸", Shortcode: "guitar"}
Gun = Reaction{Raw: "🔫", Shortcode: "gun"}
Hamburger = Reaction{Raw: "🍔", Shortcode: "hamburger"}
Hammer = Reaction{Raw: "🔨", Shortcode: "hammer"}
Handbag = Reaction{Raw: "👜", Shortcode: "handbag"}
Headphones = Reaction{Raw: "🎧", Shortcode: "headphones"}
Hearts = Reaction{Raw: "♥", Shortcode: "hearts"}
HighBrightness = Reaction{Raw: "🔆", Shortcode: "high_brightness"}
HighHeel = Reaction{Raw: "👠", Shortcode: "high_heel"}
Hocho = Reaction{Raw: "🔪", Shortcode: "hocho"}
HoneyPot = Reaction{Raw: "🍯", Shortcode: "honey_pot"}
HorseRacing = Reaction{Raw: "🏇", Shortcode: "horse_racing"}
Hourglass = Reaction{Raw: "⌛", Shortcode: "hourglass"}
HourglassFlowingSand = Reaction{Raw: "⏳", Shortcode: "hourglass_flowing_sand"}
IceCream = Reaction{Raw: "🍨", Shortcode: "ice_cream"}
Icecream = Reaction{Raw: "🍦", Shortcode: "icecream"}
InboxTray = Reaction{Raw: "📥", Shortcode: "inbox_tray"}
IncomingEnvelope = Reaction{Raw: "📨", Shortcode: "incoming_envelope"}
Iphone = Reaction{Raw: "📱", Shortcode: "iphone"}
JackOLantern = Reaction{Raw: "🎃", Shortcode: "jack_o_lantern"}
Jeans = Reaction{Raw: "👖", Shortcode: "jeans"}
Key = Reaction{Raw: "🔑", Shortcode: "key"}
Kimono = Reaction{Raw: "👘", Shortcode: "kimono"}
Ledger = Reaction{Raw: "📒", Shortcode: "ledger"}
Lemon = Reaction{Raw: "🍋", Shortcode: "lemon"}
Lipstick = Reaction{Raw: "💄", Shortcode: "lipstick"}
Lock = Reaction{Raw: "🔒", Shortcode: "lock"}
LockWithInkPen = Reaction{Raw: "🔏", Shortcode: "lock_with_ink_pen"}
Lollipop = Reaction{Raw: "🍭", Shortcode: "lollipop"}
Loop = Reaction{Raw: "➿", Shortcode: "loop"}
Loudspeaker = Reaction{Raw: "📢", Shortcode: "loudspeaker"}
LowBrightness = Reaction{Raw: "🔅", Shortcode: "low_brightness"}
Mag = Reaction{Raw: "🔍", Shortcode: "mag"}
MagRight = Reaction{Raw: "🔎", Shortcode: "mag_right"}
Mahjong = Reaction{Raw: "🀄", Shortcode: "mahjong"}
Mailbox = Reaction{Raw: "📫", Shortcode: "mailbox"}
MailboxClosed = Reaction{Raw: "📪", Shortcode: "mailbox_closed"}
MailboxWithMail = Reaction{Raw: "📬", Shortcode: "mailbox_with_mail"}
MailboxWithNoMail = Reaction{Raw: "📭", Shortcode: "mailbox_with_no_mail"}
MansShoe = Reaction{Raw: "👞", Shortcode: "mans_shoe"}
MeatOnBone = Reaction{Raw: "🍖", Shortcode: "meat_on_bone"}
Mega = Reaction{Raw: "📣", Shortcode: "mega"}
Melon = Reaction{Raw: "🍈", Shortcode: "melon"}
Memo = Reaction{Raw: "📝", Shortcode: "memo"}
Microphone = Reaction{Raw: "🎤", Shortcode: "microphone"}
Microscope = Reaction{Raw: "🔬", Shortcode: "microscope"}
Minidisc = Reaction{Raw: "💽", Shortcode: "minidisc"}
MoneyWithWings = Reaction{Raw: "💸", Shortcode: "money_with_wings"}
Moneybag = Reaction{Raw: "💰", Shortcode: "moneybag"}
MortarBoard = Reaction{Raw: "🎓", Shortcode: "mortar_board"}
MountainBicyclist = Reaction{Raw: "🚵", Shortcode: "mountain_bicyclist"}
MovieCamera = Reaction{Raw: "🎥", Shortcode: "movie_camera"}
MusicalKeyboard = Reaction{Raw: "🎹", Shortcode: "musical_keyboard"}
MusicalScore = Reaction{Raw: "🎼", Shortcode: "musical_score"}
Mute = Reaction{Raw: "🔇", Shortcode: "mute"}
NameBadge = Reaction{Raw: "📛", Shortcode: "name_badge"}
Necktie = Reaction{Raw: "👔", Shortcode: "necktie"}
Newspaper = Reaction{Raw: "📰", Shortcode: "newspaper"}
NoBell = Reaction{Raw: "🔕", Shortcode: "no_bell"}
Notebook = Reaction{Raw: "📓", Shortcode: "notebook"}
NotebookWithDecorativeCover = Reaction{Raw: "📔", Shortcode: "notebook_with_decorative_cover"}
NutAndBolt = Reaction{Raw: "🔩", Shortcode: "nut_and_bolt"}
Oden = Reaction{Raw: "🍢", Shortcode: "oden"}
OpenFileFolder = Reaction{Raw: "📂", Shortcode: "open_file_folder"}
OrangeBook = Reaction{Raw: "📙", Shortcode: "orange_book"}
OutboxTray = Reaction{Raw: "📤", Shortcode: "outbox_tray"}
Package = Reaction{Raw: "📦", Shortcode: "package"}
PageFacingUp = Reaction{Raw: "📄", Shortcode: "page_facing_up"}
PageWithCurl = Reaction{Raw: "📃", Shortcode: "page_with_curl"}
Pager = Reaction{Raw: "📟", Shortcode: "pager"}
Paperclip = Reaction{Raw: "📎", Shortcode: "paperclip"}
Peach = Reaction{Raw: "🍑", Shortcode: "peach"}
Pear = Reaction{Raw: "🍐", Shortcode: "pear"}
Pencil = Reaction{Raw: "✏", Shortcode: "pencil"}
PencilTwo = Reaction{Raw: "✏", Shortcode: "pencil2"}
Phone = Reaction{Raw: "☎️", Shortcode: "phone"}
Pill = Reaction{Raw: "💊", Shortcode: "pill"}
Pineapple = Reaction{Raw: "🍍", Shortcode: "pineapple"}
Pizza = Reaction{Raw: "🍕", Shortcode: "pizza"}
PostalHorn = Reaction{Raw: "📯", Shortcode: "postal_horn"}
Postbox = Reaction{Raw: "📮", Shortcode: "postbox"}
Pouch = Reaction{Raw: "👝", Shortcode: "pouch"}
PoultryLeg = Reaction{Raw: "🍗", Shortcode: "poultry_leg"}
Pound = Reaction{Raw: "💷", Shortcode: "pound"}
Purse = Reaction{Raw: "👛", Shortcode: "purse"}
Pushpin = Reaction{Raw: "📌", Shortcode: "pushpin"}
Radio = Reaction{Raw: "📻", Shortcode: "radio"}
Ramen = Reaction{Raw: "🍜", Shortcode: "ramen"}
Ribbon = Reaction{Raw: "🎀", Shortcode: "ribbon"}
Rice = Reaction{Raw: "🍚", Shortcode: "rice"}
RiceBall = Reaction{Raw: "🍙", Shortcode: "rice_ball"}
RiceCracker = Reaction{Raw: "🍘", Shortcode: "rice_cracker"}
RiceScene = Reaction{Raw: "🎑", Shortcode: "rice_scene"}
Ring = Reaction{Raw: "💍", Shortcode: "ring"}
RugbyFootball = Reaction{Raw: "🏉", Shortcode: "rugby_football"}
RunningShirtWithSash = Reaction{Raw: "🎽", Shortcode: "running_shirt_with_sash"}
Sake = Reaction{Raw: "🍶", Shortcode: "sake"}
Sandal = Reaction{Raw: "👡", Shortcode: "sandal"}
Santa = Reaction{Raw: "🎅", Shortcode: "santa"}
Satellite = Reaction{Raw: "🛰", Shortcode: "satellite"}
Saxophone = Reaction{Raw: "🎷", Shortcode: "saxophone"}
SchoolSatchel = Reaction{Raw: "🎒", Shortcode: "school_satchel"}
Scissors = Reaction{Raw: "✂", Shortcode: "scissors"}
Scroll = Reaction{Raw: "📜", Shortcode: "scroll"}
Seat = Reaction{Raw: "💺", Shortcode: "seat"}
ShavedIce = Reaction{Raw: "🍧", Shortcode: "shaved_ice"}
Shirt = Reaction{Raw: "👕", Shortcode: "shirt"}
Shoe = Reaction{Raw: "👞", Shortcode: "shoe"}
Shower = Reaction{Raw: "🚿", Shortcode: "shower"}
Ski = Reaction{Raw: "🎿", Shortcode: "ski"}
Smoking = Reaction{Raw: "🚬", Shortcode: "smoking"}
Snowboarder = Reaction{Raw: "🏂", Shortcode: "snowboarder"}
Soccer = Reaction{Raw: "⚽", Shortcode: "soccer"}
Sound = Reaction{Raw: "🔉", Shortcode: "sound"}
SpaceInvader = Reaction{Raw: "👾", Shortcode: "space_invader"}
Spades = Reaction{Raw: "♠", Shortcode: "spades"}
Spaghetti = Reaction{Raw: "🍝", Shortcode: "spaghetti"}
Sparkler = Reaction{Raw: "🎇", Shortcode: "sparkler"}
Speaker = Reaction{Raw: "🔈", Shortcode: "speaker"}
Stew = Reaction{Raw: "🍲", Shortcode: "stew"}
StraightRuler = Reaction{Raw: "📏", Shortcode: "straight_ruler"}
Strawberry = Reaction{Raw: "🍓", Shortcode: "strawberry"}
Surfer = Reaction{Raw: "🏄", Shortcode: "surfer"}
Sushi = Reaction{Raw: "🍣", Shortcode: "sushi"}
SweetPotato = Reaction{Raw: "🍠", Shortcode: "sweet_potato"}
Swimmer = Reaction{Raw: "🏊", Shortcode: "swimmer"}
Syringe = Reaction{Raw: "💉", Shortcode: "syringe"}
Tada = Reaction{Raw: "🎉", Shortcode: "tada"}
TanabataTree = Reaction{Raw: "🎋", Shortcode: "tanabata_tree"}
Tangerine = Reaction{Raw: "🍊", Shortcode: "tangerine"}
Tea = Reaction{Raw: "🍵", Shortcode: "tea"}
Telephone = Reaction{Raw: "☎", Shortcode: "telephone"}
TelephoneReceiver = Reaction{Raw: "📞", Shortcode: "telephone_receiver"}
Telescope = Reaction{Raw: "🔭", Shortcode: "telescope"}
Tennis = Reaction{Raw: "🎾", Shortcode: "tennis"}
Toilet = Reaction{Raw: "🚽", Shortcode: "toilet"}
Tomato = Reaction{Raw: "🍅", Shortcode: "tomato"}
Tophat = Reaction{Raw: "🎩", Shortcode: "tophat"}
TriangularRuler = Reaction{Raw: "📐", Shortcode: "triangular_ruler"}
Trophy = Reaction{Raw: "🏆", Shortcode: "trophy"}
TropicalDrink = Reaction{Raw: "🍹", Shortcode: "tropical_drink"}
Trumpet = Reaction{Raw: "🎺", Shortcode: "trumpet"}
Tshirt = Reaction{Raw: "👕", Shortcode: "tshirt"}
Tv = Reaction{Raw: "📺", Shortcode: "tv"}
Unlock = Reaction{Raw: "🔓", Shortcode: "unlock"}
Vhs = Reaction{Raw: "📼", Shortcode: "vhs"}
VideoCamera = Reaction{Raw: "📹", Shortcode: "video_camera"}
VideoGame = Reaction{Raw: "🎮", Shortcode: "video_game"}
Violin = Reaction{Raw: "🎻", Shortcode: "violin"}
Watch = Reaction{Raw: "⌚", Shortcode: "watch"}
Watermelon = Reaction{Raw: "🍉", Shortcode: "watermelon"}
WindChime = Reaction{Raw: "🎐", Shortcode: "wind_chime"}
WineGlass = Reaction{Raw: "🍷", Shortcode: "wine_glass"}
WomansClothes = Reaction{Raw: "👚", Shortcode: "womans_clothes"}
WomansHat = Reaction{Raw: "👒", Shortcode: "womans_hat"}
Wrench = Reaction{Raw: "🔧", Shortcode: "wrench"}
Yen = Reaction{Raw: "💴", Shortcode: "yen"}
)
// Places emojis.
var (
AerialTramway = Reaction{Raw: "🚡", Shortcode: "aerial_tramway"}
Airplane = Reaction{Raw: "✈", Shortcode: "airplane"}
Ambulance = Reaction{Raw: "🚑", Shortcode: "ambulance"}
Anchor = Reaction{Raw: "⚓", Shortcode: "anchor"}
ArticulatedLorry = Reaction{Raw: "🚛", Shortcode: "articulated_lorry"}
Atm = Reaction{Raw: "🏧", Shortcode: "atm"}
Bank = Reaction{Raw: "🏦", Shortcode: "bank"}
Barber = Reaction{Raw: "💈", Shortcode: "barber"}
Beginner = Reaction{Raw: "🔰", Shortcode: "beginner"}
Bike = Reaction{Raw: "🚲", Shortcode: "bike"}
BlueCar = Reaction{Raw: "🚙", Shortcode: "blue_car"}
Boat = Reaction{Raw: "⛵️", Shortcode: "boat"}
BridgeAtNight = Reaction{Raw: "🌉", Shortcode: "bridge_at_night"}
BullettrainFront = Reaction{Raw: "🚅", Shortcode: "bullettrain_front"}
BullettrainSide = Reaction{Raw: "🚄", Shortcode: "bullettrain_side"}
Bus = Reaction{Raw: "🚌", Shortcode: "bus"}
Busstop = Reaction{Raw: "🚏", Shortcode: "busstop"}
Car = Reaction{Raw: "🚗", Shortcode: "car"}
CarouselHorse = Reaction{Raw: "🎠", Shortcode: "carousel_horse"}
CheckeredFlag = Reaction{Raw: "🏁", Shortcode: "checkered_flag"}
Church = Reaction{Raw: "⛪", Shortcode: "church"}
CircusTent = Reaction{Raw: "🎪", Shortcode: "circus_tent"}
CitySunrise = Reaction{Raw: "🌇", Shortcode: "city_sunrise"}
CitySunset = Reaction{Raw: "🌇", Shortcode: "city_sunset"}
Cn = Reaction{Raw: "🇨🇳", Shortcode: "cn"}
Construction = Reaction{Raw: "🚧", Shortcode: "construction"}
ConvenienceStore = Reaction{Raw: "🏪", Shortcode: "convenience_store"}
CrossedFlags = Reaction{Raw: "🎌", Shortcode: "crossed_flags"}
De = Reaction{Raw: "🇩🇪", Shortcode: "de"}
DepartmentStore = Reaction{Raw: "🏬", Shortcode: "department_store"}
Es = Reaction{Raw: "🇪🇸", Shortcode: "es"}
EuropeanCastle = Reaction{Raw: "🏰", Shortcode: "european_castle"}
EuropeanPostOffice = Reaction{Raw: "🏤", Shortcode: "european_post_office"}
Factory = Reaction{Raw: "🏭", Shortcode: "factory"}
FerrisWheel = Reaction{Raw: "🎡", Shortcode: "ferris_wheel"}
FireEngine = Reaction{Raw: "🚒", Shortcode: "fire_engine"}
Fountain = Reaction{Raw: "⛲", Shortcode: "fountain"}
Fr = Reaction{Raw: "🇫🇷", Shortcode: "fr"}
Fuelpump = Reaction{Raw: "⛽", Shortcode: "fuelpump"}
Gb = Reaction{Raw: "🇬🇧", Shortcode: "gb"}
Helicopter = Reaction{Raw: "🚁", Shortcode: "helicopter"}
Hospital = Reaction{Raw: "🏥", Shortcode: "hospital"}
Hotel = Reaction{Raw: "🏨", Shortcode: "hotel"}
Hotsprings = Reaction{Raw: "♨", Shortcode: "hotsprings"}
House = Reaction{Raw: "🏠", Shortcode: "house"}
HouseWithGarden = Reaction{Raw: "🏡", Shortcode: "house_with_garden"}
It = Reaction{Raw: "🇮🇹", Shortcode: "it"}
IzakayaLantern = Reaction{Raw: "🏮", Shortcode: "izakaya_lantern"}
Japan = Reaction{Raw: "🗾", Shortcode: "japan"}
JapaneseCastle = Reaction{Raw: "🏯", Shortcode: "japanese_castle"}
Jp = Reaction{Raw: "🇯🇵", Shortcode: "jp"}
Kr = Reaction{Raw: "🇰🇷", Shortcode: "kr"}
LightRail = Reaction{Raw: "🚈", Shortcode: "light_rail"}
LoveHotel = Reaction{Raw: "🏩", Shortcode: "love_hotel"}
Minibus = Reaction{Raw: "🚐", Shortcode: "minibus"}
Monorail = Reaction{Raw: "🚝", Shortcode: "monorail"}
MountFuji = Reaction{Raw: "🗻", Shortcode: "mount_fuji"}
MountainCableway = Reaction{Raw: "🚠", Shortcode: "mountain_cableway"}
MountainRailway = Reaction{Raw: "🚞", Shortcode: "mountain_railway"}
Moyai = Reaction{Raw: "🗿", Shortcode: "moyai"}
Office = Reaction{Raw: "🏢", Shortcode: "office"}
OncomingAutomobile = Reaction{Raw: "🚘", Shortcode: "oncoming_automobile"}
OncomingBus = Reaction{Raw: "🚍", Shortcode: "oncoming_bus"}
OncomingPoliceCar = Reaction{Raw: "🚔", Shortcode: "oncoming_police_car"}
OncomingTaxi = Reaction{Raw: "🚖", Shortcode: "oncoming_taxi"}
PerformingArts = Reaction{Raw: "🎭", Shortcode: "performing_arts"}
PoliceCar = Reaction{Raw: "🚓", Shortcode: "police_car"}
PostOffice = Reaction{Raw: "🏤", Shortcode: "post_office"}
RailwayCar = Reaction{Raw: "🚃", Shortcode: "railway_car"}
Rainbow = Reaction{Raw: "🌈", Shortcode: "rainbow"}
RedCar = Reaction{Raw: "🚗", Shortcode: "red_car"}
Rocket = Reaction{Raw: "🚀", Shortcode: "rocket"}
RollerCoaster = Reaction{Raw: "🎢", Shortcode: "roller_coaster"}
RotatingLight = Reaction{Raw: "🚨", Shortcode: "rotating_light"}
RoundPushpin = Reaction{Raw: "📍", Shortcode: "round_pushpin"}
Rowboat = Reaction{Raw: "🚣", Shortcode: "rowboat"}
Ru = Reaction{Raw: "🇷🇺", Shortcode: "ru"}
Sailboat = Reaction{Raw: "⛵", Shortcode: "sailboat"}
School = Reaction{Raw: "🏫", Shortcode: "school"}
Ship = Reaction{Raw: "🚢", Shortcode: "ship"}
SlotMachine = Reaction{Raw: "🎰", Shortcode: "slot_machine"}
Speedboat = Reaction{Raw: "🚤", Shortcode: "speedboat"}
Stars = Reaction{Raw: "🌠", Shortcode: "stars"}
Station = Reaction{Raw: "🚉", Shortcode: "station"}
StatueOfLiberty = Reaction{Raw: "🗽", Shortcode: "statue_of_liberty"}
SteamLocomotive = Reaction{Raw: "🚂", Shortcode: "steam_locomotive"}
Sunrise = Reaction{Raw: "🌅", Shortcode: "sunrise"}
SunriseOverMountains = Reaction{Raw: "🌄", Shortcode: "sunrise_over_mountains"}
SuspensionRailway = Reaction{Raw: "🚟", Shortcode: "suspension_railway"}
Taxi = Reaction{Raw: "🚕", Shortcode: "taxi"}
Tent = Reaction{Raw: "⛺", Shortcode: "tent"}
Ticket = Reaction{Raw: "🎫", Shortcode: "ticket"}
TokyoTower = Reaction{Raw: "🗼", Shortcode: "tokyo_tower"}
Tractor = Reaction{Raw: "🚜", Shortcode: "tractor"}
TrafficLight = Reaction{Raw: "🚥", Shortcode: "traffic_light"}
Train = Reaction{Raw: "🚆", Shortcode: "train"}
TrainTwo = Reaction{Raw: "🚆", Shortcode: "train2"}
Tram = Reaction{Raw: "🚊", Shortcode: "tram"}
TriangularFlagOnPost = Reaction{Raw: "🚩", Shortcode: "triangular_flag_on_post"}
Trolleybus = Reaction{Raw: "🚎", Shortcode: "trolleybus"}
Truck = Reaction{Raw: "🚚", Shortcode: "truck"}
Uk = Reaction{Raw: "🇬🇧", Shortcode: "uk"}
Us = Reaction{Raw: "🇺🇸", Shortcode: "us"}
VerticalTrafficLight = Reaction{Raw: "🚦", Shortcode: "vertical_traffic_light"}
Warning = Reaction{Raw: "⚠", Shortcode: "warning"}
Wedding = Reaction{Raw: "💒", Shortcode: "wedding"}
)
// Symbols emojis.
var (
OneZeroZero = Reaction{Raw: "💯", Shortcode: "100"}
OneTwoThreeFour = Reaction{Raw: "🔢", Shortcode: "1234"}
A = Reaction{Raw: "🅰", Shortcode: "a"}
Ab = Reaction{Raw: "🆎", Shortcode: "ab"}
Abc = Reaction{Raw: "🔤", Shortcode: "abc"}
Abcd = Reaction{Raw: "🔡", Shortcode: "abcd"}
Accept = Reaction{Raw: "🉑", Shortcode: "accept"}
Aquarius = Reaction{Raw: "♒", Shortcode: "aquarius"}
Aries = Reaction{Raw: "♈", Shortcode: "aries"}
ArrowBackward = Reaction{Raw: "◀", Shortcode: "arrow_backward"}
ArrowDoubleDown = Reaction{Raw: "⏬", Shortcode: "arrow_double_down"}
ArrowDoubleUp = Reaction{Raw: "⏫", Shortcode: "arrow_double_up"}
ArrowDown = Reaction{Raw: "⬇", Shortcode: "arrow_down"}
ArrowDownSmall = Reaction{Raw: "🔽", Shortcode: "arrow_down_small"}
ArrowForward = Reaction{Raw: "▶", Shortcode: "arrow_forward"}
ArrowHeadingDown = Reaction{Raw: "⤵", Shortcode: "arrow_heading_down"}
ArrowHeadingUp = Reaction{Raw: "⤴", Shortcode: "arrow_heading_up"}
ArrowLeft = Reaction{Raw: "⬅", Shortcode: "arrow_left"}
ArrowLowerLeft = Reaction{Raw: "↙", Shortcode: "arrow_lower_left"}
ArrowLowerRight = Reaction{Raw: "↘", Shortcode: "arrow_lower_right"}
ArrowRight = Reaction{Raw: "➡", Shortcode: "arrow_right"}
ArrowRightHook = Reaction{Raw: "↪", Shortcode: "arrow_right_hook"}
ArrowUp = Reaction{Raw: "⬆", Shortcode: "arrow_up"}
ArrowUpDown = Reaction{Raw: "↕", Shortcode: "arrow_up_down"}
ArrowUpSmall = Reaction{Raw: "🔼", Shortcode: "arrow_up_small"}
ArrowUpperLeft = Reaction{Raw: "↖", Shortcode: "arrow_upper_left"}
ArrowUpperRight = Reaction{Raw: "↗", Shortcode: "arrow_upper_right"}
ArrowsClockwise = Reaction{Raw: "🔃", Shortcode: "arrows_clockwise"}
ArrowsCounterclockwise = Reaction{Raw: "🔄", Shortcode: "arrows_counterclockwise"}
B = Reaction{Raw: "🅱", Shortcode: "b"}
BabySymbol = Reaction{Raw: "🚼", Shortcode: "baby_symbol"}
Back = Reaction{Raw: "🔙", Shortcode: "back"}
BaggageClaim = Reaction{Raw: "🛄", Shortcode: "baggage_claim"}
BallotBoxWithCheck = Reaction{Raw: "☑", Shortcode: "ballot_box_with_check"}
Bangbang = Reaction{Raw: "‼", Shortcode: "bangbang"}
BlackCircle = Reaction{Raw: "⚫", Shortcode: "black_circle"}
BlackLargeSquare = Reaction{Raw: "⬛", Shortcode: "black_large_square"}
BlackMediumSmallSquare = Reaction{Raw: "◾", Shortcode: "black_medium_small_square"}
BlackMediumSquare = Reaction{Raw: "◼", Shortcode: "black_medium_square"}
BlackSmallSquare = Reaction{Raw: "▪", Shortcode: "black_small_square"}
BlackSquareButton = Reaction{Raw: "🔲", Shortcode: "black_square_button"}
Cancer = Reaction{Raw: "♋", Shortcode: "cancer"}
CapitalAbcd = Reaction{Raw: "🔠", Shortcode: "capital_abcd"}
Capricorn = Reaction{Raw: "♑", Shortcode: "capricorn"}
Chart = Reaction{Raw: "💹", Shortcode: "chart"}
ChildrenCrossing = Reaction{Raw: "🚸", Shortcode: "children_crossing"}
Cinema = Reaction{Raw: "🎦", Shortcode: "cinema"}
Cl = Reaction{Raw: "🆑", Shortcode: "cl"}
ClockOne = Reaction{Raw: "🕐", Shortcode: "clock1"}
ClockOneZero = Reaction{Raw: "🕙", Shortcode: "clock10"}
ClockOneZeroThreeZero = Reaction{Raw: "🕥", Shortcode: "clock1030"}
ClockOneOne = Reaction{Raw: "🕚", Shortcode: "clock11"}
ClockOneOneThreeZero = Reaction{Raw: "🕦", Shortcode: "clock1130"}
ClockOneTwo = Reaction{Raw: "🕛", Shortcode: "clock12"}
ClockOneTwoThreeZero = Reaction{Raw: "🕧", Shortcode: "clock1230"}
ClockOneThreeZero = Reaction{Raw: "🕜", Shortcode: "clock130"}
ClockTwo = Reaction{Raw: "🕑", Shortcode: "clock2"}
ClockTwoThreeZero = Reaction{Raw: "🕝", Shortcode: "clock230"}
ClockThree = Reaction{Raw: "🕒", Shortcode: "clock3"}
ClockThreeThreeZero = Reaction{Raw: "🕞", Shortcode: "clock330"}
ClockFour = Reaction{Raw: "🕓", Shortcode: "clock4"}
ClockFourThreeZero = Reaction{Raw: "🕟", Shortcode: "clock430"}
ClockFive = Reaction{Raw: "🕔", Shortcode: "clock5"}
ClockFiveThreeZero = Reaction{Raw: "🕠", Shortcode: "clock530"}
ClockSix = Reaction{Raw: "🕕", Shortcode: "clock6"}
ClockSixThreeZero = Reaction{Raw: "🕡", Shortcode: "clock630"}
ClockSeven = Reaction{Raw: "🕖", Shortcode: "clock7"}
ClockSevenThreeZero = Reaction{Raw: "🕢", Shortcode: "clock730"}
ClockEight = Reaction{Raw: "🕗", Shortcode: "clock8"}
ClockEightThreeZero = Reaction{Raw: "🕣", Shortcode: "clock830"}
ClockNine = Reaction{Raw: "🕘", Shortcode: "clock9"}
ClockNineThreeZero = Reaction{Raw: "🕤", Shortcode: "clock930"}
Congratulations = Reaction{Raw: "㊗", Shortcode: "congratulations"}
Cool = Reaction{Raw: "🆒", Shortcode: "cool"}
Copyright = Reaction{Raw: "©", Shortcode: "copyright"}
CurlyLoop = Reaction{Raw: "➰", Shortcode: "curly_loop"}
CurrencyExchange = Reaction{Raw: "💱", Shortcode: "currency_exchange"}
Customs = Reaction{Raw: "🛃", Shortcode: "customs"}
DiamondShapeWithADotInside = Reaction{Raw: "💠", Shortcode: "diamond_shape_with_a_dot_inside"}
DoNotLitter = Reaction{Raw: "🚯", Shortcode: "do_not_litter"}
Eight = Reaction{Raw: "8⃣", Shortcode: "eight"}
EightPointedBlackStar = Reaction{Raw: "✴", Shortcode: "eight_pointed_black_star"}
EightSpokedAsterisk = Reaction{Raw: "✳", Shortcode: "eight_spoked_asterisk"}
End = Reaction{Raw: "🔚", Shortcode: "end"}
FastForward = Reaction{Raw: "⏩", Shortcode: "fast_forward"}
Five = Reaction{Raw: "5⃣", Shortcode: "five"}
Four = Reaction{Raw: "4⃣", Shortcode: "four"}
Free = Reaction{Raw: "🆓", Shortcode: "free"}
Gemini = Reaction{Raw: "♊", Shortcode: "gemini"}
Hash = Reaction{Raw: "#️⃣", Shortcode: "hash"}
HeartDecoration = Reaction{Raw: "💟", Shortcode: "heart_decoration"}
HeavyCheckMark = Reaction{Raw: "✔", Shortcode: "heavy_check_mark"}
HeavyDivisionSign = Reaction{Raw: "➗", Shortcode: "heavy_division_sign"}
HeavyDollarSign = Reaction{Raw: "💲", Shortcode: "heavy_dollar_sign"}
HeavyExclamationMark = Reaction{Raw: "❗️", Shortcode: "heavy_exclamation_mark"}
HeavyMinusSign = Reaction{Raw: "", Shortcode: "heavy_minus_sign"}
HeavyMultiplicationX = Reaction{Raw: "✖", Shortcode: "heavy_multiplication_x"}
HeavyPlusSign = Reaction{Raw: "", Shortcode: "heavy_plus_sign"}
ID = Reaction{Raw: "🆔", Shortcode: "id"}
IdeographAdvantage = Reaction{Raw: "🉐", Shortcode: "ideograph_advantage"}
InformationSource = Reaction{Raw: "", Shortcode: "information_source"}
Interrobang = Reaction{Raw: "⁉", Shortcode: "interrobang"}
KeycapTen = Reaction{Raw: "🔟", Shortcode: "keycap_ten"}
Koko = Reaction{Raw: "🈁", Shortcode: "koko"}
LargeBlueCircle = Reaction{Raw: "🔵", Shortcode: "large_blue_circle"}
LargeBlueDiamond = Reaction{Raw: "🔷", Shortcode: "large_blue_diamond"}
LargeOrangeDiamond = Reaction{Raw: "🔶", Shortcode: "large_orange_diamond"}
LeftLuggage = Reaction{Raw: "🛅", Shortcode: "left_luggage"}
LeftRightArrow = Reaction{Raw: "↔", Shortcode: "left_right_arrow"}
LeftwardsArrowWithHook = Reaction{Raw: "↩", Shortcode: "leftwards_arrow_with_hook"}
Leo = Reaction{Raw: "♌", Shortcode: "leo"}
Libra = Reaction{Raw: "♎", Shortcode: "libra"}
Link = Reaction{Raw: "🔗", Shortcode: "link"}
M = Reaction{Raw: "ⓜ", Shortcode: "m"}
Mens = Reaction{Raw: "🚹", Shortcode: "mens"}
Metro = Reaction{Raw: "🚇", Shortcode: "metro"}
MobilePhoneOff = Reaction{Raw: "📴", Shortcode: "mobile_phone_off"}
NegativeSquaredCrossMark = Reaction{Raw: "❎", Shortcode: "negative_squared_cross_mark"}
New = Reaction{Raw: "🆕", Shortcode: "new"}
Ng = Reaction{Raw: "🆖", Shortcode: "ng"}
Nine = Reaction{Raw: "9⃣", Shortcode: "nine"}
NoBicycles = Reaction{Raw: "🚳", Shortcode: "no_bicycles"}
NoEntry = Reaction{Raw: "⛔", Shortcode: "no_entry"}
NoEntrySign = Reaction{Raw: "🚫", Shortcode: "no_entry_sign"}
NoMobilePhones = Reaction{Raw: "📵", Shortcode: "no_mobile_phones"}
NoPedestrians = Reaction{Raw: "🚷", Shortcode: "no_pedestrians"}
NoSmoking = Reaction{Raw: "🚭", Shortcode: "no_smoking"}
NonMinuspotableWater = Reaction{Raw: "🚱", Shortcode: "non-potable_water"}
O = Reaction{Raw: "⭕", Shortcode: "o"}
OTwo = Reaction{Raw: "🅾", Shortcode: "o2"}
Ok = Reaction{Raw: "🆗", Shortcode: "ok"}
On = Reaction{Raw: "🔛", Shortcode: "on"}
One = Reaction{Raw: "1⃣", Shortcode: "one"}
Ophiuchus = Reaction{Raw: "⛎", Shortcode: "ophiuchus"}
Parking = Reaction{Raw: "🅿", Shortcode: "parking"}
PartAlternationMark = Reaction{Raw: "〽", Shortcode: "part_alternation_mark"}
PassportControl = Reaction{Raw: "🛂", Shortcode: "passport_control"}
Pisces = Reaction{Raw: "♓", Shortcode: "pisces"}
PotableWater = Reaction{Raw: "🚰", Shortcode: "potable_water"}
PutLitterInItsPlace = Reaction{Raw: "🚮", Shortcode: "put_litter_in_its_place"}
RadioButton = Reaction{Raw: "🔘", Shortcode: "radio_button"}
Recycle = Reaction{Raw: "♻", Shortcode: "recycle"}
RedCircle = Reaction{Raw: "🔴", Shortcode: "red_circle"}
Registered = Reaction{Raw: "®", Shortcode: "registered"}
Repeat = Reaction{Raw: "🔁", Shortcode: "repeat"}
RepeatOne = Reaction{Raw: "🔂", Shortcode: "repeat_one"}
Restroom = Reaction{Raw: "🚻", Shortcode: "restroom"}
Rewind = Reaction{Raw: "⏪", Shortcode: "rewind"}
Sa = Reaction{Raw: "🈂", Shortcode: "sa"}
Sagittarius = Reaction{Raw: "♐", Shortcode: "sagittarius"}
Scorpius = Reaction{Raw: "♏", Shortcode: "scorpius"}
Secret = Reaction{Raw: "㊙", Shortcode: "secret"}
Seven = Reaction{Raw: "7⃣", Shortcode: "seven"}
Shipit = Reaction{Raw: "", Shortcode: "shipit"}
SignalStrength = Reaction{Raw: "📶", Shortcode: "signal_strength"}
Six = Reaction{Raw: "6⃣", Shortcode: "six"}
SixPointedStar = Reaction{Raw: "🔯", Shortcode: "six_pointed_star"}
SmallBlueDiamond = Reaction{Raw: "🔹", Shortcode: "small_blue_diamond"}
SmallOrangeDiamond = Reaction{Raw: "🔸", Shortcode: "small_orange_diamond"}
SmallRedTriangle = Reaction{Raw: "🔺", Shortcode: "small_red_triangle"}
SmallRedTriangleDown = Reaction{Raw: "🔻", Shortcode: "small_red_triangle_down"}
Soon = Reaction{Raw: "🔜", Shortcode: "soon"}
Sos = Reaction{Raw: "🆘", Shortcode: "sos"}
Sparkle = Reaction{Raw: "❇", Shortcode: "sparkle"}
Symbols = Reaction{Raw: "🔣", Shortcode: "symbols"}
Taurus = Reaction{Raw: "♉", Shortcode: "taurus"}
Three = Reaction{Raw: "3⃣", Shortcode: "three"}
Tm = Reaction{Raw: "™", Shortcode: "tm"}
Top = Reaction{Raw: "🔝", Shortcode: "top"}
Trident = Reaction{Raw: "🔱", Shortcode: "trident"}
TwistedRightwardsArrows = Reaction{Raw: "🔀", Shortcode: "twisted_rightwards_arrows"}
Two = Reaction{Raw: "2⃣", Shortcode: "two"}
UFiveTwoSevenTwo = Reaction{Raw: "🈹", Shortcode: "u5272"}
UFiveFourZeroEight = Reaction{Raw: "🈴", Shortcode: "u5408"}
UFiveFivebSix = Reaction{Raw: "🈺", Shortcode: "u55b6"}
USixThreeZeroSeven = Reaction{Raw: "🈯", Shortcode: "u6307"}
USixSevenZeroEight = Reaction{Raw: "🈷", Shortcode: "u6708"}
USixSevenZeroNine = Reaction{Raw: "🈶", Shortcode: "u6709"}
USixeEightZero = Reaction{Raw: "🈵", Shortcode: "u6e80"}
USevenOneTwoOne = Reaction{Raw: "🈚", Shortcode: "u7121"}
USevenFiveThreeThree = Reaction{Raw: "🈸", Shortcode: "u7533"}
USevenNineEightOne = Reaction{Raw: "🈲", Shortcode: "u7981"}
USevenaSevena = Reaction{Raw: "🈳", Shortcode: "u7a7a"}
Underage = Reaction{Raw: "🔞", Shortcode: "underage"}
Up = Reaction{Raw: "🆙", Shortcode: "up"}
VibrationMode = Reaction{Raw: "📳", Shortcode: "vibration_mode"}
Virgo = Reaction{Raw: "♍", Shortcode: "virgo"}
Vs = Reaction{Raw: "🆚", Shortcode: "vs"}
WavyDash = Reaction{Raw: "〰", Shortcode: "wavy_dash"}
Wc = Reaction{Raw: "🚾", Shortcode: "wc"}
Wheelchair = Reaction{Raw: "♿", Shortcode: "wheelchair"}
WhiteCheckMark = Reaction{Raw: "✅", Shortcode: "white_check_mark"}
WhiteCircle = Reaction{Raw: "⚪", Shortcode: "white_circle"}
WhiteFlower = Reaction{Raw: "💮", Shortcode: "white_flower"}
WhiteLargeSquare = Reaction{Raw: "⬜", Shortcode: "white_large_square"}
WhiteMediumSmallSquare = Reaction{Raw: "◽", Shortcode: "white_medium_small_square"}
WhiteMediumSquare = Reaction{Raw: "◻", Shortcode: "white_medium_square"}
WhiteSmallSquare = Reaction{Raw: "▫", Shortcode: "white_small_square"}
WhiteSquareButton = Reaction{Raw: "🔳", Shortcode: "white_square_button"}
Womens = Reaction{Raw: "🚺", Shortcode: "womens"}
X = Reaction{Raw: "❌", Shortcode: "x"}
Zero = Reaction{Raw: "0⃣", Shortcode: "zero"}
)
// String returns the UTF string value of the Reaction (e.g. 👍).
func (r Reaction) String() string {
if r.Raw != "" {
return r.Raw
}
return r.Shortcode
}

187
vendor/github.com/go-joe/joe/storage.go generated vendored Normal file
View File

@ -0,0 +1,187 @@
package joe
import (
"encoding/json"
"sort"
"sync"
"github.com/pkg/errors"
"go.uber.org/zap"
)
// A Storage provides a convenient interface to a Memory implementation. It is
// responsible for how the actual key value data is encoded and provides
// concurrent access as well as logging.
//
// The default Storage that is returned by joe.NewStorage() encodes values as
// JSON and stores them in-memory.
type Storage struct {
logger *zap.Logger
mu sync.RWMutex
memory Memory
encoder MemoryEncoder
}
// The Memory interface allows the bot to persist data as key-value pairs.
// The default implementation of the Memory is to store all keys and values in
// a map (i.e. in-memory). Other implementations typically offer actual long term
// persistence into a file or to redis.
type Memory interface {
Set(key string, value []byte) error
Get(key string) ([]byte, bool, error)
Delete(key string) (bool, error)
Keys() ([]string, error)
Close() error
}
// A MemoryEncoder is used to encode and decode any values that are stored in
// the Memory. The default implementation that is used by the Storage uses a
// JSON encoding.
type MemoryEncoder interface {
Encode(value interface{}) ([]byte, error)
Decode(data []byte, target interface{}) error
}
type inMemory struct {
data map[string][]byte
}
type jsonEncoder struct{}
// NewStorage creates a new Storage instance that encodes values as JSON and
// stores them in-memory. You can change the memory and encoding via the
// provided setters.
func NewStorage(logger *zap.Logger) *Storage {
return &Storage{
logger: logger,
memory: newInMemory(),
encoder: new(jsonEncoder),
}
}
// SetMemory assigns a different Memory implementation.
func (s *Storage) SetMemory(m Memory) {
s.mu.Lock()
s.memory = m
s.mu.Unlock()
}
// SetMemoryEncoder assigns a different MemoryEncoder.
func (s *Storage) SetMemoryEncoder(enc MemoryEncoder) {
s.mu.Lock()
s.encoder = enc
s.mu.Unlock()
}
// Keys returns all keys known to the Memory.
func (s *Storage) Keys() ([]string, error) {
s.mu.RLock()
keys, err := s.memory.Keys()
s.mu.RUnlock()
sort.Strings(keys)
return keys, err
}
// Set encodes the given data and stores it in the Memory that is managed by the
// Storage.
func (s *Storage) Set(key string, value interface{}) error {
data, err := s.encoder.Encode(value)
if err != nil {
return errors.Wrap(err, "encode data")
}
s.mu.Lock()
s.logger.Debug("Writing data to memory", zap.String("key", key))
err = s.memory.Set(key, data)
s.mu.Unlock()
return err
}
// Get retrieves the value under the requested key and decodes it into the
// passed "value" argument which must be a pointer. The boolean return value
// indicates if the value actually existed in the Memory and is false if it did
// not. It is legal to pass <nil> as the value if you only want to check if
// the given key exists but you do not actually care about the concrete value.
func (s *Storage) Get(key string, value interface{}) (bool, error) {
s.mu.RLock()
s.logger.Debug("Retrieving data from memory", zap.String("key", key))
data, ok, err := s.memory.Get(key)
s.mu.RUnlock()
if err != nil {
return false, errors.WithStack(err)
}
if !ok || value == nil {
return ok, nil
}
err = s.encoder.Decode(data, value)
if err != nil {
return false, errors.Wrap(err, "decode data")
}
return true, nil
}
// Delete removes a key and its associated value from the memory. The boolean
// return value indicates if the key existed or not.
func (s *Storage) Delete(key string) (bool, error) {
s.mu.Lock()
s.logger.Debug("Deleting data from memory", zap.String("key", key))
ok, err := s.memory.Delete(key)
s.mu.Unlock()
return ok, err
}
// Close closes the Memory that is managed by this Storage.
func (s *Storage) Close() error {
s.mu.Lock()
err := s.memory.Close()
s.mu.Unlock()
return err
}
func newInMemory() *inMemory {
return &inMemory{data: map[string][]byte{}}
}
func (m *inMemory) Set(key string, value []byte) error {
m.data[key] = value
return nil
}
func (m *inMemory) Get(key string) ([]byte, bool, error) {
value, ok := m.data[key]
return value, ok, nil
}
func (m *inMemory) Delete(key string) (bool, error) {
_, ok := m.data[key]
delete(m.data, key)
return ok, nil
}
func (m *inMemory) Keys() ([]string, error) {
keys := make([]string, 0, len(m.data))
for k := range m.data {
keys = append(keys, k)
}
return keys, nil
}
func (m *inMemory) Close() error {
m.data = map[string][]byte{}
return nil
}
func (jsonEncoder) Encode(value interface{}) ([]byte, error) {
return json.Marshal(value)
}
func (jsonEncoder) Decode(data []byte, target interface{}) error {
return json.Unmarshal(data, target)
}

8
vendor/github.com/go-joe/joe/user.go generated vendored Normal file
View File

@ -0,0 +1,8 @@
package joe
// User contains all the information about a user.
type User struct {
ID string
Name string
RealName string
}

24
vendor/github.com/pkg/errors/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

10
vendor/github.com/pkg/errors/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,10 @@
language: go
go_import_path: github.com/pkg/errors
go:
- 1.11.x
- 1.12.x
- 1.13.x
- tip
script:
- make check

23
vendor/github.com/pkg/errors/LICENSE generated vendored Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2015, Dave Cheney <[email protected]>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

44
vendor/github.com/pkg/errors/Makefile generated vendored Normal file
View File

@ -0,0 +1,44 @@
PKGS := github.com/pkg/errors
SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
GO := go
check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
test:
$(GO) test $(PKGS)
vet: | test
$(GO) vet $(PKGS)
staticcheck:
$(GO) get honnef.co/go/tools/cmd/staticcheck
staticcheck -checks all $(PKGS)
misspell:
$(GO) get github.com/client9/misspell/cmd/misspell
misspell \
-locale GB \
-error \
*.md *.go
unconvert:
$(GO) get github.com/mdempsky/unconvert
unconvert -v $(PKGS)
ineffassign:
$(GO) get github.com/gordonklaus/ineffassign
find $(SRCDIRS) -name '*.go' | xargs ineffassign
pedantic: check errcheck
unparam:
$(GO) get mvdan.cc/unparam
unparam ./...
errcheck:
$(GO) get github.com/kisielk/errcheck
errcheck $(PKGS)
gofmt:
@echo Checking code is gofmted
@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"

59
vendor/github.com/pkg/errors/README.md generated vendored Normal file
View File

@ -0,0 +1,59 @@
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
Package errors provides simple error handling primitives.
`go get github.com/pkg/errors`
The traditional error handling idiom in Go is roughly akin to
```go
if err != nil {
return err
}
```
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
## Adding context to an error
The errors.Wrap function returns a new error that adds context to the original error. For example
```go
_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}
```
## Retrieving the cause of an error
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
```go
type causer interface {
Cause() error
}
```
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
```go
switch err := errors.Cause(err).(type) {
case *MyError:
// handle specifically
default:
// unknown error
}
```
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Roadmap
With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
- 1.0. Final release.
## Contributing
Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
Before sending a PR, please discuss your change by raising an issue.
## License
BSD-2-Clause

32
vendor/github.com/pkg/errors/appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,32 @@
version: build-{build}.{branch}
clone_folder: C:\gopath\src\github.com\pkg\errors
shallow_clone: true # for startup speed
environment:
GOPATH: C:\gopath
platform:
- x64
# http://www.appveyor.com/docs/installed-software
install:
# some helpful output for debugging builds
- go version
- go env
# pre-installed MinGW at C:\MinGW is 32bit only
# but MSYS2 at C:\msys64 has mingw64
- set PATH=C:\msys64\mingw64\bin;%PATH%
- gcc --version
- g++ --version
build_script:
- go install -v ./...
test_script:
- set PATH=C:\gopath\bin;%PATH%
- go test -v ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off

288
vendor/github.com/pkg/errors/errors.go generated vendored Normal file
View File

@ -0,0 +1,288 @@
// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
// if err != nil {
// return err
// }
//
// which when applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error by recording a stack trace at the point Wrap is called,
// together with the supplied message. For example
//
// _, err := ioutil.ReadAll(r)
// if err != nil {
// return errors.Wrap(err, "read failed")
// }
//
// If additional control is required, the errors.WithStack and
// errors.WithMessage functions destructure errors.Wrap into its component
// operations: annotating an error with a stack trace and with a message,
// respectively.
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
// type causer interface {
// Cause() error
// }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error that does not implement causer, which is assumed to be
// the original cause. For example:
//
// switch err := errors.Cause(err).(type) {
// case *MyError:
// // handle specifically
// default:
// // unknown error
// }
//
// Although the causer interface is not exported by this package, it is
// considered a part of its stable public interface.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported:
//
// %s print the error. If the error has a Cause it will be
// printed recursively.
// %v see %s
// %+v extended format. Each Frame of the error's StackTrace will
// be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface:
//
// type stackTracer interface {
// StackTrace() errors.StackTrace
// }
//
// The returned errors.StackTrace type is defined as
//
// type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d\n", f, f)
// }
// }
//
// Although the stackTracer interface is not exported by this package, it is
// considered a part of its stable public interface.
//
// See the documentation for Frame.Format for more details.
package errors
import (
"fmt"
"io"
)
// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
return &fundamental{
msg: message,
stack: callers(),
}
}
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
return &fundamental{
msg: fmt.Sprintf(format, args...),
stack: callers(),
}
}
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
msg string
*stack
}
func (f *fundamental) Error() string { return f.msg }
func (f *fundamental) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, f.msg)
case 'q':
fmt.Fprintf(s, "%q", f.msg)
}
}
// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
func WithStack(err error) error {
if err == nil {
return nil
}
return &withStack{
err,
callers(),
}
}
type withStack struct {
error
*stack
}
func (w *withStack) Cause() error { return w.error }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withStack) Unwrap() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v", w.Cause())
w.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, w.Error())
case 'q':
fmt.Fprintf(s, "%q", w.Error())
}
}
// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: message,
}
return &withStack{
err,
callers(),
}
}
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is called, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
// WithMessage annotates err with a new message.
// If err is nil, WithMessage returns nil.
func WithMessage(err error, message string) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: message,
}
}
// WithMessagef annotates err with the format specifier.
// If err is nil, WithMessagef returns nil.
func WithMessagef(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
}
type withMessage struct {
cause error
msg string
}
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withMessage) Unwrap() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v\n", w.Cause())
io.WriteString(s, w.msg)
return
}
fallthrough
case 's', 'q':
io.WriteString(s, w.Error())
}
}
// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
// type causer interface {
// Cause() error
// }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
type causer interface {
Cause() error
}
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}

38
vendor/github.com/pkg/errors/go113.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// +build go1.13
package errors
import (
stderrors "errors"
)
// Is reports whether any error in err's chain matches target.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
func Is(err, target error) bool { return stderrors.Is(err, target) }
// As finds the first error in err's chain that matches target, and if so, sets
// target to that error value and returns true.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error matches target if the error's concrete value is assignable to the value
// pointed to by target, or if the error has a method As(interface{}) bool such that
// As(target) returns true. In the latter case, the As method is responsible for
// setting target.
//
// As will panic if target is not a non-nil pointer to either a type that implements
// error, or to any interface type. As returns false if err is nil.
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
// Unwrap returns the result of calling the Unwrap method on err, if err's
// type contains an Unwrap method returning error.
// Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
return stderrors.Unwrap(err)
}

177
vendor/github.com/pkg/errors/stack.go generated vendored Normal file
View File

@ -0,0 +1,177 @@
package errors
import (
"fmt"
"io"
"path"
"runtime"
"strconv"
"strings"
)
// Frame represents a program counter inside a stack frame.
// For historical reasons if Frame is interpreted as a uintptr
// its value represents the program counter + 1.
type Frame uintptr
// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f Frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}
// line returns the line number of source code of the
// function for this Frame's pc.
func (f Frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}
// name returns the name of this function, if known.
func (f Frame) name() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
return fn.Name()
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
// %d source line
// %n function name
// %v equivalent to %s:%d
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s function name and path of source file relative to the compile time
// GOPATH separated by \n\t (<funcname>\n\t<path>)
// %+v equivalent to %+s:%d
func (f Frame) Format(s fmt.State, verb rune) {
switch verb {
case 's':
switch {
case s.Flag('+'):
io.WriteString(s, f.name())
io.WriteString(s, "\n\t")
io.WriteString(s, f.file())
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
io.WriteString(s, strconv.Itoa(f.line()))
case 'n':
io.WriteString(s, funcname(f.name()))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
f.Format(s, 'd')
}
}
// MarshalText formats a stacktrace Frame as a text string. The output is the
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
func (f Frame) MarshalText() ([]byte, error) {
name := f.name()
if name == "unknown" {
return []byte(name), nil
}
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
// Format formats the stack of Frames according to the fmt.Formatter interface.
//
// %s lists source files for each Frame in the stack
// %v lists the source file and line number for each Frame in the stack
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+v Prints filename, function, and line number for each Frame in the stack.
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
for _, f := range st {
io.WriteString(s, "\n")
f.Format(s, verb)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
st.formatSlice(s, verb)
}
case 's':
st.formatSlice(s, verb)
}
}
// formatSlice will format this StackTrace into the given buffer as a slice of
// Frame, only valid when called with '%s' or '%v'.
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
io.WriteString(s, "[")
for i, f := range st {
if i > 0 {
io.WriteString(s, " ")
}
f.Format(s, verb)
}
io.WriteString(s, "]")
}
// stack represents a stack of program counters.
type stack []uintptr
func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}
func (s *stack) StackTrace() StackTrace {
f := make([]Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = Frame((*s)[i])
}
return f
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
// funcname removes the path prefix component of a function's name reported by func.Name().
func funcname(name string) string {
i := strings.LastIndex(name, "/")
name = name[i+1:]
i = strings.Index(name, ".")
return name[i+1:]
}

15
vendor/go.uber.org/atomic/.codecov.yml generated vendored Normal file
View File

@ -0,0 +1,15 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 100 # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure

11
vendor/go.uber.org/atomic/.gitignore generated vendored Normal file
View File

@ -0,0 +1,11 @@
.DS_Store
/vendor
/cover
cover.out
lint.log
# Binaries
*.test
# Profiling output
*.prof

27
vendor/go.uber.org/atomic/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,27 @@
sudo: false
language: go
go_import_path: go.uber.org/atomic
go:
- 1.11.x
- 1.12.x
matrix:
include:
- go: 1.12.x
env: NO_TEST=yes LINT=yes
cache:
directories:
- vendor
install:
- make install_ci
script:
- test -n "$NO_TEST" || make test_ci
- test -n "$NO_TEST" || scripts/test-ubergo.sh
- test -z "$LINT" || make install_lint lint
after_success:
- bash <(curl -s https://codecov.io/bash)

19
vendor/go.uber.org/atomic/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2016 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

51
vendor/go.uber.org/atomic/Makefile generated vendored Normal file
View File

@ -0,0 +1,51 @@
# Many Go tools take file globs or directories as arguments instead of packages.
PACKAGE_FILES ?= *.go
# For pre go1.6
export GO15VENDOREXPERIMENT=1
.PHONY: build
build:
go build -i ./...
.PHONY: install
install:
glide --version || go get github.com/Masterminds/glide
glide install
.PHONY: test
test:
go test -cover -race ./...
.PHONY: install_ci
install_ci: install
go get github.com/wadey/gocovmerge
go get github.com/mattn/goveralls
go get golang.org/x/tools/cmd/cover
.PHONY: install_lint
install_lint:
go get golang.org/x/lint/golint
.PHONY: lint
lint:
@rm -rf lint.log
@echo "Checking formatting..."
@gofmt -d -s $(PACKAGE_FILES) 2>&1 | tee lint.log
@echo "Checking vet..."
@go vet ./... 2>&1 | tee -a lint.log;)
@echo "Checking lint..."
@golint $$(go list ./...) 2>&1 | tee -a lint.log
@echo "Checking for unresolved FIXMEs..."
@git grep -i fixme | grep -v -e vendor -e Makefile | tee -a lint.log
@[ ! -s lint.log ]
.PHONY: test_ci
test_ci: install_ci build
./scripts/cover.sh $(shell go list $(PACKAGES))

36
vendor/go.uber.org/atomic/README.md generated vendored Normal file
View File

@ -0,0 +1,36 @@
# atomic [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][reportcard-img]][reportcard]
Simple wrappers for primitive types to enforce atomic access.
## Installation
`go get -u go.uber.org/atomic`
## Usage
The standard library's `sync/atomic` is powerful, but it's easy to forget which
variables must be accessed atomically. `go.uber.org/atomic` preserves all the
functionality of the standard library, but wraps the primitive types to
provide a safer, more convenient API.
```go
var atom atomic.Uint32
atom.Store(42)
atom.Sub(2)
atom.CAS(40, 11)
```
See the [documentation][doc] for a complete API specification.
## Development Status
Stable.
___
Released under the [MIT License](LICENSE.txt).
[doc-img]: https://godoc.org/github.com/uber-go/atomic?status.svg
[doc]: https://godoc.org/go.uber.org/atomic
[ci-img]: https://travis-ci.com/uber-go/atomic.svg?branch=master
[ci]: https://travis-ci.com/uber-go/atomic
[cov-img]: https://codecov.io/gh/uber-go/atomic/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/atomic
[reportcard-img]: https://goreportcard.com/badge/go.uber.org/atomic
[reportcard]: https://goreportcard.com/report/go.uber.org/atomic

351
vendor/go.uber.org/atomic/atomic.go generated vendored Normal file
View File

@ -0,0 +1,351 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package atomic provides simple wrappers around numerics to enforce atomic
// access.
package atomic
import (
"math"
"sync/atomic"
"time"
)
// Int32 is an atomic wrapper around an int32.
type Int32 struct{ v int32 }
// NewInt32 creates an Int32.
func NewInt32(i int32) *Int32 {
return &Int32{i}
}
// Load atomically loads the wrapped value.
func (i *Int32) Load() int32 {
return atomic.LoadInt32(&i.v)
}
// Add atomically adds to the wrapped int32 and returns the new value.
func (i *Int32) Add(n int32) int32 {
return atomic.AddInt32(&i.v, n)
}
// Sub atomically subtracts from the wrapped int32 and returns the new value.
func (i *Int32) Sub(n int32) int32 {
return atomic.AddInt32(&i.v, -n)
}
// Inc atomically increments the wrapped int32 and returns the new value.
func (i *Int32) Inc() int32 {
return i.Add(1)
}
// Dec atomically decrements the wrapped int32 and returns the new value.
func (i *Int32) Dec() int32 {
return i.Sub(1)
}
// CAS is an atomic compare-and-swap.
func (i *Int32) CAS(old, new int32) bool {
return atomic.CompareAndSwapInt32(&i.v, old, new)
}
// Store atomically stores the passed value.
func (i *Int32) Store(n int32) {
atomic.StoreInt32(&i.v, n)
}
// Swap atomically swaps the wrapped int32 and returns the old value.
func (i *Int32) Swap(n int32) int32 {
return atomic.SwapInt32(&i.v, n)
}
// Int64 is an atomic wrapper around an int64.
type Int64 struct{ v int64 }
// NewInt64 creates an Int64.
func NewInt64(i int64) *Int64 {
return &Int64{i}
}
// Load atomically loads the wrapped value.
func (i *Int64) Load() int64 {
return atomic.LoadInt64(&i.v)
}
// Add atomically adds to the wrapped int64 and returns the new value.
func (i *Int64) Add(n int64) int64 {
return atomic.AddInt64(&i.v, n)
}
// Sub atomically subtracts from the wrapped int64 and returns the new value.
func (i *Int64) Sub(n int64) int64 {
return atomic.AddInt64(&i.v, -n)
}
// Inc atomically increments the wrapped int64 and returns the new value.
func (i *Int64) Inc() int64 {
return i.Add(1)
}
// Dec atomically decrements the wrapped int64 and returns the new value.
func (i *Int64) Dec() int64 {
return i.Sub(1)
}
// CAS is an atomic compare-and-swap.
func (i *Int64) CAS(old, new int64) bool {
return atomic.CompareAndSwapInt64(&i.v, old, new)
}
// Store atomically stores the passed value.
func (i *Int64) Store(n int64) {
atomic.StoreInt64(&i.v, n)
}
// Swap atomically swaps the wrapped int64 and returns the old value.
func (i *Int64) Swap(n int64) int64 {
return atomic.SwapInt64(&i.v, n)
}
// Uint32 is an atomic wrapper around an uint32.
type Uint32 struct{ v uint32 }
// NewUint32 creates a Uint32.
func NewUint32(i uint32) *Uint32 {
return &Uint32{i}
}
// Load atomically loads the wrapped value.
func (i *Uint32) Load() uint32 {
return atomic.LoadUint32(&i.v)
}
// Add atomically adds to the wrapped uint32 and returns the new value.
func (i *Uint32) Add(n uint32) uint32 {
return atomic.AddUint32(&i.v, n)
}
// Sub atomically subtracts from the wrapped uint32 and returns the new value.
func (i *Uint32) Sub(n uint32) uint32 {
return atomic.AddUint32(&i.v, ^(n - 1))
}
// Inc atomically increments the wrapped uint32 and returns the new value.
func (i *Uint32) Inc() uint32 {
return i.Add(1)
}
// Dec atomically decrements the wrapped int32 and returns the new value.
func (i *Uint32) Dec() uint32 {
return i.Sub(1)
}
// CAS is an atomic compare-and-swap.
func (i *Uint32) CAS(old, new uint32) bool {
return atomic.CompareAndSwapUint32(&i.v, old, new)
}
// Store atomically stores the passed value.
func (i *Uint32) Store(n uint32) {
atomic.StoreUint32(&i.v, n)
}
// Swap atomically swaps the wrapped uint32 and returns the old value.
func (i *Uint32) Swap(n uint32) uint32 {
return atomic.SwapUint32(&i.v, n)
}
// Uint64 is an atomic wrapper around a uint64.
type Uint64 struct{ v uint64 }
// NewUint64 creates a Uint64.
func NewUint64(i uint64) *Uint64 {
return &Uint64{i}
}
// Load atomically loads the wrapped value.
func (i *Uint64) Load() uint64 {
return atomic.LoadUint64(&i.v)
}
// Add atomically adds to the wrapped uint64 and returns the new value.
func (i *Uint64) Add(n uint64) uint64 {
return atomic.AddUint64(&i.v, n)
}
// Sub atomically subtracts from the wrapped uint64 and returns the new value.
func (i *Uint64) Sub(n uint64) uint64 {
return atomic.AddUint64(&i.v, ^(n - 1))
}
// Inc atomically increments the wrapped uint64 and returns the new value.
func (i *Uint64) Inc() uint64 {
return i.Add(1)
}
// Dec atomically decrements the wrapped uint64 and returns the new value.
func (i *Uint64) Dec() uint64 {
return i.Sub(1)
}
// CAS is an atomic compare-and-swap.
func (i *Uint64) CAS(old, new uint64) bool {
return atomic.CompareAndSwapUint64(&i.v, old, new)
}
// Store atomically stores the passed value.
func (i *Uint64) Store(n uint64) {
atomic.StoreUint64(&i.v, n)
}
// Swap atomically swaps the wrapped uint64 and returns the old value.
func (i *Uint64) Swap(n uint64) uint64 {
return atomic.SwapUint64(&i.v, n)
}
// Bool is an atomic Boolean.
type Bool struct{ v uint32 }
// NewBool creates a Bool.
func NewBool(initial bool) *Bool {
return &Bool{boolToInt(initial)}
}
// Load atomically loads the Boolean.
func (b *Bool) Load() bool {
return truthy(atomic.LoadUint32(&b.v))
}
// CAS is an atomic compare-and-swap.
func (b *Bool) CAS(old, new bool) bool {
return atomic.CompareAndSwapUint32(&b.v, boolToInt(old), boolToInt(new))
}
// Store atomically stores the passed value.
func (b *Bool) Store(new bool) {
atomic.StoreUint32(&b.v, boolToInt(new))
}
// Swap sets the given value and returns the previous value.
func (b *Bool) Swap(new bool) bool {
return truthy(atomic.SwapUint32(&b.v, boolToInt(new)))
}
// Toggle atomically negates the Boolean and returns the previous value.
func (b *Bool) Toggle() bool {
return truthy(atomic.AddUint32(&b.v, 1) - 1)
}
func truthy(n uint32) bool {
return n&1 == 1
}
func boolToInt(b bool) uint32 {
if b {
return 1
}
return 0
}
// Float64 is an atomic wrapper around float64.
type Float64 struct {
v uint64
}
// NewFloat64 creates a Float64.
func NewFloat64(f float64) *Float64 {
return &Float64{math.Float64bits(f)}
}
// Load atomically loads the wrapped value.
func (f *Float64) Load() float64 {
return math.Float64frombits(atomic.LoadUint64(&f.v))
}
// Store atomically stores the passed value.
func (f *Float64) Store(s float64) {
atomic.StoreUint64(&f.v, math.Float64bits(s))
}
// Add atomically adds to the wrapped float64 and returns the new value.
func (f *Float64) Add(s float64) float64 {
for {
old := f.Load()
new := old + s
if f.CAS(old, new) {
return new
}
}
}
// Sub atomically subtracts from the wrapped float64 and returns the new value.
func (f *Float64) Sub(s float64) float64 {
return f.Add(-s)
}
// CAS is an atomic compare-and-swap.
func (f *Float64) CAS(old, new float64) bool {
return atomic.CompareAndSwapUint64(&f.v, math.Float64bits(old), math.Float64bits(new))
}
// Duration is an atomic wrapper around time.Duration
// https://godoc.org/time#Duration
type Duration struct {
v Int64
}
// NewDuration creates a Duration.
func NewDuration(d time.Duration) *Duration {
return &Duration{v: *NewInt64(int64(d))}
}
// Load atomically loads the wrapped value.
func (d *Duration) Load() time.Duration {
return time.Duration(d.v.Load())
}
// Store atomically stores the passed value.
func (d *Duration) Store(n time.Duration) {
d.v.Store(int64(n))
}
// Add atomically adds to the wrapped time.Duration and returns the new value.
func (d *Duration) Add(n time.Duration) time.Duration {
return time.Duration(d.v.Add(int64(n)))
}
// Sub atomically subtracts from the wrapped time.Duration and returns the new value.
func (d *Duration) Sub(n time.Duration) time.Duration {
return time.Duration(d.v.Sub(int64(n)))
}
// Swap atomically swaps the wrapped time.Duration and returns the old value.
func (d *Duration) Swap(n time.Duration) time.Duration {
return time.Duration(d.v.Swap(int64(n)))
}
// CAS is an atomic compare-and-swap.
func (d *Duration) CAS(old, new time.Duration) bool {
return d.v.CAS(int64(old), int64(new))
}
// Value shadows the type of the same name from sync/atomic
// https://godoc.org/sync/atomic#Value
type Value struct{ atomic.Value }

55
vendor/go.uber.org/atomic/error.go generated vendored Normal file
View File

@ -0,0 +1,55 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package atomic
// Error is an atomic type-safe wrapper around Value for errors
type Error struct{ v Value }
// errorHolder is non-nil holder for error object.
// atomic.Value panics on saving nil object, so err object needs to be
// wrapped with valid object first.
type errorHolder struct{ err error }
// NewError creates new atomic error object
func NewError(err error) *Error {
e := &Error{}
if err != nil {
e.Store(err)
}
return e
}
// Load atomically loads the wrapped error
func (e *Error) Load() error {
v := e.v.Load()
if v == nil {
return nil
}
eh := v.(errorHolder)
return eh.err
}
// Store atomically stores error.
// NOTE: a holder object is allocated on each Store call.
func (e *Error) Store(err error) {
e.v.Store(errorHolder{err: err})
}

17
vendor/go.uber.org/atomic/glide.lock generated vendored Normal file
View File

@ -0,0 +1,17 @@
hash: f14d51408e3e0e4f73b34e4039484c78059cd7fc5f4996fdd73db20dc8d24f53
updated: 2016-10-27T00:10:51.16960137-07:00
imports: []
testImports:
- name: github.com/davecgh/go-spew
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
subpackages:
- spew
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/stretchr/testify
version: d77da356e56a7428ad25149ca77381849a6a5232
subpackages:
- assert
- require

6
vendor/go.uber.org/atomic/glide.yaml generated vendored Normal file
View File

@ -0,0 +1,6 @@
package: go.uber.org/atomic
testImport:
- package: github.com/stretchr/testify
subpackages:
- assert
- require

49
vendor/go.uber.org/atomic/string.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package atomic
// String is an atomic type-safe wrapper around Value for strings.
type String struct{ v Value }
// NewString creates a String.
func NewString(str string) *String {
s := &String{}
if str != "" {
s.Store(str)
}
return s
}
// Load atomically loads the wrapped string.
func (s *String) Load() string {
v := s.v.Load()
if v == nil {
return ""
}
return v.(string)
}
// Store atomically stores the passed string.
// Note: Converting the string to an interface{} to store in the Value
// requires an allocation.
func (s *String) Store(str string) {
s.v.Store(str)
}

15
vendor/go.uber.org/multierr/.codecov.yml generated vendored Normal file
View File

@ -0,0 +1,15 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 100 # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure

1
vendor/go.uber.org/multierr/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
/vendor

33
vendor/go.uber.org/multierr/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,33 @@
sudo: false
language: go
go_import_path: go.uber.org/multierr
env:
global:
- GO15VENDOREXPERIMENT=1
go:
- 1.11.x
- 1.12.x
- 1.13.x
cache:
directories:
- vendor
before_install:
- go version
install:
- |
set -e
make install_ci
script:
- |
set -e
make lint
make test_ci
after_success:
- bash <(curl -s https://codecov.io/bash)

35
vendor/go.uber.org/multierr/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,35 @@
Releases
========
v1.2.0 (2019-09-26)
===================
- Support extracting and matching against wrapped errors with `errors.As`
and `errors.Is`.
v1.1.0 (2017-06-30)
===================
- Added an `Errors(error) []error` function to extract the underlying list of
errors for a multierr error.
v1.0.0 (2017-05-31)
===================
No changes since v0.2.0. This release is committing to making no breaking
changes to the current API in the 1.X series.
v0.2.0 (2017-04-11)
===================
- Repeatedly appending to the same error is now faster due to fewer
allocations.
v0.1.0 (2017-31-03)
===================
- Initial release

19
vendor/go.uber.org/multierr/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2017 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

74
vendor/go.uber.org/multierr/Makefile generated vendored Normal file
View File

@ -0,0 +1,74 @@
export GO15VENDOREXPERIMENT=1
PACKAGES := $(shell glide nv)
GO_FILES := $(shell \
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
-o -name '*.go' -print | cut -b3-)
.PHONY: install
install:
glide --version || go get github.com/Masterminds/glide
glide install
.PHONY: build
build:
go build -i $(PACKAGES)
.PHONY: test
test:
go test -cover -race $(PACKAGES)
.PHONY: gofmt
gofmt:
$(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX))
@gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true
@[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" | cat - $(FMT_LOG) && false)
.PHONY: govet
govet:
$(eval VET_LOG := $(shell mktemp -t govet.XXXXX))
@go vet $(PACKAGES) 2>&1 \
| grep -v '^exit status' > $(VET_LOG) || true
@[ ! -s "$(VET_LOG)" ] || (echo "govet failed:" | cat - $(VET_LOG) && false)
.PHONY: golint
golint:
@go get golang.org/x/lint/golint
$(eval LINT_LOG := $(shell mktemp -t golint.XXXXX))
@cat /dev/null > $(LINT_LOG)
@$(foreach pkg, $(PACKAGES), golint $(pkg) >> $(LINT_LOG) || true;)
@[ ! -s "$(LINT_LOG)" ] || (echo "golint failed:" | cat - $(LINT_LOG) && false)
.PHONY: staticcheck
staticcheck:
@go get honnef.co/go/tools/cmd/staticcheck
$(eval STATICCHECK_LOG := $(shell mktemp -t staticcheck.XXXXX))
@staticcheck $(PACKAGES) 2>&1 > $(STATICCHECK_LOG) || true
@[ ! -s "$(STATICCHECK_LOG)" ] || (echo "staticcheck failed:" | cat - $(STATICCHECK_LOG) && false)
.PHONY: lint
lint: gofmt govet golint staticcheck
.PHONY: cover
cover:
./scripts/cover.sh $(shell go list $(PACKAGES))
go tool cover -html=cover.out -o cover.html
update-license:
@go get go.uber.org/tools/update-license
@update-license \
$(shell go list -json $(PACKAGES) | \
jq -r '.Dir + "/" + (.GoFiles | .[])')
##############################################################################
.PHONY: install_ci
install_ci: install
go get github.com/wadey/gocovmerge
go get github.com/mattn/goveralls
go get golang.org/x/tools/cmd/cover
.PHONY: test_ci
test_ci: install_ci
./scripts/cover.sh $(shell go list $(PACKAGES))

23
vendor/go.uber.org/multierr/README.md generated vendored Normal file
View File

@ -0,0 +1,23 @@
# multierr [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
`multierr` allows combining one or more Go `error`s together.
## Installation
go get -u go.uber.org/multierr
## Status
Stable: No breaking changes will be made before 2.0.
-------------------------------------------------------------------------------
Released under the [MIT License].
[MIT License]: LICENSE.txt
[doc-img]: https://godoc.org/go.uber.org/multierr?status.svg
[doc]: https://godoc.org/go.uber.org/multierr
[ci-img]: https://travis-ci.com/uber-go/multierr.svg?branch=master
[cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg
[ci]: https://travis-ci.com/uber-go/multierr
[cov]: https://codecov.io/gh/uber-go/multierr

399
vendor/go.uber.org/multierr/error.go generated vendored Normal file
View File

@ -0,0 +1,399 @@
// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package multierr allows combining one or more errors together.
//
// Overview
//
// Errors can be combined with the use of the Combine function.
//
// multierr.Combine(
// reader.Close(),
// writer.Close(),
// conn.Close(),
// )
//
// If only two errors are being combined, the Append function may be used
// instead.
//
// err = multierr.Append(reader.Close(), writer.Close())
//
// This makes it possible to record resource cleanup failures from deferred
// blocks with the help of named return values.
//
// func sendRequest(req Request) (err error) {
// conn, err := openConnection()
// if err != nil {
// return err
// }
// defer func() {
// err = multierr.Append(err, conn.Close())
// }()
// // ...
// }
//
// The underlying list of errors for a returned error object may be retrieved
// with the Errors function.
//
// errors := multierr.Errors(err)
// if len(errors) > 0 {
// fmt.Println("The following errors occurred:")
// }
//
// Advanced Usage
//
// Errors returned by Combine and Append MAY implement the following
// interface.
//
// type errorGroup interface {
// // Returns a slice containing the underlying list of errors.
// //
// // This slice MUST NOT be modified by the caller.
// Errors() []error
// }
//
// Note that if you need access to list of errors behind a multierr error, you
// should prefer using the Errors function. That said, if you need cheap
// read-only access to the underlying errors slice, you can attempt to cast
// the error to this interface. You MUST handle the failure case gracefully
// because errors returned by Combine and Append are not guaranteed to
// implement this interface.
//
// var errors []error
// group, ok := err.(errorGroup)
// if ok {
// errors = group.Errors()
// } else {
// errors = []error{err}
// }
package multierr // import "go.uber.org/multierr"
import (
"bytes"
"fmt"
"io"
"strings"
"sync"
"go.uber.org/atomic"
)
var (
// Separator for single-line error messages.
_singlelineSeparator = []byte("; ")
// Prefix for multi-line messages
_multilinePrefix = []byte("the following errors occurred:")
// Prefix for the first and following lines of an item in a list of
// multi-line error messages.
//
// For example, if a single item is:
//
// foo
// bar
//
// It will become,
//
// - foo
// bar
_multilineSeparator = []byte("\n - ")
_multilineIndent = []byte(" ")
)
// _bufferPool is a pool of bytes.Buffers.
var _bufferPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
type errorGroup interface {
Errors() []error
}
// Errors returns a slice containing zero or more errors that the supplied
// error is composed of. If the error is nil, the returned slice is empty.
//
// err := multierr.Append(r.Close(), w.Close())
// errors := multierr.Errors(err)
//
// If the error is not composed of other errors, the returned slice contains
// just the error that was passed in.
//
// Callers of this function are free to modify the returned slice.
func Errors(err error) []error {
if err == nil {
return nil
}
// Note that we're casting to multiError, not errorGroup. Our contract is
// that returned errors MAY implement errorGroup. Errors, however, only
// has special behavior for multierr-specific error objects.
//
// This behavior can be expanded in the future but I think it's prudent to
// start with as little as possible in terms of contract and possibility
// of misuse.
eg, ok := err.(*multiError)
if !ok {
return []error{err}
}
errors := eg.Errors()
result := make([]error, len(errors))
copy(result, errors)
return result
}
// multiError is an error that holds one or more errors.
//
// An instance of this is guaranteed to be non-empty and flattened. That is,
// none of the errors inside multiError are other multiErrors.
//
// multiError formats to a semi-colon delimited list of error messages with
// %v and with a more readable multi-line format with %+v.
type multiError struct {
copyNeeded atomic.Bool
errors []error
}
var _ errorGroup = (*multiError)(nil)
// Errors returns the list of underlying errors.
//
// This slice MUST NOT be modified.
func (merr *multiError) Errors() []error {
if merr == nil {
return nil
}
return merr.errors
}
func (merr *multiError) Error() string {
if merr == nil {
return ""
}
buff := _bufferPool.Get().(*bytes.Buffer)
buff.Reset()
merr.writeSingleline(buff)
result := buff.String()
_bufferPool.Put(buff)
return result
}
func (merr *multiError) Format(f fmt.State, c rune) {
if c == 'v' && f.Flag('+') {
merr.writeMultiline(f)
} else {
merr.writeSingleline(f)
}
}
func (merr *multiError) writeSingleline(w io.Writer) {
first := true
for _, item := range merr.errors {
if first {
first = false
} else {
w.Write(_singlelineSeparator)
}
io.WriteString(w, item.Error())
}
}
func (merr *multiError) writeMultiline(w io.Writer) {
w.Write(_multilinePrefix)
for _, item := range merr.errors {
w.Write(_multilineSeparator)
writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item))
}
}
// Writes s to the writer with the given prefix added before each line after
// the first.
func writePrefixLine(w io.Writer, prefix []byte, s string) {
first := true
for len(s) > 0 {
if first {
first = false
} else {
w.Write(prefix)
}
idx := strings.IndexByte(s, '\n')
if idx < 0 {
idx = len(s) - 1
}
io.WriteString(w, s[:idx+1])
s = s[idx+1:]
}
}
type inspectResult struct {
// Number of top-level non-nil errors
Count int
// Total number of errors including multiErrors
Capacity int
// Index of the first non-nil error in the list. Value is meaningless if
// Count is zero.
FirstErrorIdx int
// Whether the list contains at least one multiError
ContainsMultiError bool
}
// Inspects the given slice of errors so that we can efficiently allocate
// space for it.
func inspect(errors []error) (res inspectResult) {
first := true
for i, err := range errors {
if err == nil {
continue
}
res.Count++
if first {
first = false
res.FirstErrorIdx = i
}
if merr, ok := err.(*multiError); ok {
res.Capacity += len(merr.errors)
res.ContainsMultiError = true
} else {
res.Capacity++
}
}
return
}
// fromSlice converts the given list of errors into a single error.
func fromSlice(errors []error) error {
res := inspect(errors)
switch res.Count {
case 0:
return nil
case 1:
// only one non-nil entry
return errors[res.FirstErrorIdx]
case len(errors):
if !res.ContainsMultiError {
// already flat
return &multiError{errors: errors}
}
}
nonNilErrs := make([]error, 0, res.Capacity)
for _, err := range errors[res.FirstErrorIdx:] {
if err == nil {
continue
}
if nested, ok := err.(*multiError); ok {
nonNilErrs = append(nonNilErrs, nested.errors...)
} else {
nonNilErrs = append(nonNilErrs, err)
}
}
return &multiError{errors: nonNilErrs}
}
// Combine combines the passed errors into a single error.
//
// If zero arguments were passed or if all items are nil, a nil error is
// returned.
//
// Combine(nil, nil) // == nil
//
// If only a single error was passed, it is returned as-is.
//
// Combine(err) // == err
//
// Combine skips over nil arguments so this function may be used to combine
// together errors from operations that fail independently of each other.
//
// multierr.Combine(
// reader.Close(),
// writer.Close(),
// pipe.Close(),
// )
//
// If any of the passed errors is a multierr error, it will be flattened along
// with the other errors.
//
// multierr.Combine(multierr.Combine(err1, err2), err3)
// // is the same as
// multierr.Combine(err1, err2, err3)
//
// The returned error formats into a readable multi-line error message if
// formatted with %+v.
//
// fmt.Sprintf("%+v", multierr.Combine(err1, err2))
func Combine(errors ...error) error {
return fromSlice(errors)
}
// Append appends the given errors together. Either value may be nil.
//
// This function is a specialization of Combine for the common case where
// there are only two errors.
//
// err = multierr.Append(reader.Close(), writer.Close())
//
// The following pattern may also be used to record failure of deferred
// operations without losing information about the original error.
//
// func doSomething(..) (err error) {
// f := acquireResource()
// defer func() {
// err = multierr.Append(err, f.Close())
// }()
func Append(left error, right error) error {
switch {
case left == nil:
return right
case right == nil:
return left
}
if _, ok := right.(*multiError); !ok {
if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) {
// Common case where the error on the left is constantly being
// appended to.
errs := append(l.errors, right)
return &multiError{errors: errs}
} else if !ok {
// Both errors are single errors.
return &multiError{errors: []error{left, right}}
}
}
// Either right or both, left and right, are multiErrors. Rely on usual
// expensive logic.
errors := [2]error{left, right}
return fromSlice(errors[0:])
}

19
vendor/go.uber.org/multierr/glide.lock generated vendored Normal file
View File

@ -0,0 +1,19 @@
hash: b53b5e9a84b9cb3cc4b2d0499e23da2feca1eec318ce9bb717ecf35bf24bf221
updated: 2017-04-10T13:34:45.671678062-07:00
imports:
- name: go.uber.org/atomic
version: 3b8db5e93c4c02efbc313e17b2e796b0914a01fb
testImports:
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
- spew
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
subpackages:
- assert
- require

8
vendor/go.uber.org/multierr/glide.yaml generated vendored Normal file
View File

@ -0,0 +1,8 @@
package: go.uber.org/multierr
import:
- package: go.uber.org/atomic
version: ^1
testImport:
- package: github.com/stretchr/testify
subpackages:
- assert

52
vendor/go.uber.org/multierr/go113.go generated vendored Normal file
View File

@ -0,0 +1,52 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// +build go1.13
package multierr
import "errors"
// As attempts to find the first error in the error list that matches the type
// of the value that target points to.
//
// This function allows errors.As to traverse the values stored on the
// multierr error.
func (merr *multiError) As(target interface{}) bool {
for _, err := range merr.Errors() {
if errors.As(err, target) {
return true
}
}
return false
}
// Is attempts to match the provided error against errors in the error list.
//
// This function allows errors.Is to traverse the values stored on the
// multierr error.
func (merr *multiError) Is(target error) bool {
for _, err := range merr.Errors() {
if errors.Is(err, target) {
return true
}
}
return false
}

17
vendor/go.uber.org/zap/.codecov.yml generated vendored Normal file
View File

@ -0,0 +1,17 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 95% # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure
ignore:
- internal/readme/readme.go

28
vendor/go.uber.org/zap/.gitignore generated vendored Normal file
View File

@ -0,0 +1,28 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
vendor
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*.pprof
*.out
*.log

108
vendor/go.uber.org/zap/.readme.tmpl generated vendored Normal file
View File

@ -0,0 +1,108 @@
# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Blazing fast, structured, leveled logging in Go.
## Installation
`go get -u go.uber.org/zap`
Note that zap only supports the two most recent minor versions of Go.
## Quick Start
In contexts where performance is nice, but not critical, use the
`SugaredLogger`. It's 4-10x faster than other structured logging
packages and includes both structured and `printf`-style APIs.
```go
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
```
When performance and type safety are critical, use the `Logger`. It's even
faster than the `SugaredLogger` and allocates far less, but it only supports
structured logging.
```go
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
```
See the [documentation][doc] and [FAQ](FAQ.md) for more details.
## Performance
For applications that log in the hot path, reflection-based serialization and
string formatting are prohibitively expensive &mdash; they're CPU-intensive
and make many small allocations. Put differently, using `encoding/json` and
`fmt.Fprintf` to log tons of `interface{}`s makes your application slow.
Zap takes a different approach. It includes a reflection-free, zero-allocation
JSON encoder, and the base `Logger` strives to avoid serialization overhead
and allocations wherever possible. By building the high-level `SugaredLogger`
on that foundation, zap lets users *choose* when they need to count every
allocation and when they'd prefer a more familiar, loosely typed API.
As measured by its own [benchmarking suite][], not only is zap more performant
than comparable structured logging packages &mdash; it's also faster than the
standard library. Like all benchmarks, take these with a grain of salt.<sup
id="anchor-versions">[1](#footnote-versions)</sup>
Log a message and 10 fields:
{{.BenchmarkAddingFields}}
Log a message with a logger that already has 10 fields of context:
{{.BenchmarkAccumulatedContext}}
Log a static string, without any context or `printf`-style templating:
{{.BenchmarkWithoutFields}}
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
zap to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors &mdash;
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on
issues and pull requests, but you can also report any negative conduct to
[email protected]. That email list is a private, safe space; even the zap
maintainers don't have access, so don't hesitate to hold us to a high
standard.
<hr>
Released under the [MIT License](LICENSE.txt).
<sup id="footnote-versions">1</sup> In particular, keep in mind that we may be
benchmarking against slightly older versions of other packages. Versions are
pinned in zap's [glide.lock][] file. [↩](#anchor-versions)
[doc-img]: https://godoc.org/go.uber.org/zap?status.svg
[doc]: https://godoc.org/go.uber.org/zap
[ci-img]: https://travis-ci.org/uber-go/zap.svg?branch=master
[ci]: https://travis-ci.org/uber-go/zap
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/zap
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
[glide.lock]: https://github.com/uber-go/zap/blob/master/glide.lock

21
vendor/go.uber.org/zap/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,21 @@
language: go
sudo: false
go:
- 1.11.x
- 1.12.x
go_import_path: go.uber.org/zap
env:
global:
- TEST_TIMEOUT_SCALE=10
cache:
directories:
- vendor
install:
- make dependencies
script:
- make lint
- make test
- make bench
after_success:
- make cover
- bash <(curl -s https://codecov.io/bash)

327
vendor/go.uber.org/zap/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,327 @@
# Changelog
## 1.10.0 (29 Apr 2019)
Bugfixes:
* [#657][]: Fix `MapObjectEncoder.AppendByteString` not adding value as a
string.
* [#706][]: Fix incorrect call depth to determine caller in Go 1.12.
Enhancements:
* [#610][]: Add `zaptest.WrapOptions` to wrap `zap.Option` for creating test
loggers.
* [#675][]: Don't panic when encoding a String field.
* [#704][]: Disable HTML escaping for JSON objects encoded using the
reflect-based encoder.
Thanks to @iaroslav-ciupin, @lelenanam, @joa, @NWilson for their contributions
to this release.
## v1.9.1 (06 Aug 2018)
Bugfixes:
* [#614][]: MapObjectEncoder should not ignore empty slices.
## v1.9.0 (19 Jul 2018)
Enhancements:
* [#602][]: Reduce number of allocations when logging with reflection.
* [#572][], [#606][]: Expose a registry for third-party logging sinks.
Thanks to @nfarah86, @AlekSi, @JeanMertz, @philippgille, @etsangsplk, and
@dimroc for their contributions to this release.
## v1.8.0 (13 Apr 2018)
Enhancements:
* [#508][]: Make log level configurable when redirecting the standard
library's logger.
* [#518][]: Add a logger that writes to a `*testing.TB`.
* [#577][]: Add a top-level alias for `zapcore.Field` to clean up GoDoc.
Bugfixes:
* [#574][]: Add a missing import comment to `go.uber.org/zap/buffer`.
Thanks to @DiSiqueira and @djui for their contributions to this release.
## v1.7.1 (25 Sep 2017)
Bugfixes:
* [#504][]: Store strings when using AddByteString with the map encoder.
## v1.7.0 (21 Sep 2017)
Enhancements:
* [#487][]: Add `NewStdLogAt`, which extends `NewStdLog` by allowing the user
to specify the level of the logged messages.
## v1.6.0 (30 Aug 2017)
Enhancements:
* [#491][]: Omit zap stack frames from stacktraces.
* [#490][]: Add a `ContextMap` method to observer logs for simpler
field validation in tests.
## v1.5.0 (22 Jul 2017)
Enhancements:
* [#460][] and [#470][]: Support errors produced by `go.uber.org/multierr`.
* [#465][]: Support user-supplied encoders for logger names.
Bugfixes:
* [#477][]: Fix a bug that incorrectly truncated deep stacktraces.
Thanks to @richard-tunein and @pavius for their contributions to this release.
## v1.4.1 (08 Jun 2017)
This release fixes two bugs.
Bugfixes:
* [#435][]: Support a variety of case conventions when unmarshaling levels.
* [#444][]: Fix a panic in the observer.
## v1.4.0 (12 May 2017)
This release adds a few small features and is fully backward-compatible.
Enhancements:
* [#424][]: Add a `LineEnding` field to `EncoderConfig`, allowing users to
override the Unix-style default.
* [#425][]: Preserve time zones when logging times.
* [#431][]: Make `zap.AtomicLevel` implement `fmt.Stringer`, which makes a
variety of operations a bit simpler.
## v1.3.0 (25 Apr 2017)
This release adds an enhancement to zap's testing helpers as well as the
ability to marshal an AtomicLevel. It is fully backward-compatible.
Enhancements:
* [#415][]: Add a substring-filtering helper to zap's observer. This is
particularly useful when testing the `SugaredLogger`.
* [#416][]: Make `AtomicLevel` implement `encoding.TextMarshaler`.
## v1.2.0 (13 Apr 2017)
This release adds a gRPC compatibility wrapper. It is fully backward-compatible.
Enhancements:
* [#402][]: Add a `zapgrpc` package that wraps zap's Logger and implements
`grpclog.Logger`.
## v1.1.0 (31 Mar 2017)
This release fixes two bugs and adds some enhancements to zap's testing helpers.
It is fully backward-compatible.
Bugfixes:
* [#385][]: Fix caller path trimming on Windows.
* [#396][]: Fix a panic when attempting to use non-existent directories with
zap's configuration struct.
Enhancements:
* [#386][]: Add filtering helpers to zaptest's observing logger.
Thanks to @moitias for contributing to this release.
## v1.0.0 (14 Mar 2017)
This is zap's first stable release. All exported APIs are now final, and no
further breaking changes will be made in the 1.x release series. Anyone using a
semver-aware dependency manager should now pin to `^1`.
Breaking changes:
* [#366][]: Add byte-oriented APIs to encoders to log UTF-8 encoded text without
casting from `[]byte` to `string`.
* [#364][]: To support buffering outputs, add `Sync` methods to `zapcore.Core`,
`zap.Logger`, and `zap.SugaredLogger`.
* [#371][]: Rename the `testutils` package to `zaptest`, which is less likely to
clash with other testing helpers.
Bugfixes:
* [#362][]: Make the ISO8601 time formatters fixed-width, which is friendlier
for tab-separated console output.
* [#369][]: Remove the automatic locks in `zapcore.NewCore`, which allows zap to
work with concurrency-safe `WriteSyncer` implementations.
* [#347][]: Stop reporting errors when trying to `fsync` standard out on Linux
systems.
* [#373][]: Report the correct caller from zap's standard library
interoperability wrappers.
Enhancements:
* [#348][]: Add a registry allowing third-party encodings to work with zap's
built-in `Config`.
* [#327][]: Make the representation of logger callers configurable (like times,
levels, and durations).
* [#376][]: Allow third-party encoders to use their own buffer pools, which
removes the last performance advantage that zap's encoders have over plugins.
* [#346][]: Add `CombineWriteSyncers`, a convenience function to tee multiple
`WriteSyncer`s and lock the result.
* [#365][]: Make zap's stacktraces compatible with mid-stack inlining (coming in
Go 1.9).
* [#372][]: Export zap's observing logger as `zaptest/observer`. This makes it
easier for particularly punctilious users to unit test their application's
logging.
Thanks to @suyash, @htrendev, @flisky, @Ulexus, and @skipor for their
contributions to this release.
## v1.0.0-rc.3 (7 Mar 2017)
This is the third release candidate for zap's stable release. There are no
breaking changes.
Bugfixes:
* [#339][]: Byte slices passed to `zap.Any` are now correctly treated as binary blobs
rather than `[]uint8`.
Enhancements:
* [#307][]: Users can opt into colored output for log levels.
* [#353][]: In addition to hijacking the output of the standard library's
package-global logging functions, users can now construct a zap-backed
`log.Logger` instance.
* [#311][]: Frames from common runtime functions and some of zap's internal
machinery are now omitted from stacktraces.
Thanks to @ansel1 and @suyash for their contributions to this release.
## v1.0.0-rc.2 (21 Feb 2017)
This is the second release candidate for zap's stable release. It includes two
breaking changes.
Breaking changes:
* [#316][]: Zap's global loggers are now fully concurrency-safe
(previously, users had to ensure that `ReplaceGlobals` was called before the
loggers were in use). However, they must now be accessed via the `L()` and
`S()` functions. Users can update their projects with
```
gofmt -r "zap.L -> zap.L()" -w .
gofmt -r "zap.S -> zap.S()" -w .
```
* [#309][] and [#317][]: RC1 was mistakenly shipped with invalid
JSON and YAML struct tags on all config structs. This release fixes the tags
and adds static analysis to prevent similar bugs in the future.
Bugfixes:
* [#321][]: Redirecting the standard library's `log` output now
correctly reports the logger's caller.
Enhancements:
* [#325][] and [#333][]: Zap now transparently supports non-standard, rich
errors like those produced by `github.com/pkg/errors`.
* [#326][]: Though `New(nil)` continues to return a no-op logger, `NewNop()` is
now preferred. Users can update their projects with `gofmt -r 'zap.New(nil) ->
zap.NewNop()' -w .`.
* [#300][]: Incorrectly importing zap as `github.com/uber-go/zap` now returns a
more informative error.
Thanks to @skipor and @chapsuk for their contributions to this release.
## v1.0.0-rc.1 (14 Feb 2017)
This is the first release candidate for zap's stable release. There are multiple
breaking changes and improvements from the pre-release version. Most notably:
* **Zap's import path is now "go.uber.org/zap"** &mdash; all users will
need to update their code.
* User-facing types and functions remain in the `zap` package. Code relevant
largely to extension authors is now in the `zapcore` package.
* The `zapcore.Core` type makes it easy for third-party packages to use zap's
internals but provide a different user-facing API.
* `Logger` is now a concrete type instead of an interface.
* A less verbose (though slower) logging API is included by default.
* Package-global loggers `L` and `S` are included.
* A human-friendly console encoder is included.
* A declarative config struct allows common logger configurations to be managed
as configuration instead of code.
* Sampling is more accurate, and doesn't depend on the standard library's shared
timer heap.
## v0.1.0-beta.1 (6 Feb 2017)
This is a minor version, tagged to allow users to pin to the pre-1.0 APIs and
upgrade at their leisure. Since this is the first tagged release, there are no
backward compatibility concerns and all functionality is new.
Early zap adopters should pin to the 0.1.x minor version until they're ready to
upgrade to the upcoming stable release.
[#316]: https://github.com/uber-go/zap/pull/316
[#309]: https://github.com/uber-go/zap/pull/309
[#317]: https://github.com/uber-go/zap/pull/317
[#321]: https://github.com/uber-go/zap/pull/321
[#325]: https://github.com/uber-go/zap/pull/325
[#333]: https://github.com/uber-go/zap/pull/333
[#326]: https://github.com/uber-go/zap/pull/326
[#300]: https://github.com/uber-go/zap/pull/300
[#339]: https://github.com/uber-go/zap/pull/339
[#307]: https://github.com/uber-go/zap/pull/307
[#353]: https://github.com/uber-go/zap/pull/353
[#311]: https://github.com/uber-go/zap/pull/311
[#366]: https://github.com/uber-go/zap/pull/366
[#364]: https://github.com/uber-go/zap/pull/364
[#371]: https://github.com/uber-go/zap/pull/371
[#362]: https://github.com/uber-go/zap/pull/362
[#369]: https://github.com/uber-go/zap/pull/369
[#347]: https://github.com/uber-go/zap/pull/347
[#373]: https://github.com/uber-go/zap/pull/373
[#348]: https://github.com/uber-go/zap/pull/348
[#327]: https://github.com/uber-go/zap/pull/327
[#376]: https://github.com/uber-go/zap/pull/376
[#346]: https://github.com/uber-go/zap/pull/346
[#365]: https://github.com/uber-go/zap/pull/365
[#372]: https://github.com/uber-go/zap/pull/372
[#385]: https://github.com/uber-go/zap/pull/385
[#396]: https://github.com/uber-go/zap/pull/396
[#386]: https://github.com/uber-go/zap/pull/386
[#402]: https://github.com/uber-go/zap/pull/402
[#415]: https://github.com/uber-go/zap/pull/415
[#416]: https://github.com/uber-go/zap/pull/416
[#424]: https://github.com/uber-go/zap/pull/424
[#425]: https://github.com/uber-go/zap/pull/425
[#431]: https://github.com/uber-go/zap/pull/431
[#435]: https://github.com/uber-go/zap/pull/435
[#444]: https://github.com/uber-go/zap/pull/444
[#477]: https://github.com/uber-go/zap/pull/477
[#465]: https://github.com/uber-go/zap/pull/465
[#460]: https://github.com/uber-go/zap/pull/460
[#470]: https://github.com/uber-go/zap/pull/470
[#487]: https://github.com/uber-go/zap/pull/487
[#490]: https://github.com/uber-go/zap/pull/490
[#491]: https://github.com/uber-go/zap/pull/491
[#504]: https://github.com/uber-go/zap/pull/504
[#508]: https://github.com/uber-go/zap/pull/508
[#518]: https://github.com/uber-go/zap/pull/518
[#577]: https://github.com/uber-go/zap/pull/577
[#574]: https://github.com/uber-go/zap/pull/574
[#602]: https://github.com/uber-go/zap/pull/602
[#572]: https://github.com/uber-go/zap/pull/572
[#606]: https://github.com/uber-go/zap/pull/606
[#614]: https://github.com/uber-go/zap/pull/614
[#657]: https://github.com/uber-go/zap/pull/657
[#706]: https://github.com/uber-go/zap/pull/706
[#610]: https://github.com/uber-go/zap/pull/610
[#675]: https://github.com/uber-go/zap/pull/675
[#704]: https://github.com/uber-go/zap/pull/704

75
vendor/go.uber.org/zap/CODE_OF_CONDUCT.md generated vendored Normal file
View File

@ -0,0 +1,75 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age,
body size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual
identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an
appointed representative at an online or offline event. Representation of a
project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [email protected]. The project
team will review and investigate all complaints, and will respond in a way
that it deems appropriate to the circumstances. The project team is obligated
to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
[http://contributor-covenant.org/version/1/4][version].
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

81
vendor/go.uber.org/zap/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,81 @@
# Contributing
We'd love your help making zap the very best structured logging library in Go!
If you'd like to add new exported APIs, please [open an issue][open-issue]
describing your proposal &mdash; discussing API changes ahead of time makes
pull request review much smoother. In your issue, pull request, and any other
communications, please remember to treat your fellow contributors with
respect! We take our [code of conduct](CODE_OF_CONDUCT.md) seriously.
Note that you'll need to sign [Uber's Contributor License Agreement][cla]
before we can accept any of your contributions. If necessary, a bot will remind
you to accept the CLA when you open your pull request.
## Setup
[Fork][fork], then clone the repository:
```
mkdir -p $GOPATH/src/go.uber.org
cd $GOPATH/src/go.uber.org
git clone [email protected]:your_github_username/zap.git
cd zap
git remote add upstream https://github.com/uber-go/zap.git
git fetch upstream
```
Install zap's dependencies:
```
make dependencies
```
Make sure that the tests and the linters pass:
```
make test
make lint
```
If you're not using the minor version of Go specified in the Makefile's
`LINTABLE_MINOR_VERSIONS` variable, `make lint` doesn't do anything. This is
fine, but it means that you'll only discover lint failures after you open your
pull request.
## Making Changes
Start by creating a new branch for your changes:
```
cd $GOPATH/src/go.uber.org/zap
git checkout master
git fetch upstream
git rebase upstream/master
git checkout -b cool_new_feature
```
Make your changes, then ensure that `make lint` and `make test` still pass. If
you're satisfied with your changes, push them to your fork.
```
git push origin cool_new_feature
```
Then use the GitHub UI to open a pull request.
At this point, you're waiting on us to review your changes. We *try* to respond
to issues and pull requests within a few business days, and we may suggest some
improvements or alternatives. Once your changes are approved, one of the
project maintainers will merge them.
We're much more likely to approve your changes if you:
* Add tests for new functionality.
* Write a [good commit message][commit-message].
* Maintain backward compatibility.
[fork]: https://github.com/uber-go/zap/fork
[open-issue]: https://github.com/uber-go/zap/issues/new
[cla]: https://cla-assistant.io/uber-go/zap
[commit-message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html

155
vendor/go.uber.org/zap/FAQ.md generated vendored Normal file
View File

@ -0,0 +1,155 @@
# Frequently Asked Questions
## Design
### Why spend so much effort on logger performance?
Of course, most applications won't notice the impact of a slow logger: they
already take tens or hundreds of milliseconds for each operation, so an extra
millisecond doesn't matter.
On the other hand, why *not* make structured logging fast? The `SugaredLogger`
isn't any harder to use than other logging packages, and the `Logger` makes
structured logging possible in performance-sensitive contexts. Across a fleet
of Go microservices, making each application even slightly more efficient adds
up quickly.
### Why aren't `Logger` and `SugaredLogger` interfaces?
Unlike the familiar `io.Writer` and `http.Handler`, `Logger` and
`SugaredLogger` interfaces would include *many* methods. As [Rob Pike points
out][go-proverbs], "The bigger the interface, the weaker the abstraction."
Interfaces are also rigid &mdash; *any* change requires releasing a new major
version, since it breaks all third-party implementations.
Making the `Logger` and `SugaredLogger` concrete types doesn't sacrifice much
abstraction, and it lets us add methods without introducing breaking changes.
Your applications should define and depend upon an interface that includes
just the methods you use.
### Why sample application logs?
Applications often experience runs of errors, either because of a bug or
because of a misbehaving user. Logging errors is usually a good idea, but it
can easily make this bad situation worse: not only is your application coping
with a flood of errors, it's also spending extra CPU cycles and I/O logging
those errors. Since writes are typically serialized, logging limits throughput
when you need it most.
Sampling fixes this problem by dropping repetitive log entries. Under normal
conditions, your application writes out every entry. When similar entries are
logged hundreds or thousands of times each second, though, zap begins dropping
duplicates to preserve throughput.
### Why do the structured logging APIs take a message in addition to fields?
Subjectively, we find it helpful to accompany structured context with a brief
description. This isn't critical during development, but it makes debugging
and operating unfamiliar systems much easier.
More concretely, zap's sampling algorithm uses the message to identify
duplicate entries. In our experience, this is a practical middle ground
between random sampling (which often drops the exact entry that you need while
debugging) and hashing the complete entry (which is prohibitively expensive).
### Why include package-global loggers?
Since so many other logging packages include a global logger, many
applications aren't designed to accept loggers as explicit parameters.
Changing function signatures is often a breaking change, so zap includes
global loggers to simplify migration.
Avoid them where possible.
### Why include dedicated Panic and Fatal log levels?
In general, application code should handle errors gracefully instead of using
`panic` or `os.Exit`. However, every rule has exceptions, and it's common to
crash when an error is truly unrecoverable. To avoid losing any information
&mdash; especially the reason for the crash &mdash; the logger must flush any
buffered entries before the process exits.
Zap makes this easy by offering `Panic` and `Fatal` logging methods that
automatically flush before exiting. Of course, this doesn't guarantee that
logs will never be lost, but it eliminates a common error.
See the discussion in uber-go/zap#207 for more details.
### What's `DPanic`?
`DPanic` stands for "panic in development." In development, it logs at
`PanicLevel`; otherwise, it logs at `ErrorLevel`. `DPanic` makes it easier to
catch errors that are theoretically possible, but shouldn't actually happen,
*without* crashing in production.
If you've ever written code like this, you need `DPanic`:
```go
if err != nil {
panic(fmt.Sprintf("shouldn't ever get here: %v", err))
}
```
## Installation
### What does the error `expects import "go.uber.org/zap"` mean?
Either zap was installed incorrectly or you're referencing the wrong package
name in your code.
Zap's source code happens to be hosted on GitHub, but the [import
path][import-path] is `go.uber.org/zap`. This gives us, the project
maintainers, the freedom to move the source code if necessary. However, it
means that you need to take a little care when installing and using the
package.
If you follow two simple rules, everything should work: install zap with `go
get -u go.uber.org/zap`, and always import it in your code with `import
"go.uber.org/zap"`. Your code shouldn't contain *any* references to
`github.com/uber-go/zap`.
## Usage
### Does zap support log rotation?
Zap doesn't natively support rotating log files, since we prefer to leave this
to an external program like `logrotate`.
However, it's easy to integrate a log rotation package like
[`gopkg.in/natefinch/lumberjack.v2`][lumberjack] as a `zapcore.WriteSyncer`.
```go
// lumberjack.Logger is already safe for concurrent use, so we don't need to
// lock it.
w := zapcore.AddSync(&lumberjack.Logger{
Filename: "/var/log/myapp/foo.log",
MaxSize: 500, // megabytes
MaxBackups: 3,
MaxAge: 28, // days
})
core := zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
w,
zap.InfoLevel,
)
logger := zap.New(core)
```
## Extensions
We'd love to support every logging need within zap itself, but we're only
familiar with a handful of log ingestion systems, flag-parsing packages, and
the like. Rather than merging code that we can't effectively debug and
support, we'd rather grow an ecosystem of zap extensions.
We're aware of the following extensions, but haven't used them ourselves:
| Package | Integration |
| --- | --- |
| `github.com/tchap/zapext` | Sentry, syslog |
| `github.com/fgrosse/zaptest` | Ginkgo |
| `github.com/blendle/zapdriver` | Stackdriver |
[go-proverbs]: https://go-proverbs.github.io/
[import-path]: https://golang.org/cmd/go/#hdr-Remote_import_paths
[lumberjack]: https://godoc.org/gopkg.in/natefinch/lumberjack.v2

19
vendor/go.uber.org/zap/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2016-2017 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

76
vendor/go.uber.org/zap/Makefile generated vendored Normal file
View File

@ -0,0 +1,76 @@
export GO15VENDOREXPERIMENT=1
BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem
PKGS ?= $(shell glide novendor)
# Many Go tools take file globs or directories as arguments instead of packages.
PKG_FILES ?= *.go zapcore benchmarks buffer zapgrpc zaptest zaptest/observer internal/bufferpool internal/exit internal/color internal/ztest
# The linting tools evolve with each Go version, so run them only on the latest
# stable release.
GO_VERSION := $(shell go version | cut -d " " -f 3)
GO_MINOR_VERSION := $(word 2,$(subst ., ,$(GO_VERSION)))
LINTABLE_MINOR_VERSIONS := 12
ifneq ($(filter $(LINTABLE_MINOR_VERSIONS),$(GO_MINOR_VERSION)),)
SHOULD_LINT := true
endif
.PHONY: all
all: lint test
.PHONY: dependencies
dependencies:
@echo "Installing Glide and locked dependencies..."
glide --version || go get -u -f github.com/Masterminds/glide
glide install
@echo "Installing test dependencies..."
go install ./vendor/github.com/axw/gocov/gocov
go install ./vendor/github.com/mattn/goveralls
ifdef SHOULD_LINT
@echo "Installing golint..."
go install ./vendor/github.com/golang/lint/golint
else
@echo "Not installing golint, since we don't expect to lint on" $(GO_VERSION)
endif
# Disable printf-like invocation checking due to testify.assert.Error()
VET_RULES := -printf=false
.PHONY: lint
lint:
ifdef SHOULD_LINT
@rm -rf lint.log
@echo "Checking formatting..."
@gofmt -d -s $(PKG_FILES) 2>&1 | tee lint.log
@echo "Installing test dependencies for vet..."
@go test -i $(PKGS)
@echo "Checking vet..."
@go vet $(VET_RULES) $(PKGS) 2>&1 | tee -a lint.log
@echo "Checking lint..."
@$(foreach dir,$(PKGS),golint $(dir) 2>&1 | tee -a lint.log;)
@echo "Checking for unresolved FIXMEs..."
@git grep -i fixme | grep -v -e vendor -e Makefile | tee -a lint.log
@echo "Checking for license headers..."
@./check_license.sh | tee -a lint.log
@[ ! -s lint.log ]
else
@echo "Skipping linters on" $(GO_VERSION)
endif
.PHONY: test
test:
go test -race $(PKGS)
.PHONY: cover
cover:
./scripts/cover.sh $(PKGS)
.PHONY: bench
BENCH ?= .
bench:
@$(foreach pkg,$(PKGS),go test -bench=$(BENCH) -run="^$$" $(BENCH_FLAGS) $(pkg);)
.PHONY: updatereadme
updatereadme:
rm -f README.md
cat .readme.tmpl | go run internal/readme/readme.go > README.md

136
vendor/go.uber.org/zap/README.md generated vendored Normal file
View File

@ -0,0 +1,136 @@
# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Blazing fast, structured, leveled logging in Go.
## Installation
`go get -u go.uber.org/zap`
Note that zap only supports the two most recent minor versions of Go.
## Quick Start
In contexts where performance is nice, but not critical, use the
`SugaredLogger`. It's 4-10x faster than other structured logging
packages and includes both structured and `printf`-style APIs.
```go
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
```
When performance and type safety are critical, use the `Logger`. It's even
faster than the `SugaredLogger` and allocates far less, but it only supports
structured logging.
```go
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
```
See the [documentation][doc] and [FAQ](FAQ.md) for more details.
## Performance
For applications that log in the hot path, reflection-based serialization and
string formatting are prohibitively expensive &mdash; they're CPU-intensive
and make many small allocations. Put differently, using `encoding/json` and
`fmt.Fprintf` to log tons of `interface{}`s makes your application slow.
Zap takes a different approach. It includes a reflection-free, zero-allocation
JSON encoder, and the base `Logger` strives to avoid serialization overhead
and allocations wherever possible. By building the high-level `SugaredLogger`
on that foundation, zap lets users *choose* when they need to count every
allocation and when they'd prefer a more familiar, loosely typed API.
As measured by its own [benchmarking suite][], not only is zap more performant
than comparable structured logging packages &mdash; it's also faster than the
standard library. Like all benchmarks, take these with a grain of salt.<sup
id="anchor-versions">[1](#footnote-versions)</sup>
Log a message and 10 fields:
| Package | Time | Objects Allocated |
| :--- | :---: | :---: |
| :zap: zap | 3131 ns/op | 5 allocs/op |
| :zap: zap (sugared) | 4173 ns/op | 21 allocs/op |
| zerolog | 16154 ns/op | 90 allocs/op |
| lion | 16341 ns/op | 111 allocs/op |
| go-kit | 17049 ns/op | 126 allocs/op |
| logrus | 23662 ns/op | 142 allocs/op |
| log15 | 36351 ns/op | 149 allocs/op |
| apex/log | 42530 ns/op | 126 allocs/op |
Log a message with a logger that already has 10 fields of context:
| Package | Time | Objects Allocated |
| :--- | :---: | :---: |
| :zap: zap | 380 ns/op | 0 allocs/op |
| :zap: zap (sugared) | 564 ns/op | 2 allocs/op |
| zerolog | 321 ns/op | 0 allocs/op |
| lion | 7092 ns/op | 39 allocs/op |
| go-kit | 20226 ns/op | 115 allocs/op |
| logrus | 22312 ns/op | 130 allocs/op |
| log15 | 28788 ns/op | 79 allocs/op |
| apex/log | 42063 ns/op | 115 allocs/op |
Log a static string, without any context or `printf`-style templating:
| Package | Time | Objects Allocated |
| :--- | :---: | :---: |
| :zap: zap | 361 ns/op | 0 allocs/op |
| :zap: zap (sugared) | 534 ns/op | 2 allocs/op |
| zerolog | 323 ns/op | 0 allocs/op |
| standard library | 575 ns/op | 2 allocs/op |
| go-kit | 922 ns/op | 13 allocs/op |
| lion | 1413 ns/op | 10 allocs/op |
| logrus | 2291 ns/op | 27 allocs/op |
| apex/log | 3690 ns/op | 11 allocs/op |
| log15 | 5954 ns/op | 26 allocs/op |
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
zap to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors &mdash;
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on
issues and pull requests, but you can also report any negative conduct to
[email protected]. That email list is a private, safe space; even the zap
maintainers don't have access, so don't hesitate to hold us to a high
standard.
<hr>
Released under the [MIT License](LICENSE.txt).
<sup id="footnote-versions">1</sup> In particular, keep in mind that we may be
benchmarking against slightly older versions of other packages. Versions are
pinned in zap's [glide.lock][] file. [](#anchor-versions)
[doc-img]: https://godoc.org/go.uber.org/zap?status.svg
[doc]: https://godoc.org/go.uber.org/zap
[ci-img]: https://travis-ci.org/uber-go/zap.svg?branch=master
[ci]: https://travis-ci.org/uber-go/zap
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/zap
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
[glide.lock]: https://github.com/uber-go/zap/blob/master/glide.lock

320
vendor/go.uber.org/zap/array.go generated vendored Normal file
View File

@ -0,0 +1,320 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"time"
"go.uber.org/zap/zapcore"
)
// Array constructs a field with the given key and ArrayMarshaler. It provides
// a flexible, but still type-safe and efficient, way to add array-like types
// to the logging context. The struct's MarshalLogArray method is called lazily.
func Array(key string, val zapcore.ArrayMarshaler) Field {
return Field{Key: key, Type: zapcore.ArrayMarshalerType, Interface: val}
}
// Bools constructs a field that carries a slice of bools.
func Bools(key string, bs []bool) Field {
return Array(key, bools(bs))
}
// ByteStrings constructs a field that carries a slice of []byte, each of which
// must be UTF-8 encoded text.
func ByteStrings(key string, bss [][]byte) Field {
return Array(key, byteStringsArray(bss))
}
// Complex128s constructs a field that carries a slice of complex numbers.
func Complex128s(key string, nums []complex128) Field {
return Array(key, complex128s(nums))
}
// Complex64s constructs a field that carries a slice of complex numbers.
func Complex64s(key string, nums []complex64) Field {
return Array(key, complex64s(nums))
}
// Durations constructs a field that carries a slice of time.Durations.
func Durations(key string, ds []time.Duration) Field {
return Array(key, durations(ds))
}
// Float64s constructs a field that carries a slice of floats.
func Float64s(key string, nums []float64) Field {
return Array(key, float64s(nums))
}
// Float32s constructs a field that carries a slice of floats.
func Float32s(key string, nums []float32) Field {
return Array(key, float32s(nums))
}
// Ints constructs a field that carries a slice of integers.
func Ints(key string, nums []int) Field {
return Array(key, ints(nums))
}
// Int64s constructs a field that carries a slice of integers.
func Int64s(key string, nums []int64) Field {
return Array(key, int64s(nums))
}
// Int32s constructs a field that carries a slice of integers.
func Int32s(key string, nums []int32) Field {
return Array(key, int32s(nums))
}
// Int16s constructs a field that carries a slice of integers.
func Int16s(key string, nums []int16) Field {
return Array(key, int16s(nums))
}
// Int8s constructs a field that carries a slice of integers.
func Int8s(key string, nums []int8) Field {
return Array(key, int8s(nums))
}
// Strings constructs a field that carries a slice of strings.
func Strings(key string, ss []string) Field {
return Array(key, stringArray(ss))
}
// Times constructs a field that carries a slice of time.Times.
func Times(key string, ts []time.Time) Field {
return Array(key, times(ts))
}
// Uints constructs a field that carries a slice of unsigned integers.
func Uints(key string, nums []uint) Field {
return Array(key, uints(nums))
}
// Uint64s constructs a field that carries a slice of unsigned integers.
func Uint64s(key string, nums []uint64) Field {
return Array(key, uint64s(nums))
}
// Uint32s constructs a field that carries a slice of unsigned integers.
func Uint32s(key string, nums []uint32) Field {
return Array(key, uint32s(nums))
}
// Uint16s constructs a field that carries a slice of unsigned integers.
func Uint16s(key string, nums []uint16) Field {
return Array(key, uint16s(nums))
}
// Uint8s constructs a field that carries a slice of unsigned integers.
func Uint8s(key string, nums []uint8) Field {
return Array(key, uint8s(nums))
}
// Uintptrs constructs a field that carries a slice of pointer addresses.
func Uintptrs(key string, us []uintptr) Field {
return Array(key, uintptrs(us))
}
// Errors constructs a field that carries a slice of errors.
func Errors(key string, errs []error) Field {
return Array(key, errArray(errs))
}
type bools []bool
func (bs bools) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range bs {
arr.AppendBool(bs[i])
}
return nil
}
type byteStringsArray [][]byte
func (bss byteStringsArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range bss {
arr.AppendByteString(bss[i])
}
return nil
}
type complex128s []complex128
func (nums complex128s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendComplex128(nums[i])
}
return nil
}
type complex64s []complex64
func (nums complex64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendComplex64(nums[i])
}
return nil
}
type durations []time.Duration
func (ds durations) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ds {
arr.AppendDuration(ds[i])
}
return nil
}
type float64s []float64
func (nums float64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendFloat64(nums[i])
}
return nil
}
type float32s []float32
func (nums float32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendFloat32(nums[i])
}
return nil
}
type ints []int
func (nums ints) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt(nums[i])
}
return nil
}
type int64s []int64
func (nums int64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt64(nums[i])
}
return nil
}
type int32s []int32
func (nums int32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt32(nums[i])
}
return nil
}
type int16s []int16
func (nums int16s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt16(nums[i])
}
return nil
}
type int8s []int8
func (nums int8s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt8(nums[i])
}
return nil
}
type stringArray []string
func (ss stringArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ss {
arr.AppendString(ss[i])
}
return nil
}
type times []time.Time
func (ts times) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ts {
arr.AppendTime(ts[i])
}
return nil
}
type uints []uint
func (nums uints) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint(nums[i])
}
return nil
}
type uint64s []uint64
func (nums uint64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint64(nums[i])
}
return nil
}
type uint32s []uint32
func (nums uint32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint32(nums[i])
}
return nil
}
type uint16s []uint16
func (nums uint16s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint16(nums[i])
}
return nil
}
type uint8s []uint8
func (nums uint8s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint8(nums[i])
}
return nil
}
type uintptrs []uintptr
func (nums uintptrs) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUintptr(nums[i])
}
return nil
}

115
vendor/go.uber.org/zap/buffer/buffer.go generated vendored Normal file
View File

@ -0,0 +1,115 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package buffer provides a thin wrapper around a byte slice. Unlike the
// standard library's bytes.Buffer, it supports a portion of the strconv
// package's zero-allocation formatters.
package buffer // import "go.uber.org/zap/buffer"
import "strconv"
const _size = 1024 // by default, create 1 KiB buffers
// Buffer is a thin wrapper around a byte slice. It's intended to be pooled, so
// the only way to construct one is via a Pool.
type Buffer struct {
bs []byte
pool Pool
}
// AppendByte writes a single byte to the Buffer.
func (b *Buffer) AppendByte(v byte) {
b.bs = append(b.bs, v)
}
// AppendString writes a string to the Buffer.
func (b *Buffer) AppendString(s string) {
b.bs = append(b.bs, s...)
}
// AppendInt appends an integer to the underlying buffer (assuming base 10).
func (b *Buffer) AppendInt(i int64) {
b.bs = strconv.AppendInt(b.bs, i, 10)
}
// AppendUint appends an unsigned integer to the underlying buffer (assuming
// base 10).
func (b *Buffer) AppendUint(i uint64) {
b.bs = strconv.AppendUint(b.bs, i, 10)
}
// AppendBool appends a bool to the underlying buffer.
func (b *Buffer) AppendBool(v bool) {
b.bs = strconv.AppendBool(b.bs, v)
}
// AppendFloat appends a float to the underlying buffer. It doesn't quote NaN
// or +/- Inf.
func (b *Buffer) AppendFloat(f float64, bitSize int) {
b.bs = strconv.AppendFloat(b.bs, f, 'f', -1, bitSize)
}
// Len returns the length of the underlying byte slice.
func (b *Buffer) Len() int {
return len(b.bs)
}
// Cap returns the capacity of the underlying byte slice.
func (b *Buffer) Cap() int {
return cap(b.bs)
}
// Bytes returns a mutable reference to the underlying byte slice.
func (b *Buffer) Bytes() []byte {
return b.bs
}
// String returns a string copy of the underlying byte slice.
func (b *Buffer) String() string {
return string(b.bs)
}
// Reset resets the underlying byte slice. Subsequent writes re-use the slice's
// backing array.
func (b *Buffer) Reset() {
b.bs = b.bs[:0]
}
// Write implements io.Writer.
func (b *Buffer) Write(bs []byte) (int, error) {
b.bs = append(b.bs, bs...)
return len(bs), nil
}
// TrimNewline trims any final "\n" byte from the end of the buffer.
func (b *Buffer) TrimNewline() {
if i := len(b.bs) - 1; i >= 0 {
if b.bs[i] == '\n' {
b.bs = b.bs[:i]
}
}
}
// Free returns the Buffer to its Pool.
//
// Callers must not retain references to the Buffer after calling Free.
func (b *Buffer) Free() {
b.pool.put(b)
}

49
vendor/go.uber.org/zap/buffer/pool.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package buffer
import "sync"
// A Pool is a type-safe wrapper around a sync.Pool.
type Pool struct {
p *sync.Pool
}
// NewPool constructs a new Pool.
func NewPool() Pool {
return Pool{p: &sync.Pool{
New: func() interface{} {
return &Buffer{bs: make([]byte, 0, _size)}
},
}}
}
// Get retrieves a Buffer from the pool, creating one if necessary.
func (p Pool) Get() *Buffer {
buf := p.p.Get().(*Buffer)
buf.Reset()
buf.pool = p
return buf
}
func (p Pool) put(buf *Buffer) {
p.p.Put(buf)
}

17
vendor/go.uber.org/zap/check_license.sh generated vendored Normal file
View File

@ -0,0 +1,17 @@
#!/bin/bash -e
ERROR_COUNT=0
while read -r file
do
case "$(head -1 "${file}")" in
*"Copyright (c) "*" Uber Technologies, Inc.")
# everything's cool
;;
*)
echo "$file is missing license header."
(( ERROR_COUNT++ ))
;;
esac
done < <(git ls-files "*\.go")
exit $ERROR_COUNT

243
vendor/go.uber.org/zap/config.go generated vendored Normal file
View File

@ -0,0 +1,243 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"sort"
"time"
"go.uber.org/zap/zapcore"
)
// SamplingConfig sets a sampling strategy for the logger. Sampling caps the
// global CPU and I/O load that logging puts on your process while attempting
// to preserve a representative subset of your logs.
//
// Values configured here are per-second. See zapcore.NewSampler for details.
type SamplingConfig struct {
Initial int `json:"initial" yaml:"initial"`
Thereafter int `json:"thereafter" yaml:"thereafter"`
}
// Config offers a declarative way to construct a logger. It doesn't do
// anything that can't be done with New, Options, and the various
// zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to
// toggle common options.
//
// Note that Config intentionally supports only the most common options. More
// unusual logging setups (logging to network connections or message queues,
// splitting output between multiple files, etc.) are possible, but require
// direct use of the zapcore package. For sample code, see the package-level
// BasicConfiguration and AdvancedConfiguration examples.
//
// For an example showing runtime log level changes, see the documentation for
// AtomicLevel.
type Config struct {
// Level is the minimum enabled logging level. Note that this is a dynamic
// level, so calling Config.Level.SetLevel will atomically change the log
// level of all loggers descended from this config.
Level AtomicLevel `json:"level" yaml:"level"`
// Development puts the logger in development mode, which changes the
// behavior of DPanicLevel and takes stacktraces more liberally.
Development bool `json:"development" yaml:"development"`
// DisableCaller stops annotating logs with the calling function's file
// name and line number. By default, all logs are annotated.
DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
// DisableStacktrace completely disables automatic stacktrace capturing. By
// default, stacktraces are captured for WarnLevel and above logs in
// development and ErrorLevel and above in production.
DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
// Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
// Encoding sets the logger's encoding. Valid values are "json" and
// "console", as well as any third-party encodings registered via
// RegisterEncoder.
Encoding string `json:"encoding" yaml:"encoding"`
// EncoderConfig sets options for the chosen encoder. See
// zapcore.EncoderConfig for details.
EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
// OutputPaths is a list of URLs or file paths to write logging output to.
// See Open for details.
OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
// ErrorOutputPaths is a list of URLs to write internal logger errors to.
// The default is standard error.
//
// Note that this setting only affects internal errors; for sample code that
// sends error-level logs to a different location from info- and debug-level
// logs, see the package-level AdvancedConfiguration example.
ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
// InitialFields is a collection of fields to add to the root logger.
InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
}
// NewProductionEncoderConfig returns an opinionated EncoderConfig for
// production environments.
func NewProductionEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
TimeKey: "ts",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.EpochTimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
}
// NewProductionConfig is a reasonable production logging configuration.
// Logging is enabled at InfoLevel and above.
//
// It uses a JSON encoder, writes to standard error, and enables sampling.
// Stacktraces are automatically included on logs of ErrorLevel and above.
func NewProductionConfig() Config {
return Config{
Level: NewAtomicLevelAt(InfoLevel),
Development: false,
Sampling: &SamplingConfig{
Initial: 100,
Thereafter: 100,
},
Encoding: "json",
EncoderConfig: NewProductionEncoderConfig(),
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
}
// NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for
// development environments.
func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
// Keys can be anything except the empty string.
TimeKey: "T",
LevelKey: "L",
NameKey: "N",
CallerKey: "C",
MessageKey: "M",
StacktraceKey: "S",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
}
// NewDevelopmentConfig is a reasonable development logging configuration.
// Logging is enabled at DebugLevel and above.
//
// It enables development mode (which makes DPanicLevel logs panic), uses a
// console encoder, writes to standard error, and disables sampling.
// Stacktraces are automatically included on logs of WarnLevel and above.
func NewDevelopmentConfig() Config {
return Config{
Level: NewAtomicLevelAt(DebugLevel),
Development: true,
Encoding: "console",
EncoderConfig: NewDevelopmentEncoderConfig(),
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}
}
// Build constructs a logger from the Config and Options.
func (cfg Config) Build(opts ...Option) (*Logger, error) {
enc, err := cfg.buildEncoder()
if err != nil {
return nil, err
}
sink, errSink, err := cfg.openSinks()
if err != nil {
return nil, err
}
log := New(
zapcore.NewCore(enc, sink, cfg.Level),
cfg.buildOptions(errSink)...,
)
if len(opts) > 0 {
log = log.WithOptions(opts...)
}
return log, nil
}
func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
opts := []Option{ErrorOutput(errSink)}
if cfg.Development {
opts = append(opts, Development())
}
if !cfg.DisableCaller {
opts = append(opts, AddCaller())
}
stackLevel := ErrorLevel
if cfg.Development {
stackLevel = WarnLevel
}
if !cfg.DisableStacktrace {
opts = append(opts, AddStacktrace(stackLevel))
}
if cfg.Sampling != nil {
opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core {
return zapcore.NewSampler(core, time.Second, int(cfg.Sampling.Initial), int(cfg.Sampling.Thereafter))
}))
}
if len(cfg.InitialFields) > 0 {
fs := make([]Field, 0, len(cfg.InitialFields))
keys := make([]string, 0, len(cfg.InitialFields))
for k := range cfg.InitialFields {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fs = append(fs, Any(k, cfg.InitialFields[k]))
}
opts = append(opts, Fields(fs...))
}
return opts
}
func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
sink, closeOut, err := Open(cfg.OutputPaths...)
if err != nil {
return nil, nil, err
}
errSink, _, err := Open(cfg.ErrorOutputPaths...)
if err != nil {
closeOut()
return nil, nil, err
}
return sink, errSink, nil
}
func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
return newEncoder(cfg.Encoding, cfg.EncoderConfig)
}

113
vendor/go.uber.org/zap/doc.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package zap provides fast, structured, leveled logging.
//
// For applications that log in the hot path, reflection-based serialization
// and string formatting are prohibitively expensive - they're CPU-intensive
// and make many small allocations. Put differently, using json.Marshal and
// fmt.Fprintf to log tons of interface{} makes your application slow.
//
// Zap takes a different approach. It includes a reflection-free,
// zero-allocation JSON encoder, and the base Logger strives to avoid
// serialization overhead and allocations wherever possible. By building the
// high-level SugaredLogger on that foundation, zap lets users choose when
// they need to count every allocation and when they'd prefer a more familiar,
// loosely typed API.
//
// Choosing a Logger
//
// In contexts where performance is nice, but not critical, use the
// SugaredLogger. It's 4-10x faster than other structured logging packages and
// supports both structured and printf-style logging. Like log15 and go-kit,
// the SugaredLogger's structured logging APIs are loosely typed and accept a
// variadic number of key-value pairs. (For more advanced use cases, they also
// accept strongly typed fields - see the SugaredLogger.With documentation for
// details.)
// sugar := zap.NewExample().Sugar()
// defer sugar.Sync()
// sugar.Infow("failed to fetch URL",
// "url", "http://example.com",
// "attempt", 3,
// "backoff", time.Second,
// )
// sugar.Infof("failed to fetch URL: %s", "http://example.com")
//
// By default, loggers are unbuffered. However, since zap's low-level APIs
// allow buffering, calling Sync before letting your process exit is a good
// habit.
//
// In the rare contexts where every microsecond and every allocation matter,
// use the Logger. It's even faster than the SugaredLogger and allocates far
// less, but it only supports strongly-typed, structured logging.
// logger := zap.NewExample()
// defer logger.Sync()
// logger.Info("failed to fetch URL",
// zap.String("url", "http://example.com"),
// zap.Int("attempt", 3),
// zap.Duration("backoff", time.Second),
// )
//
// Choosing between the Logger and SugaredLogger doesn't need to be an
// application-wide decision: converting between the two is simple and
// inexpensive.
// logger := zap.NewExample()
// defer logger.Sync()
// sugar := logger.Sugar()
// plain := sugar.Desugar()
//
// Configuring Zap
//
// The simplest way to build a Logger is to use zap's opinionated presets:
// NewExample, NewProduction, and NewDevelopment. These presets build a logger
// with a single function call:
// logger, err := zap.NewProduction()
// if err != nil {
// log.Fatalf("can't initialize zap logger: %v", err)
// }
// defer logger.Sync()
//
// Presets are fine for small projects, but larger projects and organizations
// naturally require a bit more customization. For most users, zap's Config
// struct strikes the right balance between flexibility and convenience. See
// the package-level BasicConfiguration example for sample code.
//
// More unusual configurations (splitting output between files, sending logs
// to a message queue, etc.) are possible, but require direct use of
// go.uber.org/zap/zapcore. See the package-level AdvancedConfiguration
// example for sample code.
//
// Extending Zap
//
// The zap package itself is a relatively thin wrapper around the interfaces
// in go.uber.org/zap/zapcore. Extending zap to support a new encoding (e.g.,
// BSON), a new log sink (e.g., Kafka), or something more exotic (perhaps an
// exception aggregation service, like Sentry or Rollbar) typically requires
// implementing the zapcore.Encoder, zapcore.WriteSyncer, or zapcore.Core
// interfaces. See the zapcore documentation for details.
//
// Similarly, package authors can use the high-performance Encoder and Core
// implementations in the zapcore package to build their own loggers.
//
// Frequently Asked Questions
//
// An FAQ covering everything from installation errors to design decisions is
// available at https://github.com/uber-go/zap/blob/master/FAQ.md.
package zap // import "go.uber.org/zap"

75
vendor/go.uber.org/zap/encoder.go generated vendored Normal file
View File

@ -0,0 +1,75 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"errors"
"fmt"
"sync"
"go.uber.org/zap/zapcore"
)
var (
errNoEncoderNameSpecified = errors.New("no encoder name specified")
_encoderNameToConstructor = map[string]func(zapcore.EncoderConfig) (zapcore.Encoder, error){
"console": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
return zapcore.NewConsoleEncoder(encoderConfig), nil
},
"json": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
return zapcore.NewJSONEncoder(encoderConfig), nil
},
}
_encoderMutex sync.RWMutex
)
// RegisterEncoder registers an encoder constructor, which the Config struct
// can then reference. By default, the "json" and "console" encoders are
// registered.
//
// Attempting to register an encoder whose name is already taken returns an
// error.
func RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) error {
_encoderMutex.Lock()
defer _encoderMutex.Unlock()
if name == "" {
return errNoEncoderNameSpecified
}
if _, ok := _encoderNameToConstructor[name]; ok {
return fmt.Errorf("encoder already registered for name %q", name)
}
_encoderNameToConstructor[name] = constructor
return nil
}
func newEncoder(name string, encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {
_encoderMutex.RLock()
defer _encoderMutex.RUnlock()
if name == "" {
return nil, errNoEncoderNameSpecified
}
constructor, ok := _encoderNameToConstructor[name]
if !ok {
return nil, fmt.Errorf("no encoder registered for name %q", name)
}
return constructor(encoderConfig)
}

80
vendor/go.uber.org/zap/error.go generated vendored Normal file
View File

@ -0,0 +1,80 @@
// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"sync"
"go.uber.org/zap/zapcore"
)
var _errArrayElemPool = sync.Pool{New: func() interface{} {
return &errArrayElem{}
}}
// Error is shorthand for the common idiom NamedError("error", err).
func Error(err error) Field {
return NamedError("error", err)
}
// NamedError constructs a field that lazily stores err.Error() under the
// provided key. Errors which also implement fmt.Formatter (like those produced
// by github.com/pkg/errors) will also have their verbose representation stored
// under key+"Verbose". If passed a nil error, the field is a no-op.
//
// For the common case in which the key is simply "error", the Error function
// is shorter and less repetitive.
func NamedError(key string, err error) Field {
if err == nil {
return Skip()
}
return Field{Key: key, Type: zapcore.ErrorType, Interface: err}
}
type errArray []error
func (errs errArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range errs {
if errs[i] == nil {
continue
}
// To represent each error as an object with an "error" attribute and
// potentially an "errorVerbose" attribute, we need to wrap it in a
// type that implements LogObjectMarshaler. To prevent this from
// allocating, pool the wrapper type.
elem := _errArrayElemPool.Get().(*errArrayElem)
elem.error = errs[i]
arr.AppendObject(elem)
elem.error = nil
_errArrayElemPool.Put(elem)
}
return nil
}
type errArrayElem struct {
error
}
func (e *errArrayElem) MarshalLogObject(enc zapcore.ObjectEncoder) error {
// Re-use the error field's logic, which supports non-standard error types.
Error(e.error).AddTo(enc)
return nil
}

310
vendor/go.uber.org/zap/field.go generated vendored Normal file
View File

@ -0,0 +1,310 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"fmt"
"math"
"time"
"go.uber.org/zap/zapcore"
)
// Field is an alias for Field. Aliasing this type dramatically
// improves the navigability of this package's API documentation.
type Field = zapcore.Field
// Skip constructs a no-op field, which is often useful when handling invalid
// inputs in other Field constructors.
func Skip() Field {
return Field{Type: zapcore.SkipType}
}
// Binary constructs a field that carries an opaque binary blob.
//
// Binary data is serialized in an encoding-appropriate format. For example,
// zap's JSON encoder base64-encodes binary blobs. To log UTF-8 encoded text,
// use ByteString.
func Binary(key string, val []byte) Field {
return Field{Key: key, Type: zapcore.BinaryType, Interface: val}
}
// Bool constructs a field that carries a bool.
func Bool(key string, val bool) Field {
var ival int64
if val {
ival = 1
}
return Field{Key: key, Type: zapcore.BoolType, Integer: ival}
}
// ByteString constructs a field that carries UTF-8 encoded text as a []byte.
// To log opaque binary blobs (which aren't necessarily valid UTF-8), use
// Binary.
func ByteString(key string, val []byte) Field {
return Field{Key: key, Type: zapcore.ByteStringType, Interface: val}
}
// Complex128 constructs a field that carries a complex number. Unlike most
// numeric fields, this costs an allocation (to convert the complex128 to
// interface{}).
func Complex128(key string, val complex128) Field {
return Field{Key: key, Type: zapcore.Complex128Type, Interface: val}
}
// Complex64 constructs a field that carries a complex number. Unlike most
// numeric fields, this costs an allocation (to convert the complex64 to
// interface{}).
func Complex64(key string, val complex64) Field {
return Field{Key: key, Type: zapcore.Complex64Type, Interface: val}
}
// Float64 constructs a field that carries a float64. The way the
// floating-point value is represented is encoder-dependent, so marshaling is
// necessarily lazy.
func Float64(key string, val float64) Field {
return Field{Key: key, Type: zapcore.Float64Type, Integer: int64(math.Float64bits(val))}
}
// Float32 constructs a field that carries a float32. The way the
// floating-point value is represented is encoder-dependent, so marshaling is
// necessarily lazy.
func Float32(key string, val float32) Field {
return Field{Key: key, Type: zapcore.Float32Type, Integer: int64(math.Float32bits(val))}
}
// Int constructs a field with the given key and value.
func Int(key string, val int) Field {
return Int64(key, int64(val))
}
// Int64 constructs a field with the given key and value.
func Int64(key string, val int64) Field {
return Field{Key: key, Type: zapcore.Int64Type, Integer: val}
}
// Int32 constructs a field with the given key and value.
func Int32(key string, val int32) Field {
return Field{Key: key, Type: zapcore.Int32Type, Integer: int64(val)}
}
// Int16 constructs a field with the given key and value.
func Int16(key string, val int16) Field {
return Field{Key: key, Type: zapcore.Int16Type, Integer: int64(val)}
}
// Int8 constructs a field with the given key and value.
func Int8(key string, val int8) Field {
return Field{Key: key, Type: zapcore.Int8Type, Integer: int64(val)}
}
// String constructs a field with the given key and value.
func String(key string, val string) Field {
return Field{Key: key, Type: zapcore.StringType, String: val}
}
// Uint constructs a field with the given key and value.
func Uint(key string, val uint) Field {
return Uint64(key, uint64(val))
}
// Uint64 constructs a field with the given key and value.
func Uint64(key string, val uint64) Field {
return Field{Key: key, Type: zapcore.Uint64Type, Integer: int64(val)}
}
// Uint32 constructs a field with the given key and value.
func Uint32(key string, val uint32) Field {
return Field{Key: key, Type: zapcore.Uint32Type, Integer: int64(val)}
}
// Uint16 constructs a field with the given key and value.
func Uint16(key string, val uint16) Field {
return Field{Key: key, Type: zapcore.Uint16Type, Integer: int64(val)}
}
// Uint8 constructs a field with the given key and value.
func Uint8(key string, val uint8) Field {
return Field{Key: key, Type: zapcore.Uint8Type, Integer: int64(val)}
}
// Uintptr constructs a field with the given key and value.
func Uintptr(key string, val uintptr) Field {
return Field{Key: key, Type: zapcore.UintptrType, Integer: int64(val)}
}
// Reflect constructs a field with the given key and an arbitrary object. It uses
// an encoding-appropriate, reflection-based function to lazily serialize nearly
// any object into the logging context, but it's relatively slow and
// allocation-heavy. Outside tests, Any is always a better choice.
//
// If encoding fails (e.g., trying to serialize a map[int]string to JSON), Reflect
// includes the error message in the final log output.
func Reflect(key string, val interface{}) Field {
return Field{Key: key, Type: zapcore.ReflectType, Interface: val}
}
// Namespace creates a named, isolated scope within the logger's context. All
// subsequent fields will be added to the new namespace.
//
// This helps prevent key collisions when injecting loggers into sub-components
// or third-party libraries.
func Namespace(key string) Field {
return Field{Key: key, Type: zapcore.NamespaceType}
}
// Stringer constructs a field with the given key and the output of the value's
// String method. The Stringer's String method is called lazily.
func Stringer(key string, val fmt.Stringer) Field {
return Field{Key: key, Type: zapcore.StringerType, Interface: val}
}
// Time constructs a Field with the given key and value. The encoder
// controls how the time is serialized.
func Time(key string, val time.Time) Field {
return Field{Key: key, Type: zapcore.TimeType, Integer: val.UnixNano(), Interface: val.Location()}
}
// Stack constructs a field that stores a stacktrace of the current goroutine
// under provided key. Keep in mind that taking a stacktrace is eager and
// expensive (relatively speaking); this function both makes an allocation and
// takes about two microseconds.
func Stack(key string) Field {
// Returning the stacktrace as a string costs an allocation, but saves us
// from expanding the zapcore.Field union struct to include a byte slice. Since
// taking a stacktrace is already so expensive (~10us), the extra allocation
// is okay.
return String(key, takeStacktrace())
}
// Duration constructs a field with the given key and value. The encoder
// controls how the duration is serialized.
func Duration(key string, val time.Duration) Field {
return Field{Key: key, Type: zapcore.DurationType, Integer: int64(val)}
}
// Object constructs a field with the given key and ObjectMarshaler. It
// provides a flexible, but still type-safe and efficient, way to add map- or
// struct-like user-defined types to the logging context. The struct's
// MarshalLogObject method is called lazily.
func Object(key string, val zapcore.ObjectMarshaler) Field {
return Field{Key: key, Type: zapcore.ObjectMarshalerType, Interface: val}
}
// Any takes a key and an arbitrary value and chooses the best way to represent
// them as a field, falling back to a reflection-based approach only if
// necessary.
//
// Since byte/uint8 and rune/int32 are aliases, Any can't differentiate between
// them. To minimize surprises, []byte values are treated as binary blobs, byte
// values are treated as uint8, and runes are always treated as integers.
func Any(key string, value interface{}) Field {
switch val := value.(type) {
case zapcore.ObjectMarshaler:
return Object(key, val)
case zapcore.ArrayMarshaler:
return Array(key, val)
case bool:
return Bool(key, val)
case []bool:
return Bools(key, val)
case complex128:
return Complex128(key, val)
case []complex128:
return Complex128s(key, val)
case complex64:
return Complex64(key, val)
case []complex64:
return Complex64s(key, val)
case float64:
return Float64(key, val)
case []float64:
return Float64s(key, val)
case float32:
return Float32(key, val)
case []float32:
return Float32s(key, val)
case int:
return Int(key, val)
case []int:
return Ints(key, val)
case int64:
return Int64(key, val)
case []int64:
return Int64s(key, val)
case int32:
return Int32(key, val)
case []int32:
return Int32s(key, val)
case int16:
return Int16(key, val)
case []int16:
return Int16s(key, val)
case int8:
return Int8(key, val)
case []int8:
return Int8s(key, val)
case string:
return String(key, val)
case []string:
return Strings(key, val)
case uint:
return Uint(key, val)
case []uint:
return Uints(key, val)
case uint64:
return Uint64(key, val)
case []uint64:
return Uint64s(key, val)
case uint32:
return Uint32(key, val)
case []uint32:
return Uint32s(key, val)
case uint16:
return Uint16(key, val)
case []uint16:
return Uint16s(key, val)
case uint8:
return Uint8(key, val)
case []byte:
return Binary(key, val)
case uintptr:
return Uintptr(key, val)
case []uintptr:
return Uintptrs(key, val)
case time.Time:
return Time(key, val)
case []time.Time:
return Times(key, val)
case time.Duration:
return Duration(key, val)
case []time.Duration:
return Durations(key, val)
case error:
return NamedError(key, val)
case []error:
return Errors(key, val)
case fmt.Stringer:
return Stringer(key, val)
default:
return Reflect(key, val)
}
}

39
vendor/go.uber.org/zap/flag.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"flag"
"go.uber.org/zap/zapcore"
)
// LevelFlag uses the standard library's flag.Var to declare a global flag
// with the specified name, default, and usage guidance. The returned value is
// a pointer to the value of the flag.
//
// If you don't want to use the flag package's global state, you can use any
// non-nil *Level as a flag.Value with your own *flag.FlagSet.
func LevelFlag(name string, defaultLevel zapcore.Level, usage string) *zapcore.Level {
lvl := defaultLevel
flag.Var(&lvl, name, usage)
return &lvl
}

76
vendor/go.uber.org/zap/glide.lock generated vendored Normal file
View File

@ -0,0 +1,76 @@
hash: f073ba522c06c88ea3075bde32a8aaf0969a840a66cab6318a0897d141ffee92
updated: 2017-07-22T18:06:49.598185334-07:00
imports:
- name: go.uber.org/atomic
version: 4e336646b2ef9fc6e47be8e21594178f98e5ebcf
- name: go.uber.org/multierr
version: 3c4937480c32f4c13a875a1829af76c98ca3d40a
testImports:
- name: github.com/apex/log
version: d9b960447bfa720077b2da653cc79e533455b499
subpackages:
- handlers/json
- name: github.com/axw/gocov
version: 3a69a0d2a4ef1f263e2d92b041a69593d6964fe8
subpackages:
- gocov
- name: github.com/davecgh/go-spew
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
subpackages:
- spew
- name: github.com/fatih/color
version: 62e9147c64a1ed519147b62a56a14e83e2be02c1
- name: github.com/go-kit/kit
version: e10f5bf035be9af21fd5b2fb4469d5716c6ab07d
subpackages:
- log
- name: github.com/go-logfmt/logfmt
version: 390ab7935ee28ec6b286364bba9b4dd6410cb3d5
- name: github.com/go-stack/stack
version: 54be5f394ed2c3e19dac9134a40a95ba5a017f7b
- name: github.com/golang/lint
version: c5fb716d6688a859aae56d26d3e6070808df29f7
subpackages:
- golint
- name: github.com/kr/logfmt
version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0
- name: github.com/mattn/go-colorable
version: 3fa8c76f9daed4067e4a806fb7e4dc86455c6d6a
- name: github.com/mattn/go-isatty
version: fc9e8d8ef48496124e79ae0df75490096eccf6fe
- name: github.com/mattn/goveralls
version: 6efce81852ad1b7567c17ad71b03aeccc9dd9ae0
- name: github.com/pborman/uuid
version: e790cca94e6cc75c7064b1332e63811d4aae1a53
- name: github.com/pkg/errors
version: 645ef00459ed84a119197bfb8d8205042c6df63d
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/rs/zerolog
version: eed4c2b94d945e0b2456ad6aa518a443986b5f22
- name: github.com/satori/go.uuid
version: 5bf94b69c6b68ee1b541973bb8e1144db23a194b
- name: github.com/sirupsen/logrus
version: 7dd06bf38e1e13df288d471a57d5adbac106be9e
- name: github.com/stretchr/testify
version: f6abca593680b2315d2075e0f5e2a9751e3f431a
subpackages:
- assert
- require
- name: go.pedge.io/lion
version: 87958e8713f1fa138d993087133b97e976642159
- name: golang.org/x/sys
version: c4489faa6e5ab84c0ef40d6ee878f7a030281f0f
subpackages:
- unix
- name: golang.org/x/tools
version: 496819729719f9d07692195e0a94d6edd2251389
subpackages:
- cover
- name: gopkg.in/inconshreveable/log15.v2
version: b105bd37f74e5d9dc7b6ad7806715c7a2b83fd3f
subpackages:
- stack
- term

35
vendor/go.uber.org/zap/glide.yaml generated vendored Normal file
View File

@ -0,0 +1,35 @@
package: go.uber.org/zap
license: MIT
import:
- package: go.uber.org/atomic
version: ^1
- package: go.uber.org/multierr
version: ^1
testImport:
- package: github.com/satori/go.uuid
- package: github.com/sirupsen/logrus
- package: github.com/apex/log
subpackages:
- handlers/json
- package: github.com/go-kit/kit
subpackages:
- log
- package: github.com/stretchr/testify
subpackages:
- assert
- require
- package: gopkg.in/inconshreveable/log15.v2
- package: github.com/mattn/goveralls
- package: github.com/pborman/uuid
- package: github.com/pkg/errors
- package: go.pedge.io/lion
- package: github.com/rs/zerolog
- package: golang.org/x/tools
subpackages:
- cover
- package: github.com/golang/lint
subpackages:
- golint
- package: github.com/axw/gocov
subpackages:
- gocov

168
vendor/go.uber.org/zap/global.go generated vendored Normal file
View File

@ -0,0 +1,168 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"bytes"
"fmt"
"log"
"os"
"sync"
"go.uber.org/zap/zapcore"
)
const (
_loggerWriterDepth = 2
_programmerErrorTemplate = "You've found a bug in zap! Please file a bug at " +
"https://github.com/uber-go/zap/issues/new and reference this error: %v"
)
var (
_globalMu sync.RWMutex
_globalL = NewNop()
_globalS = _globalL.Sugar()
)
// L returns the global Logger, which can be reconfigured with ReplaceGlobals.
// It's safe for concurrent use.
func L() *Logger {
_globalMu.RLock()
l := _globalL
_globalMu.RUnlock()
return l
}
// S returns the global SugaredLogger, which can be reconfigured with
// ReplaceGlobals. It's safe for concurrent use.
func S() *SugaredLogger {
_globalMu.RLock()
s := _globalS
_globalMu.RUnlock()
return s
}
// ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a
// function to restore the original values. It's safe for concurrent use.
func ReplaceGlobals(logger *Logger) func() {
_globalMu.Lock()
prev := _globalL
_globalL = logger
_globalS = logger.Sugar()
_globalMu.Unlock()
return func() { ReplaceGlobals(prev) }
}
// NewStdLog returns a *log.Logger which writes to the supplied zap Logger at
// InfoLevel. To redirect the standard library's package-global logging
// functions, use RedirectStdLog instead.
func NewStdLog(l *Logger) *log.Logger {
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
f := logger.Info
return log.New(&loggerWriter{f}, "" /* prefix */, 0 /* flags */)
}
// NewStdLogAt returns *log.Logger which writes to supplied zap logger at
// required level.
func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error) {
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
logFunc, err := levelToFunc(logger, level)
if err != nil {
return nil, err
}
return log.New(&loggerWriter{logFunc}, "" /* prefix */, 0 /* flags */), nil
}
// RedirectStdLog redirects output from the standard library's package-global
// logger to the supplied logger at InfoLevel. Since zap already handles caller
// annotations, timestamps, etc., it automatically disables the standard
// library's annotations and prefixing.
//
// It returns a function to restore the original prefix and flags and reset the
// standard library's output to os.Stderr.
func RedirectStdLog(l *Logger) func() {
f, err := redirectStdLogAt(l, InfoLevel)
if err != nil {
// Can't get here, since passing InfoLevel to redirectStdLogAt always
// works.
panic(fmt.Sprintf(_programmerErrorTemplate, err))
}
return f
}
// RedirectStdLogAt redirects output from the standard library's package-global
// logger to the supplied logger at the specified level. Since zap already
// handles caller annotations, timestamps, etc., it automatically disables the
// standard library's annotations and prefixing.
//
// It returns a function to restore the original prefix and flags and reset the
// standard library's output to os.Stderr.
func RedirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
return redirectStdLogAt(l, level)
}
func redirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) {
flags := log.Flags()
prefix := log.Prefix()
log.SetFlags(0)
log.SetPrefix("")
logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth))
logFunc, err := levelToFunc(logger, level)
if err != nil {
return nil, err
}
log.SetOutput(&loggerWriter{logFunc})
return func() {
log.SetFlags(flags)
log.SetPrefix(prefix)
log.SetOutput(os.Stderr)
}, nil
}
func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) {
switch lvl {
case DebugLevel:
return logger.Debug, nil
case InfoLevel:
return logger.Info, nil
case WarnLevel:
return logger.Warn, nil
case ErrorLevel:
return logger.Error, nil
case DPanicLevel:
return logger.DPanic, nil
case PanicLevel:
return logger.Panic, nil
case FatalLevel:
return logger.Fatal, nil
}
return nil, fmt.Errorf("unrecognized level: %q", lvl)
}
type loggerWriter struct {
logFunc func(msg string, fields ...Field)
}
func (l *loggerWriter) Write(p []byte) (int, error) {
p = bytes.TrimSpace(p)
l.logFunc(string(p))
return len(p), nil
}

26
vendor/go.uber.org/zap/global_go112.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// See #682 for more information.
// +build go1.12
package zap
const _stdLogDefaultDepth = 1

26
vendor/go.uber.org/zap/global_prego112.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// See #682 for more information.
// +build !go1.12
package zap
const _stdLogDefaultDepth = 2

81
vendor/go.uber.org/zap/http_handler.go generated vendored Normal file
View File

@ -0,0 +1,81 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"encoding/json"
"fmt"
"net/http"
"go.uber.org/zap/zapcore"
)
// ServeHTTP is a simple JSON endpoint that can report on or change the current
// logging level.
//
// GET requests return a JSON description of the current logging level. PUT
// requests change the logging level and expect a payload like:
// {"level":"info"}
//
// It's perfectly safe to change the logging level while a program is running.
func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request) {
type errorResponse struct {
Error string `json:"error"`
}
type payload struct {
Level *zapcore.Level `json:"level"`
}
enc := json.NewEncoder(w)
switch r.Method {
case http.MethodGet:
current := lvl.Level()
enc.Encode(payload{Level: &current})
case http.MethodPut:
var req payload
if errmess := func() string {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return fmt.Sprintf("Request body must be well-formed JSON: %v", err)
}
if req.Level == nil {
return "Must specify a logging level."
}
return ""
}(); errmess != "" {
w.WriteHeader(http.StatusBadRequest)
enc.Encode(errorResponse{Error: errmess})
return
}
lvl.SetLevel(*req.Level)
enc.Encode(req)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
enc.Encode(errorResponse{
Error: "Only GET and PUT are supported.",
})
}
}

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