REFACTOR: remove DMTrove type, merge it into TweetTrove

This commit is contained in:
Alessio 2024-07-28 08:01:58 -07:00
parent 821d36b116
commit 98015ddf0c
13 changed files with 167 additions and 166 deletions

View File

@ -518,7 +518,7 @@ func start_webserver(addr string, should_auto_open bool) {
func fetch_inbox(how_many int) { func fetch_inbox(how_many int) {
trove, _ := scraper.GetInbox(how_many) trove, _ := scraper.GetInbox(how_many)
profile.SaveDMTrove(trove, true) profile.SaveTweetTrove(trove, true)
happy_exit(fmt.Sprintf("Saved %d messages from %d chats", len(trove.Messages), len(trove.Rooms)), nil) happy_exit(fmt.Sprintf("Saved %d messages from %d chats", len(trove.Messages), len(trove.Rooms)), nil)
} }
@ -529,7 +529,7 @@ func fetch_dm(id string, how_many int) {
} }
max_id := scraper.DMMessageID(^uint(0) >> 1) max_id := scraper.DMMessageID(^uint(0) >> 1)
trove := scraper.GetConversation(room.ID, max_id, how_many) trove := scraper.GetConversation(room.ID, max_id, how_many)
profile.SaveDMTrove(trove, true) profile.SaveTweetTrove(trove, true)
happy_exit( happy_exit(
fmt.Sprintf("Saved %d messages from %d chats", len(trove.Messages), len(trove.Rooms)), fmt.Sprintf("Saved %d messages from %d chats", len(trove.Messages), len(trove.Rooms)),
err, err,
@ -539,10 +539,10 @@ func fetch_dm(id string, how_many int) {
func send_dm(room_id string, text string, in_reply_to_id int) { func send_dm(room_id string, text string, in_reply_to_id int) {
room, err := profile.GetChatRoom(scraper.DMChatRoomID(room_id)) room, err := profile.GetChatRoom(scraper.DMChatRoomID(room_id))
if err != nil { if err != nil {
panic(err) die(fmt.Sprintf("No such chat room: %d", in_reply_to_id), false, 1)
} }
trove := scraper.SendDMMessage(room.ID, text, scraper.DMMessageID(in_reply_to_id)) trove := scraper.SendDMMessage(room.ID, text, scraper.DMMessageID(in_reply_to_id))
profile.SaveDMTrove(trove, true) profile.SaveTweetTrove(trove, true)
happy_exit(fmt.Sprintf("Saved %d messages from %d chats", len(trove.Messages), len(trove.Rooms)), nil) happy_exit(fmt.Sprintf("Saved %d messages from %d chats", len(trove.Messages), len(trove.Rooms)), nil)
} }

View File

@ -60,8 +60,8 @@ func (app *Application) message_send(w http.ResponseWriter, r *http.Request) {
panic_if(json.Unmarshal(body, &message_data)) panic_if(json.Unmarshal(body, &message_data))
trove := scraper.SendDMMessage(room_id, message_data.Text, 0) trove := scraper.SendDMMessage(room_id, message_data.Text, 0)
app.Profile.SaveDMTrove(trove, false) app.Profile.SaveTweetTrove(trove, false)
go app.Profile.SaveDMTrove(trove, true) go app.Profile.SaveTweetTrove(trove, true)
} }
func (app *Application) message_detail(w http.ResponseWriter, r *http.Request) { func (app *Application) message_detail(w http.ResponseWriter, r *http.Request) {
@ -85,8 +85,8 @@ func (app *Application) message_detail(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Has("scrape") && !app.IsScrapingDisabled { if r.URL.Query().Has("scrape") && !app.IsScrapingDisabled {
max_id := scraper.DMMessageID(^uint(0) >> 1) max_id := scraper.DMMessageID(^uint(0) >> 1)
trove := scraper.GetConversation(room_id, max_id, 50) // TODO: parameterizable trove := scraper.GetConversation(room_id, max_id, 50) // TODO: parameterizable
app.Profile.SaveDMTrove(trove, false) app.Profile.SaveTweetTrove(trove, false)
go app.Profile.SaveDMTrove(trove, true) // Download the content in the background go app.Profile.SaveTweetTrove(trove, true) // Download the content in the background
} }
// `LatestPollingTimestamp` sort of passes-through the function; if we're not updating it, it // `LatestPollingTimestamp` sort of passes-through the function; if we're not updating it, it
@ -110,7 +110,7 @@ func (app *Application) message_detail(w http.ResponseWriter, r *http.Request) {
c.UntilTimestamp = scraper.TimestampFromUnixMilli(int64(until_time)) c.UntilTimestamp = scraper.TimestampFromUnixMilli(int64(until_time))
} }
chat_contents := app.Profile.GetChatRoomMessagesByCursor(c) chat_contents := app.Profile.GetChatRoomMessagesByCursor(c)
chat_view_data.DMChatView.MergeWith(chat_contents.DMTrove) chat_view_data.DMChatView.MergeWith(chat_contents.TweetTrove)
chat_view_data.MessageIDs = chat_contents.MessageIDs chat_view_data.MessageIDs = chat_contents.MessageIDs
chat_view_data.Cursor = chat_contents.Cursor chat_view_data.Cursor = chat_contents.Cursor
if len(chat_view_data.MessageIDs) > 0 { if len(chat_view_data.MessageIDs) > 0 {

View File

@ -39,6 +39,12 @@ func (d PageGlobalData) Retweet(id scraper.TweetID) scraper.Retweet {
func (d PageGlobalData) Space(id scraper.SpaceID) scraper.Space { func (d PageGlobalData) Space(id scraper.SpaceID) scraper.Space {
return d.Spaces[id] return d.Spaces[id]
} }
func (d PageGlobalData) Message(id scraper.DMMessageID) scraper.DMMessage {
return d.Messages[id]
}
func (d PageGlobalData) ChatRoom(id scraper.DMChatRoomID) scraper.DMChatRoom {
return d.Rooms[id]
}
func (d PageGlobalData) GetFocusedTweetID() scraper.TweetID { func (d PageGlobalData) GetFocusedTweetID() scraper.TweetID {
return d.FocusedTweetID return d.FocusedTweetID
} }
@ -120,6 +126,8 @@ func (app *Application) make_funcmap(global_data PageGlobalData) template.FuncMa
"user": global_data.User, "user": global_data.User,
"retweet": global_data.Retweet, "retweet": global_data.Retweet,
"space": global_data.Space, "space": global_data.Space,
"dm_message": global_data.Message,
"chat_room": global_data.ChatRoom,
"focused_tweet_id": global_data.GetFocusedTweetID, "focused_tweet_id": global_data.GetFocusedTweetID,
"search_text": global_data.GetSearchText, "search_text": global_data.GetSearchText,
"global_data": global_data.GlobalData, // This fucking sucks "global_data": global_data.GlobalData, // This fucking sucks

View File

@ -102,15 +102,15 @@ func (app *Application) background_dm_polling_scrape() {
} }
fmt.Println("Scraping user DMs...") fmt.Println("Scraping user DMs...")
var trove scraper.DMTrove var trove scraper.TweetTrove
if inbox_cursor == "" { if inbox_cursor == "" {
trove, inbox_cursor = scraper.GetInbox(0) trove, inbox_cursor = scraper.GetInbox(0)
} else { } else {
trove, inbox_cursor = scraper.PollInboxUpdates(inbox_cursor) trove, inbox_cursor = scraper.PollInboxUpdates(inbox_cursor)
} }
fmt.Println("Saving DM results...") fmt.Println("Saving DM results...")
app.Profile.SaveDMTrove(trove, false) app.Profile.SaveTweetTrove(trove, false)
go app.Profile.SaveDMTrove(trove, true) go app.Profile.SaveTweetTrove(trove, true)
fmt.Println("Scraping DMs succeeded.") fmt.Println("Scraping DMs succeeded.")
} }

View File

@ -2,8 +2,7 @@
<div class="chat-list" hx-get="/messages/refresh-list?active-chat={{.ActiveRoomID}}" hx-swap="outerHTML" hx-trigger="load delay:3s"> <div class="chat-list" hx-get="/messages/refresh-list?active-chat={{.ActiveRoomID}}" hx-swap="outerHTML" hx-trigger="load delay:3s">
{{range .RoomIDs}} {{range .RoomIDs}}
{{template "chat-list-entry" (dict {{template "chat-list-entry" (dict
"room" (index $.Rooms .) "room" (chat_room .)
"messages" $.DMTrove.Messages
"is_active" (eq $.ActiveRoomID .) "is_active" (eq $.ActiveRoomID .)
"is_unread" (index $.UnreadRoomIDs .) "is_unread" (index $.UnreadRoomIDs .)
) }} ) }}

View File

@ -18,7 +18,7 @@
</div> </div>
<div class="chat-list-entry__preview-and-unread-container row"> <div class="chat-list-entry__preview-and-unread-container row">
<p class="chat-list-entry__message-preview"> <p class="chat-list-entry__message-preview">
{{ $message := (index $.messages $room.LastMessageID)}} {{ $message := (dm_message $room.LastMessageID)}}
{{ $sender := (user $message.SenderID) }} {{ $sender := (user $message.SenderID) }}
{{if ne $message.Text ""}} {{if ne $message.Text ""}}
{{if eq $room.Type "GROUP_DM"}} {{if eq $room.Type "GROUP_DM"}}

View File

@ -1,38 +1,36 @@
{{define "messages"}} {{define "message"}}
{{range .MessageIDs}} {{$user := (user .SenderID)}}
{{$message := (index $.DMTrove.Messages .)}} {{$is_us := (eq .SenderID (active_user).ID)}}
{{$user := (user $message.SenderID)}} <div class="dm-message {{if $is_us}} our-message {{end}}" data-message-id="{{ .ID }}" hx-ext="json-enc">
{{$is_us := (eq $message.SenderID (active_user).ID)}}
<div class="dm-message {{if $is_us}} our-message {{end}}" data-message-id="{{ $message.ID }}">
<div class="dm-message__row row"> <div class="dm-message__row row">
<div class="dm-message__sender-profile-img"> <div class="dm-message__sender-profile-img">
{{template "circle-profile-img" $user}} {{template "circle-profile-img" $user}}
</div> </div>
<div class="dm-message__contents"> <div class="dm-message__contents">
{{if (ne $message.InReplyToID 0)}} {{if (ne .InReplyToID 0)}}
<div class="dm-message__replying-to"> <div class="dm-message__replying-to">
<div class="dm-message__replying-to-label labelled-icon"> <div class="dm-message__replying-to-label labelled-icon">
<img class="svg-icon" src="/static/icons/replying_to.svg" width="24" height="24" /> <img class="svg-icon" src="/static/icons/replying_to.svg" width="24" height="24" />
<label>Replying to</label> <label>Replying to</label>
</div> </div>
<div class="replying-to-message" <div class="replying-to-message"
data-replying-to-message-id="{{ $message.InReplyToID }}" data-replying-to-message-id="{{ .InReplyToID }}"
onclick="doReplyTo(this)" onclick="doReplyTo(this)"
> >
{{(index $.DMTrove.Messages $message.InReplyToID).Text}} {{(dm_message .InReplyToID).Text}}
</div> </div>
</div> </div>
{{end}} {{end}}
{{if (ne $message.EmbeddedTweetID 0)}} {{if (ne .EmbeddedTweetID 0)}}
<div class="dm-message__tweet-preview"> <div class="dm-message__tweet-preview">
{{template "tweet" (dict {{template "tweet" (dict
"TweetID" $message.EmbeddedTweetID "TweetID" .EmbeddedTweetID
"RetweetID" 0 "RetweetID" 0
"QuoteNestingLevel" 1) "QuoteNestingLevel" 1)
}} }}
</div> </div>
{{end}} {{end}}
{{range $message.Images}} {{range .Images}}
<img class="dm-message__embedded-image" <img class="dm-message__embedded-image"
{{if .IsDownloaded}} {{if .IsDownloaded}}
src="/content/images/{{.LocalFilename}}" src="/content/images/{{.LocalFilename}}"
@ -43,7 +41,7 @@
onclick="image_carousel.querySelector('img').src = this.src; image_carousel.showModal();" onclick="image_carousel.querySelector('img').src = this.src; image_carousel.showModal();"
> >
{{end}} {{end}}
{{range $message.Videos}} {{range .Videos}}
<video class="dm-message__embedded-video" controls width="{{.Width}}" height="{{.Height}}" <video class="dm-message__embedded-video" controls width="{{.Width}}" height="{{.Height}}"
{{if .IsDownloaded}} {{if .IsDownloaded}}
poster="/content/video_thumbnails/{{.ThumbnailLocalPath}}" poster="/content/video_thumbnails/{{.ThumbnailLocalPath}}"
@ -58,36 +56,38 @@
{{end}} {{end}}
</video> </video>
{{end}} {{end}}
{{range $message.Urls}} {{range .Urls}}
{{template "embedded-link" .}} {{template "embedded-link" .}}
{{end}} {{end}}
{{if $message.Text}} {{if .Text}}
<div class="dm-message__text-content"> <div class="dm-message__text-content">
{{template "text-with-entities" $message.Text}} {{template "text-with-entities" .Text}}
</div> </div>
{{end}} {{end}}
</div> </div>
<div class="dm-message__emoji-button-container">
<div class="dm-message__emoji-button button" onclick="show_emoji_picker(console.log)">
<img class="svg-icon" src="/static/icons/emoji-react.svg" width="24" height="24"/>
</div>
</div>
</div> </div>
<div class="dm-message__reactions"> <div class="dm-message__reactions">
{{range $message.Reactions}} {{range .Reactions}}
{{$sender := (user .SenderID)}} {{$sender := (user .SenderID)}}
<span title="{{$sender.DisplayName}} (@{{$sender.Handle}})">{{.Emoji}}</span> <span title="{{$sender.DisplayName}} (@{{$sender.Handle}})">{{.Emoji}}</span>
{{end}} {{end}}
</div> </div>
<div class="sent-at"> <div class="sent-at">
<p class="sent-at__text"> <p class="sent-at__text">
{{$message.SentAt.Time.Format "Jan 2, 2006 @ 3:04 pm"}} {{.SentAt.Time.Format "Jan 2, 2006 @ 3:04 pm"}}
</p> </p>
</div> </div>
</div> </div>
{{end}}
{{define "messages"}}
{{range .MessageIDs}}
{{template "message" (dm_message .)}}
{{end}} {{end}}
{{end}} {{end}}
{{define "messages-with-poller"}} {{define "messages-with-poller"}}
{{template "messages" .}} {{template "messages" .}}
@ -120,6 +120,7 @@
</script> </script>
{{end}} {{end}}
{{define "chat-view"}} {{define "chat-view"}}
<div id="chat-view"> <div id="chat-view">
{{if .ActiveRoomID}} {{if .ActiveRoomID}}
@ -298,6 +299,7 @@
</script> </script>
{{end}} {{end}}
{{define "conversation-top"}} {{define "conversation-top"}}
<div class="show-more conversation-top"> <div class="show-more conversation-top">
{{if .Cursor.CursorPosition.IsEnd}} {{if .Cursor.CursorPosition.IsEnd}}
@ -312,6 +314,7 @@
</div> </div>
{{end}} {{end}}
{{/* convenience template for htmx requests */}} {{/* convenience template for htmx requests */}}
{{define "messages-top"}} {{define "messages-top"}}
{{template "conversation-top" .}} {{template "conversation-top" .}}

View File

@ -185,7 +185,7 @@ func (p Profile) GetChatMessage(id DMMessageID) (ret DMMessage, err error) {
ret.Reactions = make(map[UserID]DMReaction) ret.Reactions = make(map[UserID]DMReaction)
// This is a bit circuitous, but it doesn't matter because this function is only used in tests // This is a bit circuitous, but it doesn't matter because this function is only used in tests
trove := NewDMTrove() trove := NewTweetTrove()
trove.Messages[ret.ID] = ret trove.Messages[ret.ID] = ret
p.fill_dm_contents(&trove) p.fill_dm_contents(&trove)
@ -193,7 +193,7 @@ func (p Profile) GetChatMessage(id DMMessageID) (ret DMMessage, err error) {
} }
type DMChatView struct { type DMChatView struct {
DMTrove TweetTrove
Cursor DMCursor Cursor DMCursor
RoomIDs []DMChatRoomID RoomIDs []DMChatRoomID
MessageIDs []DMMessageID MessageIDs []DMMessageID
@ -202,7 +202,7 @@ type DMChatView struct {
func NewDMChatView() DMChatView { func NewDMChatView() DMChatView {
return DMChatView{ return DMChatView{
DMTrove: NewDMTrove(), TweetTrove: NewTweetTrove(),
RoomIDs: []DMChatRoomID{}, RoomIDs: []DMChatRoomID{},
MessageIDs: []DMMessageID{}, MessageIDs: []DMMessageID{},
} }
@ -250,7 +250,7 @@ func (p Profile) GetChatRoomsPreview(id UserID) DMChatView {
} }
// Fetch the participants // Fetch the participants
p.fill_chat_room_participants(&room, &ret.DMTrove) p.fill_chat_room_participants(&room, &ret.TweetTrove)
// Add everything to the Trove // Add everything to the Trove
room.LastMessageID = msg.ID room.LastMessageID = msg.ID
@ -259,7 +259,7 @@ func (p Profile) GetChatRoomsPreview(id UserID) DMChatView {
ret.RoomIDs = append(ret.RoomIDs, room.ID) ret.RoomIDs = append(ret.RoomIDs, room.ID)
} }
// Since the message text might be empty, fetch contents (images, tweets etc) so we can still create a preview // Since the message text might be empty, fetch contents (images, tweets etc) so we can still create a preview
p.fill_dm_contents(&ret.DMTrove) p.fill_dm_contents(&ret.TweetTrove)
return ret return ret
} }
@ -300,19 +300,19 @@ func (p Profile) GetChatRoomMessagesByCursor(c DMCursor) DMChatView {
} }
// Fetch the participants // Fetch the participants
p.fill_chat_room_participants(&room, &ret.DMTrove) p.fill_chat_room_participants(&room, &ret.TweetTrove)
// Put the room in the Trove // Put the room in the Trove
ret.Rooms[room.ID] = room ret.Rooms[room.ID] = room
// Fetch reaccs, attachments, and replied-to messages // Fetch reaccs, attachments, and replied-to messages
p.fill_dm_contents(&ret.DMTrove) p.fill_dm_contents(&ret.TweetTrove)
return ret return ret
} }
// Fetch the chat participants and insert it into the DMChatRoom. Inserts user information // Fetch the chat participants and insert it into the DMChatRoom. Inserts user information
// into the DMTrove. // into the TweetTrove.
func (p Profile) fill_chat_room_participants(room *DMChatRoom, trove *DMTrove) { func (p Profile) fill_chat_room_participants(room *DMChatRoom, trove *TweetTrove) {
var participants []struct { var participants []struct {
DMChatParticipant DMChatParticipant
User User
@ -332,8 +332,8 @@ func (p Profile) fill_chat_room_participants(room *DMChatRoom, trove *DMTrove) {
} }
} }
// Fetch reaccs, attachments/embeds and replied-to messages and add them to the DMTrove // Fetch reaccs, attachments/embeds and replied-to messages and add them to the TweetTrove
func (p Profile) fill_dm_contents(trove *DMTrove) { func (p Profile) fill_dm_contents(trove *TweetTrove) {
// Skip processing if there's no messages whomst'd've contents to fetch // Skip processing if there's no messages whomst'd've contents to fetch
if len(trove.Messages) == 0 { if len(trove.Messages) == 0 {
return return
@ -460,7 +460,7 @@ func (p Profile) fill_dm_contents(trove *DMTrove) {
} }
} }
p.fill_content(&trove.TweetTrove, UserID(0)) p.fill_content(trove, UserID(0))
} }
type DMCursor struct { type DMCursor struct {
@ -620,7 +620,7 @@ func (p Profile) NextDMPage(c DMCursor) DMChatView {
// } // }
// Fetch the participants // Fetch the participants
p.fill_chat_room_participants(&room, &ret.DMTrove) p.fill_chat_room_participants(&room, &ret.TweetTrove)
// Add to the Trove // Add to the Trove
// room.LastMessageID = msg.ID // room.LastMessageID = msg.ID
ret.Rooms[room.ID] = room ret.Rooms[room.ID] = room
@ -629,7 +629,7 @@ func (p Profile) NextDMPage(c DMCursor) DMChatView {
} }
} }
p.fill_dm_contents(&ret.DMTrove) p.fill_dm_contents(&ret.TweetTrove)
return ret return ret
} }

View File

@ -12,8 +12,8 @@ import (
// Panics if anything goes wrong. // Panics if anything goes wrong.
// //
// TODO: a lot of this function contains duplicated code and should be extracted to functions // TODO: a lot of this function contains duplicated code and should be extracted to functions
func (p Profile) SaveDMTrove(trove DMTrove, should_download bool) { func (p Profile) SaveDMTrove(trove TweetTrove, should_download bool) {
p.SaveTweetTrove(trove.TweetTrove, should_download) p.SaveTweetTrove(trove, should_download)
for _, r := range trove.Rooms { for _, r := range trove.Rooms {
err := p.SaveChatRoom(r) err := p.SaveChatRoom(r)

View File

@ -77,8 +77,8 @@ func (m *APIDMMessage) NormalizeContent() {
m.MessageData.Text = strings.TrimSpace(m.MessageData.Text) m.MessageData.Text = strings.TrimSpace(m.MessageData.Text)
} }
func (m APIDMMessage) ToDMTrove() DMTrove { func (m APIDMMessage) ToTweetTrove() TweetTrove {
ret := NewDMTrove() ret := NewTweetTrove()
if m.ID == 0 { if m.ID == 0 {
return ret return ret
} }
@ -186,8 +186,8 @@ type APIDMResponse struct {
UserEvents APIInbox `json:"user_events"` UserEvents APIInbox `json:"user_events"`
} }
func (r APIInbox) ToDMTrove() DMTrove { func (r APIInbox) ToTweetTrove() TweetTrove {
ret := NewDMTrove() ret := NewTweetTrove()
for _, entry := range r.Entries { for _, entry := range r.Entries {
if entry.JoinConversation.ID != 0 || entry.TrustConversation.ID != 0 || if entry.JoinConversation.ID != 0 || entry.TrustConversation.ID != 0 ||
@ -209,7 +209,7 @@ func (r APIInbox) ToDMTrove() DMTrove {
// panic("Already in the trove: " + fmt.Sprint(result.ID)) // panic("Already in the trove: " + fmt.Sprint(result.ID))
// } // }
ret.MergeWith(entry.Message.ToDMTrove()) ret.MergeWith(entry.Message.ToTweetTrove())
} }
for _, room := range r.Conversations { for _, room := range r.Conversations {
result := ParseAPIDMChatRoom(room) result := ParseAPIDMChatRoom(room)
@ -220,7 +220,7 @@ func (r APIInbox) ToDMTrove() DMTrove {
if err != nil { if err != nil {
panic(err) panic(err)
} }
ret.TweetTrove.Users[result.ID] = result ret.Users[result.ID] = result
} }
return ret return ret
} }

View File

@ -64,7 +64,7 @@ func TestParseAPIDMMessageWithEmbeddedTweet(t *testing.T) {
err = json.Unmarshal(data, &api_message) err = json.Unmarshal(data, &api_message)
require.NoError(t, err) require.NoError(t, err)
trove := api_message.ToDMTrove() trove := api_message.ToTweetTrove()
assert.Len(trove.Messages, 1) assert.Len(trove.Messages, 1)
m, is_ok := trove.Messages[DMMessageID(1665936253483614212)] m, is_ok := trove.Messages[DMMessageID(1665936253483614212)]
@ -92,7 +92,7 @@ func TestParseAPIDMMessageWithEmbeddedImage(t *testing.T) {
err = json.Unmarshal(data, &api_message) err = json.Unmarshal(data, &api_message)
require.NoError(t, err) require.NoError(t, err)
trove := api_message.ToDMTrove() trove := api_message.ToTweetTrove()
assert.Len(trove.Messages, 1) assert.Len(trove.Messages, 1)
m, is_ok := trove.Messages[DMMessageID(1766224476729995648)] m, is_ok := trove.Messages[DMMessageID(1766224476729995648)]
@ -117,7 +117,7 @@ func TestParseAPIDMMessageWithEmbeddedVideo(t *testing.T) {
err = json.Unmarshal(data, &api_message) err = json.Unmarshal(data, &api_message)
require.NoError(t, err) require.NoError(t, err)
trove := api_message.ToDMTrove() trove := api_message.ToTweetTrove()
assert.Len(trove.Messages, 1) assert.Len(trove.Messages, 1)
m, is_ok := trove.Messages[DMMessageID(1766248283901776125)] m, is_ok := trove.Messages[DMMessageID(1766248283901776125)]
@ -144,7 +144,7 @@ func TestParseAPIDMMessageWithUrlCard(t *testing.T) {
err = json.Unmarshal(data, &api_message) err = json.Unmarshal(data, &api_message)
require.NoError(t, err) require.NoError(t, err)
trove := api_message.ToDMTrove() trove := api_message.ToTweetTrove()
assert.Len(trove.Messages, 1) assert.Len(trove.Messages, 1)
m, is_ok := trove.Messages[DMMessageID(1766255994668191902)] m, is_ok := trove.Messages[DMMessageID(1766255994668191902)]
@ -232,7 +232,7 @@ func TestParseInbox(t *testing.T) {
err = json.Unmarshal(data, &inbox) err = json.Unmarshal(data, &inbox)
require.NoError(t, err) require.NoError(t, err)
trove := inbox.InboxInitialState.ToDMTrove() trove := inbox.InboxInitialState.ToTweetTrove()
for _, id := range []DMMessageID{1663623062195957773, 1663623203644751885, 1665922180176044037, 1665936253483614212} { for _, id := range []DMMessageID{1663623062195957773, 1663623203644751885, 1665922180176044037, 1665936253483614212} {
m, is_ok := trove.Messages[id] m, is_ok := trove.Messages[id]
@ -240,7 +240,7 @@ func TestParseInbox(t *testing.T) {
assert.Equal(m.ID, id) assert.Equal(m.ID, id)
} }
for _, id := range []UserID{1458284524761075714, 1488963321701171204} { for _, id := range []UserID{1458284524761075714, 1488963321701171204} {
u, is_ok := trove.TweetTrove.Users[id] u, is_ok := trove.Users[id]
assert.True(is_ok, "User with ID %d not in the trove!") assert.True(is_ok, "User with ID %d not in the trove!")
assert.Equal(u.ID, id) assert.Equal(u.ID, id)
} }
@ -259,7 +259,7 @@ func TestParseDMRoomResponse(t *testing.T) {
err = json.Unmarshal(data, &inbox) err = json.Unmarshal(data, &inbox)
require.NoError(t, err) require.NoError(t, err)
trove := inbox.ConversationTimeline.ToDMTrove() trove := inbox.ConversationTimeline.ToTweetTrove()
for _, id := range []DMMessageID{ for _, id := range []DMMessageID{
1663623062195957773, 1663623062195957773,
@ -273,7 +273,7 @@ func TestParseDMRoomResponse(t *testing.T) {
assert.Equal(m.ID, id) assert.Equal(m.ID, id)
} }
for _, id := range []UserID{1458284524761075714, 1488963321701171204} { for _, id := range []UserID{1458284524761075714, 1488963321701171204} {
u, is_ok := trove.TweetTrove.Users[id] u, is_ok := trove.Users[id]
assert.True(is_ok, "User with ID %d not in the trove!") assert.True(is_ok, "User with ID %d not in the trove!")
assert.Equal(u.ID, id) assert.Equal(u.ID, id)
} }
@ -293,7 +293,7 @@ func TestParseInboxUpdates(t *testing.T) {
err = json.Unmarshal(data, &inbox) err = json.Unmarshal(data, &inbox)
require.NoError(t, err) require.NoError(t, err)
trove := inbox.UserEvents.ToDMTrove() trove := inbox.UserEvents.ToTweetTrove()
assert.Len(trove.Messages, 2) // Should ignore stuff that isn't a message assert.Len(trove.Messages, 2) // Should ignore stuff that isn't a message

View File

@ -4,31 +4,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type DMTrove struct { func (t TweetTrove) GetOldestMessage(id DMChatRoomID) DMMessageID {
Rooms map[DMChatRoomID]DMChatRoom
Messages map[DMMessageID]DMMessage
TweetTrove
}
func NewDMTrove() DMTrove {
ret := DMTrove{}
ret.Rooms = make(map[DMChatRoomID]DMChatRoom)
ret.Messages = make(map[DMMessageID]DMMessage)
ret.TweetTrove = NewTweetTrove()
return ret
}
func (t1 *DMTrove) MergeWith(t2 DMTrove) {
for id, val := range t2.Rooms {
t1.Rooms[id] = val
}
for id, val := range t2.Messages {
t1.Messages[id] = val
}
t1.TweetTrove.MergeWith(t2.TweetTrove)
}
func (t DMTrove) GetOldestMessage(id DMChatRoomID) DMMessageID {
oldest := DMMessageID(^uint(0) >> 1) // Max integer oldest := DMMessageID(^uint(0) >> 1) // Max integer
for _, m := range t.Messages { for _, m := range t.Messages {
if m.ID < oldest && m.DMChatRoomID == id { if m.ID < oldest && m.DMChatRoomID == id {
@ -38,8 +14,10 @@ func (t DMTrove) GetOldestMessage(id DMChatRoomID) DMMessageID {
return oldest return oldest
} }
// Returns a DMTrove and the cursor for the next update // TODO: Why are these all here? =>
func GetInbox(how_many int) (DMTrove, string) {
// Returns a TweetTrove and the cursor for the next update
func GetInbox(how_many int) (TweetTrove, string) {
if !the_api.IsAuthenticated { if !the_api.IsAuthenticated {
log.Fatalf("Fetching DMs can only be done when authenticated. Please provide `--session [user]`") log.Fatalf("Fetching DMs can only be done when authenticated. Please provide `--session [user]`")
} }
@ -48,7 +26,7 @@ func GetInbox(how_many int) (DMTrove, string) {
panic(err) panic(err)
} }
trove := dm_response.ToDMTrove() trove := dm_response.ToTweetTrove()
cursor := dm_response.Cursor cursor := dm_response.Cursor
next_cursor_id := dm_response.InboxTimelines.Trusted.MinEntryID next_cursor_id := dm_response.InboxTimelines.Trusted.MinEntryID
for len(trove.Rooms) < how_many && dm_response.Status != "AT_END" { for len(trove.Rooms) < how_many && dm_response.Status != "AT_END" {
@ -56,7 +34,7 @@ func GetInbox(how_many int) (DMTrove, string) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
next_trove := dm_response.ToDMTrove() next_trove := dm_response.ToTweetTrove()
next_cursor_id = dm_response.MinEntryID next_cursor_id = dm_response.MinEntryID
trove.MergeWith(next_trove) trove.MergeWith(next_trove)
} }
@ -64,7 +42,7 @@ func GetInbox(how_many int) (DMTrove, string) {
return trove, cursor return trove, cursor
} }
func GetConversation(id DMChatRoomID, max_id DMMessageID, how_many int) DMTrove { func GetConversation(id DMChatRoomID, max_id DMMessageID, how_many int) TweetTrove {
if !the_api.IsAuthenticated { if !the_api.IsAuthenticated {
log.Fatalf("Fetching DMs can only be done when authenticated. Please provide `--session [user]`") log.Fatalf("Fetching DMs can only be done when authenticated. Please provide `--session [user]`")
} }
@ -73,14 +51,14 @@ func GetConversation(id DMChatRoomID, max_id DMMessageID, how_many int) DMTrove
panic(err) panic(err)
} }
trove := dm_response.ToDMTrove() trove := dm_response.ToTweetTrove()
oldest := trove.GetOldestMessage(id) oldest := trove.GetOldestMessage(id)
for len(trove.Messages) < how_many && dm_response.Status != "AT_END" { for len(trove.Messages) < how_many && dm_response.Status != "AT_END" {
dm_response, err = the_api.GetDMConversation(id, oldest) dm_response, err = the_api.GetDMConversation(id, oldest)
if err != nil { if err != nil {
panic(err) panic(err)
} }
next_trove := dm_response.ToDMTrove() next_trove := dm_response.ToTweetTrove()
oldest = next_trove.GetOldestMessage(id) oldest = next_trove.GetOldestMessage(id)
trove.MergeWith(next_trove) trove.MergeWith(next_trove)
} }
@ -88,8 +66,8 @@ func GetConversation(id DMChatRoomID, max_id DMMessageID, how_many int) DMTrove
return trove return trove
} }
// Returns a DMTrove and the cursor for the next update // Returns a TweetTrove and the cursor for the next update
func PollInboxUpdates(cursor string) (DMTrove, string) { func PollInboxUpdates(cursor string) (TweetTrove, string) {
if !the_api.IsAuthenticated { if !the_api.IsAuthenticated {
log.Fatalf("Fetching DMs can only be done when authenticated. Please provide `--session [user]`") log.Fatalf("Fetching DMs can only be done when authenticated. Please provide `--session [user]`")
} }
@ -98,10 +76,10 @@ func PollInboxUpdates(cursor string) (DMTrove, string) {
panic(err) panic(err)
} }
return dm_response.ToDMTrove(), dm_response.Cursor return dm_response.ToTweetTrove(), dm_response.Cursor
} }
func SendDMMessage(room_id DMChatRoomID, text string, in_reply_to_id DMMessageID) DMTrove { func SendDMMessage(room_id DMChatRoomID, text string, in_reply_to_id DMMessageID) TweetTrove {
if !the_api.IsAuthenticated { if !the_api.IsAuthenticated {
log.Fatalf("Fetching DMs can only be done when authenticated. Please provide `--session [user]`") log.Fatalf("Fetching DMs can only be done when authenticated. Please provide `--session [user]`")
} }
@ -109,7 +87,7 @@ func SendDMMessage(room_id DMChatRoomID, text string, in_reply_to_id DMMessageID
if err != nil { if err != nil {
panic(err) panic(err)
} }
return dm_response.ToDMTrove() return dm_response.ToTweetTrove()
} }
func MarkDMChatRead(room_id DMChatRoomID, read_message_id DMMessageID) { func MarkDMChatRead(room_id DMChatRoomID, read_message_id DMMessageID) {
if !the_api.IsAuthenticated { if !the_api.IsAuthenticated {

View File

@ -16,6 +16,10 @@ type TweetTrove struct {
Bookmarks map[BookmarkSortID]Bookmark Bookmarks map[BookmarkSortID]Bookmark
TombstoneUsers []UserHandle TombstoneUsers []UserHandle
// For DMs
Rooms map[DMChatRoomID]DMChatRoom
Messages map[DMMessageID]DMMessage
} }
func NewTweetTrove() TweetTrove { func NewTweetTrove() TweetTrove {
@ -27,6 +31,8 @@ func NewTweetTrove() TweetTrove {
ret.Likes = make(map[LikeSortID]Like) ret.Likes = make(map[LikeSortID]Like)
ret.Bookmarks = make(map[BookmarkSortID]Bookmark) ret.Bookmarks = make(map[BookmarkSortID]Bookmark)
ret.TombstoneUsers = []UserHandle{} ret.TombstoneUsers = []UserHandle{}
ret.Rooms = make(map[DMChatRoomID]DMChatRoom)
ret.Messages = make(map[DMMessageID]DMMessage)
return ret return ret
} }
@ -66,6 +72,13 @@ func (t1 *TweetTrove) MergeWith(t2 TweetTrove) {
} }
t1.TombstoneUsers = append(t1.TombstoneUsers, t2.TombstoneUsers...) t1.TombstoneUsers = append(t1.TombstoneUsers, t2.TombstoneUsers...)
for id, val := range t2.Rooms {
t1.Rooms[id] = val
}
for id, val := range t2.Messages {
t1.Messages[id] = val
}
} }
/** /**