Git Product home page Git Product logo

websocket's Introduction

⚠️ Deprecated repository

This middleware is no longer maintained, it is available within Fiber Contrib.

websocket's People

Contributors

dependabot[bot] avatar efectn avatar fenny avatar frzi avatar gaby avatar github-actions[bot] avatar hi019 avatar joeky888 avatar juanhuttemann avatar koddr avatar renewerner87 avatar stounhandj avatar thomasvvugt avatar zeroallox 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  avatar  avatar  avatar  avatar  avatar

websocket's Issues

upgrade required error

This is the code i'm using which is copied from the readme.md
when i'm running this code locally im getting upgrade required error
websocket error

safari disconnection issue

Hi All

i am experiencing an issue when disconnect from safari, i get a 1006 CloseAbnormalclosure which in chrome it gives a closeNormalClosure 1001 is the correct, this creates panic error on not removing the socket from my map, has anyone experience this issue?

or any help would be great

cheers

Jason

bug

cannot use c (type "github.com/gofiber/fiber/v2".Ctx) as type "github.com/gofiber/fiber".Ctx in argument to "github.com/gofiber/websocket".IsWebSocketUpgrade.\main.go:67:34: cannot use "github.com/gofiber/websocket".New(func literal) (type func("github.com/gofiber/fiber".Ctx)) as type func("github.com/gofiber/fiber/v2".Ctx) error in argument to app.Get

SetWriteDeadline throws error that does not recover

im using the chat example as in the fasthttp/webscoket repo's example and the SetWriteDeadline throws error each time a user disconnect which does not recover till server is restarted
c.Conn.SetWriteDeadline(time.Now().Add(writeWait))

connect close fail without error

Fiber version
"github.com/gofiber/fiber/v2"
"github.com/gofiber/websocket/v2"

Issue description
c := *websocket.Conn
c.Close() do not close connect and has not error return

Code snippet

app.Get("/ws", websocket.New(func(c *websocket.Conn) {
		// When the function returns, unregister the client and close the connection
		defer func() {
			unregister <- c
			c.Close()
		}()
		register <- c
		for {
			messageType, message, err := c.ReadMessage()
			if err != nil {
				if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
					log.Println("read error:", err)
				}

				return // Calls the deferred function, i.e. closes the connection on error
			}

			if messageType == websocket.TextMessage {
				// Broadcast the received message
				broadcast <- string(message)
			} else {
				log.Println("websocket message received of type", messageType)
			}
		}
	}))

this is code from your example: https://github.com/gofiber/recipes/blob/master/websocket-chat/main.go..
u can call c.Close() immediately but websocket still alive

Is it necessary to send ping messages by hand?

I've wrtten a websocket server in fiber's websocket, and the client is js websocket in browser.

Some questions regarding ping/pong:

  1. Is there any default ping/pong msg between the websocket server & client? If yes, then why I can't see it in chrome's devtools.
  2. If there isn't any defult ping/pong msg, should I add ping/pong between server & client myself?
  3. If it's a good practice to add ping/pong msg myself, then:
  4. Is it better to send ping from client to server, or reverse?
  5. Since conn.ReadJSON() will block, does that means I should use conn.SetPingHandler() to specify a handler, or JUST use the default handler? In either case, the ping need to be sent from client to server I guess.

Trying to use session middleware

I'm trying to use the session middleware with websocket

cmd using cobra

package cmd

import (
	"code.local/idc77/socktest/websocket/handler"
	"errors"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/session"
	"github.com/gofiber/websocket/v2"
	"github.com/spf13/cobra"
	"net"
	"os"
	"strings"
)

const (
	prefixTCP  = "tcp:"
	prefixUNIX = "unix:"
)

var websocketAddr = ""

// websocketCmd represents the websocket command
var websocketCmd = &cobra.Command{
	Use:   "websocket",
	Short: "A brief description of your command",
	RunE: func(cmd *cobra.Command, args []string) error {
		app := fiber.New()
		sconf := session.ConfigDefault
		store := session.New(sconf)
		app.Use("/ws", func(c *fiber.Ctx) error {
			sess, e := store.Get(c)
			if e != nil {
				return e
			}
			// IsWebSocketUpgrade returns true if the client
			// requested upgrade to the WebSocket protocol.
			if websocket.IsWebSocketUpgrade(c) {
				c.Locals("sess", sess)
				return c.Next()
			}
			return fiber.ErrUpgradeRequired
		})
		h := handler.NewHandler()
		ws := app.Group("/ws")
		ws.Get("/test", websocket.New(h.Gate))
		return fiberServe(app)
	},
}

func init() {
	rootCmd.AddCommand(websocketCmd)
	websocketCmd.Flags().StringVar(&websocketAddr, "addr", "tcp:127.0.0.1:3000", "tpc:addr:port or unix:/path/to/socket")
}

func fiberServe(r *fiber.App) error {
	if strings.HasPrefix(websocketAddr, prefixTCP) {
		addr := strings.TrimPrefix(websocketAddr, prefixTCP)
		return r.Listen(addr)
	} else if strings.HasPrefix(websocketAddr, prefixUNIX) {
		addr := strings.TrimPrefix(websocketAddr, prefixUNIX)
		if _, e := os.Stat(addr); errors.Is(e, os.ErrNotExist) {
			l, el := net.Listen("unix", addr)
			if el != nil {
				return el
			}
			return r.Listener(l)
		} else {
			if e := os.Remove(addr); e != nil {
				return e
			} else {
				l, el := net.Listen("unix", addr)
				if el != nil {
					return el
				}
				return r.Listener(l)
			}
		}
	} else {
		return nil
	}
}

websocket/handler/handler.go

package handler

import (
	"github.com/gofiber/fiber/v2/middleware/session"
	"github.com/gofiber/websocket/v2"
	jsoniter "github.com/json-iterator/go"
	"log"
)

const (
	CommandSet = "SET"
	CommandGet = "GET"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary

type Handler struct {
}

func NewHandler() *Handler {
	h := new(Handler)
	return h
}

type Message struct {
	Command string `json:"command"`
	Key     string `json:"key,omitempty"`
	Value   string `json:"value,omitempty"`
}

type Response struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

func (h *Handler) Gate(c *websocket.Conn) {
	sess, ok := c.Locals("sess").(*session.Session)
	if !ok {
		log.Println("sesson not ok")
	}
	for {
		mt, msg, e := c.ReadMessage()
		if e != nil {
			log.Println("read:", e)
			break
		}
		m := new(Message)
		if e := json.Unmarshal(msg, m); e != nil {
			log.Println("marshall", e)
			break
		}
		switch m.Command {
		case CommandSet:
			sess.Set(m.Key, m.Value)
			if e := sess.Save(); e != nil {
				log.Println("session save:", e)
				break
			}
		case CommandGet:
			rsp := new(Response)
			rsp.Key = m.Key
			rsp.Value = sess.Get(m.Key).(string)
			rspb, e := json.Marshal(rsp)
			if e != nil {
				log.Println("unmarshall", e)
			}
			if e := c.WriteMessage(mt, rspb); e != nil {
				log.Println("write:", e)
				break
			}
		default:

		}
		log.Printf("recv: %d, %s", mt, msg)
	}
}

result


panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xaef4c2]

goroutine 11 [running]:
github.com/gofiber/fiber/v2.(*Ctx).Response(...)
        /home/idc77/go/pkg/mod/github.com/gofiber/fiber/[email protected]/ctx.go:526
github.com/gofiber/fiber/v2/middleware/session.(*Session).setSession(0xc00027e500)
        /home/idc77/go/pkg/mod/github.com/gofiber/fiber/[email protected]/middleware/session/session.go:213 +0x662
github.com/gofiber/fiber/v2/middleware/session.(*Session).Save(0xc00027e500)
        /home/idc77/go/pkg/mod/github.com/gofiber/fiber/[email protected]/middleware/session/session.go:150 +0x6a
code.local/idc77/socktest/websocket/handler.(*Handler).Gate(0x400?, 0xc000318570)
        /home/idc77/go/src/code.local/idc77/socktest/websocket/handler/handler.go:55 +0x432
github.com/gofiber/websocket/v2.New.func2.4(0x0?)
        /home/idc77/go/pkg/mod/github.com/gofiber/websocket/[email protected]/websocket.go:121 +0x75
github.com/fasthttp/websocket.(*FastHTTPUpgrader).Upgrade.func1({0xddc298, 0xc000318660})
        /home/idc77/go/pkg/mod/github.com/fasthttp/[email protected]/server_fasthttp.go:201 +0x1ad
github.com/valyala/fasthttp.hijackConnHandler(0x0?, {0xdd2fc0?, 0xc000332000}, {0xddc3f8, 0xc0000156d8}, 0xc0001d1600, 0xc00027e5c0)
        /home/idc77/go/pkg/mod/github.com/valyala/[email protected]/server.go:2512 +0x68
created by github.com/valyala/fasthttp.(*Server).serveConn
        /home/idc77/go/pkg/mod/github.com/valyala/[email protected]/server.go:2467 +0x1c5c

Process finished with the exit code 2

On yeah payload, I forgot.

I used https://websocketking.com/
to connect to ws://127.0.0.1:3000/ws/test
with the payload

{
  "command": "SET",
  "key": "t1",
  "value": "100"
}

Writing a msg is delayed until client send some request?

I send a msg via conn.WriteJSON() to client, in my debug, the msg is not sent immediately, but blocked, until the client send some request first, then it will be sent.

I send the msg in the for{} loop of fiber.Handler, any idea why this happen, and how can I fix it?

Unable to install package due to unknown revision of fasthttp/websocket (v1.4.3)

go version

go version go1.15 linux/amd64

Hello, when I try to download package by go get -u github.com/gofiber/websocket/v2 I get following error:

go: downloading github.com/fasthttp/websocket v1.4.3
go: golang.org/x/sys upgrade => v0.0.0-20200922070232-aee5d888a860
go: github.com/klauspost/compress upgrade => v1.11.0
go: github.com/valyala/fasthttp upgrade => v1.16.0
go: github.com/gofiber/fiber/v2 upgrade => v2.0.2
go: downloading golang.org/x/sys v0.0.0-20200922070232-aee5d888a860
../../../go/pkg/mod/github.com/gofiber/websocket/[email protected]/websocket.go:13:2: reading github.com/fasthttp/websocket/go.mod at revision v1.4.3: unknown revision v1.4.3

This is because latest tag for https://github.com/fasthttp/websocket is v1.4.3-beta.2

I can offer next possible workarounds:

  1. Use older (stable?) version: github.com/fasthttp/websocket v1.4.2
  2. Use current beta github.com/fasthttp/websocket v1.4.3-beta.2
  3. Wait for fasthttp/websocket stable v1.4.3 release :)

Thanks!

Anyone able to give some guidance on reverse proxying websocket connections?

There doesn't appear to be any support for this that I can find within the proxy library. Only other examples I've seen are people starting up a net/http server on the side on a different port and proxying through that framework. I know I need to create 2 sockets one between the client and proxy and another between the proxy and backend. My issue is that I don't really see how to even setup a websocket in this situation. I'd think I'd need to setup both connections in the upgrade call, but stuff is so abstracted from me I'm not sure how I'd do that. Do I need to do it on upgrade? Some general help to get started would be much appreciated.

Honestly ... if someone can just show me how to make a new websocket with the framework and register it I could do it. Looking at the Github I'm worried all those methods are private so the backend might be incapable of making outgoing connections and only create them via someone else requesting them.

Chase Lewis

Example to implement json rpc 2 with net/rpc/jsonrpc

I tried to adapt this example for go fiber v2 websockets
https://gist.github.com/mowings/dad4917b6fc21e6e5ffe2da3b16e7ef9

func main() {
	rpc.Register(new(Arith))

	http.Handle("/ws", websocket.Handler(serve))
	http.ListenAndServe("localhost:7000", nil)
}

func serve(ws *websocket.Conn) {
	log.Printf("Handler starting")
	jsonrpc.ServeConn(ws)
	log.Printf("Handler exiting")
}

I get this error:
cannot use c (variable of type *"github.com/gofiber/websocket/v2".Conn) as io.ReadWriteCloser value in argument to jsonrpc.NewClient: *"github.com/gofiber/websocket/v2".Conn does not implement io.ReadWriteCloser (missing method Read)

Is there a way to adapt golang.org/x/net/websocket to be used with go fiber websockets?

How change websocket connection to function. so i can use function in route

app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) { // c.Locals is added to the *websocket.Conn log.Println(c.Locals("allowed")) // true log.Println(c.Params("id")) // 123 log.Println(c.Query("v")) // 1.0 log.Println(c.Cookies("session")) // "" }))
add this code in function like
func Ws(c *fiber.Ctx) error { //add websocket.New(func(c *websocket.Conn) herre return nil }

so in routes i can use
app.Get("/", Ws)

Can't put websocket handle logic in go routine

Hi!

First, gotta say I really like this library, but I have a problem where the client can't connect to the websocket when I put basic ping logic from the example in a different function and run it in goroutine. The example code is below.

Note: I've removed some log.Println to save some space here.

package main

import (
	"log"

	"github.com/gofiber/fiber"
	"github.com/gofiber/websocket"
)

func handleConnection(c *websocket.Conn) {
	var (
		mt  int
		msg []byte
		err error
	)
	for {
		if mt, msg, err = c.ReadMessage(); err != nil {
			log.Println("read:", err)
			break
		}
		log.Printf("recv: %s", msg)

		if err = c.WriteMessage(mt, msg); err != nil {
			log.Println("write:", err)
			break
		}
	}
}

func main() {
	app := fiber.New()

	app.Use(func(c *fiber.Ctx) {
		if websocket.IsWebSocketUpgrade(c) {
			c.Locals("allowed", true)
			c.Next()
		}
	})

	app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {
		go handleConnection(c)
	}))

	log.Fatal(app.Listen(3000))
}

I'm I doing something wrong?

I had a look at gorilla/websocket example (https://github.com/gorilla/websocket/blob/master/examples/chat/client.go) and I see that they can use goroutine when serving the websocket.

WSS

Hi, could you provide an example showing the usage of secured web socket ?

Need examples

Need examples of working with this middleware directly for applications written in fiber
The examples for fasthttp do not reveal the topic.

Broadcast c.WriteMessage to all listeners matching :id param

I have this specific scenario where my application spawns n chat channels, (think of it like chat rooms with many listening and only one speaking) with n users listening each channel.

Only a central authority can broadcast to those channels (e.g. my app), and I plan to fire broadcasting in other parts of my application which are in other files, so I have no more access to the c context variable directly.

Is it possible to actually fire c.WriteMessage from other parts of the project?

Relevant code snippet:

app.Get("/ws/channels/:id", websocket.New(func(c *websocket.Conn) {
  id := c.Params("id")

  // How can I save ReadMessage() and WriteMessage() instances
  // in such a manner that I can call them from any other place in
  // my Fiber application?
  //
  // But also have the intelligence of only broadcasting to those
  // who matches the same id param of my broadcast? 
  readMessageInstance := c.ReadMessage
  writeMessageInstance := c.WriteMessage

}))

Issue when DisableKeepAlive is set to true in Fiber

When DisableKeepAlive is true in Fiber Server configuration, it will send a 'Connection: Close' header after this library, so it is overwritten. The server will send both 'Connection: Upgrade' and 'Connection: Close'.

2 differents handlers for ws and non-ws route

Hello,
What is the best way to use different handlers, for the same route, depending of ws or non-ws request.
For my project I need to use the same path for regular GET requests and WS requests.
e.g.

	app.Use("/ws", func(c *fiber.Ctx) error {
		if websocket.IsWebSocketUpgrade(c) {
			c.Locals("websocket", true)
		}
                return c.Next()
	})

	app.Get("/mypath", standardHandler)
	app.Get("/mypath", websocket.New(wsHandler))

With this code, the standardHandler is executed first.
And the only way I found is to test c.Locals("websocket") in standardHandler.
Is there a cleaner way to do it?
Thanks

Access to fiber.Ctx

How to access c.Locals ( where c is *fiber.Ctx) from a custom the websocket handler?

Room or Broadcast option?

Is there any Room based or Broadcast option?

Or do we need to store "each connection ID" to a specific name and emit for every user in the loop?

Data Race with spawning server and client into two different goroutines

Hi,

I try to adapt this example https://github.com/fasthttp/websocket/tree/master/_examples/chat with fiber.
But in the client, if i spawn 2 goruntines, i have a data race.

It only works if i write this:

go client.readPump()
client.writePump()

instead of:

go client.readPump()
go client.writePump()

I created this repository to illustrate the problem: https://github.com/fabienbellanger/test-fiber-ws.

Here the race condition:

==================
WARNING: DATA RACE
Write at 0x00c00011a300 by goroutine 17:
  github.com/gofiber/websocket/v2.releaseConn()
      github.com/gofiber/websocket/[email protected]/websocket.go:146 +0x3e
  github.com/gofiber/websocket/v2.New.func2.4()
      github.com/gofiber/websocket/[email protected]/websocket.go:110 +0xad
  github.com/fasthttp/websocket.(*FastHTTPUpgrader).Upgrade.func1()
      github.com/fasthttp/[email protected]/server_fasthttp.go:201 +0x23c
  github.com/valyala/fasthttp.hijackConnHandler()
      github.com/valyala/[email protected]/server.go:2307 +0x88

Previous read at 0x00c00011a300 by goroutine 18:
  main.(*Client).readPump()
      test-ws/client.go:36 +0x276

Goroutine 17 (running) created at:
  github.com/valyala/fasthttp.(*Server).serveConn()
      /Users/fabien/go/pkg/mo13:44:10 | 404 |      0s |       127.0.0.1 | GET     | /favicon.ico    
d/github.com/valyala/[email protected]/server.go:2268 +0xfbd
  github.com/valyala/fasthttp.(*Server).serveConn-fm()
      github.com/valyala/[email protected]/server.go:1959 +0x55
  github.com/valyala/fasthttp.(*workerPool).workerFunc()
      github.com/valyala/[email protected]/workerpool.go:223 +0x109
  github.com/valyala/fasthttp.(*workerPool).getCh.func1()
      github.com/valyala/[email protected]/workerpool.go:195 +0x44

Goroutine 18 (running) created at:
  main.serveWs()
      test-ws/client.go:94 +0x154
  main.main.func3()
      test-ws/main.go:34 +0x4b
  github.com/gofiber/websocket/v2.New.func2.4()
      github.com/gofiber/websocket/[email protected]/websocket.go:109 +0xac
  github.com/fasthttp/websocket.(*FastHTTPUpgrader).Upgrade.func1()
      github.com/fasthttp/[email protected]/server_fasthttp.go:201 +0x23c
  github.com/valyala/fasthttp.hijackConnHandler()
      github.com/valyala/[email protected]/server.go:2307 +0x88
==================

I do not known if it is the same reason that the issue #12.

Thanks

unknown fasthttp revision: v1.4.3

I saw #32

But I'm still getting this issue for some reason:

go get -u github.com/gofiber/websocket/v2
go: github.com/gofiber/websocket/v2 upgrade => v2.0.2
go get: github.com/gofiber/websocket/[email protected] requires
        github.com/fasthttp/[email protected]: reading github.com/fasthttp/websocket/go.mod at revision v1.4.3: unknown revision v1.4.3

[Bug] - When trying to go get -u

go get -u github.com/gofiber/websocket/v2@master
github.com/gofiber/websocket/v2 imports
        github.com/fasthttp/websocket imports
        github.com/savsgio/gotils: cannot find module providing package github.com/savsgio/gotils

write error: An established connection was aborted by the software

write tcp4 127.0.0.1:4000->127.0.0.1:24754: wsasend: An established connection was aborted by the software in your host machine.

##problem

when i open browser first time all is ok ...
but by refrreshing it can not be established to connnection and was aborted
no data can be exchanged
the code for websocker stablishing is talking with rabbitmq task queue

code :


app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {
		 
//this chan for connection alive
		var forever chan string
		  
		Q, err := ch.Consume(
			qqq.Name, // queue
			"",               // consumer
			false,            // auto-ack
			false,            // exclusive
			false,            // no-local
			false,            // no-wait
			nil,              // args
		)

		for d := range Q{
			b := d.Body
			// log.Printf("msg recv: %s", b)

			if err = c.WriteMessage(1, b); err != nil {
				log.Println("orderbooks write:", err)

			}
		}
		<-forever

	}))

IsWebsocketUpgrade returning false

I copied the code from the example into my test server. It worked fine on localhost using https://www.websocket.org/echo.html, but when I deployed it and used wss://api.nv7haven.tk/ws/123?v=1.0, it is returning a 426. I put a print statement, and its returning a 426 because IsWebsocketUpgrade is returning false. Why is it returning false, and how can I fix this?

Excessive memory usage

image

I use code in server

app.Use("/", func(c *fiber.Ctx) error {
		if websocket.IsWebSocketUpgrade(c) {
			c.Locals("allowed", true)
			return c.Next()
		}
		
		return fiber.ErrUpgradeRequired
	})

app.Get("/",
websocket.New(func(c *websocket.Conn) {
	c.Close()
},
	websocket.Config{
		HandshakeTimeout:  time.Second * 5,
		ReadBufferSize:    1024 * 1024 * 1024,
		WriteBufferSize:   1024 * 1024 * 1024,
		EnableCompression: true,
	},
))

and this in client

c, _, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8080/ws", nil)
if err != nil {
    log.Errorf("err:%v", err)
    return err
}

When I set up the link, the memory suddenly went up, because the client has retry mechanism, so I can see from the memory monitor that the memory went up twice

go get package fails

When I run go get -u github.com/gofiber/websocket/v2 I get the follow error

github.com/gofiber/websocket/v2 imports
        github.com/fasthttp/websocket imports
        github.com/savsgio/gotils: cannot find module providing package github.com/savsgio/gotils

Example of showing as a separate function

I can use the example in the readme file but I struggled to create a separate function. If I had a separate file to the router to keep all my websocket functions, what would that look like?

write error: An established connection was aborted by the software

write tcp4 127.0.0.1:4000->127.0.0.1:24754: wsasend: An established connection was aborted by the software in your host machine.

##problem

when i open browser first time all is ok ...
but by refrreshing it can not be established to connnection and was aborted
no data can be exchanged
the code for websocker stablishing is talking with rabbitmq task queue

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.