diff --git a/README.md b/README.md index f9cb63f..c9de654 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Поставь зависимости и запусти сервер. Для этого перейди в директорию задачи и выполни команду `npm install`. После установки зависимостей, выполни команду `npm run dev`. После запуска, перейди по адресу [localhost:5000](http://localhost:5000) -1. Сейчас цвета палитры захардкожены в файле `/client/picker.mjs`, cделай так, чтобы цвета запрашивались с сервера в функции `drawPalette` ++++1. Сейчас цвета палитры захардкожены в файле `/client/picker.mjs`, cделай так, чтобы цвета запрашивались с сервера в функции `drawPalette` -2. На сервере мы будем использовать библиотеку [ws](https://github.com/websockets/ws) для подключения по протоколу [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). Она уже подключена, `WebSocket`-сервер уже правильно интегрирован с `express`, запущен и ждёт подключений по тому же порту, что и `express`. ++++2. На сервере мы будем использовать библиотеку [ws](https://github.com/websockets/ws) для подключения по протоколу [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). Она уже подключена, `WebSocket`-сервер уже правильно интегрирован с `express`, запущен и ждёт подключений по тому же порту, что и `express`. Сделай так, чтобы `WebSocket`-сервер начал обрабатывать подключения, т.е. события `connection`, как [в примере](https://github.com/websockets/ws#simple-server) -3. Сделай так, чтобы после подключения, новому клиенту присылался текущий массив состояния поля. Так как от сервера к клиенту будут передаваться разные сообщения, то удобно, чтобы каждое сообщение имело следующую структуру: ++++3. Сделай так, чтобы после подключения, новому клиенту присылался текущий массив состояния поля. Так как от сервера к клиенту будут передаваться разные сообщения, то удобно, чтобы каждое сообщение имело следующую структуру: ```javascript { @@ -28,15 +28,15 @@ Как принимать и отправлять строковые сообщения уже было показано [в примере](https://github.com/websockets/ws#simple-server) -4. Сделай так, чтобы на клиенте при получении сообщения из `WebSocket` с начальным состоянием поля, заполнялось поле. Для этого измени обработчик события на `ws` в файле `/client/index.mjs`. В него сейчас приходят события [MessageEvent](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent). Для десериализации данных в событии используй `JSON.parse()`. Для отрисовки начального состояния используй `drawer.putArray()` ++++4. Сделай так, чтобы на клиенте при получении сообщения из `WebSocket` с начальным состоянием поля, заполнялось поле. Для этого измени обработчик события на `ws` в файле `/client/index.mjs`. В него сейчас приходят события [MessageEvent](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent). Для десериализации данных в событии используй `JSON.parse()`. Для отрисовки начального состояния используй `drawer.putArray()` -5. Сделай так, чтобы при клике на поле, на сервер по `WebSocket` передавалось сообщение с координатами и цветом. Посылай сообщения с помощью метода [send()](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send). Для удобства, используй тот же формат, что и в сообщениях, посылаемых с сервера ++++5. Сделай так, чтобы при клике на поле, на сервер по `WebSocket` передавалось сообщение с координатами и цветом. Посылай сообщения с помощью метода [send()](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send). Для удобства, используй тот же формат, что и в сообщениях, посылаемых с сервера -6. Сделай так, чтобы `WebSocket`-сервер при получении сообщения с координатами и цветом валидировал его на правильность координат и цвета, а затем рассылал всем активным клиентам. Как сделать `broadcast` посмотри [в примере](https://github.com/websockets/ws#server-broadcast) ++-6. Сделай так, чтобы `WebSocket`-сервер при получении сообщения с координатами и цветом валидировал его на правильность координат и цвета, а затем рассылал всем активным клиентам. Как сделать `broadcast` посмотри [в примере](https://github.com/websockets/ws#server-broadcast) -7. Сделай так, чтобы новые пиксели не только рассылались остальным клиентам, но и добавлялись в поле, хранимое на стороне сервера. Это нужно, чтобы новые клиенты получали текущее изображение, а не начальное. Как сделаешь — проверь: открой приложение с одной вкладки браузера, нарисуй что-нибудь, затем открой со второй вкладки и убедись, что изображения совпадают ++++7. Сделай так, чтобы новые пиксели не только рассылались остальным клиентам, но и добавлялись в поле, хранимое на стороне сервера. Это нужно, чтобы новые клиенты получали текущее изображение, а не начальное. Как сделаешь — проверь: открой приложение с одной вкладки браузера, нарисуй что-нибудь, затем открой со второй вкладки и убедись, что изображения совпадают -8. Удали из обработчика клика на поле отрисовку пикселя. Для этого сделай так, чтобы при `broadcast`-е текущему клиенту тоже отправлялось сообщение. А затем сделай так, чтобы отрисовка пикселя происходила только при получении клиентом сообщения из `WebSocket`. После этого сервер будет полностью контролировать целостность поля для рисования ++++8. Удали из обработчика клика на поле отрисовку пикселя. Для этого сделай так, чтобы при `broadcast`-е текущему клиенту тоже отправлялось сообщение. А затем сделай так, чтобы отрисовка пикселя происходила только при получении клиентом сообщения из `WebSocket`. После этого сервер будет полностью контролировать целостность поля для рисования 9. Опубликуй своё приложение на [Heroku](https://id.heroku.com/login). Для этого потребуются `heroku-cli`, и `git`, если чего-то нет, пройди [вот эти шаги](https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up). diff --git a/client/index.mjs b/client/index.mjs index 3836cb0..df46ee2 100644 --- a/client/index.mjs +++ b/client/index.mjs @@ -10,11 +10,29 @@ document.querySelector("#start").addEventListener("submit", e => { const main = apiKey => { const ws = connect(apiKey); - ws.addEventListener("message", console.log); + ws.addEventListener("message", message => { + let result = JSON.parse(message.data) + console.log(result.type) + if (result.type == 'place') { + drawer.putArray(result.payload.place); + } + if(result.type == 'pick') { + drawer.put(result.payload.x, result.payload.y, result.payload.color); + } + }) timeout.next = new Date(); + drawer.onClick = (x, y) => { - drawer.put(x, y, picker.color); + + ws.send(JSON.stringify({ + type: 'click', + payload: { + x: x, + y: y, + color: picker.color + } + })) }; }; diff --git a/client/picker.mjs b/client/picker.mjs index 6a49c82..163bcb7 100644 --- a/client/picker.mjs +++ b/client/picker.mjs @@ -5,7 +5,8 @@ const setAttributes = (element, object) => { }; const drawPalette = async () => { - const colors = hardcodedColors; + const response = await fetch("/api/getColors"); + const colors = await response.json(); pickedColor = colors[0]; const palette = document.querySelector("#palette"); const fragment = document.createDocumentFragment(); diff --git a/server.mjs b/server.mjs index 02a05b5..e41462f 100644 --- a/server.mjs +++ b/server.mjs @@ -43,6 +43,11 @@ const app = express(); app.use(express.static(path.join(process.cwd(), "client"))); +app.get('/api/getColors', (req, resp) => { + console.log(colors) + resp.json(colors) +}) + app.get("/*", (_, res) => { res.send("Place(holder)"); }); @@ -50,9 +55,11 @@ app.get("/*", (_, res) => { const server = app.listen(port); const wss = new WebSocket.Server({ + port: 3000, noServer: true, }); + server.on("upgrade", (req, socket, head) => { const url = new URL(req.url, req.headers.origin); console.log(url); @@ -60,3 +67,38 @@ server.on("upgrade", (req, socket, head) => { wss.emit("connection", ws, req); }); }); + +wss.on('open', function open() { + +}); + +function sendField(ws) { + let result = { + type: 'place', + payload: { + place: place + } + }; + ws.send(JSON.stringify(result)); +} + +function insertPlace(payload) { + place[size * payload.y + payload.x] = payload.color; + wss.clients.forEach(client => { + if(client.readyState == WebSocket.OPEN) { + sendField(client); + } + }); +} + +wss.on('connection', (ws) => { + ws.on('message', (message) => { + let parseData = JSON.parse(message); + + if(parseData.type == 'click') { + insertPlace(parseData.payload); + } + }) + + sendField(ws) +}) \ No newline at end of file