forked from lonng/nano
/
main.go
124 lines (104 loc) · 2.91 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/lonnng/nano"
"github.com/lonnng/nano/component"
"github.com/lonnng/nano/serialize/json"
"github.com/lonnng/nano/session"
"strings"
)
type (
// Room represents a component that contains a bundle of room related handler
// like Join/Message
Room struct {
component.Base
group *nano.Group
timer *nano.Timer
stats *stats
}
// UserMessage represents a message that user sent
UserMessage struct {
Name string `json:"name"`
Content string `json:"content"`
}
// NewUser message will be received when new user join room
NewUser struct {
Content string `json:"content"`
}
// AllMembers contains all members uid
AllMembers struct {
Members []int64 `json:"members"`
}
// JoinResponse represents the result of joining room
JoinResponse struct {
Code int `json:"code"`
Result string `json:"result"`
}
stats struct {
outboundBytes int
inboundBytes int
}
)
func (stats *stats) outbound(s *session.Session, in []byte) ([]byte, error) {
stats.outboundBytes += len(in)
return in, nil
}
func (stats *stats) inbound(s *session.Session, in []byte) ([]byte, error) {
stats.inboundBytes += len(in)
return in, nil
}
// NewRoom returns a new room
func NewRoom() *Room {
return &Room{
group: nano.NewGroup("room"),
stats: &stats{},
}
}
// AfterInit component lifetime callback
func (r *Room) AfterInit() {
nano.OnSessionClosed(func(s *session.Session) {
r.group.Leave(s)
})
r.timer = nano.NewTimer(time.Minute, func() {
println("UserCount: Time=>", time.Now().String(), "Count=>", r.group.Count())
println("OutboundBytes", r.stats.outboundBytes)
println("InboundBytes", r.stats.outboundBytes)
})
}
// Join room
func (r *Room) Join(s *session.Session, msg []byte) error {
fakeUID := s.ID() //just use s.ID as uid !!!
s.Bind(fakeUID) // binding session uid
s.Push("onMembers", &AllMembers{Members: r.group.Members()})
// notify others
r.group.Broadcast("onNewUser", &NewUser{Content: fmt.Sprintf("New user: %d", s.ID())})
// new user join group
r.group.Add(s) // add session to group
return s.Response(&JoinResponse{Result: "success"})
}
// Message sync last message to all members
func (r *Room) Message(s *session.Session, msg *UserMessage) error {
return r.group.Broadcast("onMessage", msg)
}
func main() {
// override default serializer
nano.SetSerializer(json.NewSerializer())
// rewrite component and handler name
room := NewRoom()
nano.Register(room,
component.WithName("room"),
component.WithNameFunc(strings.ToLower),
)
// traffic stats
nano.Pipeline.Outbound.PushBack(room.stats.outbound)
nano.Pipeline.Inbound.PushBack(room.stats.inbound)
nano.EnableDebug()
log.SetFlags(log.LstdFlags | log.Llongfile)
nano.SetWSPath("/nano")
http.Handle("/web/", http.StripPrefix("/web/", http.FileServer(http.Dir("web"))))
nano.SetCheckOriginFunc(func(_ *http.Request) bool { return true })
nano.ListenWS(":3250")
}