From 966c17bb84866f10fc9e995df4107ed11ed2bdce Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Tue, 25 Mar 2014 15:54:32 +0100 Subject: Move protocol agnostic stuff into own package. So we can test it more easily. --- buddy.go | 41 --------------------------- chat/buddy.go | 41 +++++++++++++++++++++++++++ chat/messages.go | 33 ++++++++++++++++++++++ chat/rooms.go | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 2 ++ messages.go | 33 ---------------------- rooms.go | 76 -------------------------------------------------- websock.go | 3 +- 8 files changed, 162 insertions(+), 151 deletions(-) delete mode 100644 buddy.go create mode 100644 chat/buddy.go create mode 100644 chat/messages.go create mode 100644 chat/rooms.go delete mode 100644 messages.go delete mode 100644 rooms.go diff --git a/buddy.go b/buddy.go deleted file mode 100644 index 1128956..0000000 --- a/buddy.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "time" -) - -type Buddy struct { - Nick string - Receive chan Message - room *Room -} - -func NewBuddy(nick string, room *Room) *Buddy { - return &Buddy{ - Nick: nick, - Receive: make(chan Message), - room: room, - } -} - -func (b *Buddy) Leave() { - b.room.Leave(b.Nick) -} - -func (b *Buddy) Push(msg Message) { - go func() { - select { - case b.Receive <- msg: - case <-time.Tick(time.Millisecond * 100): - } - }() -} - -// Say sends a text as a chat message of this user to the connected room. -func (b *Buddy) Say(text string) { - b.room.Messages <- Message{ - Type: MsgChat, - User: b.Nick, - Text: text, - } -} diff --git a/chat/buddy.go b/chat/buddy.go new file mode 100644 index 0000000..c6f07ad --- /dev/null +++ b/chat/buddy.go @@ -0,0 +1,41 @@ +package chat + +import ( + "time" +) + +type Buddy struct { + Nick string + Receive chan Message + room *Room +} + +func NewBuddy(nick string, room *Room) *Buddy { + return &Buddy{ + Nick: nick, + Receive: make(chan Message), + room: room, + } +} + +func (b *Buddy) Leave() { + b.room.Leave(b.Nick) +} + +func (b *Buddy) Push(msg Message) { + go func() { + select { + case b.Receive <- msg: + case <-time.Tick(time.Millisecond * 100): + } + }() +} + +// Say sends a text as a chat message of this user to the connected room. +func (b *Buddy) Say(text string) { + b.room.Messages <- Message{ + Type: MsgChat, + User: b.Nick, + Text: text, + } +} diff --git a/chat/messages.go b/chat/messages.go new file mode 100644 index 0000000..793fc6c --- /dev/null +++ b/chat/messages.go @@ -0,0 +1,33 @@ +package chat + +import ( + "encoding/json" + "errors" +) + +type MsgType int + +const ( + MsgChat MsgType = iota // Default + MsgJoin + MsgLeave +) + +func (mt *MsgType) MarshalJSON() ([]byte, error) { + switch *mt { + case MsgChat: + return json.Marshal("chat") + case MsgJoin: + return json.Marshal("join") + case MsgLeave: + return json.Marshal("leave") + } + + return nil, errors.New("Unknown message type") +} + +type Message struct { + Type MsgType `json:"type"` + User string `json:"user"` + Text string `json:"text,omitempty"` +} diff --git a/chat/rooms.go b/chat/rooms.go new file mode 100644 index 0000000..e954e29 --- /dev/null +++ b/chat/rooms.go @@ -0,0 +1,84 @@ +package chat + +import ( + "errors" +) + +type Room struct { + Messages chan Message + Buddies map[string]*Buddy +} + +func NewRoom() (r *Room) { + r = new(Room) + r.Messages = make(chan Message) + r.Buddies = make(map[string]*Buddy) + go r.Broadcast() + return +} + +func (r *Room) Leave(nick string) { + if _, ok := r.Buddies[nick]; !ok { + return + } + + delete(r.Buddies, nick) + if len(r.Buddies) == 0 { + close(r.Messages) + } else { + r.Messages <- Message{ + Type: MsgLeave, + User: nick, + } + } +} + +func (r *Room) Broadcast() { + for m := range r.Messages { + for _, buddy := range r.Buddies { + buddy.Push(m) + } + } +} + +func (r *Room) ListBuddies() (buddies []string) { + for nick := range r.Buddies { + buddies = append(buddies, nick) + } + return +} + +var ( + rooms map[string]*Room + perroom int +) + +func InitRooms(room_limit int) { + rooms = make(map[string]*Room) + perroom = room_limit +} + +func Join(room, nick string) (*Buddy, *Room, error) { + r, ok := rooms[room] + if !ok { + r = NewRoom() + rooms[room] = r + } + + if _, there := r.Buddies[nick]; there { + return nil, nil, errors.New("Nickname is already in use") + } + + if len(r.Buddies) >= perroom { + return nil, nil, errors.New("Room is full") + } + + r.Messages <- Message{ + Type: MsgJoin, + User: nick, + } + + b := NewBuddy(nick, r) + r.Buddies[nick] = b + return b, r, nil +} diff --git a/main.go b/main.go index 9502f0c..4efcc9c 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "github.com/gorilla/mux" + "github.com/kch42/simplechat/chat" "log" "math" "net/http" @@ -25,6 +26,7 @@ func main() { } PrepTemplates() + chat.InitRooms(*perroom) r := mux.NewRouter() r.HandleFunc("/", Home) diff --git a/messages.go b/messages.go deleted file mode 100644 index 44e5662..0000000 --- a/messages.go +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "encoding/json" - "errors" -) - -type MsgType int - -const ( - MsgChat MsgType = iota // Default - MsgJoin - MsgLeave -) - -func (mt *MsgType) MarshalJSON() ([]byte, error) { - switch *mt { - case MsgChat: - return json.Marshal("chat") - case MsgJoin: - return json.Marshal("join") - case MsgLeave: - return json.Marshal("leave") - } - - return nil, errors.New("Unknown message type") -} - -type Message struct { - Type MsgType `json:"type"` - User string `json:"user"` - Text string `json:"text,omitempty"` -} diff --git a/rooms.go b/rooms.go deleted file mode 100644 index ff441f2..0000000 --- a/rooms.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "errors" -) - -type Room struct { - Messages chan Message - Buddies map[string]*Buddy -} - -func NewRoom() (r *Room) { - r = new(Room) - r.Messages = make(chan Message) - r.Buddies = make(map[string]*Buddy) - go r.Broadcast() - return -} - -func (r *Room) Leave(nick string) { - if _, ok := r.Buddies[nick]; !ok { - return - } - - delete(r.Buddies, nick) - if len(r.Buddies) == 0 { - close(r.Messages) - } else { - r.Messages <- Message{ - Type: MsgLeave, - User: nick, - } - } -} - -func (r *Room) Broadcast() { - for m := range r.Messages { - for _, buddy := range r.Buddies { - buddy.Push(m) - } - } -} - -func (r *Room) ListBuddies() (buddies []string) { - for nick := range r.Buddies { - buddies = append(buddies, nick) - } - return -} - -var rooms = make(map[string]*Room) - -func Join(room, nick string) (*Buddy, *Room, error) { - r, ok := rooms[room] - if !ok { - r = NewRoom() - rooms[room] = r - } - - if _, there := r.Buddies[nick]; there { - return nil, nil, errors.New("Nickname is already in use") - } - - if len(r.Buddies) >= *perroom { - return nil, nil, errors.New("Room is full") - } - - r.Messages <- Message{ - Type: MsgJoin, - User: nick, - } - - b := NewBuddy(nick, r) - r.Buddies[nick] = b - return b, r, nil -} diff --git a/websock.go b/websock.go index 6b69788..bf4fabd 100644 --- a/websock.go +++ b/websock.go @@ -3,6 +3,7 @@ package main import ( "code.google.com/p/go.net/websocket" "github.com/gorilla/mux" + "github.com/kch42/simplechat/chat" "net/http" ) @@ -25,7 +26,7 @@ func AcceptWebSock(rw http.ResponseWriter, req *http.Request) { return } - buddy, room, err := Join(roomname, nick) + buddy, room, err := chat.Join(roomname, nick) if err != nil { send(JoinResponse{ OK: false, -- cgit v1.2.3-54-g00ecf