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();