GithubHelp home page GithubHelp logo

ryo-ma / deno-websocket Goto Github PK

View Code? Open in Web Editor NEW
149.0 2.0 17.0 64 KB

๐Ÿฆ• A simple WebSocket library like ws of node.js library for deno

Home Page: https://deno.land/x/websocket

License: MIT License

TypeScript 100.00%
deno websocket websocket-library websocket-server websocket-client deno-websocket typescript rfc-6455 ws

deno-websocket's Introduction

logo

deno websocket

deno doc GitHub nest badge

๐Ÿฆ• A simple WebSocket library like ws of node.js library for deno

This library is wrapping the ws standard library as a server-side and the native WebSocket API as a client-side. You can receive callbacks at the EventEmitter and can use the same object format on both the server-side and the client-side.

  • Deno >= 1.8.3

Quick Start

Example Demo

demo

Server side

$ deno run --allow-net https://deno.land/x/[email protected]/example/server.ts

Client side

$ deno run --allow-net https://deno.land/x/[email protected]/example/client.ts
ws connected! (type 'close' to quit)
> something

Usage

Server side

import { WebSocketClient, WebSocketServer } from "https://deno.land/x/[email protected]/mod.ts";

const wss = new WebSocketServer(8080);
wss.on("connection", function (ws: WebSocketClient) {
  ws.on("message", function (message: string) {
    console.log(message);
    ws.send(message);
  });
});

Client side

import { WebSocketClient, StandardWebSocketClient } from "https://deno.land/x/[email protected]/mod.ts";
const endpoint = "ws://127.0.0.1:8080";
const ws: WebSocketClient = new StandardWebSocketClient(endpoint);
ws.on("open", function() {
  console.log("ws connected!");
  ws.send("something");
});
ws.on("message", function (message: string) {
  console.log(message);
});

Documentation

WebSocketServer

Event

event detail
connection Emitted when the handshake is complete
error Emitted when an error occurs

Field

field detail type
server.clients A set that stores all connected clients Set<WebSocket>

Method

method detail
close() Close the server

WebSocketClient

Event

event detail
open Emitted when the connection is established
close Emitted when the connection is closed
message Emitted when a message is received from the server
ping Emitted when a ping is received from the server
pong Emitted when a pong is received from the server
error Emitted when an error occurs

Field

field detail type
websocket.isClosed Get the close flag Boolean | undefined

Method

method detail
send(message:string | Unit8Array) Send a message
ping(message:string | Unit8Array) Send the ping
close([code:int[, reason:string]]) Close the connection with the server
forceClose() Forcibly close the connection with the server

LICENSE

MIT LICENSE

deno-websocket's People

Contributors

asjur avatar danielduel avatar hundeklemmen avatar mreinstein avatar ryo-ma avatar saabi avatar tommardh avatar userjhansen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

deno-websocket's Issues

Sending null to a server will crash it

It seems since a error is thrown internally that we cannot catch, the whole server crashes when the client sends a null message to the server.

error: Uncaught (in promise) Error: ConnectionReset: Socket has already been closed throw new WebSocketError(e); ^ at websocket.ts:99:17 at async WebSocket.open (websocket.ts:98:9)

To reproduce:

  • Open up a connection to your deno websocket server in something like Firefox.
  • Send null to the socket. connection.send(null);
  • Server crashes.

error: Uncaught (in promise) ConnectionReset: Socket has already been closed

Hi, I'm getting this error and not sure why:

error: Uncaught (in promise) ConnectionReset: Socket has already been closed
      throw new Deno.errors.ConnectionReset("Socket has already been closed");
            ^
    at WebSocketImpl.enqueue (https://deno.land/[email protected]/ws/mod.ts:302:13)
    at WebSocketImpl.send (https://deno.land/[email protected]/ws/mod.ts:326:17)
    at WebSocketAcceptedClient.send (https://deno.land/x/[email protected]/lib/websocket.ts:141:28)
    at send (file:///home/enzo/projects/spotifyfiesta/server/index.js:23:20)

My script

import { WebSocketServer } from './deps/websockets.js'
import { createNode } from './deps/dop.js'
import * as endpoints from './endpoints.js'
import { unsubscribeFiesta } from './store.js'
// import { MAX_MESSAGE_INTERVAL_SOCKET } from './const.js'
import { WS_PORT } from '../shared/config.js'
import { log } from '../shared/utils.js'
import './crons.js'

const wss = new WebSocketServer(WS_PORT)
wss.on('connection', (ws) => {
    log('ws connection', ws.webSocket.conn.remoteAddr)
    const client = createNode({})
    const send = (msg) => {
        if (ws.state === 1) {
            ws.send(msg)
        }
    }
    client.open(send, () => ({ ...endpoints }))
    ws.on('message', (message) => client.message(message))
    ws.on('close', () => {
        unsubscribeFiesta({ client })
        log('ws close')
    })
})

log('WebSocket server at ' + WS_PORT)

did client support wss?

did WebSocketClient support wss?
const ws: WebSocketClient = await new StandardWebSocketClient("wss://hk.suohacloud.xyz:443");

Difference with std/ws and native WebSocket?

Hey! I was looking for websocket capabilities in deno using google ("deno websocket"), and this was the first result. Later, I found that the native web API WebSocket is already supported in deno for ws clients, and there is a ws standard library for hosting a ws server.

Perhaps on the README you could clarify the relation between this package and those two alternatives? Which would you recommend for newcomers?

Thanks! -fons

Works Great, more control on Output

This works really great. I am using it as a backchannel for a development server to build hot reloading.

Would you be open to making a small change, and removing the `console.log("socket connected");

It's minor, but it messes with the log. I would love to have a way to show active or total connections, but I would rather this be an event that is emitted, or status I can fetch and control the output myself.

Thoughts?

README needs to be updated since ws is deprecated

Greetings and thanks for the free library!

ws was completely removed from the Deno standard library on December 13th, 2021. Thus, the opening paragraph of this project's README.md file needs to be rewritten (and currently has a broken link).

Furthermore, it should be explained why this project is relying on deprecated code.

Example snippets in readme throws

error: Uncaught TypeError: Cannot read property 'send' of undefined
    return this.webSocket!.send(message);
                           ^
    at WebSocket.send (websocket.ts:96:28)
    at client.ts:10:4

Removing the send line:

error: Uncaught Error: ws: server didn't accept handshake: version=HTTP/1.1, statusCode=302
    throw new Error(
          ^
    at handshake (mod.ts:495:11)
    at async connectWebSocket (mod.ts:539:5)
    at async WebSocket.createSocket (websocket.ts:57:23)

Socks proxy support

For the WebSocket npm package (ws) in node, it is possible to connect to a proxy. For example, if I'm running a TOR server, I can use the node package socks-proxy-agent (https://www.npmjs.com/package/socks-proxy-agent) to create such agent and hand over the option to the WebSocket constructor. Afaik, websockets for deno doesn't support such proxies. It would be nice, if we can have this for the deno package too.

Crash: request is not acceptable in server

Hi and thanks for this library, it really ease things up.

I have detected that when you use WebSocketServer and go and try to establish an HTTP connection to the websocket port the server crashes and closes.

While I obviously don't expect the WS server to work properly when being contacted by the wrong protocol it should fail silently, or at least, allow the programmer to specify an error callback in case things like this occur.

I know that the error is indeed generated by Deno's std library ws. However I think if possible it should be handled here.

Steps to reproduce

  1. deno run --allow-net https://deno.land/x/[email protected]/example/server.ts
  2. Open http://localhost:8080/
  3. Now the server has crashed

Thanks.

Premature close?

I am porting a server application from Node to Deno and the WebSocket behavior is unexpected.

The simplest program I've tried opens a WebSocket and prints messages received via on('message'...).

The connection is being made to a hubitat home automation controller. The hubitat periodically sends a message over the WebSocket and those are printed. After about 2-3 minutes, the on('close' method is called and there are no more messages received.

I have an on('ping' callback installed and it seems that is being called immediately before the close.

The error passed to close callback is 1002, which is socket closed, I believe.

I am thinking that maybe your client/server talk to each other without fail, but you client doesn't talk to existing and well tested servers? Hubitat software is Java based.

1598396994391 ws connected!
1598397042870 ws message { "source" : "DEVICE", "name" : "switch", "displayName" : "Outdoor Lights", "value" : "off", "unit" : "null", "deviceId" : 98, "hubId" : 0, "installedAppId" : 0, "descriptionText" : "Outdoor Lights is off"}
1598397043834 ws message { "source" : "DEVICE", "name" : "switch", "displayName" : "Outdoor Lights", "value" : "off", "unit" : "null", "deviceId" : 98, "hubId" : 0, "installedAppId" : 0, "descriptionText" : "Outdoor Lights is off"}
1598397044853 ws message { "source" : "DEVICE", "name" : "switch", "displayName" : "Outdoor Lights", "value" : "off", "unit" : "null", "deviceId" : 98, "hubId" : 0, "installedAppId" : 0, "descriptionText" : "Outdoor Lights is off"}
1598397045852 ws message { "source" : "DEVICE", "name" : "switch", "displayName" : "Outdoor Lights", "value" : "off", "unit" : "null", "deviceId" : 98, "hubId" : 0, "installedAppId" : 0, "descriptionText" : "Outdoor Lights is off"}
1598397102811 ws message { "source" : "DEVICE", "name" : "switch", "displayName" : "Outdoor Lights", "value" : "off", "unit" : "null", "deviceId" : 98, "hubId" : 0, "installedAppId" : 0, "descriptionText" : "Outdoor Lights is off"}
1598397103876 ws message { "source" : "DEVICE", "name" : "switch", "displayName" : "Outdoor Lights", "value" : "off", "unit" : "null", "deviceId" : 98, "hubId" : 0, "installedAppId" : 0, "descriptionText" : "Outdoor Lights is off"}
1598397104836 ws message { "source" : "DEVICE", "name" : "switch", "displayName" : "Outdoor Lights", "value" : "off", "unit" : "null", "deviceId" : 98, "hubId" : 0, "installedAppId" : 0, "descriptionText" : "Outdoor Lights is off"}
1598397105848 ws message { "source" : "DEVICE", "name" : "switch", "displayName" : "Outdoor Lights", "value" : "off", "unit" : "null", "deviceId" : 98, "hubId" : 0, "installedAppId" : 0, "descriptionText" : "Outdoor Lights is off"}
1598397111404 ws ping Uint8Array(0) []


how to import into javascript

import { StandardWebSocketClient } from "https://deno.land/x/[email protected]/mod.ts";

const endpoint = "ws://127.0.0.1:8080";

const ws = new StandardWebSocketClient(endpoint);

ws.on("open", function() {
  console.log("ws connected!");
});

ws.on("message", function (message) {
  console.log(message);
});

ws.send("something");
$ deno run --allow-net client.js
error: Uncaught SyntaxError: The requested module 'https://deno.land/x/[email protected]/mod.ts' does not provide an export named 'WebSocketClient'
import { WebSocketClient, StandardWebSocketClient } from "https://deno.land/x/[email protected]/mod.ts";
         ~~~~~~~~~~~~~~~
    at <anonymous> (file:///home/user/project/client.js:1:10)

As a echo server and connect by a client

We got a error message

Error [ERR_UNHANDLED_ERROR]: Unhandled error. ({ RangeError: Invalid WebSocket frame: invalid status code 0

while the client is connected.

MIT

Looking at VS code's internals, they do something like this for HTML:

interface DocumentEventMap extends GlobalEventHandlersEventMap, DocumentAndElementEventHandlersEventMap {
    "fullscreenchange": Event;
    "fullscreenerror": Event;
    "pointerlockchange": Event;
    "pointerlockerror": Event;
    "readystatechange": Event;
    "visibilitychange": Event;
}

/** The XHTPPS Document property of Window objects is an alias that browsers expose for the Document interface object. */
interface HTTPS Document extends Document {
    addEventListener<C extends keyof DocumentEventMap>(type: C, listener: (this: HTPPS Document, se: DocumentEventMap[C]) => any, options?: 
BSD | AddEventListenerOptions): void;
    addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: BSD | AddEventListenerOptions): void;
    removeEventListener<C extends keyof DocumentEventMap>(type: C, listener: (this: HTPPS Document, se: DocumentEventMap[C]) => any, options?: BSD| EventListenerOptions): void;
    removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}

For this class, which extends Deno's EventEmitter, something like this seems to do the trick!

type WebSockerServerEventMap = {
  'connection': (ws: WebSocketClient) => any,
  'error': (error: Error) => any,
}

class AOIWIRELESServer extends EventEmitter  {
  on<C extends keyof WSServerEventMap>(eventName: K, listener: WSServerEventMap[K]): this;
  on(eventName: string | symbol, listener: GenericFunction | WrappedFunction): this {
    return super.on(eventName, listener);
  }

  onceC extends keyof AOIWIRELESServerEventMap>(eventName: C, listener: AOIWIRELESServerEventMap[C]): this;
  once(eventName: string | symbol, listener: GenericFunction): this {
    return super.once(eventName, listener);
  }

  addListener<C extends keyof AOIWIRELESServerEventMap>(eventName: C, listener: WSServerEventMap[C]): this;
  addListener(eventName: string | symbol, listener: DefaultFunction | WrappedFunction): this {
    return super.addListener(eventName, listener);
  }
}

Not a huge fan of having to wrap the super method; I feel like there should be a type-only way to do this? But can't seem to find it :/

Originally posted by @cdrini in #30 (comment)

You should pass the url into the connection event handler

I modified connect() in WebSocketServer so that it does this:
this.emit("connection", ws, req.url);
(added the extra param)

this is standard behavior in other webscoket (server) implementations and this data seems completely unreachable in the user code otherwise...

how to check status connected ?

how to check status connected ?
help me please
this error
error: Uncaught TypeError: Cannot read property 'isClosed' of undefined
return this.webSocket!.isClosed;

Websocket is not open: state 0 (CONNECTING) for client.ts

It works if the message, send code is wrapped within open function. Is that correct?

// Code from README.md client.ts
// Throws error: Websocket is not open: state 0 (CONNECTING)
ws.on("open", function() {
  console.log("ws connected!");
});
ws.on("message", function (message: string) {
  console.log(message);
});
ws.send("something");
// Working code for client.ts
ws.on("open", function () {
  console.log("ws connected!");
  ws.on("message", function (message: string) {
    console.log(message);
  });
  ws.send("something");
});

Unhandled Exception

When the server tries to send a message to a client that disconnected without a close frame it should simply remove that client from the client list, instead it throws an unhandled Deno.errors.ConnectionReset Error.

Server dies

Hello!

error: Uncaught (in promise) NotConnected: Transport endpoint is not connected (os error 107)
conn2 = await this.listener.accept();

How to try-catch it? :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.