client: use prettier; add README

This commit is contained in:
Kegan Dougal 2022-02-23 19:26:38 +00:00
parent 3867cece40
commit 808d7f8d21
8 changed files with 231 additions and 90 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/syncv3 /syncv3
node_modules

13
client/README.md Normal file
View File

@ -0,0 +1,13 @@
## Sliding Sync Client
![Client](./client.png)
This is a basic JS client for Sliding Sync. It is designed to be easily readable and is aimed at
developers who want to implement Sliding Sync into their clients. The client is broken up into:
- `devtools.js` : Code for showing developer statistics.
- `index.js` : Entry point for the client and hooks into the DOM.
- `render.js` : Code to convert data structures into DOM nodes.
- `sync.js` : Sliding Sync code.
To understand sliding sync, you need to read `index.js` and `sync.js`. The rest of it can be ignored.

BIN
client/client.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

View File

@ -1,14 +1,17 @@
// This file contains code to render the developer tools overlay (bandwidth, list visualisations, etc) // This file contains code to render the developer tools overlay (bandwidth, list visualisations, etc)
// You don't need to read this file to understand sliding sync. // You don't need to read this file to understand sliding sync.
/** /**
* Set the bandwidth values on the devtools display. * Set the bandwidth values on the devtools display.
* @param {Element} domNode The node to insert the bandwidth stats to. * @param {Element} domNode The node to insert the bandwidth stats to.
* @param {SlidingSyncConnection} conn The sliding sync connection * @param {SlidingSyncConnection} conn The sliding sync connection
*/ */
export function bandwidth(domNode, conn) { export function bandwidth(domNode, conn) {
domNode.textContent = (conn.txBytes/1024.0).toFixed(2) + " KB Tx / " + (conn.rxBytes/1024.0).toFixed(2) + " KB Rx"; domNode.textContent =
(conn.txBytes / 1024.0).toFixed(2) +
" KB Tx / " +
(conn.rxBytes / 1024.0).toFixed(2) +
" KB Rx";
} }
/** /**
@ -38,8 +41,9 @@ export function svgify(domNode, activeLists, resp) {
if (al.joinedCount > height) { if (al.joinedCount > height) {
height = al.joinedCount; height = al.joinedCount;
} }
}) });
if (height < (window.innerHeight/2)) { // we can double the vertical pixel height to make it easier to see if (height < window.innerHeight / 2) {
// we can double the vertical pixel height to make it easier to see
verticalPixelHeight = 2; verticalPixelHeight = 2;
} }
svg.setAttribute("height", height * verticalPixelHeight); svg.setAttribute("height", height * verticalPixelHeight);
@ -52,34 +56,52 @@ export function svgify(domNode, activeLists, resp) {
const colorInvalidate = "#500000"; const colorInvalidate = "#500000";
const colorRoom = "#ffffff"; const colorRoom = "#ffffff";
activeLists.forEach((al, index) => { activeLists.forEach((al, index) => {
const placeholders = document.createElementNS("http://www.w3.org/2000/svg",'rect'); const placeholders = document.createElementNS(
placeholders.setAttribute("x", index*2*horizontalPixelWidth); "http://www.w3.org/2000/svg",
"rect"
);
placeholders.setAttribute("x", index * 2 * horizontalPixelWidth);
placeholders.setAttribute("y", 0); placeholders.setAttribute("y", 0);
placeholders.setAttribute("width", horizontalPixelWidth); placeholders.setAttribute("width", horizontalPixelWidth);
placeholders.setAttribute("height", al.joinedCount * verticalPixelHeight); placeholders.setAttribute(
placeholders.setAttribute('fill', colorPlaceholder); "height",
al.joinedCount * verticalPixelHeight
);
placeholders.setAttribute("fill", colorPlaceholder);
svg.appendChild(placeholders); svg.appendChild(placeholders);
// [[0, 20], [50,60]]; // [[0, 20], [50,60]];
al.activeRanges.forEach((range) => { al.activeRanges.forEach((range) => {
const rect = document.createElementNS("http://www.w3.org/2000/svg",'rect'); const rect = document.createElementNS(
rect.setAttribute('x',index*2*horizontalPixelWidth); "http://www.w3.org/2000/svg",
rect.setAttribute('y',range[0]*verticalPixelHeight); "rect"
rect.setAttribute('width',horizontalPixelWidth); );
rect.setAttribute('height',(range[1]-range[0]) * verticalPixelHeight); rect.setAttribute("x", index * 2 * horizontalPixelWidth);
rect.setAttribute('fill',colorInWindow); rect.setAttribute("y", range[0] * verticalPixelHeight);
rect.setAttribute("width", horizontalPixelWidth);
rect.setAttribute(
"height",
(range[1] - range[0]) * verticalPixelHeight
);
rect.setAttribute("fill", colorInWindow);
svg.appendChild(rect); svg.appendChild(rect);
}); });
}); });
const addLine = (index, y, colour, yLen) => { const addLine = (index, y, colour, yLen) => {
const bar = document.createElementNS("http://www.w3.org/2000/svg",'rect'); const bar = document.createElementNS(
bar.setAttribute("x", index*2*horizontalPixelWidth); "http://www.w3.org/2000/svg",
bar.setAttribute("y", y*verticalPixelHeight); "rect"
bar.setAttribute('width',horizontalPixelWidth); );
bar.setAttribute('height',verticalPixelHeight*(yLen?yLen:1)); bar.setAttribute("x", index * 2 * horizontalPixelWidth);
bar.setAttribute('fill', colour); bar.setAttribute("y", y * verticalPixelHeight);
const animation = document.createElementNS("http://www.w3.org/2000/svg","animate"); bar.setAttribute("width", horizontalPixelWidth);
bar.setAttribute("height", verticalPixelHeight * (yLen ? yLen : 1));
bar.setAttribute("fill", colour);
const animation = document.createElementNS(
"http://www.w3.org/2000/svg",
"animate"
);
animation.setAttribute("attributeName", "visibility"); animation.setAttribute("attributeName", "visibility");
animation.setAttribute("from", "visible"); animation.setAttribute("from", "visible");
animation.setAttribute("to", "hidden"); animation.setAttribute("to", "hidden");
@ -87,7 +109,7 @@ export function svgify(domNode, activeLists, resp) {
animation.setAttribute("repeatCount", "3"); animation.setAttribute("repeatCount", "3");
bar.appendChild(animation); bar.appendChild(animation);
svg.appendChild(bar); svg.appendChild(bar);
} };
// add insertions, deletions and updates // add insertions, deletions and updates
resp.ops.forEach((op) => { resp.ops.forEach((op) => {
@ -98,24 +120,40 @@ export function svgify(domNode, activeLists, resp) {
} else if (op.op === "UPDATE") { } else if (op.op === "UPDATE") {
addLine(op.list, op.index, colorUpdate); addLine(op.list, op.index, colorUpdate);
} else if (op.op === "SYNC") { } else if (op.op === "SYNC") {
addLine(op.list, op.range[0], colorSync, op.range[1]-op.range[0]+1); addLine(
op.list,
op.range[0],
colorSync,
op.range[1] - op.range[0] + 1
);
} else if (op.op === "INVALIDATE") { } else if (op.op === "INVALIDATE") {
addLine(op.list, op.range[0], colorInvalidate, op.range[1]-op.range[0]+1); addLine(
op.list,
op.range[0],
colorInvalidate,
op.range[1] - op.range[0] + 1
);
} }
}); });
// this is expensive so only do it on smaller accounts // this is expensive so only do it on smaller accounts
if (height < 500 && false) { if (height < 500 && false) {
const fifth = horizontalPixelWidth/5; const fifth = horizontalPixelWidth / 5;
// draw white dot for each room which has some kind of data stored // draw white dot for each room which has some kind of data stored
activeLists.forEach((al, index) => { activeLists.forEach((al, index) => {
for (let roomIndex of Object.keys(al.roomIndexToRoomId)) { for (let roomIndex of Object.keys(al.roomIndexToRoomId)) {
const roomPixel = document.createElementNS("http://www.w3.org/2000/svg",'rect'); const roomPixel = document.createElementNS(
roomPixel.setAttribute("x", index*2*horizontalPixelWidth + fifth); "http://www.w3.org/2000/svg",
roomPixel.setAttribute("y", roomIndex*verticalPixelHeight); "rect"
roomPixel.setAttribute('width',fifth); );
roomPixel.setAttribute('height',verticalPixelHeight); roomPixel.setAttribute(
roomPixel.setAttribute('fill', colorRoom); "x",
index * 2 * horizontalPixelWidth + fifth
);
roomPixel.setAttribute("y", roomIndex * verticalPixelHeight);
roomPixel.setAttribute("width", fifth);
roomPixel.setAttribute("height", verticalPixelHeight);
roomPixel.setAttribute("fill", colorRoom);
svg.appendChild(roomPixel); svg.appendChild(roomPixel);
} }
}); });

View File

@ -1,7 +1,7 @@
// This file contains the entry point for the client, as well as DOM interactions. // This file contains the entry point for the client, as well as DOM interactions.
import { SlidingList, SlidingSyncConnection } from './sync.js'; import { SlidingList, SlidingSyncConnection } from "./sync.js";
import * as render from './render.js'; import * as render from "./render.js";
import * as devtools from './devtools.js'; import * as devtools from "./devtools.js";
let activeSessionId; let activeSessionId;
let activeRoomId = ""; // the room currently being viewed let activeRoomId = ""; // the room currently being viewed
@ -125,14 +125,18 @@ const intersectionObserver = new IntersectionObserver(
listIndexToStartEnd[listIndex].endIndex = i; listIndexToStartEnd[listIndex].endIndex = i;
} }
}); });
console.log("Intersection indexes:", JSON.stringify(listIndexToStartEnd)); console.log(
"Intersection indexes:",
JSON.stringify(listIndexToStartEnd)
);
// buffer range // buffer range
const bufferRange = 5; const bufferRange = 5;
Object.keys(listIndexToStartEnd).forEach((listIndex) => { Object.keys(listIndexToStartEnd).forEach((listIndex) => {
let startIndex = listIndexToStartEnd[listIndex].startIndex; let startIndex = listIndexToStartEnd[listIndex].startIndex;
let endIndex = listIndexToStartEnd[listIndex].endIndex; let endIndex = listIndexToStartEnd[listIndex].endIndex;
startIndex = startIndex - bufferRange < 0 ? 0 : startIndex - bufferRange; startIndex =
startIndex - bufferRange < 0 ? 0 : startIndex - bufferRange;
endIndex = endIndex =
endIndex + bufferRange >= activeLists[listIndex].joinedCount endIndex + bufferRange >= activeLists[listIndex].joinedCount
? activeLists[listIndex].joinedCount - 1 ? activeLists[listIndex].joinedCount - 1
@ -212,15 +216,20 @@ const renderRoomContent = (roomId, refresh) => {
} }
let room = rooms.roomIdToRoom[activeRoomId]; let room = rooms.roomIdToRoom[activeRoomId];
if (!room) { if (!room) {
console.error("renderRoomContent: unknown active room ID ", activeRoomId); console.error(
"renderRoomContent: unknown active room ID ",
activeRoomId
);
return; return;
} }
document.getElementById("selectedroomname").textContent = room.name || room.room_id; document.getElementById("selectedroomname").textContent =
room.name || room.room_id;
if (room.avatar) { if (room.avatar) {
document.getElementById("selectedroomavatar").src = document.getElementById("selectedroomavatar").src =
mxcToUrl(room.avatar) || "/client/placeholder.svg"; mxcToUrl(room.avatar) || "/client/placeholder.svg";
} else { } else {
document.getElementById("selectedroomavatar").src = "/client/placeholder.svg"; document.getElementById("selectedroomavatar").src =
"/client/placeholder.svg";
} }
if (room.topic) { if (room.topic) {
document.getElementById("selectedroomtopic").textContent = room.topic; document.getElementById("selectedroomtopic").textContent = room.topic;
@ -270,7 +279,13 @@ const renderList = (container, listIndex) => {
addCount += 1; addCount += 1;
} }
if (addCount > 0 || removeCount > 0) { if (addCount > 0 || removeCount > 0) {
console.log("render: added ", addCount, "nodes, removed", removeCount, "nodes"); console.log(
"render: added ",
addCount,
"nodes, removed",
removeCount,
"nodes"
);
} }
// loop all elements and modify the contents // loop all elements and modify the contents
for (let i = 0; i < container.children.length; i++) { for (let i = 0; i < container.children.length; i++) {
@ -278,10 +293,13 @@ const renderList = (container, listIndex) => {
const roomId = listData.roomIndexToRoomId[i]; const roomId = listData.roomIndexToRoomId[i];
const r = rooms.roomIdToRoom[roomId]; const r = rooms.roomIdToRoom[roomId];
const roomNameSpan = roomCell.getElementsByClassName("roomname")[0]; const roomNameSpan = roomCell.getElementsByClassName("roomname")[0];
const roomContentSpan = roomCell.getElementsByClassName("roomcontent")[0]; const roomContentSpan =
roomCell.getElementsByClassName("roomcontent")[0];
const roomSenderSpan = roomCell.getElementsByClassName("roomsender")[0]; const roomSenderSpan = roomCell.getElementsByClassName("roomsender")[0];
const roomTimestampSpan = roomCell.getElementsByClassName("roomtimestamp")[0]; const roomTimestampSpan =
const unreadCountSpan = roomCell.getElementsByClassName("unreadcount")[0]; roomCell.getElementsByClassName("roomtimestamp")[0];
const unreadCountSpan =
roomCell.getElementsByClassName("unreadcount")[0];
unreadCountSpan.textContent = ""; unreadCountSpan.textContent = "";
unreadCountSpan.classList.remove("unreadcountnotify"); unreadCountSpan.classList.remove("unreadcountnotify");
unreadCountSpan.classList.remove("unreadcounthighlight"); unreadCountSpan.classList.remove("unreadcounthighlight");
@ -293,7 +311,8 @@ const renderList = (container, listIndex) => {
roomContentSpan.style = "background: #e0e0e0; color: #e0e0e0;"; roomContentSpan.style = "background: #e0e0e0; color: #e0e0e0;";
roomSenderSpan.textContent = ""; roomSenderSpan.textContent = "";
roomTimestampSpan.textContent = ""; roomTimestampSpan.textContent = "";
roomCell.getElementsByClassName("roomavatar")[0].src = "/client/placeholder.svg"; roomCell.getElementsByClassName("roomavatar")[0].src =
"/client/placeholder.svg";
roomCell.style = ""; roomCell.style = "";
continue; continue;
} }
@ -305,7 +324,8 @@ const renderList = (container, listIndex) => {
roomCell.getElementsByClassName("roomavatar")[0].src = roomCell.getElementsByClassName("roomavatar")[0].src =
mxcToUrl(r.avatar) || "/client/placeholder.svg"; mxcToUrl(r.avatar) || "/client/placeholder.svg";
} else { } else {
roomCell.getElementsByClassName("roomavatar")[0].src = "/client/placeholder.svg"; roomCell.getElementsByClassName("roomavatar")[0].src =
"/client/placeholder.svg";
} }
if (roomId === activeRoomId) { if (roomId === activeRoomId) {
roomCell.style = "background: #d7d7f7"; roomCell.style = "background: #d7d7f7";
@ -328,7 +348,9 @@ const renderList = (container, listIndex) => {
const mostRecentEvent = r.timeline[r.timeline.length - 1]; const mostRecentEvent = r.timeline[r.timeline.length - 1];
roomSenderSpan.textContent = mostRecentEvent.sender; roomSenderSpan.textContent = mostRecentEvent.sender;
// TODO: move to render.js // TODO: move to render.js
roomTimestampSpan.textContent = render.formatTimestamp(mostRecentEvent.origin_server_ts); roomTimestampSpan.textContent = render.formatTimestamp(
mostRecentEvent.origin_server_ts
);
const body = render.textForEvent(mostRecentEvent); const body = render.textForEvent(mostRecentEvent);
if (mostRecentEvent.type === "m.room.member") { if (mostRecentEvent.type === "m.room.member") {
@ -362,7 +384,12 @@ const indexInRange = (listIndex, i) => {
}; };
const doSyncLoop = async (accessToken, sessionId) => { const doSyncLoop = async (accessToken, sessionId) => {
console.log("Starting sync loop. Active: ", activeSessionId, " this:", sessionId); console.log(
"Starting sync loop. Active: ",
activeSessionId,
" this:",
sessionId
);
let currentPos; let currentPos;
let currentSub = ""; let currentSub = "";
@ -380,7 +407,11 @@ const doSyncLoop = async (accessToken, sessionId) => {
if (!currentPos) { if (!currentPos) {
l.required_state = requiredStateEventsInList; l.required_state = requiredStateEventsInList;
l.timeline_limit = 1; l.timeline_limit = 1;
l.sort = ["by_highlight_count", "by_notification_count", "by_recency"]; l.sort = [
"by_highlight_count",
"by_notification_count",
"by_recency",
];
} }
return l; return l;
}), }),
@ -400,7 +431,11 @@ const doSyncLoop = async (accessToken, sessionId) => {
// hold a ref to the active room ID as it may change by the time we return from doSyncRequest // hold a ref to the active room ID as it may change by the time we return from doSyncRequest
subscribingToRoom = activeRoomId; subscribingToRoom = activeRoomId;
} }
resp = await syncConnection.doSyncRequest(accessToken, currentPos, reqBody); resp = await syncConnection.doSyncRequest(
accessToken,
currentPos,
reqBody
);
currentPos = resp.pos; currentPos = resp.pos;
// update what we think we're subscribed to. // update what we think we're subscribed to.
if (subscribingToRoom) { if (subscribingToRoom) {
@ -452,7 +487,8 @@ const doSyncLoop = async (accessToken, sessionId) => {
// something is in this space, shift items out of the way // something is in this space, shift items out of the way
if (gapIndex < 0) { if (gapIndex < 0) {
console.log( console.log(
"cannot work out where gap is, INSERT without previous DELETE! List: ", op.list, "cannot work out where gap is, INSERT without previous DELETE! List: ",
op.list
); );
return; return;
} }
@ -474,7 +510,9 @@ const doSyncLoop = async (accessToken, sessionId) => {
for (let i = gapIndex; i > op.index; i--) { for (let i = gapIndex; i > op.index; i--) {
if (indexInRange(op.list, i)) { if (indexInRange(op.list, i)) {
activeLists[op.list].roomIndexToRoomId[i] = activeLists[op.list].roomIndexToRoomId[i] =
activeLists[op.list].roomIndexToRoomId[i - 1]; activeLists[op.list].roomIndexToRoomId[
i - 1
];
} }
} }
} else if (gapIndex < op.index) { } else if (gapIndex < op.index) {
@ -483,13 +521,19 @@ const doSyncLoop = async (accessToken, sessionId) => {
for (let i = gapIndex; i < op.index; i++) { for (let i = gapIndex; i < op.index; i++) {
if (indexInRange(op.list, i)) { if (indexInRange(op.list, i)) {
activeLists[op.list].roomIndexToRoomId[i] = activeLists[op.list].roomIndexToRoomId[i] =
activeLists[op.list].roomIndexToRoomId[i + 1]; activeLists[op.list].roomIndexToRoomId[
i + 1
];
} }
} }
} }
} }
accumulateRoomData(op.room, rooms.roomIdToRoom[op.room.room_id] !== undefined); accumulateRoomData(
activeLists[op.list].roomIndexToRoomId[op.index] = op.room.room_id; op.room,
rooms.roomIdToRoom[op.room.room_id] !== undefined
);
activeLists[op.list].roomIndexToRoomId[op.index] =
op.room.room_id;
renderRoomContent(op.room.room_id); renderRoomContent(op.room.room_id);
} else if (op.op === "UPDATE") { } else if (op.op === "UPDATE") {
console.log("UPDATE", op.list, op.index, op.room.room_id, ";"); console.log("UPDATE", op.list, op.index, op.room.room_id, ";");
@ -507,15 +551,30 @@ const doSyncLoop = async (accessToken, sessionId) => {
syncRooms.push(r.room_id); syncRooms.push(r.room_id);
accumulateRoomData(r); accumulateRoomData(r);
} }
console.log("SYNC", op.list, op.range[0], op.range[1], syncRooms.join(" "), ";"); console.log(
"SYNC",
op.list,
op.range[0],
op.range[1],
syncRooms.join(" "),
";"
);
} else if (op.op === "INVALIDATE") { } else if (op.op === "INVALIDATE") {
let invalidRooms = []; let invalidRooms = [];
const startIndex = op.range[0]; const startIndex = op.range[0];
for (let i = startIndex; i <= op.range[1]; i++) { for (let i = startIndex; i <= op.range[1]; i++) {
invalidRooms.push(activeLists[op.list].roomIndexToRoomId[i]); invalidRooms.push(
activeLists[op.list].roomIndexToRoomId[i]
);
delete activeLists[op.list].roomIndexToRoomId[i]; delete activeLists[op.list].roomIndexToRoomId[i];
} }
console.log("INVALIDATE", op.list, op.range[0], op.range[1], ";"); console.log(
"INVALIDATE",
op.list,
op.range[0],
op.range[1],
";"
);
} }
}); });
const roomListElements = document.getElementsByClassName("roomlist"); const roomListElements = document.getElementsByClassName("roomlist");
@ -568,12 +627,21 @@ const doSyncLoop = async (accessToken, sessionId) => {
} }
}); });
devtools.svgify(document.getElementById("listgraph"), activeLists, resp); devtools.svgify(
document.getElementById("listgraph"),
activeLists,
resp
);
} }
console.log("active session: ", activeSessionId, " this session: ", sessionId, " terminating."); console.log(
"active session: ",
activeSessionId,
" this session: ",
sessionId,
" terminating."
);
}; };
const randomName = (i, long) => { const randomName = (i, long) => {
if (i % 17 === 0) { if (i % 17 === 0) {
return long return long
@ -588,11 +656,17 @@ const randomName = (i, long) => {
? "Thats how it is with people. Nobody cares how it works as long as it works." ? "Thats how it is with people. Nobody cares how it works as long as it works."
: "I know kung fu"; : "I know kung fu";
} else if (i % 7 === 0) { } else if (i % 7 === 0) {
return long ? "The body cannot live without the mind." : "Free your mind"; return long
? "The body cannot live without the mind."
: "Free your mind";
} else if (i % 5 === 0) { } else if (i % 5 === 0) {
return long ? "Perhaps we are asking the wrong questions…" : "Agent Smith"; return long
? "Perhaps we are asking the wrong questions…"
: "Agent Smith";
} else if (i % 3 === 0) { } else if (i % 3 === 0) {
return long ? "You've been living in a dream world, Neo." : "Mr Anderson"; return long
? "You've been living in a dream world, Neo."
: "Mr Anderson";
} else { } else {
return long ? "Mr. Wizard, get me the hell out of here! " : "Morpheus"; return long ? "Mr. Wizard, get me the hell out of here! " : "Morpheus";
} }

View File

@ -23,7 +23,9 @@ const membershipChangeText = (ev) => {
if (nowMembership == prevMembership && nowMembership == "join") { if (nowMembership == prevMembership && nowMembership == "join") {
// display name or avatar change // display name or avatar change
if (prevContent.displayname !== ev.content.displayname) { if (prevContent.displayname !== ev.content.displayname) {
return ev.state_key + " set their name to " + ev.content.displayname; return (
ev.state_key + " set their name to " + ev.content.displayname
);
} }
if (prevContent.avatar_url !== ev.content.avatar_url) { if (prevContent.avatar_url !== ev.content.avatar_url) {
return ev.state_key + " changed their profile picture"; return ev.state_key + " changed their profile picture";
@ -79,11 +81,9 @@ export const renderEvent = (eventIdKey, ev) => {
const msgCell = template.content.firstElementChild.cloneNode(true); const msgCell = template.content.firstElementChild.cloneNode(true);
msgCell.setAttribute("id", eventIdKey); msgCell.setAttribute("id", eventIdKey);
msgCell.getElementsByClassName("msgsender")[0].textContent = ev.sender; msgCell.getElementsByClassName("msgsender")[0].textContent = ev.sender;
msgCell.getElementsByClassName("msgtimestamp")[0].textContent = formatTimestamp( msgCell.getElementsByClassName("msgtimestamp")[0].textContent =
ev.origin_server_ts formatTimestamp(ev.origin_server_ts);
);
let body = textForEvent(ev); let body = textForEvent(ev);
msgCell.getElementsByClassName("msgcontent")[0].textContent = body; msgCell.getElementsByClassName("msgcontent")[0].textContent = body;
return msgCell; return msgCell;
} };

View File

@ -1,13 +1,12 @@
// This file contains the main sliding sync code. // This file contains the main sliding sync code.
import * as devtools from './devtools.js'; import * as devtools from "./devtools.js";
// The default range to /always/ track on a list. // The default range to /always/ track on a list.
// When you scroll the list, new windows are added to the first element. E.g [[0,20], [37,45]] // When you scroll the list, new windows are added to the first element. E.g [[0,20], [37,45]]
// TODO: explain why // TODO: explain why
const DEFAULT_RANGES = [[0, 20]]; const DEFAULT_RANGES = [[0, 20]];
/** /**
* SlidingSyncConnection is a thin wrapper around fetch() which performs a sliding sync request. * SlidingSyncConnection is a thin wrapper around fetch() which performs a sliding sync request.
* The wrapper persists a small amount of extra data including the total number of tx/rx bytes, * The wrapper persists a small amount of extra data including the total number of tx/rx bytes,
@ -41,15 +40,18 @@ export class SlidingSyncConnection {
async doSyncRequest(accessToken, pos, reqBody) { async doSyncRequest(accessToken, pos, reqBody) {
this.abortController = new AbortController(); this.abortController = new AbortController();
const jsonBody = JSON.stringify(reqBody); const jsonBody = JSON.stringify(reqBody);
let resp = await fetch("/_matrix/client/v3/sync" + (pos ? "?pos=" + pos : ""), { let resp = await fetch(
signal: this.abortController.signal, "/_matrix/client/v3/sync" + (pos ? "?pos=" + pos : ""),
method: "POST", {
headers: { signal: this.abortController.signal,
Authorization: "Bearer " + accessToken, method: "POST",
"Content-Type": "application/json", headers: {
}, Authorization: "Bearer " + accessToken,
body: jsonBody, "Content-Type": "application/json",
}); },
body: jsonBody,
}
);
let respBody = await resp.json(); let respBody = await resp.json();
if (respBody.ops) { if (respBody.ops) {
@ -66,7 +68,9 @@ export class SlidingSyncConnection {
if (respBody.error) { if (respBody.error) {
this.lastError = respBody.error; this.lastError = respBody.error;
} }
throw new Error("/sync returned HTTP " + resp.status + " " + respBody.error); throw new Error(
"/sync returned HTTP " + resp.status + " " + respBody.error
);
} }
this.lastError = null; this.lastError = null;
return respBody; return respBody;
@ -119,12 +123,9 @@ export class SlidingList {
} }
class SlidingSync { class SlidingSync {
/** /**
* *
* @param {[]SlidingList} activeLists * @param {[]SlidingList} activeLists
*/ */
constructor(activeLists) { constructor(activeLists) {}
}
} }

14
package.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "sliding-sync",
"version": "0.1.0",
"private": true,
"devDependencies": {
"prettier": "^2.1.2"
},
"prettier": {
"trailingComma": "es5",
"tabWidth": 4,
"semi": true,
"singleQuote": false
}
}