Created
December 18, 2018 01:43
-
-
Save mackee/caafebc13193638b1e11b36ff0bf479d to your computer and use it in GitHub Desktop.
Revisions
-
mackee created this gist
Dec 18, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,62 @@ package main import ( "encoding/json" "fmt" "log" ) type Parser interface { Parse(string) error } //go:generate stringer -type=EngineIOPacketType type EngineIOPacketType rune const ( EngineIOPacketOpen EngineIOPacketType = '0' + iota EngineIOPacketClose EngineIOPacketPing EngineIOPacketPong EngineIOPacketMessage EngineIOPacketUpgrade EngineIOPacketNoop ) type EngineIO struct { InnerParser Parser } type EngineIOOpenMessage struct { PingInterval uint64 `json:"pingInterval"` PingTimeout uint64 `json:"pingTimeout"` Upgrades []string `json:"upgrades"` SessionID string `json:"sid"` } func (eio *EngineIO) Parse(message string) error { t := EngineIOPacketType(message[0]) log.Printf("[INFO] Engine.IO type is %s", t) if len(message) == 1 { return nil } if t == EngineIOPacketOpen { var v EngineIOOpenMessage err := json.Unmarshal([]byte(message[1:]), &v) if err != nil { return fmt.Errorf("open message error: %s", err) } log.Printf("[INFO] Engine.IO open message is %+v", v) return nil } if eio.InnerParser != nil { err := eio.InnerParser.Parse(message[1:]) if err != nil { return fmt.Errorf("inner parser error: %s", err) } } return nil } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,97 @@ package main import ( "io" "log" "net/http" "strings" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true }, } var parser = &EngineIO{&SocketIO{}} func main() { http.HandleFunc("/socket.io/", func(w http.ResponseWriter, r *http.Request) { log.Println("[INFO] ===================================================") for key, value := range r.Header { values := strings.Join(value, ",") log.Printf("[INFO] header=%s, value=%s", key, values) } conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Printf("[ERROR] websocket upgrade error: %s", err) w.WriteHeader(http.StatusInternalServerError) return } ctx := r.Context() url := r.URL url.Host = "localhost:3000" url.Scheme = "ws" h := http.Header{} for _, header := range []string{"Cookie", "Origin"} { h.Add(header, r.Header.Get(header)) } client, _, err := websocket.DefaultDialer.DialContext(ctx, url.String(), h) if err != nil { log.Printf("[ERROR] dial origin error: %s", err) w.WriteHeader(http.StatusInternalServerError) return } go func() { for { t, bs, err := client.ReadMessage() if err == io.EOF { break } parser.Parse(string(bs)) switch t { case websocket.TextMessage: log.Printf("send message: %s", string(bs)) case websocket.BinaryMessage: log.Printf("send binary message") case websocket.PingMessage: log.Printf("send ping: %s", string(bs)) case websocket.PongMessage: log.Printf("send pong: %s", string(bs)) } if err := conn.WriteMessage(t, bs); err != nil { log.Printf("[ERROR] fail send message: %s", err) } } }() for { t, bs, err := conn.ReadMessage() if err == io.EOF { break } parser.Parse(string(bs)) switch t { case websocket.TextMessage: log.Printf("recv message: %s", string(bs)) case websocket.BinaryMessage: log.Printf("recv binary message") case websocket.PingMessage: log.Printf("recv ping: %s", string(bs)) case websocket.PongMessage: log.Printf("recv pong: %s", string(bs)) } if err := client.WriteMessage(t, bs); err != nil { log.Printf("[ERROR] fail recv message: %s", err) } } }) log.Println("[INFO] start server") err := http.ListenAndServe(":8888", nil) if err != nil { log.Printf("[ERROR] fail launch server: %s", err) } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,60 @@ package main import ( "encoding/json" "fmt" "log" ) //go:generate stringer -type=SocketIOPacketType type SocketIOPacketType rune const ( SocketIOPacketConnect SocketIOPacketType = '0' + iota SocketIOPacketDisconnect SocketIOPacketEvent SocketIOPacketAck SocketIOPacketError SocketIOPacketBinaryEvent SocketIOPacketBinaryAck ) type SocketIO struct { } type SocketIOEvent struct { Name string Message json.RawMessage } func (e *SocketIOEvent) UnmarshalJSON(b []byte) error { var rawEvent []json.RawMessage err := json.Unmarshal(b, &rawEvent) if err != nil { return err } if len(rawEvent) != 2 { return fmt.Errorf("message is few length or too length") } e.Name = string(rawEvent[0]) e.Message = rawEvent[1] return nil } func (eio *SocketIO) Parse(message string) error { t := SocketIOPacketType(message[0]) log.Printf("[INFO] Socket.IO type is %s", t) if len(message) == 1 { return nil } if t == SocketIOPacketEvent { var event SocketIOEvent err := json.Unmarshal([]byte(message[1:]), &event) if err != nil { return fmt.Errorf("Socket.IO fail parse error: %s", err) } log.Printf("[INFO] Socket.IO event is name=%s, message=%s", event.Name, string(event.Message)) } return nil }