Skip to content

Commit

Permalink
Don't save the content or relates to structs in the RoomMessageEvent …
Browse files Browse the repository at this point in the history
…and just generate as required.

This also cleans up the code moving all content objefcts to EventContent and additional helpers to grab text, file or loaction content if you know it's what you need are added.
  • Loading branch information
nvrWhere committed Oct 12, 2024
1 parent 28ce82e commit 13509c8
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 135 deletions.
103 changes: 101 additions & 2 deletions Quotient/events/eventcontent.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

#include "filesourceinfo.h"

#include "../util.h"

#include <QtCore/QJsonObject>
#include <QtCore/QMetaType>
#include <QtCore/QMimeType>
Expand Down Expand Up @@ -163,6 +161,50 @@ class QUOTIENT_API TypedBase : public Base {
using Base::Base;
};

//! \brief Rich text content for m.text, m.emote, m.notice
//!
//! Available fields: mimeType, body. The body can be either rich text
//! or plain text, depending on what mimeType specifies.
class QUOTIENT_API TextContent : public TypedBase {
public:
TextContent(QString text, const QString& contentType);
explicit TextContent(const QJsonObject& json);

QMimeType type() const override { return mimeType; }

QMimeType mimeType;
QString body;

protected:
void fillJson(QJsonObject& json) const override;
};

//! \brief Content class for m.location
//!
//! Available fields:
//! - corresponding to the top-level JSON:
//! - geoUri ("geo_uri" in JSON)
//! - corresponding to the "info" subobject:
//! - thumbnail.url ("thumbnail_url" in JSON)
//! - corresponding to the "info/thumbnail_info" subobject:
//! - thumbnail.payloadSize
//! - thumbnail.mimeType
//! - thumbnail.imageSize
class QUOTIENT_API LocationContent : public TypedBase {
public:
LocationContent(const QString& geoUri, const Thumbnail& thumbnail = {});
explicit LocationContent(const QJsonObject& json);

QMimeType type() const override;

public:
QString geoUri;
Thumbnail thumbnail;

protected:
void fillJson(QJsonObject& o) const override;
};

//! \brief A template class for content types with a URL and additional info
//!
//! Types that derive from this class template take `url` (or, if the file
Expand Down Expand Up @@ -246,5 +288,62 @@ using ImageContent = UrlBasedContent<ImageInfo>;
//! - thumbnail.mimeType
//! - thumbnail.imageSize (QSize for `h` and `w` in JSON)
using FileContent = UrlBasedContent<FileInfo>;

//! A base class for info types that include duration: audio and video
template <typename InfoT>
class PlayableContent : public UrlBasedContent<InfoT> {
public:
using UrlBasedContent<InfoT>::UrlBasedContent;
PlayableContent(const QJsonObject& json)
: UrlBasedContent<InfoT>(json)
, duration(FileInfo::originalInfoJson["duration"_L1].toInt())
{}

protected:
void fillInfoJson(QJsonObject& infoJson) const override
{
infoJson.insert("duration"_L1, duration);
}

public:
int duration;
};

//! \brief Content class for m.video
//!
//! Available fields:
//! - corresponding to the top-level JSON:
//! - url
//! - filename (extension to the CS API spec)
//! - corresponding to the "info" subobject:
//! - payloadSize ("size" in JSON)
//! - mimeType ("mimetype" in JSON)
//! - duration
//! - imageSize (QSize for a combination of "h" and "w" in JSON)
//! - thumbnail.url ("thumbnail_url" in JSON)
//! - corresponding to the "info/thumbnail_info" subobject: contents of
//! thumbnail field, in the same vein as for "info":
//! - payloadSize
//! - mimeType
//! - imageSize
using VideoContent = PlayableContent<ImageInfo>;

//! \brief Content class for m.audio
//!
//! Available fields:
//! - corresponding to the top-level JSON:
//! - url
//! - filename (extension to the CS API spec)
//! - corresponding to the "info" subobject:
//! - payloadSize ("size" in JSON)
//! - mimeType ("mimetype" in JSON)
//! - duration
//! - thumbnail.url ("thumbnail_url" in JSON)
//! - corresponding to the "info/thumbnail_info" subobject: contents of
//! thumbnail field, in the same vein as for "info":
//! - payloadSize
//! - mimeType
//! - imageSize
using AudioContent = PlayableContent<FileInfo>;
} // namespace Quotient::EventContent
Q_DECLARE_METATYPE(const Quotient::EventContent::TypedBase*)
76 changes: 67 additions & 9 deletions Quotient/events/roommessageevent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

#include "../logging_categories_p.h"
#include "eventrelation.h"
#include <Quotient/events/eventcontent.h>

#include <QtCore/QFileInfo>
#include <QtCore/QMimeDatabase>
#include <QtGui/QImageReader>
#include <QtCore/QStringBuilder>
#include <optional>

using namespace Quotient;
using namespace EventContent;
Expand Down Expand Up @@ -121,8 +123,6 @@ RoomMessageEvent::RoomMessageEvent(const QString& plainBody,
std::optional<EventRelation> relatesTo)
: RoomEvent(
basicJson(TypeId, assembleContentJson(plainBody, jsonMsgType, content, relatesTo)))
, _content(content)
, _relatesTo(relatesTo)
{}

RoomMessageEvent::RoomMessageEvent(const QString& plainBody, MsgType msgType,
Expand All @@ -131,7 +131,7 @@ RoomMessageEvent::RoomMessageEvent(const QString& plainBody, MsgType msgType,
{}

RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
: RoomEvent(obj), _content(nullptr)
: RoomEvent(obj)
{
if (isRedacted())
return;
Expand All @@ -141,7 +141,6 @@ RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
bool msgTypeFound = false;
for (const auto& mt : msgTypes) {
if (mt.matrixType == msgtype) {
_content = mt.maker(content);
msgTypeFound = true;
}
}
Expand All @@ -152,8 +151,6 @@ RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
qCWarning(EVENTS) << formatJson << content;
return;
}

fromJson(content[RelatesToKey], _relatesTo);
} else {
qCWarning(EVENTS) << "No body or msgtype in room message event";
qCWarning(EVENTS) << formatJson << obj;
Expand All @@ -179,7 +176,34 @@ QMimeType RoomMessageEvent::mimeType() const
{
static const auto PlainTextMimeType =
QMimeDatabase().mimeTypeForName("text/plain"_L1);
return _content ? _content->type() : PlainTextMimeType;
return content() ? content()->type() : PlainTextMimeType;
}

std::unique_ptr<EventContent::TypedBase> RoomMessageEvent::content() const
{
const QJsonObject content = contentJson();
if (content.contains(MsgTypeKey) && content.contains(BodyKey)) {
auto msgtype = content[MsgTypeKey].toString();
bool msgTypeFound = false;
std::unique_ptr<EventContent::TypedBase> eventContent = nullptr;
for (const auto& mt : msgTypes) {
if (mt.matrixType == msgtype) {
eventContent = mt.maker(content);
msgTypeFound = true;
}
}

if (!msgTypeFound) {
qCWarning(EVENTS) << "RoomMessageEvent: unknown msg_type,"
<< " full content dump follows";
qCWarning(EVENTS) << formatJson << content;
}
return eventContent;
} else {
qCWarning(EVENTS) << "No body or msgtype in room message event";
qCWarning(EVENTS) << formatJson << fullJson();
return nullptr;
}
}

bool RoomMessageEvent::hasTextContent() const
Expand All @@ -189,19 +213,53 @@ bool RoomMessageEvent::hasTextContent() const
|| msgtype() == MsgType::Notice);
}

std::optional<EventContent::TextContent> RoomMessageEvent::textContent() const
{
if (!hasTextContent() || !content()) {
return std::nullopt;
}

return TextContent(contentJson());
}

bool RoomMessageEvent::hasFileContent() const
{
return content() && content()->fileInfo();
}

std::optional<EventContent::FileContent> RoomMessageEvent::fileContent() const
{
if (!hasFileContent()) {
return std::nullopt;
}

return FileContent(contentJson());
}

bool RoomMessageEvent::hasThumbnail() const
{
return content() && content()->thumbnailInfo();
}

bool RoomMessageEvent::hasLocationContent() const
{
return content() && msgtype() == MsgType::Location;
}

std::optional<EventContent::LocationContent> RoomMessageEvent::locationContent() const
{
if (!hasLocationContent()) {
return std::nullopt;
}

return LocationContent(contentJson());
}

std::optional<EventRelation> RoomMessageEvent::relatesTo() const
{
return _relatesTo;
std::optional<EventRelation> relatesTo;
fromJson(contentJson()[RelatesToKey], relatesTo);
return relatesTo;
}

QString RoomMessageEvent::upstreamEventId() const
Expand All @@ -215,7 +273,7 @@ QString RoomMessageEvent::replacedEvent() const
if (!content() || !hasTextContent())
return {};

return isReplacement(_relatesTo) ? _relatesTo->eventId : QString();
return isReplacement(relatesTo()) ? relatesTo()->eventId : QString();
}

bool RoomMessageEvent::isReplaced() const
Expand Down
Loading

0 comments on commit 13509c8

Please sign in to comment.