Skip to content

Instantly share code, notes, and snippets.

@Jimeux
Created December 24, 2021 14:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jimeux/845010dbb23e231edb244a094dda0892 to your computer and use it in GitHub Desktop.
Save Jimeux/845010dbb23e231edb244a094dda0892 to your computer and use it in GitHub Desktop.
import {ref} from "vue"
import {Leave, Message, User, UserList, usernames} from "../data/data"
import {eventBus} from "./eventBus"
import {defineStore} from "pinia"
export const usePiniaStore = defineStore("main", () => {
const connectionId = ref<string | null>()
const currentRecipient = ref<User | null>()
const userList = ref(new Map<string, User>())
const messages = ref(new Map<string, Message[]>())
const unread = ref(new Set<string>())
eventBus.subscribe("ws:open", (event: Event) => {
eventBus.send("user:joined", {
username: usernames[Math.floor(Math.random() * usernames.length)],
})
})
eventBus.subscribe("user:left", (l: Leave) => {
userList.value.delete(l.connectionId)
if (currentRecipient.value?.connectionId === l.connectionId)
currentRecipient.value = null
})
eventBus.subscribe("user:joined", (list: UserList) => {
connectionId.value = list.connectionId
for (const u of list.userList) {
if (
u.connectionId !== list.connectionId &&
!userList.value.has(u.connectionId)
)
userList.value.set(u.connectionId, u)
}
})
eventBus.subscribe("user:message", (m: Message) => {
const key =
m.receiverId === connectionId.value ? m.senderId : m.receiverId
const mm = messages.value.get(key)
if (!mm) messages.value.set(key, [m])
else mm.push(m)
if (currentRecipient.value?.connectionId !== key) {
unread.value.add(key)
} else {
unread.value.delete(key)
}
}
)
function setRecipient(u: User) {
currentRecipient.value = u
unread.value.delete(u.connectionId)
}
function sendMessage(text: string) {
if (currentRecipient.value == null || text.length === 0) return
eventBus.send("user:message", {
message: text,
senderId: connectionId.value,
receiverId: currentRecipient.value.connectionId,
})
}
return {
connectionId,
currentRecipient,
userList,
messages,
unread,
setRecipient,
sendMessage,
}
})
import {App, inject, reactive, readonly} from "vue"
import {Leave, Message, User, UserList, usernames} from "../data/data"
import {eventBus, EventBus} from "./eventBus"
interface State {
connectionId: string | null
userList: Map<string, User>
messages: Map<string, Message[]>
currentRecipient: User | null
unread: Set<string>
}
export class Store {
readonly #bus: EventBus
readonly #state: State
constructor(bus: EventBus, initial: State) {
this.#bus = bus
this.#state = reactive(initial)
bus.subscribe("ws:open", this.onOpen.bind(this))
bus.subscribe("user:left", this.eventUserLeft.bind(this))
bus.subscribe("user:joined", this.eventUserJoined.bind(this))
bus.subscribe("user:message", this.eventUserMessage.bind(this))
}
public install(app: App) {
app.provide(storeKey, this)
}
public get state() {
return readonly(this.#state)
}
public setRecipient(u: User) {
this.#state.currentRecipient = u
this.#state.unread.delete(u.connectionId)
}
public sendMessage(text: string) {
const {connectionId, currentRecipient} = this.#state
if (currentRecipient == null || text.length === 0) return
this.#bus.send("user:message", {
message: text,
senderId: connectionId,
receiverId: currentRecipient.connectionId,
})
}
private onOpen(event: Event) {
this.#bus.send("user:joined", {
username: usernames[Math.floor(Math.random() * usernames.length)],
})
}
private eventUserLeft(l: Leave) {
this.#state.userList.delete(l.connectionId)
if (this.#state.currentRecipient?.connectionId === l.connectionId)
this.#state.currentRecipient = null
}
private eventUserMessage(m: Message) {
const key =
m.receiverId === this.#state.connectionId ? m.senderId : m.receiverId
const mm = this.#state.messages.get(key)
if (!mm) this.#state.messages.set(key, [m])
else mm.push(m)
if (this.#state?.currentRecipient?.connectionId !== key) {
this.#state.unread.add(key)
} else {
this.#state.unread.delete(key)
}
}
private eventUserJoined(list: UserList) {
this.#state.connectionId = list.connectionId
for (const u of list.userList) {
if (
u.connectionId !== list.connectionId &&
!this.#state.userList.has(u.connectionId)
)
this.#state.userList.set(u.connectionId, u)
}
}
}
export const store = new Store(eventBus, {
connectionId: null,
currentRecipient: null,
userList: new Map<string, User>(),
messages: new Map<string, Message[]>(),
unread: new Set<string>(),
})
export const storeKey = Symbol("store")
export function useStore() {
const store = inject<Store>(storeKey)
if (!store) throw new Error("Store was not provided")
return store
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment