forked from digitalis-io/golang-udp-chat
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit df0c739
Showing
7 changed files
with
304 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"net" | ||
"os" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/digitalmarc/go/udp-chat/common" | ||
"github.com/nu7hatch/gouuid" | ||
) | ||
|
||
type Client struct { | ||
connection *net.UDPConn | ||
alive bool | ||
userID uuid.UUID | ||
userName string | ||
sendingMessageQueue chan string | ||
receiveMessages chan string | ||
} | ||
|
||
var scanError error | ||
|
||
func (c *Client) packMessage(msg string, messageType common.MessageType) string { | ||
return strings.Join([]string{c.userID.String(), strconv.Itoa(int(messageType)), c.userName, msg, time.Now().Format("15:04:05")}, "\x01") | ||
} | ||
|
||
func (c *Client) funcSendMessage(msg string) { | ||
message := c.packMessage(msg, common.FUNC) | ||
_, err := c.connection.Write([]byte(message)) | ||
checkError(err, "func_sendMessage") | ||
} | ||
|
||
func (c *Client) sendMessage() { | ||
for c.alive { | ||
|
||
msg := <-c.sendingMessageQueue | ||
message := c.packMessage(msg, common.CLASSIQUE) | ||
_, err := c.connection.Write([]byte(message)) | ||
checkError(err, "sendMessage") | ||
} | ||
|
||
} | ||
|
||
func (c *Client) receiveMessage() { | ||
var buf [512]byte | ||
//var userID *uuid.UUID | ||
for c.alive { | ||
n, err := c.connection.Read(buf[0:]) | ||
checkError(err, "receiveMessage") | ||
//msg := string(buf[0:n]) | ||
//stringArray := strings.Split(msg, "\x01") | ||
|
||
//userID, err = uuid.ParseHex(stringArray[0]) | ||
//checkError(err, "receiveMessage") | ||
//if *userID != c.userID { | ||
c.receiveMessages <- string(buf[0:n]) | ||
fmt.Println("") | ||
//} | ||
} | ||
} | ||
|
||
func (c *Client) readInput() { | ||
var msg string | ||
for c.alive { | ||
fmt.Println("msg: ") | ||
scanner := bufio.NewScanner(os.Stdin) | ||
scanner.Split(bufio.ScanLines) | ||
for scanner.Scan() { | ||
msg = scanner.Text() | ||
if msg == ":quit" || msg == ":q" { | ||
c.alive = false | ||
} | ||
c.sendingMessageQueue <- msg | ||
} | ||
//_,scanError := fmt.Scanln(&msg) | ||
//checkError(scanError, "readInput") | ||
|
||
} | ||
} | ||
|
||
func (c *Client) printMessage() { | ||
for c.alive { | ||
msg := <-c.receiveMessages | ||
stringArray := strings.Split(msg, "\x01") | ||
var userName = stringArray[2] | ||
var content = stringArray[3] | ||
var time = stringArray[4] | ||
fmt.Printf("%s %s: %s", time, userName, content) | ||
fmt.Println("") | ||
// pf("MESSAGE RECEIVED: %s \n", msg) | ||
// pf("USER NAME: %s \n", stringArray [2]) | ||
// pf("CONTENT: %s \n", stringArray [3]) | ||
if strings.HasPrefix(msg, ":q") || strings.HasPrefix(msg, ":quit") { | ||
fmt.Printf("%s is leaving", userName) | ||
} | ||
} | ||
} | ||
|
||
func nowTime() string { | ||
return time.Now().String() | ||
} | ||
func checkError(err error, funcName string) { | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Fatal error:%s-----in func:%s", err.Error(), funcName) | ||
os.Exit(1) | ||
} | ||
} | ||
func main() { | ||
// if len(os.Args) != 2 { | ||
// fmt.Fprintf(os.Stderr, "Usage:%s host:port", os.Args[0]) | ||
// os.Exit(1) | ||
// } | ||
// service := os.Args[1] | ||
// udpAddr, err := net.ResolveUDPAddr("udp4", service) | ||
udpAddr, err := net.ResolveUDPAddr("udp4", "78.242.118.156:1200") | ||
checkError(err, "main") | ||
|
||
var c Client | ||
c.alive = true | ||
c.sendingMessageQueue = make(chan string) | ||
c.receiveMessages = make(chan string) | ||
u, err := uuid.NewV4() | ||
|
||
c.userID = *u | ||
|
||
fmt.Println("input name: ") | ||
_, err = fmt.Scanln(&c.userName) | ||
checkError(err, "main") | ||
|
||
c.connection, err = net.DialUDP("udp", nil, udpAddr) | ||
checkError(err, "main") | ||
defer c.connection.Close() | ||
|
||
c.funcSendMessage("joined") | ||
|
||
go c.printMessage() | ||
go c.receiveMessage() | ||
|
||
go c.sendMessage() | ||
c.readInput() | ||
|
||
c.funcSendMessage("left") | ||
|
||
os.Exit(0) | ||
} |
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package common | ||
|
||
// MessageType designate the type of a message send from a client | ||
type MessageType int | ||
const ( | ||
// FUNC for functionnal messages ie technical messages from the client to the server | ||
FUNC MessageType = iota | ||
// CLASSIQUE message for messages sent by the end user | ||
CLASSIQUE | ||
) | ||
|
||
|
||
// ConnectionStatus is self explained | ||
type ConnectionStatus int | ||
const ( | ||
JOINING ConnectionStatus = iota | ||
LEAVING | ||
) |
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
https://golang.org/doc/install/source#environment | ||
|
||
$env:GOOS = "linux" | ||
$env:GOARCH="amd64" | ||
|
||
$env:GOOS = "windows" | ||
$env:GOARCH="amd64" |
Binary file not shown.
This file contains 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 characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"os" | ||
"strconv" | ||
"strings" | ||
"github.com/digitalmarc/go/udp-chat/common" | ||
"github.com/nu7hatch/gouuid" | ||
) | ||
|
||
const ( | ||
port string = ":1200" | ||
) | ||
|
||
var p = fmt.Println | ||
var pf = fmt.Printf | ||
|
||
type Server struct { | ||
conn *net.UDPConn | ||
messages chan string | ||
clients map[*uuid.UUID]Client | ||
} | ||
|
||
type Client struct { | ||
userID uuid.UUID | ||
userName string | ||
userAddr *net.UDPAddr | ||
} | ||
|
||
type Message struct { | ||
messageType common.MessageType | ||
userID *uuid.UUID | ||
userName string | ||
content string | ||
connectionStatus common.ConnectionStatus | ||
time string | ||
} | ||
|
||
func (server *Server) handleMessage() { | ||
var buf [512]byte | ||
|
||
n, addr, err := server.conn.ReadFromUDP(buf[0:]) | ||
if err != nil { | ||
return | ||
} | ||
|
||
msg := string(buf[0:n]) | ||
m := server.parseMessage(msg) | ||
|
||
if m.connectionStatus == common.LEAVING { | ||
delete(server.clients, m.userID) | ||
server.messages <- msg | ||
pf("%s left", m.userName) | ||
} else { | ||
switch m.messageType { | ||
case common.FUNC: | ||
var c Client | ||
c.userAddr = addr | ||
c.userID = *m.userID | ||
c.userName = m.userName | ||
server.clients[m.userID] = c | ||
server.messages <- msg | ||
pf("%s joining", m.userName) | ||
case common.CLASSIQUE: | ||
|
||
pf("%s %s: %s", m.time, m.userName, m.content) | ||
server.messages <- msg | ||
} | ||
} | ||
} | ||
|
||
func (s *Server) parseMessage(msg string) (m Message) { | ||
stringArray := strings.Split(msg, "\x01") | ||
|
||
fmt.Println("") | ||
m.userID, _ = uuid.ParseHex(stringArray[0]) | ||
messageTypeStr, _ := strconv.Atoi(stringArray[1]) | ||
m.messageType = common.MessageType(messageTypeStr) | ||
m.userName = stringArray[2] | ||
m.content = stringArray[3] | ||
m.time = stringArray[4] | ||
// pf("MESSAGE RECEIVED: %s \n", msg) | ||
// pf("USER NAME: %s \n", stringArray [2]) | ||
// pf("CONTENT: %s \n", stringArray [3]) | ||
if strings.HasPrefix(msg, ":q") || strings.HasPrefix(msg, ":quit") { | ||
pf("%s is leaving", m.userName) | ||
m.connectionStatus = common.LEAVING | ||
} | ||
return | ||
} | ||
|
||
func (s *Server) sendMessage() { | ||
for { | ||
msg := <-s.messages | ||
//p(00, sendstr) | ||
for _, c := range s.clients { | ||
_, err := s.conn.WriteToUDP([]byte(msg), c.userAddr) | ||
//pf("Bytes read %d, error: %v", n, err) | ||
checkError(err) | ||
} | ||
} | ||
|
||
} | ||
|
||
func checkError(err error) { | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Fatal error:%s", err.Error()) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func main() { | ||
udpAddress, err := net.ResolveUDPAddr("udp4", port) | ||
checkError(err) | ||
|
||
var s Server | ||
s.messages = make(chan string, 20) | ||
s.clients = make(map[*uuid.UUID]Client, 0) | ||
|
||
s.conn, err = net.ListenUDP("udp", udpAddress) | ||
checkError(err) | ||
|
||
go s.sendMessage() | ||
|
||
for { | ||
s.handleMessage() | ||
} | ||
} |