From ea65db42eac44aa614a962a2af0497b00e368b44 Mon Sep 17 00:00:00 2001 From: Peter Rosser Date: Sat, 18 Feb 2017 08:12:18 +0000 Subject: [PATCH 1/7] Add function for reverse geocode lookup https://dev.twitter.com/rest/reference/get/geo/reverse_geocode --- reverse_geocode.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 reverse_geocode.go diff --git a/reverse_geocode.go b/reverse_geocode.go new file mode 100644 index 0000000..c58a303 --- /dev/null +++ b/reverse_geocode.go @@ -0,0 +1,58 @@ +package anaconda + +import "net/url" + +type GeoReverseSearchResult struct { + Result struct { + Places []struct { + ID string `json:"id"` + URL string `json:"url"` + PlaceType string `json:"place_type"` + Name string `json:"name"` + FullName string `json:"full_name"` + CountryCode string `json:"country_code"` + Country string `json:"country"` + ContainedWithin []struct { + ID string `json:"id"` + URL string `json:"url"` + PlaceType string `json:"place_type"` + Name string `json:"name"` + FullName string `json:"full_name"` + CountryCode string `json:"country_code"` + Country string `json:"country"` + Centroid []float64 `json:"centroid"` + BoundingBox struct { + Type string `json:"type"` + Coordinates [][][]float64 `json:"coordinates"` + } `json:"bounding_box"` + Attributes struct { + } `json:"attributes"` + } `json:"contained_within"` + Centroid []float64 `json:"centroid"` + BoundingBox struct { + Type string `json:"type"` + Coordinates [][][]float64 `json:"coordinates"` + } `json:"bounding_box"` + Attributes struct { + } `json:"attributes"` + } `json:"places"` + } `json:"result"` + Query struct { + URL string `json:"url"` + Type string `json:"type"` + Params struct { + Accuracy float64 `json:"accuracy"` + Granularity string `json:"granularity"` + Coordinates struct { + Coordinates []float64 `json:"coordinates"` + Type string `json:"type"` + } `json:"coordinates"` + } `json:"params"` + } `json:"query"` +} + +func (a TwitterApi) GetPlaces(v url.Values) (p GeoReverseSearchResult, err error) { + response_ch := make(chan response) + a.queryQueue <- query{a.baseUrl + "/geo/reverse_geocode.json", v, &p, _GET, response_ch} + return p, (<-response_ch).err +} From 5fdfc9fc25230aab1f3f89b82cee36a2e2412c2d Mon Sep 17 00:00:00 2001 From: root Date: Mon, 20 Feb 2017 10:41:28 +0000 Subject: [PATCH 2/7] Remove files with question marks for windows compatibility --- json/statuses/show.json?id=404409873170841600 | 1 - json/statuses/show.json?id=738567564641599489 | 1 - 2 files changed, 2 deletions(-) delete mode 100644 json/statuses/show.json?id=404409873170841600 delete mode 100644 json/statuses/show.json?id=738567564641599489 diff --git a/json/statuses/show.json?id=404409873170841600 b/json/statuses/show.json?id=404409873170841600 deleted file mode 100644 index eb0ead7..0000000 --- a/json/statuses/show.json?id=404409873170841600 +++ /dev/null @@ -1 +0,0 @@ -{"errors":[{"code":144,"message":"No status found with that ID."}]} \ No newline at end of file diff --git a/json/statuses/show.json?id=738567564641599489 b/json/statuses/show.json?id=738567564641599489 deleted file mode 100644 index 5d7eda0..0000000 --- a/json/statuses/show.json?id=738567564641599489 +++ /dev/null @@ -1 +0,0 @@ -{"created_at":"Fri Jun 03 03:06:43 +0000 2016","id":738567564641599489,"id_str":"738567564641599489","text":"Well, this has certainly come a long way! https:\/\/t.co\/QomzRzwcti","truncated":false,"entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[{"url":"https:\/\/t.co\/QomzRzwcti","expanded_url":"https:\/\/twitter.com\/chimeracoder\/status\/284377451625340928","display_url":"twitter.com\/chimeracoder\/s\u2026","indices":[42,65]}]},"source":"\u003ca href=\"http:\/\/twitter.com\" rel=\"nofollow\"\u003eTwitter Web Client\u003c\/a\u003e","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":182675886,"id_str":"182675886","name":"Aditya Mukerjee","screen_name":"chimeracoder","location":"New York, NY","description":"Risk engineer at @stripe. Linux dev, statistician. Writing lots of Go. Alum of @recursecenter, @cornell_tech, @columbia","url":"https:\/\/t.co\/6PwvHXBN5Y","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/6PwvHXBN5Y","expanded_url":"https:\/\/adityamukerjee.net","display_url":"adityamukerjee.net","indices":[0,23]}]},"description":{"urls":[]}},"protected":false,"followers_count":3061,"friends_count":914,"listed_count":172,"created_at":"Wed Aug 25 03:49:41 +0000 2010","favourites_count":5193,"utc_offset":-14400,"time_zone":"Eastern Time (US & Canada)","geo_enabled":false,"verified":false,"statuses_count":9559,"lang":"en","contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"C0DEED","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":false,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1807988313\/230348_1870593437981_1035450059_32104665_3285049_n_cropped_normal.jpg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1807988313\/230348_1870593437981_1035450059_32104665_3285049_n_cropped_normal.jpg","profile_link_color":"0084B4","profile_sidebar_border_color":"C0DEED","profile_sidebar_fill_color":"DDEEF6","profile_text_color":"333333","profile_use_background_image":true,"has_extended_profile":false,"default_profile":true,"default_profile_image":false,"following":false,"follow_request_sent":false,"notifications":false},"geo":null,"coordinates":null,"place":null,"contributors":null,"quoted_status_id":284377451625340928,"quoted_status_id_str":"284377451625340928","quoted_status":{"created_at":"Thu Dec 27 19:17:22 +0000 2012","id":284377451625340928,"id_str":"284377451625340928","text":"Just created gojson - a simple tool for turning JSON data into Go structs! http:\/\/t.co\/QM6k9AUV #golang","truncated":false,"entities":{"hashtags":[{"text":"golang","indices":[96,103]}],"symbols":[],"user_mentions":[],"urls":[{"url":"http:\/\/t.co\/QM6k9AUV","expanded_url":"http:\/\/bit.ly\/UbfXOC","display_url":"bit.ly\/UbfXOC","indices":[75,95]}]},"source":"\u003ca href=\"http:\/\/twitter.com\" rel=\"nofollow\"\u003eTwitter Web Client\u003c\/a\u003e","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":182675886,"id_str":"182675886","name":"Aditya Mukerjee","screen_name":"chimeracoder","location":"New York, NY","description":"Risk engineer at @stripe. Linux dev, statistician. Writing lots of Go. Alum of @recursecenter, @cornell_tech, @columbia","url":"https:\/\/t.co\/6PwvHXBN5Y","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/6PwvHXBN5Y","expanded_url":"https:\/\/adityamukerjee.net","display_url":"adityamukerjee.net","indices":[0,23]}]},"description":{"urls":[]}},"protected":false,"followers_count":3061,"friends_count":914,"listed_count":172,"created_at":"Wed Aug 25 03:49:41 +0000 2010","favourites_count":5193,"utc_offset":-14400,"time_zone":"Eastern Time (US & Canada)","geo_enabled":false,"verified":false,"statuses_count":9559,"lang":"en","contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"C0DEED","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":false,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1807988313\/230348_1870593437981_1035450059_32104665_3285049_n_cropped_normal.jpg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1807988313\/230348_1870593437981_1035450059_32104665_3285049_n_cropped_normal.jpg","profile_link_color":"0084B4","profile_sidebar_border_color":"C0DEED","profile_sidebar_fill_color":"DDEEF6","profile_text_color":"333333","profile_use_background_image":true,"has_extended_profile":false,"default_profile":true,"default_profile_image":false,"following":false,"follow_request_sent":false,"notifications":false},"geo":null,"coordinates":null,"place":null,"contributors":null,"is_quote_status":false,"retweet_count":0,"favorite_count":2,"favorited":false,"retweeted":false,"possibly_sensitive":false,"possibly_sensitive_appealable":false,"lang":"en"},"is_quote_status":true,"retweet_count":0,"favorite_count":1,"favorited":false,"retweeted":false,"possibly_sensitive":false,"possibly_sensitive_appealable":false,"lang":"en"} \ No newline at end of file From 164d406dbee15968ea8d3fb09700927f5ca6a471 Mon Sep 17 00:00:00 2001 From: Peter Rosser Date: Mon, 20 Feb 2017 11:12:42 +0000 Subject: [PATCH 3/7] Add GetRateLimitStatus --- rate_limit_status.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 rate_limit_status.go diff --git a/rate_limit_status.go b/rate_limit_status.go new file mode 100644 index 0000000..bb3c256 --- /dev/null +++ b/rate_limit_status.go @@ -0,0 +1,40 @@ +package anaconda + +import "net/url" +import "fmt" + +type RateLimitSearchResult struct { + RateLimitContext struct { + AccessToken string `json:"access_token"` + } `json:"rate_limit_context"` + Resources struct { + Geo struct { + Similar_places struct { + Limit int `json:"limit"` + Remaining int `json:"remaining"` + Reset int `json:"reset"` + } `json:"/geo/similar_places"` + Place_id struct { + Limit int `json:"limit"` + Remaining int `json:"remaining"` + Reset int `json:"reset"` + } `json:"/geo/id/:place_id"` + Reverse_geocode struct { + Limit int `json:"limit"` + Remaining int `json:"remaining"` + Reset int `json:"reset"` + } `json:"/geo/reverse_geocode"` + Search struct { + Limit int `json:"limit"` + Remaining int `json:"remaining"` + Reset int `json:"reset"` + } `json:"/geo/search"` + } `json:"geo"` + } `json:"resources"` +} + +func (a TwitterApi) GetRateLimitStatus(v url.Values) (r RateLimitSearchResult, err error) { + response_ch := make(chan response) + a.queryQueue <- query{a.baseUrl + "/application/rate_limit_status.json", v, &r, _GET, response_ch} + return r, (<-response_ch).err +} From 31781e94af3f7762c14ab8a024401dc62408bef1 Mon Sep 17 00:00:00 2001 From: Peter Rosser Date: Mon, 20 Feb 2017 11:39:34 +0000 Subject: [PATCH 4/7] Remove unused imports --- rate_limit_status.go | 1 - 1 file changed, 1 deletion(-) diff --git a/rate_limit_status.go b/rate_limit_status.go index bb3c256..b255e4f 100644 --- a/rate_limit_status.go +++ b/rate_limit_status.go @@ -1,7 +1,6 @@ package anaconda import "net/url" -import "fmt" type RateLimitSearchResult struct { RateLimitContext struct { From 32d11ab75903becf4e163d284a4df683b61cf07b Mon Sep 17 00:00:00 2001 From: Peter Rosser Date: Mon, 20 Feb 2017 11:57:05 +0000 Subject: [PATCH 5/7] Add search/tweets --- rate_limit_status.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rate_limit_status.go b/rate_limit_status.go index b255e4f..43f62a6 100644 --- a/rate_limit_status.go +++ b/rate_limit_status.go @@ -29,6 +29,13 @@ type RateLimitSearchResult struct { Reset int `json:"reset"` } `json:"/geo/search"` } `json:"geo"` + Search struct { + Tweets struct { + Limit int `json:"limit"` + Remaining int `json:"remaining"` + Reset int `json:"reset"` + } `json:"/search/tweets"` + } `json:"search"` } `json:"resources"` } From f8c76660026bade4cf2e37c2c99ed0aa4487b824 Mon Sep 17 00:00:00 2001 From: Peter Rosser Date: Mon, 20 Feb 2017 21:18:41 +0000 Subject: [PATCH 6/7] Fix to confirm to naming convention --- reverse_geocode.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reverse_geocode.go b/reverse_geocode.go index c58a303..07adc21 100644 --- a/reverse_geocode.go +++ b/reverse_geocode.go @@ -5,7 +5,7 @@ import "net/url" type GeoReverseSearchResult struct { Result struct { Places []struct { - ID string `json:"id"` + Id string `json:"id"` URL string `json:"url"` PlaceType string `json:"place_type"` Name string `json:"name"` From 4d980089229553087420d6565d8c7e73801b390a Mon Sep 17 00:00:00 2001 From: Peter Rosser Date: Wed, 22 Feb 2017 01:45:02 +0000 Subject: [PATCH 7/7] :new: Add an Oauth2 function to make the most of application only calls. --- twitter.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/twitter.go b/twitter.go index 0cd72ea..51f1b76 100644 --- a/twitter.go +++ b/twitter.go @@ -50,6 +50,8 @@ import ( "github.com/ChimeraCoder/tokenbucket" "github.com/garyburd/go-oauth/oauth" + "golang.org/x/oauth2" + "golang.org/x/oauth2/clientcredentials" ) const ( @@ -121,6 +123,32 @@ func NewTwitterApi(access_token string, access_token_secret string) *TwitterApi return c } +//NewTwitterApi takes an user-specific access token and secret and returns a TwitterApi struct for that user. +//The TwitterApi struct can be used for accessing any of the endpoints available. +func NewTwitterAppApi(consumer_key string, consumer_secret string) *TwitterApi { + //TODO figure out how much to buffer this channel + //A non-buffered channel will cause blocking when multiple queries are made at the same time + + config := &clientcredentials.Config{ClientID: consumer_key, + ClientSecret: consumer_secret, + TokenURL: "https://api.twitter.com/oauth2/token"} + + // OAuth2 http.Client will automatically authorize Requests + httpClient := config.Client(oauth2.NoContext) + + queue := make(chan query) + c := &TwitterApi{ + queryQueue: queue, + bucket: nil, + returnRateLimitError: false, + HttpClient: httpClient, + Log: silentLogger{}, + baseUrl: BaseUrl, + } + go c.throttledQuery() + return c +} + //SetConsumerKey will set the application-specific consumer_key used in the initial OAuth process //This key is listed on https://dev.twitter.com/apps/YOUR_APP_ID/show func SetConsumerKey(consumer_key string) {