package altvr import ( "log" "net/http/cookiejar" "golang.org/x/net/publicsuffix" ) // XXX: Hold a HTTP CONNECT / Keep-Alive so we show up as online // AltVR Client Type type AltVR struct { jar *cookiejar.Jar username string password string csrfToken string // CSRF token for requests userID string // Our own user id user User // Cache of our own user data friends []User friendships []Friendship onlineFriendships []Friendship } // DisconnectFunc handler for disconnection type DisconnectFunc func(User) // ConnectFunc handler for connection type ConnectFunc func(User) // New creates a new instance of the AltVR client // Takes an account username and password as parameters func New(u, p string) AltVR { avr := AltVR{username: u, password: p} var err error avr.jar, err = cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) if err != nil { log.Fatal(err) } err = avr.doLogin() if err != nil { log.Fatal(err) } user, err := avr.fetchMyUser() if err != nil { log.Fatal(err) } avr.user = user if err := avr.FetchFriendships(); err != nil { log.Fatal(err) } return avr } // GetAvatarURL returns the cached user avatar url func (avr *AltVR) GetAvatarURL() string { return avr.user.ProfileImage } // FetchMyUser fetches our own user data and cache it func (avr *AltVR) FetchMyUser() error { user, err := avr.fetchMyUser() if err == errorLogin { log.Println("Not logged in, doing login") err = avr.doLogin() if err != nil { log.Fatal(err) } user, err = avr.fetchMyUser() } if err != nil { return err } avr.user = user return nil } // GetMyUser Returns the cached copy of our user data func (avr *AltVR) GetMyUser() User { return avr.user } // FetchClientIP retrives the client IP from the API func (avr *AltVR) FetchClientIP() (string, error) { return avr.fetchClientIP() } // FetchFriendships fetches all our friends' user data and caches it func (avr *AltVR) FetchFriendships() error { var err error friendships, err := avr.fetchFriendships() if err != nil { return err } for _, friendship := range friendships { found := false for _, ff := range avr.friendships { if friendship.FriendID == ff.FriendID { found = true break } } if !found { if err := avr.FetchFriend(friendship.FriendID); err != nil { log.Printf("Error fetching friend user data: %+v\n", err) } } } avr.friendships = friendships return nil } // GetFriendships returns the cached list of friendships func (avr *AltVR) GetFriendships() []Friendship { return avr.friendships } // FetchOnlineFriendships check for changes in the online friends list // Triggers the callback functions on dis/connect func (avr *AltVR) FetchOnlineFriendships(cfn ConnectFunc, dfn DisconnectFunc) error { friendships, err := avr.fetchFriendshipsOnline() if err != nil { return err } for _, friendship := range friendships { found := false for _, of := range avr.onlineFriendships { if friendship.FriendID == of.FriendID { found = true break } } if !found { if err := avr.FetchFriend(friendship.FriendID); err != nil { return err } cfn(avr.GetFriend(friendship.FriendID)) } } for _, friendship := range avr.onlineFriendships { found := false for _, of := range friendships { if friendship.FriendID == of.FriendID { found = true break } } if !found { if err := avr.FetchFriend(friendship.FriendID); err != nil { return err } dfn(avr.GetFriend(friendship.FriendID)) } } avr.onlineFriendships = friendships return nil } // FetchFriend fetches one user's data and update the cache func (avr *AltVR) FetchFriend(userID string) error { users, err := avr.fetchUsers(userID) if err != nil { return err } user := users[0] found := false for k, u := range avr.friends { if u.UserID == user.UserID { avr.friends[k] = user found = true break } } if !found { avr.friends = append(avr.friends, user) } return nil } // FetchFriends fetches many users' data and update the cache func (avr *AltVR) FetchFriends(userID ...string) error { users, err := avr.fetchUsers(userID...) if err != nil { return err } for _, user := range users { found := false for k, u := range avr.friends { if u.UserID == user.UserID { avr.friends[k] = user found = true break } } if !found { avr.friends = append(avr.friends, user) } } return nil } // GetFriend gets a cached friend user data with the user ID func (avr *AltVR) GetFriend(userID string) User { var user User for _, u := range avr.friends { if u.UserID == userID { user = u break } } return user } // GetFriendByUsername gets a cached friend user data with the username func (avr *AltVR) GetFriendByUsername(username string) User { var user User for _, u := range avr.friends { if u.Username == username { user = u break } } return user } // FetchPendingFriendshipRequests fetches a list of pending friendship requests func (avr *AltVR) FetchPendingFriendshipRequests() ([]Friendship, error) { fr, err := avr.fetchPendingFriendshipRequests() if err != nil { log.Printf("Error fetching pending conversations: %+v\n", err) return fr, err } var uids []string for _, ff := range fr { uids = append(uids, ff.UserID) } avr.FetchFriends(uids...) return fr, nil } // AcceptFriendshipRequest accepts a pending friendship request func (avr *AltVR) AcceptFriendshipRequest(FriendshipID string) error { return avr.acceptPendingFriendshipRequest(FriendshipID) } // DenyFriendshipRequest accepts a pending friendship request func (avr *AltVR) DenyFriendshipRequest(FriendshipID string) error { return avr.denyPendingFriendshipRequest(FriendshipID) } // FetchPendingConversations fetches any pending conversations func (avr *AltVR) FetchPendingConversations() ([]Conversation, error) { pc, err := avr.fetchPendingConversations() if err != nil { log.Printf("Error fetching pending conversations: %+v\n", err) return pc, err } var ccs []Conversation for _, c := range pc { if !c.IsRead { ccs = append(ccs, c) } } return ccs, nil } // AcknowkledgeConversation mark a conversation item as read func (avr *AltVR) AcknowkledgeConversation(conversationID string) error { return avr.markConversationAsRead(conversationID) } // PostNewConversation send a new message func (avr *AltVR) PostNewConversation(userID, message string) error { // XXX: Truncate 140 chars return avr.postNewConversation(userID, message) }