Carbon/src/js/sync/sync.js

140 lines
3.8 KiB
JavaScript

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