From 8a80b20471cb7815740776a7dd05a8422f40ce13 Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Tue, 18 Feb 2020 15:49:47 +0000 Subject: [PATCH] Add message nonces. --- package.json | 1 + src/Client.ts | 4 ++++ src/api/channels.ts | 2 ++ src/objects/Channel.ts | 49 ++++++++++++++++++++++++++++++------------ src/objects/Message.ts | 28 ++++++++++++++++++++++++ src/tester.ts | 7 ++++++ yarn.lock | 5 +++++ 7 files changed, 82 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index a0a9958b..8196d9e5 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "isomorphic-ws": "^4.0.1", "lodash": "^4.17.15", "tsc-watch": "^4.1.0", + "ulid": "^2.3.0", "ws": "^7.2.1" }, "devDependencies": { diff --git a/src/Client.ts b/src/Client.ts index 9b8fb5b5..fc1454ec 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -91,6 +91,10 @@ export class Client extends EventEmitter { let m = packet.data as RawMessage & { channel: string }; let channel = await this.findChannel(m.channel); + if (m.nonce) { + channel.messages.delete(m.nonce); + } + this.emit('message', await Message.from(m.id, channel, m)); } break; diff --git a/src/api/channels.ts b/src/api/channels.ts index 661c58bb..735082d0 100644 --- a/src/api/channels.ts +++ b/src/api/channels.ts @@ -27,6 +27,7 @@ export type RawChannel = { export type RawMessage = { id: string, + nonce?: string, author: string, content: string, edited: number | null, @@ -42,6 +43,7 @@ export namespace Channels { // POST /:id/messages export interface SendMessageRequest extends Request { content: string, + nonce: string, } export interface SendMessageResponse extends Response { diff --git a/src/objects/Channel.ts b/src/objects/Channel.ts index bc481390..e28b8dcb 100644 --- a/src/objects/Channel.ts +++ b/src/objects/Channel.ts @@ -2,6 +2,7 @@ import { Channels, ChannelType } from '../api'; import { Client } from '../Client'; import { User } from './User'; import { Message } from './Message'; +import { ulid } from 'ulid'; export class Channel { client: Client; @@ -69,21 +70,41 @@ export class Channel { return messages; } - async sendMessage(content: string) { - let res = await this.client.$req('POST', '/channels/' + this.id + '/messages', { content }); + sendMessage(content: string): [ Message, Promise ] { + if (content.length > 2000) + throw new Error("Message too long! > 2000 characters."); - if (res.success) { - let message = new Message(this, { - id: res.id, - author: this.client.userId as string, - content, - edited: null - }); + let nonce = ulid(); + let message = new Message(this, { + id: nonce, + nonce, + author: this.client.userId as string, + content, + edited: null + }); - this.messages.set(this.id, message); - return message; - } else { - throw new Error(res.error); - } + this.messages.set(nonce, message); + + return [ + message, + (async () => { + let res = await this.client.$req('POST', '/channels/' + this.id + '/messages', { content, nonce }); + if (res.success) { + this.messages.delete(nonce); + Message.from(res.id, this, + { + id: this.id, + author: this.client.userId as string, + content, + edited: null, + } + ); + + return message; + } else { + throw new Error(res.error); + } + })() + ] } } diff --git a/src/objects/Message.ts b/src/objects/Message.ts index 16db020d..e19e6b2c 100644 --- a/src/objects/Message.ts +++ b/src/objects/Message.ts @@ -8,10 +8,19 @@ export interface MessageSnapshot { content: string, } +export enum Sent { + UNSENT, + SENT, + FAILED, +} + export class Message { channel: Channel; id: string; + nonce: string; + sent: Sent; + user: User; content: string; edited: Date | null; @@ -20,6 +29,7 @@ export class Message { constructor(channel: Channel, data: RawMessage) { this.channel = channel; + this.sent = Sent.UNSENT; this.update(data); } @@ -57,12 +67,21 @@ export class Message { message = new Message(channel, await channel.client.$req('GET', '/channels/' + channel.id + '/messages/' + id)); } + message.sent = Sent.SENT; await message.$init(); channel.messages.set(id, message); return message; } async edit(content: string) { + if (this.sent === Sent.FAILED) { + throw new Error("Cannot edit failed message!"); + } + + if (this.sent === Sent.UNSENT) { + throw new Error("Cannot delete unsent message!"); + } + let res = await this.channel.client.$req('PATCH', '/channels/' + this.channel.id + '/messages/' + this.id, { content }); if (res.success) { @@ -73,6 +92,15 @@ export class Message { } async delete() { + if (this.sent === Sent.FAILED) { + this.channel.messages.delete(this.id); + return; + } + + if (this.sent === Sent.UNSENT) { + throw new Error("Cannot delete unsent message!"); + } + let res = await this.channel.client.$req('DELETE', '/channels/' + this.channel.id + '/messages/' + this.id); if (res.success) { diff --git a/src/tester.ts b/src/tester.ts index 7cae4b68..7d0427ef 100644 --- a/src/tester.ts +++ b/src/tester.ts @@ -7,6 +7,13 @@ let client = new Client(); client.on('ready', () => { console.log(`Logged in as ${client.user?.username}!`); + + /*client.findChannel('01E1CDFQ4QWT93Q2Z6YWVTW2ND') + .then(async x => { + let [ temp, next ] = x.sendMessage('bruh'); + await next; + console.log(Array.from(x.messages.values()).map(x => x.id)); + })*/ }); client.on('message', msg => { diff --git a/yarn.lock b/yarn.lock index 5d8415bd..8aa849a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -503,6 +503,11 @@ typescript@^3.8.0-dev.20200208: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.0-dev.20200208.tgz#3cd1ee025932c88ff78831f3629e99b1995e1de5" integrity sha512-/n4f+RIfoHvEmXprHjE7dHzGlDzD0wpqpvHBXBtwaCi1wp8zsGqA07v1UPijR1xBqumO5FFDMEPIuu7fEDJemA== +ulid@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" + integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"