mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-12 11:15:12 +00:00
174 lines
4.7 KiB
Go
174 lines
4.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/dghubble/go-twitter/twitter"
|
|
"github.com/micro/micro/v3/service/config"
|
|
"github.com/micro/micro/v3/service/errors"
|
|
"github.com/micro/micro/v3/service/logger"
|
|
pb "github.com/micro/services/twitter/proto"
|
|
"golang.org/x/oauth2"
|
|
"golang.org/x/oauth2/clientcredentials"
|
|
)
|
|
|
|
type Twitter struct {
|
|
Client *twitter.Client
|
|
}
|
|
|
|
func New() *Twitter {
|
|
v, err := config.Get("twitter.api_key")
|
|
if err != nil {
|
|
logger.Fatalf("twitter.api_key config not found: %v", err)
|
|
}
|
|
apiKey := v.String("")
|
|
if len(apiKey) == 0 {
|
|
logger.Fatal("twitter.api_key config not found")
|
|
}
|
|
v, err = config.Get("twitter.api_secret")
|
|
if err != nil {
|
|
logger.Fatalf("twitter.api_secret config not found: %v", err)
|
|
}
|
|
apiSecret := v.String("")
|
|
if len(apiSecret) == 0 {
|
|
logger.Fatal("twitter.api_secret config not found")
|
|
}
|
|
|
|
// oauth2 configures a client that uses app credentials to keep a fresh token
|
|
config := &clientcredentials.Config{
|
|
ClientID: apiKey,
|
|
ClientSecret: apiSecret,
|
|
TokenURL: "https://api.twitter.com/oauth2/token",
|
|
}
|
|
// http.Client will automatically authorize Requests
|
|
httpClient := config.Client(oauth2.NoContext)
|
|
|
|
// Twitter client
|
|
client := twitter.NewClient(httpClient)
|
|
|
|
return &Twitter{
|
|
Client: client,
|
|
}
|
|
}
|
|
|
|
func (t *Twitter) Timeline(ctx context.Context, req *pb.TimelineRequest, rsp *pb.TimelineResponse) error {
|
|
if len(req.Username) == 0 {
|
|
return errors.BadRequest("twitter.timeline", "missing username")
|
|
}
|
|
|
|
if req.Limit <= 0 {
|
|
req.Limit = 20
|
|
}
|
|
|
|
tweets, _, err := t.Client.Timelines.UserTimeline(&twitter.UserTimelineParams{
|
|
ScreenName: req.Username,
|
|
Count: int(req.Limit),
|
|
})
|
|
if err != nil {
|
|
logger.Errorf("Failed to retrieve tweets for %v: %v", req.Username, err)
|
|
return errors.InternalServerError("twitter.timeline", "Failed to retrieve tweets for %v: %v", req.Username, err)
|
|
}
|
|
|
|
for _, tweet := range tweets {
|
|
rsp.Tweets = append(rsp.Tweets, &pb.Tweet{
|
|
Id: tweet.ID,
|
|
Text: tweet.Text,
|
|
CreatedAt: tweet.CreatedAt,
|
|
FavouritedCount: int64(tweet.FavoriteCount),
|
|
RetweetedCount: int64(tweet.RetweetCount),
|
|
Username: tweet.User.ScreenName,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *Twitter) Search(ctx context.Context, req *pb.SearchRequest, rsp *pb.SearchResponse) error {
|
|
if len(req.Query) == 0 {
|
|
return errors.BadRequest("twitter.query", "missing query")
|
|
}
|
|
|
|
if req.Limit <= 0 {
|
|
req.Limit = 20
|
|
}
|
|
|
|
searchRsp, _, err := t.Client.Search.Tweets(&twitter.SearchTweetParams{
|
|
Query: req.Query,
|
|
Count: int(req.Limit),
|
|
})
|
|
if err != nil {
|
|
logger.Errorf("Failed to retrieve tweets for %v: %v", req.Query, err)
|
|
return errors.InternalServerError("twitter.search", "Failed to retrieve tweets for %v: %v", req.Query, err)
|
|
}
|
|
|
|
for _, tweet := range searchRsp.Statuses {
|
|
rsp.Tweets = append(rsp.Tweets, &pb.Tweet{
|
|
Id: tweet.ID,
|
|
Text: tweet.Text,
|
|
CreatedAt: tweet.CreatedAt,
|
|
FavouritedCount: int64(tweet.FavoriteCount),
|
|
RetweetedCount: int64(tweet.RetweetCount),
|
|
Username: tweet.User.ScreenName,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *Twitter) User(ctx context.Context, req *pb.UserRequest, rsp *pb.UserResponse) error {
|
|
if len(req.Username) == 0 {
|
|
return errors.BadRequest("twitter.user", "missing username")
|
|
}
|
|
|
|
user, _, err := t.Client.Users.Show(&twitter.UserShowParams{
|
|
ScreenName: req.Username,
|
|
})
|
|
if err != nil {
|
|
logger.Errorf("Failed to retrieve user profile for %v: %v", req.Username, err)
|
|
return errors.InternalServerError("twitter.user", "Failed to retrieve user profile for %v: %v", req.Username, err)
|
|
}
|
|
|
|
rsp.Status = &pb.Tweet{
|
|
Id: user.Status.ID,
|
|
Text: user.Status.Text,
|
|
CreatedAt: user.Status.CreatedAt,
|
|
FavouritedCount: int64(user.Status.FavoriteCount),
|
|
RetweetedCount: int64(user.Status.RetweetCount),
|
|
Username: req.Username,
|
|
}
|
|
|
|
rsp.Profile = &pb.Profile{
|
|
Id: user.ID,
|
|
Name: user.Name,
|
|
Username: user.ScreenName,
|
|
CreatedAt: user.CreatedAt,
|
|
Description: user.Description,
|
|
Followers: int64(user.FollowersCount),
|
|
Private: user.Protected,
|
|
Verified: user.Verified,
|
|
ImageUrl: user.ProfileImageURL,
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *Twitter) Trends(ctx context.Context, req *pb.TrendsRequest, rsp *pb.TrendsResponse) error {
|
|
trendRsp, _, err := t.Client.Trends.Place(1, &twitter.TrendsPlaceParams{WOEID: 1})
|
|
if err != nil {
|
|
logger.Errorf("Failed to retrieve trends: %v", err)
|
|
return errors.InternalServerError("twitter.trends", "Failed to retrieve trends")
|
|
}
|
|
|
|
for _, list := range trendRsp {
|
|
for _, trend := range list.Trends {
|
|
rsp.Trends = append(rsp.Trends, &pb.Trend{
|
|
Name: trend.Name,
|
|
Url: trend.URL,
|
|
TweetVolume: trend.TweetVolume,
|
|
})
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|