Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Unfurl status links #4033

Merged
merged 32 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b3af512
wip
igor-sirotin Aug 29, 2023
f8fd1be
wip
igor-sirotin Aug 29, 2023
86c657c
`UnfurlURLsResponse`
igor-sirotin Sep 14, 2023
8f0ed10
fix: url in StatusLinkPreivew
igor-sirotin Sep 21, 2023
fdc6671
wip: protobuf for unfurling status links
igor-sirotin Sep 25, 2023
b388d23
unfurling contact link works
igor-sirotin Sep 26, 2023
62d075b
wip: unfurling status community shared url
igor-sirotin Sep 26, 2023
9766027
unfurling status channel links
igor-sirotin Sep 27, 2023
6a3e6c1
fix: make url empty for empty thumbnail
igor-sirotin Sep 28, 2023
c095598
more tests, minor fixes
igor-sirotin Sep 28, 2023
a255257
fix channel community toProto. better error reporting
igor-sirotin Sep 29, 2023
c19d4fd
lint fix
igor-sirotin Sep 30, 2023
3b4eb9d
fix message editing. fix tests. address pr comments.
igor-sirotin Oct 2, 2023
6285287
remove unused test
igor-sirotin Oct 2, 2023
79026a9
fix `TestConvertFromProtoToLinkPreviews`
igor-sirotin Oct 2, 2023
9074bc0
moar test fixes
igor-sirotin Oct 2, 2023
aecb6c9
fix TestServer_MakeStatusLinkPreviewThumbnailURL
igor-sirotin Oct 2, 2023
72794ab
address comments
igor-sirotin Oct 3, 2023
6910b39
address PR comments, move image ids to common, handler test
igor-sirotin Oct 4, 2023
9a3396e
lint fix after rebase
igor-sirotin Oct 4, 2023
4756984
lint fix
igor-sirotin Oct 4, 2023
0ce8f85
fix test
igor-sirotin Oct 5, 2023
c0ef2ba
don't use url data. fetch from waku when no data.
igor-sirotin Oct 5, 2023
234fb11
rename `buildThumbnail` func
igor-sirotin Oct 6, 2023
a6c46e5
remove link preview tag indices
igor-sirotin Oct 6, 2023
4ad85d7
fix code climate warnings
igor-sirotin Oct 9, 2023
c1ff23f
change id trypes from string to bytes
igor-sirotin Oct 11, 2023
d48f018
lint/test fix
igor-sirotin Oct 11, 2023
5a93cac
test fix
igor-sirotin Oct 11, 2023
8174219
update version
igor-sirotin Oct 13, 2023
148c6e4
make generate
igor-sirotin Oct 13, 2023
157e2de
rebase fixes
igor-sirotin Oct 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.169.0
0.170.0
918 changes: 523 additions & 395 deletions appdatabase/migrations/bindata.go

Large diffs are not rendered by default.

569 changes: 329 additions & 240 deletions appdatabase/migrationsprevnodecfg/bindata.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions mailserver/migrations/bindata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 13 additions & 13 deletions multiaccounts/migrations/bindata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions protocol/anonmetrics/migrations/migrations.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions protocol/common/media_server_image_id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package common

type MediaServerImageIDPrefix string
type MediaServerImageIDPostfix string
type MediaServerImageID string

func CreateImageID(prefix MediaServerImageIDPrefix, postfix MediaServerImageIDPostfix) MediaServerImageID {
return MediaServerImageID(string(prefix) + string(postfix))
}

const (
MediaServerIconPostfix MediaServerImageIDPostfix = "icon"
MediaServerBannerPostfix MediaServerImageIDPostfix = "banner"
)

const (
MediaServerContactPrefix MediaServerImageIDPrefix = "contact-"
MediaServerCommunityPrefix MediaServerImageIDPrefix = "community-"
MediaServerChannelCommunityPrefix MediaServerImageIDPrefix = "community-channel-"
)

const (
MediaServerContactIcon = MediaServerImageID(string(MediaServerContactPrefix) + string(MediaServerIconPostfix))
MediaServerCommunityIcon = MediaServerImageID(string(MediaServerCommunityPrefix) + string(MediaServerIconPostfix))
MediaServerCommunityBanner = MediaServerImageID(string(MediaServerCommunityPrefix) + string(MediaServerBannerPostfix))
MediaServerChannelCommunityIcon = MediaServerImageID(string(MediaServerChannelCommunityPrefix) + string(MediaServerIconPostfix))
MediaServerChannelCommunityBanner = MediaServerImageID(string(MediaServerChannelCommunityPrefix) + string(MediaServerBannerPostfix))
)
120 changes: 5 additions & 115 deletions protocol/common/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"io/ioutil"
"net/url"
"os"
"strings"
"unicode"
Expand Down Expand Up @@ -82,26 +81,6 @@ const (
ContactVerificationStateCanceled
)

type LinkPreviewThumbnail struct {
Width int `json:"width"`
Height int `json:"height"`
// Non-empty when the thumbnail is available via the media server, i.e. after
// the chat message is sent.
URL string `json:"url,omitempty"`
// Non-empty when the thumbnail payload needs to be shared with the client,
// but before it has been persisted.
DataURI string `json:"dataUri,omitempty"`
}

type LinkPreview struct {
Type protobuf.UnfurledLink_LinkType `json:"type"`
URL string `json:"url"`
Hostname string `json:"hostname"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Thumbnail LinkPreviewThumbnail `json:"thumbnail,omitempty"`
}

const EveryoneMentionTag = "0x00001"

type CommandParameters struct {
Expand Down Expand Up @@ -219,8 +198,9 @@ type Message struct {
Replied bool `json:"replied"`

// Links is an array of links within given message
Links []string
LinkPreviews []LinkPreview `json:"linkPreviews"`
Links []string
LinkPreviews []LinkPreview `json:"linkPreviews"`
StatusLinkPreviews []StatusLinkPreview `json:"statusLinkPreviews"`

// EditedAt indicates the clock value it was edited
EditedAt uint64 `json:"editedAt"`
Expand Down Expand Up @@ -292,6 +272,7 @@ func (m *Message) MarshalJSON() ([]byte, error) {
Replied bool `json:"replied,omitempty"`
Links []string `json:"links,omitempty"`
LinkPreviews []LinkPreview `json:"linkPreviews,omitempty"`
StatusLinkPreviews []StatusLinkPreview `json:"statusLinkPreviews,omitempty"`
EditedAt uint64 `json:"editedAt,omitempty"`
Deleted bool `json:"deleted,omitempty"`
DeletedBy string `json:"deletedBy,omitempty"`
Expand Down Expand Up @@ -331,6 +312,7 @@ func (m *Message) MarshalJSON() ([]byte, error) {
Replied: m.Replied,
Links: m.Links,
LinkPreviews: m.LinkPreviews,
StatusLinkPreviews: m.StatusLinkPreviews,
MessageType: m.MessageType,
CommandParameters: m.CommandParameters,
GapParameters: m.GapParameters,
Expand Down Expand Up @@ -763,98 +745,6 @@ func (m *Message) LoadImage() error {
return nil
}

func isValidLinkPreviewThumbnail(thumbnail LinkPreviewThumbnail) bool {
igor-sirotin marked this conversation as resolved.
Show resolved Hide resolved
return (thumbnail.DataURI == "" && thumbnail.Width == 0 && thumbnail.Height == 0) ||
(thumbnail.DataURI != "" && thumbnail.Width > 0 && thumbnail.Height > 0)
}

func isValidLinkPreviewForProto(preview LinkPreview) bool {
switch preview.Type {
case protobuf.UnfurledLink_IMAGE:
return preview.URL != "" && isValidLinkPreviewThumbnail(preview.Thumbnail)
default: // Validate as a link type by default.
return preview.Title != "" && preview.URL != "" && isValidLinkPreviewThumbnail(preview.Thumbnail)
}
}

// ConvertLinkPreviewsToProto expects previews to be correctly sent by the
// client because we can't attempt to re-unfurl URLs at this point (it's
// actually undesirable). We run a basic validation as an additional safety net.
func (m *Message) ConvertLinkPreviewsToProto() ([]*protobuf.UnfurledLink, error) {
if len(m.LinkPreviews) == 0 {
return nil, nil
}

unfurledLinks := make([]*protobuf.UnfurledLink, 0, len(m.LinkPreviews))

for _, preview := range m.LinkPreviews {
// Do not process subsequent previews because we do expect all previews to
// be valid at this stage.
if !isValidLinkPreviewForProto(preview) {
return nil, fmt.Errorf("invalid link preview, url='%s'", preview.URL)
}

var payload []byte
var err error
if preview.Thumbnail.DataURI != "" {
payload, err = images.GetPayloadFromURI(preview.Thumbnail.DataURI)
if err != nil {
return nil, fmt.Errorf("could not get data URI payload, url='%s': %w", preview.URL, err)
}
}

ul := &protobuf.UnfurledLink{
Type: preview.Type,
Url: preview.URL,
Title: preview.Title,
Description: preview.Description,
ThumbnailWidth: uint32(preview.Thumbnail.Width),
ThumbnailHeight: uint32(preview.Thumbnail.Height),
ThumbnailPayload: payload,
}
unfurledLinks = append(unfurledLinks, ul)
}

return unfurledLinks, nil
}

func (m *Message) ConvertFromProtoToLinkPreviews(makeMediaServerURL func(msgID string, previewURL string) string) []LinkPreview {
var links []*protobuf.UnfurledLink

if links = m.GetUnfurledLinks(); links == nil {
return nil
}

previews := make([]LinkPreview, 0, len(links))
for _, link := range links {
parsedURL, err := url.Parse(link.Url)
var hostname string
// URL parsing in Go can fail with URLs that weren't correctly URL encoded.
// This shouldn't happen in general, but if an error happens we just reuse
// the full URL.
if err != nil {
hostname = link.Url
} else {
hostname = parsedURL.Hostname()
}
lp := LinkPreview{
Description: link.Description,
Hostname: hostname,
Title: link.Title,
Type: link.Type,
URL: link.Url,
}
if payload := link.GetThumbnailPayload(); payload != nil {
lp.Thumbnail.Width = int(link.ThumbnailWidth)
lp.Thumbnail.Height = int(link.ThumbnailHeight)
lp.Thumbnail.URL = makeMediaServerURL(m.ID, link.Url)
}
previews = append(previews, lp)
}

return previews
}

func (m *Message) SetAlbumIDAndImagesCount(albumID string, imagesCount uint32) error {
imageMessage := m.GetImage()
if imageMessage == nil {
Expand Down
Loading