Carbon/src/js/sync/sync.js

152 lines
4.1 KiB
JavaScript

const {store} = require("../store/store.js")
const lsm = require("../lsm.js")
const {resolveMxc} = require("../functions.js")
let lastBatch = null
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: 1
},
// 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
let notificationsChange = false
// set up directs
if (root.account_data) {
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
if (root.rooms) {
if (root.rooms.join) {
Object.entries(root.rooms.join).forEach(([id, data]) => {
if (!store.rooms.has(id)) {
store.rooms.askAdd(id, data)
}
const room = store.rooms.get(id).value()
const timeline = room.timeline
if (data.state && data.state.events) timeline.updateStateEvents(data.state.events)
if (data.timeline && data.timeline.events) {
if (!timeline.from) timeline.from = data.timeline.prev_batch
if (data.timeline.events.length) {
newEvents = true
timeline.updateEvents(data.timeline.events)
}
}
if (data.ephemeral && data.ephemeral.events) timeline.updateEphemeral(data.ephemeral.events)
if (data.unread_notifications) {
timeline.updateNotificationCount(data.unread_notifications.notification_count)
notificationsChange = true
}
if (data["org.matrix.msc2654.unread_count"] != undefined) {
timeline.updateUnreadCount(data["org.matrix.msc2654.unread_count"])
notificationsChange = true
}
})
}
}
// set up groups
if (root.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)
}
})
store.newEvents.broadcast("changeSelf") // trigger a room list update
})
}
})
).then(() => {
store.rooms.sort()
})
}
if (newEvents) store.newEvents.broadcast("changeSelf")
if (notificationsChange) store.notificationsChange.broadcast("changeSelf")
} catch (e) {
console.error(root)
throw e
}
}
function syncLoop() {
return sync().then(manageSync).then(syncLoop)
}
;[
{
id: "directs",
name: "Directs",
icon: staticFiles.get("/assets/icons/directs.svg"),
order: -2
},
{
id: "channels",
name: "Channels",
icon: staticFiles.get("/assets/icons/channels.svg"),
order: -1
}
].forEach(data => store.groups.askAdd(data.id, data))
store.activeGroup.set(store.groups.get("directs").value())
if (lsm.get("access_token")) {
syncLoop()
}