diff --git a/examples/cli-chat/package-lock.json b/examples/cli-chat/package-lock.json index 857319b744..6ce0f93968 100644 --- a/examples/cli-chat/package-lock.json +++ b/examples/cli-chat/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "libp2p-tcp": "^0.15.4", "prompt-sync": "^4.2.0", - "waku": "../../build/main/lib" + "waku": "../../build/main" }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", @@ -41,7 +41,10 @@ "node": ">=14" } }, - "../../build/main/lib": {}, + "../../build/main": {}, + "../../build/main/lib": { + "extraneous": true + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -7507,7 +7510,7 @@ "dev": true }, "node_modules/waku": { - "resolved": "../../build/main/lib", + "resolved": "../../build/main", "link": true }, "node_modules/which": { @@ -13561,7 +13564,7 @@ "dev": true }, "waku": { - "version": "file:../../build/main/lib" + "version": "file:../../build/main" }, "which": { "version": "2.0.2", diff --git a/examples/cli-chat/package.json b/examples/cli-chat/package.json index 362586dbfe..2da2cf186d 100644 --- a/examples/cli-chat/package.json +++ b/examples/cli-chat/package.json @@ -33,7 +33,7 @@ "dependencies": { "libp2p-tcp": "^0.15.4", "prompt-sync": "^4.2.0", - "waku": "../../build/main/lib" + "waku": "../../build/main" }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", diff --git a/examples/cli-chat/src/chat.spec.ts b/examples/cli-chat/src/chat.spec.ts index ae26ae36bd..542db920a4 100644 --- a/examples/cli-chat/src/chat.spec.ts +++ b/examples/cli-chat/src/chat.spec.ts @@ -1,12 +1,16 @@ import { expect } from 'chai'; -import { ChatMessage } from 'waku/chat_message'; +import { ChatMessage } from 'waku'; import { formatMessage } from './chat'; describe('CLI Chat app', () => { it('Format message', () => { const date = new Date(234325324); - const chatMessage = new ChatMessage(date, 'alice', 'Hello world!'); + const chatMessage = ChatMessage.fromUtf8String( + date, + 'alice', + 'Hello world!' + ); expect(formatMessage(chatMessage)).to.match(/^<.*> alice: Hello world!$/); }); diff --git a/examples/cli-chat/src/chat.ts b/examples/cli-chat/src/chat.ts index d11f00fdd9..bd83d3def8 100644 --- a/examples/cli-chat/src/chat.ts +++ b/examples/cli-chat/src/chat.ts @@ -3,10 +3,7 @@ import util from 'util'; import TCP from 'libp2p-tcp'; import { multiaddr, Multiaddr } from 'multiaddr'; -import { ChatMessage } from 'waku/chat_message'; -import Waku from 'waku/waku'; -import { WakuMessage } from 'waku/waku_message'; -import { StoreCodec } from 'waku/waku_store'; +import { ChatMessage, StoreCodec, Waku, WakuMessage } from 'waku'; const ChatContentTopic = 'dingpu'; @@ -84,7 +81,7 @@ export default async function startChat(): Promise { rl.prompt(); for await (const line of rl) { rl.prompt(); - const chatMessage = new ChatMessage(new Date(), nick, line); + const chatMessage = ChatMessage.fromUtf8String(new Date(), nick, line); const msg = WakuMessage.fromBytes(chatMessage.encode(), ChatContentTopic); await waku.relay.send(msg); @@ -129,5 +126,5 @@ export function formatMessage(chatMsg: ChatMessage): string { minute: '2-digit', hour12: false, }); - return `<${timestamp}> ${chatMsg.nick}: ${chatMsg.message}`; + return `<${timestamp}> ${chatMsg.nick}: ${chatMsg.payloadAsUtf8}`; } diff --git a/examples/web-chat/package-lock.json b/examples/web-chat/package-lock.json index 7dee8bc327..c0578cdb3a 100644 --- a/examples/web-chat/package-lock.json +++ b/examples/web-chat/package-lock.json @@ -11,7 +11,7 @@ "react": "^16.14.0", "react-dom": "^16.14.0", "server-name-generator": "^1.0.5", - "waku": "../../build/main/lib", + "waku": "../../build/main", "web-vitals": "^1.1.1" }, "devDependencies": { @@ -30,7 +30,10 @@ "typescript": "^4.2.4" } }, - "../../build/main/lib": {}, + "../../build/main": {}, + "../../build/main/lib": { + "extraneous": true + }, "node_modules/@babel/code-frame": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", @@ -22883,7 +22886,7 @@ } }, "node_modules/waku": { - "resolved": "../../build/main/lib", + "resolved": "../../build/main", "link": true }, "node_modules/walker": { @@ -43268,7 +43271,7 @@ } }, "waku": { - "version": "file:../../build/main/lib" + "version": "file:../../build/main" }, "walker": { "version": "1.0.7", diff --git a/examples/web-chat/package.json b/examples/web-chat/package.json index 63b2151c74..fd0172eae6 100644 --- a/examples/web-chat/package.json +++ b/examples/web-chat/package.json @@ -8,7 +8,7 @@ "react": "^16.14.0", "react-dom": "^16.14.0", "server-name-generator": "^1.0.5", - "waku": "../../build/main/lib", + "waku": "../../build/main", "web-vitals": "^1.1.1" }, "devDependencies": { diff --git a/examples/web-chat/src/App.tsx b/examples/web-chat/src/App.tsx index d25a3415fd..5288b0b667 100644 --- a/examples/web-chat/src/App.tsx +++ b/examples/web-chat/src/App.tsx @@ -2,13 +2,9 @@ import { multiaddr } from 'multiaddr'; import PeerId from 'peer-id'; import { useEffect, useState } from 'react'; import './App.css'; -import { ChatMessage } from './ChatMessage'; -import { ChatMessage as WakuChatMessage } from 'waku/chat_message'; -import { WakuMessage } from 'waku/waku_message'; -import { StoreCodec } from 'waku/waku_store'; +import { ChatMessage, WakuMessage, StoreCodec, Waku } from 'waku'; import handleCommand from './command'; import Room from './Room'; -import Waku from 'waku/waku'; import { WakuContext } from './WakuContext'; import { ThemeProvider } from '@livechat/ui-kit'; import { generate } from 'server-name-generator'; @@ -53,9 +49,7 @@ export default function App() { useEffect(() => { const handleRelayMessage = (wakuMsg: WakuMessage) => { if (wakuMsg.payload) { - const chatMsg = ChatMessage.fromWakuChatMessage( - WakuChatMessage.decode(wakuMsg.payload) - ); + const chatMsg = ChatMessage.decode(wakuMsg.payload); if (chatMsg) { setNewMessages([chatMsg]); } @@ -77,10 +71,7 @@ export default function App() { const messages = response .map((wakuMsg) => wakuMsg.payload) .filter((payload) => !!payload) - .map((payload) => WakuChatMessage.decode(payload as Uint8Array)) - .map((wakuChatMessage) => - ChatMessage.fromWakuChatMessage(wakuChatMessage) - ); + .map((payload) => ChatMessage.decode(payload as Uint8Array)); setArchivedMessages(messages); } } catch (e) { @@ -132,7 +123,7 @@ export default function App() { setNick ); const commandMessages = response.map((msg) => { - return new ChatMessage(new Date(), new Date(), command, msg); + return ChatMessage.fromUtf8String(new Date(), command, msg); }); setNewMessages(commandMessages); }} diff --git a/examples/web-chat/src/ChatList.tsx b/examples/web-chat/src/ChatList.tsx index 8a6c076062..a714f86c70 100644 --- a/examples/web-chat/src/ChatList.tsx +++ b/examples/web-chat/src/ChatList.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from 'react'; -import { ChatMessage } from './ChatMessage'; +import { ChatMessage } from 'waku'; import { Message, MessageText, @@ -43,14 +43,14 @@ export default function ChatList(props: Props) { {currentMessageGroup.map((currentMessage) => ( - {currentMessage.message} + {currentMessage.payloadAsUtf8} ))} @@ -84,7 +84,7 @@ function groupMessagesBySender(messageArray: ChatMessage[]): ChatMessage[][] { } function formatDisplayDate(message: ChatMessage): string { - return message.sentTimestamp.toLocaleString([], { + return message.timestamp.toLocaleString([], { month: 'short', day: 'numeric', hour: 'numeric', @@ -127,14 +127,14 @@ function copyMergeUniqueReplace( copy.push(msg); } }); - copy.sort((a, b) => a.sentTimestamp.valueOf() - b.sentTimestamp.valueOf()); + copy.sort((a, b) => a.timestamp.valueOf() - b.timestamp.valueOf()); return copy; } function isEqual(lhs: ChatMessage, rhs: ChatMessage): boolean { return ( lhs.nick === rhs.nick && - lhs.message === rhs.message && - lhs.sentTimestamp.toString() === rhs.sentTimestamp.toString() + lhs.payloadAsUtf8 === rhs.payloadAsUtf8 && + lhs.timestamp.toString() === rhs.timestamp.toString() ); } diff --git a/examples/web-chat/src/ChatMessage.ts b/examples/web-chat/src/ChatMessage.ts deleted file mode 100644 index 8b8f696572..0000000000 --- a/examples/web-chat/src/ChatMessage.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ChatMessage as WakuChatMessage } from 'waku/chat_message'; - -export class ChatMessage { - constructor( - public receivedTimestampMs: Date, - public sentTimestamp: Date, - public nick: string, - public message: string - ) {} - - static fromWakuChatMessage(wakuChatMessage: WakuChatMessage): ChatMessage { - return new ChatMessage( - new Date(), - wakuChatMessage.timestamp, - wakuChatMessage.nick, - wakuChatMessage.message - ); - } -} diff --git a/examples/web-chat/src/Room.tsx b/examples/web-chat/src/Room.tsx index 76ccc5cc4b..25ff6f5859 100644 --- a/examples/web-chat/src/Room.tsx +++ b/examples/web-chat/src/Room.tsx @@ -1,6 +1,4 @@ -import { ChatMessage } from './ChatMessage'; -import { ChatMessage as WakuChatMessage } from 'waku/chat_message'; -import { WakuMessage } from 'waku/waku_message'; +import { ChatMessage, WakuMessage } from 'waku'; import { ChatContentTopic } from './App'; import ChatList from './ChatList'; import MessageInput from './MessageInput'; @@ -54,7 +52,7 @@ async function handleMessage( if (message.startsWith('/')) { commandHandler(message); } else { - const chatMessage = new WakuChatMessage(new Date(), nick, message); + const chatMessage = ChatMessage.fromUtf8String(new Date(), nick, message); const wakuMsg = WakuMessage.fromBytes( chatMessage.encode(), ChatContentTopic diff --git a/examples/web-chat/src/WakuContext.ts b/examples/web-chat/src/WakuContext.ts index 6650c74f5c..eb72723e6d 100644 --- a/examples/web-chat/src/WakuContext.ts +++ b/examples/web-chat/src/WakuContext.ts @@ -1,5 +1,5 @@ import { createContext, useContext } from 'react'; -import Waku from 'waku/waku'; +import { Waku } from 'waku'; export type WakuContextType = { waku?: Waku; diff --git a/examples/web-chat/src/command.ts b/examples/web-chat/src/command.ts index 6704341da0..d59eea32db 100644 --- a/examples/web-chat/src/command.ts +++ b/examples/web-chat/src/command.ts @@ -1,6 +1,6 @@ import { multiaddr } from 'multiaddr'; import PeerId from 'peer-id'; -import Waku from 'waku/waku'; +import { Waku } from 'waku'; function help(): string[] { return [ diff --git a/proto/chat/v2/chat_message.proto b/proto/chat/v2/chat_message.proto index 9d33bec91f..76b9524650 100644 --- a/proto/chat/v2/chat_message.proto +++ b/proto/chat/v2/chat_message.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package chat.v2; -message ChatMessageProto { +message ChatMessage { uint64 timestamp = 1; string nick = 2; bytes payload = 3; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000000..86d529950e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,10 @@ +export { Waku } from './lib/waku'; +export { WakuMessage } from './lib/waku_message'; + +export { ChatMessage } from './lib/chat_message'; + +export { WakuRelay, RelayCodec } from './lib/waku_relay'; + +export { WakuStore, StoreCodec } from './lib/waku_store'; + +export * as proto from './proto'; diff --git a/src/lib/chat_message/index.spec.ts b/src/lib/chat_message/index.spec.ts index 58a34dcb70..af0f05ce07 100644 --- a/src/lib/chat_message/index.spec.ts +++ b/src/lib/chat_message/index.spec.ts @@ -11,14 +11,14 @@ describe('Chat Message', function () { fc.string(), fc.string(), (timestamp, nick, message) => { - const msg = new ChatMessage(timestamp, nick, message); + const msg = ChatMessage.fromUtf8String(timestamp, nick, message); const buf = msg.encode(); const actual = ChatMessage.decode(buf); // Date.toString does not include ms, as we loose this precision by design expect(actual.timestamp.toString()).to.eq(timestamp.toString()); expect(actual.nick).to.eq(nick); - expect(actual.message).to.eq(message); + expect(actual.payloadAsUtf8).to.eq(message); } ) ); diff --git a/src/lib/chat_message/index.ts b/src/lib/chat_message/index.ts index db44448cb2..e12db9462c 100644 --- a/src/lib/chat_message/index.ts +++ b/src/lib/chat_message/index.ts @@ -1,36 +1,54 @@ import { Reader } from 'protobufjs/minimal'; -import { ChatMessageProto } from '../../proto/chat/v2/chat_message'; +import * as proto from '../../proto/chat/v2/chat_message'; -// TODO: Move to waku library? export class ChatMessage { - public constructor( - public timestamp: Date, - public nick: string, - public message: string - ) {} + public constructor(public proto: proto.ChatMessage) {} + + /** + * Create Chat Message with a utf-8 string as payload. + */ + static fromUtf8String( + timestamp: Date, + nick: string, + text: string + ): ChatMessage { + const timestampNumber = Math.floor(timestamp.valueOf() / 1000); + const payload = Buffer.from(text, 'utf-8'); + + return new ChatMessage({ + timestamp: timestampNumber, + nick, + payload, + }); + } static decode(bytes: Uint8Array): ChatMessage { - const protoMsg = ChatMessageProto.decode(Reader.create(bytes)); - const timestamp = new Date(protoMsg.timestamp * 1000); - const message = protoMsg.payload - ? Array.from(protoMsg.payload) - .map((char) => { - return String.fromCharCode(char); - }) - .join('') - : ''; - return new ChatMessage(timestamp, protoMsg.nick, message); + const protoMsg = proto.ChatMessage.decode(Reader.create(bytes)); + return new ChatMessage(protoMsg); } encode(): Uint8Array { - const timestamp = Math.floor(this.timestamp.valueOf() / 1000); - const payload = Buffer.from(this.message, 'utf-8'); + return proto.ChatMessage.encode(this.proto).finish(); + } - return ChatMessageProto.encode({ - timestamp, - nick: this.nick, - payload, - }).finish(); + get timestamp(): Date { + return new Date(this.proto.timestamp * 1000); + } + + get nick(): string { + return this.proto.nick; + } + + get payloadAsUtf8(): string { + if (!this.proto.payload) { + return ''; + } + + return Array.from(this.proto.payload) + .map((char) => { + return String.fromCharCode(char); + }) + .join(''); } } diff --git a/src/lib/waku.spec.ts b/src/lib/waku.spec.ts index a0ee871d85..c0fe3b982a 100644 --- a/src/lib/waku.spec.ts +++ b/src/lib/waku.spec.ts @@ -8,7 +8,7 @@ import { NOISE_KEY_2, } from '../test_utils/'; -import Waku from './waku'; +import { Waku } from './waku'; import { RelayCodec } from './waku_relay'; describe('Waku Dial', function () { diff --git a/src/lib/waku.ts b/src/lib/waku.ts index d00e04e337..ee194e2a86 100644 --- a/src/lib/waku.ts +++ b/src/lib/waku.ts @@ -21,7 +21,7 @@ export type CreateOptions = } | (Libp2pOptions & import('libp2p').CreateOptions); -export default class Waku { +export class Waku { public libp2p: Libp2p; public relay: WakuRelay; public store: WakuStore; diff --git a/src/lib/waku_relay/index.spec.ts b/src/lib/waku_relay/index.spec.ts index 1b5a3d4609..eb0303b2aa 100644 --- a/src/lib/waku_relay/index.spec.ts +++ b/src/lib/waku_relay/index.spec.ts @@ -8,7 +8,7 @@ import { NOISE_KEY_2, } from '../../test_utils'; import { delay } from '../delay'; -import Waku from '../waku'; +import { Waku } from '../waku'; import { WakuMessage } from '../waku_message'; import { RelayCodec, RelayDefaultTopic } from './index'; diff --git a/src/lib/waku_relay/index.ts b/src/lib/waku_relay/index.ts index 495bdda27b..2b21a42b3f 100644 --- a/src/lib/waku_relay/index.ts +++ b/src/lib/waku_relay/index.ts @@ -19,11 +19,11 @@ import PeerId from 'peer-id'; import { WakuMessage } from '../waku_message'; import * as constants from './constants'; +import { RelayCodec, RelayDefaultTopic } from './constants'; import { getRelayPeers } from './get_relay_peers'; import { RelayHeartbeat } from './relay_heartbeat'; -export * from './constants'; -export * from './relay_heartbeat'; +export { RelayCodec, RelayDefaultTopic }; /** * See {GossipOptions} from libp2p-gossipsub diff --git a/src/lib/waku_store/index.spec.ts b/src/lib/waku_store/index.spec.ts index a4a20a2528..2f2d3f17f2 100644 --- a/src/lib/waku_store/index.spec.ts +++ b/src/lib/waku_store/index.spec.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import TCP from 'libp2p-tcp'; import { makeLogFileName, NimWaku, NOISE_KEY_1 } from '../../test_utils'; -import Waku from '../waku'; +import { Waku } from '../waku'; import { WakuMessage } from '../waku_message'; describe('Waku Store', () => { diff --git a/src/proto/chat/v2/chat_message.ts b/src/proto/chat/v2/chat_message.ts index 1d25d85cdf..9715ae63b7 100644 --- a/src/proto/chat/v2/chat_message.ts +++ b/src/proto/chat/v2/chat_message.ts @@ -4,17 +4,17 @@ import _m0 from 'protobufjs/minimal'; export const protobufPackage = 'chat.v2'; -export interface ChatMessageProto { +export interface ChatMessage { timestamp: number; nick: string; payload: Uint8Array; } -const baseChatMessageProto: object = { timestamp: 0, nick: '' }; +const baseChatMessage: object = { timestamp: 0, nick: '' }; -export const ChatMessageProto = { +export const ChatMessage = { encode( - message: ChatMessageProto, + message: ChatMessage, writer: _m0.Writer = _m0.Writer.create() ): _m0.Writer { if (message.timestamp !== 0) { @@ -29,10 +29,10 @@ export const ChatMessageProto = { return writer; }, - decode(input: _m0.Reader | Uint8Array, length?: number): ChatMessageProto { + decode(input: _m0.Reader | Uint8Array, length?: number): ChatMessage { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; - const message = { ...baseChatMessageProto } as ChatMessageProto; + const message = { ...baseChatMessage } as ChatMessage; message.payload = new Uint8Array(); while (reader.pos < end) { const tag = reader.uint32(); @@ -54,8 +54,8 @@ export const ChatMessageProto = { return message; }, - fromJSON(object: any): ChatMessageProto { - const message = { ...baseChatMessageProto } as ChatMessageProto; + fromJSON(object: any): ChatMessage { + const message = { ...baseChatMessage } as ChatMessage; message.payload = new Uint8Array(); if (object.timestamp !== undefined && object.timestamp !== null) { message.timestamp = Number(object.timestamp); @@ -73,7 +73,7 @@ export const ChatMessageProto = { return message; }, - toJSON(message: ChatMessageProto): unknown { + toJSON(message: ChatMessage): unknown { const obj: any = {}; message.timestamp !== undefined && (obj.timestamp = message.timestamp); message.nick !== undefined && (obj.nick = message.nick); @@ -84,8 +84,8 @@ export const ChatMessageProto = { return obj; }, - fromPartial(object: DeepPartial): ChatMessageProto { - const message = { ...baseChatMessageProto } as ChatMessageProto; + fromPartial(object: DeepPartial): ChatMessage { + const message = { ...baseChatMessage } as ChatMessage; if (object.timestamp !== undefined && object.timestamp !== null) { message.timestamp = object.timestamp; } else { diff --git a/src/proto/index.ts b/src/proto/index.ts new file mode 100644 index 0000000000..22440dad58 --- /dev/null +++ b/src/proto/index.ts @@ -0,0 +1,13 @@ +export { ChatMessage } from './chat/v2/chat_message'; + +export { WakuMessage } from './waku/v2/message'; + +export { + Index, + PagingInfo, + PagingInfo_Direction, + ContentFilter, + HistoryQuery, + HistoryResponse, + HistoryRPC, +} from './waku/v2/store';