You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
3.3 KiB
154 lines
3.3 KiB
2 years ago
|
function serializer_create(size) {
|
||
|
const buffer = new ArrayBuffer(size);
|
||
|
return {
|
||
|
'offset': 0,
|
||
|
'size': size,
|
||
|
'buffer': buffer,
|
||
|
'view': new DataView(buffer),
|
||
|
'strview': new Uint8Array(buffer),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function ser_u8(s, value) {
|
||
|
s.view.setUint8(s.offset, value);
|
||
|
s.offset += 1;
|
||
|
}
|
||
|
|
||
|
function ser_u16(s, value) {
|
||
|
s.view.setUint16(s.offset, value, true);
|
||
|
s.offset += 2;
|
||
|
}
|
||
|
|
||
|
function ser_u32(s, value) {
|
||
|
s.view.setUint32(s.offset, value, true);
|
||
|
s.offset += 4;
|
||
|
}
|
||
|
|
||
|
function ser_event(s, event) {
|
||
|
ser_u8(s, event.type);
|
||
|
ser_u8(s, 0); // padding for 16bit alignment
|
||
|
|
||
|
switch (event.type) {
|
||
|
case EVENT.PREDRAW: {
|
||
|
ser_u16(s, event.x);
|
||
|
ser_u16(s, event.y);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case EVENT.STROKE: {
|
||
|
ser_u16(s, event.points.length);
|
||
|
|
||
|
console.debug('original', event.points);
|
||
|
|
||
|
for (const point of event.points) {
|
||
|
ser_u16(s, point.x);
|
||
|
ser_u16(s, point.y);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case EVENT.UNDO:
|
||
|
case EVENT.REDO: {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default: {
|
||
|
console.error('fuck');
|
||
|
process.exit(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async function send_ack(sn) {
|
||
|
const s = serializer_create(1 + 4);
|
||
|
|
||
|
ser_u8(s, MESSAGE.ACK);
|
||
|
ser_u32(s, sn);
|
||
|
|
||
|
console.debug(`ack ${sn} out`);
|
||
|
|
||
|
if (ws) await ws.send(s.buffer);
|
||
|
}
|
||
|
|
||
|
async function sync_queue() {
|
||
|
if (ws === null) {
|
||
|
console.debug('socket has closed, stopping SYNs');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
let size = 1 + 1 + 4 + 4; // opcode + lsn + event count
|
||
|
let count = storage.lsn - storage.server_lsn;
|
||
|
|
||
|
if (count === 0) {
|
||
|
console.debug('server ACKed all events, clearing queue');
|
||
|
storage.queue.length = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (let i = count - 1; i >= 0; --i) {
|
||
|
const event = storage.queue[storage.queue.length - 1 - i];
|
||
|
size += event_size(event);
|
||
|
}
|
||
|
|
||
|
const s = serializer_create(size);
|
||
|
|
||
|
ser_u8(s, MESSAGE.SYN);
|
||
|
ser_u8(s, 0); // padding for 16bit alignment
|
||
|
ser_u32(s, storage.lsn);
|
||
|
ser_u32(s, count);
|
||
|
|
||
|
for (let i = count - 1; i >= 0; --i) {
|
||
|
const event = storage.queue[storage.queue.length - 1 - i];
|
||
|
ser_event(s, event);
|
||
|
}
|
||
|
|
||
|
console.debug(`syn ${storage.lsn} out`);
|
||
|
|
||
|
if (ws) await ws.send(s.buffer);
|
||
|
|
||
|
setTimeout(sync_queue, config.sync_timeout);
|
||
|
}
|
||
|
|
||
|
function push_event(event) {
|
||
|
storage.lsn += 1;
|
||
|
|
||
|
switch (event.type) {
|
||
|
case EVENT.STROKE: {
|
||
|
const points = process_stroke(event.points);
|
||
|
storage.queue.push({ 'type': EVENT.STROKE, 'points': points });
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case EVENT.UNDO:
|
||
|
case EVENT.REDO: {
|
||
|
storage.queue.push(event);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Queue an event and initialize repated sends until ACKed
|
||
|
function queue_event(event, skip = false) {
|
||
|
push_event(event);
|
||
|
|
||
|
if (skip) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (storage.timers.queue_sync) {
|
||
|
clearTimeout(storage.timers.queue_sync);
|
||
|
}
|
||
|
|
||
|
sync_queue();
|
||
|
}
|
||
|
|
||
|
// Fire and forget. Doesn't do anything if we are offline
|
||
|
async function fire_event(event) {
|
||
|
const s = serializer_create(1 + event_size(event));
|
||
|
|
||
|
ser_u8(s, MESSAGE.FIRE);
|
||
|
ser_event(s, event);
|
||
|
|
||
|
if (ws) await ws.send(s.buffer);
|
||
|
}
|