import {store} from "../store/store.js" import * as lsm from "../lsm.js" let lastBatch = null function resolveMxc(url, size, method) { const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1) if (size && method) { return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}` } else { return `${lsm.get("domain")}/_matrix/media/r0/download/${server}/${id}` } } function sync() { const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/sync`) url.searchParams.append("access_token", lsm.get("access_token")) const filter = { room: { // pulling more from the timeline massively increases download size timeline: { limit: 5 }, // members are not currently needed state: { lazy_load_members: true } }, presence: { // presence is not implemented, ignore it types: [] } } url.searchParams.append("filter", JSON.stringify(filter)) url.searchParams.append("timeout", 20000) if (lastBatch) { url.searchParams.append("since", lastBatch) } return fetch(url.toString()).then(res => res.json()).then(root => { lastBatch = root.next_batch return root }) } function manageSync(root) { try { let newEvents = false // set up directs const directs = root.account_data.events.find(e => e.type === "m.direct") if (directs) { Object.values(directs.content).forEach(ids => { ids.forEach(id => store.directs.add(id)) }) } // set up rooms Object.entries(root.rooms.join).forEach(([id, room]) => { if (!store.rooms.has(id)) { store.rooms.askAdd(id, room) } const timeline = store.rooms.get(id).value().timeline if (room.timeline.events.length) newEvents = true timeline.updateEvents(room.timeline.events) }) // set up groups Promise.all( Object.keys(root.groups.join).map(id => { if (!store.groups.has(id)) { return Promise.all(["profile", "rooms"].map(path => { const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/groups/${id}/${path}`) url.searchParams.append("access_token", lsm.get("access_token")) return fetch(url.toString()).then(res => res.json()) })).then(([profile, rooms]) => { rooms = rooms.chunk let order = 999 let orderEvent = root.account_data.events.find(e => e.type === "im.vector.web.tag_ordering") if (orderEvent) { if (orderEvent.content.tags.includes(id)) { order = orderEvent.content.tags.indexOf(id) } } const data = { name: profile.name, icon: resolveMxc(profile.avatar_url, 96, "crop"), order } store.groups.askAdd(id, data) rooms.forEach(groupRoom => { if (store.rooms.has(groupRoom.room_id)) { store.rooms.get(groupRoom.room_id).value().setGroup(id) } }) }) } }) ).then(() => { store.rooms.sort() }) if (newEvents) store.newEvents.broadcast("changeSelf") } catch (e) { console.error(root) throw e } } function syncLoop() { return sync().then(manageSync).then(syncLoop) } ;[ { id: "directs", name: "Directs", icon: "/static/directs.svg", order: -2 }, { id: "channels", name: "Channels", icon: "/static/channels.svg", order: -1 } ].forEach(data => store.groups.askAdd(data.id, data)) store.activeGroup.set(store.groups.get("directs").value()) syncLoop()