func CreateHandler(user *User, data []byte) { // request body unmarshaling req := new(gs_protocol.ReqCreate) err := proto.Unmarshal(data, req) gs.CheckError(err) if user.userID != req.GetUserID() { if DEBUG { gs.Log("Fail room create, user id missmatch") } return } // room create roomID := GetRandomRoomID() r := NewRoom(roomID) r.users.Set(user.userID, user) // insert user user.room = r // set room rooms.Set(roomID, r) // set room into global shared map if DEBUG { gs.Log("Get rand room id : ", gs.Itoa64(roomID)) } // response body marshaling res := new(gs_protocol.ResCreate) res.RoomID = proto.Int64(roomID) res.UserID = proto.Int64(user.userID) if DEBUG { gs.Log("Room create, room id : ", gs.Itoa64(roomID)) } msg, err := proto.Marshal(res) gs.CheckError(err) user.Push(NewMessage(user.userID, gs_protocol.Type_Create, msg)) }
func ClientReader(user *User, c net.Conn) { data := make([]byte, 4096) // 4096 byte slice (dynamic resize) for { n, err := c.Read(data) if err != nil { if DEBUG { gs.Log("Fail Stream read, err : ", err) } break } // header - body format (header + body in single line) messageType := gs_protocol.Type(gs.ReadInt32(data[0:4])) if DEBUG { gs.Log("Decoding type : ", messageType) } rawData := data[4:n] // 4~ end of line <--if fail read rawData, need calculated body size data (field) handler, ok := msgHandlerMapping[messageType] if ok { handler(user, rawData) // calling proper handler function } else { if DEBUG { gs.Log("Fail no function defined for type", handler) } break } } // fail read user.exit <- struct{}{} }
func ClientSender(user *User, c net.Conn) { defer user.Leave() for { select { case <-user.exit: // when receive signal then finish the program if DEBUG { gs.Log("Leave user id :" + gs.Itoa64(user.userID)) } return case m := <-user.recv: // on receive message msgTypeBytes := gs.WriteMsgType(m.msgType) // msg header + msg type msg := append(msgTypeBytes, m.content...) // '...' need when concat between slice+slice if DEBUG { gs.Log("Client recv, user id : " + gs.Itoa64(user.userID)) } _, err := c.Write(msg) // send data to client if err != nil { if DEBUG { gs.Log(err) } return } } } }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) ln, err := net.Listen("tcp", ":8000") // using TCP protocol over 8000 port if err != nil { if DEBUG { gs.Log(err) } return } InitRooms() defer ln.Close() // reserve listen wait close for { conn, err := ln.Accept() // server accept client connection -> return connection if err != nil { gs.Log("Fail Accept err : ", err) continue } defer conn.Close() // reserve tcp connection close go ClientHandler(conn) } }
func Action1Handler(user *User, data []byte) { // request body unmarshaling req := new(gs_protocol.ReqAction1) err := proto.Unmarshal(data, req) gs.CheckError(err) // TODO create business logic for Action1 Type if DEBUG { gs.Log("Action1 userID : ", gs.Itoa64(req.GetUserID())) } // broadcast message notifyMsg := new(gs_protocol.NotifyAction1Msg) notifyMsg.UserID = proto.Int64(user.userID) msg, err := proto.Marshal(notifyMsg) gs.CheckError(err) user.SendToAll(NewMessage(user.userID, gs_protocol.Type_NotifyAction1, msg)) // response body marshaling res := new(gs_protocol.ResAction1) res.UserID = proto.Int64(user.userID) res.Result = proto.Int32(1) // is success? msg, err = proto.Marshal(res) gs.CheckError(err) user.Push(NewMessage(user.userID, gs_protocol.Type_DefinedAction1, msg)) }
func GetRoom(roomID int64) (r *Room) { value, ok := rooms.Get(roomID) if !ok { if DEBUG { gs.Log("err: not exist room : ", roomID) } } r = value.(*Room) return }
// On Client Connect func ClientHandler(c net.Conn) { if DEBUG { gs.Log("New Connection: ", c.RemoteAddr()) } gs.WriteScribe("access", "test") user := NewUser(0, nil) // empty user data go ClientReader(user, c) go ClientSender(user, c) }
func GetRandomRoomID() (uuid int64) { for { // TODO change room-id generate strategy uuid = int64(gs.RandInt32(1, math.MaxInt32)) if _, ok := rooms.Get(uuid); ok { if DEBUG { gs.Log("err: exist same room id") } continue } return } }
func (r *Room) RoomMessageLoop() { // when messages channel is closed then "for-loop" will be break for m := range r.messages { for userID, _ := range r.users.Map() { if userID != m.userID { value, ok := r.users.Get(userID) if ok { user := value.(*User) if DEBUG { gs.Log("Push message for broadcast :" + gs.Itoa64(user.userID)) } user.Push(m) } } } } }
func JoinHandler(user *User, data []byte) { // request body unmarshaling req := new(gs_protocol.ReqJoin) err := proto.Unmarshal(data, req) gs.CheckError(err) roomID := req.GetRoomID() value, ok := rooms.Get(roomID) if !ok { if DEBUG { gs.Log("Fail room join, room does not exist, room id : ", gs.Itoa64(roomID)) } return } r := value.(*Room) r.users.Set(user.userID, user) user.room = r // broadcast message notifyMsg := new(gs_protocol.NotifyJoinMsg) notifyMsg.UserID = proto.Int64(user.userID) notifyMsg.RoomID = proto.Int64(roomID) msg, err := proto.Marshal(notifyMsg) gs.CheckError(err) user.SendToAll(NewMessage(user.userID, gs_protocol.Type_NotifyJoin, msg)) // response body marshaling res := new(gs_protocol.ResJoin) res.UserID = proto.Int64(user.userID) res.RoomID = proto.Int64(roomID) res.Members = r.getRoomUsers() msg, err = proto.Marshal(res) gs.CheckError(err) user.Push(NewMessage(user.userID, gs_protocol.Type_Join, msg)) }
func main() { client, err := net.Dial("tcp", "127.0.0.1:8000") if err != nil { fmt.Println(err) return } defer client.Close() data := make([]byte, 4096) exit := make(chan struct{}) var userID int64 var method int fmt.Println("=================================================================") fmt.Println(" Input user ID (it must be a whole number greater than 0") fmt.Println("=================================================================") fmt.Print("userID : ") fmt.Scanln(&userID) ReqLogin(client, userID, data) go func() { for { fmt.Println("=================================================================") fmt.Println(" Input command number (1~5)") fmt.Println("=================================================================") fmt.Println("1. room list") fmt.Println("2. room create") fmt.Println("3. join") fmt.Println("4. action1") fmt.Println("5. quit") fmt.Print("choose number: ") fmt.Scanln(&method) switch method { case 1: ReqRoomList(client, userID, data) case 2: ReqCreate(client, userID, data) case 3: var roomID int64 fmt.Print("input room id : ") fmt.Scanln(&roomID) ReqJoin(client, userID, data, roomID) case 4: ReqAction1(client, userID, data) case 5: ReqQuit(client, userID, data) fmt.Println("program exit..bye") exit <- struct{}{} return default: continue } } }() go func() { data := make([]byte, 4096) for { n, err := client.Read(data) if err != nil { gs.Log("Fail Stream read, err : ", err) break } messageType := gs_protocol.Type(gs.ReadInt32(data[0:4])) gs.Log("Decoding type : ", messageType) rawData := data[4:n] handler, ok := msgHandlerMapping[messageType] if ok { handler(rawData) } else { gs.Log("Fail no function defined for type", handler) break } } }() <-exit }