Skip to content

Commit

Permalink
feat: support offline message sync molvqingtai#45
Browse files Browse the repository at this point in the history
  • Loading branch information
molvqingtai committed Nov 3, 2024
1 parent 96b6cd5 commit 7c4f655
Show file tree
Hide file tree
Showing 13 changed files with 297 additions and 84 deletions.
2 changes: 1 addition & 1 deletion src/app/content/components/MessageItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const MessageItem: FC<MessageItemProps> = (props) => {
<div className="overflow-hidden">
<div className="grid grid-cols-[1fr_auto] items-center gap-x-2 leading-none">
<div className="truncate text-sm font-semibold text-slate-600 dark:text-slate-50">{props.data.username}</div>
<FormatDate className="text-xs text-slate-400 dark:text-slate-100" date={props.data.date}></FormatDate>
<FormatDate className="text-xs text-slate-400 dark:text-slate-100" date={props.data.receiveTime}></FormatDate>
</div>
<div>
<div className="pb-2">
Expand Down
14 changes: 7 additions & 7 deletions src/app/content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ export default defineContentScript({
container.append(app)
const root = createRoot(app)
root.render(
<React.StrictMode>
<RemeshRoot store={store}>
<RemeshScope domains={[NotificationDomain()]}>
<App />
</RemeshScope>
</RemeshRoot>
</React.StrictMode>
// <React.StrictMode>
<RemeshRoot store={store}>
<RemeshScope domains={[NotificationDomain()]}>
<App />
</RemeshScope>
</RemeshRoot>
// </React.StrictMode>
)
return root
},
Expand Down
11 changes: 9 additions & 2 deletions src/app/content/views/Footer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import MessageInput from '../../components/MessageInput'
import EmojiButton from '../../components/EmojiButton'
import { Button } from '@/components/ui/Button'
import MessageInputDomain from '@/domain/MessageInput'
import { MESSAGE_MAX_LENGTH } from '@/constants/config'
import { MESSAGE_MAX_LENGTH, WEB_RTC_MAX_MESSAGE_SIZE } from '@/constants/config'
import RoomDomain from '@/domain/Room'
import useCursorPosition from '@/hooks/useCursorPosition'
import useShareRef from '@/hooks/useShareRef'
Expand All @@ -15,7 +15,7 @@ import useTriggerAway from '@/hooks/useTriggerAway'
import { ScrollArea } from '@/components/ui/ScrollArea'
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso'
import UserInfoDomain from '@/domain/UserInfo'
import { blobToBase64, cn, compressImage, getRootNode, getTextSimilarity } from '@/utils'
import { blobToBase64, cn, compressImage, getRootNode, getTextByteSize, getTextSimilarity } from '@/utils'
import { Avatar, AvatarFallback } from '@/components/ui/Avatar'
import { AvatarImage } from '@radix-ui/react-avatar'
import ToastDomain from '@/domain/Toast'
Expand Down Expand Up @@ -136,6 +136,13 @@ const Footer: FC = () => {
})
.filter(Boolean)

const newMessage = { body: transformedMessage, atUsers }
const byteSize = getTextByteSize(JSON.stringify(newMessage))

if (byteSize > WEB_RTC_MAX_MESSAGE_SIZE) {
return send(toastDomain.command.WarningCommand('Message size cannot exceed 256KiB.'))
}

send(roomDomain.command.SendTextMessageCommand({ body: transformedMessage, atUsers }))
send(messageInputDomain.command.ClearCommand())
}
Expand Down
20 changes: 11 additions & 9 deletions src/app/content/views/Main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@ const Main: FC = () => {
const userInfoDomain = useRemeshDomain(UserInfoDomain())
const userInfo = useRemeshQuery(userInfoDomain.query.UserInfoQuery())
const _messageList = useRemeshQuery(messageListDomain.query.ListQuery())
const messageList = _messageList.map((message) => {
if (message.type === MessageType.Normal) {
return {
...message,
like: message.likeUsers.some((likeUser) => likeUser.userId === userInfo?.id),
hate: message.hateUsers.some((hateUser) => hateUser.userId === userInfo?.id)
const messageList = _messageList
.map((message) => {
if (message.type === MessageType.Normal) {
return {
...message,
like: message.likeUsers.some((likeUser) => likeUser.userId === userInfo?.id),
hate: message.hateUsers.some((hateUser) => hateUser.userId === userInfo?.id)
}
}
}
return message
})
return message
})
.toSorted((a, b) => a.worldTime - b.worldTime)

const handleLikeChange = (messageId: string) => {
send(roomDomain.command.SendLikeMessageCommand(messageId))
Expand Down
15 changes: 6 additions & 9 deletions src/app/content/views/Setup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ const mockTextList = [
`![ExampleImage](${ExampleImage})`
]

let printTextList = [...mockTextList]

const generateUserInfo = async (): Promise<UserInfo> => {
return {
id: nanoid(),
Expand All @@ -52,8 +50,10 @@ const generateMessage = async (userInfo: UserInfo): Promise<Message> => {
const { name: username, avatar: userAvatar, id: userId } = userInfo
return {
id: nanoid(),
body: printTextList.shift()!,
date: Date.now(),
body: mockTextList.shift()!,
sendTime: Date.now(),
receiveTime: Date.now(),
worldTime: Date.now(),
type: MessageType.Normal,
userId,
username,
Expand Down Expand Up @@ -87,19 +87,16 @@ const Setup: FC = () => {
}

useEffect(() => {
printTextList.length === 0 && (printTextList = [...mockTextList])
const timer = new Timer(
async () => {
await createMessage(await refreshUserInfo())
},
{ delay: 2000, immediate: true, limit: printTextList.length }
{ delay: 2000, immediate: true, limit: mockTextList.length }
)
timer.on('stop', () => {
printTextList.length === 0 && send(messageListDomain.command.ClearListCommand())
})
timer.start()
return () => {
timer.stop()
send(messageListDomain.command.ClearListCommand())
}
}, [])

Expand Down
8 changes: 8 additions & 0 deletions src/constants/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,11 @@ export const APP_STATUS_STORAGE_KEY = 'WEB_CHAT_APP_STATUS' as const
* 8kb * (1 - 0.33) = 5488 bytes
*/
export const MAX_AVATAR_SIZE = 5120 as const

export const SYNC_HISTORY_MAX_DAYS = 30 as const

/**
* https://lgrahl.de/articles/demystifying-webrtc-dc-size-limit.html
* Message max size is 256KiB; if the message is too large, it will cause the connection to drop.
*/
export const WEB_RTC_MAX_MESSAGE_SIZE = 262144 as const
46 changes: 43 additions & 3 deletions src/domain/MessageList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export interface NormalMessage extends MessageUser {
type: MessageType.Normal
id: string
body: string
date: number
sendTime: number
receiveTime: number
worldTime: number
likeUsers: MessageUser[]
hateUsers: MessageUser[]
atUsers: AtUser[]
Expand All @@ -34,7 +36,9 @@ export interface PromptMessage extends MessageUser {
type: MessageType.Prompt
id: string
body: string
date: number
sendTime: number
receiveTime: number
worldTime: number
}

export type Message = NormalMessage | PromptMessage
Expand Down Expand Up @@ -120,6 +124,38 @@ const MessageListDomain = Remesh.domain({
}
})

const UpsertItemCommand = domain.command({
name: 'MessageList.UpsertItemCommand',
impl: (_, message: Message) => {
return [
MessageListModule.command.UpsertItemCommand(message),
UpsertItemEvent(message),
ChangeListEvent(),
SyncToStorageEvent()
]
}
})

const UpsertItemEvent = domain.event<Message>({
name: 'MessageList.UpsertItemEvent'
})

const ResetListCommand = domain.command({
name: 'MessageList.ResetListCommand',
impl: (_, messages: Message[]) => {
return [
MessageListModule.command.SetListCommand(messages),
ResetListEvent(messages),
ChangeListEvent(),
SyncToStorageEvent()
]
}
})

const ResetListEvent = domain.event<Message[]>({
name: 'MessageList.ResetListEvent'
})

const ClearListEvent = domain.event({
name: 'MessageList.ClearListEvent'
})
Expand Down Expand Up @@ -164,14 +200,18 @@ const MessageListDomain = Remesh.domain({
CreateItemCommand,
UpdateItemCommand,
DeleteItemCommand,
ClearListCommand
UpsertItemCommand,
ClearListCommand,
ResetListCommand
},
event: {
ChangeListEvent,
CreateItemEvent,
UpdateItemEvent,
DeleteItemEvent,
UpsertItemEvent,
ClearListEvent,
ResetListEvent,
SyncToStateEvent,
SyncToStorageEvent
}
Expand Down
Loading

0 comments on commit 7c4f655

Please sign in to comment.