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 }