import * as des from './deserializer'; import * as send from './send'; import * as math from './math'; import * as storage from './storage'; import * as config from './config'; import { SESSION, MESSAGE, EVENT } from './enums'; import { sessions, desks, queries } from './storage'; // Session ACKed events up to SN function recv_ack(d, session) { const sn = des.u32(d); session.state = SESSION.READY; session.sn = sn; if (config.DEBUG_PRINT) console.log(`ack ${sn} in`); } async function recv_syn(d, session) { const lsn = des.u32(d); const count = des.u32(d); if (config.DEBUG_PRINT) console.log(`syn ${lsn} in, total size = ${d.size}`); const we_expect = lsn - session.lsn; const first = count - we_expect; const events = []; if (config.DEBUG_PRINT) console.log(`we expect ${we_expect}, count ${count}`); for (let i = 0; i < count; ++i) { const event = des.event(d); if (i >= first) { event.desk_id = session.desk_id; event.user_id = session.user_id; handle_event(session, event); events.push(event); } } desks[session.desk_id].sn += we_expect; desks[session.desk_id].events.push(...events); session.lsn = lsn; storage.queries.update_desk_sn.run({ '$id': session.desk_id, '$sn': desks[session.desk_id].sn }); storage.queries.update_session_lsn.run({ '$id': session.id, '$lsn': lsn }); send.send_ack(session.ws, lsn); send.sync_desk(session.desk_id); } function recv_fire(d, session) { const event = des.event(d); event.user_id = session.user_id; switch (event.type) { case EVENT.SET_COLOR: { session.color = event.color; storage.queries.update_session_color.run({ '$id': session.id, '$color': event.color }); break; } case EVENT.SET_WIDTH: { session.width = event.width; storage.queries.update_session_width.run({ '$id': session.id, 'width': event.width }); break; } } for (const sid in sessions) { const other = sessions[sid]; if (other.id === session.id) { continue; } if (other.state !== SESSION.READY) { continue; } if (other.desk_id != session.desk_id) { continue; } send.send_fire(other.ws, event); } } function handle_event(session, event) { switch (event.type) { case EVENT.STROKE: { event.stroke_id = math.fast_random32(); storage.queries.insert_stroke.run({ '$id': event.stroke_id, '$width': event.width, '$color': event.color, '$points': event.points }); storage.queries.insert_event.run({ '$type': event.type, '$desk_id': session.desk_id, '$session_id': session.id, '$stroke_id': event.stroke_id, '$image_id': 0, '$x': 0, '$y': 0, }); break; } case EVENT.ERASER: case EVENT.IMAGE: case EVENT.IMAGE_MOVE: case EVENT.UNDO: { storage.queries.insert_event.run({ '$type': event.type, '$desk_id': session.desk_id, '$session_id': session.id, '$stroke_id': event.stroke_id || 0, '$image_id': event.image_id || 0, '$x': event.x || 0, '$y': event.y || 0, }); break; } default: { console.error('fuck'); console.trace(); process.exit(1); } } } export async function handle_message(ws, d) { if (!(ws.data.session_id in sessions)) { return; } const session = sessions[ws.data.session_id]; const desk_id = session.desk_id; const message_type = des.u8(d); switch (message_type) { case MESSAGE.FIRE: { recv_fire(d, session); break; } case MESSAGE.SYN: { recv_syn(d, session); break; } case MESSAGE.ACK: { recv_ack(d, session); break; } default: { console.error('fuck'); console.trace(); process.exit(1); } } }