<commit_before>import HelFloat64 = require('helschema/float64');
import HelStruct = require('helschema/struct');
import HelDictionary = require('helschema/dictionary');
import { createSocketServer, createSocket } from 'helnet';
import createClient = require('../client');
import createServer = require('../server');

const Entity = HelStruct({
    x: HelFloat64(),
    y: HelFloat64(),
});

const protocol = {
    client: {
        state: Entity,
        message: {},
        rpc: {},
    },
    server: {
        state: HelDictionary(Entity),
        message: { },
        rpc: {},
    },
};

const socketServer = createSocketServer({
    local: {},
});

const server = createServer({
    protocol,
    socketServer,
});

server.start({
    message: {
    },
    rpc: {
    },
    ready() {
    },
    connect(client) {
        server.state[client.sessionId] = client.schema.clone(client.state);
        server.commit();
    },
    state(client) {
        const serverEntity = server.state[client.sessionId];
        const clientEntity = client.state;
        serverEntity.x = clientEntity.x;
        serverEntity.y = clientEntity.y;
        server.commit();
    },
    disconnect(client) {
        delete server.state[client.sessionId];
        server.commit();
    },
});

function startClient () {
    const socket = createSocket({
        sessionId: Math.random() + 'client',
        local: {
            server: socketServer,
        },
    });

    const client = createClient({
        protocol,
        socket,
    });

    const canvas = document.createElement('canvas');
    canvas.width = canvas.height = 256;
    const context = canvas.getContext('2d');

    function draw () {
        if (!context) {
            return;
        }
        context.fillStyle = '#000';
        context.fillRect(0, 0, 256, 256);

        const state = client.server.state;
        Object.keys(state).forEach((name) => {
            if (name === client.sessionId) {
                return;
            }

            const entity = state[name];

            context.fillStyle = '#fff';
            context.fillRect(entity.x - 2.5, entity.y - 2.5, 5, 5);
        });

        context.fillStyle = '#f00';
        context.fillRect(client.state.x - 3, client.state.y - 3, 6, 6);

        requestAnimationFrame(draw);
    }

    document.body.appendChild(canvas);

    client.start({
        message: {
        },
        rpc: {
        },
        ready (err?:any) {
            if (err) {
                return;
            }
            canvas.addEventListener('mousemove', (ev) => {
                const bounds = canvas.getBoundingClientRect();
                client.state.x = ev.clientX - bounds.left;
                client.state.y = ev.clientY - bounds.top;
                client.commit();
            });
            draw();
        },
        state () {
        },
        close () {
        },
    });
}

const addClientButton = document.createElement('input');
addClientButton.value = 'add client';
addClientButton.type = 'button';
addClientButton.addEventListener('click', startClient);
document.body.appendChild(addClientButton);<commit_msg>implement test for closing connections<commit_after>import HelFloat64 = require('helschema/float64');
import HelStruct = require('helschema/struct');
import HelDictionary = require('helschema/dictionary');
import { createSocketServer, createSocket } from 'helnet';
import createClient = require('../client');
import createServer = require('../server');

const Entity = HelStruct({
    x: HelFloat64(),
    y: HelFloat64(),
});

const protocol = {
    client: {
        state: Entity,
        message: {},
        rpc: {},
    },
    server: {
        state: HelDictionary(Entity),
        message: { },
        rpc: {},
    },
};

const socketServer = createSocketServer({
    local: {},
});

const server = createServer({
    protocol,
    socketServer,
});

server.start({
    message: {
    },
    rpc: {
    },
    ready() {
    },
    connect(client) {
        server.state[client.sessionId] = client.schema.clone(client.state);
        server.commit();
    },
    state(client) {
        const serverEntity = server.state[client.sessionId];
        const clientEntity = client.state;
        serverEntity.x = clientEntity.x;
        serverEntity.y = clientEntity.y;
        server.commit();
    },
    disconnect(client) {
        delete server.state[client.sessionId];
        server.commit();
    },
});

function startClient () {
    const socket = createSocket({
        sessionId: Math.random() + 'client',
        local: {
            server: socketServer,
        },
    });

    const client = createClient({
        protocol,
        socket,
    });

    const container = document.createElement('div');
    container.style.position = 'static';
    container.style.display = 'inline';

    const closeButton = document.createElement('input');
    closeButton.type = 'button';
    closeButton.value = 'x';
    closeButton.style.position = 'absolute';
    closeButton.addEventListener('click', () => client.close());
    container.appendChild(closeButton);

    const canvas = document.createElement('canvas');
    canvas.width = canvas.height = 256;
    const context = canvas.getContext('2d');
    container.appendChild(canvas);

    document.body.appendChild(container);

    function draw () {
        if (!context) {
            return;
        }
        context.fillStyle = '#000';
        context.fillRect(0, 0, 256, 256);

        const state = client.server.state;
        Object.keys(state).forEach((name) => {
            if (name === client.sessionId) {
                return;
            }

            const entity = state[name];

            context.fillStyle = '#fff';
            context.fillRect(entity.x - 2.5, entity.y - 2.5, 5, 5);
        });

        context.fillStyle = '#f00';
        context.fillRect(client.state.x - 3, client.state.y - 3, 6, 6);

        requestAnimationFrame(draw);
    }

    client.start({
        message: {
        },
        rpc: {
        },
        ready (err?:any) {
            if (err) {
                return;
            }
            canvas.addEventListener('mousemove', (ev) => {
                const bounds = canvas.getBoundingClientRect();
                client.state.x = ev.clientX - bounds.left;
                client.state.y = ev.clientY - bounds.top;
                client.commit();
            });
            draw();
        },
        state () {
        },
        close () {
            document.body.removeChild(container);
        },
    });
}

const addClientButton = document.createElement('input');
addClientButton.value = 'add client';
addClientButton.type = 'button';
addClientButton.addEventListener('click', startClient);

const clientButtonContainer = document.createElement('div');
clientButtonContainer.appendChild(addClientButton);

document.body.appendChild(clientButtonContainer);
{'fraction_non_alphanumeric': 0.14056862462115746, 'fraction_numerical': 0.010102467888584212, 'mean_word_length': 2.1020590868397493, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1329971', 'n_tokens_mistral': 1970, 'n_tokens_neox': 1878, 'n_words': 370}