mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Switch to dep from glide (#664)
This commit is contained in:
committed by
Reed Allman
parent
0a09d74137
commit
3b9818bc58
@@ -53,9 +53,9 @@ asking for suggestions on how to address the documentation part.
|
||||
|
||||
### Build
|
||||
|
||||
Use go 1.9.1 or newer.
|
||||
Requires Go >= 1.9.1.
|
||||
|
||||
The first time after you fork or after dependencies get updated, run:
|
||||
The first time after you clone or after dependencies get updated, run:
|
||||
|
||||
```sh
|
||||
make dep
|
||||
|
||||
604
Gopkg.lock
generated
Normal file
604
Gopkg.lock
generated
Normal file
@@ -0,0 +1,604 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Azure/go-ansiterm"
|
||||
packages = [".","winterm"]
|
||||
revision = "19f72df4d05d31cbe1c56bfc8045c96babff6c7e"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Microsoft/go-winio"
|
||||
packages = ["."]
|
||||
revision = "78439966b38d69bf38227fbf57ac8a6fee70f69a"
|
||||
version = "v0.4.5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/Nvveen/Gotty"
|
||||
packages = ["."]
|
||||
revision = "cd527374f1e5bff4938207604a14f2e38a9cf512"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/PuerkitoBio/purell"
|
||||
packages = ["."]
|
||||
revision = "8a290539e2e8629dbc4e6bad948158f790ec31f4"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/PuerkitoBio/urlesc"
|
||||
packages = ["."]
|
||||
revision = "5bd2802263f21d8788851d5305584c82a5c75d7e"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Shopify/sarama"
|
||||
packages = ["."]
|
||||
revision = "4704a3a8c95920361c47e9a2adec13c3d757c757"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/apache/thrift"
|
||||
packages = ["lib/go/thrift"]
|
||||
revision = "4c30c15924bfbc7c9e6bfc0e82630e97980e556e"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/asaskevich/govalidator"
|
||||
packages = ["."]
|
||||
revision = "15028e809df8c71964e8efa6c11e81d5c0262302"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/beorn7/perks"
|
||||
packages = ["quantile"]
|
||||
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/boltdb/bolt"
|
||||
packages = ["."]
|
||||
revision = "fa5367d20c994db73282594be0146ab221657943"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/cloudflare/cfssl"
|
||||
packages = ["api","auth","certdb","config","crypto/pkcs7","csr","errors","helpers","helpers/derhelpers","info","initca","log","ocsp/config","signer","signer/local"]
|
||||
revision = "7d88da830aad9d533c2fb8532da23f6a75331b52"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/coreos/etcd"
|
||||
packages = ["raft/raftpb"]
|
||||
revision = "5bb9f9591f01d0a3c61d2eb3a3bb281726005b2b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/coreos/go-semver"
|
||||
packages = ["semver"]
|
||||
revision = "8ab6407b697782a06568d4b7f1db25550ec2e4c6"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/dchest/siphash"
|
||||
packages = ["."]
|
||||
revision = "4ebf1de738443ea7f45f02dc394c4df1942a126d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/distribution"
|
||||
packages = [".","digestset","manifest","manifest/schema1","manifest/schema2","reference","registry/api/errcode","registry/api/v2","registry/client","registry/client/auth","registry/client/auth/challenge","registry/client/transport","registry/storage/cache","registry/storage/cache/memory"]
|
||||
revision = "bc3c7b0525e59d3ecfab3e1568350895fd4a462f"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/docker"
|
||||
packages = ["api/types","api/types/blkiodev","api/types/container","api/types/filters","api/types/mount","api/types/network","api/types/registry","api/types/strslice","api/types/swarm","api/types/swarm/runtime","api/types/versions","daemon/cluster/convert","opts","pkg/archive","pkg/fileutils","pkg/homedir","pkg/idtools","pkg/ioutils","pkg/jsonlog","pkg/jsonmessage","pkg/longpath","pkg/mount","pkg/namesgenerator","pkg/pools","pkg/promise","pkg/stdcopy","pkg/system","pkg/term","pkg/term/windows"]
|
||||
revision = "cdf870bd0b5fa678b10ef2708cca7ad776b4913c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/go-connections"
|
||||
packages = ["nat"]
|
||||
revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/docker/go-events"
|
||||
packages = ["."]
|
||||
revision = "9461782956ad83b30282bf90e31fa6a70c255ba9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/go-units"
|
||||
packages = ["."]
|
||||
revision = "0dadbb0345b35ec7ef35e228dabb8de89a65bf52"
|
||||
version = "v0.3.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/libkv"
|
||||
packages = [".","store"]
|
||||
revision = "93ab0e6c056d325dfbb11e1d58a3b4f5f62e7f3c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/libnetwork"
|
||||
packages = ["datastore","discoverapi","types"]
|
||||
revision = "6d098467ec58038b68620a3c2c418936661efa64"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/docker/libtrust"
|
||||
packages = ["."]
|
||||
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/swarmkit"
|
||||
packages = ["api","api/deepcopy","api/equality","api/genericresource","api/naming","ca","connectionbroker","identity","ioutils","log","manager/raftselector","manager/state","manager/state/store","protobuf/plugin","remotes","watch","watch/queue"]
|
||||
revision = "bd7bafb8a61de1f5f23c8215ce7b9ecbcb30ff21"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/dustin/go-humanize"
|
||||
packages = ["."]
|
||||
revision = "bb3d318650d48840a39aa21a027c6630e198e626"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/eapache/go-resiliency"
|
||||
packages = ["breaker"]
|
||||
revision = "b1fe83b5b03f624450823b751b662259ffc6af70"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/eapache/go-xerial-snappy"
|
||||
packages = ["."]
|
||||
revision = "bb955e01b9346ac19dc29eb16586c90ded99a98c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/eapache/queue"
|
||||
packages = ["."]
|
||||
revision = "44cc805cf13205b55f69e14bcb69867d1ae92f98"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/emicklei/go-restful"
|
||||
packages = [".","log"]
|
||||
revision = "ff4f55a206334ef123e4f79bbf348980da81ca46"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/emicklei/go-restful-swagger12"
|
||||
packages = ["."]
|
||||
revision = "dcef7f55730566d41eae5db10e7d6981829720f6"
|
||||
version = "1.0.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/fnproject/fdk-go"
|
||||
packages = ["."]
|
||||
revision = "7c1e1a329cf1004edf545318280d672f35e15081"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fnproject/fn_go"
|
||||
packages = ["client","client/apps","client/call","client/operations","client/routes","models"]
|
||||
revision = "7ce3bb2e624df60cdfbfc1ee5483f6df80bb2b1b"
|
||||
version = "0.2.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fsouza/go-dockerclient"
|
||||
packages = ["."]
|
||||
revision = "98edf3edfae6a6500fecc69d2bcccf1302544004"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/garyburd/redigo"
|
||||
packages = ["internal","redis"]
|
||||
revision = "70e1b1943d4fc9c56791abaa6f4d1e727b9ab925"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/ghodss/yaml"
|
||||
packages = ["."]
|
||||
revision = "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gin-contrib/cors"
|
||||
packages = ["."]
|
||||
revision = "cf4846e6a636a76237a28d9286f163c132e841bc"
|
||||
version = "v1.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gin-contrib/sse"
|
||||
packages = ["."]
|
||||
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gin-gonic/gin"
|
||||
packages = [".","binding","json","render"]
|
||||
revision = "5afc5b19730118c9b8324fe9dd995d44ec65c81a"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
revision = "c787282c39ac1fc618827141a1f762240def08a3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-logfmt/logfmt"
|
||||
packages = ["."]
|
||||
revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/analysis"
|
||||
packages = ["."]
|
||||
revision = "8ed83f2ea9f00f945516462951a288eaa68bf0d6"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/errors"
|
||||
packages = ["."]
|
||||
revision = "03cfca65330da08a5a440053faf994a3c682b5bf"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-openapi/jsonpointer"
|
||||
packages = ["."]
|
||||
revision = "779f45308c19820f1a69e9a4cd965f496e0da10f"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/jsonreference"
|
||||
packages = ["."]
|
||||
revision = "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/loads"
|
||||
packages = ["."]
|
||||
revision = "a80dea3052f00e5f032e860dd7355cd0cc67e24d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/runtime"
|
||||
packages = [".","client"]
|
||||
revision = "d6605b7c17ac3b1033ca794886e6142a4141f5b0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/spec"
|
||||
packages = ["."]
|
||||
revision = "3faa0055dbbf2110abc1f3b4e3adbb22721e96e7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-openapi/strfmt"
|
||||
packages = ["."]
|
||||
revision = "4dd3d302e100bae008baedc42d446ce83bdd10ad"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/swag"
|
||||
packages = ["."]
|
||||
revision = "f3f9494671f93fcff853e3c6e9e948b3eb71e590"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-openapi/validate"
|
||||
packages = ["."]
|
||||
revision = "8a82927c942c94794a5cd8b8b50ce2f48a955c0c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
packages = ["."]
|
||||
revision = "21d7e97c9f760ca685a01ecea202e1c84276daa1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = ["gogoproto","proto","protoc-gen-gogo/descriptor","sortkeys","types"]
|
||||
revision = "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/golang/glog"
|
||||
packages = ["."]
|
||||
revision = "44145f04b68cf362d9c4df2182967c2275eaefed"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["proto","ptypes/any"]
|
||||
revision = "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/snappy"
|
||||
packages = ["."]
|
||||
revision = "553a641470496b2327abcac10b36396bd98e45c9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/google/btree"
|
||||
packages = ["."]
|
||||
revision = "316fb6d3f031ae8f4d457c6c5186b9e3ded70435"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/google/certificate-transparency-go"
|
||||
packages = [".","asn1","client","jsonclient","tls","x509","x509/pkix"]
|
||||
revision = "0dac42a6ed448ba220ee315abfaa6d26fd5fc9bb"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/google/gofuzz"
|
||||
packages = ["."]
|
||||
revision = "44d81051d367757e1c7c6a5a86423ece9afcf63c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gorilla/context"
|
||||
packages = ["."]
|
||||
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/mux"
|
||||
packages = ["."]
|
||||
revision = "24fca303ac6da784b9e8269f724ddeb0b2eea5e7"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||
packages = ["."]
|
||||
revision = "6b7015e65d366bf3f19b2b2a000a831940f0f7e0"
|
||||
version = "v1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/go-immutable-radix"
|
||||
packages = ["."]
|
||||
revision = "8aac2701530899b64bdea735a1de8da899815220"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hashicorp/go-memdb"
|
||||
packages = ["."]
|
||||
revision = "ec43fcf8f202880feb35d2abb40a570c1f4172e9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hashicorp/golang-lru"
|
||||
packages = ["simplelru"]
|
||||
revision = "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/jmoiron/sqlx"
|
||||
packages = [".","reflectx"]
|
||||
revision = "d9bd385d68c068f1fabb5057e3dedcbcbb039d0f"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/json-iterator/go"
|
||||
packages = ["."]
|
||||
revision = "fdfe0b9a69118ff692d6e1005e9de7e0cffb7d6b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/juju/ratelimit"
|
||||
packages = ["."]
|
||||
revision = "5b9ff866471762aa2ab2dced63c9fb6f53921342"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kr/logfmt"
|
||||
packages = ["."]
|
||||
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/lib/pq"
|
||||
packages = [".","oid"]
|
||||
revision = "23da1db4f16d9658a86ae9b717c245fc078f10f1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mailru/easyjson"
|
||||
packages = ["buffer","jlexer","jwriter"]
|
||||
revision = "32fa128f234d041f196a9f3e0fea5ac9772c08e1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattes/migrate"
|
||||
packages = [".","database","source"]
|
||||
revision = "5b98c13eff7657ab49a1a5f705b72f961d7fc558"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "fc9e8d8ef48496124e79ae0df75490096eccf6fe"
|
||||
version = "v0.0.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
packages = ["."]
|
||||
revision = "05548ff55570cdb9ac72ff4a25a3b5e77a6fb7e5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/minio/go-homedir"
|
||||
packages = ["."]
|
||||
revision = "4d76aabb80b22bad8695d3904e943f1fb5e6199f"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/minio/minio-go"
|
||||
packages = [".","pkg/credentials","pkg/encrypt","pkg/policy","pkg/s3signer","pkg/s3utils","pkg/set"]
|
||||
revision = "a62e2045a5d3a6630dbb7040260994583ac56b10"
|
||||
version = "4.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
revision = "d0303fe809921458f417bcf828397a65db30a7e4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/opencontainers/go-digest"
|
||||
packages = ["."]
|
||||
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
||||
version = "v1.0.0-rc1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/opencontainers/image-spec"
|
||||
packages = ["specs-go","specs-go/v1"]
|
||||
revision = "ebd93fd0782379ca3d821f0fa74f0651a9347a3e"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/opencontainers/runc"
|
||||
packages = ["libcontainer/system","libcontainer/user"]
|
||||
revision = "ae2948042b08ad3d6d13cd09f40a50ffff4fc688"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/opentracing-contrib/go-observer"
|
||||
packages = ["."]
|
||||
revision = "a52f2342449246d5bcc273e65cbdcfa5f7d6c63c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/opentracing/opentracing-go"
|
||||
packages = [".","ext","log"]
|
||||
revision = "8ebe5d4e236eed9fd88e593c288bfb804d630b8c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/openzipkin/zipkin-go-opentracing"
|
||||
packages = [".","flag","thrift/gen-go/scribe","thrift/gen-go/zipkincore","types","wire"]
|
||||
revision = "9c88fa03bfdfaa5fec7cd1b40f3d10ec15c15fc6"
|
||||
version = "v0.3.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/patrickmn/go-cache"
|
||||
packages = ["."]
|
||||
revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0"
|
||||
version = "v2.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/petar/GoLLRB"
|
||||
packages = ["llrb"]
|
||||
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pierrec/lz4"
|
||||
packages = ["."]
|
||||
revision = "08c27939df1bd95e881e2c2367a749964ad1fceb"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/pierrec/xxHash"
|
||||
packages = ["xxHash32"]
|
||||
revision = "a0006b13c722f7f12368c00a3d3c2ae8a999a0c6"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = ["prometheus","prometheus/promhttp"]
|
||||
revision = "c5b7fccd204277076155f10851dad72b76a49317"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/prometheus/client_model"
|
||||
packages = ["go"]
|
||||
revision = "6f3806018612930941127f2a7c6c453ba2c527d2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/prometheus/common"
|
||||
packages = ["expfmt","internal/bitbucket.org/ww/goautoneg","model"]
|
||||
revision = "2f17f4a9d485bf34b4bfaccc273805040e4f86c8"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [".","xfs"]
|
||||
revision = "a1dba9ce8baed984a2495b658c82687f8157b98f"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/rcrowley/go-metrics"
|
||||
packages = ["."]
|
||||
revision = "1f30fe9094a513ce4c700b9a54458bbb0c96996c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/rdallman/migrate"
|
||||
packages = [".","database/mysql","database/postgres","database/sqlite3","source","source/go-bindata"]
|
||||
revision = "bc72eeb997c7334cb5f05f5aefd2d70bc34d71ef"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = [".","hooks/syslog"]
|
||||
revision = "89742aefa4b206dcf400792f3bd35b542998eb3b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "9ff6c6923cfffbcd502984b8e0c80539a94968b7"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/ugorji/go"
|
||||
packages = ["codec"]
|
||||
revision = "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ocsp","pkcs12","pkcs12/internal/rc2","ssh/terminal"]
|
||||
revision = "94eea52f7b742c7cbe0b03b22f0c4c8631ece122"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = ["context","context/ctxhttp","http2","http2/hpack","idna","internal/timeseries","lex/httplex","trace"]
|
||||
revision = "a8b9294777976932365dabb6640cf1468d95c70f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix","windows"]
|
||||
revision = "8b4580aae2a0dd0c231a45d3ccb8434ff533b840"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/text"
|
||||
packages = ["cases","collate","collate/build","internal","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","runes","secure/bidirule","secure/precis","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable","width"]
|
||||
revision = "57961680700a5336d15015c8c50686ca5ba362a4"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
revision = "09f6ed296fc66555a25fe4ce95173148778dfa85"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [".","codes","credentials","grpclb/grpc_lb_v1","grpclog","internal","keepalive","metadata","naming","peer","stats","status","tap","transport"]
|
||||
revision = "b8669c35455183da6d5c474ea6e72fbf55183274"
|
||||
version = "v1.5.1"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/go-playground/validator.v8"
|
||||
packages = ["."]
|
||||
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
|
||||
version = "v8.18.2"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/inf.v0"
|
||||
packages = ["."]
|
||||
revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
|
||||
version = "v0.9.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/mgo.v2"
|
||||
packages = ["bson","internal/json"]
|
||||
revision = "3f83fa5005286a7fe593b055f0d7771a7dce4655"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "53feefa2559fb8dfa8d81baad31be332c97d6c77"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/apimachinery"
|
||||
packages = ["pkg/api/equality","pkg/api/errors","pkg/api/meta","pkg/api/resource","pkg/apimachinery","pkg/apimachinery/announced","pkg/apimachinery/registered","pkg/apis/meta/v1","pkg/apis/meta/v1/unstructured","pkg/apis/meta/v1alpha1","pkg/conversion","pkg/conversion/queryparams","pkg/conversion/unstructured","pkg/fields","pkg/labels","pkg/openapi","pkg/runtime","pkg/runtime/schema","pkg/runtime/serializer","pkg/runtime/serializer/json","pkg/runtime/serializer/protobuf","pkg/runtime/serializer/recognizer","pkg/runtime/serializer/streaming","pkg/runtime/serializer/versioning","pkg/selection","pkg/types","pkg/util/clock","pkg/util/diff","pkg/util/errors","pkg/util/framer","pkg/util/intstr","pkg/util/json","pkg/util/net","pkg/util/rand","pkg/util/runtime","pkg/util/sets","pkg/util/validation","pkg/util/validation/field","pkg/util/wait","pkg/util/yaml","pkg/version","pkg/watch","third_party/forked/golang/reflect"]
|
||||
revision = "1fd2e63a9a370677308a42f24fd40c86438afddf"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/client-go"
|
||||
packages = ["discovery","kubernetes","kubernetes/scheme","kubernetes/typed/admissionregistration/v1alpha1","kubernetes/typed/apps/v1beta1","kubernetes/typed/authentication/v1","kubernetes/typed/authentication/v1beta1","kubernetes/typed/authorization/v1","kubernetes/typed/authorization/v1beta1","kubernetes/typed/autoscaling/v1","kubernetes/typed/autoscaling/v2alpha1","kubernetes/typed/batch/v1","kubernetes/typed/batch/v2alpha1","kubernetes/typed/certificates/v1beta1","kubernetes/typed/core/v1","kubernetes/typed/extensions/v1beta1","kubernetes/typed/networking/v1","kubernetes/typed/policy/v1beta1","kubernetes/typed/rbac/v1alpha1","kubernetes/typed/rbac/v1beta1","kubernetes/typed/settings/v1alpha1","kubernetes/typed/storage/v1","kubernetes/typed/storage/v1beta1","pkg/api","pkg/api/v1","pkg/api/v1/ref","pkg/apis/admissionregistration","pkg/apis/admissionregistration/v1alpha1","pkg/apis/apps","pkg/apis/apps/v1beta1","pkg/apis/authentication","pkg/apis/authentication/v1","pkg/apis/authentication/v1beta1","pkg/apis/authorization","pkg/apis/authorization/v1","pkg/apis/authorization/v1beta1","pkg/apis/autoscaling","pkg/apis/autoscaling/v1","pkg/apis/autoscaling/v2alpha1","pkg/apis/batch","pkg/apis/batch/v1","pkg/apis/batch/v2alpha1","pkg/apis/certificates","pkg/apis/certificates/v1beta1","pkg/apis/extensions","pkg/apis/extensions/v1beta1","pkg/apis/networking","pkg/apis/networking/v1","pkg/apis/policy","pkg/apis/policy/v1beta1","pkg/apis/rbac","pkg/apis/rbac/v1alpha1","pkg/apis/rbac/v1beta1","pkg/apis/settings","pkg/apis/settings/v1alpha1","pkg/apis/storage","pkg/apis/storage/v1","pkg/apis/storage/v1beta1","pkg/util","pkg/util/parsers","pkg/version","rest","rest/watch","tools/clientcmd/api","tools/metrics","transport","util/cert","util/flowcontrol","util/integer"]
|
||||
revision = "d92e8497f71b7b4e0494e5bd204b48d34bd6f254"
|
||||
version = "v4.0.0"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "c0ba99cc154500d7d551e61f56d172037c20d1e3e0b119c486e9aae15680b586"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
106
Gopkg.toml
Normal file
106
Gopkg.toml
Normal file
@@ -0,0 +1,106 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
ignored = ["github.com/fnproject/fn/cli"]
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/boltdb/bolt"
|
||||
revision = "fa5367d20c994db73282594be0146ab221657943"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/coreos/go-semver"
|
||||
version = "^0.2.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/dchest/siphash"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/fnproject/fn_go"
|
||||
version = "0.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gin-contrib/cors"
|
||||
version = "~1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/go-openapi/strfmt"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/google/btree"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/minio/minio-go"
|
||||
version = "4.0.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/openzipkin/zipkin-go-opentracing"
|
||||
version = "0.3.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/patrickmn/go-cache"
|
||||
version = "2.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/prometheus/client_golang"
|
||||
version = "0.8.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
revision = "89742aefa4b206dcf400792f3bd35b542998eb3b"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/docker/docker"
|
||||
revision = "cdf870bd0b5fa678b10ef2708cca7ad776b4913c"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/docker/cli"
|
||||
revision = "139fcd3ee95f37f3ac17b1200fb0a63908cb6781"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/docker/distribution"
|
||||
revision = "bc3c7b0525e59d3ecfab3e1568350895fd4a462f"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/rdallman/migrate" # TODO change to mattes/migrate w/ https://github.com/mattes/migrate/pull/299
|
||||
revision = "bc72eeb997c7334cb5f05f5aefd2d70bc34d71ef"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
revision = "21d7e97c9f760ca685a01ecea202e1c84276daa1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/opencontainers/go-digest"
|
||||
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/opencontainers/runc"
|
||||
revision = "ae2948042b08ad3d6d13cd09f40a50ffff4fc688"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Azure/go-ansiterm"
|
||||
revision = "19f72df4d05d31cbe1c56bfc8045c96babff6c7e"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/prometheus/common"
|
||||
revision = "2f17f4a9d485bf34b4bfaccc273805040e4f86c8"
|
||||
8
Makefile
8
Makefile
@@ -2,10 +2,10 @@
|
||||
.PHONY: all test dep build test-log-datastore checkfmt pull-images api-test fn-test-utils test-middleware test-extensions test-basic test-api
|
||||
|
||||
dep:
|
||||
glide install -v
|
||||
dep ensure --vendor-only
|
||||
|
||||
dep-up:
|
||||
glide up -v
|
||||
dep ensure
|
||||
|
||||
build:
|
||||
go build -o fnserver
|
||||
@@ -70,10 +70,6 @@ test-build-arm:
|
||||
run: build
|
||||
GIN_MODE=debug ./fnserver
|
||||
|
||||
docker-dep:
|
||||
# todo: need to create a dep tool image for this (or just ditch this)
|
||||
docker run --rm -it -v ${CURDIR}:/go/src/github.com/fnproject/fn -w /go/src/github.com/fnproject/fn treeder/glide install -v
|
||||
|
||||
docker-build:
|
||||
docker build --build-arg HTTPS_PROXY --build-arg HTTP_PROXY -t fnproject/fnserver:latest .
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ func CheckRegistry(ctx context.Context, image string, config docker.AuthConfigur
|
||||
|
||||
tran = &retryWrap{cm, tran}
|
||||
|
||||
repo, err := registry.NewRepository(ctx, repoNamed, regURL, tran)
|
||||
repo, err := registry.NewRepository(repoNamed, regURL, tran)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
595
glide.lock
generated
595
glide.lock
generated
@@ -1,595 +0,0 @@
|
||||
hash: 3fa5b86f68121ba1422761f2937e6a9b7f5c330adc6f84e2f3b7b78b87a747d7
|
||||
updated: 2017-12-04T17:26:34.506649Z
|
||||
imports:
|
||||
- name: github.com/amir/raidman
|
||||
version: 1ccc43bfb9c93cb401a4025e49c64ba71e5e668b
|
||||
- name: github.com/apache/thrift
|
||||
version: 4c30c15924bfbc7c9e6bfc0e82630e97980e556e
|
||||
subpackages:
|
||||
- lib/go/thrift
|
||||
- name: github.com/asaskevich/govalidator
|
||||
version: 15028e809df8c71964e8efa6c11e81d5c0262302
|
||||
- name: github.com/Azure/go-ansiterm
|
||||
version: 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
|
||||
subpackages:
|
||||
- winterm
|
||||
- name: github.com/beorn7/perks
|
||||
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||
subpackages:
|
||||
- quantile
|
||||
- name: github.com/boltdb/bolt
|
||||
version: fa5367d20c994db73282594be0146ab221657943
|
||||
- name: github.com/cactus/go-statsd-client
|
||||
version: ce77ca9ecdee1c3ffd097e32f9bb832825ccb203
|
||||
subpackages:
|
||||
- statsd
|
||||
- name: github.com/cloudflare/cfssl
|
||||
version: 7d88da830aad9d533c2fb8532da23f6a75331b52
|
||||
subpackages:
|
||||
- api
|
||||
- auth
|
||||
- certdb
|
||||
- config
|
||||
- crypto/pkcs7
|
||||
- csr
|
||||
- errors
|
||||
- helpers
|
||||
- helpers/derhelpers
|
||||
- info
|
||||
- initca
|
||||
- log
|
||||
- ocsp/config
|
||||
- signer
|
||||
- signer/local
|
||||
- name: github.com/coreos/etcd
|
||||
version: 5bb9f9591f01d0a3c61d2eb3a3bb281726005b2b
|
||||
subpackages:
|
||||
- raft/raftpb
|
||||
- name: github.com/coreos/go-semver
|
||||
version: 8ab6407b697782a06568d4b7f1db25550ec2e4c6
|
||||
subpackages:
|
||||
- semver
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/dchest/siphash
|
||||
version: 4ebf1de738443ea7f45f02dc394c4df1942a126d
|
||||
- name: github.com/dghubble/go-twitter
|
||||
version: c4115fa44a928413e0b857e0eb47376ffde3a61a
|
||||
subpackages:
|
||||
- twitter
|
||||
- name: github.com/dghubble/oauth1
|
||||
version: 7d51c10e15ca32917b32ce43f6e25840d6951db4
|
||||
- name: github.com/dgrijalva/jwt-go
|
||||
version: a539ee1a749a2b895533f979515ac7e6e0f5b650
|
||||
- name: github.com/docker/cli
|
||||
version: 139fcd3ee95f37f3ac17b1200fb0a63908cb6781
|
||||
subpackages:
|
||||
- cli/config/configfile
|
||||
- name: github.com/docker/distribution
|
||||
version: 5f6282db7d65e6d72ad7c2cc66310724a57be716
|
||||
subpackages:
|
||||
- digestset
|
||||
- manifest
|
||||
- manifest/schema1
|
||||
- manifest/schema2
|
||||
- reference
|
||||
- registry/api/errcode
|
||||
- registry/api/v2
|
||||
- registry/client
|
||||
- registry/client/auth
|
||||
- registry/client/auth/challenge
|
||||
- registry/client/transport
|
||||
- registry/storage/cache
|
||||
- registry/storage/cache/memory
|
||||
- name: github.com/docker/docker
|
||||
version: cdf870bd0b5fa678b10ef2708cca7ad776b4913c
|
||||
subpackages:
|
||||
- api/types
|
||||
- api/types/blkiodev
|
||||
- api/types/container
|
||||
- api/types/filters
|
||||
- api/types/mount
|
||||
- api/types/network
|
||||
- api/types/registry
|
||||
- api/types/strslice
|
||||
- api/types/swarm
|
||||
- api/types/swarm/runtime
|
||||
- api/types/versions
|
||||
- daemon/cluster/convert
|
||||
- opts
|
||||
- pkg/archive
|
||||
- pkg/fileutils
|
||||
- pkg/homedir
|
||||
- pkg/idtools
|
||||
- pkg/ioutils
|
||||
- pkg/jsonlog
|
||||
- pkg/jsonmessage
|
||||
- pkg/longpath
|
||||
- pkg/mount
|
||||
- pkg/namesgenerator
|
||||
- pkg/pools
|
||||
- pkg/promise
|
||||
- pkg/stdcopy
|
||||
- pkg/system
|
||||
- pkg/term
|
||||
- pkg/term/windows
|
||||
- name: github.com/docker/go-connections
|
||||
version: 3ede32e2033de7505e6500d6c868c2b9ed9f169d
|
||||
subpackages:
|
||||
- nat
|
||||
- name: github.com/docker/go-events
|
||||
version: 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||
- name: github.com/docker/go-units
|
||||
version: 0dadbb0345b35ec7ef35e228dabb8de89a65bf52
|
||||
- name: github.com/docker/libkv
|
||||
version: 93ab0e6c056d325dfbb11e1d58a3b4f5f62e7f3c
|
||||
subpackages:
|
||||
- store
|
||||
- name: github.com/docker/libnetwork
|
||||
version: 6d098467ec58038b68620a3c2c418936661efa64
|
||||
subpackages:
|
||||
- datastore
|
||||
- discoverapi
|
||||
- types
|
||||
- name: github.com/docker/libtrust
|
||||
version: aabc10ec26b754e797f9028f4589c5b7bd90dc20
|
||||
- name: github.com/docker/swarmkit
|
||||
version: bd7bafb8a61de1f5f23c8215ce7b9ecbcb30ff21
|
||||
subpackages:
|
||||
- api
|
||||
- api/deepcopy
|
||||
- api/equality
|
||||
- api/genericresource
|
||||
- api/naming
|
||||
- ca
|
||||
- connectionbroker
|
||||
- identity
|
||||
- ioutils
|
||||
- log
|
||||
- manager/raftselector
|
||||
- manager/state
|
||||
- manager/state/store
|
||||
- protobuf/plugin
|
||||
- remotes
|
||||
- watch
|
||||
- watch/queue
|
||||
- name: github.com/eapache/go-resiliency
|
||||
version: b1fe83b5b03f624450823b751b662259ffc6af70
|
||||
subpackages:
|
||||
- breaker
|
||||
- name: github.com/eapache/go-xerial-snappy
|
||||
version: bb955e01b9346ac19dc29eb16586c90ded99a98c
|
||||
- name: github.com/eapache/queue
|
||||
version: 44cc805cf13205b55f69e14bcb69867d1ae92f98
|
||||
- name: github.com/emicklei/go-restful
|
||||
version: ff4f55a206334ef123e4f79bbf348980da81ca46
|
||||
subpackages:
|
||||
- log
|
||||
- name: github.com/emicklei/go-restful-swagger12
|
||||
version: dcef7f55730566d41eae5db10e7d6981829720f6
|
||||
- name: github.com/fnproject/fn_go
|
||||
version: 7ce3bb2e624df60cdfbfc1ee5483f6df80bb2b1b
|
||||
subpackages:
|
||||
- client
|
||||
- client/apps
|
||||
- client/call
|
||||
- client/operations
|
||||
- client/routes
|
||||
- models
|
||||
- name: github.com/fsouza/go-dockerclient
|
||||
version: 98edf3edfae6a6500fecc69d2bcccf1302544004
|
||||
- name: github.com/garyburd/redigo
|
||||
version: 70e1b1943d4fc9c56791abaa6f4d1e727b9ab925
|
||||
subpackages:
|
||||
- internal
|
||||
- redis
|
||||
- name: github.com/ghodss/yaml
|
||||
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
|
||||
- name: github.com/gin-contrib/cors
|
||||
version: cf4846e6a636a76237a28d9286f163c132e841bc
|
||||
- name: github.com/gin-contrib/sse
|
||||
version: 22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae
|
||||
- name: github.com/gin-gonic/gin
|
||||
version: 5afc5b19730118c9b8324fe9dd995d44ec65c81a
|
||||
subpackages:
|
||||
- binding
|
||||
- json
|
||||
- render
|
||||
- name: github.com/go-ini/ini
|
||||
version: c787282c39ac1fc618827141a1f762240def08a3
|
||||
- name: github.com/go-logfmt/logfmt
|
||||
version: 390ab7935ee28ec6b286364bba9b4dd6410cb3d5
|
||||
- name: github.com/go-openapi/analysis
|
||||
version: 8ed83f2ea9f00f945516462951a288eaa68bf0d6
|
||||
- name: github.com/go-openapi/errors
|
||||
version: 03cfca65330da08a5a440053faf994a3c682b5bf
|
||||
- name: github.com/go-openapi/jsonpointer
|
||||
version: 779f45308c19820f1a69e9a4cd965f496e0da10f
|
||||
- name: github.com/go-openapi/jsonreference
|
||||
version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272
|
||||
- name: github.com/go-openapi/loads
|
||||
version: a80dea3052f00e5f032e860dd7355cd0cc67e24d
|
||||
subpackages:
|
||||
- fmts
|
||||
- name: github.com/go-openapi/runtime
|
||||
version: d6605b7c17ac3b1033ca794886e6142a4141f5b0
|
||||
subpackages:
|
||||
- client
|
||||
- name: github.com/go-openapi/spec
|
||||
version: 3faa0055dbbf2110abc1f3b4e3adbb22721e96e7
|
||||
- name: github.com/go-openapi/strfmt
|
||||
version: 610b6cacdcde6852f4de68998bd20ce1dac85b22
|
||||
- name: github.com/go-openapi/swag
|
||||
version: f3f9494671f93fcff853e3c6e9e948b3eb71e590
|
||||
- name: github.com/go-openapi/validate
|
||||
version: 8a82927c942c94794a5cd8b8b50ce2f48a955c0c
|
||||
- name: github.com/go-sql-driver/mysql
|
||||
version: 21d7e97c9f760ca685a01ecea202e1c84276daa1
|
||||
- name: github.com/gogo/protobuf
|
||||
version: c0656edd0d9eab7c66d1eb0c568f9039345796f7
|
||||
subpackages:
|
||||
- gogoproto
|
||||
- proto
|
||||
- protoc-gen-gogo/descriptor
|
||||
- sortkeys
|
||||
- types
|
||||
- name: github.com/golang/glog
|
||||
version: 44145f04b68cf362d9c4df2182967c2275eaefed
|
||||
- name: github.com/golang/protobuf
|
||||
version: 4bd1920723d7b7c925de087aa32e2187708897f7
|
||||
subpackages:
|
||||
- proto
|
||||
- ptypes/any
|
||||
- name: github.com/golang/snappy
|
||||
version: 553a641470496b2327abcac10b36396bd98e45c9
|
||||
- name: github.com/google/btree
|
||||
version: 316fb6d3f031ae8f4d457c6c5186b9e3ded70435
|
||||
- name: github.com/google/certificate-transparency-go
|
||||
version: 0dac42a6ed448ba220ee315abfaa6d26fd5fc9bb
|
||||
repo: https://github.com/google/certificate-transparency-go
|
||||
subpackages:
|
||||
- asn1
|
||||
- client
|
||||
- jsonclient
|
||||
- tls
|
||||
- x509
|
||||
- x509/pkix
|
||||
- name: github.com/google/gofuzz
|
||||
version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
|
||||
- name: github.com/gorilla/context
|
||||
version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
|
||||
- name: github.com/gorilla/mux
|
||||
version: 24fca303ac6da784b9e8269f724ddeb0b2eea5e7
|
||||
- name: github.com/grpc-ecosystem/go-grpc-prometheus
|
||||
version: 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
||||
- name: github.com/hashicorp/go-immutable-radix
|
||||
version: 8aac2701530899b64bdea735a1de8da899815220
|
||||
- name: github.com/hashicorp/go-memdb
|
||||
version: ec43fcf8f202880feb35d2abb40a570c1f4172e9
|
||||
- name: github.com/hashicorp/golang-lru
|
||||
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
|
||||
subpackages:
|
||||
- simplelru
|
||||
- name: github.com/jmoiron/jsonq
|
||||
version: e874b168d07ecc7808bc950a17998a8aa3141d82
|
||||
- name: github.com/jmoiron/sqlx
|
||||
version: d9bd385d68c068f1fabb5057e3dedcbcbb039d0f
|
||||
subpackages:
|
||||
- reflectx
|
||||
- name: github.com/json-iterator/go
|
||||
version: fdfe0b9a69118ff692d6e1005e9de7e0cffb7d6b
|
||||
- name: github.com/juju/ratelimit
|
||||
version: 5b9ff866471762aa2ab2dced63c9fb6f53921342
|
||||
- name: github.com/kr/logfmt
|
||||
version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0
|
||||
- name: github.com/lib/pq
|
||||
version: 23da1db4f16d9658a86ae9b717c245fc078f10f1
|
||||
subpackages:
|
||||
- oid
|
||||
- name: github.com/mailru/easyjson
|
||||
version: 32fa128f234d041f196a9f3e0fea5ac9772c08e1
|
||||
subpackages:
|
||||
- buffer
|
||||
- jlexer
|
||||
- jwriter
|
||||
- name: github.com/mattes/migrate
|
||||
version: 5b98c13eff7657ab49a1a5f705b72f961d7fc558
|
||||
subpackages:
|
||||
- database
|
||||
- source
|
||||
- name: github.com/mattn/go-isatty
|
||||
version: fc9e8d8ef48496124e79ae0df75490096eccf6fe
|
||||
- name: github.com/mattn/go-sqlite3
|
||||
version: 05548ff55570cdb9ac72ff4a25a3b5e77a6fb7e5
|
||||
- name: github.com/matttproud/golang_protobuf_extensions
|
||||
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
|
||||
subpackages:
|
||||
- pbutil
|
||||
- name: github.com/Microsoft/go-winio
|
||||
version: 78439966b38d69bf38227fbf57ac8a6fee70f69a
|
||||
- name: github.com/minio/go-homedir
|
||||
version: 21304a94172ae3a09dee2cd86a12fb6f842138c7
|
||||
- name: github.com/minio/minio-go
|
||||
version: a62e2045a5d3a6630dbb7040260994583ac56b10
|
||||
subpackages:
|
||||
- pkg/credentials
|
||||
- pkg/encrypt
|
||||
- pkg/policy
|
||||
- pkg/s3signer
|
||||
- pkg/s3utils
|
||||
- pkg/set
|
||||
- name: github.com/mitchellh/mapstructure
|
||||
version: d0303fe809921458f417bcf828397a65db30a7e4
|
||||
- name: github.com/Nvveen/Gotty
|
||||
version: cd527374f1e5bff4938207604a14f2e38a9cf512
|
||||
- name: github.com/opencontainers/go-digest
|
||||
version: 279bed98673dd5bef374d3b6e4b09e2af76183bf
|
||||
- name: github.com/opencontainers/image-spec
|
||||
version: ebd93fd0782379ca3d821f0fa74f0651a9347a3e
|
||||
subpackages:
|
||||
- specs-go
|
||||
- specs-go/v1
|
||||
- name: github.com/opencontainers/runc
|
||||
version: ae2948042b08ad3d6d13cd09f40a50ffff4fc688
|
||||
subpackages:
|
||||
- libcontainer/system
|
||||
- libcontainer/user
|
||||
- name: github.com/opentracing-contrib/go-observer
|
||||
version: a52f2342449246d5bcc273e65cbdcfa5f7d6c63c
|
||||
- name: github.com/opentracing/opentracing-go
|
||||
version: 8ebe5d4e236eed9fd88e593c288bfb804d630b8c
|
||||
subpackages:
|
||||
- ext
|
||||
- log
|
||||
- name: github.com/openzipkin/zipkin-go-opentracing
|
||||
version: 9c88fa03bfdfaa5fec7cd1b40f3d10ec15c15fc6
|
||||
subpackages:
|
||||
- flag
|
||||
- thrift/gen-go/scribe
|
||||
- thrift/gen-go/zipkincore
|
||||
- types
|
||||
- wire
|
||||
- name: github.com/patrickmn/go-cache
|
||||
version: a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0
|
||||
- name: github.com/pierrec/lz4
|
||||
version: 08c27939df1bd95e881e2c2367a749964ad1fceb
|
||||
- name: github.com/pierrec/xxHash
|
||||
version: a0006b13c722f7f12368c00a3d3c2ae8a999a0c6
|
||||
subpackages:
|
||||
- xxHash32
|
||||
- name: github.com/pkg/errors
|
||||
version: 2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb
|
||||
- name: github.com/prometheus/client_golang
|
||||
version: c5b7fccd204277076155f10851dad72b76a49317
|
||||
subpackages:
|
||||
- prometheus
|
||||
- prometheus/promhttp
|
||||
- name: github.com/prometheus/client_model
|
||||
version: 6f3806018612930941127f2a7c6c453ba2c527d2
|
||||
subpackages:
|
||||
- go
|
||||
- name: github.com/prometheus/common
|
||||
version: 2f17f4a9d485bf34b4bfaccc273805040e4f86c8
|
||||
subpackages:
|
||||
- expfmt
|
||||
- internal/bitbucket.org/ww/goautoneg
|
||||
- model
|
||||
- name: github.com/prometheus/procfs
|
||||
version: a1dba9ce8baed984a2495b658c82687f8157b98f
|
||||
subpackages:
|
||||
- xfs
|
||||
- name: github.com/PuerkitoBio/purell
|
||||
version: 8a290539e2e8629dbc4e6bad948158f790ec31f4
|
||||
- name: github.com/PuerkitoBio/urlesc
|
||||
version: 5bd2802263f21d8788851d5305584c82a5c75d7e
|
||||
- name: github.com/rcrowley/go-metrics
|
||||
version: 1f30fe9094a513ce4c700b9a54458bbb0c96996c
|
||||
- name: github.com/rdallman/migrate
|
||||
version: bc72eeb997c7334cb5f05f5aefd2d70bc34d71ef
|
||||
subpackages:
|
||||
- database/mysql
|
||||
- database/postgres
|
||||
- database/sqlite3
|
||||
- source
|
||||
- source/go-bindata
|
||||
- name: github.com/Shopify/sarama
|
||||
version: 4704a3a8c95920361c47e9a2adec13c3d757c757
|
||||
- name: github.com/sirupsen/logrus
|
||||
version: 89742aefa4b206dcf400792f3bd35b542998eb3b
|
||||
subpackages:
|
||||
- hooks/syslog
|
||||
- name: github.com/spf13/pflag
|
||||
version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7
|
||||
- name: github.com/ugorji/go
|
||||
version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74
|
||||
subpackages:
|
||||
- codec
|
||||
- name: golang.org/x/crypto
|
||||
version: 94eea52f7b742c7cbe0b03b22f0c4c8631ece122
|
||||
subpackages:
|
||||
- ocsp
|
||||
- pkcs12
|
||||
- pkcs12/internal/rc2
|
||||
- ssh/terminal
|
||||
- name: golang.org/x/net
|
||||
version: a8b9294777976932365dabb6640cf1468d95c70f
|
||||
subpackages:
|
||||
- context
|
||||
- context/ctxhttp
|
||||
- http2
|
||||
- http2/hpack
|
||||
- idna
|
||||
- internal/timeseries
|
||||
- lex/httplex
|
||||
- trace
|
||||
- name: golang.org/x/sys
|
||||
version: 8b4580aae2a0dd0c231a45d3ccb8434ff533b840
|
||||
subpackages:
|
||||
- unix
|
||||
- windows
|
||||
- name: golang.org/x/text
|
||||
version: 57961680700a5336d15015c8c50686ca5ba362a4
|
||||
subpackages:
|
||||
- cases
|
||||
- internal
|
||||
- internal/tag
|
||||
- language
|
||||
- runes
|
||||
- secure/bidirule
|
||||
- secure/precis
|
||||
- transform
|
||||
- unicode/bidi
|
||||
- unicode/norm
|
||||
- width
|
||||
- name: google.golang.org/genproto
|
||||
version: 09f6ed296fc66555a25fe4ce95173148778dfa85
|
||||
subpackages:
|
||||
- googleapis/rpc/status
|
||||
- name: google.golang.org/grpc
|
||||
version: b8669c35455183da6d5c474ea6e72fbf55183274
|
||||
subpackages:
|
||||
- codes
|
||||
- credentials
|
||||
- grpclb/grpc_lb_v1
|
||||
- grpclog
|
||||
- internal
|
||||
- keepalive
|
||||
- metadata
|
||||
- naming
|
||||
- peer
|
||||
- stats
|
||||
- status
|
||||
- tap
|
||||
- transport
|
||||
- name: gopkg.in/go-playground/validator.v8
|
||||
version: 5f1438d3fca68893a817e4a66806cea46a9e4ebf
|
||||
- name: gopkg.in/inf.v0
|
||||
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
||||
- name: gopkg.in/mgo.v2
|
||||
version: 3f83fa5005286a7fe593b055f0d7771a7dce4655
|
||||
subpackages:
|
||||
- bson
|
||||
- internal/json
|
||||
- name: gopkg.in/yaml.v2
|
||||
version: 53feefa2559fb8dfa8d81baad31be332c97d6c77
|
||||
- name: k8s.io/apimachinery
|
||||
version: 1fd2e63a9a370677308a42f24fd40c86438afddf
|
||||
subpackages:
|
||||
- pkg/api/equality
|
||||
- pkg/api/errors
|
||||
- pkg/api/meta
|
||||
- pkg/api/resource
|
||||
- pkg/apimachinery
|
||||
- pkg/apimachinery/announced
|
||||
- pkg/apimachinery/registered
|
||||
- pkg/apis/meta/v1
|
||||
- pkg/apis/meta/v1/unstructured
|
||||
- pkg/apis/meta/v1alpha1
|
||||
- pkg/conversion
|
||||
- pkg/conversion/queryparams
|
||||
- pkg/conversion/unstructured
|
||||
- pkg/fields
|
||||
- pkg/labels
|
||||
- pkg/openapi
|
||||
- pkg/runtime
|
||||
- pkg/runtime/schema
|
||||
- pkg/runtime/serializer
|
||||
- pkg/runtime/serializer/json
|
||||
- pkg/runtime/serializer/protobuf
|
||||
- pkg/runtime/serializer/recognizer
|
||||
- pkg/runtime/serializer/streaming
|
||||
- pkg/runtime/serializer/versioning
|
||||
- pkg/selection
|
||||
- pkg/types
|
||||
- pkg/util/clock
|
||||
- pkg/util/diff
|
||||
- pkg/util/errors
|
||||
- pkg/util/framer
|
||||
- pkg/util/intstr
|
||||
- pkg/util/json
|
||||
- pkg/util/net
|
||||
- pkg/util/rand
|
||||
- pkg/util/runtime
|
||||
- pkg/util/sets
|
||||
- pkg/util/validation
|
||||
- pkg/util/validation/field
|
||||
- pkg/util/wait
|
||||
- pkg/util/yaml
|
||||
- pkg/version
|
||||
- pkg/watch
|
||||
- third_party/forked/golang/reflect
|
||||
- name: k8s.io/client-go
|
||||
version: d92e8497f71b7b4e0494e5bd204b48d34bd6f254
|
||||
subpackages:
|
||||
- discovery
|
||||
- kubernetes
|
||||
- kubernetes/scheme
|
||||
- kubernetes/typed/admissionregistration/v1alpha1
|
||||
- kubernetes/typed/apps/v1beta1
|
||||
- kubernetes/typed/authentication/v1
|
||||
- kubernetes/typed/authentication/v1beta1
|
||||
- kubernetes/typed/authorization/v1
|
||||
- kubernetes/typed/authorization/v1beta1
|
||||
- kubernetes/typed/autoscaling/v1
|
||||
- kubernetes/typed/autoscaling/v2alpha1
|
||||
- kubernetes/typed/batch/v1
|
||||
- kubernetes/typed/batch/v2alpha1
|
||||
- kubernetes/typed/certificates/v1beta1
|
||||
- kubernetes/typed/core/v1
|
||||
- kubernetes/typed/extensions/v1beta1
|
||||
- kubernetes/typed/networking/v1
|
||||
- kubernetes/typed/policy/v1beta1
|
||||
- kubernetes/typed/rbac/v1alpha1
|
||||
- kubernetes/typed/rbac/v1beta1
|
||||
- kubernetes/typed/settings/v1alpha1
|
||||
- kubernetes/typed/storage/v1
|
||||
- kubernetes/typed/storage/v1beta1
|
||||
- pkg/api
|
||||
- pkg/api/v1
|
||||
- pkg/api/v1/ref
|
||||
- pkg/apis/admissionregistration
|
||||
- pkg/apis/admissionregistration/v1alpha1
|
||||
- pkg/apis/apps
|
||||
- pkg/apis/apps/v1beta1
|
||||
- pkg/apis/authentication
|
||||
- pkg/apis/authentication/v1
|
||||
- pkg/apis/authentication/v1beta1
|
||||
- pkg/apis/authorization
|
||||
- pkg/apis/authorization/v1
|
||||
- pkg/apis/authorization/v1beta1
|
||||
- pkg/apis/autoscaling
|
||||
- pkg/apis/autoscaling/v1
|
||||
- pkg/apis/autoscaling/v2alpha1
|
||||
- pkg/apis/batch
|
||||
- pkg/apis/batch/v1
|
||||
- pkg/apis/batch/v2alpha1
|
||||
- pkg/apis/certificates
|
||||
- pkg/apis/certificates/v1beta1
|
||||
- pkg/apis/extensions
|
||||
- pkg/apis/extensions/v1beta1
|
||||
- pkg/apis/networking
|
||||
- pkg/apis/networking/v1
|
||||
- pkg/apis/policy
|
||||
- pkg/apis/policy/v1beta1
|
||||
- pkg/apis/rbac
|
||||
- pkg/apis/rbac/v1alpha1
|
||||
- pkg/apis/rbac/v1beta1
|
||||
- pkg/apis/settings
|
||||
- pkg/apis/settings/v1alpha1
|
||||
- pkg/apis/storage
|
||||
- pkg/apis/storage/v1
|
||||
- pkg/apis/storage/v1beta1
|
||||
- pkg/util
|
||||
- pkg/util/parsers
|
||||
- pkg/version
|
||||
- rest
|
||||
- rest/watch
|
||||
- tools/clientcmd/api
|
||||
- tools/metrics
|
||||
- transport
|
||||
- util/cert
|
||||
- util/flowcontrol
|
||||
- util/integer
|
||||
testImports: []
|
||||
94
glide.yaml
94
glide.yaml
@@ -1,94 +0,0 @@
|
||||
package: github.com/fnproject/fn
|
||||
excludeDirs:
|
||||
- cli
|
||||
import:
|
||||
- package: golang.org/x/crypto
|
||||
version: master
|
||||
subpackages:
|
||||
- pkcs12
|
||||
- package: github.com/fnproject/fn_go
|
||||
version: ^0.2.0
|
||||
subpackages:
|
||||
- models
|
||||
- package: github.com/sirupsen/logrus
|
||||
version: 89742aefa4b206dcf400792f3bd35b542998eb3b
|
||||
- package: github.com/amir/raidman
|
||||
- package: github.com/boltdb/bolt
|
||||
- package: github.com/cactus/go-statsd-client
|
||||
subpackages:
|
||||
- statsd
|
||||
- package: github.com/dchest/siphash
|
||||
- package: github.com/dghubble/go-twitter
|
||||
subpackages:
|
||||
- twitter
|
||||
- package: github.com/dghubble/oauth1
|
||||
- package: github.com/dgrijalva/jwt-go
|
||||
- package: github.com/docker/cli
|
||||
version: 139fcd3ee95f37f3ac17b1200fb0a63908cb6781
|
||||
subpackages:
|
||||
- cli/config/configfile
|
||||
- package: github.com/docker/distribution
|
||||
version: 5f6282db7d65e6d72ad7c2cc66310724a57be716
|
||||
- package: github.com/fsouza/go-dockerclient
|
||||
- package: github.com/garyburd/redigo
|
||||
subpackages:
|
||||
- redis
|
||||
- package: github.com/gin-gonic/gin
|
||||
- package: github.com/rdallman/migrate
|
||||
version: bc72eeb997c7334cb5f05f5aefd2d70bc34d71ef
|
||||
- package: github.com/go-openapi/errors
|
||||
- package: github.com/go-openapi/loads
|
||||
subpackages:
|
||||
- fmts
|
||||
- package: github.com/go-openapi/runtime
|
||||
subpackages:
|
||||
- client
|
||||
- package: github.com/go-openapi/spec
|
||||
- package: github.com/go-openapi/strfmt
|
||||
- package: github.com/go-openapi/swag
|
||||
- package: github.com/go-openapi/validate
|
||||
- package: github.com/go-sql-driver/mysql
|
||||
version: 21d7e97c9f760ca685a01ecea202e1c84276daa1
|
||||
- package: github.com/google/btree
|
||||
- package: github.com/jmoiron/jsonq
|
||||
- package: github.com/lib/pq
|
||||
- package: github.com/docker/docker
|
||||
version: cdf870bd0b5fa678b10ef2708cca7ad776b4913c
|
||||
- package: github.com/pkg/errors
|
||||
- package: github.com/jmoiron/sqlx
|
||||
- package: github.com/mattn/go-sqlite3
|
||||
- package: github.com/minio/minio-go
|
||||
- package: github.com/opentracing/opentracing-go
|
||||
- package: github.com/openzipkin/zipkin-go-opentracing
|
||||
- package: github.com/opencontainers/go-digest
|
||||
version: 279bed98673dd5bef374d3b6e4b09e2af76183bf
|
||||
- package: github.com/opencontainers/runc
|
||||
version: ae2948042b08ad3d6d13cd09f40a50ffff4fc688
|
||||
- package: github.com/Azure/go-ansiterm
|
||||
version: 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
|
||||
- package: github.com/prometheus/common
|
||||
version: 2f17f4a9d485bf34b4bfaccc273805040e4f86c8
|
||||
- package: github.com/prometheus/client_golang
|
||||
- package: github.com/gin-contrib/cors
|
||||
version: ~1.2.0
|
||||
- package: k8s.io/client-go
|
||||
version: ^v4.0.0
|
||||
subpackages:
|
||||
- kubernetes
|
||||
- package: github.com/emicklei/go-restful-swagger12
|
||||
- package: golang.org/x/sys
|
||||
version: master
|
||||
subpackages:
|
||||
- unix
|
||||
- package: golang.org/x/net
|
||||
version: master
|
||||
subpackages:
|
||||
- http2
|
||||
- package: golang.org/x/text
|
||||
version: master
|
||||
- package: github.com/mailru/easyjson
|
||||
version: master
|
||||
subpackages:
|
||||
- jwriter
|
||||
testImport:
|
||||
- package: github.com/patrickmn/go-cache
|
||||
73
vendor/github.com/amir/raidman/README.md
generated
vendored
73
vendor/github.com/amir/raidman/README.md
generated
vendored
@@ -1,73 +0,0 @@
|
||||
Raidman
|
||||
=======
|
||||
|
||||
Go Riemann client
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/amir/raidman"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c, err := raidman.Dial("tcp", "localhost:5555")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var event = &raidman.Event{
|
||||
State: "success",
|
||||
Host: "raidman",
|
||||
Service: "raidman-sample",
|
||||
Metric: 100,
|
||||
Ttl: 10,
|
||||
}
|
||||
|
||||
// send one event
|
||||
err = c.Send(event)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// send multiple events at once
|
||||
err = c.SendMulti([]*raidman.Event{
|
||||
&raidman.Event{
|
||||
State: "success",
|
||||
Host: "raidman",
|
||||
Service: "raidman-sample",
|
||||
Metric: 100,
|
||||
Ttl: 10,
|
||||
},
|
||||
&raidman.Event{
|
||||
State: "failure",
|
||||
Host: "raidman",
|
||||
Service: "raidman-sample",
|
||||
Metric: 100,
|
||||
Ttl: 10,
|
||||
},
|
||||
&raidman.Event{
|
||||
State: "success",
|
||||
Host: "raidman",
|
||||
Service: "raidman-sample",
|
||||
Metric: 100,
|
||||
Ttl: 10,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
events, err := c.Query("host = \"raidman\"")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(events) < 1 {
|
||||
panic("Submitted event not found")
|
||||
}
|
||||
|
||||
c.Close()
|
||||
}
|
||||
|
||||
```
|
||||
24
vendor/github.com/amir/raidman/UNLICENSE
generated
vendored
24
vendor/github.com/amir/raidman/UNLICENSE
generated
vendored
@@ -1,24 +0,0 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
6
vendor/github.com/amir/raidman/proto/Makefile
generated
vendored
6
vendor/github.com/amir/raidman/proto/Makefile
generated
vendored
@@ -1,6 +0,0 @@
|
||||
proto.pb.go: proto.proto
|
||||
mkdir -p _pb
|
||||
protoc --go_out=_pb $<
|
||||
cat _pb/$@\
|
||||
|gofmt >$@
|
||||
rm -rf _pb
|
||||
273
vendor/github.com/amir/raidman/proto/proto.pb.go
generated
vendored
273
vendor/github.com/amir/raidman/proto/proto.pb.go
generated
vendored
@@ -1,273 +0,0 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: proto.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
package proto
|
||||
|
||||
import proto1 "github.com/golang/protobuf/proto"
|
||||
import json "encoding/json"
|
||||
import math "math"
|
||||
|
||||
// Reference proto, json, and math imports to suppress error if they are not otherwise used.
|
||||
var _ = proto1.Marshal
|
||||
var _ = &json.SyntaxError{}
|
||||
var _ = math.Inf
|
||||
|
||||
type State struct {
|
||||
Time *int64 `protobuf:"varint,1,opt,name=time" json:"time,omitempty"`
|
||||
State *string `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"`
|
||||
Service *string `protobuf:"bytes,3,opt,name=service" json:"service,omitempty"`
|
||||
Host *string `protobuf:"bytes,4,opt,name=host" json:"host,omitempty"`
|
||||
Description *string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"`
|
||||
Once *bool `protobuf:"varint,6,opt,name=once" json:"once,omitempty"`
|
||||
Tags []string `protobuf:"bytes,7,rep,name=tags" json:"tags,omitempty"`
|
||||
Ttl *float32 `protobuf:"fixed32,8,opt,name=ttl" json:"ttl,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (this *State) Reset() { *this = State{} }
|
||||
func (this *State) String() string { return proto1.CompactTextString(this) }
|
||||
func (*State) ProtoMessage() {}
|
||||
|
||||
func (this *State) GetTime() int64 {
|
||||
if this != nil && this.Time != nil {
|
||||
return *this.Time
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *State) GetState() string {
|
||||
if this != nil && this.State != nil {
|
||||
return *this.State
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *State) GetService() string {
|
||||
if this != nil && this.Service != nil {
|
||||
return *this.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *State) GetHost() string {
|
||||
if this != nil && this.Host != nil {
|
||||
return *this.Host
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *State) GetDescription() string {
|
||||
if this != nil && this.Description != nil {
|
||||
return *this.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *State) GetOnce() bool {
|
||||
if this != nil && this.Once != nil {
|
||||
return *this.Once
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *State) GetTags() []string {
|
||||
if this != nil {
|
||||
return this.Tags
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *State) GetTtl() float32 {
|
||||
if this != nil && this.Ttl != nil {
|
||||
return *this.Ttl
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
Time *int64 `protobuf:"varint,1,opt,name=time" json:"time,omitempty"`
|
||||
State *string `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"`
|
||||
Service *string `protobuf:"bytes,3,opt,name=service" json:"service,omitempty"`
|
||||
Host *string `protobuf:"bytes,4,opt,name=host" json:"host,omitempty"`
|
||||
Description *string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"`
|
||||
Tags []string `protobuf:"bytes,7,rep,name=tags" json:"tags,omitempty"`
|
||||
Ttl *float32 `protobuf:"fixed32,8,opt,name=ttl" json:"ttl,omitempty"`
|
||||
Attributes []*Attribute `protobuf:"bytes,9,rep,name=attributes" json:"attributes,omitempty"`
|
||||
MetricSint64 *int64 `protobuf:"zigzag64,13,opt,name=metric_sint64" json:"metric_sint64,omitempty"`
|
||||
MetricD *float64 `protobuf:"fixed64,14,opt,name=metric_d" json:"metric_d,omitempty"`
|
||||
MetricF *float32 `protobuf:"fixed32,15,opt,name=metric_f" json:"metric_f,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (this *Event) Reset() { *this = Event{} }
|
||||
func (this *Event) String() string { return proto1.CompactTextString(this) }
|
||||
func (*Event) ProtoMessage() {}
|
||||
|
||||
func (this *Event) GetTime() int64 {
|
||||
if this != nil && this.Time != nil {
|
||||
return *this.Time
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *Event) GetState() string {
|
||||
if this != nil && this.State != nil {
|
||||
return *this.State
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Event) GetService() string {
|
||||
if this != nil && this.Service != nil {
|
||||
return *this.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Event) GetHost() string {
|
||||
if this != nil && this.Host != nil {
|
||||
return *this.Host
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Event) GetDescription() string {
|
||||
if this != nil && this.Description != nil {
|
||||
return *this.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Event) GetTags() []string {
|
||||
if this != nil {
|
||||
return this.Tags
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Event) GetTtl() float32 {
|
||||
if this != nil && this.Ttl != nil {
|
||||
return *this.Ttl
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *Event) GetAttributes() []*Attribute {
|
||||
if this != nil {
|
||||
return this.Attributes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Event) GetMetricSint64() int64 {
|
||||
if this != nil && this.MetricSint64 != nil {
|
||||
return *this.MetricSint64
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *Event) GetMetricD() float64 {
|
||||
if this != nil && this.MetricD != nil {
|
||||
return *this.MetricD
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *Event) GetMetricF() float32 {
|
||||
if this != nil && this.MetricF != nil {
|
||||
return *this.MetricF
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
String_ *string `protobuf:"bytes,1,opt,name=string" json:"string,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (this *Query) Reset() { *this = Query{} }
|
||||
func (this *Query) String() string { return proto1.CompactTextString(this) }
|
||||
func (*Query) ProtoMessage() {}
|
||||
|
||||
func (this *Query) GetString_() string {
|
||||
if this != nil && this.String_ != nil {
|
||||
return *this.String_
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Msg struct {
|
||||
Ok *bool `protobuf:"varint,2,opt,name=ok" json:"ok,omitempty"`
|
||||
Error *string `protobuf:"bytes,3,opt,name=error" json:"error,omitempty"`
|
||||
States []*State `protobuf:"bytes,4,rep,name=states" json:"states,omitempty"`
|
||||
Query *Query `protobuf:"bytes,5,opt,name=query" json:"query,omitempty"`
|
||||
Events []*Event `protobuf:"bytes,6,rep,name=events" json:"events,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (this *Msg) Reset() { *this = Msg{} }
|
||||
func (this *Msg) String() string { return proto1.CompactTextString(this) }
|
||||
func (*Msg) ProtoMessage() {}
|
||||
|
||||
func (this *Msg) GetOk() bool {
|
||||
if this != nil && this.Ok != nil {
|
||||
return *this.Ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *Msg) GetError() string {
|
||||
if this != nil && this.Error != nil {
|
||||
return *this.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Msg) GetStates() []*State {
|
||||
if this != nil {
|
||||
return this.States
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Msg) GetQuery() *Query {
|
||||
if this != nil {
|
||||
return this.Query
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Msg) GetEvents() []*Event {
|
||||
if this != nil {
|
||||
return this.Events
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Attribute struct {
|
||||
Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
|
||||
Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (this *Attribute) Reset() { *this = Attribute{} }
|
||||
func (this *Attribute) String() string { return proto1.CompactTextString(this) }
|
||||
func (*Attribute) ProtoMessage() {}
|
||||
|
||||
func (this *Attribute) GetKey() string {
|
||||
if this != nil && this.Key != nil {
|
||||
return *this.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (this *Attribute) GetValue() string {
|
||||
if this != nil && this.Value != nil {
|
||||
return *this.Value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
}
|
||||
45
vendor/github.com/amir/raidman/proto/proto.proto
generated
vendored
45
vendor/github.com/amir/raidman/proto/proto.proto
generated
vendored
@@ -1,45 +0,0 @@
|
||||
option java_package = "com.aphyr.riemann";
|
||||
option java_outer_classname = "Proto";
|
||||
|
||||
message State {
|
||||
optional int64 time = 1;
|
||||
optional string state = 2;
|
||||
optional string service = 3;
|
||||
optional string host = 4;
|
||||
optional string description = 5;
|
||||
optional bool once = 6;
|
||||
repeated string tags = 7;
|
||||
optional float ttl = 8;
|
||||
}
|
||||
|
||||
message Event {
|
||||
optional int64 time = 1;
|
||||
optional string state = 2;
|
||||
optional string service = 3;
|
||||
optional string host = 4;
|
||||
optional string description = 5;
|
||||
repeated string tags = 7;
|
||||
optional float ttl = 8;
|
||||
repeated Attribute attributes = 9;
|
||||
|
||||
optional sint64 metric_sint64 = 13;
|
||||
optional double metric_d = 14;
|
||||
optional float metric_f = 15;
|
||||
}
|
||||
|
||||
message Query {
|
||||
optional string string = 1;
|
||||
}
|
||||
|
||||
message Msg {
|
||||
optional bool ok = 2;
|
||||
optional string error = 3;
|
||||
repeated State states = 4;
|
||||
optional Query query = 5;
|
||||
repeated Event events = 6;
|
||||
}
|
||||
|
||||
message Attribute {
|
||||
required string key = 1;
|
||||
optional string value = 2;
|
||||
}
|
||||
341
vendor/github.com/amir/raidman/raidman.go
generated
vendored
341
vendor/github.com/amir/raidman/raidman.go
generated
vendored
@@ -1,341 +0,0 @@
|
||||
// Go Riemann client
|
||||
package raidman
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/amir/raidman/proto"
|
||||
pb "github.com/golang/protobuf/proto"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
type network interface {
|
||||
Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
|
||||
}
|
||||
|
||||
type tcp struct{}
|
||||
|
||||
type udp struct{}
|
||||
|
||||
// Client represents a connection to a Riemann server
|
||||
type Client struct {
|
||||
sync.Mutex
|
||||
net network
|
||||
connection net.Conn
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// An Event represents a single Riemann event
|
||||
type Event struct {
|
||||
Ttl float32 `json:"ttl,omitempty"`
|
||||
Time int64 `json:"time,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Host string `json:"host,omitempty"` // Defaults to os.Hostname()
|
||||
State string `json:"state,omitempty"`
|
||||
Service string `json:"service,omitempty"`
|
||||
Metric interface{} `json:"metric,omitempty"` // Could be Int, Float32, Float64
|
||||
Description string `json:"description,omitempty"`
|
||||
Attributes map[string]string `json:"attributes,omitempty"`
|
||||
}
|
||||
|
||||
// Dial establishes a connection to a Riemann server at addr, on the network
|
||||
// netwrk, with a timeout of timeout
|
||||
//
|
||||
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
|
||||
func DialWithTimeout(netwrk, addr string, timeout time.Duration) (c *Client, err error) {
|
||||
c = new(Client)
|
||||
|
||||
var cnet network
|
||||
switch netwrk {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
cnet = new(tcp)
|
||||
case "udp", "udp4", "udp6":
|
||||
cnet = new(udp)
|
||||
default:
|
||||
return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
|
||||
}
|
||||
|
||||
dialer, err := newDialer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.net = cnet
|
||||
c.timeout = timeout
|
||||
c.connection, err = dialer.Dial(netwrk, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func newDialer() (proxy.Dialer, error) {
|
||||
var proxyUrl = os.Getenv("RIEMANN_PROXY")
|
||||
var dialer proxy.Dialer = proxy.Direct
|
||||
|
||||
// Get a proxy Dialer that will create the connection on our
|
||||
// behalf via the SOCKS5 proxy. Specify the authentication
|
||||
// and re-create the dialer/transport/client if tor's
|
||||
// IsolateSOCKSAuth is needed.
|
||||
if len(proxyUrl) > 0 {
|
||||
u, err := url.Parse(proxyUrl)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to obtain proxy dialer: %v\n", err)
|
||||
}
|
||||
if dialer, err = proxy.FromURL(u, dialer); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse " + proxyUrl + " as a proxy: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return dialer, nil
|
||||
}
|
||||
|
||||
// Dial establishes a connection to a Riemann server at addr, on the network
|
||||
// netwrk.
|
||||
//
|
||||
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
|
||||
func Dial(netwrk, addr string) (c *Client, err error) {
|
||||
return DialWithTimeout(netwrk, addr, 0)
|
||||
}
|
||||
|
||||
func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
|
||||
msg := &proto.Msg{}
|
||||
data, err := pb.Marshal(message)
|
||||
if err != nil {
|
||||
return msg, err
|
||||
}
|
||||
b := new(bytes.Buffer)
|
||||
if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
|
||||
return msg, err
|
||||
}
|
||||
if _, err = conn.Write(b.Bytes()); err != nil {
|
||||
return msg, err
|
||||
}
|
||||
if _, err = conn.Write(data); err != nil {
|
||||
return msg, err
|
||||
}
|
||||
var header uint32
|
||||
if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
|
||||
return msg, err
|
||||
}
|
||||
response := make([]byte, header)
|
||||
if err = readFully(conn, response); err != nil {
|
||||
return msg, err
|
||||
}
|
||||
if err = pb.Unmarshal(response, msg); err != nil {
|
||||
return msg, err
|
||||
}
|
||||
if msg.GetOk() != true {
|
||||
return msg, errors.New(msg.GetError())
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
func readFully(r io.Reader, p []byte) error {
|
||||
for len(p) > 0 {
|
||||
n, err := r.Read(p)
|
||||
p = p[n:]
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
|
||||
data, err := pb.Marshal(message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = conn.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func isZero(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Map:
|
||||
return v.IsNil()
|
||||
case reflect.Slice:
|
||||
zero := true
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
zero = zero && isZero(v.Index(i))
|
||||
}
|
||||
return zero
|
||||
}
|
||||
zero := reflect.Zero(v.Type())
|
||||
return v.Interface() == zero.Interface()
|
||||
}
|
||||
|
||||
func eventToPbEvent(event *Event) (*proto.Event, error) {
|
||||
var e proto.Event
|
||||
|
||||
if event.Host == "" {
|
||||
event.Host, _ = os.Hostname()
|
||||
}
|
||||
t := reflect.ValueOf(&e).Elem()
|
||||
s := reflect.ValueOf(event).Elem()
|
||||
typeOfEvent := s.Type()
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
f := s.Field(i)
|
||||
value := reflect.ValueOf(f.Interface())
|
||||
if !isZero(f) {
|
||||
name := typeOfEvent.Field(i).Name
|
||||
switch name {
|
||||
case "State", "Service", "Host", "Description":
|
||||
tmp := reflect.ValueOf(pb.String(value.String()))
|
||||
t.FieldByName(name).Set(tmp)
|
||||
case "Ttl":
|
||||
tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
|
||||
t.FieldByName(name).Set(tmp)
|
||||
case "Time":
|
||||
tmp := reflect.ValueOf(pb.Int64(value.Int()))
|
||||
t.FieldByName(name).Set(tmp)
|
||||
case "Tags":
|
||||
tmp := reflect.ValueOf(value.Interface().([]string))
|
||||
t.FieldByName(name).Set(tmp)
|
||||
case "Metric":
|
||||
switch reflect.TypeOf(f.Interface()).Kind() {
|
||||
case reflect.Int, reflect.Int64:
|
||||
tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
|
||||
t.FieldByName("MetricSint64").Set(tmp)
|
||||
case reflect.Uint64:
|
||||
tmp := reflect.ValueOf(pb.Int64(int64(value.Uint())))
|
||||
t.FieldByName("MetricSint64").Set(tmp)
|
||||
case reflect.Float32:
|
||||
tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
|
||||
t.FieldByName("MetricF").Set(tmp)
|
||||
case reflect.Float64:
|
||||
tmp := reflect.ValueOf(pb.Float64(value.Float()))
|
||||
t.FieldByName("MetricD").Set(tmp)
|
||||
default:
|
||||
return nil, fmt.Errorf("Metric of invalid type (type %v)",
|
||||
reflect.TypeOf(f.Interface()).Kind())
|
||||
}
|
||||
case "Attributes":
|
||||
var attrs []*proto.Attribute
|
||||
for k, v := range value.Interface().(map[string]string) {
|
||||
// Copy k,v so we can take
|
||||
// pointers to the new
|
||||
// temporaries
|
||||
k_, v_ := k, v
|
||||
attrs = append(attrs, &proto.Attribute{
|
||||
Key: &k_,
|
||||
Value: &v_,
|
||||
})
|
||||
}
|
||||
t.FieldByName(name).Set(reflect.ValueOf(attrs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &e, nil
|
||||
}
|
||||
|
||||
func pbEventsToEvents(pbEvents []*proto.Event) []Event {
|
||||
var events []Event
|
||||
|
||||
for _, event := range pbEvents {
|
||||
e := Event{
|
||||
State: event.GetState(),
|
||||
Service: event.GetService(),
|
||||
Host: event.GetHost(),
|
||||
Description: event.GetDescription(),
|
||||
Ttl: event.GetTtl(),
|
||||
Time: event.GetTime(),
|
||||
Tags: event.GetTags(),
|
||||
}
|
||||
if event.MetricF != nil {
|
||||
e.Metric = event.GetMetricF()
|
||||
} else if event.MetricD != nil {
|
||||
e.Metric = event.GetMetricD()
|
||||
} else {
|
||||
e.Metric = event.GetMetricSint64()
|
||||
}
|
||||
if event.Attributes != nil {
|
||||
e.Attributes = make(map[string]string, len(event.GetAttributes()))
|
||||
for _, attr := range event.GetAttributes() {
|
||||
e.Attributes[attr.GetKey()] = attr.GetValue()
|
||||
}
|
||||
}
|
||||
|
||||
events = append(events, e)
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
// Send sends an event to Riemann
|
||||
func (c *Client) Send(event *Event) error {
|
||||
return c.SendMulti([]*Event{event})
|
||||
}
|
||||
|
||||
// SendMulti sends multiple events to Riemann
|
||||
func (c *Client) SendMulti(events []*Event) error {
|
||||
message := &proto.Msg{}
|
||||
|
||||
for _, event := range events {
|
||||
e, err := eventToPbEvent(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
message.Events = append(message.Events, e)
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
if c.timeout > 0 {
|
||||
err := c.connection.SetDeadline(time.Now().Add(c.timeout))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err := c.net.Send(message, c.connection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Query returns a list of events matched by query
|
||||
func (c *Client) Query(q string) ([]Event, error) {
|
||||
switch c.net.(type) {
|
||||
case *udp:
|
||||
return nil, errors.New("Querying over UDP is not supported")
|
||||
}
|
||||
query := &proto.Query{}
|
||||
query.String_ = pb.String(q)
|
||||
message := &proto.Msg{}
|
||||
message.Query = query
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
response, err := c.net.Send(message, c.connection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pbEventsToEvents(response.GetEvents()), nil
|
||||
}
|
||||
|
||||
// Close closes the connection to Riemann
|
||||
func (c *Client) Close() error {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
return c.connection.Close()
|
||||
}
|
||||
286
vendor/github.com/amir/raidman/raidman_test.go
generated
vendored
286
vendor/github.com/amir/raidman/raidman_test.go
generated
vendored
@@ -1,286 +0,0 @@
|
||||
package raidman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTCP(t *testing.T) {
|
||||
c, err := Dial("tcp", "localhost:5555")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
var event = &Event{
|
||||
State: "success",
|
||||
Host: "raidman",
|
||||
Service: "tcp",
|
||||
Metric: 42,
|
||||
Ttl: 1,
|
||||
Tags: []string{"tcp", "test", "raidman"},
|
||||
Attributes: map[string]string{"type": "test"},
|
||||
}
|
||||
|
||||
err = c.Send(event)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
events, err := c.Query("tagged \"test\"")
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
if len(events) < 1 {
|
||||
t.Error("Submitted event not found")
|
||||
}
|
||||
|
||||
testAttributeExists := false
|
||||
for _, event := range events {
|
||||
if val, ok := event.Attributes["type"]; ok && val == "test" {
|
||||
testAttributeExists = true
|
||||
}
|
||||
}
|
||||
|
||||
if !testAttributeExists {
|
||||
t.Error("Attribute \"type\" is missing")
|
||||
}
|
||||
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestMultiTCP(t *testing.T) {
|
||||
c, err := Dial("tcp", "localhost:5555")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
err = c.SendMulti([]*Event{
|
||||
&Event{
|
||||
State: "success",
|
||||
Host: "raidman",
|
||||
Service: "tcp-multi-1",
|
||||
Metric: 42,
|
||||
Ttl: 1,
|
||||
Tags: []string{"tcp", "test", "raidman", "multi"},
|
||||
Attributes: map[string]string{"type": "test"},
|
||||
},
|
||||
&Event{
|
||||
State: "success",
|
||||
Host: "raidman",
|
||||
Service: "tcp-multi-2",
|
||||
Metric: 42,
|
||||
Ttl: 1,
|
||||
Tags: []string{"tcp", "test", "raidman", "multi"},
|
||||
Attributes: map[string]string{"type": "test"},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
events, err := c.Query("tagged \"test\" and tagged \"multi\"")
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
if len(events) != 2 {
|
||||
t.Error("Submitted event not found")
|
||||
}
|
||||
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestMetricIsInt64(t *testing.T) {
|
||||
c, err := Dial("tcp", "localhost:5555")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
var int64metric int64 = 9223372036854775807
|
||||
|
||||
var event = &Event{
|
||||
State: "success",
|
||||
Host: "raidman",
|
||||
Service: "tcp",
|
||||
Metric: int64metric,
|
||||
Ttl: 1,
|
||||
Tags: []string{"tcp", "test", "raidman"},
|
||||
Attributes: map[string]string{"type": "test"},
|
||||
}
|
||||
|
||||
err = c.Send(event)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUDP(t *testing.T) {
|
||||
c, err := Dial("udp", "localhost:5555")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
var event = &Event{
|
||||
State: "warning",
|
||||
Host: "raidman",
|
||||
Service: "udp",
|
||||
Metric: 3.4,
|
||||
Ttl: 10.7,
|
||||
}
|
||||
|
||||
err = c.Send(event)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func TestTCPWithoutHost(t *testing.T) {
|
||||
c, err := Dial("tcp", "localhost:5555")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
var event = &Event{
|
||||
State: "success",
|
||||
Service: "tcp-host-not-set",
|
||||
Ttl: 5,
|
||||
}
|
||||
|
||||
err = c.Send(event)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
events, err := c.Query("service = \"tcp-host-not-set\"")
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
if len(events) < 1 {
|
||||
t.Error("Submitted event not found")
|
||||
}
|
||||
|
||||
for _, e := range events {
|
||||
if e.Host == "" {
|
||||
t.Error("Default host name is not set")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsZero(t *testing.T) {
|
||||
event := &Event{
|
||||
Time: 1,
|
||||
}
|
||||
elem := reflect.ValueOf(event).Elem()
|
||||
eventType := elem.Type()
|
||||
for i := 0; i < elem.NumField(); i++ {
|
||||
field := elem.Field(i)
|
||||
name := eventType.Field(i).Name
|
||||
if name == "Time" {
|
||||
if isZero(field) {
|
||||
t.Error("Time should not be zero")
|
||||
}
|
||||
} else {
|
||||
if !isZero(field) {
|
||||
t.Errorf("%s should be zero", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialer(t *testing.T) {
|
||||
proxyAddr := "localhost:9999"
|
||||
os.Setenv("RIEMANN_PROXY", "socks5://"+proxyAddr)
|
||||
defer os.Unsetenv("RIEMANN_PROXY")
|
||||
dialer, err := newDialer()
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
val := reflect.Indirect(reflect.ValueOf(dialer))
|
||||
// this is a horrible hack but proxy.Dialer exports nothing.
|
||||
addr := fmt.Sprintf("%s", val.FieldByName("addr"))
|
||||
if addr != proxyAddr {
|
||||
t.Errorf("RIEMANN_PROXY is set and is %s but dialer's proxy is %s", proxyAddr, addr)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTCP(b *testing.B) {
|
||||
c, err := Dial("tcp", "localhost:5555")
|
||||
|
||||
var event = &Event{
|
||||
State: "good",
|
||||
Host: "raidman",
|
||||
Service: "benchmark",
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Send(event)
|
||||
}
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func BenchmarkUDP(b *testing.B) {
|
||||
c, err := Dial("udp", "localhost:5555")
|
||||
|
||||
var event = &Event{
|
||||
State: "good",
|
||||
Host: "raidman",
|
||||
Service: "benchmark",
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Send(event)
|
||||
}
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func BenchmarkConcurrentTCP(b *testing.B) {
|
||||
c, err := Dial("tcp", "localhost:5555")
|
||||
|
||||
var event = &Event{
|
||||
Host: "raidman",
|
||||
Service: "tcp_concurrent",
|
||||
Tags: []string{"concurrent", "tcp", "benchmark"},
|
||||
}
|
||||
|
||||
ch := make(chan int, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
go func(metric int) {
|
||||
event.Metric = metric
|
||||
err = c.Send(event)
|
||||
ch <- i
|
||||
}(i)
|
||||
}
|
||||
<-ch
|
||||
|
||||
c.Close()
|
||||
}
|
||||
|
||||
func BenchmarkConcurrentUDP(b *testing.B) {
|
||||
c, err := Dial("udp", "localhost:5555")
|
||||
|
||||
var event = &Event{
|
||||
Host: "raidman",
|
||||
Service: "udp_concurrent",
|
||||
Tags: []string{"concurrent", "udp", "benchmark"},
|
||||
}
|
||||
|
||||
ch := make(chan int, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
go func(metric int) {
|
||||
event.Metric = metric
|
||||
err = c.Send(event)
|
||||
ch <- i
|
||||
}(i)
|
||||
}
|
||||
<-ch
|
||||
|
||||
c.Close()
|
||||
}
|
||||
10
vendor/github.com/cactus/go-statsd-client/.travis.yml
generated
vendored
10
vendor/github.com/cactus/go-statsd-client/.travis.yml
generated
vendored
@@ -1,10 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
script: go test -v -cpu=1,2 ./...
|
||||
go:
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
49
vendor/github.com/cactus/go-statsd-client/CHANGELOG.md
generated
vendored
49
vendor/github.com/cactus/go-statsd-client/CHANGELOG.md
generated
vendored
@@ -1,49 +0,0 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
## head
|
||||
* Fix leak on sender create with unresolvable destination (GH-34).
|
||||
|
||||
## v3.1.0 2016-05-30
|
||||
* `NewClientWithSender(Sender, string) (Statter, error)` method added to
|
||||
enable building a Client from a prefix and an already created Sender.
|
||||
* Add stat recording sender in submodule statsdtest (GH-32).
|
||||
* Add an example helper stat validation function.
|
||||
* Change the way scope joins are done (GH-26).
|
||||
* Reorder some structs to avoid middle padding.
|
||||
|
||||
## 3.0.3 2016-02-18
|
||||
* make sampler function tunable (GH-24)
|
||||
|
||||
## 3.0.2 2016-01-13
|
||||
* reduce memory allocations
|
||||
* improve performance of buffered clients
|
||||
|
||||
## 3.0.1 2016-01-01
|
||||
* documentation typo fixes
|
||||
* fix possible race condition with `buffered_sender` send/close.
|
||||
|
||||
## 3.0.0 2015-12-04
|
||||
* add substatter support
|
||||
|
||||
## 2.0.2 2015-10-16
|
||||
* remove trailing newline in buffered sends to avoid etsy statsd log messages
|
||||
* minor internal code reorganization for clarity (no api changes)
|
||||
|
||||
## 2.0.1 2015-07-12
|
||||
* Add Set and SetInt funcs to support Sets
|
||||
* Properly flush BufferedSender on close (bugfix)
|
||||
* Add TimingDuration with support for sub-millisecond timing
|
||||
* fewer allocations, better performance of BufferedClient
|
||||
|
||||
## 2.0.0 2015-03-19
|
||||
* BufferedClient - send multiple stats at once
|
||||
* clean up godocs
|
||||
* clean up interfaces -- BREAKING CHANGE: for users who previously defined
|
||||
types as *Client instead of the Statter interface type.
|
||||
|
||||
## 1.0.1 2015-03-19
|
||||
* BufferedClient - send multiple stats at once
|
||||
|
||||
## 1.0.0 2015-02-04
|
||||
* tag a version as fix for GH-8
|
||||
19
vendor/github.com/cactus/go-statsd-client/LICENSE.md
generated
vendored
19
vendor/github.com/cactus/go-statsd-client/LICENSE.md
generated
vendored
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2012-2016 Eli Janssen
|
||||
|
||||
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.
|
||||
68
vendor/github.com/cactus/go-statsd-client/README.md
generated
vendored
68
vendor/github.com/cactus/go-statsd-client/README.md
generated
vendored
@@ -1,68 +0,0 @@
|
||||
go-statsd-client
|
||||
================
|
||||
|
||||
[](https://travis-ci.org/cactus/go-statsd-client)
|
||||
[](https://godoc.org/github.com/cactus/go-statsd-client/statsd)
|
||||
[](https://goreportcard.com/report/cactus/go-statsd-client)
|
||||
|
||||
|
||||
## About
|
||||
|
||||
A [StatsD][1] client for Go.
|
||||
|
||||
## Docs
|
||||
|
||||
Viewable online at [godoc.org][2].
|
||||
|
||||
## Example
|
||||
|
||||
``` go
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/cactus/go-statsd-client/statsd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// first create a client
|
||||
// The basic client sends one stat per packet (for compatibility).
|
||||
client, err := statsd.NewClient("127.0.0.1:8125", "test-client")
|
||||
|
||||
// A buffered client, which sends multiple stats in one packet, is
|
||||
// recommended when your server supports it (better performance).
|
||||
// client, err := statsd.NewBufferedClient("127.0.0.1:8125", "test-client", 300*time.Millisecond, 0)
|
||||
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// make sure to clean up
|
||||
defer client.Close()
|
||||
|
||||
// Send a stat
|
||||
client.Inc("stat1", 42, 1.0)
|
||||
}
|
||||
```
|
||||
|
||||
See [docs][2] for more info. There is also some simple example code in the
|
||||
`test-client` directory.
|
||||
|
||||
## Contributors
|
||||
|
||||
See [here][4].
|
||||
|
||||
## Alternative Implementations
|
||||
|
||||
See the [statsd wiki][5] for some additional client implementations
|
||||
(scroll down to the Go section).
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT license][3]. See `LICENSE.md` file for details.
|
||||
|
||||
|
||||
[1]: https://github.com/etsy/statsd
|
||||
[2]: http://godoc.org/github.com/cactus/go-statsd-client/statsd
|
||||
[3]: http://www.opensource.org/licenses/mit-license.php
|
||||
[4]: https://github.com/cactus/go-statsd-client/graphs/contributors
|
||||
[5]: https://github.com/etsy/statsd/wiki#client-implementations
|
||||
98
vendor/github.com/cactus/go-statsd-client/statsd/bench_buffered_test.go
generated
vendored
98
vendor/github.com/cactus/go-statsd-client/statsd/bench_buffered_test.go
generated
vendored
@@ -1,98 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BenchmarkBufferedClientInc(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
c, err := NewBufferedClient(l.LocalAddr().String(), "test", 1*time.Second, 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
c.Inc("benchinc", 1, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkBufferedClientIncSample(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
c, err := NewBufferedClient(l.LocalAddr().String(), "test", 1*time.Second, 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
c.Inc("benchinc", 1, 0.3)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkBufferedClientSetInt(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
c, err := NewBufferedClient(l.LocalAddr().String(), "test", 1*time.Second, 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
c.SetInt("setint", 1, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkBufferedClientSetIntSample(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
c, err := NewBufferedClient(l.LocalAddr().String(), "test", 1*time.Second, 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
c.SetInt("setint", 1, 0.3)
|
||||
}
|
||||
})
|
||||
}
|
||||
97
vendor/github.com/cactus/go-statsd-client/statsd/bench_client_test.go
generated
vendored
97
vendor/github.com/cactus/go-statsd-client/statsd/bench_client_test.go
generated
vendored
@@ -1,97 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkClientInc(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
c, err := NewClient(l.LocalAddr().String(), "test")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
c.Inc("benchinc", 1, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkClientIncSample(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
c, err := NewClient(l.LocalAddr().String(), "test")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
c.Inc("benchinc", 1, 0.3)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkClientSetInt(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
c, err := NewClient(l.LocalAddr().String(), "test")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
c.SetInt("setint", 1, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkClientSetIntSample(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
c, err := NewClient(l.LocalAddr().String(), "test")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
c.SetInt("setint", 1, 0.3)
|
||||
}
|
||||
})
|
||||
}
|
||||
102
vendor/github.com/cactus/go-statsd-client/statsd/bench_sender_test.go
generated
vendored
102
vendor/github.com/cactus/go-statsd-client/statsd/bench_sender_test.go
generated
vendored
@@ -1,102 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BenchmarkSenderSmall(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
s, err := NewSimpleSender(l.LocalAddr().String())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
data := []byte("test.gauge:1|g\n")
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
s.Send(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkSenderLarge(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
s, err := NewSimpleSender(l.LocalAddr().String())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
data := bytes.Repeat([]byte("test.gauge:1|g\n"), 50)
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
s.Send(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkBufferedSenderSmall(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
s, err := NewBufferedSender(l.LocalAddr().String(), 300*time.Millisecond, 1432)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
data := []byte("test.gauge:1|g\n")
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
s.Send(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
func BenchmarkBufferedSenderLarge(b *testing.B) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
s, err := NewBufferedSender(l.LocalAddr().String(), 300*time.Millisecond, 1432)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
data := bytes.Repeat([]byte("test.gauge:1|g\n"), 50)
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
//i := 0; i < b.N; i++ {
|
||||
s.Send(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
31
vendor/github.com/cactus/go-statsd-client/statsd/buffer_pool.go
generated
vendored
31
vendor/github.com/cactus/go-statsd-client/statsd/buffer_pool.go
generated
vendored
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type bufferPool struct {
|
||||
*sync.Pool
|
||||
}
|
||||
|
||||
func newBufferPool() *bufferPool {
|
||||
return &bufferPool{
|
||||
&sync.Pool{New: func() interface{} {
|
||||
return bytes.NewBuffer(make([]byte, 0, 1700))
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
func (bp *bufferPool) Get() *bytes.Buffer {
|
||||
return (bp.Pool.Get()).(*bytes.Buffer)
|
||||
}
|
||||
|
||||
func (bp *bufferPool) Put(b *bytes.Buffer) {
|
||||
b.Truncate(0)
|
||||
bp.Pool.Put(b)
|
||||
}
|
||||
330
vendor/github.com/cactus/go-statsd-client/statsd/client.go
generated
vendored
330
vendor/github.com/cactus/go-statsd-client/statsd/client.go
generated
vendored
@@ -1,330 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var bufPool = newBufferPool()
|
||||
|
||||
// The StatSender interface wraps all the statsd metric methods
|
||||
type StatSender interface {
|
||||
Inc(string, int64, float32) error
|
||||
Dec(string, int64, float32) error
|
||||
Gauge(string, int64, float32) error
|
||||
GaugeDelta(string, int64, float32) error
|
||||
Timing(string, int64, float32) error
|
||||
TimingDuration(string, time.Duration, float32) error
|
||||
Set(string, string, float32) error
|
||||
SetInt(string, int64, float32) error
|
||||
Raw(string, string, float32) error
|
||||
}
|
||||
|
||||
// The Statter interface defines the behavior of a stat client
|
||||
type Statter interface {
|
||||
StatSender
|
||||
NewSubStatter(string) SubStatter
|
||||
SetPrefix(string)
|
||||
Close() error
|
||||
}
|
||||
|
||||
// The SubStatter interface defines the behavior of a stat child/subclient
|
||||
type SubStatter interface {
|
||||
StatSender
|
||||
SetSamplerFunc(SamplerFunc)
|
||||
NewSubStatter(string) SubStatter
|
||||
}
|
||||
|
||||
// The SamplerFunc type defines a function that can serve
|
||||
// as a Client sampler function.
|
||||
type SamplerFunc func(float32) bool
|
||||
|
||||
// DefaultSampler is the default rate sampler function
|
||||
func DefaultSampler(rate float32) bool {
|
||||
if rate < 1 {
|
||||
if rand.Float32() < rate {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// A Client is a statsd client.
|
||||
type Client struct {
|
||||
// prefix for statsd name
|
||||
prefix string
|
||||
// packet sender
|
||||
sender Sender
|
||||
// sampler method
|
||||
sampler SamplerFunc
|
||||
}
|
||||
|
||||
// Close closes the connection and cleans up.
|
||||
func (s *Client) Close() error {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := s.sender.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// Inc increments a statsd count type.
|
||||
// stat is a string name for the metric.
|
||||
// value is the integer value
|
||||
// rate is the sample rate (0.0 to 1.0)
|
||||
func (s *Client) Inc(stat string, value int64, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.submit(stat, "", value, "|c", rate)
|
||||
}
|
||||
|
||||
// Dec decrements a statsd count type.
|
||||
// stat is a string name for the metric.
|
||||
// value is the integer value.
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *Client) Dec(stat string, value int64, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.submit(stat, "", -value, "|c", rate)
|
||||
}
|
||||
|
||||
// Gauge submits/updates a statsd gauge type.
|
||||
// stat is a string name for the metric.
|
||||
// value is the integer value.
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *Client) Gauge(stat string, value int64, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.submit(stat, "", value, "|g", rate)
|
||||
}
|
||||
|
||||
// GaugeDelta submits a delta to a statsd gauge.
|
||||
// stat is the string name for the metric.
|
||||
// value is the (positive or negative) change.
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *Client) GaugeDelta(stat string, value int64, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if negative, the submit formatter will prefix with a - already
|
||||
// so only special case the positive value
|
||||
if value >= 0 {
|
||||
return s.submit(stat, "+", value, "|g", rate)
|
||||
}
|
||||
return s.submit(stat, "", value, "|g", rate)
|
||||
}
|
||||
|
||||
// Timing submits a statsd timing type.
|
||||
// stat is a string name for the metric.
|
||||
// delta is the time duration value in milliseconds
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *Client) Timing(stat string, delta int64, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.submit(stat, "", delta, "|ms", rate)
|
||||
}
|
||||
|
||||
// TimingDuration submits a statsd timing type.
|
||||
// stat is a string name for the metric.
|
||||
// delta is the timing value as time.Duration
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *Client) TimingDuration(stat string, delta time.Duration, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
ms := float64(delta) / float64(time.Millisecond)
|
||||
return s.submit(stat, "", ms, "|ms", rate)
|
||||
}
|
||||
|
||||
// Set submits a stats set type
|
||||
// stat is a string name for the metric.
|
||||
// value is the string value
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *Client) Set(stat string, value string, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.submit(stat, "", value, "|s", rate)
|
||||
}
|
||||
|
||||
// SetInt submits a number as a stats set type.
|
||||
// stat is a string name for the metric.
|
||||
// value is the integer value
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *Client) SetInt(stat string, value int64, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.submit(stat, "", value, "|s", rate)
|
||||
}
|
||||
|
||||
// Raw submits a preformatted value.
|
||||
// stat is the string name for the metric.
|
||||
// value is a preformatted "raw" value string.
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *Client) Raw(stat string, value string, rate float32) error {
|
||||
if !s.includeStat(rate) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.submit(stat, "", value, "", rate)
|
||||
}
|
||||
|
||||
// SetSamplerFunc sets a sampler function to something other than the default
|
||||
// sampler is a function that determines whether the metric is
|
||||
// to be accepted, or discarded.
|
||||
// An example use case is for submitted pre-sampled metrics.
|
||||
func (s *Client) SetSamplerFunc(sampler SamplerFunc) {
|
||||
s.sampler = sampler
|
||||
}
|
||||
|
||||
// submit an already sampled raw stat
|
||||
func (s *Client) submit(stat, vprefix string, value interface{}, suffix string, rate float32) error {
|
||||
data := bufPool.Get()
|
||||
defer bufPool.Put(data)
|
||||
|
||||
if s.prefix != "" {
|
||||
data.WriteString(s.prefix)
|
||||
data.WriteString(".")
|
||||
}
|
||||
|
||||
data.WriteString(stat)
|
||||
data.WriteString(":")
|
||||
|
||||
if vprefix != "" {
|
||||
data.WriteString(vprefix)
|
||||
}
|
||||
|
||||
// sadly, no way to jam this back into the bytes.Buffer without
|
||||
// doing a few allocations... avoiding those is the whole point here...
|
||||
// so from here on out just use it as a raw []byte
|
||||
b := data.Bytes()
|
||||
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
b = append(b, v...)
|
||||
case int64:
|
||||
b = strconv.AppendInt(b, v, 10)
|
||||
case float64:
|
||||
b = strconv.AppendFloat(b, v, 'f', -1, 64)
|
||||
default:
|
||||
return fmt.Errorf("No matching type format")
|
||||
}
|
||||
|
||||
if suffix != "" {
|
||||
b = append(b, suffix...)
|
||||
}
|
||||
|
||||
if rate < 1 {
|
||||
b = append(b, "|@"...)
|
||||
b = strconv.AppendFloat(b, float64(rate), 'f', 6, 32)
|
||||
}
|
||||
|
||||
_, err := s.sender.Send(b)
|
||||
return err
|
||||
}
|
||||
|
||||
// check for nil client, and perform sampling calculation
|
||||
func (s *Client) includeStat(rate float32) bool {
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// test for nil in case someone builds their own
|
||||
// client without calling new (result is nil sampler)
|
||||
if s.sampler != nil {
|
||||
return s.sampler(rate)
|
||||
}
|
||||
return DefaultSampler(rate)
|
||||
}
|
||||
|
||||
// SetPrefix sets/updates the statsd client prefix.
|
||||
// Note: Does not change the prefix of any SubStatters.
|
||||
func (s *Client) SetPrefix(prefix string) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.prefix = prefix
|
||||
}
|
||||
|
||||
// NewSubStatter returns a SubStatter with appended prefix
|
||||
func (s *Client) NewSubStatter(prefix string) SubStatter {
|
||||
var c *Client
|
||||
if s != nil {
|
||||
c = &Client{
|
||||
prefix: joinPathComp(s.prefix, prefix),
|
||||
sender: s.sender,
|
||||
sampler: s.sampler,
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// NewClient returns a pointer to a new Client, and an error.
|
||||
//
|
||||
// addr is a string of the format "hostname:port", and must be parsable by
|
||||
// net.ResolveUDPAddr.
|
||||
//
|
||||
// prefix is the statsd client prefix. Can be "" if no prefix is desired.
|
||||
func NewClient(addr, prefix string) (Statter, error) {
|
||||
sender, err := NewSimpleSender(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{prefix: prefix, sender: sender}, nil
|
||||
}
|
||||
|
||||
// NewClientWithSender returns a pointer to a new Client and an error.
|
||||
//
|
||||
// sender is an instance of a statsd.Sender interface and may not be nil
|
||||
//
|
||||
// prefix is the stastd client prefix. Can be "" if no prefix is desired.
|
||||
func NewClientWithSender(sender Sender, prefix string) (Statter, error) {
|
||||
if sender == nil {
|
||||
return nil, fmt.Errorf("Client sender may not be nil")
|
||||
}
|
||||
|
||||
return &Client{prefix: prefix, sender: sender}, nil
|
||||
}
|
||||
|
||||
// joinPathComp is a helper that ensures we combine path components with a dot
|
||||
// when it's appropriate to do so; prefix is the existing prefix and suffix is
|
||||
// the new component being added.
|
||||
//
|
||||
// It returns the joined prefix.
|
||||
func joinPathComp(prefix, suffix string) string {
|
||||
suffix = strings.TrimLeft(suffix, ".")
|
||||
if prefix != "" && suffix != "" {
|
||||
return prefix + "." + suffix
|
||||
}
|
||||
return prefix + suffix
|
||||
}
|
||||
|
||||
// Dial is a compatibility alias for NewClient
|
||||
var Dial = NewClient
|
||||
|
||||
// New is a compatibility alias for NewClient
|
||||
var New = NewClient
|
||||
48
vendor/github.com/cactus/go-statsd-client/statsd/client_buffered.go
generated
vendored
48
vendor/github.com/cactus/go-statsd-client/statsd/client_buffered.go
generated
vendored
@@ -1,48 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import "time"
|
||||
|
||||
// NewBufferedClient returns a new BufferedClient
|
||||
//
|
||||
// addr is a string of the format "hostname:port", and must be parsable by
|
||||
// net.ResolveUDPAddr.
|
||||
//
|
||||
// prefix is the statsd client prefix. Can be "" if no prefix is desired.
|
||||
//
|
||||
// flushInterval is a time.Duration, and specifies the maximum interval for
|
||||
// packet sending. Note that if you send lots of metrics, you will send more
|
||||
// often. This is just a maximal threshold.
|
||||
//
|
||||
// If flushInterval is 0ms, defaults to 300ms.
|
||||
//
|
||||
// flushBytes specifies the maximum udp packet size you wish to send. If adding
|
||||
// a metric would result in a larger packet than flushBytes, the packet will
|
||||
// first be send, then the new data will be added to the next packet.
|
||||
//
|
||||
// If flushBytes is 0, defaults to 1432 bytes, which is considered safe
|
||||
// for local traffic. If sending over the public internet, 512 bytes is
|
||||
// the recommended value.
|
||||
func NewBufferedClient(addr, prefix string, flushInterval time.Duration, flushBytes int) (Statter, error) {
|
||||
if flushBytes <= 0 {
|
||||
// https://github.com/etsy/statsd/blob/master/docs/metric_types.md#multi-metric-packets
|
||||
flushBytes = 1432
|
||||
}
|
||||
if flushInterval <= time.Duration(0) {
|
||||
flushInterval = 300 * time.Millisecond
|
||||
}
|
||||
sender, err := NewBufferedSender(addr, flushInterval, flushBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
prefix: prefix,
|
||||
sender: sender,
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
203
vendor/github.com/cactus/go-statsd-client/statsd/client_buffered_test.go
generated
vendored
203
vendor/github.com/cactus/go-statsd-client/statsd/client_buffered_test.go
generated
vendored
@@ -1,203 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBufferedClientFlushSize(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
for _, tt := range statsdPacketTests {
|
||||
// set flush length to the size of the expected output packet
|
||||
// so we can ensure a flush happens right away.
|
||||
// set flush time sufficiently high so that it never matters for this
|
||||
// test
|
||||
c, err := NewBufferedClient(l.LocalAddr().String(), tt.Prefix, 10*time.Second, len(tt.Expected)+1)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
method := reflect.ValueOf(c).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
c.Close()
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, len(tt.Expected)+16)
|
||||
_, _, err = l.ReadFrom(data)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = bytes.TrimRight(data, "\x00\n")
|
||||
if bytes.Equal(data, []byte(tt.Expected)) != true {
|
||||
t.Fatalf("%s got '%s' expected '%s'", tt.Method, data, tt.Expected)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferedClientFlushTime(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
for _, tt := range statsdPacketTests {
|
||||
// set flush length to the size of the expected output packet
|
||||
// so we can ensure a flush happens right away.
|
||||
// set flush time sufficiently high so that it never matters for this
|
||||
// test
|
||||
c, err := NewBufferedClient(l.LocalAddr().String(), tt.Prefix, 1*time.Microsecond, 1024)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
method := reflect.ValueOf(c).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
c.Close()
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
|
||||
data := make([]byte, len(tt.Expected)+16)
|
||||
_, _, err = l.ReadFrom(data)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = bytes.TrimRight(data, "\x00\n")
|
||||
if bytes.Equal(data, []byte(tt.Expected)) != true {
|
||||
t.Fatalf("%s got '%s' expected '%s'", tt.Method, data, tt.Expected)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferedClientBigPacket(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
c, err := NewBufferedClient(l.LocalAddr().String(), "test", 10*time.Millisecond, 1024)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
for _, tt := range statsdPacketTests {
|
||||
if tt.Prefix != "test" {
|
||||
continue
|
||||
}
|
||||
method := reflect.ValueOf(c).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
}
|
||||
|
||||
expected := ""
|
||||
for _, tt := range statsdPacketTests {
|
||||
if tt.Prefix != "test" {
|
||||
continue
|
||||
}
|
||||
expected = expected + tt.Expected + "\n"
|
||||
}
|
||||
|
||||
expected = strings.TrimSuffix(expected, "\n")
|
||||
|
||||
time.Sleep(12 * time.Millisecond)
|
||||
data := make([]byte, 1024)
|
||||
_, _, err = l.ReadFrom(data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = bytes.TrimRight(data, "\x00")
|
||||
if bytes.Equal(data, []byte(expected)) != true {
|
||||
t.Fatalf("got '%s' expected '%s'", data, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlushOnClose(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
c, err := NewBufferedClient(l.LocalAddr().String(), "test", 1*time.Second, 1024)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c.Inc("count", int64(1), 1.0)
|
||||
c.Close()
|
||||
|
||||
expected := "test.count:1|c"
|
||||
|
||||
data := make([]byte, 1024)
|
||||
_, _, err = l.ReadFrom(data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = bytes.TrimRight(data, "\x00")
|
||||
if bytes.Equal(data, []byte(expected)) != true {
|
||||
fmt.Println(data)
|
||||
fmt.Println([]byte(expected))
|
||||
t.Fatalf("got '%s' expected '%s'", data, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleClient_buffered() {
|
||||
// first create a client
|
||||
client, err := NewBufferedClient("127.0.0.1:8125", "test-client", 10*time.Millisecond, 0)
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// make sure to clean up
|
||||
defer client.Close()
|
||||
|
||||
// Send a stat
|
||||
err = client.Inc("stat1", 42, 1.0)
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Printf("Error sending metric: %+v", err)
|
||||
}
|
||||
}
|
||||
111
vendor/github.com/cactus/go-statsd-client/statsd/client_noop.go
generated
vendored
111
vendor/github.com/cactus/go-statsd-client/statsd/client_noop.go
generated
vendored
@@ -1,111 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import "time"
|
||||
|
||||
// A NoopClient is a client that does nothing.
|
||||
type NoopClient struct{}
|
||||
|
||||
// Close closes the connection and cleans up.
|
||||
func (s *NoopClient) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Inc increments a statsd count type.
|
||||
// stat is a string name for the metric.
|
||||
// value is the integer value
|
||||
// rate is the sample rate (0.0 to 1.0)
|
||||
func (s *NoopClient) Inc(stat string, value int64, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dec decrements a statsd count type.
|
||||
// stat is a string name for the metric.
|
||||
// value is the integer value.
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *NoopClient) Dec(stat string, value int64, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Gauge submits/Updates a statsd gauge type.
|
||||
// stat is a string name for the metric.
|
||||
// value is the integer value.
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *NoopClient) Gauge(stat string, value int64, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GaugeDelta submits a delta to a statsd gauge.
|
||||
// stat is the string name for the metric.
|
||||
// value is the (positive or negative) change.
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *NoopClient) GaugeDelta(stat string, value int64, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Timing submits a statsd timing type.
|
||||
// stat is a string name for the metric.
|
||||
// delta is the time duration value in milliseconds
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *NoopClient) Timing(stat string, delta int64, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TimingDuration submits a statsd timing type.
|
||||
// stat is a string name for the metric.
|
||||
// delta is the timing value as time.Duration
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *NoopClient) TimingDuration(stat string, delta time.Duration, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set submits a stats set type.
|
||||
// stat is a string name for the metric.
|
||||
// value is the string value
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *NoopClient) Set(stat string, value string, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetInt submits a number as a stats set type.
|
||||
// convenience method for Set with number.
|
||||
// stat is a string name for the metric.
|
||||
// value is the integer value
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *NoopClient) SetInt(stat string, value int64, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Raw formats the statsd event data, handles sampling, prepares it,
|
||||
// and sends it to the server.
|
||||
// stat is the string name for the metric.
|
||||
// value is the preformatted "raw" value string.
|
||||
// rate is the sample rate (0.0 to 1.0).
|
||||
func (s *NoopClient) Raw(stat string, value string, rate float32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPrefix sets/updates the statsd client prefix
|
||||
func (s *NoopClient) SetPrefix(prefix string) {}
|
||||
|
||||
// NewSubStatter returns a SubStatter with appended prefix
|
||||
func (s *NoopClient) NewSubStatter(prefix string) SubStatter {
|
||||
return &NoopClient{}
|
||||
}
|
||||
|
||||
// SetSamplerFunc sets the sampler function
|
||||
func (s *NoopClient) SetSamplerFunc(sampler SamplerFunc) {}
|
||||
|
||||
// NewNoopClient returns a pointer to a new NoopClient, and an error (always
|
||||
// nil, just supplied to support api convention).
|
||||
// Use variadic arguments to support identical format as NewClient, or a more
|
||||
// conventional no argument form.
|
||||
func NewNoopClient(a ...interface{}) (Statter, error) {
|
||||
return &NoopClient{}, nil
|
||||
}
|
||||
|
||||
// NewNoop is a compatibility alias for NewNoopClient
|
||||
var NewNoop = NewNoopClient
|
||||
292
vendor/github.com/cactus/go-statsd-client/statsd/client_substatter_test.go
generated
vendored
292
vendor/github.com/cactus/go-statsd-client/statsd/client_substatter_test.go
generated
vendored
@@ -1,292 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var statsdSubStatterPacketTests = []struct {
|
||||
Prefix string
|
||||
SubPrefix string
|
||||
Method string
|
||||
Stat string
|
||||
Value interface{}
|
||||
Rate float32
|
||||
Expected string
|
||||
}{
|
||||
{"test", "sub", "Gauge", "gauge", int64(1), 1.0, "test.sub.gauge:1|g"},
|
||||
{"test", "sub", "Inc", "count", int64(1), 0.999999, "test.sub.count:1|c|@0.999999"},
|
||||
{"test", "sub", "Inc", "count", int64(1), 1.0, "test.sub.count:1|c"},
|
||||
{"test", "sub", "Dec", "count", int64(1), 1.0, "test.sub.count:-1|c"},
|
||||
{"test", "sub", "Timing", "timing", int64(1), 1.0, "test.sub.timing:1|ms"},
|
||||
{"test", "sub", "TimingDuration", "timing", 1500 * time.Microsecond, 1.0, "test.sub.timing:1.5|ms"},
|
||||
{"test", "sub", "TimingDuration", "timing", 3 * time.Microsecond, 1.0, "test.sub.timing:0.003|ms"},
|
||||
{"test", "sub", "Set", "strset", "pickle", 1.0, "test.sub.strset:pickle|s"},
|
||||
{"test", "sub", "SetInt", "intset", int64(1), 1.0, "test.sub.intset:1|s"},
|
||||
{"test", "sub", "GaugeDelta", "gauge", int64(1), 1.0, "test.sub.gauge:+1|g"},
|
||||
{"test", "sub", "GaugeDelta", "gauge", int64(-1), 1.0, "test.sub.gauge:-1|g"},
|
||||
// empty sub prefix -- note: not used in subsub tests
|
||||
{"test", "", "Inc", "count", int64(1), 1.0, "test.count:1|c"},
|
||||
// empty base prefix
|
||||
{"", "sub", "Inc", "count", int64(1), 1.0, "sub.count:1|c"},
|
||||
}
|
||||
|
||||
func TestSubStatterClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
for _, tt := range statsdSubStatterPacketTests {
|
||||
c, err := NewClient(l.LocalAddr().String(), tt.Prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := c.NewSubStatter(tt.SubPrefix)
|
||||
method := reflect.ValueOf(s).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, 128)
|
||||
_, _, err = l.ReadFrom(data)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = bytes.TrimRight(data, "\x00")
|
||||
if bytes.Equal(data, []byte(tt.Expected)) != true {
|
||||
c.Close()
|
||||
t.Fatalf("%s got '%s' expected '%s'", tt.Method, data, tt.Expected)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultSubStatterClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
for _, tt := range statsdSubStatterPacketTests {
|
||||
// ignore empty sub test for this, as there is nothing to regex sub
|
||||
if tt.SubPrefix == "" {
|
||||
continue
|
||||
}
|
||||
c, err := NewClient(l.LocalAddr().String(), tt.Prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s1 := c.NewSubStatter("sub1")
|
||||
s2 := c.NewSubStatter("sub2")
|
||||
|
||||
responses := [][]byte{}
|
||||
for _, s := range []SubStatter{s1, s2} {
|
||||
method := reflect.ValueOf(s).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, 128)
|
||||
_, _, err = l.ReadFrom(data)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = bytes.TrimRight(data, "\x00")
|
||||
responses = append(responses, data)
|
||||
}
|
||||
|
||||
expected := strings.Replace(tt.Expected, "sub.", "sub1.", -1)
|
||||
if bytes.Equal(responses[0], []byte(expected)) != true {
|
||||
c.Close()
|
||||
t.Fatalf("%s got '%s' expected '%s'",
|
||||
tt.Method, responses[0], tt.Expected)
|
||||
}
|
||||
|
||||
expected = strings.Replace(tt.Expected, "sub.", "sub2.", -1)
|
||||
if bytes.Equal(responses[1], []byte(expected)) != true {
|
||||
c.Close()
|
||||
t.Fatalf("%s got '%s' expected '%s'",
|
||||
tt.Method, responses[1], tt.Expected)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubSubStatterClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
for _, tt := range statsdSubStatterPacketTests {
|
||||
// ignore empty sub test for this, as there is nothing to regex sub
|
||||
if tt.SubPrefix == "" {
|
||||
continue
|
||||
}
|
||||
c, err := NewClient(l.LocalAddr().String(), tt.Prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := c.NewSubStatter(tt.SubPrefix).NewSubStatter("sub2")
|
||||
|
||||
method := reflect.ValueOf(s).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, 128)
|
||||
_, _, err = l.ReadFrom(data)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = bytes.TrimRight(data, "\x00")
|
||||
expected := strings.Replace(tt.Expected, "sub.", "sub.sub2.", -1)
|
||||
if bytes.Equal(data, []byte(expected)) != true {
|
||||
c.Close()
|
||||
t.Fatalf("%s got '%s' expected '%s'", tt.Method, data, tt.Expected)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubStatterClosedClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
for _, tt := range statsdSubStatterPacketTests {
|
||||
c, err := NewClient(l.LocalAddr().String(), tt.Prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
s := c.NewSubStatter(tt.SubPrefix)
|
||||
method := reflect.ValueOf(s).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter == nil {
|
||||
t.Fatal("Expected error but got none")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilSubStatterClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
for _, tt := range statsdSubStatterPacketTests {
|
||||
var c *Client
|
||||
s := c.NewSubStatter(tt.SubPrefix)
|
||||
|
||||
method := reflect.ValueOf(s).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, 128)
|
||||
n, _, err := l.ReadFrom(data)
|
||||
// this is expected to error, since there should
|
||||
// be no udp data sent, so the read will time out
|
||||
if err == nil || n != 0 {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoopSubStatterClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
for _, tt := range statsdSubStatterPacketTests {
|
||||
c, err := NewNoopClient(l.LocalAddr().String(), tt.Prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := c.NewSubStatter(tt.SubPrefix)
|
||||
method := reflect.ValueOf(s).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, 128)
|
||||
n, _, err := l.ReadFrom(data)
|
||||
// this is expected to error, since there should
|
||||
// be no udp data sent, so the read will time out
|
||||
if err == nil || n != 0 {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleClient_substatter() {
|
||||
// first create a client
|
||||
client, err := NewClient("127.0.0.1:8125", "test-client")
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// make sure to clean up
|
||||
defer client.Close()
|
||||
|
||||
// create a substatter
|
||||
subclient := client.NewSubStatter("sub")
|
||||
// send a stat
|
||||
err = subclient.Inc("stat1", 42, 1.0)
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Printf("Error sending metric: %+v", err)
|
||||
}
|
||||
}
|
||||
201
vendor/github.com/cactus/go-statsd-client/statsd/client_test.go
generated
vendored
201
vendor/github.com/cactus/go-statsd-client/statsd/client_test.go
generated
vendored
@@ -1,201 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var statsdPacketTests = []struct {
|
||||
Prefix string
|
||||
Method string
|
||||
Stat string
|
||||
Value interface{}
|
||||
Rate float32
|
||||
Expected string
|
||||
}{
|
||||
{"test", "Gauge", "gauge", int64(1), 1.0, "test.gauge:1|g"},
|
||||
{"test", "Inc", "count", int64(1), 0.999999, "test.count:1|c|@0.999999"},
|
||||
{"test", "Inc", "count", int64(1), 1.0, "test.count:1|c"},
|
||||
{"test", "Dec", "count", int64(1), 1.0, "test.count:-1|c"},
|
||||
{"test", "Timing", "timing", int64(1), 1.0, "test.timing:1|ms"},
|
||||
{"test", "TimingDuration", "timing", 1500 * time.Microsecond, 1.0, "test.timing:1.5|ms"},
|
||||
{"test", "TimingDuration", "timing", 3 * time.Microsecond, 1.0, "test.timing:0.003|ms"},
|
||||
{"test", "Set", "strset", "pickle", 1.0, "test.strset:pickle|s"},
|
||||
{"test", "SetInt", "intset", int64(1), 1.0, "test.intset:1|s"},
|
||||
{"test", "GaugeDelta", "gauge", int64(1), 1.0, "test.gauge:+1|g"},
|
||||
{"test", "GaugeDelta", "gauge", int64(-1), 1.0, "test.gauge:-1|g"},
|
||||
|
||||
{"", "Gauge", "gauge", int64(1), 1.0, "gauge:1|g"},
|
||||
{"", "Inc", "count", int64(1), 0.999999, "count:1|c|@0.999999"},
|
||||
{"", "Inc", "count", int64(1), 1.0, "count:1|c"},
|
||||
{"", "Dec", "count", int64(1), 1.0, "count:-1|c"},
|
||||
{"", "Timing", "timing", int64(1), 1.0, "timing:1|ms"},
|
||||
{"", "TimingDuration", "timing", 1500 * time.Microsecond, 1.0, "timing:1.5|ms"},
|
||||
{"", "Set", "strset", "pickle", 1.0, "strset:pickle|s"},
|
||||
{"", "SetInt", "intset", int64(1), 1.0, "intset:1|s"},
|
||||
{"", "GaugeDelta", "gauge", int64(1), 1.0, "gauge:+1|g"},
|
||||
{"", "GaugeDelta", "gauge", int64(-1), 1.0, "gauge:-1|g"},
|
||||
}
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
for _, tt := range statsdPacketTests {
|
||||
c, err := NewClient(l.LocalAddr().String(), tt.Prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
method := reflect.ValueOf(c).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, 128)
|
||||
_, _, err = l.ReadFrom(data)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data = bytes.TrimRight(data, "\x00")
|
||||
if bytes.Equal(data, []byte(tt.Expected)) != true {
|
||||
c.Close()
|
||||
t.Fatalf("%s got '%s' expected '%s'", tt.Method, data, tt.Expected)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
for _, tt := range statsdPacketTests {
|
||||
var c *Client
|
||||
|
||||
method := reflect.ValueOf(c).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, 128)
|
||||
n, _, err := l.ReadFrom(data)
|
||||
// this is expected to error, since there should
|
||||
// be no udp data sent, so the read will time out
|
||||
if err == nil || n != 0 {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoopClient(t *testing.T) {
|
||||
l, err := newUDPListener("127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
for _, tt := range statsdPacketTests {
|
||||
c, err := NewNoopClient(l.LocalAddr().String(), tt.Prefix)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
method := reflect.ValueOf(c).MethodByName(tt.Method)
|
||||
e := method.Call([]reflect.Value{
|
||||
reflect.ValueOf(tt.Stat),
|
||||
reflect.ValueOf(tt.Value),
|
||||
reflect.ValueOf(tt.Rate)})[0]
|
||||
errInter := e.Interface()
|
||||
if errInter != nil {
|
||||
t.Fatal(errInter.(error))
|
||||
}
|
||||
|
||||
data := make([]byte, 128)
|
||||
n, _, err := l.ReadFrom(data)
|
||||
// this is expected to error, since there should
|
||||
// be no udp data sent, so the read will time out
|
||||
if err == nil || n != 0 {
|
||||
c.Close()
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func newUDPListener(addr string) (*net.UDPConn, error) {
|
||||
l, err := net.ListenPacket("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.SetDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
l.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
l.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
return l.(*net.UDPConn), nil
|
||||
}
|
||||
|
||||
func ExampleClient() {
|
||||
// first create a client
|
||||
client, err := NewClient("127.0.0.1:8125", "test-client")
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// make sure to clean up
|
||||
defer client.Close()
|
||||
|
||||
// Send a stat
|
||||
err = client.Inc("stat1", 42, 1.0)
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Printf("Error sending metric: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleClient_noop() {
|
||||
// use interface so we can sub noop client if needed
|
||||
var client Statter
|
||||
var err error
|
||||
|
||||
// first try to create a real client
|
||||
client, err = NewClient("not-resolvable:8125", "test-client")
|
||||
// Let us say real client creation fails, but you don't care enough about
|
||||
// stats that you don't want your program to run. Just log an error and
|
||||
// make a NoopClient instead
|
||||
if err != nil {
|
||||
log.Println("Remote endpoint did not resolve. Disabling stats", err)
|
||||
client, err = NewNoopClient()
|
||||
}
|
||||
// make sure to clean up
|
||||
defer client.Close()
|
||||
|
||||
// Send a stat
|
||||
err = client.Inc("stat1", 42, 1.0)
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Printf("Error sending metric: %+v", err)
|
||||
}
|
||||
}
|
||||
29
vendor/github.com/cactus/go-statsd-client/statsd/doc.go
generated
vendored
29
vendor/github.com/cactus/go-statsd-client/statsd/doc.go
generated
vendored
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package statsd provides a StatsD client implementation that is safe for
|
||||
concurrent use by multiple goroutines and for efficiency can be created and
|
||||
reused.
|
||||
|
||||
Example usage:
|
||||
|
||||
// first create a client
|
||||
client, err := statsd.NewClient("127.0.0.1:8125", "test-client")
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// make sure to clean up
|
||||
defer client.Close()
|
||||
|
||||
// Send a stat
|
||||
err = client.Inc("stat1", 42, 1.0)
|
||||
// handle any errors
|
||||
if err != nil {
|
||||
log.Printf("Error sending metric: %+v", err)
|
||||
}
|
||||
|
||||
*/
|
||||
package statsd
|
||||
69
vendor/github.com/cactus/go-statsd-client/statsd/sender.go
generated
vendored
69
vendor/github.com/cactus/go-statsd-client/statsd/sender.go
generated
vendored
@@ -1,69 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
// The Sender interface wraps a Send and Close
|
||||
type Sender interface {
|
||||
Send(data []byte) (int, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
// SimpleSender provides a socket send interface.
|
||||
type SimpleSender struct {
|
||||
// underlying connection
|
||||
c net.PacketConn
|
||||
// resolved udp address
|
||||
ra *net.UDPAddr
|
||||
}
|
||||
|
||||
// Send sends the data to the server endpoint.
|
||||
func (s *SimpleSender) Send(data []byte) (int, error) {
|
||||
// no need for locking here, as the underlying fdNet
|
||||
// already serialized writes
|
||||
n, err := s.c.(*net.UDPConn).WriteToUDP(data, s.ra)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if n == 0 {
|
||||
return n, errors.New("Wrote no bytes")
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Close closes the SimpleSender
|
||||
func (s *SimpleSender) Close() error {
|
||||
err := s.c.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// NewSimpleSender returns a new SimpleSender for sending to the supplied
|
||||
// addresss.
|
||||
//
|
||||
// addr is a string of the format "hostname:port", and must be parsable by
|
||||
// net.ResolveUDPAddr.
|
||||
func NewSimpleSender(addr string) (Sender, error) {
|
||||
c, err := net.ListenPacket("udp", ":0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ra, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sender := &SimpleSender{
|
||||
c: c,
|
||||
ra: ra,
|
||||
}
|
||||
|
||||
return sender, nil
|
||||
}
|
||||
175
vendor/github.com/cactus/go-statsd-client/statsd/sender_buffered.go
generated
vendored
175
vendor/github.com/cactus/go-statsd-client/statsd/sender_buffered.go
generated
vendored
@@ -1,175 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var senderPool = newBufferPool()
|
||||
|
||||
// BufferedSender provides a buffered statsd udp, sending multiple
|
||||
// metrics, where possible.
|
||||
type BufferedSender struct {
|
||||
sender Sender
|
||||
flushBytes int
|
||||
flushInterval time.Duration
|
||||
// buffers
|
||||
bufmx sync.Mutex
|
||||
buffer *bytes.Buffer
|
||||
bufs chan *bytes.Buffer
|
||||
// lifecycle
|
||||
runmx sync.RWMutex
|
||||
shutdown chan chan error
|
||||
running bool
|
||||
}
|
||||
|
||||
// Send bytes.
|
||||
func (s *BufferedSender) Send(data []byte) (int, error) {
|
||||
s.runmx.RLock()
|
||||
if !s.running {
|
||||
s.runmx.RUnlock()
|
||||
return 0, fmt.Errorf("BufferedSender is not running")
|
||||
}
|
||||
|
||||
s.withBufferLock(func() {
|
||||
blen := s.buffer.Len()
|
||||
if blen > 0 && blen+len(data)+1 >= s.flushBytes {
|
||||
s.swapnqueue()
|
||||
}
|
||||
|
||||
s.buffer.Write(data)
|
||||
s.buffer.WriteByte('\n')
|
||||
|
||||
if s.buffer.Len() >= s.flushBytes {
|
||||
s.swapnqueue()
|
||||
}
|
||||
})
|
||||
s.runmx.RUnlock()
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// Close Buffered Sender
|
||||
func (s *BufferedSender) Close() error {
|
||||
// since we are running, write lock during cleanup
|
||||
s.runmx.Lock()
|
||||
defer s.runmx.Unlock()
|
||||
if !s.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
errChan := make(chan error)
|
||||
s.running = false
|
||||
s.shutdown <- errChan
|
||||
return <-errChan
|
||||
}
|
||||
|
||||
// Start Buffered Sender
|
||||
// Begins ticker and read loop
|
||||
func (s *BufferedSender) Start() {
|
||||
// write lock to start running
|
||||
s.runmx.Lock()
|
||||
defer s.runmx.Unlock()
|
||||
if s.running {
|
||||
return
|
||||
}
|
||||
|
||||
s.running = true
|
||||
s.bufs = make(chan *bytes.Buffer, 32)
|
||||
go s.run()
|
||||
}
|
||||
|
||||
func (s *BufferedSender) withBufferLock(fn func()) {
|
||||
s.bufmx.Lock()
|
||||
fn()
|
||||
s.bufmx.Unlock()
|
||||
}
|
||||
|
||||
func (s *BufferedSender) swapnqueue() {
|
||||
if s.buffer.Len() == 0 {
|
||||
return
|
||||
}
|
||||
ob := s.buffer
|
||||
nb := senderPool.Get()
|
||||
s.buffer = nb
|
||||
s.bufs <- ob
|
||||
}
|
||||
|
||||
func (s *BufferedSender) run() {
|
||||
ticker := time.NewTicker(s.flushInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
doneChan := make(chan bool)
|
||||
go func() {
|
||||
for buf := range s.bufs {
|
||||
s.flush(buf)
|
||||
senderPool.Put(buf)
|
||||
}
|
||||
doneChan <- true
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
s.withBufferLock(func() {
|
||||
s.swapnqueue()
|
||||
})
|
||||
case errChan := <-s.shutdown:
|
||||
s.withBufferLock(func() {
|
||||
s.swapnqueue()
|
||||
})
|
||||
close(s.bufs)
|
||||
<-doneChan
|
||||
errChan <- s.sender.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send to remove endpoint and truncate buffer
|
||||
func (s *BufferedSender) flush(b *bytes.Buffer) (int, error) {
|
||||
bb := b.Bytes()
|
||||
bbl := len(bb)
|
||||
if bb[bbl-1] == '\n' {
|
||||
bb = bb[:bbl-1]
|
||||
}
|
||||
//n, err := s.sender.Send(bytes.TrimSuffix(b.Bytes(), []byte("\n")))
|
||||
n, err := s.sender.Send(bb)
|
||||
b.Truncate(0) // clear the buffer
|
||||
return n, err
|
||||
}
|
||||
|
||||
// NewBufferedSender returns a new BufferedSender
|
||||
//
|
||||
// addr is a string of the format "hostname:port", and must be parsable by
|
||||
// net.ResolveUDPAddr.
|
||||
//
|
||||
// flushInterval is a time.Duration, and specifies the maximum interval for
|
||||
// packet sending. Note that if you send lots of metrics, you will send more
|
||||
// often. This is just a maximal threshold.
|
||||
//
|
||||
// flushBytes specifies the maximum udp packet size you wish to send. If adding
|
||||
// a metric would result in a larger packet than flushBytes, the packet will
|
||||
// first be send, then the new data will be added to the next packet.
|
||||
func NewBufferedSender(addr string, flushInterval time.Duration, flushBytes int) (Sender, error) {
|
||||
simpleSender, err := NewSimpleSender(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sender := &BufferedSender{
|
||||
flushBytes: flushBytes,
|
||||
flushInterval: flushInterval,
|
||||
sender: simpleSender,
|
||||
buffer: senderPool.Get(),
|
||||
shutdown: make(chan chan error),
|
||||
}
|
||||
|
||||
sender.Start()
|
||||
return sender, nil
|
||||
}
|
||||
116
vendor/github.com/cactus/go-statsd-client/statsd/sender_buffered_test.go
generated
vendored
116
vendor/github.com/cactus/go-statsd-client/statsd/sender_buffered_test.go
generated
vendored
@@ -1,116 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type mockSender struct {
|
||||
closeCallCount int
|
||||
}
|
||||
|
||||
func (m *mockSender) Send(data []byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (m *mockSender) Close() error {
|
||||
m.closeCallCount++
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
mockSender := &mockSender{}
|
||||
sender := &BufferedSender{
|
||||
flushBytes: 512,
|
||||
flushInterval: 1 * time.Second,
|
||||
sender: mockSender,
|
||||
buffer: bytes.NewBuffer(make([]byte, 0, 512)),
|
||||
shutdown: make(chan chan error),
|
||||
}
|
||||
|
||||
sender.Close()
|
||||
if mockSender.closeCallCount != 0 {
|
||||
t.Fatalf("expected close to have been called zero times, but got %d", mockSender.closeCallCount)
|
||||
}
|
||||
|
||||
sender.Start()
|
||||
if !sender.running {
|
||||
t.Fatal("sender failed to start")
|
||||
}
|
||||
|
||||
sender.Close()
|
||||
if mockSender.closeCallCount != 1 {
|
||||
t.Fatalf("expected close to have been called once, but got %d", mockSender.closeCallCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseConcurrent(t *testing.T) {
|
||||
mockSender := &mockSender{}
|
||||
sender := &BufferedSender{
|
||||
flushBytes: 512,
|
||||
flushInterval: 1 * time.Second,
|
||||
sender: mockSender,
|
||||
buffer: bytes.NewBuffer(make([]byte, 0, 512)),
|
||||
shutdown: make(chan chan error),
|
||||
}
|
||||
sender.Start()
|
||||
|
||||
const N = 10
|
||||
c := make(chan struct{}, N)
|
||||
for i := 0; i < N; i++ {
|
||||
go func() {
|
||||
sender.Close()
|
||||
c <- struct{}{}
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < N; i++ {
|
||||
<-c
|
||||
}
|
||||
|
||||
if mockSender.closeCallCount != 1 {
|
||||
t.Errorf("expected close to have been called once, but got %d", mockSender.closeCallCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseDuringSendConcurrent(t *testing.T) {
|
||||
mockSender := &mockSender{}
|
||||
sender := &BufferedSender{
|
||||
flushBytes: 512,
|
||||
flushInterval: 1 * time.Second,
|
||||
sender: mockSender,
|
||||
buffer: bytes.NewBuffer(make([]byte, 0, 512)),
|
||||
shutdown: make(chan chan error),
|
||||
}
|
||||
sender.Start()
|
||||
|
||||
const N = 10
|
||||
c := make(chan struct{}, N)
|
||||
for i := 0; i < N; i++ {
|
||||
go func() {
|
||||
for {
|
||||
_, err := sender.Send([]byte("stat:1|c"))
|
||||
if err != nil {
|
||||
c <- struct{}{}
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// senders should error out now
|
||||
// we should not receive any panics
|
||||
sender.Close()
|
||||
for i := 0; i < N; i++ {
|
||||
<-c
|
||||
}
|
||||
|
||||
if mockSender.closeCallCount != 1 {
|
||||
t.Errorf("expected close to have been called once, but got %d", mockSender.closeCallCount)
|
||||
}
|
||||
}
|
||||
81
vendor/github.com/cactus/go-statsd-client/statsd/statsdtest/recorder.go
generated
vendored
81
vendor/github.com/cactus/go-statsd-client/statsd/statsdtest/recorder.go
generated
vendored
@@ -1,81 +0,0 @@
|
||||
package statsdtest
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// RecordingSender implements statsd.Sender but parses individual Stats into a
|
||||
// buffer that can be later inspected instead of sending to some server. It
|
||||
// should constructed with NewRecordingSender().
|
||||
type RecordingSender struct {
|
||||
m sync.Mutex
|
||||
buffer Stats
|
||||
closed bool
|
||||
}
|
||||
|
||||
// NewRecordingSender creates a new RecordingSender for use by a statsd.Client.
|
||||
func NewRecordingSender() *RecordingSender {
|
||||
rs := &RecordingSender{}
|
||||
rs.buffer = make(Stats, 0)
|
||||
return rs
|
||||
}
|
||||
|
||||
// GetSent returns the stats that have been sent. Locks and copies the current
|
||||
// state of the sent Stats.
|
||||
//
|
||||
// The entire buffer of Stat objects (including Stat.Raw is copied).
|
||||
func (rs *RecordingSender) GetSent() Stats {
|
||||
rs.m.Lock()
|
||||
defer rs.m.Unlock()
|
||||
|
||||
results := make(Stats, len(rs.buffer))
|
||||
for i, e := range rs.buffer {
|
||||
results[i] = e
|
||||
results[i].Raw = make([]byte, len(e.Raw))
|
||||
for j, b := range e.Raw {
|
||||
results[i].Raw[j] = b
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// ClearSent locks the sender and clears any Stats that have been recorded.
|
||||
func (rs *RecordingSender) ClearSent() {
|
||||
rs.m.Lock()
|
||||
defer rs.m.Unlock()
|
||||
|
||||
rs.buffer = rs.buffer[:0]
|
||||
}
|
||||
|
||||
// Send parses the provided []byte into stat objects and then appends these to
|
||||
// the buffer of sent stats. Buffer operations are synchronized so it is safe
|
||||
// to call this from multiple goroutines (though contenion will impact
|
||||
// performance so don't use this during a benchmark). Send treats '\n' as a
|
||||
// delimiter between multiple sats in the same []byte.
|
||||
//
|
||||
// Calling after the Sender has been closed will return an error (and not
|
||||
// mutate the buffer).
|
||||
func (rs *RecordingSender) Send(data []byte) (int, error) {
|
||||
sent := ParseStats(data)
|
||||
|
||||
rs.m.Lock()
|
||||
defer rs.m.Unlock()
|
||||
if rs.closed {
|
||||
return 0, errors.New("writing to a closed sender")
|
||||
}
|
||||
|
||||
rs.buffer = append(rs.buffer, sent...)
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// Close marks this sender as closed. Subsequent attempts to Send stats will
|
||||
// result in an error.
|
||||
func (rs *RecordingSender) Close() error {
|
||||
rs.m.Lock()
|
||||
defer rs.m.Unlock()
|
||||
|
||||
rs.closed = true
|
||||
return nil
|
||||
}
|
||||
57
vendor/github.com/cactus/go-statsd-client/statsd/statsdtest/recorder_test.go
generated
vendored
57
vendor/github.com/cactus/go-statsd-client/statsd/statsdtest/recorder_test.go
generated
vendored
@@ -1,57 +0,0 @@
|
||||
package statsdtest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cactus/go-statsd-client/statsd"
|
||||
)
|
||||
|
||||
func TestRecordingSenderIsSender(t *testing.T) {
|
||||
// This ensures that if the Sender interface changes in the future we'll get
|
||||
// compile time failures should the RecordingSender not be updated to meet
|
||||
// the new definition. This keeps changes from inadvertently breaking tests
|
||||
// of folks that use go-statsd-client.
|
||||
var _ statsd.Sender = NewRecordingSender()
|
||||
}
|
||||
|
||||
func TestRecordingSender(t *testing.T) {
|
||||
start := time.Now()
|
||||
rs := new(RecordingSender)
|
||||
statter, err := statsd.NewClientWithSender(rs, "test")
|
||||
if err != nil {
|
||||
t.Errorf("failed to construct client")
|
||||
return
|
||||
}
|
||||
|
||||
statter.Inc("stat", 4444, 1.0)
|
||||
statter.Dec("stat", 5555, 1.0)
|
||||
statter.Set("set-stat", "some string", 1.0)
|
||||
|
||||
d := time.Since(start)
|
||||
statter.TimingDuration("timing", d, 1.0)
|
||||
|
||||
sent := rs.GetSent()
|
||||
if len(sent) != 4 {
|
||||
// just dive out because everything else relies on ordering
|
||||
t.Fatalf("Did not capture all stats sent; got: %s", sent)
|
||||
}
|
||||
|
||||
ms := float64(d) / float64(time.Millisecond)
|
||||
// somewhat fragile in that it assums float rendering within client *shrug*
|
||||
msStr := string(strconv.AppendFloat([]byte(""), ms, 'f', -1, 64))
|
||||
|
||||
expected := Stats{
|
||||
{[]byte("test.stat:4444|c"), "test.stat", "4444", "c", "", true},
|
||||
{[]byte("test.stat:-5555|c"), "test.stat", "-5555", "c", "", true},
|
||||
{[]byte("test.set-stat:some string|s"), "test.set-stat", "some string", "s", "", true},
|
||||
{[]byte(fmt.Sprintf("test.timing:%s|ms", msStr)), "test.timing", msStr, "ms", "", true},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(sent, expected) {
|
||||
t.Errorf("got: %s, want: %s", sent, expected)
|
||||
}
|
||||
}
|
||||
140
vendor/github.com/cactus/go-statsd-client/statsd/statsdtest/stat.go
generated
vendored
140
vendor/github.com/cactus/go-statsd-client/statsd/statsdtest/stat.go
generated
vendored
@@ -1,140 +0,0 @@
|
||||
package statsdtest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Stat contains the raw and extracted stat information from a stat that was
|
||||
// sent by the RecordingSender. Raw will always have the content that was
|
||||
// consumed for this specific stat and Parsed will be set if no errors were hit
|
||||
// pulling information out of it.
|
||||
type Stat struct {
|
||||
Raw []byte
|
||||
Stat string
|
||||
Value string
|
||||
Tag string
|
||||
Rate string
|
||||
Parsed bool
|
||||
}
|
||||
|
||||
// String fulfils the stringer interface
|
||||
func (s *Stat) String() string {
|
||||
return fmt.Sprintf("%s %s %s", s.Stat, s.Value, s.Rate)
|
||||
}
|
||||
|
||||
// ParseStats takes a sequence of bytes destined for a Statsd server and parses
|
||||
// it out into one or more Stat structs. Each struct includes both the raw
|
||||
// bytes (copied, so the src []byte may be reused if desired) as well as each
|
||||
// component it was able to parse out. If parsing was incomplete Stat.Parsed
|
||||
// will be set to false but no error is returned / kept.
|
||||
func ParseStats(src []byte) Stats {
|
||||
d := make([]byte, len(src))
|
||||
for i, b := range src {
|
||||
d[i] = b
|
||||
}
|
||||
// standard protocol indicates one stat per line
|
||||
entries := bytes.Split(d, []byte{'\n'})
|
||||
|
||||
result := make(Stats, len(entries))
|
||||
|
||||
for i, e := range entries {
|
||||
result[i] = Stat{Raw: e}
|
||||
ss := &result[i]
|
||||
|
||||
// : deliniates the stat name from the stat data
|
||||
marker := bytes.IndexByte(e, ':')
|
||||
if marker == -1 {
|
||||
continue
|
||||
}
|
||||
ss.Stat = string(e[0:marker])
|
||||
|
||||
// stat data folows ':' with the form {value}|{type tag}[|@{sample rate}]
|
||||
e = e[marker+1:]
|
||||
marker = bytes.IndexByte(e, '|')
|
||||
if marker == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
ss.Value = string(e[:marker])
|
||||
|
||||
e = e[marker+1:]
|
||||
marker = bytes.IndexByte(e, '|')
|
||||
if marker == -1 {
|
||||
// no sample rate
|
||||
ss.Tag = string(e)
|
||||
} else {
|
||||
ss.Tag = string(e[:marker])
|
||||
e = e[marker+1:]
|
||||
if len(e) == 0 || e[0] != '@' {
|
||||
// sample rate should be prefixed with '@'; bail otherwise
|
||||
continue
|
||||
}
|
||||
ss.Rate = string(e[1:])
|
||||
}
|
||||
|
||||
ss.Parsed = true
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Stats is a slice of Stat
|
||||
type Stats []Stat
|
||||
|
||||
// Unparsed returns any stats that were unable to be completely parsed.
|
||||
func (s Stats) Unparsed() Stats {
|
||||
var r Stats
|
||||
for _, e := range s {
|
||||
if !e.Parsed {
|
||||
r = append(r, e)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// CollectNamed returns all data sent for a given stat name.
|
||||
func (s Stats) CollectNamed(statName string) Stats {
|
||||
return s.Collect(func(e Stat) bool {
|
||||
return e.Stat == statName
|
||||
})
|
||||
}
|
||||
|
||||
// Collect gathers all stats that make some predicate true.
|
||||
func (s Stats) Collect(pred func(Stat) bool) Stats {
|
||||
var r Stats
|
||||
for _, e := range s {
|
||||
if pred(e) {
|
||||
r = append(r, e)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Values returns the values associated with this Stats object.
|
||||
func (s Stats) Values() []string {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
r := make([]string, len(s))
|
||||
for i, e := range s {
|
||||
r[i] = e.Value
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// String fulfils the stringer interface
|
||||
func (s Stats) String() string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
r := make([]string, len(s))
|
||||
for i, e := range s {
|
||||
r[i] = e.String()
|
||||
}
|
||||
return strings.Join(r, "\n")
|
||||
}
|
||||
154
vendor/github.com/cactus/go-statsd-client/statsd/statsdtest/stat_test.go
generated
vendored
154
vendor/github.com/cactus/go-statsd-client/statsd/statsdtest/stat_test.go
generated
vendored
@@ -1,154 +0,0 @@
|
||||
package statsdtest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type parsingTestCase struct {
|
||||
name string
|
||||
sent [][]byte
|
||||
expected Stats
|
||||
}
|
||||
|
||||
var (
|
||||
badStatNameOnly = []byte("foo.bar.baz:")
|
||||
bsnoStat = Stat{
|
||||
Raw: badStatNameOnly,
|
||||
Stat: "foo.bar.baz",
|
||||
Parsed: false,
|
||||
}
|
||||
|
||||
gaugeWithoutRate = []byte("foo.bar.baz:1.000|g")
|
||||
gworStat = Stat{
|
||||
Raw: gaugeWithoutRate,
|
||||
Stat: "foo.bar.baz",
|
||||
Value: "1.000",
|
||||
Tag: "g",
|
||||
Parsed: true,
|
||||
}
|
||||
|
||||
counterWithRate = []byte("foo.bar.baz:1.000|c|@0.75")
|
||||
cwrStat = Stat{
|
||||
Raw: counterWithRate,
|
||||
Stat: "foo.bar.baz",
|
||||
Value: "1.000",
|
||||
Tag: "c",
|
||||
Rate: "0.75",
|
||||
Parsed: true,
|
||||
}
|
||||
|
||||
stringStat = []byte(":some string value|s")
|
||||
sStat = Stat{
|
||||
Raw: stringStat,
|
||||
Stat: "",
|
||||
Value: "some string value",
|
||||
Tag: "s",
|
||||
Parsed: true,
|
||||
}
|
||||
|
||||
badValue = []byte("asoentuh")
|
||||
bvStat = Stat{Raw: badValue}
|
||||
|
||||
testCases = []parsingTestCase{
|
||||
{name: "no stat data",
|
||||
sent: [][]byte{badStatNameOnly},
|
||||
expected: Stats{bsnoStat}},
|
||||
{name: "trivial case",
|
||||
sent: [][]byte{gaugeWithoutRate},
|
||||
expected: Stats{gworStat}},
|
||||
{name: "multiple simple",
|
||||
sent: [][]byte{gaugeWithoutRate, counterWithRate},
|
||||
expected: Stats{gworStat, cwrStat}},
|
||||
{name: "mixed good and bad",
|
||||
sent: [][]byte{badValue, badValue, stringStat, badValue, counterWithRate, badValue},
|
||||
expected: Stats{bvStat, bvStat, sStat, bvStat, cwrStat, bvStat}},
|
||||
}
|
||||
)
|
||||
|
||||
func TestParseBytes(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
got := ParseStats(bytes.Join(tc.sent, []byte("\n")))
|
||||
want := tc.expected
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("%s: got: %+v, want: %+v", tc.name, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsUnparsed(t *testing.T) {
|
||||
start := Stats{bsnoStat, gworStat, bsnoStat, bsnoStat, cwrStat}
|
||||
got := start.Unparsed()
|
||||
want := Stats{bsnoStat, bsnoStat, bsnoStat}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got: %+v, want: %+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsCollectNamed(t *testing.T) {
|
||||
type test struct {
|
||||
name string
|
||||
start Stats
|
||||
want Stats
|
||||
matchOn string
|
||||
}
|
||||
|
||||
cases := []test{
|
||||
{"No matches",
|
||||
Stats{bsnoStat, cwrStat},
|
||||
nil,
|
||||
"foo"},
|
||||
{"One match",
|
||||
Stats{bsnoStat, Stat{Stat: "foo"}, cwrStat},
|
||||
Stats{Stat{Stat: "foo"}},
|
||||
"foo"},
|
||||
{"Two matches",
|
||||
Stats{bsnoStat, Stat{Stat: "foo"}, cwrStat},
|
||||
Stats{bsnoStat, cwrStat},
|
||||
"foo.bar.baz"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
got := c.start.CollectNamed(c.matchOn)
|
||||
if !reflect.DeepEqual(got, c.want) {
|
||||
t.Errorf("%s: got: %+v, want: %+v", c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsCollect(t *testing.T) {
|
||||
type test struct {
|
||||
name string
|
||||
start Stats
|
||||
want Stats
|
||||
pred func(Stat) bool
|
||||
}
|
||||
|
||||
cases := []test{
|
||||
{"Not called",
|
||||
Stats{},
|
||||
nil,
|
||||
func(_ Stat) bool { t.Errorf("should not be called"); return true }},
|
||||
{"Matches value = 1.000",
|
||||
Stats{bsnoStat, gworStat, cwrStat, sStat, bsnoStat},
|
||||
Stats{gworStat, cwrStat},
|
||||
func(s Stat) bool { return s.Value == "1.000" }},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
got := c.start.Collect(c.pred)
|
||||
if !reflect.DeepEqual(got, c.want) {
|
||||
t.Errorf("%s: got: %+v, want: %+v", c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsValues(t *testing.T) {
|
||||
start := Stats{bsnoStat, sStat, gworStat}
|
||||
got := start.Values()
|
||||
want := []string{bsnoStat.Value, sStat.Value, gworStat.Value}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got: %+v, want: %+v", got, want)
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/cactus/go-statsd-client/statsd/validator.go
generated
vendored
26
vendor/github.com/cactus/go-statsd-client/statsd/validator.go
generated
vendored
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// The ValidatorFunc type defines a function that can serve
|
||||
// as a stat name validation function.
|
||||
type ValidatorFunc func(string) error
|
||||
|
||||
var safeName = regexp.MustCompile(`^[a-zA-Z0-9\-_.]+$`)
|
||||
|
||||
// CheckName may be used to validate whether a stat name contains invalid
|
||||
// characters. If invalid characters are found, the function will return an
|
||||
// error.
|
||||
func CheckName(stat string) error {
|
||||
if !safeName.MatchString(stat) {
|
||||
return fmt.Errorf("invalid stat name: %s", stat)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
30
vendor/github.com/cactus/go-statsd-client/statsd/validator_test.go
generated
vendored
30
vendor/github.com/cactus/go-statsd-client/statsd/validator_test.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package statsd
|
||||
|
||||
import "testing"
|
||||
|
||||
var validatorTests = []struct {
|
||||
Stat string
|
||||
Valid bool
|
||||
}{
|
||||
{"test.one", true},
|
||||
{"test#two", false},
|
||||
{"test|three", false},
|
||||
{"test@four", false},
|
||||
}
|
||||
|
||||
func TestValidator(t *testing.T) {
|
||||
var err error
|
||||
for _, tt := range validatorTests {
|
||||
err = CheckName(tt.Stat)
|
||||
switch {
|
||||
case err != nil && tt.Valid:
|
||||
t.Fatal(err)
|
||||
case err == nil && !tt.Valid:
|
||||
t.Fatalf("validation should have failed for %s", tt.Stat)
|
||||
}
|
||||
}
|
||||
}
|
||||
113
vendor/github.com/cactus/go-statsd-client/test-client/main.go
generated
vendored
113
vendor/github.com/cactus/go-statsd-client/test-client/main.go
generated
vendored
@@ -1,113 +0,0 @@
|
||||
// Copyright (c) 2012-2016 Eli Janssen
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/cactus/go-statsd-client/statsd"
|
||||
flags "github.com/jessevdk/go-flags"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// command line flags
|
||||
var opts struct {
|
||||
HostPort string `long:"host" default:"127.0.0.1:8125" description:"host:port of statsd server"`
|
||||
Prefix string `long:"prefix" default:"test-client" description:"Statsd prefix"`
|
||||
StatType string `long:"type" default:"count" description:"stat type to send. Can be one of: timing, count, guage"`
|
||||
StatValue int64 `long:"value" default:"1" description:"Value to send"`
|
||||
Name string `short:"n" long:"name" default:"counter" description:"stat name"`
|
||||
Rate float32 `short:"r" long:"rate" default:"1.0" description:"sample rate"`
|
||||
Volume int `short:"c" long:"count" default:"1000" description:"Number of stats to send. Volume."`
|
||||
Nil bool `long:"nil" description:"Use nil client"`
|
||||
Buffered bool `long:"buffered" description:"Use a buffered client"`
|
||||
Duration time.Duration `short:"d" long:"duration" default:"10s" description:"How long to spread the volume across. For each second of duration, volume/seconds events will be sent."`
|
||||
}
|
||||
|
||||
// parse said flags
|
||||
_, err := flags.Parse(&opts)
|
||||
if err != nil {
|
||||
if e, ok := err.(*flags.Error); ok {
|
||||
if e.Type == flags.ErrHelp {
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
fmt.Printf("Error: %+v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if opts.Nil && opts.Buffered {
|
||||
fmt.Printf("Specifying both nil and buffered together is invalid\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if opts.Name == "" || statsd.CheckName(opts.Name) != nil {
|
||||
fmt.Printf("Stat name contains invalid characters\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if statsd.CheckName(opts.Prefix) != nil {
|
||||
fmt.Printf("Stat prefix contains invalid characters\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var client statsd.Statter
|
||||
if !opts.Nil {
|
||||
if !opts.Buffered {
|
||||
client, err = statsd.NewClient(opts.HostPort, opts.Prefix)
|
||||
} else {
|
||||
client, err = statsd.NewBufferedClient(opts.HostPort, opts.Prefix, opts.Duration/time.Duration(4), 0)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Close()
|
||||
}
|
||||
|
||||
var stat func(stat string, value int64, rate float32) error
|
||||
switch opts.StatType {
|
||||
case "count":
|
||||
stat = func(stat string, value int64, rate float32) error {
|
||||
return client.Inc(stat, value, rate)
|
||||
}
|
||||
case "gauge":
|
||||
stat = func(stat string, value int64, rate float32) error {
|
||||
return client.Gauge(stat, value, rate)
|
||||
}
|
||||
case "timing":
|
||||
stat = func(stat string, value int64, rate float32) error {
|
||||
return client.Timing(stat, value, rate)
|
||||
}
|
||||
default:
|
||||
log.Fatal("Unsupported state type")
|
||||
}
|
||||
|
||||
pertick := opts.Volume / int(opts.Duration.Seconds()) / 10
|
||||
// add some extra time, because the first tick takes a while
|
||||
ender := time.After(opts.Duration + 100*time.Millisecond)
|
||||
c := time.Tick(time.Second / 10)
|
||||
count := 0
|
||||
for {
|
||||
select {
|
||||
case <-c:
|
||||
for x := 0; x < pertick; x++ {
|
||||
err := stat(opts.Name, opts.StatValue, opts.Rate)
|
||||
if err != nil {
|
||||
log.Printf("Got Error: %+v\n", err)
|
||||
break
|
||||
}
|
||||
count++
|
||||
}
|
||||
case <-ender:
|
||||
log.Printf("%d events called\n", count)
|
||||
os.Exit(0)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/dghubble/go-twitter/.gitignore
generated
vendored
2
vendor/github.com/dghubble/go-twitter/.gitignore
generated
vendored
@@ -1,2 +0,0 @@
|
||||
/coverage
|
||||
/bin
|
||||
11
vendor/github.com/dghubble/go-twitter/.travis.yml
generated
vendored
11
vendor/github.com/dghubble/go-twitter/.travis.yml
generated
vendored
@@ -1,11 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- tip
|
||||
install:
|
||||
- go get github.com/golang/lint/golint
|
||||
- go get -v -t ./twitter
|
||||
script:
|
||||
- ./test
|
||||
270
vendor/github.com/dghubble/go-twitter/README.md
generated
vendored
270
vendor/github.com/dghubble/go-twitter/README.md
generated
vendored
@@ -1,270 +0,0 @@
|
||||
|
||||
|
||||
# go-twitter [](https://travis-ci.org/dghubble/go-twitter) [](https://godoc.org/github.com/dghubble/go-twitter)
|
||||
<img align="right" src="https://storage.googleapis.com/dghubble/gopher-on-bird.png">
|
||||
|
||||
go-twitter is a Go client library for the [Twitter API](https://dev.twitter.com/rest/public). Check the [usage](#usage) section or try the [examples](/examples) to see how to access the Twitter API.
|
||||
|
||||
### Features
|
||||
|
||||
* Twitter REST API:
|
||||
* Accounts
|
||||
* Direct Messages
|
||||
* Favorites
|
||||
* Friends
|
||||
* Friendships
|
||||
* Followers
|
||||
* Search
|
||||
* Statuses
|
||||
* Timelines
|
||||
* Users
|
||||
* Twitter Streaming API
|
||||
* Public Streams
|
||||
* User Streams
|
||||
* Site Streams
|
||||
* Firehose Streams
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/dghubble/go-twitter/twitter
|
||||
|
||||
## Documentation
|
||||
|
||||
Read [GoDoc](https://godoc.org/github.com/dghubble/go-twitter/twitter)
|
||||
|
||||
## Usage
|
||||
|
||||
### REST API
|
||||
|
||||
The `twitter` package provides a `Client` for accessing the Twitter API. Here are some example requests.
|
||||
|
||||
```go
|
||||
config := oauth1.NewConfig("consumerKey", "consumerSecret")
|
||||
token := oauth1.NewToken("accessToken", "accessSecret")
|
||||
httpClient := config.Client(oauth1.NoContext, token)
|
||||
|
||||
// Twitter client
|
||||
client := twitter.NewClient(httpClient)
|
||||
|
||||
// Home Timeline
|
||||
tweets, resp, err := client.Timelines.HomeTimeline(&twitter.HomeTimelineParams{
|
||||
Count: 20,
|
||||
})
|
||||
|
||||
// Send a Tweet
|
||||
tweet, resp, err := client.Statuses.Update("just setting up my twttr", nil)
|
||||
|
||||
// Status Show
|
||||
tweet, resp, err := client.Statuses.Show(585613041028431872, nil)
|
||||
|
||||
// Search Tweets
|
||||
search, resp, err := client.Search.Tweets(&twitter.SearchTweetParams{
|
||||
Query: "gopher",
|
||||
})
|
||||
|
||||
// User Show
|
||||
user, resp, err := client.Users.Show(&twitter.UserShowParams{
|
||||
ScreenName: "dghubble",
|
||||
})
|
||||
|
||||
// Followers
|
||||
followers, resp, err := client.Followers.List(&twitter.FollowerListParams{})
|
||||
```
|
||||
|
||||
Authentication is handled by the `http.Client` passed to `NewClient` to handle user auth (OAuth1) or application auth (OAuth2). See the [Authentication](#authentication) section.
|
||||
|
||||
Required parameters are passed as positional arguments. Optional parameters are passed typed params structs (or nil).
|
||||
|
||||
## Streaming API
|
||||
|
||||
The Twitter Public, User, Site, and Firehose Streaming APIs can be accessed through the `Client` `StreamService` which provides methods `Filter`, `Sample`, `User`, `Site`, and `Firehose`.
|
||||
|
||||
Create a `Client` with an authenticated `http.Client`. All stream endpoints require a user auth context so choose an OAuth1 `http.Client`.
|
||||
|
||||
client := twitter.NewClient(httpClient)
|
||||
|
||||
Next, request a managed `Stream` be started.
|
||||
|
||||
#### Filter
|
||||
|
||||
Filter Streams return Tweets that match one or more filtering predicates such as `Track`, `Follow`, and `Locations`.
|
||||
|
||||
```go
|
||||
params := &twitter.StreamFilterParams{
|
||||
Track: []string{"kitten"},
|
||||
StallWarnings: twitter.Bool(true),
|
||||
}
|
||||
stream, err := client.Streams.Filter(params)
|
||||
```
|
||||
|
||||
#### User
|
||||
|
||||
User Streams provide messages specific to the authenticate User and possibly those they follow.
|
||||
|
||||
```go
|
||||
params := &twitter.StreamUserParams{
|
||||
With: "followings",
|
||||
StallWarnings: twitter.Bool(true),
|
||||
}
|
||||
stream, err := client.Streams.User(params)
|
||||
```
|
||||
|
||||
*Note* To see Direct Message events, your consumer application must ask Users for read/write/DM access to their account.
|
||||
|
||||
#### Sample
|
||||
|
||||
Sample Streams return a small sample of public Tweets.
|
||||
|
||||
```go
|
||||
params := &twitter.StreamSampleParams{
|
||||
StallWarnings: twitter.Bool(true),
|
||||
}
|
||||
stream, err := client.Streams.Sample(params)
|
||||
```
|
||||
|
||||
#### Site, Firehose
|
||||
|
||||
Site and Firehose Streams require your application to have special permissions, but their API works the same way.
|
||||
|
||||
### Receiving Messages
|
||||
|
||||
Each `Stream` maintains the connection to the Twitter Streaming API endpoint, receives messages, and sends them on the `Stream.Messages` channel.
|
||||
|
||||
Go channels support range iterations which allow you to read the messages which are of type `interface{}`.
|
||||
|
||||
```go
|
||||
for message := range stream.Messages {
|
||||
fmt.Println(message)
|
||||
}
|
||||
```
|
||||
|
||||
If you run this in your main goroutine, it will receive messages forever unless the stream stops. To continue execution, receive messages using a separate goroutine.
|
||||
|
||||
### Demux
|
||||
|
||||
Receiving messages of type `interface{}` isn't very nice, it means you'll have to type switch and probably filter out message types you don't care about.
|
||||
|
||||
For this, try a `Demux`, like `SwitchDemux`, which receives messages and type switches them to call functions with typed messages.
|
||||
|
||||
For example, say you're only interested in Tweets and Direct Messages.
|
||||
|
||||
```go
|
||||
demux := twitter.NewSwitchDemux()
|
||||
demux.Tweet = func(tweet *twitter.Tweet) {
|
||||
fmt.Println(tweet.Text)
|
||||
}
|
||||
demux.DM = func(dm *twitter.DirectMessage) {
|
||||
fmt.Println(dm.SenderID)
|
||||
}
|
||||
```
|
||||
|
||||
Pass the `Demux` each message or give it the entire `Stream.Message` channel.
|
||||
|
||||
```go
|
||||
for message := range stream.Messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
// or pass the channel
|
||||
demux.HandleChan(stream.Messages)
|
||||
```
|
||||
|
||||
### Stopping
|
||||
|
||||
The `Stream` will stop itself if the stream disconnects and retrying produces unrecoverable errors. When this occurs, `Stream` will close the `stream.Messages` channel, so execution will break out of any message *for range* loops.
|
||||
|
||||
When you are finished receiving from a `Stream`, call `Stop()` which closes the connection, channels, and stops the goroutine **before** returning. This ensures resources are properly cleaned up.
|
||||
|
||||
### Pitfalls
|
||||
|
||||
**Bad**: In this example, `Stop()` is unlikely to be reached. Control stays in the message loop unless the `Stream` becomes disconnected and cannot retry.
|
||||
|
||||
```go
|
||||
// program does not terminate :(
|
||||
stream, _ := client.Streams.Sample(params)
|
||||
for message := range stream.Messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
stream.Stop()
|
||||
```
|
||||
|
||||
**Bad**: Here, messages are received on a non-main goroutine, but then `Stop()` is called immediately. The `Stream` is stopped and the program exits.
|
||||
|
||||
```go
|
||||
// got no messages :(
|
||||
stream, _ := client.Streams.Sample(params)
|
||||
go demux.HandleChan(stream.Messages)
|
||||
stream.Stop()
|
||||
```
|
||||
|
||||
**Good**: For main package scripts, one option is to receive messages in a goroutine and wait for CTRL-C to be pressed, then explicitly stop the `Stream`.
|
||||
|
||||
```go
|
||||
stream, err := client.Streams.Sample(params)
|
||||
go demux.HandleChan(stream.Messages)
|
||||
|
||||
// Wait for SIGINT and SIGTERM (HIT CTRL-C)
|
||||
ch := make(chan os.Signal)
|
||||
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
||||
log.Println(<-ch)
|
||||
|
||||
stream.Stop()
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
The API client accepts an any `http.Client` capable of making user auth (OAuth1) or application auth (OAuth2) authorized requests. See the [dghubble/oauth1](https://github.com/dghubble/oauth1) and [golang/oauth2](https://github.com/golang/oauth2/) packages which can provide such agnostic clients.
|
||||
|
||||
Passing an `http.Client` directly grants you control over the underlying transport, avoids dependencies on particular OAuth1 or OAuth2 packages, and keeps client APIs separate from authentication protocols.
|
||||
|
||||
See the [google/go-github](https://github.com/google/go-github) client which takes the same approach.
|
||||
|
||||
For example, make requests as a consumer application on behalf of a user who has granted access, with OAuth1.
|
||||
|
||||
```go
|
||||
// OAuth1
|
||||
import (
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"github.com/dghubble/oauth1"
|
||||
)
|
||||
|
||||
config := oauth1.NewConfig("consumerKey", "consumerSecret")
|
||||
token := oauth1.NewToken("accessToken", "accessSecret")
|
||||
// http.Client will automatically authorize Requests
|
||||
httpClient := config.Client(oauth1.NoContext, token)
|
||||
|
||||
// Twitter client
|
||||
client := twitter.NewClient(httpClient)
|
||||
```
|
||||
|
||||
If no user auth context is needed, make requests as your application with application auth.
|
||||
|
||||
```go
|
||||
// OAuth2
|
||||
import (
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
config := &oauth2.Config{}
|
||||
token := &oauth2.Token{AccessToken: accessToken}
|
||||
// http.Client will automatically authorize Requests
|
||||
httpClient := config.Client(oauth2.NoContext, token)
|
||||
|
||||
// Twitter client
|
||||
client := twitter.NewClient(httpClient)
|
||||
```
|
||||
|
||||
To implement Login with Twitter for web or mobile, see the gologin [package](https://github.com/dghubble/gologin) and [examples](https://github.com/dghubble/gologin/tree/master/examples/twitter).
|
||||
|
||||
## Roadmap
|
||||
|
||||
* Support gzipped streams
|
||||
* Auto-stop streams in the event of long stalls
|
||||
|
||||
## Contributing
|
||||
|
||||
See the [Contributing Guide](https://gist.github.com/dghubble/be682c123727f70bcfe7).
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](LICENSE)
|
||||
42
vendor/github.com/dghubble/go-twitter/examples/README.md
generated
vendored
42
vendor/github.com/dghubble/go-twitter/examples/README.md
generated
vendored
@@ -1,42 +0,0 @@
|
||||
|
||||
# Examples
|
||||
|
||||
Get the dependencies and examples
|
||||
|
||||
cd examples
|
||||
go get .
|
||||
|
||||
## User Auth (OAuth1)
|
||||
|
||||
A user access token (OAuth1) grants a consumer application access to a user's Twitter resources.
|
||||
|
||||
Setup an OAuth1 `http.Client` with the consumer key and secret and oauth token and secret.
|
||||
|
||||
export TWITTER_CONSUMER_KEY=xxx
|
||||
export TWITTER_CONSUMER_SECRET=xxx
|
||||
export TWITTER_ACCESS_TOKEN=xxx
|
||||
export TWITTER_ACCESS_SECRET=xxx
|
||||
|
||||
To make requests as an application, on behalf of a user, create a `twitter` `Client` to get the home timeline, mention timeline, and more (example will **not** post Tweets).
|
||||
|
||||
go run user-auth.go
|
||||
|
||||
## App Auth (OAuth2)
|
||||
|
||||
An application access token (OAuth2) allows an application to make Twitter API requests for public content, with rate limits counting against the app itself. App auth requests can be made to API endpoints which do not require a user context.
|
||||
|
||||
Setup an OAuth2 `http.Client` with the Twitter application access token.
|
||||
|
||||
export TWITTER_APP_ACCESS_TOKEN=xxx
|
||||
|
||||
To make requests as an application, create a `twitter` `Client` and get public Tweets or timelines or other public content.
|
||||
|
||||
go run app-auth.go
|
||||
|
||||
## Streaming API
|
||||
|
||||
A user access token (OAuth1) is required for Streaming API requests. See above.
|
||||
|
||||
go run streaming.go
|
||||
|
||||
Hit CTRL-C to stop streaming. Uncomment different examples in code to try different streams.
|
||||
71
vendor/github.com/dghubble/go-twitter/examples/app-auth.go
generated
vendored
71
vendor/github.com/dghubble/go-twitter/examples/app-auth.go
generated
vendored
@@ -1,71 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/pkg/flagutil"
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flags := flag.NewFlagSet("app-auth", flag.ExitOnError)
|
||||
accessToken := flags.String("app-access-token", "", "Twitter Application Access Token")
|
||||
flags.Parse(os.Args[1:])
|
||||
flagutil.SetFlagsFromEnv(flags, "TWITTER")
|
||||
|
||||
if *accessToken == "" {
|
||||
log.Fatal("Application Access Token required")
|
||||
}
|
||||
|
||||
config := &oauth2.Config{}
|
||||
token := &oauth2.Token{AccessToken: *accessToken}
|
||||
// OAuth2 http.Client will automatically authorize Requests
|
||||
httpClient := config.Client(oauth2.NoContext, token)
|
||||
|
||||
// Twitter client
|
||||
client := twitter.NewClient(httpClient)
|
||||
|
||||
// user show
|
||||
userShowParams := &twitter.UserShowParams{ScreenName: "golang"}
|
||||
user, _, _ := client.Users.Show(userShowParams)
|
||||
fmt.Printf("USERS SHOW:\n%+v\n", user)
|
||||
|
||||
// users lookup
|
||||
userLookupParams := &twitter.UserLookupParams{ScreenName: []string{"golang", "gophercon"}}
|
||||
users, _, _ := client.Users.Lookup(userLookupParams)
|
||||
fmt.Printf("USERS LOOKUP:\n%+v\n", users)
|
||||
|
||||
// status show
|
||||
statusShowParams := &twitter.StatusShowParams{}
|
||||
tweet, _, _ := client.Statuses.Show(584077528026849280, statusShowParams)
|
||||
fmt.Printf("STATUSES SHOW:\n%+v\n", tweet)
|
||||
|
||||
// statuses lookup
|
||||
statusLookupParams := &twitter.StatusLookupParams{ID: []int64{20}, TweetMode: "extended"}
|
||||
tweets, _, _ := client.Statuses.Lookup([]int64{573893817000140800}, statusLookupParams)
|
||||
fmt.Printf("STATUSES LOOKUP:\n%+v\n", tweets)
|
||||
|
||||
// oEmbed status
|
||||
statusOembedParams := &twitter.StatusOEmbedParams{ID: 691076766878691329, MaxWidth: 500}
|
||||
oembed, _, _ := client.Statuses.OEmbed(statusOembedParams)
|
||||
fmt.Printf("OEMBED TWEET:\n%+v\n", oembed)
|
||||
|
||||
// user timeline
|
||||
userTimelineParams := &twitter.UserTimelineParams{ScreenName: "golang", Count: 2}
|
||||
tweets, _, _ = client.Timelines.UserTimeline(userTimelineParams)
|
||||
fmt.Printf("USER TIMELINE:\n%+v\n", tweets)
|
||||
|
||||
// search tweets
|
||||
searchTweetParams := &twitter.SearchTweetParams{
|
||||
Query: "happy birthday",
|
||||
TweetMode: "extended",
|
||||
Count: 3,
|
||||
}
|
||||
search, _, _ := client.Search.Tweets(searchTweetParams)
|
||||
fmt.Printf("SEARCH TWEETS:\n%+v\n", search)
|
||||
fmt.Printf("SEARCH METADATA:\n%+v\n", search.Metadata)
|
||||
}
|
||||
91
vendor/github.com/dghubble/go-twitter/examples/streaming.go
generated
vendored
91
vendor/github.com/dghubble/go-twitter/examples/streaming.go
generated
vendored
@@ -1,91 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/coreos/pkg/flagutil"
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"github.com/dghubble/oauth1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flags := flag.NewFlagSet("user-auth", flag.ExitOnError)
|
||||
consumerKey := flags.String("consumer-key", "", "Twitter Consumer Key")
|
||||
consumerSecret := flags.String("consumer-secret", "", "Twitter Consumer Secret")
|
||||
accessToken := flags.String("access-token", "", "Twitter Access Token")
|
||||
accessSecret := flags.String("access-secret", "", "Twitter Access Secret")
|
||||
flags.Parse(os.Args[1:])
|
||||
flagutil.SetFlagsFromEnv(flags, "TWITTER")
|
||||
|
||||
if *consumerKey == "" || *consumerSecret == "" || *accessToken == "" || *accessSecret == "" {
|
||||
log.Fatal("Consumer key/secret and Access token/secret required")
|
||||
}
|
||||
|
||||
config := oauth1.NewConfig(*consumerKey, *consumerSecret)
|
||||
token := oauth1.NewToken(*accessToken, *accessSecret)
|
||||
// OAuth1 http.Client will automatically authorize Requests
|
||||
httpClient := config.Client(oauth1.NoContext, token)
|
||||
|
||||
// Twitter Client
|
||||
client := twitter.NewClient(httpClient)
|
||||
|
||||
// Convenience Demux demultiplexed stream messages
|
||||
demux := twitter.NewSwitchDemux()
|
||||
demux.Tweet = func(tweet *twitter.Tweet) {
|
||||
fmt.Println(tweet.Text)
|
||||
}
|
||||
demux.DM = func(dm *twitter.DirectMessage) {
|
||||
fmt.Println(dm.SenderID)
|
||||
}
|
||||
demux.Event = func(event *twitter.Event) {
|
||||
fmt.Printf("%#v\n", event)
|
||||
}
|
||||
|
||||
fmt.Println("Starting Stream...")
|
||||
|
||||
// FILTER
|
||||
filterParams := &twitter.StreamFilterParams{
|
||||
Track: []string{"cat"},
|
||||
StallWarnings: twitter.Bool(true),
|
||||
}
|
||||
stream, err := client.Streams.Filter(filterParams)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// USER (quick test: auth'd user likes a tweet -> event)
|
||||
// userParams := &twitter.StreamUserParams{
|
||||
// StallWarnings: twitter.Bool(true),
|
||||
// With: "followings",
|
||||
// Language: []string{"en"},
|
||||
// }
|
||||
// stream, err := client.Streams.User(userParams)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
|
||||
// SAMPLE
|
||||
// sampleParams := &twitter.StreamSampleParams{
|
||||
// StallWarnings: twitter.Bool(true),
|
||||
// }
|
||||
// stream, err := client.Streams.Sample(sampleParams)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
|
||||
// Receive messages until stopped or stream quits
|
||||
go demux.HandleChan(stream.Messages)
|
||||
|
||||
// Wait for SIGINT and SIGTERM (HIT CTRL-C)
|
||||
ch := make(chan os.Signal)
|
||||
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
||||
log.Println(<-ch)
|
||||
|
||||
fmt.Println("Stopping Stream...")
|
||||
stream.Stop()
|
||||
}
|
||||
70
vendor/github.com/dghubble/go-twitter/examples/user-auth.go
generated
vendored
70
vendor/github.com/dghubble/go-twitter/examples/user-auth.go
generated
vendored
@@ -1,70 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/pkg/flagutil"
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"github.com/dghubble/oauth1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flags := flag.NewFlagSet("user-auth", flag.ExitOnError)
|
||||
consumerKey := flags.String("consumer-key", "", "Twitter Consumer Key")
|
||||
consumerSecret := flags.String("consumer-secret", "", "Twitter Consumer Secret")
|
||||
accessToken := flags.String("access-token", "", "Twitter Access Token")
|
||||
accessSecret := flags.String("access-secret", "", "Twitter Access Secret")
|
||||
flags.Parse(os.Args[1:])
|
||||
flagutil.SetFlagsFromEnv(flags, "TWITTER")
|
||||
|
||||
if *consumerKey == "" || *consumerSecret == "" || *accessToken == "" || *accessSecret == "" {
|
||||
log.Fatal("Consumer key/secret and Access token/secret required")
|
||||
}
|
||||
|
||||
config := oauth1.NewConfig(*consumerKey, *consumerSecret)
|
||||
token := oauth1.NewToken(*accessToken, *accessSecret)
|
||||
// OAuth1 http.Client will automatically authorize Requests
|
||||
httpClient := config.Client(oauth1.NoContext, token)
|
||||
|
||||
// Twitter client
|
||||
client := twitter.NewClient(httpClient)
|
||||
|
||||
// Verify Credentials
|
||||
verifyParams := &twitter.AccountVerifyParams{
|
||||
SkipStatus: twitter.Bool(true),
|
||||
IncludeEmail: twitter.Bool(true),
|
||||
}
|
||||
user, _, _ := client.Accounts.VerifyCredentials(verifyParams)
|
||||
fmt.Printf("User's ACCOUNT:\n%+v\n", user)
|
||||
|
||||
// Home Timeline
|
||||
homeTimelineParams := &twitter.HomeTimelineParams{
|
||||
Count: 2,
|
||||
TweetMode: "extended",
|
||||
}
|
||||
tweets, _, _ := client.Timelines.HomeTimeline(homeTimelineParams)
|
||||
fmt.Printf("User's HOME TIMELINE:\n%+v\n", tweets)
|
||||
|
||||
// Mention Timeline
|
||||
mentionTimelineParams := &twitter.MentionTimelineParams{
|
||||
Count: 2,
|
||||
TweetMode: "extended",
|
||||
}
|
||||
tweets, _, _ = client.Timelines.MentionTimeline(mentionTimelineParams)
|
||||
fmt.Printf("User's MENTION TIMELINE:\n%+v\n", tweets)
|
||||
|
||||
// Retweets of Me Timeline
|
||||
retweetTimelineParams := &twitter.RetweetsOfMeTimelineParams{
|
||||
Count: 2,
|
||||
TweetMode: "extended",
|
||||
}
|
||||
tweets, _, _ = client.Timelines.RetweetsOfMeTimeline(retweetTimelineParams)
|
||||
fmt.Printf("User's 'RETWEETS OF ME' TIMELINE:\n%+v\n", tweets)
|
||||
|
||||
// Update (POST!) Tweet (uncomment to run)
|
||||
// tweet, _, _ := client.Statuses.Update("just setting up my twttr", nil)
|
||||
// fmt.Printf("Posted Tweet\n%v\n", tweet)
|
||||
}
|
||||
23
vendor/github.com/dghubble/go-twitter/test
generated
vendored
23
vendor/github.com/dghubble/go-twitter/test
generated
vendored
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
PKGS=$(go list ./... | grep -v /examples)
|
||||
FORMATTABLE="$(ls -d */)"
|
||||
LINTABLE=$(go list ./...)
|
||||
|
||||
go test $PKGS -cover
|
||||
go vet $PKGS
|
||||
|
||||
echo "Checking gofmt..."
|
||||
fmtRes=$(gofmt -l $FORMATTABLE)
|
||||
if [ -n "${fmtRes}" ]; then
|
||||
echo -e "gofmt checking failed:\n${fmtRes}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "Checking golint..."
|
||||
lintRes=$(echo $LINTABLE | xargs -n 1 golint)
|
||||
if [ -n "${lintRes}" ]; then
|
||||
echo -e "golint checking failed:\n${lintRes}"
|
||||
exit 2
|
||||
fi
|
||||
37
vendor/github.com/dghubble/go-twitter/twitter/accounts.go
generated
vendored
37
vendor/github.com/dghubble/go-twitter/twitter/accounts.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// AccountService provides a method for account credential verification.
|
||||
type AccountService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newAccountService returns a new AccountService.
|
||||
func newAccountService(sling *sling.Sling) *AccountService {
|
||||
return &AccountService{
|
||||
sling: sling.Path("account/"),
|
||||
}
|
||||
}
|
||||
|
||||
// AccountVerifyParams are the params for AccountService.VerifyCredentials.
|
||||
type AccountVerifyParams struct {
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
SkipStatus *bool `url:"skip_status,omitempty"`
|
||||
IncludeEmail *bool `url:"include_email,omitempty"`
|
||||
}
|
||||
|
||||
// VerifyCredentials returns the authorized user if credentials are valid and
|
||||
// returns an error otherwise.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/get/account/verify_credentials
|
||||
func (s *AccountService) VerifyCredentials(params *AccountVerifyParams) (*User, *http.Response, error) {
|
||||
user := new(User)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("verify_credentials.json").QueryStruct(params).Receive(user, apiError)
|
||||
return user, resp, relevantError(err, *apiError)
|
||||
}
|
||||
27
vendor/github.com/dghubble/go-twitter/twitter/accounts_test.go
generated
vendored
27
vendor/github.com/dghubble/go-twitter/twitter/accounts_test.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAccountService_VerifyCredentials(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/account/verify_credentials.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"include_entities": "false", "include_email": "true"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"name": "Dalton Hubble", "id": 623265148}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
user, _, err := client.Accounts.VerifyCredentials(&AccountVerifyParams{IncludeEntities: Bool(false), IncludeEmail: Bool(true)})
|
||||
expected := &User{Name: "Dalton Hubble", ID: 623265148}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, user)
|
||||
}
|
||||
25
vendor/github.com/dghubble/go-twitter/twitter/backoffs.go
generated
vendored
25
vendor/github.com/dghubble/go-twitter/twitter/backoffs.go
generated
vendored
@@ -1,25 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
)
|
||||
|
||||
func newExponentialBackOff() *backoff.ExponentialBackOff {
|
||||
b := backoff.NewExponentialBackOff()
|
||||
b.InitialInterval = 5 * time.Second
|
||||
b.Multiplier = 2.0
|
||||
b.MaxInterval = 320 * time.Second
|
||||
b.Reset()
|
||||
return b
|
||||
}
|
||||
|
||||
func newAggressiveExponentialBackOff() *backoff.ExponentialBackOff {
|
||||
b := backoff.NewExponentialBackOff()
|
||||
b.InitialInterval = 1 * time.Minute
|
||||
b.Multiplier = 2.0
|
||||
b.MaxInterval = 16 * time.Minute
|
||||
b.Reset()
|
||||
return b
|
||||
}
|
||||
37
vendor/github.com/dghubble/go-twitter/twitter/backoffs_test.go
generated
vendored
37
vendor/github.com/dghubble/go-twitter/twitter/backoffs_test.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewExponentialBackOff(t *testing.T) {
|
||||
b := newExponentialBackOff()
|
||||
assert.Equal(t, 5*time.Second, b.InitialInterval)
|
||||
assert.Equal(t, 2.0, b.Multiplier)
|
||||
assert.Equal(t, 320*time.Second, b.MaxInterval)
|
||||
}
|
||||
|
||||
func TestNewAggressiveExponentialBackOff(t *testing.T) {
|
||||
b := newAggressiveExponentialBackOff()
|
||||
assert.Equal(t, 1*time.Minute, b.InitialInterval)
|
||||
assert.Equal(t, 2.0, b.Multiplier)
|
||||
assert.Equal(t, 16*time.Minute, b.MaxInterval)
|
||||
}
|
||||
|
||||
// BackoffRecorder is an implementation of backoff.BackOff that records
|
||||
// calls to NextBackOff and Reset for later inspection in tests.
|
||||
type BackOffRecorder struct {
|
||||
Count int
|
||||
}
|
||||
|
||||
func (b *BackOffRecorder) NextBackOff() time.Duration {
|
||||
b.Count++
|
||||
return 1 * time.Nanosecond
|
||||
}
|
||||
|
||||
func (b *BackOffRecorder) Reset() {
|
||||
b.Count = 0
|
||||
}
|
||||
88
vendor/github.com/dghubble/go-twitter/twitter/demux.go
generated
vendored
88
vendor/github.com/dghubble/go-twitter/twitter/demux.go
generated
vendored
@@ -1,88 +0,0 @@
|
||||
package twitter
|
||||
|
||||
// A Demux receives interface{} messages individually or from a channel and
|
||||
// sends those messages to one or more outputs determined by the
|
||||
// implementation.
|
||||
type Demux interface {
|
||||
Handle(message interface{})
|
||||
HandleChan(messages <-chan interface{})
|
||||
}
|
||||
|
||||
// SwitchDemux receives messages and uses a type switch to send each typed
|
||||
// message to a handler function.
|
||||
type SwitchDemux struct {
|
||||
All func(message interface{})
|
||||
Tweet func(tweet *Tweet)
|
||||
DM func(dm *DirectMessage)
|
||||
StatusDeletion func(deletion *StatusDeletion)
|
||||
LocationDeletion func(LocationDeletion *LocationDeletion)
|
||||
StreamLimit func(limit *StreamLimit)
|
||||
StatusWithheld func(statusWithheld *StatusWithheld)
|
||||
UserWithheld func(userWithheld *UserWithheld)
|
||||
StreamDisconnect func(disconnect *StreamDisconnect)
|
||||
Warning func(warning *StallWarning)
|
||||
FriendsList func(friendsList *FriendsList)
|
||||
Event func(event *Event)
|
||||
Other func(message interface{})
|
||||
}
|
||||
|
||||
// NewSwitchDemux returns a new SwitchMux which has NoOp handler functions.
|
||||
func NewSwitchDemux() SwitchDemux {
|
||||
return SwitchDemux{
|
||||
All: func(message interface{}) {},
|
||||
Tweet: func(tweet *Tweet) {},
|
||||
DM: func(dm *DirectMessage) {},
|
||||
StatusDeletion: func(deletion *StatusDeletion) {},
|
||||
LocationDeletion: func(LocationDeletion *LocationDeletion) {},
|
||||
StreamLimit: func(limit *StreamLimit) {},
|
||||
StatusWithheld: func(statusWithheld *StatusWithheld) {},
|
||||
UserWithheld: func(userWithheld *UserWithheld) {},
|
||||
StreamDisconnect: func(disconnect *StreamDisconnect) {},
|
||||
Warning: func(warning *StallWarning) {},
|
||||
FriendsList: func(friendsList *FriendsList) {},
|
||||
Event: func(event *Event) {},
|
||||
Other: func(message interface{}) {},
|
||||
}
|
||||
}
|
||||
|
||||
// Handle determines the type of a message and calls the corresponding receiver
|
||||
// function with the typed message. All messages are passed to the All func.
|
||||
// Messages with unmatched types are passed to the Other func.
|
||||
func (d SwitchDemux) Handle(message interface{}) {
|
||||
d.All(message)
|
||||
switch msg := message.(type) {
|
||||
case *Tweet:
|
||||
d.Tweet(msg)
|
||||
case *DirectMessage:
|
||||
d.DM(msg)
|
||||
case *StatusDeletion:
|
||||
d.StatusDeletion(msg)
|
||||
case *LocationDeletion:
|
||||
d.LocationDeletion(msg)
|
||||
case *StreamLimit:
|
||||
d.StreamLimit(msg)
|
||||
case *StatusWithheld:
|
||||
d.StatusWithheld(msg)
|
||||
case *UserWithheld:
|
||||
d.UserWithheld(msg)
|
||||
case *StreamDisconnect:
|
||||
d.StreamDisconnect(msg)
|
||||
case *StallWarning:
|
||||
d.Warning(msg)
|
||||
case *FriendsList:
|
||||
d.FriendsList(msg)
|
||||
case *Event:
|
||||
d.Event(msg)
|
||||
default:
|
||||
d.Other(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleChan receives messages and calls the corresponding receiver function
|
||||
// with the typed message. All messages are passed to the All func. Messages
|
||||
// with unmatched type are passed to the Other func.
|
||||
func (d SwitchDemux) HandleChan(messages <-chan interface{}) {
|
||||
for message := range messages {
|
||||
d.Handle(message)
|
||||
}
|
||||
}
|
||||
135
vendor/github.com/dghubble/go-twitter/twitter/demux_test.go
generated
vendored
135
vendor/github.com/dghubble/go-twitter/twitter/demux_test.go
generated
vendored
@@ -1,135 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDemux_Handle(t *testing.T) {
|
||||
messages, expectedCounts := exampleMessages()
|
||||
counts := &counter{}
|
||||
demux := newCounterDemux(counts)
|
||||
for _, message := range messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
assert.Equal(t, expectedCounts, counts)
|
||||
}
|
||||
|
||||
func TestDemux_HandleChan(t *testing.T) {
|
||||
messages, expectedCounts := exampleMessages()
|
||||
counts := &counter{}
|
||||
demux := newCounterDemux(counts)
|
||||
ch := make(chan interface{})
|
||||
// stream messages into channel
|
||||
go func() {
|
||||
for _, msg := range messages {
|
||||
ch <- msg
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
// handle channel messages until exhausted
|
||||
demux.HandleChan(ch)
|
||||
assert.Equal(t, expectedCounts, counts)
|
||||
}
|
||||
|
||||
// counter counts stream messages by type for testing.
|
||||
type counter struct {
|
||||
all int
|
||||
tweet int
|
||||
dm int
|
||||
statusDeletion int
|
||||
locationDeletion int
|
||||
streamLimit int
|
||||
statusWithheld int
|
||||
userWithheld int
|
||||
streamDisconnect int
|
||||
stallWarning int
|
||||
friendsList int
|
||||
event int
|
||||
other int
|
||||
}
|
||||
|
||||
// newCounterDemux returns a Demux which counts message types.
|
||||
func newCounterDemux(counter *counter) Demux {
|
||||
demux := NewSwitchDemux()
|
||||
demux.All = func(interface{}) {
|
||||
counter.all++
|
||||
}
|
||||
demux.Tweet = func(*Tweet) {
|
||||
counter.tweet++
|
||||
}
|
||||
demux.DM = func(*DirectMessage) {
|
||||
counter.dm++
|
||||
}
|
||||
demux.StatusDeletion = func(*StatusDeletion) {
|
||||
counter.statusDeletion++
|
||||
}
|
||||
demux.LocationDeletion = func(*LocationDeletion) {
|
||||
counter.locationDeletion++
|
||||
}
|
||||
demux.StreamLimit = func(*StreamLimit) {
|
||||
counter.streamLimit++
|
||||
}
|
||||
demux.StatusWithheld = func(*StatusWithheld) {
|
||||
counter.statusWithheld++
|
||||
}
|
||||
demux.UserWithheld = func(*UserWithheld) {
|
||||
counter.userWithheld++
|
||||
}
|
||||
demux.StreamDisconnect = func(*StreamDisconnect) {
|
||||
counter.streamDisconnect++
|
||||
}
|
||||
demux.Warning = func(*StallWarning) {
|
||||
counter.stallWarning++
|
||||
}
|
||||
demux.FriendsList = func(*FriendsList) {
|
||||
counter.friendsList++
|
||||
}
|
||||
demux.Event = func(*Event) {
|
||||
counter.event++
|
||||
}
|
||||
demux.Other = func(interface{}) {
|
||||
counter.other++
|
||||
}
|
||||
return demux
|
||||
}
|
||||
|
||||
// examples messages returns a test stream of messages and the expected
|
||||
// counts of each message type.
|
||||
func exampleMessages() (messages []interface{}, expectedCounts *counter) {
|
||||
var (
|
||||
tweet = &Tweet{}
|
||||
dm = &DirectMessage{}
|
||||
statusDeletion = &StatusDeletion{}
|
||||
locationDeletion = &LocationDeletion{}
|
||||
streamLimit = &StreamLimit{}
|
||||
statusWithheld = &StatusWithheld{}
|
||||
userWithheld = &UserWithheld{}
|
||||
streamDisconnect = &StreamDisconnect{}
|
||||
stallWarning = &StallWarning{}
|
||||
friendsList = &FriendsList{}
|
||||
event = &Event{}
|
||||
otherA = func() {}
|
||||
otherB = struct{}{}
|
||||
)
|
||||
messages = []interface{}{tweet, dm, statusDeletion, locationDeletion,
|
||||
streamLimit, statusWithheld, userWithheld, streamDisconnect,
|
||||
stallWarning, friendsList, event, otherA, otherB}
|
||||
expectedCounts = &counter{
|
||||
all: len(messages),
|
||||
tweet: 1,
|
||||
dm: 1,
|
||||
statusDeletion: 1,
|
||||
locationDeletion: 1,
|
||||
streamLimit: 1,
|
||||
statusWithheld: 1,
|
||||
userWithheld: 1,
|
||||
streamDisconnect: 1,
|
||||
stallWarning: 1,
|
||||
friendsList: 1,
|
||||
event: 1,
|
||||
other: 2,
|
||||
}
|
||||
return messages, expectedCounts
|
||||
}
|
||||
130
vendor/github.com/dghubble/go-twitter/twitter/direct_messages.go
generated
vendored
130
vendor/github.com/dghubble/go-twitter/twitter/direct_messages.go
generated
vendored
@@ -1,130 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// DirectMessage is a direct message to a single recipient.
|
||||
type DirectMessage struct {
|
||||
CreatedAt string `json:"created_at"`
|
||||
Entities *Entities `json:"entities"`
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
Recipient *User `json:"recipient"`
|
||||
RecipientID int64 `json:"recipient_id"`
|
||||
RecipientScreenName string `json:"recipient_screen_name"`
|
||||
Sender *User `json:"sender"`
|
||||
SenderID int64 `json:"sender_id"`
|
||||
SenderScreenName string `json:"sender_screen_name"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// DirectMessageService provides methods for accessing Twitter direct message
|
||||
// API endpoints.
|
||||
type DirectMessageService struct {
|
||||
baseSling *sling.Sling
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newDirectMessageService returns a new DirectMessageService.
|
||||
func newDirectMessageService(sling *sling.Sling) *DirectMessageService {
|
||||
return &DirectMessageService{
|
||||
baseSling: sling.New(),
|
||||
sling: sling.Path("direct_messages/"),
|
||||
}
|
||||
}
|
||||
|
||||
// directMessageShowParams are the parameters for DirectMessageService.Show
|
||||
type directMessageShowParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
}
|
||||
|
||||
// Show returns the requested Direct Message.
|
||||
// Requires a user auth context with DM scope.
|
||||
// https://dev.twitter.com/rest/reference/get/direct_messages/show
|
||||
func (s *DirectMessageService) Show(id int64) (*DirectMessage, *http.Response, error) {
|
||||
params := &directMessageShowParams{ID: id}
|
||||
dm := new(DirectMessage)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(dm, apiError)
|
||||
return dm, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// DirectMessageGetParams are the parameters for DirectMessageService.Get
|
||||
type DirectMessageGetParams struct {
|
||||
SinceID int64 `url:"since_id,omitempty"`
|
||||
MaxID int64 `url:"max_id,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
SkipStatus *bool `url:"skip_status,omitempty"`
|
||||
}
|
||||
|
||||
// Get returns recent Direct Messages received by the authenticated user.
|
||||
// Requires a user auth context with DM scope.
|
||||
// https://dev.twitter.com/rest/reference/get/direct_messages
|
||||
func (s *DirectMessageService) Get(params *DirectMessageGetParams) ([]DirectMessage, *http.Response, error) {
|
||||
dms := new([]DirectMessage)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.baseSling.New().Get("direct_messages.json").QueryStruct(params).Receive(dms, apiError)
|
||||
return *dms, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// DirectMessageSentParams are the parameters for DirectMessageService.Sent
|
||||
type DirectMessageSentParams struct {
|
||||
SinceID int64 `url:"since_id,omitempty"`
|
||||
MaxID int64 `url:"max_id,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
Page int `url:"page,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
}
|
||||
|
||||
// Sent returns recent Direct Messages sent by the authenticated user.
|
||||
// Requires a user auth context with DM scope.
|
||||
// https://dev.twitter.com/rest/reference/get/direct_messages/sent
|
||||
func (s *DirectMessageService) Sent(params *DirectMessageSentParams) ([]DirectMessage, *http.Response, error) {
|
||||
dms := new([]DirectMessage)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("sent.json").QueryStruct(params).Receive(dms, apiError)
|
||||
return *dms, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// DirectMessageNewParams are the parameters for DirectMessageService.New
|
||||
type DirectMessageNewParams struct {
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
Text string `url:"text"`
|
||||
}
|
||||
|
||||
// New sends a new Direct Message to a specified user as the authenticated
|
||||
// user.
|
||||
// Requires a user auth context with DM scope.
|
||||
// https://dev.twitter.com/rest/reference/post/direct_messages/new
|
||||
func (s *DirectMessageService) New(params *DirectMessageNewParams) (*DirectMessage, *http.Response, error) {
|
||||
dm := new(DirectMessage)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Post("new.json").BodyForm(params).Receive(dm, apiError)
|
||||
return dm, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// DirectMessageDestroyParams are the parameters for DirectMessageService.Destroy
|
||||
type DirectMessageDestroyParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
}
|
||||
|
||||
// Destroy deletes the Direct Message with the given id and returns it if
|
||||
// successful.
|
||||
// Requires a user auth context with DM scope.
|
||||
// https://dev.twitter.com/rest/reference/post/direct_messages/destroy
|
||||
func (s *DirectMessageService) Destroy(id int64, params *DirectMessageDestroyParams) (*DirectMessage, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &DirectMessageDestroyParams{}
|
||||
}
|
||||
params.ID = id
|
||||
dm := new(DirectMessage)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Post("destroy.json").BodyForm(params).Receive(dm, apiError)
|
||||
return dm, resp, relevantError(err, *apiError)
|
||||
}
|
||||
110
vendor/github.com/dghubble/go-twitter/twitter/direct_messages_test.go
generated
vendored
110
vendor/github.com/dghubble/go-twitter/twitter/direct_messages_test.go
generated
vendored
@@ -1,110 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
testDM = DirectMessage{
|
||||
ID: 240136858829479936,
|
||||
Recipient: &User{ScreenName: "theSeanCook"},
|
||||
Sender: &User{ScreenName: "s0c1alm3dia"},
|
||||
Text: "hello world",
|
||||
}
|
||||
testDMIDStr = "240136858829479936"
|
||||
testDMJSON = `{"id": 240136858829479936,"recipient": {"screen_name": "theSeanCook"},"sender": {"screen_name": "s0c1alm3dia"},"text": "hello world"}`
|
||||
)
|
||||
|
||||
func TestDirectMessageService_Show(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/direct_messages/show.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"id": testDMIDStr}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, testDMJSON)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
dms, _, err := client.DirectMessages.Show(testDM.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, &testDM, dms)
|
||||
}
|
||||
|
||||
func TestDirectMessageService_Get(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/direct_messages.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"since_id": "589147592367431680", "count": "1"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[`+testDMJSON+`]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &DirectMessageGetParams{SinceID: 589147592367431680, Count: 1}
|
||||
dms, _, err := client.DirectMessages.Get(params)
|
||||
expected := []DirectMessage{testDM}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, dms)
|
||||
}
|
||||
|
||||
func TestDirectMessageService_Sent(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/direct_messages/sent.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"since_id": "589147592367431680", "count": "1"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[`+testDMJSON+`]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &DirectMessageSentParams{SinceID: 589147592367431680, Count: 1}
|
||||
dms, _, err := client.DirectMessages.Sent(params)
|
||||
expected := []DirectMessage{testDM}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, dms)
|
||||
}
|
||||
|
||||
func TestDirectMessageService_New(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/direct_messages/new.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertPostForm(t, map[string]string{"screen_name": "theseancook", "text": "hello world"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, testDMJSON)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &DirectMessageNewParams{ScreenName: "theseancook", Text: "hello world"}
|
||||
dm, _, err := client.DirectMessages.New(params)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, &testDM, dm)
|
||||
}
|
||||
|
||||
func TestDirectMessageService_Destroy(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/direct_messages/destroy.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertPostForm(t, map[string]string{"id": testDMIDStr}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, testDMJSON)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
dm, _, err := client.DirectMessages.Destroy(testDM.ID, nil)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, &testDM, dm)
|
||||
}
|
||||
70
vendor/github.com/dghubble/go-twitter/twitter/doc.go
generated
vendored
70
vendor/github.com/dghubble/go-twitter/twitter/doc.go
generated
vendored
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
Package twitter provides a Client for the Twitter API.
|
||||
|
||||
|
||||
The twitter package provides a Client for accessing the Twitter API. Here are
|
||||
some example requests.
|
||||
|
||||
// Twitter client
|
||||
client := twitter.NewClient(httpClient)
|
||||
// Home Timeline
|
||||
tweets, resp, err := client.Timelines.HomeTimeline(&HomeTimelineParams{})
|
||||
// Send a Tweet
|
||||
tweet, resp, err := client.Statuses.Update("just setting up my twttr", nil)
|
||||
// Status Show
|
||||
tweet, resp, err := client.Statuses.Show(585613041028431872, nil)
|
||||
// User Show
|
||||
params := &twitter.UserShowParams{ScreenName: "dghubble"}
|
||||
user, resp, err := client.Users.Show(params)
|
||||
// Followers
|
||||
followers, resp, err := client.Followers.List(&FollowerListParams{})
|
||||
|
||||
Required parameters are passed as positional arguments. Optional parameters
|
||||
are passed in a typed params struct (or pass nil).
|
||||
|
||||
Authentication
|
||||
|
||||
By design, the Twitter Client accepts any http.Client so user auth (OAuth1) or
|
||||
application auth (OAuth2) requests can be made by using the appropriate
|
||||
authenticated client. Use the https://github.com/dghubble/oauth1 and
|
||||
https://github.com/golang/oauth2 packages to obtain an http.Client which
|
||||
transparently authorizes requests.
|
||||
|
||||
For example, make requests as a consumer application on behalf of a user who
|
||||
has granted access, with OAuth1.
|
||||
|
||||
// OAuth1
|
||||
import (
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"github.com/dghubble/oauth1"
|
||||
)
|
||||
|
||||
config := oauth1.NewConfig("consumerKey", "consumerSecret")
|
||||
token := oauth1.NewToken("accessToken", "accessSecret")
|
||||
// http.Client will automatically authorize Requests
|
||||
httpClient := config.Client(oauth1.NoContext, token)
|
||||
|
||||
// twitter client
|
||||
client := twitter.NewClient(httpClient)
|
||||
|
||||
If no user auth context is needed, make requests as your application with
|
||||
application auth.
|
||||
|
||||
// OAuth2
|
||||
import (
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
config := &oauth2.Config{}
|
||||
token := &oauth2.Token{AccessToken: accessToken}
|
||||
// http.Client will automatically authorize Requests
|
||||
httpClient := config.Client(oauth2.NoContext, token)
|
||||
|
||||
// twitter client
|
||||
client := twitter.NewClient(httpClient)
|
||||
|
||||
To implement Login with Twitter, see https://github.com/dghubble/gologin.
|
||||
|
||||
*/
|
||||
package twitter
|
||||
104
vendor/github.com/dghubble/go-twitter/twitter/entities.go
generated
vendored
104
vendor/github.com/dghubble/go-twitter/twitter/entities.go
generated
vendored
@@ -1,104 +0,0 @@
|
||||
package twitter
|
||||
|
||||
// Entities represent metadata and context info parsed from Twitter components.
|
||||
// https://dev.twitter.com/overview/api/entities
|
||||
// TODO: symbols
|
||||
type Entities struct {
|
||||
Hashtags []HashtagEntity `json:"hashtags"`
|
||||
Media []MediaEntity `json:"media"`
|
||||
Urls []URLEntity `json:"urls"`
|
||||
UserMentions []MentionEntity `json:"user_mentions"`
|
||||
}
|
||||
|
||||
// HashtagEntity represents a hashtag which has been parsed from text.
|
||||
type HashtagEntity struct {
|
||||
Indices Indices `json:"indices"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// URLEntity represents a URL which has been parsed from text.
|
||||
type URLEntity struct {
|
||||
Indices Indices `json:"indices"`
|
||||
DisplayURL string `json:"display_url"`
|
||||
ExpandedURL string `json:"expanded_url"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// MediaEntity represents media elements associated with a Tweet.
|
||||
type MediaEntity struct {
|
||||
URLEntity
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
MediaURL string `json:"media_url"`
|
||||
MediaURLHttps string `json:"media_url_https"`
|
||||
SourceStatusID int64 `json:"source_status_id"`
|
||||
SourceStatusIDStr string `json:"source_status_id_str"`
|
||||
Type string `json:"type"`
|
||||
Sizes MediaSizes `json:"sizes"`
|
||||
VideoInfo VideoInfo `json:"video_info"`
|
||||
}
|
||||
|
||||
// MentionEntity represents Twitter user mentions parsed from text.
|
||||
type MentionEntity struct {
|
||||
Indices Indices `json:"indices"`
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
Name string `json:"name"`
|
||||
ScreenName string `json:"screen_name"`
|
||||
}
|
||||
|
||||
// UserEntities contain Entities parsed from User url and description fields.
|
||||
// https://dev.twitter.com/overview/api/entities-in-twitter-objects#users
|
||||
type UserEntities struct {
|
||||
URL Entities `json:"url"`
|
||||
Description Entities `json:"description"`
|
||||
}
|
||||
|
||||
// ExtendedEntity contains media information.
|
||||
// https://dev.twitter.com/overview/api/entities-in-twitter-objects#extended_entities
|
||||
type ExtendedEntity struct {
|
||||
Media []MediaEntity `json:"media"`
|
||||
}
|
||||
|
||||
// Indices represent the start and end offsets within text.
|
||||
type Indices [2]int
|
||||
|
||||
// Start returns the index at which an entity starts, inclusive.
|
||||
func (i Indices) Start() int {
|
||||
return i[0]
|
||||
}
|
||||
|
||||
// End returns the index at which an entity ends, exclusive.
|
||||
func (i Indices) End() int {
|
||||
return i[1]
|
||||
}
|
||||
|
||||
// MediaSizes contain the different size media that are available.
|
||||
// https://dev.twitter.com/overview/api/entities#obj-sizes
|
||||
type MediaSizes struct {
|
||||
Thumb MediaSize `json:"thumb"`
|
||||
Large MediaSize `json:"large"`
|
||||
Medium MediaSize `json:"medium"`
|
||||
Small MediaSize `json:"small"`
|
||||
}
|
||||
|
||||
// MediaSize describes the height, width, and resizing method used.
|
||||
type MediaSize struct {
|
||||
Width int `json:"w"`
|
||||
Height int `json:"h"`
|
||||
Resize string `json:"resize"`
|
||||
}
|
||||
|
||||
// VideoInfo is available on video media objects.
|
||||
type VideoInfo struct {
|
||||
AspectRatio [2]int `json:"aspect_ratio"`
|
||||
DurationMillis int `json:"duration_millis"`
|
||||
Variants []VideoVariant `json:"variants"`
|
||||
}
|
||||
|
||||
// VideoVariant describes one of the available video formats.
|
||||
type VideoVariant struct {
|
||||
ContentType string `json:"content_type"`
|
||||
Bitrate int `json:"bitrate"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
22
vendor/github.com/dghubble/go-twitter/twitter/entities_test.go
generated
vendored
22
vendor/github.com/dghubble/go-twitter/twitter/entities_test.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIndices(t *testing.T) {
|
||||
cases := []struct {
|
||||
pair Indices
|
||||
expectedStart int
|
||||
expectedEnd int
|
||||
}{
|
||||
{Indices{}, 0, 0},
|
||||
{Indices{25, 47}, 25, 47},
|
||||
}
|
||||
for _, c := range cases {
|
||||
assert.Equal(t, c.expectedStart, c.pair.Start())
|
||||
assert.Equal(t, c.expectedEnd, c.pair.End())
|
||||
}
|
||||
}
|
||||
47
vendor/github.com/dghubble/go-twitter/twitter/errors.go
generated
vendored
47
vendor/github.com/dghubble/go-twitter/twitter/errors.go
generated
vendored
@@ -1,47 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// APIError represents a Twitter API Error response
|
||||
// https://dev.twitter.com/overview/api/response-codes
|
||||
type APIError struct {
|
||||
Errors []ErrorDetail `json:"errors"`
|
||||
}
|
||||
|
||||
// ErrorDetail represents an individual item in an APIError.
|
||||
type ErrorDetail struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
func (e APIError) Error() string {
|
||||
if len(e.Errors) > 0 {
|
||||
err := e.Errors[0]
|
||||
return fmt.Sprintf("twitter: %d %v", err.Code, err.Message)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Empty returns true if empty. Otherwise, at least 1 error message/code is
|
||||
// present and false is returned.
|
||||
func (e APIError) Empty() bool {
|
||||
if len(e.Errors) == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// relevantError returns any non-nil http-related error (creating the request,
|
||||
// getting the response, decoding) if any. If the decoded apiError is non-zero
|
||||
// the apiError is returned. Otherwise, no errors occurred, returns nil.
|
||||
func relevantError(httpError error, apiError APIError) error {
|
||||
if httpError != nil {
|
||||
return httpError
|
||||
}
|
||||
if apiError.Empty() {
|
||||
return nil
|
||||
}
|
||||
return apiError
|
||||
}
|
||||
48
vendor/github.com/dghubble/go-twitter/twitter/errors_test.go
generated
vendored
48
vendor/github.com/dghubble/go-twitter/twitter/errors_test.go
generated
vendored
@@ -1,48 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var errAPI = APIError{
|
||||
Errors: []ErrorDetail{
|
||||
ErrorDetail{Message: "Status is a duplicate", Code: 187},
|
||||
},
|
||||
}
|
||||
var errHTTP = fmt.Errorf("unknown host")
|
||||
|
||||
func TestAPIError_Error(t *testing.T) {
|
||||
err := APIError{}
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, "", err.Error())
|
||||
}
|
||||
if assert.Error(t, errAPI) {
|
||||
assert.Equal(t, "twitter: 187 Status is a duplicate", errAPI.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIError_Empty(t *testing.T) {
|
||||
err := APIError{}
|
||||
assert.True(t, err.Empty())
|
||||
assert.False(t, errAPI.Empty())
|
||||
}
|
||||
|
||||
func TestRelevantError(t *testing.T) {
|
||||
cases := []struct {
|
||||
httpError error
|
||||
apiError APIError
|
||||
expected error
|
||||
}{
|
||||
{nil, APIError{}, nil},
|
||||
{nil, errAPI, errAPI},
|
||||
{errHTTP, APIError{}, errHTTP},
|
||||
{errHTTP, errAPI, errHTTP},
|
||||
}
|
||||
for _, c := range cases {
|
||||
err := relevantError(c.httpError, c.apiError)
|
||||
assert.Equal(t, c.expected, err)
|
||||
}
|
||||
}
|
||||
72
vendor/github.com/dghubble/go-twitter/twitter/favorites.go
generated
vendored
72
vendor/github.com/dghubble/go-twitter/twitter/favorites.go
generated
vendored
@@ -1,72 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// FavoriteService provides methods for accessing Twitter favorite API endpoints.
|
||||
//
|
||||
// Note: the like action was known as favorite before November 3, 2015; the
|
||||
// historical naming remains in API methods and object properties.
|
||||
type FavoriteService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newFavoriteService returns a new FavoriteService.
|
||||
func newFavoriteService(sling *sling.Sling) *FavoriteService {
|
||||
return &FavoriteService{
|
||||
sling: sling.Path("favorites/"),
|
||||
}
|
||||
}
|
||||
|
||||
// FavoriteListParams are the parameters for FavoriteService.List.
|
||||
type FavoriteListParams struct {
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
SinceID int64 `url:"since_id,omitempty"`
|
||||
MaxID int64 `url:"max_id,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// List returns liked Tweets from the specified user.
|
||||
// https://dev.twitter.com/rest/reference/get/favorites/list
|
||||
func (s *FavoriteService) List(params *FavoriteListParams) ([]Tweet, *http.Response, error) {
|
||||
favorites := new([]Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("list.json").QueryStruct(params).Receive(favorites, apiError)
|
||||
return *favorites, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// FavoriteCreateParams are the parameters for FavoriteService.Create.
|
||||
type FavoriteCreateParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
}
|
||||
|
||||
// Create favorites the specified tweet.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/post/favorites/create
|
||||
func (s *FavoriteService) Create(params *FavoriteCreateParams) (*Tweet, *http.Response, error) {
|
||||
tweet := new(Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Post("create.json").QueryStruct(params).Receive(tweet, apiError)
|
||||
return tweet, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// FavoriteDestroyParams are the parameters for FavoriteService.Destroy.
|
||||
type FavoriteDestroyParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
}
|
||||
|
||||
// Destroy un-favorites the specified tweet.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/post/favorites/destroy
|
||||
func (s *FavoriteService) Destroy(params *FavoriteDestroyParams) (*Tweet, *http.Response, error) {
|
||||
tweet := new(Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Post("destroy.json").QueryStruct(params).Receive(tweet, apiError)
|
||||
return tweet, resp, relevantError(err, *apiError)
|
||||
}
|
||||
65
vendor/github.com/dghubble/go-twitter/twitter/favorites_test.go
generated
vendored
65
vendor/github.com/dghubble/go-twitter/twitter/favorites_test.go
generated
vendored
@@ -1,65 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFavoriteService_List(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/favorites/list.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"user_id": "113419064", "since_id": "101492475", "include_entities": "false"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"text": "Gophercon talks!"}, {"text": "Why gophers are so adorable"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
tweets, _, err := client.Favorites.List(&FavoriteListParams{UserID: 113419064, SinceID: 101492475, IncludeEntities: Bool(false)})
|
||||
expected := []Tweet{Tweet{Text: "Gophercon talks!"}, Tweet{Text: "Why gophers are so adorable"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweets)
|
||||
}
|
||||
|
||||
func TestFavoriteService_Create(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/favorites/create.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertPostForm(t, map[string]string{"id": "12345"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id": 581980947630845953, "text": "very informative tweet"}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FavoriteCreateParams{ID: 12345}
|
||||
tweet, _, err := client.Favorites.Create(params)
|
||||
assert.Nil(t, err)
|
||||
expected := &Tweet{ID: 581980947630845953, Text: "very informative tweet"}
|
||||
assert.Equal(t, expected, tweet)
|
||||
}
|
||||
|
||||
func TestFavoriteService_Destroy(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/favorites/destroy.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertPostForm(t, map[string]string{"id": "12345"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id": 581980947630845953, "text": "very unhappy tweet"}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FavoriteDestroyParams{ID: 12345}
|
||||
tweet, _, err := client.Favorites.Destroy(params)
|
||||
assert.Nil(t, err)
|
||||
expected := &Tweet{ID: 581980947630845953, Text: "very unhappy tweet"}
|
||||
assert.Equal(t, expected, tweet)
|
||||
}
|
||||
73
vendor/github.com/dghubble/go-twitter/twitter/followers.go
generated
vendored
73
vendor/github.com/dghubble/go-twitter/twitter/followers.go
generated
vendored
@@ -1,73 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// FollowerIDs is a cursored collection of follower ids.
|
||||
type FollowerIDs struct {
|
||||
IDs []int64 `json:"ids"`
|
||||
NextCursor int64 `json:"next_cursor"`
|
||||
NextCursorStr string `json:"next_cursor_str"`
|
||||
PreviousCursor int64 `json:"previous_cursor"`
|
||||
PreviousCursorStr string `json:"previous_cursor_str"`
|
||||
}
|
||||
|
||||
// Followers is a cursored collection of followers.
|
||||
type Followers struct {
|
||||
Users []User `json:"users"`
|
||||
NextCursor int64 `json:"next_cursor"`
|
||||
NextCursorStr string `json:"next_cursor_str"`
|
||||
PreviousCursor int64 `json:"previous_cursor"`
|
||||
PreviousCursorStr string `json:"previous_cursor_str"`
|
||||
}
|
||||
|
||||
// FollowerService provides methods for accessing Twitter followers endpoints.
|
||||
type FollowerService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newFollowerService returns a new FollowerService.
|
||||
func newFollowerService(sling *sling.Sling) *FollowerService {
|
||||
return &FollowerService{
|
||||
sling: sling.Path("followers/"),
|
||||
}
|
||||
}
|
||||
|
||||
// FollowerIDParams are the parameters for FollowerService.Ids
|
||||
type FollowerIDParams struct {
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
Cursor int64 `url:"cursor,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
}
|
||||
|
||||
// IDs returns a cursored collection of user ids following the specified user.
|
||||
// https://dev.twitter.com/rest/reference/get/followers/ids
|
||||
func (s *FollowerService) IDs(params *FollowerIDParams) (*FollowerIDs, *http.Response, error) {
|
||||
ids := new(FollowerIDs)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("ids.json").QueryStruct(params).Receive(ids, apiError)
|
||||
return ids, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// FollowerListParams are the parameters for FollowerService.List
|
||||
type FollowerListParams struct {
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
Cursor int64 `url:"cursor,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
SkipStatus *bool `url:"skip_status,omitempty"`
|
||||
IncludeUserEntities *bool `url:"include_user_entities,omitempty"`
|
||||
}
|
||||
|
||||
// List returns a cursored collection of Users following the specified user.
|
||||
// https://dev.twitter.com/rest/reference/get/followers/list
|
||||
func (s *FollowerService) List(params *FollowerListParams) (*Followers, *http.Response, error) {
|
||||
followers := new(Followers)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("list.json").QueryStruct(params).Receive(followers, apiError)
|
||||
return followers, resp, relevantError(err, *apiError)
|
||||
}
|
||||
69
vendor/github.com/dghubble/go-twitter/twitter/followers_test.go
generated
vendored
69
vendor/github.com/dghubble/go-twitter/twitter/followers_test.go
generated
vendored
@@ -1,69 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFollowerService_Ids(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/followers/ids.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"user_id": "623265148", "count": "5", "cursor": "1516933260114270762"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"ids":[178082406,3318241001,1318020818,191714329,376703838],"next_cursor":1516837838944119498,"next_cursor_str":"1516837838944119498","previous_cursor":-1516924983503961435,"previous_cursor_str":"-1516924983503961435"}`)
|
||||
})
|
||||
expected := &FollowerIDs{
|
||||
IDs: []int64{178082406, 3318241001, 1318020818, 191714329, 376703838},
|
||||
NextCursor: 1516837838944119498,
|
||||
NextCursorStr: "1516837838944119498",
|
||||
PreviousCursor: -1516924983503961435,
|
||||
PreviousCursorStr: "-1516924983503961435",
|
||||
}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FollowerIDParams{
|
||||
UserID: 623265148,
|
||||
Count: 5,
|
||||
Cursor: 1516933260114270762,
|
||||
}
|
||||
followerIDs, _, err := client.Followers.IDs(params)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, followerIDs)
|
||||
}
|
||||
|
||||
func TestFollowerService_List(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/followers/list.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"screen_name": "dghubble", "count": "5", "cursor": "1516933260114270762", "skip_status": "true", "include_user_entities": "false"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"users": [{"id": 123}], "next_cursor":1516837838944119498,"next_cursor_str":"1516837838944119498","previous_cursor":-1516924983503961435,"previous_cursor_str":"-1516924983503961435"}`)
|
||||
})
|
||||
expected := &Followers{
|
||||
Users: []User{User{ID: 123}},
|
||||
NextCursor: 1516837838944119498,
|
||||
NextCursorStr: "1516837838944119498",
|
||||
PreviousCursor: -1516924983503961435,
|
||||
PreviousCursorStr: "-1516924983503961435",
|
||||
}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FollowerListParams{
|
||||
ScreenName: "dghubble",
|
||||
Count: 5,
|
||||
Cursor: 1516933260114270762,
|
||||
SkipStatus: Bool(true),
|
||||
IncludeUserEntities: Bool(false),
|
||||
}
|
||||
followers, _, err := client.Followers.List(params)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, followers)
|
||||
}
|
||||
73
vendor/github.com/dghubble/go-twitter/twitter/friends.go
generated
vendored
73
vendor/github.com/dghubble/go-twitter/twitter/friends.go
generated
vendored
@@ -1,73 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// FriendIDs is a cursored collection of friend ids.
|
||||
type FriendIDs struct {
|
||||
IDs []int64 `json:"ids"`
|
||||
NextCursor int64 `json:"next_cursor"`
|
||||
NextCursorStr string `json:"next_cursor_str"`
|
||||
PreviousCursor int64 `json:"previous_cursor"`
|
||||
PreviousCursorStr string `json:"previous_cursor_str"`
|
||||
}
|
||||
|
||||
// Friends is a cursored collection of friends.
|
||||
type Friends struct {
|
||||
Users []User `json:"users"`
|
||||
NextCursor int64 `json:"next_cursor"`
|
||||
NextCursorStr string `json:"next_cursor_str"`
|
||||
PreviousCursor int64 `json:"previous_cursor"`
|
||||
PreviousCursorStr string `json:"previous_cursor_str"`
|
||||
}
|
||||
|
||||
// FriendService provides methods for accessing Twitter friends endpoints.
|
||||
type FriendService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newFriendService returns a new FriendService.
|
||||
func newFriendService(sling *sling.Sling) *FriendService {
|
||||
return &FriendService{
|
||||
sling: sling.Path("friends/"),
|
||||
}
|
||||
}
|
||||
|
||||
// FriendIDParams are the parameters for FriendService.Ids
|
||||
type FriendIDParams struct {
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
Cursor int64 `url:"cursor,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
}
|
||||
|
||||
// IDs returns a cursored collection of user ids that the specified user is following.
|
||||
// https://dev.twitter.com/rest/reference/get/friends/ids
|
||||
func (s *FriendService) IDs(params *FriendIDParams) (*FriendIDs, *http.Response, error) {
|
||||
ids := new(FriendIDs)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("ids.json").QueryStruct(params).Receive(ids, apiError)
|
||||
return ids, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// FriendListParams are the parameters for FriendService.List
|
||||
type FriendListParams struct {
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
Cursor int64 `url:"cursor,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
SkipStatus *bool `url:"skip_status,omitempty"`
|
||||
IncludeUserEntities *bool `url:"include_user_entities,omitempty"`
|
||||
}
|
||||
|
||||
// List returns a cursored collection of Users that the specified user is following.
|
||||
// https://dev.twitter.com/rest/reference/get/friends/list
|
||||
func (s *FriendService) List(params *FriendListParams) (*Friends, *http.Response, error) {
|
||||
friends := new(Friends)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("list.json").QueryStruct(params).Receive(friends, apiError)
|
||||
return friends, resp, relevantError(err, *apiError)
|
||||
}
|
||||
69
vendor/github.com/dghubble/go-twitter/twitter/friends_test.go
generated
vendored
69
vendor/github.com/dghubble/go-twitter/twitter/friends_test.go
generated
vendored
@@ -1,69 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFriendService_Ids(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/friends/ids.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"user_id": "623265148", "count": "5", "cursor": "1516933260114270762"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"ids":[178082406,3318241001,1318020818,191714329,376703838],"next_cursor":1516837838944119498,"next_cursor_str":"1516837838944119498","previous_cursor":-1516924983503961435,"previous_cursor_str":"-1516924983503961435"}`)
|
||||
})
|
||||
expected := &FriendIDs{
|
||||
IDs: []int64{178082406, 3318241001, 1318020818, 191714329, 376703838},
|
||||
NextCursor: 1516837838944119498,
|
||||
NextCursorStr: "1516837838944119498",
|
||||
PreviousCursor: -1516924983503961435,
|
||||
PreviousCursorStr: "-1516924983503961435",
|
||||
}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FriendIDParams{
|
||||
UserID: 623265148,
|
||||
Count: 5,
|
||||
Cursor: 1516933260114270762,
|
||||
}
|
||||
friendIDs, _, err := client.Friends.IDs(params)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, friendIDs)
|
||||
}
|
||||
|
||||
func TestFriendService_List(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/friends/list.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"screen_name": "dghubble", "count": "5", "cursor": "1516933260114270762", "skip_status": "true", "include_user_entities": "false"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"users": [{"id": 123}], "next_cursor":1516837838944119498,"next_cursor_str":"1516837838944119498","previous_cursor":-1516924983503961435,"previous_cursor_str":"-1516924983503961435"}`)
|
||||
})
|
||||
expected := &Friends{
|
||||
Users: []User{User{ID: 123}},
|
||||
NextCursor: 1516837838944119498,
|
||||
NextCursorStr: "1516837838944119498",
|
||||
PreviousCursor: -1516924983503961435,
|
||||
PreviousCursorStr: "-1516924983503961435",
|
||||
}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FriendListParams{
|
||||
ScreenName: "dghubble",
|
||||
Count: 5,
|
||||
Cursor: 1516933260114270762,
|
||||
SkipStatus: Bool(true),
|
||||
IncludeUserEntities: Bool(false),
|
||||
}
|
||||
friends, _, err := client.Friends.List(params)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, friends)
|
||||
}
|
||||
134
vendor/github.com/dghubble/go-twitter/twitter/friendships.go
generated
vendored
134
vendor/github.com/dghubble/go-twitter/twitter/friendships.go
generated
vendored
@@ -1,134 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// FriendshipService provides methods for accessing Twitter friendship API
|
||||
// endpoints.
|
||||
type FriendshipService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newFriendshipService returns a new FriendshipService.
|
||||
func newFriendshipService(sling *sling.Sling) *FriendshipService {
|
||||
return &FriendshipService{
|
||||
sling: sling.Path("friendships/"),
|
||||
}
|
||||
}
|
||||
|
||||
// FriendshipCreateParams are parameters for FriendshipService.Create
|
||||
type FriendshipCreateParams struct {
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
Follow *bool `url:"follow,omitempty"`
|
||||
}
|
||||
|
||||
// Create creates a friendship to (i.e. follows) the specified user and
|
||||
// returns the followed user.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/post/friendships/create
|
||||
func (s *FriendshipService) Create(params *FriendshipCreateParams) (*User, *http.Response, error) {
|
||||
user := new(User)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Post("create.json").QueryStruct(params).Receive(user, apiError)
|
||||
return user, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// FriendshipShowParams are paramenters for FriendshipService.Show
|
||||
type FriendshipShowParams struct {
|
||||
SourceID int64 `url:"source_id,omitempty"`
|
||||
SourceScreenName string `url:"source_screen_name,omitempty"`
|
||||
TargetID int64 `url:"target_id,omitempty"`
|
||||
TargetScreenName string `url:"target_screen_name,omitempty"`
|
||||
}
|
||||
|
||||
// Show returns the relationship between two arbitrary users.
|
||||
// Requires a user auth or an app context.
|
||||
// https://dev.twitter.com/rest/reference/get/friendships/show
|
||||
func (s *FriendshipService) Show(params *FriendshipShowParams) (*Relationship, *http.Response, error) {
|
||||
response := new(RelationshipResponse)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(response, apiError)
|
||||
return response.Relationship, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// RelationshipResponse contains a relationship.
|
||||
type RelationshipResponse struct {
|
||||
Relationship *Relationship `json:"relationship"`
|
||||
}
|
||||
|
||||
// Relationship represents the relation between a source user and target user.
|
||||
type Relationship struct {
|
||||
Source RelationshipSource `json:"source"`
|
||||
Target RelationshipTarget `json:"target"`
|
||||
}
|
||||
|
||||
// RelationshipSource represents the source user.
|
||||
type RelationshipSource struct {
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
ScreenName string `json:"screen_name"`
|
||||
Following bool `json:"following"`
|
||||
FollowedBy bool `json:"followed_by"`
|
||||
CanDM bool `json:"can_dm"`
|
||||
Blocking bool `json:"blocking"`
|
||||
Muting bool `json:"muting"`
|
||||
AllReplies bool `json:"all_replies"`
|
||||
WantRetweets bool `json:"want_retweets"`
|
||||
MarkedSpam bool `json:"marked_spam"`
|
||||
NotificationsEnabled bool `json:"notifications_enabled"`
|
||||
}
|
||||
|
||||
// RelationshipTarget represents the target user.
|
||||
type RelationshipTarget struct {
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
ScreenName string `json:"screen_name"`
|
||||
Following bool `json:"following"`
|
||||
FollowedBy bool `json:"followed_by"`
|
||||
}
|
||||
|
||||
// FriendshipDestroyParams are paramenters for FriendshipService.Destroy
|
||||
type FriendshipDestroyParams struct {
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
}
|
||||
|
||||
// Destroy destroys a friendship to (i.e. unfollows) the specified user and
|
||||
// returns the unfollowed user.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/post/friendships/destroy
|
||||
func (s *FriendshipService) Destroy(params *FriendshipDestroyParams) (*User, *http.Response, error) {
|
||||
user := new(User)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Post("destroy.json").QueryStruct(params).Receive(user, apiError)
|
||||
return user, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// FriendshipPendingParams are paramenters for FriendshipService.Outgoing
|
||||
type FriendshipPendingParams struct {
|
||||
Cursor int64 `url:"cursor,omitempty"`
|
||||
}
|
||||
|
||||
// Outgoing returns a collection of numeric IDs for every protected user for whom the authenticating
|
||||
// user has a pending follow request.
|
||||
// https://dev.twitter.com/rest/reference/get/friendships/outgoing
|
||||
func (s *FriendshipService) Outgoing(params *FriendshipPendingParams) (*FriendIDs, *http.Response, error) {
|
||||
ids := new(FriendIDs)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("outgoing.json").QueryStruct(params).Receive(ids, apiError)
|
||||
return ids, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// Incoming returns a collection of numeric IDs for every user who has a pending request to
|
||||
// follow the authenticating user.
|
||||
// https://dev.twitter.com/rest/reference/get/friendships/incoming
|
||||
func (s *FriendshipService) Incoming(params *FriendshipPendingParams) (*FriendIDs, *http.Response, error) {
|
||||
ids := new(FriendIDs)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("incoming.json").QueryStruct(params).Receive(ids, apiError)
|
||||
return ids, resp, relevantError(err, *apiError)
|
||||
}
|
||||
123
vendor/github.com/dghubble/go-twitter/twitter/friendships_test.go
generated
vendored
123
vendor/github.com/dghubble/go-twitter/twitter/friendships_test.go
generated
vendored
@@ -1,123 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFriendshipService_Create(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/friendships/create.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertPostForm(t, map[string]string{"user_id": "12345"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id": 12345, "name": "Doug Williams"}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FriendshipCreateParams{UserID: 12345}
|
||||
user, _, err := client.Friendships.Create(params)
|
||||
assert.Nil(t, err)
|
||||
expected := &User{ID: 12345, Name: "Doug Williams"}
|
||||
assert.Equal(t, expected, user)
|
||||
}
|
||||
|
||||
func TestFriendshipService_Show(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/friendships/show.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"source_screen_name": "foo", "target_screen_name": "bar"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{ "relationship": { "source": { "can_dm": false, "muting": true, "id_str": "8649302", "id": 8649302, "screen_name": "foo"}, "target": { "id_str": "12148", "id": 12148, "screen_name": "bar", "following": true, "followed_by": false } } }`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FriendshipShowParams{SourceScreenName: "foo", TargetScreenName: "bar"}
|
||||
relationship, _, err := client.Friendships.Show(params)
|
||||
assert.Nil(t, err)
|
||||
expected := &Relationship{
|
||||
Source: RelationshipSource{ID: 8649302, ScreenName: "foo", IDStr: "8649302", CanDM: false, Muting: true, WantRetweets: false},
|
||||
Target: RelationshipTarget{ID: 12148, ScreenName: "bar", IDStr: "12148", Following: true, FollowedBy: false},
|
||||
}
|
||||
assert.Equal(t, expected, relationship)
|
||||
}
|
||||
|
||||
func TestFriendshipService_Destroy(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/friendships/destroy.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertPostForm(t, map[string]string{"user_id": "12345"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id": 12345, "name": "Doug Williams"}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FriendshipDestroyParams{UserID: 12345}
|
||||
user, _, err := client.Friendships.Destroy(params)
|
||||
assert.Nil(t, err)
|
||||
expected := &User{ID: 12345, Name: "Doug Williams"}
|
||||
assert.Equal(t, expected, user)
|
||||
}
|
||||
|
||||
func TestFriendshipService_Outgoing(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/friendships/outgoing.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"cursor": "1516933260114270762"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"ids":[178082406,3318241001,1318020818,191714329,376703838],"next_cursor":1516837838944119498,"next_cursor_str":"1516837838944119498","previous_cursor":-1516924983503961435,"previous_cursor_str":"-1516924983503961435"}`)
|
||||
})
|
||||
expected := &FriendIDs{
|
||||
IDs: []int64{178082406, 3318241001, 1318020818, 191714329, 376703838},
|
||||
NextCursor: 1516837838944119498,
|
||||
NextCursorStr: "1516837838944119498",
|
||||
PreviousCursor: -1516924983503961435,
|
||||
PreviousCursorStr: "-1516924983503961435",
|
||||
}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FriendshipPendingParams{
|
||||
Cursor: 1516933260114270762,
|
||||
}
|
||||
friendIDs, _, err := client.Friendships.Outgoing(params)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, friendIDs)
|
||||
}
|
||||
|
||||
func TestFriendshipService_Incoming(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/friendships/incoming.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"cursor": "1516933260114270762"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"ids":[178082406,3318241001,1318020818,191714329,376703838],"next_cursor":1516837838944119498,"next_cursor_str":"1516837838944119498","previous_cursor":-1516924983503961435,"previous_cursor_str":"-1516924983503961435"}`)
|
||||
})
|
||||
expected := &FriendIDs{
|
||||
IDs: []int64{178082406, 3318241001, 1318020818, 191714329, 376703838},
|
||||
NextCursor: 1516837838944119498,
|
||||
NextCursorStr: "1516837838944119498",
|
||||
PreviousCursor: -1516924983503961435,
|
||||
PreviousCursorStr: "-1516924983503961435",
|
||||
}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &FriendshipPendingParams{
|
||||
Cursor: 1516933260114270762,
|
||||
}
|
||||
friendIDs, _, err := client.Friendships.Incoming(params)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, friendIDs)
|
||||
}
|
||||
62
vendor/github.com/dghubble/go-twitter/twitter/search.go
generated
vendored
62
vendor/github.com/dghubble/go-twitter/twitter/search.go
generated
vendored
@@ -1,62 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// Search represents the result of a Tweet search.
|
||||
type Search struct {
|
||||
Statuses []Tweet `json:"statuses"`
|
||||
Metadata *SearchMetadata `json:"search_metadata"`
|
||||
}
|
||||
|
||||
// SearchMetadata describes a Search result.
|
||||
type SearchMetadata struct {
|
||||
Count int `json:"count"`
|
||||
SinceID int64 `json:"since_id"`
|
||||
SinceIDStr string `json:"since_id_str"`
|
||||
MaxID int64 `json:"max_id"`
|
||||
MaxIDStr string `json:"max_id_str"`
|
||||
RefreshURL string `json:"refresh_url"`
|
||||
NextResults string `json:"next_results"`
|
||||
CompletedIn float64 `json:"completed_in"`
|
||||
Query string `json:"query"`
|
||||
}
|
||||
|
||||
// SearchService provides methods for accessing Twitter search API endpoints.
|
||||
type SearchService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newSearchService returns a new SearchService.
|
||||
func newSearchService(sling *sling.Sling) *SearchService {
|
||||
return &SearchService{
|
||||
sling: sling.Path("search/"),
|
||||
}
|
||||
}
|
||||
|
||||
// SearchTweetParams are the parameters for SearchService.Tweets
|
||||
type SearchTweetParams struct {
|
||||
Query string `url:"q,omitempty"`
|
||||
Geocode string `url:"geocode,omitempty"`
|
||||
Lang string `url:"lang,omitempty"`
|
||||
Locale string `url:"locale,omitempty"`
|
||||
ResultType string `url:"result_type,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
SinceID int64 `url:"since_id,omitempty"`
|
||||
MaxID int64 `url:"max_id,omitempty"`
|
||||
Until string `url:"until,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// Tweets returns a collection of Tweets matching a search query.
|
||||
// https://dev.twitter.com/rest/reference/get/search/tweets
|
||||
func (s *SearchService) Tweets(params *SearchTweetParams) (*Search, *http.Response, error) {
|
||||
search := new(Search)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("tweets.json").QueryStruct(params).Receive(search, apiError)
|
||||
return search, resp, relevantError(err, *apiError)
|
||||
}
|
||||
46
vendor/github.com/dghubble/go-twitter/twitter/search_test.go
generated
vendored
46
vendor/github.com/dghubble/go-twitter/twitter/search_test.go
generated
vendored
@@ -1,46 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSearchService_Tweets(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/search/tweets.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"q": "happy birthday", "result_type": "popular", "count": "1"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"statuses":[{"id":781760642139250689}],"search_metadata":{"completed_in":0.043,"max_id":781760642139250689,"max_id_str":"781760642139250689","next_results":"?max_id=781760640104828927&q=happy+birthday&count=1&include_entities=1","query":"happy birthday","refresh_url":"?since_id=781760642139250689&q=happy+birthday&include_entities=1","count":1,"since_id":0,"since_id_str":"0"}}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
search, _, err := client.Search.Tweets(&SearchTweetParams{
|
||||
Query: "happy birthday",
|
||||
Count: 1,
|
||||
ResultType: "popular",
|
||||
})
|
||||
expected := &Search{
|
||||
Statuses: []Tweet{
|
||||
Tweet{ID: 781760642139250689},
|
||||
},
|
||||
Metadata: &SearchMetadata{
|
||||
Count: 1,
|
||||
SinceID: 0,
|
||||
SinceIDStr: "0",
|
||||
MaxID: 781760642139250689,
|
||||
MaxIDStr: "781760642139250689",
|
||||
RefreshURL: "?since_id=781760642139250689&q=happy+birthday&include_entities=1",
|
||||
NextResults: "?max_id=781760640104828927&q=happy+birthday&count=1&include_entities=1",
|
||||
CompletedIn: 0.043,
|
||||
Query: "happy birthday",
|
||||
},
|
||||
}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, search)
|
||||
}
|
||||
310
vendor/github.com/dghubble/go-twitter/twitter/statuses.go
generated
vendored
310
vendor/github.com/dghubble/go-twitter/twitter/statuses.go
generated
vendored
@@ -1,310 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// Tweet represents a Twitter Tweet, previously called a status.
|
||||
// https://dev.twitter.com/overview/api/tweets
|
||||
type Tweet struct {
|
||||
Coordinates *Coordinates `json:"coordinates"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
CurrentUserRetweet *TweetIdentifier `json:"current_user_retweet"`
|
||||
Entities *Entities `json:"entities"`
|
||||
FavoriteCount int `json:"favorite_count"`
|
||||
Favorited bool `json:"favorited"`
|
||||
FilterLevel string `json:"filter_level"`
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
InReplyToScreenName string `json:"in_reply_to_screen_name"`
|
||||
InReplyToStatusID int64 `json:"in_reply_to_status_id"`
|
||||
InReplyToStatusIDStr string `json:"in_reply_to_status_id_str"`
|
||||
InReplyToUserID int64 `json:"in_reply_to_user_id"`
|
||||
InReplyToUserIDStr string `json:"in_reply_to_user_id_str"`
|
||||
Lang string `json:"lang"`
|
||||
PossiblySensitive bool `json:"possibly_sensitive"`
|
||||
RetweetCount int `json:"retweet_count"`
|
||||
Retweeted bool `json:"retweeted"`
|
||||
RetweetedStatus *Tweet `json:"retweeted_status"`
|
||||
Source string `json:"source"`
|
||||
Scopes map[string]interface{} `json:"scopes"`
|
||||
Text string `json:"text"`
|
||||
FullText string `json:"full_text"`
|
||||
DisplayTextRange Indices `json:"display_text_range"`
|
||||
Place *Place `json:"place"`
|
||||
Truncated bool `json:"truncated"`
|
||||
User *User `json:"user"`
|
||||
WithheldCopyright bool `json:"withheld_copyright"`
|
||||
WithheldInCountries []string `json:"withheld_in_countries"`
|
||||
WithheldScope string `json:"withheld_scope"`
|
||||
ExtendedEntities *ExtendedEntity `json:"extended_entities"`
|
||||
ExtendedTweet *ExtendedTweet `json:"extended_tweet"`
|
||||
QuotedStatusID int64 `json:"quoted_status_id"`
|
||||
QuotedStatusIDStr string `json:"quoted_status_id_str"`
|
||||
QuotedStatus *Tweet `json:"quoted_status"`
|
||||
}
|
||||
|
||||
// CreatedAtTime is a convenience wrapper that returns the Created_at time, parsed as a time.Time struct
|
||||
func (t Tweet) CreatedAtTime() (time.Time, error) {
|
||||
return time.Parse(time.RubyDate, t.CreatedAt)
|
||||
}
|
||||
|
||||
// ExtendedTweet represents fields embedded in extended Tweets when served in
|
||||
// compatibility mode (default).
|
||||
// https://dev.twitter.com/overview/api/upcoming-changes-to-tweets
|
||||
type ExtendedTweet struct {
|
||||
FullText string `json:"full_text"`
|
||||
DisplayTextRange Indices `json:"display_text_range"`
|
||||
Entities *Entities `json:"entities"`
|
||||
ExtendedEntities *ExtendedEntity `json:"extended_entities"`
|
||||
}
|
||||
|
||||
// Place represents a Twitter Place / Location
|
||||
// https://dev.twitter.com/overview/api/places
|
||||
type Place struct {
|
||||
Attributes map[string]string `json:"attributes"`
|
||||
BoundingBox *BoundingBox `json:"bounding_box"`
|
||||
Country string `json:"country"`
|
||||
CountryCode string `json:"country_code"`
|
||||
FullName string `json:"full_name"`
|
||||
Geometry *BoundingBox `json:"geometry"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PlaceType string `json:"place_type"`
|
||||
Polylines []string `json:"polylines"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// BoundingBox represents the bounding coordinates (longitude, latitutde)
|
||||
// defining the bounds of a box containing a Place entity.
|
||||
type BoundingBox struct {
|
||||
Coordinates [][][2]float64 `json:"coordinates"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Coordinates are pairs of longitude and latitude locations.
|
||||
type Coordinates struct {
|
||||
Coordinates [2]float64 `json:"coordinates"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// TweetIdentifier represents the id by which a Tweet can be identified.
|
||||
type TweetIdentifier struct {
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
}
|
||||
|
||||
// StatusService provides methods for accessing Twitter status API endpoints.
|
||||
type StatusService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newStatusService returns a new StatusService.
|
||||
func newStatusService(sling *sling.Sling) *StatusService {
|
||||
return &StatusService{
|
||||
sling: sling.Path("statuses/"),
|
||||
}
|
||||
}
|
||||
|
||||
// StatusShowParams are the parameters for StatusService.Show
|
||||
type StatusShowParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
IncludeMyRetweet *bool `url:"include_my_retweet,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// Show returns the requested Tweet.
|
||||
// https://dev.twitter.com/rest/reference/get/statuses/show/%3Aid
|
||||
func (s *StatusService) Show(id int64, params *StatusShowParams) (*Tweet, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &StatusShowParams{}
|
||||
}
|
||||
params.ID = id
|
||||
tweet := new(Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(tweet, apiError)
|
||||
return tweet, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// StatusLookupParams are the parameters for StatusService.Lookup
|
||||
type StatusLookupParams struct {
|
||||
ID []int64 `url:"id,omitempty,comma"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
Map *bool `url:"map,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// Lookup returns the requested Tweets as a slice. Combines ids from the
|
||||
// required ids argument and from params.Id.
|
||||
// https://dev.twitter.com/rest/reference/get/statuses/lookup
|
||||
func (s *StatusService) Lookup(ids []int64, params *StatusLookupParams) ([]Tweet, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &StatusLookupParams{}
|
||||
}
|
||||
params.ID = append(params.ID, ids...)
|
||||
tweets := new([]Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(tweets, apiError)
|
||||
return *tweets, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// StatusUpdateParams are the parameters for StatusService.Update
|
||||
type StatusUpdateParams struct {
|
||||
Status string `url:"status,omitempty"`
|
||||
InReplyToStatusID int64 `url:"in_reply_to_status_id,omitempty"`
|
||||
PossiblySensitive *bool `url:"possibly_sensitive,omitempty"`
|
||||
Lat *float64 `url:"lat,omitempty"`
|
||||
Long *float64 `url:"long,omitempty"`
|
||||
PlaceID string `url:"place_id,omitempty"`
|
||||
DisplayCoordinates *bool `url:"display_coordinates,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
MediaIds []int64 `url:"media_ids,omitempty,comma"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// Update updates the user's status, also known as Tweeting.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/post/statuses/update
|
||||
func (s *StatusService) Update(status string, params *StatusUpdateParams) (*Tweet, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &StatusUpdateParams{}
|
||||
}
|
||||
params.Status = status
|
||||
tweet := new(Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Post("update.json").BodyForm(params).Receive(tweet, apiError)
|
||||
return tweet, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// StatusRetweetParams are the parameters for StatusService.Retweet
|
||||
type StatusRetweetParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// Retweet retweets the Tweet with the given id and returns the original Tweet
|
||||
// with embedded retweet details.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/post/statuses/retweet/%3Aid
|
||||
func (s *StatusService) Retweet(id int64, params *StatusRetweetParams) (*Tweet, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &StatusRetweetParams{}
|
||||
}
|
||||
params.ID = id
|
||||
tweet := new(Tweet)
|
||||
apiError := new(APIError)
|
||||
path := fmt.Sprintf("retweet/%d.json", params.ID)
|
||||
resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
|
||||
return tweet, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// StatusUnretweetParams are the parameters for StatusService.Unretweet
|
||||
type StatusUnretweetParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// Unretweet unretweets the Tweet with the given id and returns the original Tweet.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/post/statuses/unretweet/%3Aid
|
||||
func (s *StatusService) Unretweet(id int64, params *StatusUnretweetParams) (*Tweet, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &StatusUnretweetParams{}
|
||||
}
|
||||
params.ID = id
|
||||
tweet := new(Tweet)
|
||||
apiError := new(APIError)
|
||||
path := fmt.Sprintf("unretweet/%d.json", params.ID)
|
||||
resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
|
||||
return tweet, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// StatusRetweetsParams are the parameters for StatusService.Retweets
|
||||
type StatusRetweetsParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// Retweets returns the most recent retweets of the Tweet with the given id.
|
||||
// https://dev.twitter.com/rest/reference/get/statuses/retweets/%3Aid
|
||||
func (s *StatusService) Retweets(id int64, params *StatusRetweetsParams) ([]Tweet, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &StatusRetweetsParams{}
|
||||
}
|
||||
params.ID = id
|
||||
tweets := new([]Tweet)
|
||||
apiError := new(APIError)
|
||||
path := fmt.Sprintf("retweets/%d.json", params.ID)
|
||||
resp, err := s.sling.New().Get(path).QueryStruct(params).Receive(tweets, apiError)
|
||||
return *tweets, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// StatusDestroyParams are the parameters for StatusService.Destroy
|
||||
type StatusDestroyParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// Destroy deletes the Tweet with the given id and returns it if successful.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/post/statuses/destroy/%3Aid
|
||||
func (s *StatusService) Destroy(id int64, params *StatusDestroyParams) (*Tweet, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &StatusDestroyParams{}
|
||||
}
|
||||
params.ID = id
|
||||
tweet := new(Tweet)
|
||||
apiError := new(APIError)
|
||||
path := fmt.Sprintf("destroy/%d.json", params.ID)
|
||||
resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
|
||||
return tweet, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// OEmbedTweet represents a Tweet in oEmbed format.
|
||||
type OEmbedTweet struct {
|
||||
URL string `json:"url"`
|
||||
ProviderURL string `json:"provider_url"`
|
||||
ProviderName string `json:"provider_name"`
|
||||
AuthorName string `json:"author_name"`
|
||||
Version string `json:"version"`
|
||||
AuthorURL string `json:"author_url"`
|
||||
Type string `json:"type"`
|
||||
HTML string `json:"html"`
|
||||
Height int64 `json:"height"`
|
||||
Width int64 `json:"width"`
|
||||
CacheAge string `json:"cache_age"`
|
||||
}
|
||||
|
||||
// StatusOEmbedParams are the parameters for StatusService.OEmbed
|
||||
type StatusOEmbedParams struct {
|
||||
ID int64 `url:"id,omitempty"`
|
||||
URL string `url:"url,omitempty"`
|
||||
Align string `url:"align,omitempty"`
|
||||
MaxWidth int64 `url:"maxwidth,omitempty"`
|
||||
HideMedia *bool `url:"hide_media,omitempty"`
|
||||
HideThread *bool `url:"hide_media,omitempty"`
|
||||
OmitScript *bool `url:"hide_media,omitempty"`
|
||||
WidgetType string `url:"widget_type,omitempty"`
|
||||
HideTweet *bool `url:"hide_tweet,omitempty"`
|
||||
}
|
||||
|
||||
// OEmbed returns the requested Tweet in oEmbed format.
|
||||
// https://dev.twitter.com/rest/reference/get/statuses/oembed
|
||||
func (s *StatusService) OEmbed(params *StatusOEmbedParams) (*OEmbedTweet, *http.Response, error) {
|
||||
oEmbedTweet := new(OEmbedTweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("oembed.json").QueryStruct(params).Receive(oEmbedTweet, apiError)
|
||||
return oEmbedTweet, resp, relevantError(err, *apiError)
|
||||
}
|
||||
275
vendor/github.com/dghubble/go-twitter/twitter/statuses_test.go
generated
vendored
275
vendor/github.com/dghubble/go-twitter/twitter/statuses_test.go
generated
vendored
@@ -1,275 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStatusService_Show(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/show.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"id": "589488862814076930", "include_entities": "false"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"user": {"screen_name": "dghubble"}, "text": ".@audreyr use a DONTREADME file if you really want people to read it :P"}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &StatusShowParams{ID: 5441, IncludeEntities: Bool(false)}
|
||||
tweet, _, err := client.Statuses.Show(589488862814076930, params)
|
||||
expected := &Tweet{User: &User{ScreenName: "dghubble"}, Text: ".@audreyr use a DONTREADME file if you really want people to read it :P"}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweet)
|
||||
}
|
||||
|
||||
func TestStatusService_ShowHandlesNilParams(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/show.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertQuery(t, map[string]string{"id": "589488862814076930"}, r)
|
||||
})
|
||||
client := NewClient(httpClient)
|
||||
client.Statuses.Show(589488862814076930, nil)
|
||||
}
|
||||
|
||||
func TestStatusService_Lookup(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/lookup.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"id": "20,573893817000140800", "trim_user": "true"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"id": 20, "text": "just setting up my twttr"}, {"id": 573893817000140800, "text": "Don't get lost #PaxEast2015"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &StatusLookupParams{ID: []int64{20}, TrimUser: Bool(true)}
|
||||
tweets, _, err := client.Statuses.Lookup([]int64{573893817000140800}, params)
|
||||
expected := []Tweet{Tweet{ID: 20, Text: "just setting up my twttr"}, Tweet{ID: 573893817000140800, Text: "Don't get lost #PaxEast2015"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweets)
|
||||
}
|
||||
|
||||
func TestStatusService_LookupHandlesNilParams(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
mux.HandleFunc("/1.1/statuses/lookup.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertQuery(t, map[string]string{"id": "20,573893817000140800"}, r)
|
||||
})
|
||||
client := NewClient(httpClient)
|
||||
client.Statuses.Lookup([]int64{20, 573893817000140800}, nil)
|
||||
}
|
||||
|
||||
func TestStatusService_Update(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/update.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertQuery(t, map[string]string{}, r)
|
||||
assertPostForm(t, map[string]string{"status": "very informative tweet", "media_ids": "123456789,987654321", "lat": "37.826706", "long": "-122.42219"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id": 581980947630845953, "text": "very informative tweet"}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &StatusUpdateParams{MediaIds: []int64{123456789, 987654321}, Lat: Float(37.826706), Long: Float(-122.422190)}
|
||||
tweet, _, err := client.Statuses.Update("very informative tweet", params)
|
||||
expected := &Tweet{ID: 581980947630845953, Text: "very informative tweet"}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweet)
|
||||
}
|
||||
|
||||
func TestStatusService_UpdateHandlesNilParams(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
mux.HandleFunc("/1.1/statuses/update.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertPostForm(t, map[string]string{"status": "very informative tweet"}, r)
|
||||
})
|
||||
client := NewClient(httpClient)
|
||||
client.Statuses.Update("very informative tweet", nil)
|
||||
}
|
||||
|
||||
func TestStatusService_APIError(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
mux.HandleFunc("/1.1/statuses/update.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertPostForm(t, map[string]string{"status": "very informative tweet"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(403)
|
||||
fmt.Fprintf(w, `{"errors": [{"message": "Status is a duplicate", "code": 187}]}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
_, _, err := client.Statuses.Update("very informative tweet", nil)
|
||||
expected := APIError{
|
||||
Errors: []ErrorDetail{
|
||||
ErrorDetail{Message: "Status is a duplicate", Code: 187},
|
||||
},
|
||||
}
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusService_HTTPError(t *testing.T) {
|
||||
httpClient, _, server := testServer()
|
||||
server.Close()
|
||||
client := NewClient(httpClient)
|
||||
_, _, err := client.Statuses.Update("very informative tweet", nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "connection refused") {
|
||||
t.Errorf("Statuses.Update error expected connection refused, got: \n %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusService_Retweet(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/retweet/20.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertQuery(t, map[string]string{}, r)
|
||||
assertPostForm(t, map[string]string{"id": "20", "trim_user": "true"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id": 581980947630202020, "text": "RT @jack: just setting up my twttr", "retweeted_status": {"id": 20, "text": "just setting up my twttr"}}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &StatusRetweetParams{TrimUser: Bool(true)}
|
||||
tweet, _, err := client.Statuses.Retweet(20, params)
|
||||
expected := &Tweet{ID: 581980947630202020, Text: "RT @jack: just setting up my twttr", RetweetedStatus: &Tweet{ID: 20, Text: "just setting up my twttr"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweet)
|
||||
}
|
||||
|
||||
func TestStatusService_RetweetHandlesNilParams(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/retweet/20.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertPostForm(t, map[string]string{"id": "20"}, r)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
client.Statuses.Retweet(20, nil)
|
||||
}
|
||||
|
||||
func TestStatusService_Unretweet(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/unretweet/20.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertQuery(t, map[string]string{}, r)
|
||||
assertPostForm(t, map[string]string{"id": "20", "trim_user": "true"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id": 581980947630202020, "text":"RT @jack: just setting up my twttr", "retweeted_status": {"id": 20, "text": "just setting up my twttr"}}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &StatusUnretweetParams{TrimUser: Bool(true)}
|
||||
tweet, _, err := client.Statuses.Unretweet(20, params)
|
||||
expected := &Tweet{ID: 581980947630202020, Text: "RT @jack: just setting up my twttr", RetweetedStatus: &Tweet{ID: 20, Text: "just setting up my twttr"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweet)
|
||||
}
|
||||
|
||||
func TestStatusService_Retweets(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/retweets/20.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"id": "20", "count": "2"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"text": "RT @jack: just setting up my twttr"}, {"text": "RT @jack: just setting up my twttr"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &StatusRetweetsParams{Count: 2}
|
||||
retweets, _, err := client.Statuses.Retweets(20, params)
|
||||
expected := []Tweet{Tweet{Text: "RT @jack: just setting up my twttr"}, Tweet{Text: "RT @jack: just setting up my twttr"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, retweets)
|
||||
}
|
||||
|
||||
func TestStatusService_RetweetsHandlesNilParams(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/retweets/20.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertQuery(t, map[string]string{"id": "20"}, r)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
client.Statuses.Retweets(20, nil)
|
||||
}
|
||||
|
||||
func TestStatusService_Destroy(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/destroy/40.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertQuery(t, map[string]string{}, r)
|
||||
assertPostForm(t, map[string]string{"id": "40", "trim_user": "true"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id": 40, "text": "wishing I had another sammich"}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &StatusDestroyParams{TrimUser: Bool(true)}
|
||||
tweet, _, err := client.Statuses.Destroy(40, params)
|
||||
// feed Biz Stone a sammich, he deletes sammich Tweet
|
||||
expected := &Tweet{ID: 40, Text: "wishing I had another sammich"}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweet)
|
||||
}
|
||||
|
||||
func TestStatusService_DestroyHandlesNilParams(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/destroy/40.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertPostForm(t, map[string]string{"id": "40"}, r)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
client.Statuses.Destroy(40, nil)
|
||||
}
|
||||
|
||||
func TestStatusService_OEmbed(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/oembed.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"id": "691076766878691329", "maxwidth": "400", "hide_media": "true"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
// abbreviated oEmbed response
|
||||
fmt.Fprintf(w, `{"url": "https://twitter.com/dghubble/statuses/691076766878691329", "width": 400, "html": "<blockquote></blockquote>"}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
params := &StatusOEmbedParams{
|
||||
ID: 691076766878691329,
|
||||
MaxWidth: 400,
|
||||
HideMedia: Bool(true),
|
||||
}
|
||||
oembed, _, err := client.Statuses.OEmbed(params)
|
||||
expected := &OEmbedTweet{
|
||||
URL: "https://twitter.com/dghubble/statuses/691076766878691329",
|
||||
Width: 400,
|
||||
HTML: "<blockquote></blockquote>",
|
||||
}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, oembed)
|
||||
}
|
||||
110
vendor/github.com/dghubble/go-twitter/twitter/stream_messages.go
generated
vendored
110
vendor/github.com/dghubble/go-twitter/twitter/stream_messages.go
generated
vendored
@@ -1,110 +0,0 @@
|
||||
package twitter
|
||||
|
||||
// StatusDeletion indicates that a given Tweet has been deleted.
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#status_deletion_notices_delete
|
||||
type StatusDeletion struct {
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
UserID int64 `json:"user_id"`
|
||||
UserIDStr string `json:"user_id_str"`
|
||||
}
|
||||
|
||||
type statusDeletionNotice struct {
|
||||
Delete struct {
|
||||
StatusDeletion *StatusDeletion `json:"status"`
|
||||
} `json:"delete"`
|
||||
}
|
||||
|
||||
// LocationDeletion indicates geolocation data must be stripped from a range
|
||||
// of Tweets.
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#Location_deletion_notices_scrub_geo
|
||||
type LocationDeletion struct {
|
||||
UserID int64 `json:"user_id"`
|
||||
UserIDStr string `json:"user_id_str"`
|
||||
UpToStatusID int64 `json:"up_to_status_id"`
|
||||
UpToStatusIDStr string `json:"up_to_status_id_str"`
|
||||
}
|
||||
|
||||
type locationDeletionNotice struct {
|
||||
ScrubGeo *LocationDeletion `json:"scrub_geo"`
|
||||
}
|
||||
|
||||
// StreamLimit indicates a stream matched more statuses than its rate limit
|
||||
// allowed. The track number is the number of undelivered matches.
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#limit_notices
|
||||
type StreamLimit struct {
|
||||
Track int64 `json:"track"`
|
||||
}
|
||||
|
||||
type streamLimitNotice struct {
|
||||
Limit *StreamLimit `json:"limit"`
|
||||
}
|
||||
|
||||
// StatusWithheld indicates a Tweet with the given ID, belonging to UserId,
|
||||
// has been withheld in certain countries.
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#withheld_content_notices
|
||||
type StatusWithheld struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
WithheldInCountries []string `json:"withheld_in_countries"`
|
||||
}
|
||||
|
||||
type statusWithheldNotice struct {
|
||||
StatusWithheld *StatusWithheld `json:"status_withheld"`
|
||||
}
|
||||
|
||||
// UserWithheld indicates a User with the given ID has been withheld in
|
||||
// certain countries.
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#withheld_content_notices
|
||||
type UserWithheld struct {
|
||||
ID int64 `json:"id"`
|
||||
WithheldInCountries []string `json:"withheld_in_countries"`
|
||||
}
|
||||
type userWithheldNotice struct {
|
||||
UserWithheld *UserWithheld `json:"user_withheld"`
|
||||
}
|
||||
|
||||
// StreamDisconnect indicates the stream has been shutdown for some reason.
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#disconnect_messages
|
||||
type StreamDisconnect struct {
|
||||
Code int64 `json:"code"`
|
||||
StreamName string `json:"stream_name"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
type streamDisconnectNotice struct {
|
||||
StreamDisconnect *StreamDisconnect `json:"disconnect"`
|
||||
}
|
||||
|
||||
// StallWarning indicates the client is falling behind in the stream.
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#stall_warnings
|
||||
type StallWarning struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
PercentFull int `json:"percent_full"`
|
||||
}
|
||||
|
||||
type stallWarningNotice struct {
|
||||
StallWarning *StallWarning `json:"warning"`
|
||||
}
|
||||
|
||||
// FriendsList is a list of some of a user's friends.
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#friends_list_friends
|
||||
type FriendsList struct {
|
||||
Friends []int64 `json:"friends"`
|
||||
}
|
||||
|
||||
type directMessageNotice struct {
|
||||
DirectMessage *DirectMessage `json:"direct_message"`
|
||||
}
|
||||
|
||||
// Event is a non-Tweet notification message (e.g. like, retweet, follow).
|
||||
// https://dev.twitter.com/streaming/overview/messages-types#Events_event
|
||||
type Event struct {
|
||||
Event string `json:"event"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Target *User `json:"target"`
|
||||
Source *User `json:"source"`
|
||||
// TODO: add List or deprecate it
|
||||
TargetObject *Tweet `json:"target_object"`
|
||||
}
|
||||
95
vendor/github.com/dghubble/go-twitter/twitter/stream_utils.go
generated
vendored
95
vendor/github.com/dghubble/go-twitter/twitter/stream_utils.go
generated
vendored
@@ -1,95 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// stopped returns true if the done channel receives, false otherwise.
|
||||
func stopped(done <-chan struct{}) bool {
|
||||
select {
|
||||
case <-done:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// sleepOrDone pauses the current goroutine until the done channel receives
|
||||
// or until at least the duration d has elapsed, whichever comes first. This
|
||||
// is similar to time.Sleep(d), except it can be interrupted.
|
||||
func sleepOrDone(d time.Duration, done <-chan struct{}) {
|
||||
sleep := time.NewTimer(d)
|
||||
defer sleep.Stop()
|
||||
select {
|
||||
case <-sleep.C:
|
||||
return
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// streamResponseBodyReader is a buffered reader for Twitter stream response
|
||||
// body. It can scan the arbitrary length of response body unlike bufio.Scanner.
|
||||
type streamResponseBodyReader struct {
|
||||
reader *bufio.Reader
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
// newStreamResponseBodyReader returns an instance of streamResponseBodyReader
|
||||
// for the given Twitter stream response body.
|
||||
func newStreamResponseBodyReader(body io.Reader) *streamResponseBodyReader {
|
||||
return &streamResponseBodyReader{reader: bufio.NewReader(body)}
|
||||
}
|
||||
|
||||
// readNext reads Twitter stream response body and returns the next stream
|
||||
// content if exists. Returns io.EOF error if we reached the end of the stream
|
||||
// and there's no more message to read.
|
||||
func (r *streamResponseBodyReader) readNext() ([]byte, error) {
|
||||
// Discard all the bytes from buf and continue to use the allocated memory
|
||||
// space for reading the next message.
|
||||
r.buf.Truncate(0)
|
||||
for {
|
||||
// Twitter stream messages are separated with "\r\n", and a valid
|
||||
// message may sometimes contain '\n' in the middle.
|
||||
// bufio.Reader.Read() can accept one byte delimiter only, so we need to
|
||||
// first break out each line on '\n' and then check whether the line ends
|
||||
// with "\r\n" to find message boundaries.
|
||||
// https://dev.twitter.com/streaming/overview/processing
|
||||
line, err := r.reader.ReadBytes('\n')
|
||||
// Non-EOF error should be propagated to callers immediately.
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
// EOF error means that we reached the end of the stream body before finding
|
||||
// delimiter '\n'. If "line" is empty, it means the reader didn't read any
|
||||
// data from the stream before reaching EOF and there's nothing to append to
|
||||
// buf.
|
||||
if err == io.EOF && len(line) == 0 {
|
||||
// if buf has no data, propagate io.EOF to callers and let them know that
|
||||
// we've finished processing the stream.
|
||||
if r.buf.Len() == 0 {
|
||||
return nil, err
|
||||
}
|
||||
// Otherwise, we still have a remaining stream message to return.
|
||||
break
|
||||
}
|
||||
// If the line ends with "\r\n", it's the end of one stream message data.
|
||||
if bytes.HasSuffix(line, []byte("\r\n")) {
|
||||
// reader.ReadBytes() returns a slice including the delimiter itself, so
|
||||
// we need to trim '\n' as well as '\r' from the end of the slice.
|
||||
r.buf.Write(bytes.TrimRight(line, "\r\n"))
|
||||
break
|
||||
}
|
||||
// Otherwise, the line is not the end of a stream message, so we append
|
||||
// the line to buf and continue to scan lines.
|
||||
r.buf.Write(line)
|
||||
}
|
||||
|
||||
// Get the stream message bytes from buf. Not that Bytes() won't mark the
|
||||
// returned data as "read", and we need to explicitly call Truncate(0) to
|
||||
// discard from buf before writing the next stream message to buf.
|
||||
return r.buf.Bytes(), nil
|
||||
}
|
||||
111
vendor/github.com/dghubble/go-twitter/twitter/stream_utils_test.go
generated
vendored
111
vendor/github.com/dghubble/go-twitter/twitter/stream_utils_test.go
generated
vendored
@@ -1,111 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStopped(t *testing.T) {
|
||||
done := make(chan struct{})
|
||||
assert.False(t, stopped(done))
|
||||
close(done)
|
||||
assert.True(t, stopped(done))
|
||||
}
|
||||
|
||||
func TestSleepOrDone_Sleep(t *testing.T) {
|
||||
wait := time.Nanosecond * 20
|
||||
done := make(chan struct{})
|
||||
completed := make(chan struct{})
|
||||
go func() {
|
||||
sleepOrDone(wait, done)
|
||||
close(completed)
|
||||
}()
|
||||
// wait for goroutine SleepOrDone to sleep
|
||||
assertDone(t, completed, defaultTestTimeout)
|
||||
}
|
||||
|
||||
func TestSleepOrDone_Done(t *testing.T) {
|
||||
wait := time.Second * 5
|
||||
done := make(chan struct{})
|
||||
completed := make(chan struct{})
|
||||
go func() {
|
||||
sleepOrDone(wait, done)
|
||||
close(completed)
|
||||
}()
|
||||
// close done, interrupting SleepOrDone
|
||||
close(done)
|
||||
// assert that SleepOrDone exited, closing completed
|
||||
assertDone(t, completed, defaultTestTimeout)
|
||||
}
|
||||
|
||||
func TestStreamResponseBodyReader(t *testing.T) {
|
||||
cases := []struct {
|
||||
in []byte
|
||||
want [][]byte
|
||||
}{
|
||||
{
|
||||
in: []byte("foo\r\nbar\r\n"),
|
||||
want: [][]byte{
|
||||
[]byte("foo"),
|
||||
[]byte("bar"),
|
||||
},
|
||||
},
|
||||
{
|
||||
in: []byte("foo\nbar\r\n"),
|
||||
want: [][]byte{
|
||||
[]byte("foo\nbar"),
|
||||
},
|
||||
},
|
||||
{
|
||||
in: []byte("foo\r\n\r\n"),
|
||||
want: [][]byte{
|
||||
[]byte("foo"),
|
||||
[]byte(""),
|
||||
},
|
||||
},
|
||||
{
|
||||
in: []byte("foo\r\nbar"),
|
||||
want: [][]byte{
|
||||
[]byte("foo"),
|
||||
[]byte("bar"),
|
||||
},
|
||||
},
|
||||
{
|
||||
// Message length is more than bufio.MaxScanTokenSize, which can't be
|
||||
// parsed by bufio.Scanner with default buffer size.
|
||||
in: []byte(strings.Repeat("X", bufio.MaxScanTokenSize+1) + "\r\n"),
|
||||
want: [][]byte{
|
||||
[]byte(strings.Repeat("X", bufio.MaxScanTokenSize+1)),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
body := bytes.NewReader(c.in)
|
||||
reader := newStreamResponseBodyReader(body)
|
||||
|
||||
for i, want := range c.want {
|
||||
data, err := reader.readNext()
|
||||
if err != nil {
|
||||
t.Errorf("reader(%q).readNext() * %d: err == %q, want nil", c.in, i, err)
|
||||
}
|
||||
if !bytes.Equal(data, want) {
|
||||
t.Errorf("reader(%q).readNext() * %d: data == %q, want %q", c.in, i, data, want)
|
||||
}
|
||||
}
|
||||
|
||||
data, err := reader.readNext()
|
||||
if err != io.EOF {
|
||||
t.Errorf("reader(%q).readNext() * %d: err == %q, want io.EOF", c.in, len(c.want), err)
|
||||
}
|
||||
if len(data) != 0 {
|
||||
t.Errorf("reader(%q).readNext() * %d: data == %q, want \"\"", c.in, len(c.want), data)
|
||||
}
|
||||
}
|
||||
}
|
||||
323
vendor/github.com/dghubble/go-twitter/twitter/streams.go
generated
vendored
323
vendor/github.com/dghubble/go-twitter/twitter/streams.go
generated
vendored
@@ -1,323 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
const (
|
||||
userAgent = "go-twitter v0.1"
|
||||
publicStream = "https://stream.twitter.com/1.1/"
|
||||
userStream = "https://userstream.twitter.com/1.1/"
|
||||
siteStream = "https://sitestream.twitter.com/1.1/"
|
||||
)
|
||||
|
||||
// StreamService provides methods for accessing the Twitter Streaming API.
|
||||
type StreamService struct {
|
||||
client *http.Client
|
||||
public *sling.Sling
|
||||
user *sling.Sling
|
||||
site *sling.Sling
|
||||
}
|
||||
|
||||
// newStreamService returns a new StreamService.
|
||||
func newStreamService(client *http.Client, sling *sling.Sling) *StreamService {
|
||||
sling.Set("User-Agent", userAgent)
|
||||
return &StreamService{
|
||||
client: client,
|
||||
public: sling.New().Base(publicStream).Path("statuses/"),
|
||||
user: sling.New().Base(userStream),
|
||||
site: sling.New().Base(siteStream),
|
||||
}
|
||||
}
|
||||
|
||||
// StreamFilterParams are parameters for StreamService.Filter.
|
||||
type StreamFilterParams struct {
|
||||
FilterLevel string `url:"filter_level,omitempty"`
|
||||
Follow []string `url:"follow,omitempty,comma"`
|
||||
Language []string `url:"language,omitempty,comma"`
|
||||
Locations []string `url:"locations,omitempty,comma"`
|
||||
StallWarnings *bool `url:"stall_warnings,omitempty"`
|
||||
Track []string `url:"track,omitempty,comma"`
|
||||
}
|
||||
|
||||
// Filter returns messages that match one or more filter predicates.
|
||||
// https://dev.twitter.com/streaming/reference/post/statuses/filter
|
||||
func (srv *StreamService) Filter(params *StreamFilterParams) (*Stream, error) {
|
||||
req, err := srv.public.New().Post("filter.json").QueryStruct(params).Request()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newStream(srv.client, req), nil
|
||||
}
|
||||
|
||||
// StreamSampleParams are the parameters for StreamService.Sample.
|
||||
type StreamSampleParams struct {
|
||||
StallWarnings *bool `url:"stall_warnings,omitempty"`
|
||||
Language []string `url:"language,omitempty,comma"`
|
||||
}
|
||||
|
||||
// Sample returns a small sample of public stream messages.
|
||||
// https://dev.twitter.com/streaming/reference/get/statuses/sample
|
||||
func (srv *StreamService) Sample(params *StreamSampleParams) (*Stream, error) {
|
||||
req, err := srv.public.New().Get("sample.json").QueryStruct(params).Request()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newStream(srv.client, req), nil
|
||||
}
|
||||
|
||||
// StreamUserParams are the parameters for StreamService.User.
|
||||
type StreamUserParams struct {
|
||||
FilterLevel string `url:"filter_level,omitempty"`
|
||||
Language []string `url:"language,omitempty,comma"`
|
||||
Locations []string `url:"locations,omitempty,comma"`
|
||||
Replies string `url:"replies,omitempty"`
|
||||
StallWarnings *bool `url:"stall_warnings,omitempty"`
|
||||
Track []string `url:"track,omitempty,comma"`
|
||||
With string `url:"with,omitempty"`
|
||||
}
|
||||
|
||||
// User returns a stream of messages specific to the authenticated User.
|
||||
// https://dev.twitter.com/streaming/reference/get/user
|
||||
func (srv *StreamService) User(params *StreamUserParams) (*Stream, error) {
|
||||
req, err := srv.user.New().Get("user.json").QueryStruct(params).Request()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newStream(srv.client, req), nil
|
||||
}
|
||||
|
||||
// StreamSiteParams are the parameters for StreamService.Site.
|
||||
type StreamSiteParams struct {
|
||||
FilterLevel string `url:"filter_level,omitempty"`
|
||||
Follow []string `url:"follow,omitempty,comma"`
|
||||
Language []string `url:"language,omitempty,comma"`
|
||||
Replies string `url:"replies,omitempty"`
|
||||
StallWarnings *bool `url:"stall_warnings,omitempty"`
|
||||
With string `url:"with,omitempty"`
|
||||
}
|
||||
|
||||
// Site returns messages for a set of users.
|
||||
// Requires special permission to access.
|
||||
// https://dev.twitter.com/streaming/reference/get/site
|
||||
func (srv *StreamService) Site(params *StreamSiteParams) (*Stream, error) {
|
||||
req, err := srv.site.New().Get("site.json").QueryStruct(params).Request()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newStream(srv.client, req), nil
|
||||
}
|
||||
|
||||
// StreamFirehoseParams are the parameters for StreamService.Firehose.
|
||||
type StreamFirehoseParams struct {
|
||||
Count int `url:"count,omitempty"`
|
||||
FilterLevel string `url:"filter_level,omitempty"`
|
||||
Language []string `url:"language,omitempty,comma"`
|
||||
StallWarnings *bool `url:"stall_warnings,omitempty"`
|
||||
}
|
||||
|
||||
// Firehose returns all public messages and statuses.
|
||||
// Requires special permission to access.
|
||||
// https://dev.twitter.com/streaming/reference/get/statuses/firehose
|
||||
func (srv *StreamService) Firehose(params *StreamFirehoseParams) (*Stream, error) {
|
||||
req, err := srv.public.New().Get("firehose.json").QueryStruct(params).Request()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newStream(srv.client, req), nil
|
||||
}
|
||||
|
||||
// Stream maintains a connection to the Twitter Streaming API, receives
|
||||
// messages from the streaming response, and sends them on the Messages
|
||||
// channel from a goroutine. The stream goroutine stops itself if an EOF is
|
||||
// reached or retry errors occur, also closing the Messages channel.
|
||||
//
|
||||
// The client must Stop() the stream when finished receiving, which will
|
||||
// wait until the stream is properly stopped.
|
||||
type Stream struct {
|
||||
client *http.Client
|
||||
Messages chan interface{}
|
||||
done chan struct{}
|
||||
group *sync.WaitGroup
|
||||
body io.Closer
|
||||
}
|
||||
|
||||
// newStream creates a Stream and starts a goroutine to retry connecting and
|
||||
// receive from a stream response. The goroutine may stop due to retry errors
|
||||
// or be stopped by calling Stop() on the stream.
|
||||
func newStream(client *http.Client, req *http.Request) *Stream {
|
||||
s := &Stream{
|
||||
client: client,
|
||||
Messages: make(chan interface{}),
|
||||
done: make(chan struct{}),
|
||||
group: &sync.WaitGroup{},
|
||||
}
|
||||
s.group.Add(1)
|
||||
go s.retry(req, newExponentialBackOff(), newAggressiveExponentialBackOff())
|
||||
return s
|
||||
}
|
||||
|
||||
// Stop signals retry and receiver to stop, closes the Messages channel, and
|
||||
// blocks until done.
|
||||
func (s *Stream) Stop() {
|
||||
close(s.done)
|
||||
// Scanner does not have a Stop() or take a done channel, so for low volume
|
||||
// streams Scan() blocks until the next keep-alive. Close the resp.Body to
|
||||
// escape and stop the stream in a timely fashion.
|
||||
if s.body != nil {
|
||||
s.body.Close()
|
||||
}
|
||||
// block until the retry goroutine stops
|
||||
s.group.Wait()
|
||||
}
|
||||
|
||||
// retry retries making the given http.Request and receiving the response
|
||||
// according to the Twitter backoff policies. Callers should invoke in a
|
||||
// goroutine since backoffs sleep between retries.
|
||||
// https://dev.twitter.com/streaming/overview/connecting
|
||||
func (s *Stream) retry(req *http.Request, expBackOff backoff.BackOff, aggExpBackOff backoff.BackOff) {
|
||||
// close Messages channel and decrement the wait group counter
|
||||
defer close(s.Messages)
|
||||
defer s.group.Done()
|
||||
|
||||
var wait time.Duration
|
||||
for !stopped(s.done) {
|
||||
resp, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
// stop retrying for HTTP protocol errors
|
||||
s.Messages <- err
|
||||
return
|
||||
}
|
||||
// when err is nil, resp contains a non-nil Body which must be closed
|
||||
defer resp.Body.Close()
|
||||
s.body = resp.Body
|
||||
switch resp.StatusCode {
|
||||
case 200:
|
||||
// receive stream response Body, handles closing
|
||||
s.receive(resp.Body)
|
||||
expBackOff.Reset()
|
||||
aggExpBackOff.Reset()
|
||||
case 503:
|
||||
// exponential backoff
|
||||
wait = expBackOff.NextBackOff()
|
||||
case 420, 429:
|
||||
// aggressive exponential backoff
|
||||
wait = aggExpBackOff.NextBackOff()
|
||||
default:
|
||||
// stop retrying for other response codes
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
// close response before each retry
|
||||
resp.Body.Close()
|
||||
if wait == backoff.Stop {
|
||||
return
|
||||
}
|
||||
sleepOrDone(wait, s.done)
|
||||
}
|
||||
}
|
||||
|
||||
// receive scans a stream response body, JSON decodes tokens to messages, and
|
||||
// sends messages to the Messages channel. Receiving continues until an EOF,
|
||||
// scan error, or the done channel is closed.
|
||||
func (s *Stream) receive(body io.Reader) {
|
||||
reader := newStreamResponseBodyReader(body)
|
||||
for !stopped(s.done) {
|
||||
data, err := reader.readNext()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(data) == 0 {
|
||||
// empty keep-alive
|
||||
continue
|
||||
}
|
||||
select {
|
||||
// send messages, data, or errors
|
||||
case s.Messages <- getMessage(data):
|
||||
continue
|
||||
// allow client to Stop(), even if not receiving
|
||||
case <-s.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getMessage unmarshals the token and returns a message struct, if the type
|
||||
// can be determined. Otherwise, returns the token unmarshalled into a data
|
||||
// map[string]interface{} or the unmarshal error.
|
||||
func getMessage(token []byte) interface{} {
|
||||
var data map[string]interface{}
|
||||
// unmarshal JSON encoded token into a map for
|
||||
err := json.Unmarshal(token, &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return decodeMessage(token, data)
|
||||
}
|
||||
|
||||
// decodeMessage determines the message type from known data keys, allocates
|
||||
// at most one message struct, and JSON decodes the token into the message.
|
||||
// Returns the message struct or the data map if the message type could not be
|
||||
// determined.
|
||||
func decodeMessage(token []byte, data map[string]interface{}) interface{} {
|
||||
if hasPath(data, "retweet_count") {
|
||||
tweet := new(Tweet)
|
||||
json.Unmarshal(token, tweet)
|
||||
return tweet
|
||||
} else if hasPath(data, "direct_message") {
|
||||
notice := new(directMessageNotice)
|
||||
json.Unmarshal(token, notice)
|
||||
return notice.DirectMessage
|
||||
} else if hasPath(data, "delete") {
|
||||
notice := new(statusDeletionNotice)
|
||||
json.Unmarshal(token, notice)
|
||||
return notice.Delete.StatusDeletion
|
||||
} else if hasPath(data, "scrub_geo") {
|
||||
notice := new(locationDeletionNotice)
|
||||
json.Unmarshal(token, notice)
|
||||
return notice.ScrubGeo
|
||||
} else if hasPath(data, "limit") {
|
||||
notice := new(streamLimitNotice)
|
||||
json.Unmarshal(token, notice)
|
||||
return notice.Limit
|
||||
} else if hasPath(data, "status_withheld") {
|
||||
notice := new(statusWithheldNotice)
|
||||
json.Unmarshal(token, notice)
|
||||
return notice.StatusWithheld
|
||||
} else if hasPath(data, "user_withheld") {
|
||||
notice := new(userWithheldNotice)
|
||||
json.Unmarshal(token, notice)
|
||||
return notice.UserWithheld
|
||||
} else if hasPath(data, "disconnect") {
|
||||
notice := new(streamDisconnectNotice)
|
||||
json.Unmarshal(token, notice)
|
||||
return notice.StreamDisconnect
|
||||
} else if hasPath(data, "warning") {
|
||||
notice := new(stallWarningNotice)
|
||||
json.Unmarshal(token, notice)
|
||||
return notice.StallWarning
|
||||
} else if hasPath(data, "friends") {
|
||||
friendsList := new(FriendsList)
|
||||
json.Unmarshal(token, friendsList)
|
||||
return friendsList
|
||||
} else if hasPath(data, "event") {
|
||||
event := new(Event)
|
||||
json.Unmarshal(token, event)
|
||||
return event
|
||||
}
|
||||
// message type unknown, return the data map[string]interface{}
|
||||
return data
|
||||
}
|
||||
|
||||
// hasPath returns true if the map contains the given key, false otherwise.
|
||||
func hasPath(data map[string]interface{}, key string) bool {
|
||||
_, ok := data[key]
|
||||
return ok
|
||||
}
|
||||
393
vendor/github.com/dghubble/go-twitter/twitter/streams_test.go
generated
vendored
393
vendor/github.com/dghubble/go-twitter/twitter/streams_test.go
generated
vendored
@@ -1,393 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStream_MessageJSONError(t *testing.T) {
|
||||
badJSON := []byte(`{`)
|
||||
msg := getMessage(badJSON)
|
||||
assert.EqualError(t, msg.(error), "unexpected end of JSON input")
|
||||
}
|
||||
|
||||
func TestStream_GetMessageTweet(t *testing.T) {
|
||||
msgJSON := []byte(`{"id": 20, "text": "just setting up my twttr", "retweet_count": "68535"}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &Tweet{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_GetMessageDirectMessage(t *testing.T) {
|
||||
msgJSON := []byte(`{"direct_message": {"id": 666024290140217347}}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &DirectMessage{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_GetMessageDelete(t *testing.T) {
|
||||
msgJSON := []byte(`{"delete": { "id": 20}}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &StatusDeletion{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_GetMessageLocationDeletion(t *testing.T) {
|
||||
msgJSON := []byte(`{"scrub_geo": { "up_to_status_id": 20}}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &LocationDeletion{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_GetMessageStreamLimit(t *testing.T) {
|
||||
msgJSON := []byte(`{"limit": { "track": 10 }}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &StreamLimit{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_StatusWithheld(t *testing.T) {
|
||||
msgJSON := []byte(`{"status_withheld": { "id": 20, "user_id": 12, "withheld_in_countries":["USA", "China"] }}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &StatusWithheld{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_UserWithheld(t *testing.T) {
|
||||
msgJSON := []byte(`{"user_withheld": { "id": 12, "withheld_in_countries":["USA", "China"] }}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &UserWithheld{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_StreamDisconnect(t *testing.T) {
|
||||
msgJSON := []byte(`{"disconnect": { "code": "420", "stream_name": "streaming stuff", "reason": "too many connections" }}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &StreamDisconnect{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_StallWarning(t *testing.T) {
|
||||
msgJSON := []byte(`{"warning": { "code": "420", "percent_full": 90, "message": "a lot of messages" }}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &StallWarning{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_FriendsList(t *testing.T) {
|
||||
msgJSON := []byte(`{"friends": [666024290140217347, 666024290140217349, 666024290140217342]}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &FriendsList{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_Event(t *testing.T) {
|
||||
msgJSON := []byte(`{"event": "block", "target": {"name": "XKCD Comic", "favourites_count": 2}, "source": {"name": "XKCD Comic2", "favourites_count": 3}, "created_at": "Sat Sep 4 16:10:54 +0000 2010"}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, &Event{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_Unknown(t *testing.T) {
|
||||
msgJSON := []byte(`{"unknown_data": {"new_twitter_type":"unexpected"}}`)
|
||||
msg := getMessage(msgJSON)
|
||||
assert.IsType(t, map[string]interface{}{}, msg)
|
||||
}
|
||||
|
||||
func TestStream_Filter(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
reqCount := 0
|
||||
mux.HandleFunc("/1.1/statuses/filter.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "POST", r)
|
||||
assertQuery(t, map[string]string{"track": "gophercon,golang"}, r)
|
||||
switch reqCount {
|
||||
case 0:
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
fmt.Fprintf(w,
|
||||
`{"text": "Gophercon talks!"}`+"\r\n"+
|
||||
`{"text": "Gophercon super talks!"}`+"\r\n",
|
||||
)
|
||||
default:
|
||||
// Only allow first request
|
||||
http.Error(w, "Stream API not available!", 130)
|
||||
}
|
||||
reqCount++
|
||||
})
|
||||
|
||||
counts := &counter{}
|
||||
demux := newCounterDemux(counts)
|
||||
client := NewClient(httpClient)
|
||||
streamFilterParams := &StreamFilterParams{
|
||||
Track: []string{"gophercon", "golang"},
|
||||
}
|
||||
stream, err := client.Streams.Filter(streamFilterParams)
|
||||
// assert that the expected messages are received
|
||||
assert.NoError(t, err)
|
||||
defer stream.Stop()
|
||||
for message := range stream.Messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
expectedCounts := &counter{all: 2, other: 2}
|
||||
assert.Equal(t, expectedCounts, counts)
|
||||
}
|
||||
|
||||
func TestStream_Sample(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
reqCount := 0
|
||||
mux.HandleFunc("/1.1/statuses/sample.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"stall_warnings": "true"}, r)
|
||||
switch reqCount {
|
||||
case 0:
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
fmt.Fprintf(w,
|
||||
`{"text": "Gophercon talks!"}`+"\r\n"+
|
||||
`{"text": "Gophercon super talks!"}`+"\r\n",
|
||||
)
|
||||
default:
|
||||
// Only allow first request
|
||||
http.Error(w, "Stream API not available!", 130)
|
||||
}
|
||||
reqCount++
|
||||
})
|
||||
|
||||
counts := &counter{}
|
||||
demux := newCounterDemux(counts)
|
||||
client := NewClient(httpClient)
|
||||
streamSampleParams := &StreamSampleParams{
|
||||
StallWarnings: Bool(true),
|
||||
}
|
||||
stream, err := client.Streams.Sample(streamSampleParams)
|
||||
// assert that the expected messages are received
|
||||
assert.NoError(t, err)
|
||||
defer stream.Stop()
|
||||
for message := range stream.Messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
expectedCounts := &counter{all: 2, other: 2}
|
||||
assert.Equal(t, expectedCounts, counts)
|
||||
}
|
||||
|
||||
func TestStream_User(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
reqCount := 0
|
||||
mux.HandleFunc("/1.1/user.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"stall_warnings": "true", "with": "followings"}, r)
|
||||
switch reqCount {
|
||||
case 0:
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
fmt.Fprintf(w, `{"friends": [666024290140217347, 666024290140217349, 666024290140217342]}`+"\r\n"+"\r\n")
|
||||
default:
|
||||
// Only allow first request
|
||||
http.Error(w, "Stream API not available!", 130)
|
||||
}
|
||||
reqCount++
|
||||
})
|
||||
|
||||
counts := &counter{}
|
||||
demux := newCounterDemux(counts)
|
||||
client := NewClient(httpClient)
|
||||
streamUserParams := &StreamUserParams{
|
||||
StallWarnings: Bool(true),
|
||||
With: "followings",
|
||||
}
|
||||
stream, err := client.Streams.User(streamUserParams)
|
||||
// assert that the expected messages are received
|
||||
assert.NoError(t, err)
|
||||
defer stream.Stop()
|
||||
for message := range stream.Messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
expectedCounts := &counter{all: 1, friendsList: 1}
|
||||
assert.Equal(t, expectedCounts, counts)
|
||||
}
|
||||
|
||||
func TestStream_User_TooManyFriends(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
reqCount := 0
|
||||
mux.HandleFunc("/1.1/user.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"stall_warnings": "true", "with": "followings"}, r)
|
||||
switch reqCount {
|
||||
case 0:
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
// The first friend list message is more than bufio.MaxScanTokenSize (65536) bytes
|
||||
friendsList := "[" + strings.Repeat("1234567890, ", 7000) + "1234567890]"
|
||||
fmt.Fprintf(w, `{"friends": %s}`+"\r\n"+"\r\n", friendsList)
|
||||
default:
|
||||
// Only allow first request
|
||||
http.Error(w, "Stream API not available!", 130)
|
||||
}
|
||||
reqCount++
|
||||
})
|
||||
|
||||
counts := &counter{}
|
||||
demux := newCounterDemux(counts)
|
||||
client := NewClient(httpClient)
|
||||
streamUserParams := &StreamUserParams{
|
||||
StallWarnings: Bool(true),
|
||||
With: "followings",
|
||||
}
|
||||
stream, err := client.Streams.User(streamUserParams)
|
||||
// assert that the expected messages are received
|
||||
assert.NoError(t, err)
|
||||
defer stream.Stop()
|
||||
for message := range stream.Messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
expectedCounts := &counter{all: 1, friendsList: 1}
|
||||
assert.Equal(t, expectedCounts, counts)
|
||||
}
|
||||
|
||||
func TestStream_Site(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
reqCount := 0
|
||||
mux.HandleFunc("/1.1/site.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"follow": "666024290140217347,666024290140217349"}, r)
|
||||
switch reqCount {
|
||||
case 0:
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
fmt.Fprintf(w,
|
||||
`{"text": "Gophercon talks!"}`+"\r\n"+
|
||||
`{"text": "Gophercon super talks!"}`+"\r\n",
|
||||
)
|
||||
default:
|
||||
// Only allow first request
|
||||
http.Error(w, "Stream API not available!", 130)
|
||||
}
|
||||
reqCount++
|
||||
})
|
||||
|
||||
counts := &counter{}
|
||||
demux := newCounterDemux(counts)
|
||||
client := NewClient(httpClient)
|
||||
streamSiteParams := &StreamSiteParams{
|
||||
Follow: []string{"666024290140217347", "666024290140217349"},
|
||||
}
|
||||
stream, err := client.Streams.Site(streamSiteParams)
|
||||
// assert that the expected messages are received
|
||||
assert.NoError(t, err)
|
||||
defer stream.Stop()
|
||||
for message := range stream.Messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
expectedCounts := &counter{all: 2, other: 2}
|
||||
assert.Equal(t, expectedCounts, counts)
|
||||
}
|
||||
|
||||
func TestStream_PublicFirehose(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
reqCount := 0
|
||||
mux.HandleFunc("/1.1/statuses/firehose.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"count": "100"}, r)
|
||||
switch reqCount {
|
||||
case 0:
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
fmt.Fprintf(w,
|
||||
`{"text": "Gophercon talks!"}`+"\r\n"+
|
||||
`{"text": "Gophercon super talks!"}`+"\r\n",
|
||||
)
|
||||
default:
|
||||
// Only allow first request
|
||||
http.Error(w, "Stream API not available!", 130)
|
||||
}
|
||||
reqCount++
|
||||
})
|
||||
|
||||
counts := &counter{}
|
||||
demux := newCounterDemux(counts)
|
||||
client := NewClient(httpClient)
|
||||
streamFirehoseParams := &StreamFirehoseParams{
|
||||
Count: 100,
|
||||
}
|
||||
stream, err := client.Streams.Firehose(streamFirehoseParams)
|
||||
// assert that the expected messages are received
|
||||
assert.NoError(t, err)
|
||||
defer stream.Stop()
|
||||
for message := range stream.Messages {
|
||||
demux.Handle(message)
|
||||
}
|
||||
expectedCounts := &counter{all: 2, other: 2}
|
||||
assert.Equal(t, expectedCounts, counts)
|
||||
}
|
||||
|
||||
func TestStreamRetry_ExponentialBackoff(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
reqCount := 0
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
switch reqCount {
|
||||
case 0:
|
||||
http.Error(w, "Service Unavailable", 503)
|
||||
default:
|
||||
// Only allow first request
|
||||
http.Error(w, "Stream API not available!", 130)
|
||||
}
|
||||
reqCount++
|
||||
})
|
||||
stream := &Stream{
|
||||
client: httpClient,
|
||||
Messages: make(chan interface{}),
|
||||
done: make(chan struct{}),
|
||||
group: &sync.WaitGroup{},
|
||||
}
|
||||
stream.group.Add(1)
|
||||
req, _ := http.NewRequest("GET", "http://example.com/", nil)
|
||||
expBackoff := &BackOffRecorder{}
|
||||
// receive messages and throw them away
|
||||
go NewSwitchDemux().HandleChan(stream.Messages)
|
||||
stream.retry(req, expBackoff, nil)
|
||||
defer stream.Stop()
|
||||
// assert exponential backoff in response to 503
|
||||
assert.Equal(t, 1, expBackoff.Count)
|
||||
}
|
||||
|
||||
func TestStreamRetry_AggressiveBackoff(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
reqCount := 0
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
switch reqCount {
|
||||
case 0:
|
||||
http.Error(w, "Enhance Your Calm", 420)
|
||||
case 1:
|
||||
http.Error(w, "Too Many Requests", 429)
|
||||
default:
|
||||
// Only allow first request
|
||||
http.Error(w, "Stream API not available!", 130)
|
||||
}
|
||||
reqCount++
|
||||
})
|
||||
stream := &Stream{
|
||||
client: httpClient,
|
||||
Messages: make(chan interface{}),
|
||||
done: make(chan struct{}),
|
||||
group: &sync.WaitGroup{},
|
||||
}
|
||||
stream.group.Add(1)
|
||||
req, _ := http.NewRequest("GET", "http://example.com/", nil)
|
||||
aggExpBackoff := &BackOffRecorder{}
|
||||
// receive messages and throw them away
|
||||
go NewSwitchDemux().HandleChan(stream.Messages)
|
||||
stream.retry(req, nil, aggExpBackoff)
|
||||
defer stream.Stop()
|
||||
// assert aggressive exponential backoff in response to 420 and 429
|
||||
assert.Equal(t, 2, aggExpBackoff.Count)
|
||||
}
|
||||
109
vendor/github.com/dghubble/go-twitter/twitter/timelines.go
generated
vendored
109
vendor/github.com/dghubble/go-twitter/twitter/timelines.go
generated
vendored
@@ -1,109 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// TimelineService provides methods for accessing Twitter status timeline
|
||||
// API endpoints.
|
||||
type TimelineService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newTimelineService returns a new TimelineService.
|
||||
func newTimelineService(sling *sling.Sling) *TimelineService {
|
||||
return &TimelineService{
|
||||
sling: sling.Path("statuses/"),
|
||||
}
|
||||
}
|
||||
|
||||
// UserTimelineParams are the parameters for TimelineService.UserTimeline.
|
||||
type UserTimelineParams struct {
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
Count int `url:"count,omitempty"`
|
||||
SinceID int64 `url:"since_id,omitempty"`
|
||||
MaxID int64 `url:"max_id,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
ExcludeReplies *bool `url:"exclude_replies,omitempty"`
|
||||
IncludeRetweets *bool `url:"include_rts,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// UserTimeline returns recent Tweets from the specified user.
|
||||
// https://dev.twitter.com/rest/reference/get/statuses/user_timeline
|
||||
func (s *TimelineService) UserTimeline(params *UserTimelineParams) ([]Tweet, *http.Response, error) {
|
||||
tweets := new([]Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("user_timeline.json").QueryStruct(params).Receive(tweets, apiError)
|
||||
return *tweets, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// HomeTimelineParams are the parameters for TimelineService.HomeTimeline.
|
||||
type HomeTimelineParams struct {
|
||||
Count int `url:"count,omitempty"`
|
||||
SinceID int64 `url:"since_id,omitempty"`
|
||||
MaxID int64 `url:"max_id,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
ExcludeReplies *bool `url:"exclude_replies,omitempty"`
|
||||
ContributorDetails *bool `url:"contributor_details,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// HomeTimeline returns recent Tweets and retweets from the user and those
|
||||
// users they follow.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/get/statuses/home_timeline
|
||||
func (s *TimelineService) HomeTimeline(params *HomeTimelineParams) ([]Tweet, *http.Response, error) {
|
||||
tweets := new([]Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("home_timeline.json").QueryStruct(params).Receive(tweets, apiError)
|
||||
return *tweets, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// MentionTimelineParams are the parameters for TimelineService.MentionTimeline.
|
||||
type MentionTimelineParams struct {
|
||||
Count int `url:"count,omitempty"`
|
||||
SinceID int64 `url:"since_id,omitempty"`
|
||||
MaxID int64 `url:"max_id,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
ContributorDetails *bool `url:"contributor_details,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// MentionTimeline returns recent Tweet mentions of the authenticated user.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/get/statuses/mentions_timeline
|
||||
func (s *TimelineService) MentionTimeline(params *MentionTimelineParams) ([]Tweet, *http.Response, error) {
|
||||
tweets := new([]Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("mentions_timeline.json").QueryStruct(params).Receive(tweets, apiError)
|
||||
return *tweets, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// RetweetsOfMeTimelineParams are the parameters for
|
||||
// TimelineService.RetweetsOfMeTimeline.
|
||||
type RetweetsOfMeTimelineParams struct {
|
||||
Count int `url:"count,omitempty"`
|
||||
SinceID int64 `url:"since_id,omitempty"`
|
||||
MaxID int64 `url:"max_id,omitempty"`
|
||||
TrimUser *bool `url:"trim_user,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"`
|
||||
IncludeUserEntities *bool `url:"include_user_entities"`
|
||||
TweetMode string `url:"tweet_mode,omitempty"`
|
||||
}
|
||||
|
||||
// RetweetsOfMeTimeline returns the most recent Tweets by the authenticated
|
||||
// user that have been retweeted by others.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/get/statuses/retweets_of_me
|
||||
func (s *TimelineService) RetweetsOfMeTimeline(params *RetweetsOfMeTimelineParams) ([]Tweet, *http.Response, error) {
|
||||
tweets := new([]Tweet)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("retweets_of_me.json").QueryStruct(params).Receive(tweets, apiError)
|
||||
return *tweets, resp, relevantError(err, *apiError)
|
||||
}
|
||||
81
vendor/github.com/dghubble/go-twitter/twitter/timelines_test.go
generated
vendored
81
vendor/github.com/dghubble/go-twitter/twitter/timelines_test.go
generated
vendored
@@ -1,81 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTimelineService_UserTimeline(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/user_timeline.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"user_id": "113419064", "trim_user": "true", "include_rts": "false"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"text": "Gophercon talks!"}, {"text": "Why gophers are so adorable"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
tweets, _, err := client.Timelines.UserTimeline(&UserTimelineParams{UserID: 113419064, TrimUser: Bool(true), IncludeRetweets: Bool(false)})
|
||||
expected := []Tweet{Tweet{Text: "Gophercon talks!"}, Tweet{Text: "Why gophers are so adorable"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweets)
|
||||
}
|
||||
|
||||
func TestTimelineService_HomeTimeline(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/home_timeline.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"since_id": "589147592367431680", "exclude_replies": "false"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"text": "Live on #Periscope"}, {"text": "Clickbait journalism"}, {"text": "Useful announcement"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
tweets, _, err := client.Timelines.HomeTimeline(&HomeTimelineParams{SinceID: 589147592367431680, ExcludeReplies: Bool(false)})
|
||||
expected := []Tweet{Tweet{Text: "Live on #Periscope"}, Tweet{Text: "Clickbait journalism"}, Tweet{Text: "Useful announcement"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweets)
|
||||
}
|
||||
|
||||
func TestTimelineService_MentionTimeline(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/mentions_timeline.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"count": "20", "include_entities": "false"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"text": "@dghubble can I get verified?"}, {"text": "@dghubble why are gophers so great?"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
tweets, _, err := client.Timelines.MentionTimeline(&MentionTimelineParams{Count: 20, IncludeEntities: Bool(false)})
|
||||
expected := []Tweet{Tweet{Text: "@dghubble can I get verified?"}, Tweet{Text: "@dghubble why are gophers so great?"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweets)
|
||||
}
|
||||
|
||||
func TestTimelineService_RetweetsOfMeTimeline(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/statuses/retweets_of_me.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"trim_user": "false", "include_user_entities": "false"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"text": "RT Twitter UK edition"}, {"text": "RT Triply-replicated Gophers"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
tweets, _, err := client.Timelines.RetweetsOfMeTimeline(&RetweetsOfMeTimelineParams{TrimUser: Bool(false), IncludeUserEntities: Bool(false)})
|
||||
expected := []Tweet{Tweet{Text: "RT Twitter UK edition"}, Tweet{Text: "RT Triply-replicated Gophers"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, tweets)
|
||||
}
|
||||
102
vendor/github.com/dghubble/go-twitter/twitter/trends.go
generated
vendored
102
vendor/github.com/dghubble/go-twitter/twitter/trends.go
generated
vendored
@@ -1,102 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// TrendsService provides methods for accessing Twitter trends API endpoints.
|
||||
type TrendsService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newTrendsService returns a new TrendsService.
|
||||
func newTrendsService(sling *sling.Sling) *TrendsService {
|
||||
return &TrendsService{
|
||||
sling: sling.Path("trends/"),
|
||||
}
|
||||
}
|
||||
|
||||
// PlaceType represents a twitter trends PlaceType.
|
||||
type PlaceType struct {
|
||||
Code int `json:"code"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Location reporesents a twitter Location.
|
||||
type Location struct {
|
||||
Country string `json:"country"`
|
||||
CountryCode string `json:"countryCode"`
|
||||
Name string `json:"name"`
|
||||
ParentID int `json:"parentid"`
|
||||
PlaceType PlaceType `json:"placeType"`
|
||||
URL string `json:"url"`
|
||||
WOEID int64 `json:"woeid"`
|
||||
}
|
||||
|
||||
// Available returns the locations that Twitter has trending topic information for.
|
||||
// https://dev.twitter.com/rest/reference/get/trends/available
|
||||
func (s *TrendsService) Available() ([]Location, *http.Response, error) {
|
||||
locations := new([]Location)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("available.json").Receive(locations, apiError)
|
||||
return *locations, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// Trend represents a twitter trend.
|
||||
type Trend struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
PromotedContent string `json:"promoted_content"`
|
||||
Query string `json:"query"`
|
||||
TweetVolume int64 `json:"tweet_volume"`
|
||||
}
|
||||
|
||||
// TrendsList represents a list of twitter trends.
|
||||
type TrendsList struct {
|
||||
Trends []Trend `json:"trends"`
|
||||
AsOf string `json:"as_of"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Locations []TrendsLocation `json:"locations"`
|
||||
}
|
||||
|
||||
// TrendsLocation represents a twitter trend location.
|
||||
type TrendsLocation struct {
|
||||
Name string `json:"name"`
|
||||
WOEID int64 `json:"woeid"`
|
||||
}
|
||||
|
||||
// TrendsPlaceParams are the parameters for Trends.Place.
|
||||
type TrendsPlaceParams struct {
|
||||
WOEID int64 `url:"id,omitempty"`
|
||||
Exclude string `url:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
// Place returns the top 50 trending topics for a specific WOEID.
|
||||
// https://dev.twitter.com/rest/reference/get/trends/place
|
||||
func (s *TrendsService) Place(woeid int64, params *TrendsPlaceParams) ([]TrendsList, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &TrendsPlaceParams{}
|
||||
}
|
||||
trendsList := new([]TrendsList)
|
||||
params.WOEID = woeid
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("place.json").QueryStruct(params).Receive(trendsList, apiError)
|
||||
return *trendsList, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// ClosestParams are the parameters for Trends.Closest.
|
||||
type ClosestParams struct {
|
||||
Lat float64 `url:"lat"`
|
||||
Long float64 `url:"long"`
|
||||
}
|
||||
|
||||
// Closest returns the locations that Twitter has trending topic information for, closest to a specified location.
|
||||
// https://dev.twitter.com/rest/reference/get/trends/closest
|
||||
func (s *TrendsService) Closest(params *ClosestParams) ([]Location, *http.Response, error) {
|
||||
locations := new([]Location)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("closest.json").QueryStruct(params).Receive(locations, apiError)
|
||||
return *locations, resp, relevantError(err, *apiError)
|
||||
}
|
||||
87
vendor/github.com/dghubble/go-twitter/twitter/trends_test.go
generated
vendored
87
vendor/github.com/dghubble/go-twitter/twitter/trends_test.go
generated
vendored
@@ -1,87 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTrendsService_Available(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/trends/available.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"country": "Sweden","countryCode": "SE","name": "Sweden","parentid": 1,"placeType": {"code": 12,"name": "Country"},"url": "http://where.yahooapis.com/v1/place/23424954","woeid": 23424954}]`)
|
||||
})
|
||||
expected := []Location{
|
||||
Location{
|
||||
Country: "Sweden",
|
||||
CountryCode: "SE",
|
||||
Name: "Sweden",
|
||||
ParentID: 1,
|
||||
PlaceType: PlaceType{Code: 12, Name: "Country"},
|
||||
URL: "http://where.yahooapis.com/v1/place/23424954",
|
||||
WOEID: 23424954,
|
||||
},
|
||||
}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
locations, _, err := client.Trends.Available()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, locations)
|
||||
}
|
||||
|
||||
func TestTrendsService_Place(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/trends/place.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"id": "123456"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"trends":[{"name":"#gotwitter"}], "as_of": "2017-02-08T16:18:18Z", "created_at": "2017-02-08T16:10:33Z","locations":[{"name": "Worldwide","woeid": 1}]}]`)
|
||||
})
|
||||
expected := []TrendsList{TrendsList{
|
||||
Trends: []Trend{Trend{Name: "#gotwitter"}},
|
||||
AsOf: "2017-02-08T16:18:18Z",
|
||||
CreatedAt: "2017-02-08T16:10:33Z",
|
||||
Locations: []TrendsLocation{TrendsLocation{Name: "Worldwide", WOEID: 1}},
|
||||
}}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
places, _, err := client.Trends.Place(123456, &TrendsPlaceParams{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, places)
|
||||
}
|
||||
|
||||
func TestTrendsService_Closest(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/trends/closest.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"lat": "37.781157", "long": "-122.400612831116"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"country": "Sweden","countryCode": "SE","name": "Sweden","parentid": 1,"placeType": {"code": 12,"name": "Country"},"url": "http://where.yahooapis.com/v1/place/23424954","woeid": 23424954}]`)
|
||||
})
|
||||
expected := []Location{
|
||||
Location{
|
||||
Country: "Sweden",
|
||||
CountryCode: "SE",
|
||||
Name: "Sweden",
|
||||
ParentID: 1,
|
||||
PlaceType: PlaceType{Code: 12, Name: "Country"},
|
||||
URL: "http://where.yahooapis.com/v1/place/23424954",
|
||||
WOEID: 23424954,
|
||||
},
|
||||
}
|
||||
|
||||
client := NewClient(httpClient)
|
||||
locations, _, err := client.Trends.Closest(&ClosestParams{Lat: 37.781157, Long: -122.400612831116})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, locations)
|
||||
}
|
||||
61
vendor/github.com/dghubble/go-twitter/twitter/twitter.go
generated
vendored
61
vendor/github.com/dghubble/go-twitter/twitter/twitter.go
generated
vendored
@@ -1,61 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
const twitterAPI = "https://api.twitter.com/1.1/"
|
||||
|
||||
// Client is a Twitter client for making Twitter API requests.
|
||||
type Client struct {
|
||||
sling *sling.Sling
|
||||
// Twitter API Services
|
||||
Accounts *AccountService
|
||||
DirectMessages *DirectMessageService
|
||||
Favorites *FavoriteService
|
||||
Followers *FollowerService
|
||||
Friends *FriendService
|
||||
Friendships *FriendshipService
|
||||
Search *SearchService
|
||||
Statuses *StatusService
|
||||
Streams *StreamService
|
||||
Timelines *TimelineService
|
||||
Trends *TrendsService
|
||||
Users *UserService
|
||||
}
|
||||
|
||||
// NewClient returns a new Client.
|
||||
func NewClient(httpClient *http.Client) *Client {
|
||||
base := sling.New().Client(httpClient).Base(twitterAPI)
|
||||
return &Client{
|
||||
sling: base,
|
||||
Accounts: newAccountService(base.New()),
|
||||
DirectMessages: newDirectMessageService(base.New()),
|
||||
Favorites: newFavoriteService(base.New()),
|
||||
Followers: newFollowerService(base.New()),
|
||||
Friends: newFriendService(base.New()),
|
||||
Friendships: newFriendshipService(base.New()),
|
||||
Search: newSearchService(base.New()),
|
||||
Statuses: newStatusService(base.New()),
|
||||
Streams: newStreamService(httpClient, base.New()),
|
||||
Timelines: newTimelineService(base.New()),
|
||||
Trends: newTrendsService(base.New()),
|
||||
Users: newUserService(base.New()),
|
||||
}
|
||||
}
|
||||
|
||||
// Bool returns a new pointer to the given bool value.
|
||||
func Bool(v bool) *bool {
|
||||
ptr := new(bool)
|
||||
*ptr = v
|
||||
return ptr
|
||||
}
|
||||
|
||||
// Float returns a new pointer to the given float64 value.
|
||||
func Float(v float64) *float64 {
|
||||
ptr := new(float64)
|
||||
*ptr = v
|
||||
return ptr
|
||||
}
|
||||
93
vendor/github.com/dghubble/go-twitter/twitter/twitter_test.go
generated
vendored
93
vendor/github.com/dghubble/go-twitter/twitter/twitter_test.go
generated
vendored
@@ -1,93 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var defaultTestTimeout = time.Second * 1
|
||||
|
||||
// testServer returns an http Client, ServeMux, and Server. The client proxies
|
||||
// requests to the server and handlers can be registered on the mux to handle
|
||||
// requests. The caller must close the test server.
|
||||
func testServer() (*http.Client, *http.ServeMux, *httptest.Server) {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
transport := &RewriteTransport{&http.Transport{
|
||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||
return url.Parse(server.URL)
|
||||
},
|
||||
}}
|
||||
client := &http.Client{Transport: transport}
|
||||
return client, mux, server
|
||||
}
|
||||
|
||||
// RewriteTransport rewrites https requests to http to avoid TLS cert issues
|
||||
// during testing.
|
||||
type RewriteTransport struct {
|
||||
Transport http.RoundTripper
|
||||
}
|
||||
|
||||
// RoundTrip rewrites the request scheme to http and calls through to the
|
||||
// composed RoundTripper or if it is nil, to the http.DefaultTransport.
|
||||
func (t *RewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req.URL.Scheme = "http"
|
||||
if t.Transport == nil {
|
||||
return http.DefaultTransport.RoundTrip(req)
|
||||
}
|
||||
return t.Transport.RoundTrip(req)
|
||||
}
|
||||
|
||||
func assertMethod(t *testing.T, expectedMethod string, req *http.Request) {
|
||||
assert.Equal(t, expectedMethod, req.Method)
|
||||
}
|
||||
|
||||
// assertQuery tests that the Request has the expected url query key/val pairs
|
||||
func assertQuery(t *testing.T, expected map[string]string, req *http.Request) {
|
||||
queryValues := req.URL.Query()
|
||||
expectedValues := url.Values{}
|
||||
for key, value := range expected {
|
||||
expectedValues.Add(key, value)
|
||||
}
|
||||
assert.Equal(t, expectedValues, queryValues)
|
||||
}
|
||||
|
||||
// assertPostForm tests that the Request has the expected key values pairs url
|
||||
// encoded in its Body
|
||||
func assertPostForm(t *testing.T, expected map[string]string, req *http.Request) {
|
||||
req.ParseForm() // parses request Body to put url.Values in r.Form/r.PostForm
|
||||
expectedValues := url.Values{}
|
||||
for key, value := range expected {
|
||||
expectedValues.Add(key, value)
|
||||
}
|
||||
assert.Equal(t, expectedValues, req.Form)
|
||||
}
|
||||
|
||||
// assertDone asserts that the empty struct channel is closed before the given
|
||||
// timeout elapses.
|
||||
func assertDone(t *testing.T, ch <-chan struct{}, timeout time.Duration) {
|
||||
select {
|
||||
case <-ch:
|
||||
_, more := <-ch
|
||||
assert.False(t, more)
|
||||
case <-time.After(timeout):
|
||||
t.Errorf("expected channel to be closed within timeout %v", timeout)
|
||||
}
|
||||
}
|
||||
|
||||
// assertClosed asserts that the channel is closed before the given timeout
|
||||
// elapses.
|
||||
func assertClosed(t *testing.T, ch <-chan interface{}, timeout time.Duration) {
|
||||
select {
|
||||
case <-ch:
|
||||
_, more := <-ch
|
||||
assert.False(t, more)
|
||||
case <-time.After(timeout):
|
||||
t.Errorf("expected channel to be closed within timeout %v", timeout)
|
||||
}
|
||||
}
|
||||
122
vendor/github.com/dghubble/go-twitter/twitter/users.go
generated
vendored
122
vendor/github.com/dghubble/go-twitter/twitter/users.go
generated
vendored
@@ -1,122 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
// User represents a Twitter User.
|
||||
// https://dev.twitter.com/overview/api/users
|
||||
type User struct {
|
||||
ContributorsEnabled bool `json:"contributors_enabled"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
DefaultProfile bool `json:"default_profile"`
|
||||
DefaultProfileImage bool `json:"default_profile_image"`
|
||||
Description string `json:"description"`
|
||||
Email string `json:"email"`
|
||||
Entities *UserEntities `json:"entities"`
|
||||
FavouritesCount int `json:"favourites_count"`
|
||||
FollowRequestSent bool `json:"follow_request_sent"`
|
||||
Following bool `json:"following"`
|
||||
FollowersCount int `json:"followers_count"`
|
||||
FriendsCount int `json:"friends_count"`
|
||||
GeoEnabled bool `json:"geo_enabled"`
|
||||
ID int64 `json:"id"`
|
||||
IDStr string `json:"id_str"`
|
||||
IsTranslator bool `json:"is_translator"`
|
||||
Lang string `json:"lang"`
|
||||
ListedCount int `json:"listed_count"`
|
||||
Location string `json:"location"`
|
||||
Name string `json:"name"`
|
||||
Notifications bool `json:"notifications"`
|
||||
ProfileBackgroundColor string `json:"profile_background_color"`
|
||||
ProfileBackgroundImageURL string `json:"profile_background_image_url"`
|
||||
ProfileBackgroundImageURLHttps string `json:"profile_background_image_url_https"`
|
||||
ProfileBackgroundTile bool `json:"profile_background_tile"`
|
||||
ProfileBannerURL string `json:"profile_banner_url"`
|
||||
ProfileImageURL string `json:"profile_image_url"`
|
||||
ProfileImageURLHttps string `json:"profile_image_url_https"`
|
||||
ProfileLinkColor string `json:"profile_link_color"`
|
||||
ProfileSidebarBorderColor string `json:"profile_sidebar_border_color"`
|
||||
ProfileSidebarFillColor string `json:"profile_sidebar_fill_color"`
|
||||
ProfileTextColor string `json:"profile_text_color"`
|
||||
ProfileUseBackgroundImage bool `json:"profile_use_background_image"`
|
||||
Protected bool `json:"protected"`
|
||||
ScreenName string `json:"screen_name"`
|
||||
ShowAllInlineMedia bool `json:"show_all_inline_media"`
|
||||
Status *Tweet `json:"status"`
|
||||
StatusesCount int `json:"statuses_count"`
|
||||
Timezone string `json:"time_zone"`
|
||||
URL string `json:"url"`
|
||||
UtcOffset int `json:"utc_offset"`
|
||||
Verified bool `json:"verified"`
|
||||
WithheldInCountries []string `json:"withheld_in_countries"`
|
||||
WithholdScope string `json:"withheld_scope"`
|
||||
}
|
||||
|
||||
// UserService provides methods for accessing Twitter user API endpoints.
|
||||
type UserService struct {
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
// newUserService returns a new UserService.
|
||||
func newUserService(sling *sling.Sling) *UserService {
|
||||
return &UserService{
|
||||
sling: sling.Path("users/"),
|
||||
}
|
||||
}
|
||||
|
||||
// UserShowParams are the parameters for UserService.Show.
|
||||
type UserShowParams struct {
|
||||
UserID int64 `url:"user_id,omitempty"`
|
||||
ScreenName string `url:"screen_name,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"` // whether 'status' should include entities
|
||||
}
|
||||
|
||||
// Show returns the requested User.
|
||||
// https://dev.twitter.com/rest/reference/get/users/show
|
||||
func (s *UserService) Show(params *UserShowParams) (*User, *http.Response, error) {
|
||||
user := new(User)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(user, apiError)
|
||||
return user, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// UserLookupParams are the parameters for UserService.Lookup.
|
||||
type UserLookupParams struct {
|
||||
UserID []int64 `url:"user_id,omitempty,comma"`
|
||||
ScreenName []string `url:"screen_name,omitempty,comma"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"` // whether 'status' should include entities
|
||||
}
|
||||
|
||||
// Lookup returns the requested Users as a slice.
|
||||
// https://dev.twitter.com/rest/reference/get/users/lookup
|
||||
func (s *UserService) Lookup(params *UserLookupParams) ([]User, *http.Response, error) {
|
||||
users := new([]User)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(users, apiError)
|
||||
return *users, resp, relevantError(err, *apiError)
|
||||
}
|
||||
|
||||
// UserSearchParams are the parameters for UserService.Search.
|
||||
type UserSearchParams struct {
|
||||
Query string `url:"q,omitempty"`
|
||||
Page int `url:"page,omitempty"` // 1-based page number
|
||||
Count int `url:"count,omitempty"`
|
||||
IncludeEntities *bool `url:"include_entities,omitempty"` // whether 'status' should include entities
|
||||
}
|
||||
|
||||
// Search queries public user accounts.
|
||||
// Requires a user auth context.
|
||||
// https://dev.twitter.com/rest/reference/get/users/search
|
||||
func (s *UserService) Search(query string, params *UserSearchParams) ([]User, *http.Response, error) {
|
||||
if params == nil {
|
||||
params = &UserSearchParams{}
|
||||
}
|
||||
params.Query = query
|
||||
users := new([]User)
|
||||
apiError := new(APIError)
|
||||
resp, err := s.sling.New().Get("search.json").QueryStruct(params).Receive(users, apiError)
|
||||
return *users, resp, relevantError(err, *apiError)
|
||||
}
|
||||
92
vendor/github.com/dghubble/go-twitter/twitter/users_test.go
generated
vendored
92
vendor/github.com/dghubble/go-twitter/twitter/users_test.go
generated
vendored
@@ -1,92 +0,0 @@
|
||||
package twitter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUserService_Show(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/users/show.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"screen_name": "xkcdComic"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"name": "XKCD Comic", "favourites_count": 2}`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
user, _, err := client.Users.Show(&UserShowParams{ScreenName: "xkcdComic"})
|
||||
expected := &User{Name: "XKCD Comic", FavouritesCount: 2}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, user)
|
||||
}
|
||||
|
||||
func TestUserService_LookupWithIds(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/users/lookup.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"user_id": "113419064,623265148"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"screen_name": "golang"}, {"screen_name": "dghubble"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
users, _, err := client.Users.Lookup(&UserLookupParams{UserID: []int64{113419064, 623265148}})
|
||||
expected := []User{User{ScreenName: "golang"}, User{ScreenName: "dghubble"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, users)
|
||||
}
|
||||
|
||||
func TestUserService_LookupWithScreenNames(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/users/lookup.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"screen_name": "foo,bar"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"name": "Foo"}, {"name": "Bar"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
users, _, err := client.Users.Lookup(&UserLookupParams{ScreenName: []string{"foo", "bar"}})
|
||||
expected := []User{User{Name: "Foo"}, User{Name: "Bar"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, users)
|
||||
}
|
||||
|
||||
func TestUserService_Search(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/users/search.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertMethod(t, "GET", r)
|
||||
assertQuery(t, map[string]string{"count": "11", "q": "news"}, r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `[{"name": "BBC"}, {"name": "BBC Breaking News"}]`)
|
||||
})
|
||||
|
||||
client := NewClient(httpClient)
|
||||
users, _, err := client.Users.Search("news", &UserSearchParams{Query: "override me", Count: 11})
|
||||
expected := []User{User{Name: "BBC"}, User{Name: "BBC Breaking News"}}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, users)
|
||||
}
|
||||
|
||||
func TestUserService_SearchHandlesNilParams(t *testing.T) {
|
||||
httpClient, mux, server := testServer()
|
||||
defer server.Close()
|
||||
|
||||
mux.HandleFunc("/1.1/users/search.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
assertQuery(t, map[string]string{"q": "news"}, r)
|
||||
})
|
||||
client := NewClient(httpClient)
|
||||
client.Users.Search("news", nil)
|
||||
}
|
||||
10
vendor/github.com/dghubble/oauth1/.travis.yml
generated
vendored
10
vendor/github.com/dghubble/oauth1/.travis.yml
generated
vendored
@@ -1,10 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.7
|
||||
- 1.8
|
||||
- tip
|
||||
install:
|
||||
- go get github.com/golang/lint/golint
|
||||
- go get -v -t .
|
||||
script:
|
||||
- ./test
|
||||
30
vendor/github.com/dghubble/oauth1/CHANGES.md
generated
vendored
30
vendor/github.com/dghubble/oauth1/CHANGES.md
generated
vendored
@@ -1,30 +0,0 @@
|
||||
# OAuth1 Changelog
|
||||
|
||||
## v0.4.0 (2016-04-20)
|
||||
|
||||
* Add a Signer field to the Config to allow custom Signer implementations.
|
||||
* Use the HMACSigner by default. This provides the same signing behavior as in previous versions (HMAC-SHA1).
|
||||
* Add an RSASigner for "RSA-SHA1" OAuth1 Providers.
|
||||
* Add missing Authorization Header quotes around OAuth parameter values. Many providers allowed these quotes to be missing.
|
||||
* Change `Signer` to be a signer interface.
|
||||
* Remove the old Signer methods `SetAccessTokenAuthHeader`, `SetRequestAuthHeader`, and `SetRequestTokenAuthHeader`.
|
||||
|
||||
## v0.3.0 (2015-09-13)
|
||||
|
||||
* Added `NoContext` which may be used in most cases.
|
||||
* Allowed Transport Base http.RoundTripper to be set through a ctx.
|
||||
* Changed `NewClient` to require a context.Context.
|
||||
* Changed `Config.Client` to require a context.Context.
|
||||
|
||||
## v.0.2.0 (2015-08-30)
|
||||
|
||||
* Improved OAuth 1 spec compliance and test coverage.
|
||||
* Added `func StaticTokenSource(*Token) TokenSource`
|
||||
* Added `ParseAuthorizationCallback` function. Removed `Config.HandleAuthorizationCallback` method.
|
||||
* Changed `Config` method signatures to allow an interface to be defined for the OAuth1 authorization flow. Gives users of this package (and downstream packages) the freedom to use other implementations if they wish.
|
||||
* Removed `RequestToken` in favor of passing token and secret value strings.
|
||||
* Removed `ReuseTokenSource` struct, it was effectively a static source. Replaced by `StaticTokenSource`.
|
||||
|
||||
## v0.1.0 (2015-04-26)
|
||||
|
||||
* Initial OAuth1 support for obtaining authorization and making authorized requests.
|
||||
21
vendor/github.com/dghubble/oauth1/LICENSE
generated
vendored
21
vendor/github.com/dghubble/oauth1/LICENSE
generated
vendored
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Dalton Hubble
|
||||
|
||||
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.
|
||||
125
vendor/github.com/dghubble/oauth1/README.md
generated
vendored
125
vendor/github.com/dghubble/oauth1/README.md
generated
vendored
@@ -1,125 +0,0 @@
|
||||
|
||||
# OAuth1 [](https://travis-ci.org/dghubble/oauth1) [](http://godoc.org/github.com/dghubble/oauth1)
|
||||
<img align="right" src="https://storage.googleapis.com/dghubble/oauth1.png">
|
||||
|
||||
OAauth1 is a Go implementation of the [OAuth 1 spec](https://tools.ietf.org/html/rfc5849).
|
||||
|
||||
It allows end-users to authorize a client (consumer) to access protected resources on his/her behalf and to make signed and authorized requests.
|
||||
|
||||
Package `oauth1` takes design cues from [golang.org/x/oauth2](https://godoc.org/golang.org/x/oauth2), to provide an analogous API and an `http.Client` with a Transport which signs/authorizes requests.
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/dghubble/oauth1
|
||||
|
||||
## Docs
|
||||
|
||||
Read [GoDoc](https://godoc.org/github.com/dghubble/oauth1)
|
||||
|
||||
## Usage
|
||||
|
||||
Package `oauth1` implements the OAuth1 authorization flow and provides an `http.Client` which can sign and authorize OAuth1 requests.
|
||||
|
||||
To implement "Login with X", use the [gologin](https://github.com/dghubble/gologin) packages which provide login handlers for OAuth1 and OAuth2 providers.
|
||||
|
||||
To call the Twitter, Digits, or Tumblr OAuth1 APIs, use the higher level Go API clients.
|
||||
|
||||
* [Twitter](https://github.com/dghubble/go-twitter)
|
||||
* [Digits](https://github.com/dghubble/go-digits)
|
||||
* [Tumblr](https://github.com/benfb/go-tumblr)
|
||||
|
||||
### Authorization Flow
|
||||
|
||||
Perform the OAuth 1 authorization flow to ask a user to grant an application access to his/her resources via an access token.
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/dghubble/oauth1"
|
||||
"github.com/dghubble/oauth1/twitter""
|
||||
)
|
||||
...
|
||||
|
||||
config := oauth1.Config{
|
||||
ConsumerKey: "consumerKey",
|
||||
ConsumerSecret: "consumerSecret",
|
||||
CallbackURL: "http://mysite.com/oauth/twitter/callback",
|
||||
Endpoint: twitter.AuthorizeEndpoint,
|
||||
}
|
||||
```
|
||||
|
||||
1. When a user performs an action (e.g. "Login with X" button calls "/login" route) get an OAuth1 request token (temporary credentials).
|
||||
|
||||
```go
|
||||
requestToken, requestSecret, err = config.RequestToken()
|
||||
// handle err
|
||||
```
|
||||
|
||||
2. Obtain authorization from the user by redirecting them to the OAuth1 provider's authorization URL to grant the application access.
|
||||
|
||||
```go
|
||||
authorizationURL, err := config.AuthorizationURL(requestToken)
|
||||
// handle err
|
||||
http.Redirect(w, req, authorizationURL.String(), http.StatusFound)
|
||||
```
|
||||
|
||||
Receive the callback from the OAuth1 provider in a handler.
|
||||
|
||||
```go
|
||||
requestToken, verifier, err := oauth1.ParseAuthorizationCallback(req)
|
||||
// handle err
|
||||
```
|
||||
|
||||
3. Acquire the access token (token credentials) which can later be used to make requests on behalf of the user.
|
||||
|
||||
```go
|
||||
accessToken, accessSecret, err := config.AccessToken(requestToken, requestSecret, verifier)
|
||||
// handle error
|
||||
token := oauth1.NewToken(accessToken, accessSecret)
|
||||
```
|
||||
|
||||
Check the [examples](examples) to see this authorization flow in action from the command line, with Twitter PIN-based login and Tumblr login.
|
||||
|
||||
### Authorized Requests
|
||||
|
||||
Use an access `Token` to make authorized requests on behalf of a user.
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/dghubble/oauth1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config := oauth1.NewConfig("consumerKey", "consumerSecret")
|
||||
token := oauth1.NewToken("token", "tokenSecret")
|
||||
|
||||
// httpClient will automatically authorize http.Request's
|
||||
httpClient := config.Client(oauth1.NoContext, token)
|
||||
|
||||
// example Twitter API request
|
||||
path := "https://api.twitter.com/1.1/statuses/home_timeline.json?count=2"
|
||||
resp, _ := httpClient.Get(path)
|
||||
defer resp.Body.Close()
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Printf("Raw Response Body:\n%v\n", string(body))
|
||||
}
|
||||
```
|
||||
|
||||
Check the [examples](examples) to see Twitter and Tumblr requests in action.
|
||||
|
||||
### Concepts
|
||||
|
||||
An `Endpoint` groups an OAuth provider's token and authorization URL endpoints.Endpoints for common providers are provided in subpackages.
|
||||
|
||||
A `Config` stores a consumer application's consumer key and secret, the registered callback URL, and the `Endpoint` to which the consumer is registered. It provides OAuth1 authorization flow methods.
|
||||
|
||||
An OAuth1 `Token` is an access token which can be used to make signed requests on behalf of a user. See [Authorized Requests](#Authorized Requests) for details.
|
||||
|
||||
If you've used the [golang.org/x/oauth2](https://godoc.org/golang.org/x/oauth2) package for OAuth2 before, this organization should be familiar.
|
||||
|
||||
## Contributing
|
||||
|
||||
See the [Contributing Guide](https://gist.github.com/dghubble/be682c123727f70bcfe7).
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](LICENSE)
|
||||
265
vendor/github.com/dghubble/oauth1/auther.go
generated
vendored
265
vendor/github.com/dghubble/oauth1/auther.go
generated
vendored
@@ -1,265 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
authorizationHeaderParam = "Authorization"
|
||||
authorizationPrefix = "OAuth " // trailing space is intentional
|
||||
oauthConsumerKeyParam = "oauth_consumer_key"
|
||||
oauthNonceParam = "oauth_nonce"
|
||||
oauthSignatureParam = "oauth_signature"
|
||||
oauthSignatureMethodParam = "oauth_signature_method"
|
||||
oauthTimestampParam = "oauth_timestamp"
|
||||
oauthTokenParam = "oauth_token"
|
||||
oauthVersionParam = "oauth_version"
|
||||
oauthCallbackParam = "oauth_callback"
|
||||
oauthVerifierParam = "oauth_verifier"
|
||||
defaultOauthVersion = "1.0"
|
||||
contentType = "Content-Type"
|
||||
formContentType = "application/x-www-form-urlencoded"
|
||||
)
|
||||
|
||||
// clock provides a interface for current time providers. A Clock can be used
|
||||
// in place of calling time.Now() directly.
|
||||
type clock interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
// A noncer provides random nonce strings.
|
||||
type noncer interface {
|
||||
Nonce() string
|
||||
}
|
||||
|
||||
// auther adds an "OAuth" Authorization header field to requests.
|
||||
type auther struct {
|
||||
config *Config
|
||||
clock clock
|
||||
noncer noncer
|
||||
}
|
||||
|
||||
func newAuther(config *Config) *auther {
|
||||
return &auther{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// setRequestTokenAuthHeader adds the OAuth1 header for the request token
|
||||
// request (temporary credential) according to RFC 5849 2.1.
|
||||
func (a *auther) setRequestTokenAuthHeader(req *http.Request) error {
|
||||
oauthParams := a.commonOAuthParams()
|
||||
oauthParams[oauthCallbackParam] = a.config.CallbackURL
|
||||
params, err := collectParameters(req, oauthParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signatureBase := signatureBase(req, params)
|
||||
signature, err := a.signer().Sign("", signatureBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oauthParams[oauthSignatureParam] = signature
|
||||
req.Header.Set(authorizationHeaderParam, authHeaderValue(oauthParams))
|
||||
return nil
|
||||
}
|
||||
|
||||
// setAccessTokenAuthHeader sets the OAuth1 header for the access token request
|
||||
// (token credential) according to RFC 5849 2.3.
|
||||
func (a *auther) setAccessTokenAuthHeader(req *http.Request, requestToken, requestSecret, verifier string) error {
|
||||
oauthParams := a.commonOAuthParams()
|
||||
oauthParams[oauthTokenParam] = requestToken
|
||||
oauthParams[oauthVerifierParam] = verifier
|
||||
params, err := collectParameters(req, oauthParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signatureBase := signatureBase(req, params)
|
||||
signature, err := a.signer().Sign(requestSecret, signatureBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oauthParams[oauthSignatureParam] = signature
|
||||
req.Header.Set(authorizationHeaderParam, authHeaderValue(oauthParams))
|
||||
return nil
|
||||
}
|
||||
|
||||
// setRequestAuthHeader sets the OAuth1 header for making authenticated
|
||||
// requests with an AccessToken (token credential) according to RFC 5849 3.1.
|
||||
func (a *auther) setRequestAuthHeader(req *http.Request, accessToken *Token) error {
|
||||
oauthParams := a.commonOAuthParams()
|
||||
oauthParams[oauthTokenParam] = accessToken.Token
|
||||
params, err := collectParameters(req, oauthParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signatureBase := signatureBase(req, params)
|
||||
signature, err := a.signer().Sign(accessToken.TokenSecret, signatureBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oauthParams[oauthSignatureParam] = signature
|
||||
req.Header.Set(authorizationHeaderParam, authHeaderValue(oauthParams))
|
||||
return nil
|
||||
}
|
||||
|
||||
// commonOAuthParams returns a map of the common OAuth1 protocol parameters,
|
||||
// excluding the oauth_signature parameter.
|
||||
func (a *auther) commonOAuthParams() map[string]string {
|
||||
return map[string]string{
|
||||
oauthConsumerKeyParam: a.config.ConsumerKey,
|
||||
oauthSignatureMethodParam: a.signer().Name(),
|
||||
oauthTimestampParam: strconv.FormatInt(a.epoch(), 10),
|
||||
oauthNonceParam: a.nonce(),
|
||||
oauthVersionParam: defaultOauthVersion,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a base64 encoded random 32 byte string.
|
||||
func (a *auther) nonce() string {
|
||||
if a.noncer != nil {
|
||||
return a.noncer.Nonce()
|
||||
}
|
||||
b := make([]byte, 32)
|
||||
rand.Read(b)
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
// Returns the Unix epoch seconds.
|
||||
func (a *auther) epoch() int64 {
|
||||
if a.clock != nil {
|
||||
return a.clock.Now().Unix()
|
||||
}
|
||||
return time.Now().Unix()
|
||||
}
|
||||
|
||||
// Returns the Config's Signer or the default Signer.
|
||||
func (a *auther) signer() Signer {
|
||||
if a.config.Signer != nil {
|
||||
return a.config.Signer
|
||||
}
|
||||
return &HMACSigner{ConsumerSecret: a.config.ConsumerSecret}
|
||||
}
|
||||
|
||||
// authHeaderValue formats OAuth parameters according to RFC 5849 3.5.1. OAuth
|
||||
// params are percent encoded, sorted by key (for testability), and joined by
|
||||
// "=" into pairs. Pairs are joined with a ", " comma separator into a header
|
||||
// string.
|
||||
// The given OAuth params should include the "oauth_signature" key.
|
||||
func authHeaderValue(oauthParams map[string]string) string {
|
||||
pairs := sortParameters(encodeParameters(oauthParams), `%s="%s"`)
|
||||
return authorizationPrefix + strings.Join(pairs, ", ")
|
||||
}
|
||||
|
||||
// encodeParameters percent encodes parameter keys and values according to
|
||||
// RFC5849 3.6 and RFC3986 2.1 and returns a new map.
|
||||
func encodeParameters(params map[string]string) map[string]string {
|
||||
encoded := map[string]string{}
|
||||
for key, value := range params {
|
||||
encoded[PercentEncode(key)] = PercentEncode(value)
|
||||
}
|
||||
return encoded
|
||||
}
|
||||
|
||||
// sortParameters sorts parameters by key and returns a slice of key/value
|
||||
// pairs formatted with the given format string (e.g. "%s=%s").
|
||||
func sortParameters(params map[string]string, format string) []string {
|
||||
// sort by key
|
||||
keys := make([]string, len(params))
|
||||
i := 0
|
||||
for key := range params {
|
||||
keys[i] = key
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
// parameter join
|
||||
pairs := make([]string, len(params))
|
||||
for i, key := range keys {
|
||||
pairs[i] = fmt.Sprintf(format, key, params[key])
|
||||
}
|
||||
return pairs
|
||||
}
|
||||
|
||||
// collectParameters collects request parameters from the request query, OAuth
|
||||
// parameters (which should exclude oauth_signature), and the request body
|
||||
// provided the body is single part, form encoded, and the form content type
|
||||
// header is set. The returned map of collected parameter keys and values
|
||||
// follow RFC 5849 3.4.1.3, except duplicate parameters are not supported.
|
||||
func collectParameters(req *http.Request, oauthParams map[string]string) (map[string]string, error) {
|
||||
// add oauth, query, and body parameters into params
|
||||
params := map[string]string{}
|
||||
for key, value := range req.URL.Query() {
|
||||
// most backends do not accept duplicate query keys
|
||||
params[key] = value[0]
|
||||
}
|
||||
if req.Body != nil && req.Header.Get(contentType) == formContentType {
|
||||
// reads data to a []byte, draining req.Body
|
||||
b, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values, err := url.ParseQuery(string(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for key, value := range values {
|
||||
// not supporting params with duplicate keys
|
||||
params[key] = value[0]
|
||||
}
|
||||
// reinitialize Body with ReadCloser over the []byte
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||
}
|
||||
for key, value := range oauthParams {
|
||||
params[key] = value
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// signatureBase combines the uppercase request method, percent encoded base
|
||||
// string URI, and normalizes the request parameters int a parameter string.
|
||||
// Returns the OAuth1 signature base string according to RFC5849 3.4.1.
|
||||
func signatureBase(req *http.Request, params map[string]string) string {
|
||||
method := strings.ToUpper(req.Method)
|
||||
baseURL := baseURI(req)
|
||||
parameterString := normalizedParameterString(params)
|
||||
// signature base string constructed accoding to 3.4.1.1
|
||||
baseParts := []string{method, PercentEncode(baseURL), PercentEncode(parameterString)}
|
||||
return strings.Join(baseParts, "&")
|
||||
}
|
||||
|
||||
// baseURI returns the base string URI of a request according to RFC 5849
|
||||
// 3.4.1.2. The scheme and host are lowercased, the port is dropped if it
|
||||
// is 80 or 443, and the path minus query parameters is included.
|
||||
func baseURI(req *http.Request) string {
|
||||
scheme := strings.ToLower(req.URL.Scheme)
|
||||
host := strings.ToLower(req.URL.Host)
|
||||
if hostPort := strings.Split(host, ":"); len(hostPort) == 2 && (hostPort[1] == "80" || hostPort[1] == "443") {
|
||||
host = hostPort[0]
|
||||
}
|
||||
// TODO: use req.URL.EscapedPath() once Go 1.5 is more generally adopted
|
||||
// For now, hacky workaround accomplishes the same internal escaping mode
|
||||
// escape(u.Path, encodePath) for proper compliance with the OAuth1 spec.
|
||||
path := req.URL.Path
|
||||
if path != "" {
|
||||
path = strings.Split(req.URL.RequestURI(), "?")[0]
|
||||
}
|
||||
return fmt.Sprintf("%v://%v%v", scheme, host, path)
|
||||
}
|
||||
|
||||
// parameterString normalizes collected OAuth parameters (which should exclude
|
||||
// oauth_signature) into a parameter string as defined in RFC 5894 3.4.1.3.2.
|
||||
// The parameters are encoded, sorted by key, keys and values joined with "&",
|
||||
// and pairs joined with "=" (e.g. foo=bar&q=gopher).
|
||||
func normalizedParameterString(params map[string]string) string {
|
||||
return strings.Join(sortParameters(encodeParameters(params), "%s=%s"), "&")
|
||||
}
|
||||
244
vendor/github.com/dghubble/oauth1/auther_test.go
generated
vendored
244
vendor/github.com/dghubble/oauth1/auther_test.go
generated
vendored
@@ -1,244 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommonOAuthParams(t *testing.T) {
|
||||
config := &Config{ConsumerKey: "some_consumer_key"}
|
||||
auther := &auther{config, &fixedClock{time.Unix(50037133, 0)}, &fixedNoncer{"some_nonce"}}
|
||||
expectedParams := map[string]string{
|
||||
"oauth_consumer_key": "some_consumer_key",
|
||||
"oauth_signature_method": "HMAC-SHA1",
|
||||
"oauth_timestamp": "50037133",
|
||||
"oauth_nonce": "some_nonce",
|
||||
"oauth_version": "1.0",
|
||||
}
|
||||
assert.Equal(t, expectedParams, auther.commonOAuthParams())
|
||||
}
|
||||
|
||||
func TestNonce(t *testing.T) {
|
||||
auther := &auther{}
|
||||
nonce := auther.nonce()
|
||||
// assert that 32 bytes (256 bites) become 44 bytes since a base64 byte
|
||||
// zeros the 2 high bits. 3 bytes convert to 4 base64 bytes, 40 base64 bytes
|
||||
// represent the first 30 of 32 bytes, = padding adds another 4 byte group.
|
||||
// base64 bytes = 4 * floor(bytes/3) + 4
|
||||
assert.Equal(t, 44, len([]byte(nonce)))
|
||||
}
|
||||
|
||||
func TestEpoch(t *testing.T) {
|
||||
a := &auther{}
|
||||
// assert that a real time is used by default
|
||||
assert.InEpsilon(t, time.Now().Unix(), a.epoch(), 1)
|
||||
// assert that the fixed clock can be used for testing
|
||||
a = &auther{clock: &fixedClock{time.Unix(50037133, 0)}}
|
||||
assert.Equal(t, int64(50037133), a.epoch())
|
||||
}
|
||||
|
||||
func TestSigner_Default(t *testing.T) {
|
||||
config := &Config{ConsumerSecret: "consumer_secret"}
|
||||
a := newAuther(config)
|
||||
// echo -n "hello world" | openssl dgst -sha1 -hmac "consumer_secret&token_secret" -binary | base64
|
||||
expectedSignature := "BE0uILOruKfSXd4UzYlLJDfOq08="
|
||||
// assert that the default signer produces the expected HMAC-SHA1 digest
|
||||
method := a.signer().Name()
|
||||
digest, err := a.signer().Sign("token_secret", "hello world")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "HMAC-SHA1", method)
|
||||
assert.Equal(t, expectedSignature, digest)
|
||||
}
|
||||
|
||||
type identitySigner struct{}
|
||||
|
||||
func (s *identitySigner) Name() string {
|
||||
return "identity"
|
||||
}
|
||||
|
||||
func (s *identitySigner) Sign(tokenSecret, message string) (string, error) {
|
||||
return message, nil
|
||||
}
|
||||
|
||||
func TestSigner_Custom(t *testing.T) {
|
||||
config := &Config{
|
||||
ConsumerSecret: "consumer_secret",
|
||||
Signer: &identitySigner{},
|
||||
}
|
||||
a := newAuther(config)
|
||||
// assert that the custom signer is used
|
||||
method := a.signer().Name()
|
||||
digest, err := a.signer().Sign("secret", "hello world")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "identity", method)
|
||||
assert.Equal(t, "hello world", digest)
|
||||
}
|
||||
|
||||
func TestAuthHeaderValue(t *testing.T) {
|
||||
cases := []struct {
|
||||
params map[string]string
|
||||
authHeader string
|
||||
}{
|
||||
{map[string]string{}, "OAuth "},
|
||||
{map[string]string{"a": "b"}, `OAuth a="b"`},
|
||||
{map[string]string{"a": "b", "c": "d", "e": "f", "1": "2"}, `OAuth 1="2", a="b", c="d", e="f"`},
|
||||
{map[string]string{"/= +doencode": "/= +doencode"}, `OAuth %2F%3D%20%2Bdoencode="%2F%3D%20%2Bdoencode"`},
|
||||
{map[string]string{"-._~dontencode": "-._~dontencode"}, `OAuth -._~dontencode="-._~dontencode"`},
|
||||
}
|
||||
for _, c := range cases {
|
||||
assert.Equal(t, c.authHeader, authHeaderValue(c.params))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeParameters(t *testing.T) {
|
||||
input := map[string]string{
|
||||
"a": "Dogs, Cats & Mice",
|
||||
"☃": "snowman",
|
||||
"ル": "ル",
|
||||
}
|
||||
expected := map[string]string{
|
||||
"a": "Dogs%2C%20Cats%20%26%20Mice",
|
||||
"%E2%98%83": "snowman",
|
||||
"%E3%83%AB": "%E3%83%AB",
|
||||
}
|
||||
assert.Equal(t, expected, encodeParameters(input))
|
||||
}
|
||||
|
||||
func TestSortParameters(t *testing.T) {
|
||||
input := map[string]string{
|
||||
".": "ape",
|
||||
"5.6": "bat",
|
||||
"rsa": "cat",
|
||||
"%20": "dog",
|
||||
"%E3%83%AB": "eel",
|
||||
"dup": "fox",
|
||||
//"dup": "fix", // duplicate keys not supported
|
||||
}
|
||||
expected := []string{
|
||||
"%20=dog",
|
||||
"%E3%83%AB=eel",
|
||||
".=ape",
|
||||
"5.6=bat",
|
||||
"dup=fox",
|
||||
"rsa=cat",
|
||||
}
|
||||
assert.Equal(t, expected, sortParameters(input, "%s=%s"))
|
||||
}
|
||||
|
||||
func TestCollectParameters(t *testing.T) {
|
||||
// example from RFC 5849 3.4.1.3.1
|
||||
oauthParams := map[string]string{
|
||||
"oauth_token": "kkk9d7dh3k39sjv7",
|
||||
"oauth_consumer_key": "9djdj82h48djs9d2",
|
||||
"oauth_signature_method": "HMAC-SHA1",
|
||||
"oauth_timestamp": "137131201",
|
||||
"oauth_nonce": "7d8f3e4a",
|
||||
}
|
||||
values := url.Values{}
|
||||
values.Add("c2", "")
|
||||
values.Add("plus", "2 q") // duplicate keys not supported, a3 -> plus
|
||||
req, err := http.NewRequest("POST", "/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b", strings.NewReader(values.Encode()))
|
||||
assert.Nil(t, err)
|
||||
req.Header.Set(contentType, formContentType)
|
||||
params, err := collectParameters(req, oauthParams)
|
||||
// assert parameters were collected from oauthParams, the query, and form body
|
||||
expected := map[string]string{
|
||||
"b5": "=%3D",
|
||||
"a3": "a",
|
||||
"c@": "",
|
||||
"a2": "r b",
|
||||
"oauth_token": "kkk9d7dh3k39sjv7",
|
||||
"oauth_consumer_key": "9djdj82h48djs9d2",
|
||||
"oauth_signature_method": "HMAC-SHA1",
|
||||
"oauth_timestamp": "137131201",
|
||||
"oauth_nonce": "7d8f3e4a",
|
||||
"c2": "",
|
||||
"plus": "2 q",
|
||||
}
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expected, params)
|
||||
// RFC 5849 3.4.1.3.1 requires a {"a3"="2 q"} be form encoded to "a3=2+q" in
|
||||
// the application/x-www-form-urlencoded body. The parameter "2+q" should be
|
||||
// read as "2 q" and percent encoded to "2%20q".
|
||||
// In Go, data is form encoded by calling Encode on url.Values{} (URL
|
||||
// encoding) and decoded with url.ParseQuery to url.Values. So the encoding
|
||||
// of "2 q" to "2+q" and decoding back to "2 q" is handled and then params
|
||||
// are percent encoded.
|
||||
// http://golang.org/src/net/http/client.go#L496
|
||||
// http://golang.org/src/net/http/request.go#L837
|
||||
}
|
||||
|
||||
func TestSignatureBase(t *testing.T) {
|
||||
reqA, err := http.NewRequest("get", "HTTPS://HELLO.IO?q=test", nil)
|
||||
assert.Nil(t, err)
|
||||
reqB, err := http.NewRequest("POST", "http://hello.io:8080", nil)
|
||||
assert.Nil(t, err)
|
||||
cases := []struct {
|
||||
req *http.Request
|
||||
params map[string]string
|
||||
signatureBase string
|
||||
}{
|
||||
{reqA, map[string]string{"a": "b", "c": "d"}, "GET&https%3A%2F%2Fhello.io&a%3Db%26c%3Dd"},
|
||||
{reqB, map[string]string{"a": "b"}, "POST&http%3A%2F%2Fhello.io%3A8080&a%3Db"},
|
||||
}
|
||||
// assert that method is uppercased, base uri rules applied, queries added, joined by &
|
||||
for _, c := range cases {
|
||||
base := signatureBase(c.req, c.params)
|
||||
assert.Equal(t, c.signatureBase, base)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseURI(t *testing.T) {
|
||||
reqA, err := http.NewRequest("GET", "HTTP://EXAMPLE.COM:80/r%20v/X?id=123", nil)
|
||||
assert.Nil(t, err)
|
||||
reqB, err := http.NewRequest("POST", "https://www.example.net:8080/?q=1", nil)
|
||||
assert.Nil(t, err)
|
||||
reqC, err := http.NewRequest("POST", "https://example.com:443", nil)
|
||||
cases := []struct {
|
||||
req *http.Request
|
||||
baseURI string
|
||||
}{
|
||||
{reqA, "http://example.com/r%20v/X"},
|
||||
{reqB, "https://www.example.net:8080/"},
|
||||
{reqC, "https://example.com"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
baseURI := baseURI(c.req)
|
||||
assert.Equal(t, c.baseURI, baseURI)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizedParameterString(t *testing.T) {
|
||||
simple := map[string]string{
|
||||
"a": "b & c",
|
||||
"☃": "snowman",
|
||||
}
|
||||
rfcExample := map[string]string{
|
||||
"b5": "=%3D",
|
||||
"a3": "a",
|
||||
"c@": "",
|
||||
"a2": "r b",
|
||||
"oauth_token": "kkk9d7dh3k39sjv7",
|
||||
"oauth_consumer_key": "9djdj82h48djs9d2",
|
||||
"oauth_signature_method": "HMAC-SHA1",
|
||||
"oauth_timestamp": "137131201",
|
||||
"oauth_nonce": "7d8f3e4a",
|
||||
"c2": "",
|
||||
"plus": "2 q",
|
||||
}
|
||||
cases := []struct {
|
||||
params map[string]string
|
||||
parameterStr string
|
||||
}{
|
||||
{simple, "%E2%98%83=snowman&a=b%20%26%20c"},
|
||||
{rfcExample, "a2=r%20b&a3=a&b5=%3D%253D&c%40=&c2=&oauth_consumer_key=9djdj82h48djs9d2&oauth_nonce=7d8f3e4a&oauth_signature_method=HMAC-SHA1&oauth_timestamp=137131201&oauth_token=kkk9d7dh3k39sjv7&plus=2%20q"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
assert.Equal(t, c.parameterStr, normalizedParameterString(c.params))
|
||||
}
|
||||
}
|
||||
172
vendor/github.com/dghubble/oauth1/config.go
generated
vendored
172
vendor/github.com/dghubble/oauth1/config.go
generated
vendored
@@ -1,172 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
oauthTokenSecretParam = "oauth_token_secret"
|
||||
oauthCallbackConfirmedParam = "oauth_callback_confirmed"
|
||||
)
|
||||
|
||||
// Config represents an OAuth1 consumer's (client's) key and secret, the
|
||||
// callback URL, and the provider Endpoint to which the consumer corresponds.
|
||||
type Config struct {
|
||||
// Consumer Key (Client Identifier)
|
||||
ConsumerKey string
|
||||
// Consumer Secret (Client Shared-Secret)
|
||||
ConsumerSecret string
|
||||
// Callback URL
|
||||
CallbackURL string
|
||||
// Provider Endpoint specifying OAuth1 endpoint URLs
|
||||
Endpoint Endpoint
|
||||
// OAuth1 Signer (defaults to HMAC-SHA1)
|
||||
Signer Signer
|
||||
}
|
||||
|
||||
// NewConfig returns a new Config with the given consumer key and secret.
|
||||
func NewConfig(consumerKey, consumerSecret string) *Config {
|
||||
return &Config{
|
||||
ConsumerKey: consumerKey,
|
||||
ConsumerSecret: consumerSecret,
|
||||
}
|
||||
}
|
||||
|
||||
// Client returns an HTTP client which uses the provided ctx and access Token.
|
||||
func (c *Config) Client(ctx context.Context, t *Token) *http.Client {
|
||||
return NewClient(ctx, c, t)
|
||||
}
|
||||
|
||||
// NewClient returns a new http Client which signs requests via OAuth1.
|
||||
func NewClient(ctx context.Context, config *Config, token *Token) *http.Client {
|
||||
transport := &Transport{
|
||||
Base: contextTransport(ctx),
|
||||
source: StaticTokenSource(token),
|
||||
auther: newAuther(config),
|
||||
}
|
||||
return &http.Client{Transport: transport}
|
||||
}
|
||||
|
||||
// RequestToken obtains a Request token and secret (temporary credential) by
|
||||
// POSTing a request (with oauth_callback in the auth header) to the Endpoint
|
||||
// RequestTokenURL. The response body form is validated to ensure
|
||||
// oauth_callback_confirmed is true. Returns the request token and secret
|
||||
// (temporary credentials).
|
||||
// See RFC 5849 2.1 Temporary Credentials.
|
||||
func (c *Config) RequestToken() (requestToken, requestSecret string, err error) {
|
||||
req, err := http.NewRequest("POST", c.Endpoint.RequestTokenURL, nil)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
err = newAuther(c).setRequestTokenAuthHeader(req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
// when err is nil, resp contains a non-nil resp.Body which must be closed
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
||||
return "", "", fmt.Errorf("oauth1: Server returned status %d", resp.StatusCode)
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
// ParseQuery to decode URL-encoded application/x-www-form-urlencoded body
|
||||
values, err := url.ParseQuery(string(body))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
requestToken = values.Get(oauthTokenParam)
|
||||
requestSecret = values.Get(oauthTokenSecretParam)
|
||||
if requestToken == "" || requestSecret == "" {
|
||||
return "", "", errors.New("oauth1: Response missing oauth_token or oauth_token_secret")
|
||||
}
|
||||
if values.Get(oauthCallbackConfirmedParam) != "true" {
|
||||
return "", "", errors.New("oauth1: oauth_callback_confirmed was not true")
|
||||
}
|
||||
return requestToken, requestSecret, nil
|
||||
}
|
||||
|
||||
// AuthorizationURL accepts a request token and returns the *url.URL to the
|
||||
// Endpoint's authorization page that asks the user (resource owner) for to
|
||||
// authorize the consumer to act on his/her/its behalf.
|
||||
// See RFC 5849 2.2 Resource Owner Authorization.
|
||||
func (c *Config) AuthorizationURL(requestToken string) (*url.URL, error) {
|
||||
authorizationURL, err := url.Parse(c.Endpoint.AuthorizeURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values := authorizationURL.Query()
|
||||
values.Add(oauthTokenParam, requestToken)
|
||||
authorizationURL.RawQuery = values.Encode()
|
||||
return authorizationURL, nil
|
||||
}
|
||||
|
||||
// ParseAuthorizationCallback parses an OAuth1 authorization callback request
|
||||
// from a provider server. The oauth_token and oauth_verifier parameters are
|
||||
// parsed to return the request token from earlier in the flow and the
|
||||
// verifier string.
|
||||
// See RFC 5849 2.2 Resource Owner Authorization.
|
||||
func ParseAuthorizationCallback(req *http.Request) (requestToken, verifier string, err error) {
|
||||
// parse the raw query from the URL into req.Form
|
||||
err = req.ParseForm()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
requestToken = req.Form.Get(oauthTokenParam)
|
||||
verifier = req.Form.Get(oauthVerifierParam)
|
||||
if requestToken == "" || verifier == "" {
|
||||
return "", "", errors.New("oauth1: Request missing oauth_token or oauth_verifier")
|
||||
}
|
||||
return requestToken, verifier, nil
|
||||
}
|
||||
|
||||
// AccessToken obtains an access token (token credential) by POSTing a
|
||||
// request (with oauth_token and oauth_verifier in the auth header) to the
|
||||
// Endpoint AccessTokenURL. Returns the access token and secret (token
|
||||
// credentials).
|
||||
// See RFC 5849 2.3 Token Credentials.
|
||||
func (c *Config) AccessToken(requestToken, requestSecret, verifier string) (accessToken, accessSecret string, err error) {
|
||||
req, err := http.NewRequest("POST", c.Endpoint.AccessTokenURL, nil)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
err = newAuther(c).setAccessTokenAuthHeader(req, requestToken, requestSecret, verifier)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
// when err is nil, resp contains a non-nil resp.Body which must be closed
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
||||
return "", "", fmt.Errorf("oauth1: Server returned status %d", resp.StatusCode)
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
// ParseQuery to decode URL-encoded application/x-www-form-urlencoded body
|
||||
values, err := url.ParseQuery(string(body))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
accessToken = values.Get(oauthTokenParam)
|
||||
accessSecret = values.Get(oauthTokenSecretParam)
|
||||
if accessToken == "" || accessSecret == "" {
|
||||
return "", "", errors.New("oauth1: Response missing oauth_token or oauth_token_secret")
|
||||
}
|
||||
return accessToken, accessSecret, nil
|
||||
}
|
||||
346
vendor/github.com/dghubble/oauth1/config_test.go
generated
vendored
346
vendor/github.com/dghubble/oauth1/config_test.go
generated
vendored
@@ -1,346 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const expectedVerifier = "some_verifier"
|
||||
|
||||
func TestNewConfig(t *testing.T) {
|
||||
expectedConsumerKey := "consumer_key"
|
||||
expectedConsumerSecret := "consumer_secret"
|
||||
config := NewConfig(expectedConsumerKey, expectedConsumerSecret)
|
||||
assert.Equal(t, expectedConsumerKey, config.ConsumerKey)
|
||||
assert.Equal(t, expectedConsumerSecret, config.ConsumerSecret)
|
||||
}
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
expectedToken := "access_token"
|
||||
expectedConsumerKey := "consumer_key"
|
||||
config := NewConfig(expectedConsumerKey, "consumer_secret")
|
||||
token := NewToken(expectedToken, "access_secret")
|
||||
client := config.Client(NoContext, token)
|
||||
|
||||
server := newMockServer(func(w http.ResponseWriter, req *http.Request) {
|
||||
assert.Equal(t, "GET", req.Method)
|
||||
params := parseOAuthParamsOrFail(t, req.Header.Get(authorizationHeaderParam))
|
||||
assert.Equal(t, expectedToken, params[oauthTokenParam])
|
||||
assert.Equal(t, expectedConsumerKey, params[oauthConsumerKeyParam])
|
||||
})
|
||||
defer server.Close()
|
||||
client.Get(server.URL)
|
||||
}
|
||||
|
||||
func TestNewClient_DefaultTransport(t *testing.T) {
|
||||
client := NewClient(NoContext, NewConfig("t", "s"), NewToken("t", "s"))
|
||||
// assert that the client uses the DefaultTransport
|
||||
transport, ok := client.Transport.(*Transport)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, http.DefaultTransport, transport.base())
|
||||
}
|
||||
|
||||
func TestNewClient_ContextClientTransport(t *testing.T) {
|
||||
baseTransport := &http.Transport{}
|
||||
baseClient := &http.Client{Transport: baseTransport}
|
||||
ctx := context.WithValue(NoContext, HTTPClient, baseClient)
|
||||
client := NewClient(ctx, NewConfig("t", "s"), NewToken("t", "s"))
|
||||
// assert that the client uses the ctx client's Transport as its base RoundTripper
|
||||
transport, ok := client.Transport.(*Transport)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, baseTransport, transport.base())
|
||||
}
|
||||
|
||||
// newRequestTokenServer returns a new httptest.Server for an OAuth1 provider
|
||||
// request token endpoint.
|
||||
func newRequestTokenServer(t *testing.T, data url.Values) *httptest.Server {
|
||||
return newMockServer(func(w http.ResponseWriter, req *http.Request) {
|
||||
assert.Equal(t, "POST", req.Method)
|
||||
assert.NotEmpty(t, req.Header.Get("Authorization"))
|
||||
w.Header().Set(contentType, formContentType)
|
||||
w.Write([]byte(data.Encode()))
|
||||
})
|
||||
}
|
||||
|
||||
// newAccessTokenServer returns a new httptest.Server for an OAuth1 provider
|
||||
// access token endpoint.
|
||||
func newAccessTokenServer(t *testing.T, data url.Values) *httptest.Server {
|
||||
return newMockServer(func(w http.ResponseWriter, req *http.Request) {
|
||||
assert.Equal(t, "POST", req.Method)
|
||||
assert.NotEmpty(t, req.Header.Get("Authorization"))
|
||||
params := parseOAuthParamsOrFail(t, req.Header.Get(authorizationHeaderParam))
|
||||
assert.Equal(t, expectedVerifier, params[oauthVerifierParam])
|
||||
w.Header().Set(contentType, formContentType)
|
||||
w.Write([]byte(data.Encode()))
|
||||
})
|
||||
}
|
||||
|
||||
// newUnparseableBodyServer returns a new httptest.Server which writes
|
||||
// responses with bodies that error when parsed by url.ParseQuery.
|
||||
func newUnparseableBodyServer() *httptest.Server {
|
||||
return newMockServer(func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set(contentType, formContentType)
|
||||
// url.ParseQuery will error, https://golang.org/src/net/url/url_test.go#L1107
|
||||
w.Write([]byte("%gh&%ij"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestConfigRequestToken(t *testing.T) {
|
||||
expectedToken := "reqest_token"
|
||||
expectedSecret := "request_secret"
|
||||
data := url.Values{}
|
||||
data.Add("oauth_token", expectedToken)
|
||||
data.Add("oauth_token_secret", expectedSecret)
|
||||
data.Add("oauth_callback_confirmed", "true")
|
||||
server := newRequestTokenServer(t, data)
|
||||
defer server.Close()
|
||||
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
RequestTokenURL: server.URL,
|
||||
},
|
||||
}
|
||||
requestToken, requestSecret, err := config.RequestToken()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expectedToken, requestToken)
|
||||
assert.Equal(t, expectedSecret, requestSecret)
|
||||
}
|
||||
|
||||
func TestConfigRequestToken_InvalidRequestTokenURL(t *testing.T) {
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
RequestTokenURL: "http://wrong.com/oauth/request_token",
|
||||
},
|
||||
}
|
||||
requestToken, requestSecret, err := config.RequestToken()
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "", requestToken)
|
||||
assert.Equal(t, "", requestSecret)
|
||||
}
|
||||
|
||||
func TestConfigRequestToken_CallbackNotConfirmed(t *testing.T) {
|
||||
const expectedToken = "reqest_token"
|
||||
const expectedSecret = "request_secret"
|
||||
data := url.Values{}
|
||||
data.Add("oauth_token", expectedToken)
|
||||
data.Add("oauth_token_secret", expectedSecret)
|
||||
data.Add("oauth_callback_confirmed", "false")
|
||||
server := newRequestTokenServer(t, data)
|
||||
defer server.Close()
|
||||
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
RequestTokenURL: server.URL,
|
||||
},
|
||||
}
|
||||
requestToken, requestSecret, err := config.RequestToken()
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, "oauth1: oauth_callback_confirmed was not true", err.Error())
|
||||
}
|
||||
assert.Equal(t, "", requestToken)
|
||||
assert.Equal(t, "", requestSecret)
|
||||
}
|
||||
|
||||
func TestConfigRequestToken_CannotParseBody(t *testing.T) {
|
||||
server := newUnparseableBodyServer()
|
||||
defer server.Close()
|
||||
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
RequestTokenURL: server.URL,
|
||||
},
|
||||
}
|
||||
requestToken, requestSecret, err := config.RequestToken()
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "invalid URL escape")
|
||||
}
|
||||
assert.Equal(t, "", requestToken)
|
||||
assert.Equal(t, "", requestSecret)
|
||||
}
|
||||
|
||||
func TestConfigRequestToken_MissingTokenOrSecret(t *testing.T) {
|
||||
data := url.Values{}
|
||||
data.Add("oauth_token", "any_token")
|
||||
data.Add("oauth_callback_confirmed", "true")
|
||||
server := newRequestTokenServer(t, data)
|
||||
defer server.Close()
|
||||
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
RequestTokenURL: server.URL,
|
||||
},
|
||||
}
|
||||
requestToken, requestSecret, err := config.RequestToken()
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, "oauth1: Response missing oauth_token or oauth_token_secret", err.Error())
|
||||
}
|
||||
assert.Equal(t, "", requestToken)
|
||||
assert.Equal(t, "", requestSecret)
|
||||
}
|
||||
|
||||
func TestAuthorizationURL(t *testing.T) {
|
||||
expectedURL := "https://api.example.com/oauth/authorize?oauth_token=a%2Frequest_token"
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
AuthorizeURL: "https://api.example.com/oauth/authorize",
|
||||
},
|
||||
}
|
||||
url, err := config.AuthorizationURL("a/request_token")
|
||||
assert.Nil(t, err)
|
||||
if assert.NotNil(t, url) {
|
||||
assert.Equal(t, expectedURL, url.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthorizationURL_CannotParseAuthorizeURL(t *testing.T) {
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
AuthorizeURL: "%gh&%ij",
|
||||
},
|
||||
}
|
||||
url, err := config.AuthorizationURL("any_request_token")
|
||||
assert.Nil(t, url)
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "parse")
|
||||
assert.Contains(t, err.Error(), "invalid URL")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigAccessToken(t *testing.T) {
|
||||
expectedToken := "access_token"
|
||||
expectedSecret := "access_secret"
|
||||
data := url.Values{}
|
||||
data.Add("oauth_token", expectedToken)
|
||||
data.Add("oauth_token_secret", expectedSecret)
|
||||
server := newAccessTokenServer(t, data)
|
||||
defer server.Close()
|
||||
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
AccessTokenURL: server.URL,
|
||||
},
|
||||
}
|
||||
accessToken, accessSecret, err := config.AccessToken("request_token", "request_secret", expectedVerifier)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expectedToken, accessToken)
|
||||
assert.Equal(t, expectedSecret, accessSecret)
|
||||
}
|
||||
|
||||
func TestConfigAccessToken_InvalidAccessTokenURL(t *testing.T) {
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
AccessTokenURL: "http://wrong.com/oauth/access_token",
|
||||
},
|
||||
}
|
||||
accessToken, accessSecret, err := config.AccessToken("any_token", "any_secret", "any_verifier")
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "", accessToken)
|
||||
assert.Equal(t, "", accessSecret)
|
||||
}
|
||||
|
||||
func TestConfigAccessToken_CannotParseBody(t *testing.T) {
|
||||
server := newUnparseableBodyServer()
|
||||
defer server.Close()
|
||||
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
AccessTokenURL: server.URL,
|
||||
},
|
||||
}
|
||||
accessToken, accessSecret, err := config.AccessToken("any_token", "any_secret", "any_verifier")
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "invalid URL escape")
|
||||
}
|
||||
assert.Equal(t, "", accessToken)
|
||||
assert.Equal(t, "", accessSecret)
|
||||
}
|
||||
|
||||
func TestConfigAccessToken_MissingTokenOrSecret(t *testing.T) {
|
||||
data := url.Values{}
|
||||
data.Add("oauth_token", "any_token")
|
||||
server := newAccessTokenServer(t, data)
|
||||
defer server.Close()
|
||||
|
||||
config := &Config{
|
||||
Endpoint: Endpoint{
|
||||
AccessTokenURL: server.URL,
|
||||
},
|
||||
}
|
||||
accessToken, accessSecret, err := config.AccessToken("request_token", "request_secret", expectedVerifier)
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, "oauth1: Response missing oauth_token or oauth_token_secret", err.Error())
|
||||
}
|
||||
assert.Equal(t, "", accessToken)
|
||||
assert.Equal(t, "", accessSecret)
|
||||
}
|
||||
|
||||
func TestParseAuthorizationCallback_GET(t *testing.T) {
|
||||
expectedToken := "token"
|
||||
expectedVerifier := "verifier"
|
||||
server := newMockServer(func(w http.ResponseWriter, req *http.Request) {
|
||||
assert.Equal(t, "GET", req.Method)
|
||||
// logic under test
|
||||
requestToken, verifier, err := ParseAuthorizationCallback(req)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expectedToken, requestToken)
|
||||
assert.Equal(t, expectedVerifier, verifier)
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
// OAuth1 provider calls callback url
|
||||
url, err := url.Parse(server.URL)
|
||||
assert.Nil(t, err)
|
||||
query := url.Query()
|
||||
query.Add("oauth_token", expectedToken)
|
||||
query.Add("oauth_verifier", expectedVerifier)
|
||||
url.RawQuery = query.Encode()
|
||||
http.Get(url.String())
|
||||
}
|
||||
|
||||
func TestParseAuthorizationCallback_POST(t *testing.T) {
|
||||
expectedToken := "token"
|
||||
expectedVerifier := "verifier"
|
||||
server := newMockServer(func(w http.ResponseWriter, req *http.Request) {
|
||||
assert.Equal(t, "POST", req.Method)
|
||||
// logic under test
|
||||
requestToken, verifier, err := ParseAuthorizationCallback(req)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, expectedToken, requestToken)
|
||||
assert.Equal(t, expectedVerifier, verifier)
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
// OAuth1 provider calls callback url
|
||||
form := url.Values{}
|
||||
form.Add("oauth_token", expectedToken)
|
||||
form.Add("oauth_verifier", expectedVerifier)
|
||||
http.PostForm(server.URL, form)
|
||||
}
|
||||
|
||||
func TestParseAuthorizationCallback_MissingTokenOrVerifier(t *testing.T) {
|
||||
server := newMockServer(func(w http.ResponseWriter, req *http.Request) {
|
||||
assert.Equal(t, "GET", req.Method)
|
||||
// logic under test
|
||||
requestToken, verifier, err := ParseAuthorizationCallback(req)
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, "oauth1: Request missing oauth_token or oauth_verifier", err.Error())
|
||||
}
|
||||
assert.Equal(t, "", requestToken)
|
||||
assert.Equal(t, "", verifier)
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
// OAuth1 provider calls callback url
|
||||
url, err := url.Parse(server.URL)
|
||||
assert.Nil(t, err)
|
||||
query := url.Query()
|
||||
query.Add("oauth_token", "any_token")
|
||||
query.Add("oauth_verifier", "") // missing oauth_verifier
|
||||
url.RawQuery = query.Encode()
|
||||
http.Get(url.String())
|
||||
}
|
||||
24
vendor/github.com/dghubble/oauth1/context.go
generated
vendored
24
vendor/github.com/dghubble/oauth1/context.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type contextKey struct{}
|
||||
|
||||
// HTTPClient is the context key to associate an *http.Client value with
|
||||
// a context.
|
||||
var HTTPClient contextKey
|
||||
|
||||
// NoContext is the default context to use in most cases.
|
||||
var NoContext = context.TODO()
|
||||
|
||||
// contextTransport gets the Transport from the context client or nil.
|
||||
func contextTransport(ctx context.Context) http.RoundTripper {
|
||||
if client, ok := ctx.Value(HTTPClient).(*http.Client); ok {
|
||||
return client.Transport
|
||||
}
|
||||
return nil
|
||||
}
|
||||
21
vendor/github.com/dghubble/oauth1/context_test.go
generated
vendored
21
vendor/github.com/dghubble/oauth1/context_test.go
generated
vendored
@@ -1,21 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestContextTransport(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Transport: http.DefaultTransport,
|
||||
}
|
||||
ctx := context.WithValue(NoContext, HTTPClient, client)
|
||||
assert.Equal(t, http.DefaultTransport, contextTransport(ctx))
|
||||
}
|
||||
|
||||
func TestContextTransport_NoContextClient(t *testing.T) {
|
||||
assert.Nil(t, contextTransport(NoContext))
|
||||
}
|
||||
97
vendor/github.com/dghubble/oauth1/doc.go
generated
vendored
97
vendor/github.com/dghubble/oauth1/doc.go
generated
vendored
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
Package oauth1 is a Go implementation of the OAuth1 spec RFC 5849.
|
||||
|
||||
It allows end-users to authorize a client (consumer) to access protected
|
||||
resources on their behalf (e.g. login) and allows clients to make signed and
|
||||
authorized requests on behalf of a user (e.g. API calls).
|
||||
|
||||
It takes design cues from golang.org/x/oauth2, providing an http.Client which
|
||||
handles request signing and authorization.
|
||||
|
||||
Usage
|
||||
|
||||
Package oauth1 implements the OAuth1 authorization flow and provides an
|
||||
http.Client which can sign and authorize OAuth1 requests.
|
||||
|
||||
To implement "Login with X", use the https://github.com/dghubble/gologin
|
||||
packages which provide login handlers for OAuth1 and OAuth2 providers.
|
||||
|
||||
To call the Twitter, Digits, or Tumblr OAuth1 APIs, use the higher level Go API
|
||||
clients.
|
||||
|
||||
* https://github.com/dghubble/go-twitter
|
||||
* https://github.com/dghubble/go-digits
|
||||
* https://github.com/benfb/go-tumblr
|
||||
|
||||
Authorization Flow
|
||||
|
||||
Perform the OAuth 1 authorization flow to ask a user to grant an application
|
||||
access to his/her resources via an access token.
|
||||
|
||||
import (
|
||||
"github.com/dghubble/oauth1"
|
||||
"github.com/dghubble/oauth1/twitter""
|
||||
)
|
||||
...
|
||||
|
||||
config := oauth1.Config{
|
||||
ConsumerKey: "consumerKey",
|
||||
ConsumerSecret: "consumerSecret",
|
||||
CallbackURL: "http://mysite.com/oauth/twitter/callback",
|
||||
Endpoint: twitter.AuthorizeEndpoint,
|
||||
}
|
||||
|
||||
1. When a user performs an action (e.g. "Login with X" button calls "/login"
|
||||
route) get an OAuth1 request token (temporary credentials).
|
||||
|
||||
requestToken, requestSecret, err = config.RequestToken()
|
||||
// handle err
|
||||
|
||||
2. Obtain authorization from the user by redirecting them to the OAuth1
|
||||
provider's authorization URL to grant the application access.
|
||||
|
||||
authorizationURL, err := config.AuthorizationURL(requestToken)
|
||||
// handle err
|
||||
http.Redirect(w, req, authorizationURL.String(), htt.StatusFound)
|
||||
|
||||
Receive the callback from the OAuth1 provider in a handler.
|
||||
|
||||
requestToken, verifier, err := oauth1.ParseAuthorizationCallback(req)
|
||||
// handle err
|
||||
|
||||
3. Acquire the access token (token credentials) which can later be used
|
||||
to make requests on behalf of the user.
|
||||
|
||||
accessToken, accessSecret, err := config.AccessToken(requestToken, requestSecret, verifier)
|
||||
// handle error
|
||||
token := oauth1.NewToken(accessToken, accessSecret)
|
||||
|
||||
Check the examples to see this authorization flow in action from the command
|
||||
line, with Twitter PIN-based login and Tumblr login.
|
||||
|
||||
Authorized Requests
|
||||
|
||||
Use an access Token to make authorized requests on behalf of a user.
|
||||
|
||||
import (
|
||||
"github.com/dghubble/oauth1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config := oauth1.NewConfig("consumerKey", "consumerSecret")
|
||||
token := oauth1.NewToken("token", "tokenSecret")
|
||||
|
||||
// httpClient will automatically authorize http.Request's
|
||||
httpClient := config.Client(token)
|
||||
|
||||
// example Twitter API request
|
||||
path := "https://api.twitter.com/1.1/statuses/home_timeline.json?count=2"
|
||||
resp, _ := httpClient.Get(path)
|
||||
defer resp.Body.Close()
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
fmt.Printf("Raw Response Body:\n%v\n", string(body))
|
||||
}
|
||||
|
||||
Check the examples to see Twitter and Tumblr requests in action.
|
||||
*/
|
||||
package oauth1
|
||||
13
vendor/github.com/dghubble/oauth1/dropbox/dropbox.go
generated
vendored
13
vendor/github.com/dghubble/oauth1/dropbox/dropbox.go
generated
vendored
@@ -1,13 +0,0 @@
|
||||
// Package dropbox provides constants for using OAuth1 to access Dropbox.
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"github.com/dghubble/oauth1"
|
||||
)
|
||||
|
||||
// Endpoint is Dropbox's OAuth 1 endpoint.
|
||||
var Endpoint = oauth1.Endpoint{
|
||||
RequestTokenURL: "https://api.dropbox.com/1/oauth/request_token",
|
||||
AuthorizeURL: "https://api.dropbox.com/1/oauth/authorize",
|
||||
AccessTokenURL: "https://api.dropbox.com/1/oauth/access_token",
|
||||
}
|
||||
36
vendor/github.com/dghubble/oauth1/encode.go
generated
vendored
36
vendor/github.com/dghubble/oauth1/encode.go
generated
vendored
@@ -1,36 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// PercentEncode percent encodes a string according to RFC 3986 2.1.
|
||||
func PercentEncode(input string) string {
|
||||
var buf bytes.Buffer
|
||||
for _, b := range []byte(input) {
|
||||
// if in unreserved set
|
||||
if shouldEscape(b) {
|
||||
buf.Write([]byte(fmt.Sprintf("%%%02X", b)))
|
||||
} else {
|
||||
// do not escape, write byte as-is
|
||||
buf.WriteByte(b)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// shouldEscape returns false if the byte is an unreserved character that
|
||||
// should not be escaped and true otherwise, according to RFC 3986 2.1.
|
||||
func shouldEscape(c byte) bool {
|
||||
// RFC3986 2.3 unreserved characters
|
||||
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
|
||||
return false
|
||||
}
|
||||
switch c {
|
||||
case '-', '.', '_', '~':
|
||||
return false
|
||||
}
|
||||
// all other bytes must be escaped
|
||||
return true
|
||||
}
|
||||
27
vendor/github.com/dghubble/oauth1/encode_test.go
generated
vendored
27
vendor/github.com/dghubble/oauth1/encode_test.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPercentEncode(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{" ", "%20"},
|
||||
{"%", "%25"},
|
||||
{"&", "%26"},
|
||||
{"-._", "-._"},
|
||||
{" /=+", "%20%2F%3D%2B"},
|
||||
{"Ladies + Gentlemen", "Ladies%20%2B%20Gentlemen"},
|
||||
{"An encoded string!", "An%20encoded%20string%21"},
|
||||
{"Dogs, Cats & Mice", "Dogs%2C%20Cats%20%26%20Mice"},
|
||||
{"☃", "%E2%98%83"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if output := PercentEncode(c.input); output != c.expected {
|
||||
t.Errorf("expected %s, got %s", c.expected, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/dghubble/oauth1/endpoint.go
generated
vendored
12
vendor/github.com/dghubble/oauth1/endpoint.go
generated
vendored
@@ -1,12 +0,0 @@
|
||||
package oauth1
|
||||
|
||||
// Endpoint represents an OAuth1 provider's (server's) request token,
|
||||
// owner authorization, and access token request URLs.
|
||||
type Endpoint struct {
|
||||
// Request URL (Temporary Credential Request URI)
|
||||
RequestTokenURL string
|
||||
// Authorize URL (Resource Owner Authorization URI)
|
||||
AuthorizeURL string
|
||||
// Access Token URL (Token Request URI)
|
||||
AccessTokenURL string
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user