HeroBrine1st 88 Опубликовано: 17 августа, 2022 (изменено) Библиотечка является аналогом уже существующей библиотеки, но имеет нативную (если можно так выразиться) поддержку EEPROM и TLS с помощью dependency injection (банально передать методы для коннекта и остального надо). Если я всё правильно читал, то эта библиотека может быть даже эталонной реализацией, насколько это вообще возможно на OpenComputers. Внимание: библиотека слабо протестирована. Я написал её для собственных целей и выкладываю в надежде, что она может пригодиться кому-либо ещё, но без каких-либо гарантий на её работоспособность или пригодность к каким-то конкретным условиям. Реализовано: Пинг-понг Полная обработка WebSocket Closing Handshake (за исключением того, что из-за невозможности получения TCP/FIN библиотека в нарушение RFC закрывает соединение сама после завершения рукопожатия) Поддержка как бинарных, так и текстовых фреймов в обе стороны (используется один и тот же код, поскольку в луа string является одновременно и ByteArray, ну или как-то так) Поддержка фрагментированных пакетов в обе стороны (не протестировано) Куча проверок входящих данных, из-за которых в том числе исходник разбух до 13 килобайт Поддержка payload размером до 2^63 - 1 байт (очевидно, в ОЗУ не поместится, а обработки во время получения нет) Работа как с картой данных, так и без неё (код без карты не прилагается, нужно передать функцию base64.encode аргументом) Поддержка TLS (опять же, аргумент с функцией подключения) Из-за того, что в библиотеке фингера метод read не принимает количество байт для чтения, она может не подходить к данной библиотеке, поскольку она не имеет собственного буфера и читает ровно столько данных, сколько ей нужно Документация и типовые аннотации EmmyLua Библиотека живёт на гисте, хотя, может быть, куда-нибудь переедет. Использовать её очень просто: local component = require("component") local websocket = require("websocket") local socket = websocket.connect(component.internet.connect, component.data.encode64, "websocket.endpoint.com", 80, "/some/path", { protocols = {"optionalSubprotocol", "anotherSubprotocol"}, headers = {authentication = "Bearer cA9KDPgVQU2IHK7SYEvq5K3O2IUzRYJPVf6mLdWmMTKXJ2FG6VynLa3rfcHBXbHv"} }) while socket:update() do local message = socket:getMessage() -- Если передать сюда true, то функция будет отдавать ещё и незавершённые сообщения if message then -- Пришло сообщение local payload = message.payload local mType = message.type -- binary или text local fin = message.fin -- true, если сообщение завершено и все фреймы приняты if mType == "text" then print(payload) socket:sendText("Echo " .. payload) else socket:startClosingHandshake(1003, "Binary payload is not supported by this endpoint") end -- Закрываем соединение при получении бинарного сообщения end end Сервер для проверки не прилагается. Функции библиотеки: connect(connect_function: function, base64_encode_function: function, host: string, port: number, path: string, [options: table]) - подключиться к серверу по паре `host:port` к пути `path` с помощью сокета, который создаст функция connect_function. Options является таблицей дополнительных параметров. Заголовки устанавливаются как пары ключ-значение опции headers (см. пример), а параметр protocols в опциях указывает значение заголовка `Sec-WebSocket-Protocol`, который может быть полезен (RFC) в некоторых случаях. Возвращает объект WebSocket. Выкидывает ошибку при любом удобном случае (может быть переделаю на всякие nil и "Server has refused connection") Методы WebSocket: update() - вызывает чтение низлежащего сокета, отвечает на пинги, обрабатывает закрытие соединения и т.д.. Возвращает true, если соединение ещё живое (даже если вы закрыли соединение! там целое рукопожатие для этого) и false, если нет. Достаточно его вызывать с таким же периодом, с которым к вам приходят пинги. Может выкинуть ошибку, если произойдёт ошибка при чтении. startClosingHandshake([closeCode: number, [closeReason: string]]) - запускает WebSocket Closing Handshake sendText(payload: string, [fin: boolean]), sendBinary(payload: string, [fin: boolean]), sendFrame(initialOpcode, payload, [fin: boolean]) - отправляет, соответственно, текстовый, бинарный и произвольный фрейм с возможностью фрагментации (fin = false). Если вы указали fin = false, то вы должны в будущем отправить следующий фрагмент, при этом вы не можете отправлять другие сообщения. Никаких проверок там нет, отправляйте фреймы в закрытое соединение на свой страх и риск. isClosed() - true, если соединение закрыто isClosing() - true, если закрывающее рукопожатие активно getCloseCode(), getCloseReason() - возвращают код и причину закрытия соответственно getSocketId() - возвращает id низлежащего сокета для использования с ивентом internet_ready (лично у меня не завелось) getMessage([canBeFragmented: boolean]) - возвращает первое полученное сообщение из "непрочитанных". Если сообщение завершено, то удаляет его из внутреннего буфера. Если canBeFragmented=true, то может вернуть копию незавершённого сообщения, но не удалит его из буфера. Библиотека после минификации почти влезает в EEPROM, а после сжатия влезает в тысячу с чем-то байт. Код ниже вполне себе влезает в еепром (где-то 2 КБ), но в нём не поддерживаются (выкидывают ошибку) субпротоколы (поле protocols в опциях), поскольку баг я заметил слишком поздно, а минифицированная версия у меня уже была. Минифицировать ещё раз мне лень, поскольку нужно за минификатором поставить скобки, которые он убирает, так что как-нибудь в следующий раз. local data = component.proxy(component.list("data")()) local internet = component.proxy(component.list("internet")()) local websocket = load(data.inflate(data.decode64("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")))() Тестировал вручную без TLS с сервером KTor на движке CIO. Изменено 22 августа, 2022 пользователем HeroBrine1st Обновление 6 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
num_pi 29 Опубликовано: 17 августа, 2022 (изменено) Для какой версии мода OC библиотека? на 1.6.2 работать будет? Изменено 17 августа, 2022 пользователем num_pi Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
HeroBrine1st Автор темы 88 Опубликовано: 17 августа, 2022 3 минуты назад, num_pi сказал: Для какой версии мода OC библиотека? на 1.6.2 работать будет? По идее для любой, на которой есть луа 5.3. Лично я тестировал на 1.7.10 и мод был версии 1.7.5 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
HeroBrine1st Автор темы 88 Опубликовано: 22 августа, 2022 Добавил поддержку заголовков и сделал пример загрузки библиотеки на EEPROM. Библиотека всё так же слабо протестирована, хоть уже и активно используется.. Буду исправлять разные баги по мере обнаружения. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах