Skip to content

Commit 0720ee9

Browse files
committed
basic work
0 parents  commit 0720ee9

9 files changed

+447
-0
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
go run ggrok-gorilla-server.go
3+
4+
go run ggrok-gorilla-client.go
5+
6+
request http://localhost:8080/ through postman
7+

ggrok-client.go

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"log"
6+
"net/url"
7+
"os"
8+
"os/signal"
9+
"time"
10+
11+
"github.com/gorilla/websocket"
12+
)
13+
14+
var addr = flag.String("addr", "localhost:8080", "http service address")
15+
16+
func main() {
17+
flag.Parse()
18+
log.SetFlags(0)
19+
20+
interrupt := make(chan os.Signal, 1)
21+
signal.Notify(interrupt, os.Interrupt)
22+
23+
u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
24+
log.Printf("connecting to %s", u.String())
25+
26+
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
27+
if err != nil {
28+
log.Fatal("dial:", err)
29+
}
30+
defer c.Close()
31+
32+
done := make(chan struct{})
33+
34+
go func() {
35+
defer close(done)
36+
for {
37+
_, message, err := c.ReadMessage()
38+
if err != nil {
39+
log.Println("read:", err)
40+
return
41+
}
42+
log.Printf("recv: %s", message)
43+
}
44+
}()
45+
46+
ticker := time.NewTicker(time.Second)
47+
defer ticker.Stop()
48+
49+
for {
50+
select {
51+
case <-done:
52+
return
53+
case t := <-ticker.C:
54+
err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
55+
if err != nil {
56+
log.Println("write:", err)
57+
return
58+
}
59+
case <-interrupt:
60+
log.Println("interrupt")
61+
62+
// Cleanly close the connection by sending a close message and then
63+
// waiting (with timeout) for the server to close the connection.
64+
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
65+
if err != nil {
66+
log.Println("write close:", err)
67+
return
68+
}
69+
select {
70+
case <-done:
71+
case <-time.After(time.Second):
72+
}
73+
return
74+
}
75+
}
76+
}

ggrok-gorilla-client.go

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"encoding/json"
7+
"flag"
8+
"io"
9+
"log"
10+
"net/http"
11+
"net/http/httputil"
12+
"net/url"
13+
"os"
14+
"os/signal"
15+
"time"
16+
17+
"github.com/gorilla/websocket"
18+
)
19+
20+
var addr = flag.String("addr", "localhost:8080", "http service address")
21+
22+
func captureResponseData(resp *http.Response) (string, error) {
23+
rump, err := httputil.DumpResponse(resp, true)
24+
if err != nil {
25+
log.Printf("local response dump error ", err)
26+
return "", err
27+
}
28+
return string(rump), nil
29+
}
30+
31+
func main() {
32+
type RemoteRequest struct {
33+
Req string
34+
URL string
35+
}
36+
37+
flag.Parse()
38+
log.SetFlags(0)
39+
40+
interrupt := make(chan os.Signal, 1)
41+
signal.Notify(interrupt, os.Interrupt)
42+
43+
u := url.URL{Scheme: "ws", Host: *addr, Path: "/$$ggrok"}
44+
log.Printf("connecting to %s", u.String())
45+
46+
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
47+
if err != nil {
48+
log.Fatal("dial:", err)
49+
}
50+
defer c.Close()
51+
52+
done := make(chan struct{})
53+
54+
go func() {
55+
defer close(done)
56+
for {
57+
_, message, err := c.ReadMessage()
58+
if err != nil {
59+
log.Println("read message error:", err)
60+
continue
61+
}
62+
log.Printf("recv: %s", message)
63+
64+
var websocketReq RemoteRequest
65+
if err := json.Unmarshal(message, &websocketReq); err != nil {
66+
log.Println("json.Unmarshal error", err)
67+
continue
68+
}
69+
70+
var localRequest *http.Request
71+
r := bufio.NewReader(bytes.NewReader([]byte(websocketReq.Req)))
72+
if localRequest, err = http.ReadRequest(r); err != nil { // deserialize request
73+
log.Printf("deserialize request error", err)
74+
continue
75+
}
76+
77+
//TODO: change to config
78+
localRequest.RequestURI = ""
79+
u, err := url.Parse("/ada08e16-2112-4720-8fcb-18f2f8e47c2d")
80+
if err != nil {
81+
log.Printf("parse url error", err)
82+
}
83+
localRequest.URL = u
84+
localRequest.URL.Scheme = "https"
85+
localRequest.URL.Host = "webhook.site"
86+
resp, err := (&http.Client{}).Do(localRequest)
87+
if err != nil {
88+
log.Println("local http request error:", err)
89+
continue
90+
}
91+
92+
respStr, err := captureResponseData(resp)
93+
if err != nil {
94+
continue
95+
}
96+
97+
type WebSocketResponse struct {
98+
Status string // e.g. "200 OK"
99+
StatusCode int // e.g. 200
100+
Proto string // e.g. "HTTP/1.0"
101+
Header map[string][]string
102+
Body []byte
103+
ContentType string
104+
}
105+
body, err := io.ReadAll(resp.Body)
106+
if err != nil {
107+
log.Println("read local response error ", err)
108+
}
109+
wsRes := WebSocketResponse{Status: resp.Status, StatusCode: resp.StatusCode,
110+
Proto: resp.Proto, Header: resp.Header, Body: body, ContentType: resp.Header.Get("Content-Type")}
111+
112+
log.Println("client send response: %s", respStr)
113+
c.WriteJSON(wsRes)
114+
}
115+
}()
116+
117+
for {
118+
select {
119+
case <-done:
120+
return
121+
case <-interrupt:
122+
log.Println("interrupt")
123+
124+
// Cleanly close the connection by sending a close message and then
125+
// waiting (with timeout) for the server to close the connection.
126+
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
127+
if err != nil {
128+
log.Println("write close:", err)
129+
return
130+
}
131+
select {
132+
case <-done:
133+
case <-time.After(time.Second):
134+
}
135+
return
136+
}
137+
}
138+
}

ggrok-gorilla-server.go

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"flag"
6+
"io"
7+
"log"
8+
"net/http"
9+
10+
"github.com/gorilla/websocket"
11+
)
12+
13+
var addr = flag.String("addr", "localhost:8080", "http service address")
14+
var connections = make(map[string]*websocket.Conn)
15+
16+
var upgrader = websocket.Upgrader{
17+
CheckOrigin: func(r *http.Request) bool {
18+
return true
19+
},
20+
} // use default options
21+
22+
func register(w http.ResponseWriter, r *http.Request) {
23+
c, err := upgrader.Upgrade(w, r, nil)
24+
if err != nil {
25+
log.Print("upgrade:", err)
26+
return
27+
}
28+
29+
connections[r.Host] = c
30+
log.Println("current connections: %s", connections)
31+
}
32+
33+
func copyHeader(dst, src http.Header) {
34+
for k, vv := range src {
35+
for _, v := range vv {
36+
dst.Add(k, v)
37+
}
38+
}
39+
}
40+
func proxy(w http.ResponseWriter, r *http.Request) {
41+
remoteConn := connections[r.Host]
42+
if remoteConn == nil {
43+
io.WriteString(w, "client not register")
44+
return
45+
}
46+
47+
reqStr, err := captureRequestData(r)
48+
if err != nil {
49+
log.Println("captureRequestData error:", err)
50+
}
51+
log.Println("req serialized: %s", reqStr)
52+
53+
// remoteConn.WriteMessage(100, []byte(reqStr))
54+
type WebSocketRequest struct {
55+
Req string
56+
URL string
57+
}
58+
reqRemote := WebSocketRequest{Req: reqStr, URL: r.URL.String()}
59+
60+
remoteConn.WriteJSON(reqRemote)
61+
62+
type WebSocketResponse struct {
63+
Status string // e.g. "200 OK"
64+
StatusCode int // e.g. 200
65+
Proto string // e.g. "HTTP/1.0"
66+
Header map[string][]string
67+
Body []byte
68+
ContentType string
69+
}
70+
var wsRes WebSocketResponse
71+
err = remoteConn.ReadJSON(&wsRes)
72+
if err != nil {
73+
log.Println("read remote client response error", err)
74+
}
75+
log.Println("remote client response: %s", wsRes)
76+
77+
copyHeader(w.Header(), wsRes.Header)
78+
w.WriteHeader(wsRes.StatusCode)
79+
w.Header().Set("Content-Type", wsRes.ContentType)
80+
io.Copy(w, bytes.NewReader(wsRes.Body))
81+
}
82+
83+
func captureRequestData(req *http.Request) (string, error) {
84+
var b = &bytes.Buffer{} // holds serialized representation
85+
var err error
86+
if err = req.Write(b); err != nil { // serialize request to HTTP/1.1 wire format
87+
return "", err
88+
}
89+
return b.String(), nil
90+
}
91+
92+
func main() {
93+
flag.Parse()
94+
log.SetFlags(0)
95+
http.HandleFunc("/$$ggrok", register)
96+
http.HandleFunc("/", proxy)
97+
log.Fatal(http.ListenAndServe(*addr, nil))
98+
}

ggrok-server.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"net/http"
6+
7+
socketio "github.com/googollee/go-socket.io"
8+
"github.com/googollee/go-socket.io/engineio"
9+
"github.com/googollee/go-socket.io/engineio/transport"
10+
"github.com/googollee/go-socket.io/engineio/transport/polling"
11+
"github.com/googollee/go-socket.io/engineio/transport/websocket"
12+
)
13+
14+
// Easier to get running with CORS. Thanks for help @Vindexus and @erkie
15+
var allowOriginFunc = func(r *http.Request) bool {
16+
return true
17+
}
18+
19+
func main() {
20+
server := socketio.NewServer(&engineio.Options{
21+
Transports: []transport.Transport{
22+
&polling.Transport{
23+
CheckOrigin: allowOriginFunc,
24+
},
25+
&websocket.Transport{
26+
CheckOrigin: allowOriginFunc,
27+
},
28+
},
29+
})
30+
31+
server.OnConnect("/", func(s socketio.Conn) error {
32+
s.SetContext("")
33+
log.Println("connected:", s.ID())
34+
return nil
35+
})
36+
37+
server.OnEvent("/", "notice", func(s socketio.Conn, msg string) {
38+
log.Println("notice:", msg)
39+
s.Emit("reply", "have "+msg)
40+
})
41+
42+
server.OnEvent("/chat", "msg", func(s socketio.Conn, msg string) string {
43+
s.SetContext(msg)
44+
return "recv " + msg
45+
})
46+
47+
server.OnEvent("/", "bye", func(s socketio.Conn) string {
48+
last := s.Context().(string)
49+
s.Emit("bye", last)
50+
s.Close()
51+
return last
52+
})
53+
54+
server.OnError("/", func(s socketio.Conn, e error) {
55+
log.Println("meet error:", e)
56+
})
57+
58+
server.OnDisconnect("/", func(s socketio.Conn, reason string) {
59+
log.Println("closed", reason)
60+
})
61+
62+
go func() {
63+
if err := server.Serve(); err != nil {
64+
log.Fatalf("socketio listen error: %s\n", err)
65+
}
66+
}()
67+
defer server.Close()
68+
69+
http.Handle("/register/", server)
70+
71+
log.Println("Serving at localhost:8080...")
72+
log.Fatal(http.ListenAndServe(":8080", nil))
73+
}

0 commit comments

Comments
 (0)