Migrate REST classes to Kotlin and upgrade Javalin

This commit is contained in:
Torsten Grote
2018-08-27 16:26:41 -03:00
parent 33c509cd1f
commit 348968018a
27 changed files with 397 additions and 496 deletions

View File

@@ -1,23 +0,0 @@
package org.briarproject.bramble.identity;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
@SuppressWarnings("WeakerAccess")
public class OutputAuthor {
public final byte[] id;
public final String name;
public final byte[] publicKey;
public OutputAuthor(Author author) {
this.id = author.getId().getBytes();
this.name = author.getName();
this.publicKey = author.getPublicKey();
}
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.bramble.identity
import org.briarproject.bramble.api.identity.Author
import javax.annotation.concurrent.Immutable
@Immutable
@Suppress("unused")
class OutputAuthor(author: Author) {
val id: ByteArray = author.id.bytes
val name: String = author.name
val publicKey: ByteArray = author.publicKey
}

View File

@@ -0,0 +1,12 @@
package org.briarproject.briar.headless
import org.briarproject.bramble.api.identity.Author
import org.briarproject.bramble.identity.OutputAuthor
import org.briarproject.briar.api.blog.MessageType
fun Author.output() = OutputAuthor(this)
fun Author.Status.output() = name.toLowerCase()
fun MessageType.output() = name.toLowerCase()

View File

@@ -1,79 +0,0 @@
package org.briarproject.briar.headless;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.briar.headless.blogs.BlogController;
import org.briarproject.briar.headless.contact.ContactController;
import org.briarproject.briar.headless.forums.ForumController;
import org.briarproject.briar.headless.messaging.MessagingController;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.javalin.Javalin;
import static io.javalin.ApiBuilder.get;
import static io.javalin.ApiBuilder.path;
import static io.javalin.ApiBuilder.post;
import static io.javalin.event.EventType.SERVER_START_FAILED;
import static io.javalin.event.EventType.SERVER_STOPPED;
import static java.lang.Runtime.getRuntime;
@Immutable
@Singleton
@MethodsNotNullByDefault
@ParametersAreNonnullByDefault
public class Router {
private final BriarService briarService;
private final ContactController contactController;
private final MessagingController messagingController;
private final ForumController forumController;
private final BlogController blogController;
@Inject
public Router(BriarService briarService,
ContactController contactController,
MessagingController messagingController,
ForumController forumController,
BlogController blogController) {
this.briarService = briarService;
this.contactController = contactController;
this.messagingController = messagingController;
this.forumController = forumController;
this.blogController = blogController;
}
public void start() {
briarService.start();
getRuntime().addShutdownHook(new Thread(briarService::stop));
Javalin app = Javalin.create()
.port(7000)
.disableStartupBanner()
.enableStandardRequestLogging()
.enableRouteOverview("/")
.enableDynamicGzip()
.event(SERVER_START_FAILED, event -> briarService.stop())
.event(SERVER_STOPPED, event -> briarService.stop())
.start();
app.routes(() -> {
path("/contacts", () -> get(contactController::list));
path("/messages/:contactId", () -> {
get(messagingController::list);
post(messagingController::write);
});
path("/forums", () -> {
get(forumController::list);
post(forumController::create);
});
path("/blogs", () -> path("/posts", () -> {
get(blogController::listPosts);
post(blogController::createPost);
}));
});
}
}

View File

@@ -0,0 +1,68 @@
package org.briarproject.briar.headless
import io.javalin.Javalin
import io.javalin.JavalinEvent.SERVER_START_FAILED
import io.javalin.JavalinEvent.SERVER_STOPPED
import io.javalin.apibuilder.ApiBuilder.*
import org.briarproject.briar.headless.blogs.BlogController
import org.briarproject.briar.headless.contact.ContactController
import org.briarproject.briar.headless.forums.ForumController
import org.briarproject.briar.headless.messaging.MessagingController
import java.lang.Runtime.getRuntime
import javax.annotation.concurrent.Immutable
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.system.exitProcess
@Immutable
@Singleton
class Router @Inject
constructor(
private val briarService: BriarService,
private val contactController: ContactController,
private val messagingController: MessagingController,
private val forumController: ForumController,
private val blogController: BlogController
) {
fun start() {
briarService.start()
getRuntime().addShutdownHook(Thread(Runnable { briarService.stop() }))
val app = Javalin.create()
.port(7000)
.disableStartupBanner()
.enableDebugLogging()
.enableCaseSensitiveUrls()
.enableRouteOverview("/")
.event(SERVER_START_FAILED) { stop() }
.event(SERVER_STOPPED) { stop() }
.start()
app.routes {
path("/contacts") {
get { ctx -> contactController.list(ctx) }
}
path("/messages/:contactId") {
get { ctx -> messagingController.list(ctx) }
post { ctx -> messagingController.write(ctx) }
}
path("/forums") {
get { ctx -> forumController.list(ctx) }
post { ctx -> forumController.create(ctx) }
}
path("/blogs") {
path("/posts") {
get { ctx -> blogController.listPosts(ctx) }
post { ctx -> blogController.createPost(ctx) }
}
}
}
}
private fun stop() {
briarService.stop()
exitProcess(1)
}
}

View File

@@ -1,81 +0,0 @@
package org.briarproject.briar.headless.blogs;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.blog.Blog;
import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogPost;
import org.briarproject.briar.api.blog.BlogPostFactory;
import org.briarproject.briar.api.blog.BlogPostHeader;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.javalin.Context;
@Immutable
@Singleton
@MethodsNotNullByDefault
@ParametersAreNonnullByDefault
public class BlogController {
private final BlogManager blogManager;
private final BlogPostFactory blogPostFactory;
private final IdentityManager identityManager;
private final Clock clock;
@Inject
public BlogController(BlogManager blogManager,
BlogPostFactory blogPostFactory, IdentityManager identityManager,
Clock clock) {
this.blogManager = blogManager;
this.blogPostFactory = blogPostFactory;
this.identityManager = identityManager;
this.clock = clock;
}
public Context listPosts(Context ctx) throws DbException {
List<OutputBlogPost> posts = new ArrayList<>();
for (Blog b : blogManager.getBlogs()) {
Collection<BlogPostHeader> headers =
blogManager.getPostHeaders(b.getId());
for (BlogPostHeader header : headers) {
String body = blogManager.getPostBody(header.getId());
OutputBlogPost post = new OutputBlogPost(header, body);
posts.add(post);
}
}
return ctx.json(posts);
}
public Context createPost(Context ctx)
throws DbException, GeneralSecurityException, FormatException {
String text = ctx.formParam("text");
if (text == null || text.length() < 1) {
return ctx.status(500).result("Expecting Blog text");
} else {
LocalAuthor author = identityManager.getLocalAuthor();
Blog blog = blogManager.getPersonalBlog(author);
long now = clock.currentTimeMillis();
BlogPost post = blogPostFactory
.createBlogPost(blog.getId(), now, null, author, text);
blogManager.addLocalPost(post);
BlogPostHeader header = blogManager
.getPostHeader(blog.getId(), post.getMessage().getId());
OutputBlogPost outputPost = new OutputBlogPost(header, text);
return ctx.json(outputPost);
}
}
}

View File

@@ -0,0 +1,47 @@
package org.briarproject.briar.headless.blogs
import io.javalin.BadRequestResponse
import io.javalin.Context
import org.briarproject.bramble.api.identity.IdentityManager
import org.briarproject.bramble.api.system.Clock
import org.briarproject.briar.api.blog.BlogManager
import org.briarproject.briar.api.blog.BlogPostFactory
import javax.annotation.concurrent.Immutable
import javax.inject.Inject
import javax.inject.Singleton
@Immutable
@Singleton
class BlogController @Inject
constructor(
private val blogManager: BlogManager,
private val blogPostFactory: BlogPostFactory,
private val identityManager: IdentityManager,
private val clock: Clock
) {
fun listPosts(ctx: Context): Context {
val posts = blogManager.blogs.flatMap { blog ->
blogManager.getPostHeaders(blog.id).map { header ->
val body = blogManager.getPostBody(header.id)
header.output(body)
}
}
return ctx.json(posts)
}
fun createPost(ctx: Context): Context {
val text = ctx.formParam("text")
if (text == null || text.isEmpty())
throw BadRequestResponse("Expecting Blog text")
val author = identityManager.localAuthor
val blog = blogManager.getPersonalBlog(author)
val now = clock.currentTimeMillis()
val post = blogPostFactory.createBlogPost(blog.id, now, null, author, text)
blogManager.addLocalPost(post)
val header = blogManager.getPostHeader(blog.id, post.message.id)
return ctx.json(header.output(text))
}
}

View File

@@ -0,0 +1,5 @@
package org.briarproject.briar.headless.blogs
import org.briarproject.briar.api.blog.BlogPostHeader
internal fun BlogPostHeader.output(body: String) = OutputBlogPost(this, body)

View File

@@ -1,38 +0,0 @@
package org.briarproject.briar.headless.blogs;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.identity.OutputAuthor;
import org.briarproject.briar.api.blog.BlogPostHeader;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
@SuppressWarnings("WeakerAccess")
class OutputBlogPost {
public final String body;
public final OutputAuthor author;
public final String authorStatus, type;
public final byte[] id;
@Nullable
public final byte[] parentId;
public final boolean read, rssFeed;
public final long timestamp, timestampReceived;
OutputBlogPost(BlogPostHeader header, String body) {
this.body = body;
this.author = new OutputAuthor(header.getAuthor());
this.authorStatus = header.getAuthorStatus().name().toLowerCase();
this.type = header.getType().name().toLowerCase();
this.id = header.getId().getBytes();
this.parentId = header.getParentId() == null ? null :
header.getParentId().getBytes();
this.read = header.isRead();
this.rssFeed = header.isRssFeed();
this.timestamp = header.getTimestamp();
this.timestampReceived = header.getTimeReceived();
}
}

View File

@@ -0,0 +1,22 @@
package org.briarproject.briar.headless.blogs
import org.briarproject.bramble.identity.OutputAuthor
import org.briarproject.briar.api.blog.BlogPostHeader
import org.briarproject.briar.headless.output
import javax.annotation.concurrent.Immutable
@Immutable
@Suppress("unused")
internal class OutputBlogPost(header: BlogPostHeader, val body: String) {
val author: OutputAuthor = OutputAuthor(header.author)
val authorStatus: String = header.authorStatus.output()
val type = header.type.output()
val id: ByteArray = header.id.bytes
val parentId = header.parentId?.bytes
val read = header.isRead
val rssFeed = header.isRssFeed
val timestamp = header.timestamp
val timestampReceived = header.timeReceived
}

View File

@@ -1,39 +0,0 @@
package org.briarproject.briar.headless.contact;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.javalin.Context;
@Immutable
@Singleton
@NotNullByDefault
public class ContactController {
private final ContactManager contactManager;
@Inject
public ContactController(ContactManager contactManager) {
this.contactManager = contactManager;
}
public Context list(Context ctx) throws DbException {
Collection<Contact> contacts = contactManager.getActiveContacts();
List<OutputContact> outputContacts = new ArrayList<>(contacts.size());
for (Contact c : contacts) {
outputContacts.add(new OutputContact(c));
}
return ctx.json(outputContacts);
}
}

View File

@@ -0,0 +1,21 @@
package org.briarproject.briar.headless.contact
import io.javalin.Context
import org.briarproject.bramble.api.contact.ContactManager
import javax.annotation.concurrent.Immutable
import javax.inject.Inject
import javax.inject.Singleton
@Immutable
@Singleton
class ContactController @Inject
constructor(private val contactManager: ContactManager) {
fun list(ctx: Context): Context {
val contacts = contactManager.activeContacts.map { contact ->
contact.output()
}
return ctx.json(contacts)
}
}

View File

@@ -0,0 +1,5 @@
package org.briarproject.briar.headless.contact
import org.briarproject.bramble.api.contact.Contact
internal fun Contact.output() = OutputContact(this)

View File

@@ -1,24 +0,0 @@
package org.briarproject.briar.headless.contact;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.identity.OutputAuthor;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
@SuppressWarnings("WeakerAccess")
public class OutputContact {
public final int id;
public final OutputAuthor author;
public final boolean verified;
public OutputContact(Contact c) {
this.id = c.getId().getInt();
this.author = new OutputAuthor(c.getAuthor());
this.verified = c.isVerified();
}
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.briar.headless.contact
import org.briarproject.bramble.api.contact.Contact
import org.briarproject.briar.headless.output
import javax.annotation.concurrent.Immutable
@Immutable
@Suppress("unused")
internal class OutputContact(c: Contact) {
val id = c.id.int
val author = c.author.output()
val verified = c.isVerified
}

View File

@@ -0,0 +1,7 @@
package org.briarproject.briar.headless.forums
import org.briarproject.briar.api.forum.Forum
internal fun Forum.output() = OutputForum(this)
internal fun Collection<Forum>.output() = map { it.output() }

View File

@@ -1,47 +0,0 @@
package org.briarproject.briar.headless.forums;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.briar.api.forum.Forum;
import org.briarproject.briar.api.forum.ForumManager;
import java.util.Collection;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.javalin.Context;
import static io.javalin.translator.json.JavalinJsonPlugin.getObjectToJsonMapper;
@Immutable
@Singleton
@MethodsNotNullByDefault
@ParametersAreNonnullByDefault
public class ForumController {
private final ForumManager forumManager;
@Inject
public ForumController(ForumManager forumManager) {
this.forumManager = forumManager;
}
public Context list(Context ctx) throws DbException {
Collection<Forum> forums = forumManager.getForums();
return ctx.result(getObjectToJsonMapper().map(forums));
}
public Context create(Context ctx) throws DbException {
String name = ctx.formParam("name");
if (name == null || name.length() < 1) {
return ctx.status(500).result("Expecting Forum Name");
} else {
Forum forum = forumManager.addForum(name);
return ctx.result(getObjectToJsonMapper().map(forum));
}
}
}

View File

@@ -0,0 +1,26 @@
package org.briarproject.briar.headless.forums
import io.javalin.BadRequestResponse
import io.javalin.Context
import org.briarproject.briar.api.forum.ForumManager
import javax.annotation.concurrent.Immutable
import javax.inject.Inject
import javax.inject.Singleton
@Immutable
@Singleton
class ForumController @Inject
constructor(private val forumManager: ForumManager) {
fun list(ctx: Context): Context {
return ctx.json(forumManager.forums.output())
}
fun create(ctx: Context): Context {
val name = ctx.formParam("name")
if (name == null || name.isEmpty())
throw BadRequestResponse("Expecting Forum Name")
return ctx.json(forumManager.addForum(name).output())
}
}

View File

@@ -0,0 +1,13 @@
package org.briarproject.briar.headless.forums
import org.briarproject.briar.api.forum.Forum
import javax.annotation.concurrent.Immutable
@Immutable
@Suppress("unused")
internal class OutputForum(forum: Forum) {
val name: String = forum.name
val id: ByteArray = forum.id.bytes
}

View File

@@ -0,0 +1,8 @@
package org.briarproject.briar.headless.messaging
import org.briarproject.briar.api.messaging.PrivateMessage
import org.briarproject.briar.api.messaging.PrivateMessageHeader
internal fun PrivateMessageHeader.output(body: String) = OutputPrivateMessage(this, body)
internal fun PrivateMessage.output(body: String) = OutputPrivateMessage(this, body)

View File

@@ -1,97 +0,0 @@
package org.briarproject.briar.headless.messaging;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessage;
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.javalin.Context;
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH;
@Immutable
@Singleton
@NotNullByDefault
public class MessagingController {
private final MessagingManager messagingManager;
private final PrivateMessageFactory privateMessageFactory;
private final ContactManager contactManager;
private final Clock clock;
@Inject
public MessagingController(MessagingManager messagingManager,
PrivateMessageFactory privateMessageFactory,
ContactManager contactManager,
Clock clock) {
this.messagingManager = messagingManager;
this.privateMessageFactory = privateMessageFactory;
this.contactManager = contactManager;
this.clock = clock;
}
public Context list(Context ctx) throws DbException {
Contact contact = getContact(ctx);
if (contact == null) return ctx.status(404);
Collection<PrivateMessageHeader> headers =
messagingManager.getMessageHeaders(contact.getId());
List<OutputPrivateMessage> messages = new ArrayList<>(headers.size());
for (PrivateMessageHeader header : headers) {
String body = messagingManager.getMessageBody(header.getId());
messages.add(new OutputPrivateMessage(header, body));
}
return ctx.json(messages);
}
public Context write(Context ctx) throws DbException, FormatException {
Contact contact = getContact(ctx);
if (contact == null) return ctx.status(404);
String message = ctx.formParam("message");
if (message == null || message.length() < 1)
return ctx.status(500).result("Expecting Message text");
if (message.length() > MAX_PRIVATE_MESSAGE_BODY_LENGTH)
return ctx.status(500).result("Message text too large");
Group group = messagingManager.getContactGroup(contact);
long now = clock.currentTimeMillis();
PrivateMessage m = privateMessageFactory
.createPrivateMessage(group.getId(), now, message);
messagingManager.addLocalMessage(m);
return ctx.json(new OutputPrivateMessage(m, message));
}
@Nullable
private Contact getContact(Context ctx) throws DbException {
String contactString = ctx.param("contactId");
if (contactString == null) return null;
int contactInt = Integer.parseInt(contactString);
ContactId contactId = new ContactId(contactInt);
try {
return contactManager.getContact(contactId);
} catch (NoSuchContactException e) {
return null;
}
}
}

View File

@@ -0,0 +1,66 @@
package org.briarproject.briar.headless.messaging
import io.javalin.BadRequestResponse
import io.javalin.Context
import io.javalin.NotFoundResponse
import org.briarproject.bramble.api.contact.Contact
import org.briarproject.bramble.api.contact.ContactId
import org.briarproject.bramble.api.contact.ContactManager
import org.briarproject.bramble.api.db.NoSuchContactException
import org.briarproject.bramble.api.system.Clock
import org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH
import org.briarproject.briar.api.messaging.MessagingManager
import org.briarproject.briar.api.messaging.PrivateMessageFactory
import javax.annotation.concurrent.Immutable
import javax.inject.Inject
import javax.inject.Singleton
@Immutable
@Singleton
class MessagingController @Inject
constructor(
private val messagingManager: MessagingManager,
private val privateMessageFactory: PrivateMessageFactory,
private val contactManager: ContactManager,
private val clock: Clock
) {
fun list(ctx: Context): Context {
val contact = getContact(ctx)
val messages = messagingManager.getMessageHeaders(contact.id).map { header ->
val body = messagingManager.getMessageBody(header.id)
header.output(body)
}
return ctx.json(messages)
}
fun write(ctx: Context): Context {
val contact = getContact(ctx)
val message = ctx.formParam("message")
if (message == null || message.isEmpty())
throw BadRequestResponse("Expecting Message text")
if (message.length > MAX_PRIVATE_MESSAGE_BODY_LENGTH)
throw BadRequestResponse("Message text too large")
val group = messagingManager.getContactGroup(contact)
val now = clock.currentTimeMillis()
val m = privateMessageFactory.createPrivateMessage(group.id, now, message)
messagingManager.addLocalMessage(m)
return ctx.json(m.output(message))
}
private fun getContact(ctx: Context): Contact {
val contactString = ctx.pathParam("contactId")
val contactInt = Integer.parseInt(contactString)
val contactId = ContactId(contactInt)
return try {
contactManager.getContact(contactId)
} catch (e: NoSuchContactException) {
throw NotFoundResponse()
}
}
}

View File

@@ -1,43 +0,0 @@
package org.briarproject.briar.headless.messaging;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.messaging.PrivateMessage;
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
@SuppressWarnings("WeakerAccess")
public class OutputPrivateMessage {
public final String body;
public final long timestamp;
public final boolean read, seen, sent, local;
public final byte[] id, groupId;
OutputPrivateMessage(PrivateMessageHeader header, String body) {
this.body = body;
this.timestamp = header.getTimestamp();
this.read = header.isRead();
this.seen = header.isSeen();
this.sent = header.isSent();
this.local = header.isLocal();
this.id = header.getId().getBytes();
this.groupId = header.getGroupId().getBytes();
}
/**
* Only meant for own {@link PrivateMessage}s directly after creation.
*/
OutputPrivateMessage(PrivateMessage m, String body) {
this.body = body;
this.timestamp = m.getMessage().getTimestamp();
this.read = true;
this.seen = true;
this.sent = false;
this.local = true;
this.id = m.getMessage().getId().getBytes();
this.groupId = m.getMessage().getGroupId().getBytes();
}
}

View File

@@ -0,0 +1,44 @@
package org.briarproject.briar.headless.messaging
import org.briarproject.briar.api.messaging.PrivateMessage
import org.briarproject.briar.api.messaging.PrivateMessageHeader
import javax.annotation.concurrent.Immutable
@Immutable
@Suppress("unused", "MemberVisibilityCanBePrivate")
internal class OutputPrivateMessage {
val body: String
val timestamp: Long
val read: Boolean
val seen: Boolean
val sent: Boolean
val local: Boolean
val id: ByteArray
val groupId: ByteArray
internal constructor(header: PrivateMessageHeader, body: String) {
this.body = body
this.timestamp = header.timestamp
this.read = header.isRead
this.seen = header.isSeen
this.sent = header.isSent
this.local = header.isLocal
this.id = header.id.bytes
this.groupId = header.groupId.bytes
}
/**
* Only meant for own [PrivateMessage]s directly after creation.
*/
internal constructor(m: PrivateMessage, body: String) {
this.body = body
this.timestamp = m.message.timestamp
this.read = true
this.seen = true
this.sent = false
this.local = true
this.id = m.message.id.bytes
this.groupId = m.message.groupId.bytes
}
}