better networking
This commit is contained in:
parent
35d8ebc459
commit
e90b9c26b1
|
@ -1,95 +1,107 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"sshpong/internal/client"
|
||||||
"sshpong/internal/netwrk"
|
"sshpong/internal/netwrk"
|
||||||
"strings"
|
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var exit chan bool
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
lobbyChan := make(chan netwrk.LobbyPlayerStatus)
|
|
||||||
interrupter := make(chan netwrk.Interrupter)
|
|
||||||
messageOutput := make(chan *netwrk.LobbyMessage)
|
|
||||||
inputChan := make(chan string)
|
|
||||||
|
|
||||||
fmt.Println("Welcome to sshpong!")
|
fmt.Println("Welcome to sshpong!")
|
||||||
fmt.Println("Please enter your username")
|
fmt.Println("Please enter your username")
|
||||||
|
|
||||||
go func() {
|
egress := make(chan *netwrk.LobbyMessage)
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
ingress := make(chan *netwrk.LobbyMessage)
|
||||||
for scanner.Scan() {
|
|
||||||
text := scanner.Text()
|
|
||||||
inputChan <- text
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
username, err := reader.ReadString('\n')
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error reading from your shit bro...")
|
|
||||||
}
|
|
||||||
|
|
||||||
go netwrk.ConnectToLobby(username, messageOutput, lobbyChan, interrupter)
|
|
||||||
|
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
|
n, err := os.Stdin.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic("Bro your input is no good...")
|
||||||
|
}
|
||||||
|
username := string(buf[:n])
|
||||||
|
|
||||||
for {
|
conn, err := netwrk.ConnectToLobby(username)
|
||||||
select {
|
if err != nil {
|
||||||
case msg := <-interrupter:
|
log.Panic(err)
|
||||||
fmt.Println(msg.Message)
|
|
||||||
default:
|
|
||||||
n, err := os.Stdin.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error reading from stdin")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
input := string(buf[:n])
|
|
||||||
args := strings.Fields(input)
|
|
||||||
switch args[0] {
|
|
||||||
case "invite":
|
|
||||||
if args[1] != "" {
|
|
||||||
messageOutput <- &netwrk.LobbyMessage{
|
|
||||||
PlayerId: username,
|
|
||||||
Type: "invite",
|
|
||||||
Content: args[1],
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("Please provide a player to invite ")
|
|
||||||
}
|
|
||||||
case "chat":
|
|
||||||
if args[1] != "" {
|
|
||||||
messageOutput <- &netwrk.LobbyMessage{
|
|
||||||
PlayerId: username,
|
|
||||||
Type: "chat",
|
|
||||||
Content: strings.Join(args[1:], " "),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "/":
|
|
||||||
if args[1] != "" {
|
|
||||||
messageOutput <- &netwrk.LobbyMessage{
|
|
||||||
PlayerId: username,
|
|
||||||
Type: "chat",
|
|
||||||
Content: strings.Join(args[1:], " "),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "quit":
|
|
||||||
return
|
|
||||||
case "q":
|
|
||||||
return
|
|
||||||
case "help":
|
|
||||||
fmt.Println("use invite <player name> to invite a player\nchat or / to send a message to the lobby\nq or quit to leave the game")
|
|
||||||
case "h":
|
|
||||||
fmt.Println("use invite <player name> to invite a player\nchat or / to send a message to the lobby\nq or quit to leave the game")
|
|
||||||
default:
|
|
||||||
fmt.Println("use invite <player name> to invite a player\nchat or / to send a message to the lobby\nq or quit to leave the game")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// User input handler
|
||||||
|
go func(egress chan *netwrk.LobbyMessage) {
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
for {
|
||||||
|
|
||||||
|
n, err := os.Stdin.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic("Bro your input wack as fuck")
|
||||||
|
}
|
||||||
|
|
||||||
|
userMessage, err := client.HandleUserInput(buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
userMessage.PlayerId = username
|
||||||
|
egress <- userMessage
|
||||||
|
}
|
||||||
|
}(egress)
|
||||||
|
|
||||||
|
// Ingress Handler
|
||||||
|
go func(oc chan *netwrk.LobbyMessage) {
|
||||||
|
for {
|
||||||
|
msg := <-ingress
|
||||||
|
|
||||||
|
client.HandleServerMessage(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
}(ingress)
|
||||||
|
|
||||||
|
// Network writer
|
||||||
|
go func(userMessages chan *netwrk.LobbyMessage) {
|
||||||
|
for {
|
||||||
|
msg := <-userMessages
|
||||||
|
bytes, err := proto.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic("Malformed proto message", err)
|
||||||
|
}
|
||||||
|
_, err = conn.Write(bytes)
|
||||||
|
if err == io.EOF {
|
||||||
|
log.Panic("Server disconnected sorry...")
|
||||||
|
} else if err != nil {
|
||||||
|
log.Panic("Error reading from server connection...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(egress)
|
||||||
|
|
||||||
|
// Network reader
|
||||||
|
go func(serverMessages chan *netwrk.LobbyMessage) {
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
for {
|
||||||
|
n, err := conn.Read(buf)
|
||||||
|
if err == io.EOF {
|
||||||
|
log.Panic("Server disconnected sorry...")
|
||||||
|
} else if err != nil {
|
||||||
|
log.Panic("Error reading from server connection...")
|
||||||
|
}
|
||||||
|
|
||||||
|
message := &netwrk.LobbyMessage{}
|
||||||
|
|
||||||
|
err = proto.Unmarshal(buf[:n], message)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic("Error reading message from server")
|
||||||
|
}
|
||||||
|
|
||||||
|
serverMessages <- message
|
||||||
|
|
||||||
|
}
|
||||||
|
}(ingress)
|
||||||
|
|
||||||
|
_ = <-exit
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,12 @@ import (
|
||||||
"sshpong/internal/netwrk"
|
"sshpong/internal/netwrk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var exit chan bool
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("Starting sshpong server!")
|
fmt.Println("Starting sshpong server!")
|
||||||
|
|
||||||
netwrk.Listen()
|
netwrk.Listen()
|
||||||
|
|
||||||
|
_ = <-exit
|
||||||
}
|
}
|
||||||
|
|
71
internal/client/client_utils.go
Normal file
71
internal/client/client_utils.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"sshpong/internal/netwrk"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandleUserInput(buf []byte) (*netwrk.LobbyMessage, error) {
|
||||||
|
input := string(buf)
|
||||||
|
args := strings.Fields(input)
|
||||||
|
switch args[0] {
|
||||||
|
case "invite":
|
||||||
|
if args[1] != "" {
|
||||||
|
return &netwrk.LobbyMessage{
|
||||||
|
Type: "invite",
|
||||||
|
Content: args[1],
|
||||||
|
}, nil
|
||||||
|
} else {
|
||||||
|
fmt.Println("Please provide a player to invite ")
|
||||||
|
}
|
||||||
|
case "chat":
|
||||||
|
if args[1] != "" {
|
||||||
|
return &netwrk.LobbyMessage{
|
||||||
|
Type: "chat",
|
||||||
|
Content: strings.Join(args[1:], " "),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
case "/":
|
||||||
|
if args[1] != "" {
|
||||||
|
return &netwrk.LobbyMessage{
|
||||||
|
Type: "chat",
|
||||||
|
Content: strings.Join(args[1:], " "),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
case "quit":
|
||||||
|
return nil, io.EOF
|
||||||
|
case "q":
|
||||||
|
return nil, io.EOF
|
||||||
|
case "help":
|
||||||
|
return nil, fmt.Errorf("use invite <player name> to invite a player\nchat or / to send a message to the lobby\nq or quit to leave the game")
|
||||||
|
case "h":
|
||||||
|
return nil, fmt.Errorf("use invite <player name> to invite a player\nchat or / to send a message to the lobby\nq or quit to leave the game")
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("use invite <player name> to invite a player\nchat or / to send a message to the lobby\nq or quit to leave the game")
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleServerMessage(message *netwrk.LobbyMessage) {
|
||||||
|
switch message.Type {
|
||||||
|
case "invite":
|
||||||
|
log.Println(message.PlayerId, "is inviting you to a game.", message.Content)
|
||||||
|
case "accepted":
|
||||||
|
log.Println(message.PlayerId, "accepted your invite.", message.Content)
|
||||||
|
case "text":
|
||||||
|
log.Println(message.PlayerId, ":", message.Content)
|
||||||
|
case "decline_game":
|
||||||
|
log.Println("Invite was declined:", message.Content)
|
||||||
|
case "disconnect":
|
||||||
|
log.Println("Got disconnect for player:", message.Content)
|
||||||
|
case "connect":
|
||||||
|
log.Println("Got connect for player:", message.Content)
|
||||||
|
case "pong":
|
||||||
|
log.Println("Received", message.Content)
|
||||||
|
default:
|
||||||
|
log.Println("Received", message.Content)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,152 +2,26 @@ package netwrk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LobbyPlayerStatus struct {
|
func ConnectToLobby(username string) (net.Conn, error) {
|
||||||
Username string
|
|
||||||
Status string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Interrupter struct {
|
|
||||||
MessageType string
|
|
||||||
Message string
|
|
||||||
ReplyChan chan string
|
|
||||||
}
|
|
||||||
|
|
||||||
var username string
|
|
||||||
var lobby chan LobbyPlayerStatus
|
|
||||||
var interruptChan chan Interrupter
|
|
||||||
|
|
||||||
func ConnectToLobby(playerUsername string, messageOutputChan chan *LobbyMessage, lobbyMessageChan chan LobbyPlayerStatus, interruptChannel chan Interrupter) {
|
|
||||||
username = playerUsername
|
|
||||||
lobby = lobbyMessageChan
|
|
||||||
interruptChan = interruptChannel
|
|
||||||
|
|
||||||
conn, err := net.Dial("tcp", "127.0.0.1:12345")
|
conn, err := net.Dial("tcp", "127.0.0.1:12345")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Sorry, failed to connect to server...")
|
return nil, fmt.Errorf("Sorry, failed to connect to server...")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loginMsg, err := proto.Marshal(&LobbyMessage{Type: "name", Content: username})
|
loginMsg, err := proto.Marshal(&LobbyMessage{Type: "name", Content: username})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Sorry bro but your username is wack AF...")
|
return nil, fmt.Errorf("Sorry bro but your username is wack AF...")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Write(loginMsg)
|
_, err = conn.Write(loginMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Sorry, could not communicate with server...")
|
return nil, fmt.Errorf("Sorry, could not communicate with server...")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Starting client loop")
|
return conn, nil
|
||||||
messageInputChan := make(chan *LobbyMessage)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
messageBytes := make([]byte, 1024)
|
|
||||||
|
|
||||||
n, err := conn.Read(messageBytes)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Sorry, failed to read message from server...", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
message := &LobbyMessage{}
|
|
||||||
|
|
||||||
err = proto.Unmarshal(messageBytes[:n], message)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Sorry, the server sent something weird back...")
|
|
||||||
}
|
|
||||||
|
|
||||||
messageInputChan <- message
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case msg := <-messageInputChan:
|
|
||||||
if isDone, gameID := handleLobbyMessage(conn, msg); isDone {
|
|
||||||
if gameID != "" {
|
|
||||||
interruptChan <- Interrupter{
|
|
||||||
MessageType: "game",
|
|
||||||
Message: gameID,
|
|
||||||
ReplyChan: make(chan string),
|
|
||||||
}
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case msg := <-messageOutputChan:
|
|
||||||
fmt.Println("Sending message out", msg)
|
|
||||||
err := SendMessageToServer(conn, msg)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error!", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleLobbyMessage(serverConn net.Conn, message *LobbyMessage) (bool, string) {
|
|
||||||
switch message.Type {
|
|
||||||
case "text":
|
|
||||||
fmt.Println(message.Content)
|
|
||||||
return false, ""
|
|
||||||
case "error":
|
|
||||||
fmt.Println("Error:", message.Content)
|
|
||||||
return false, ""
|
|
||||||
case "invite":
|
|
||||||
fmt.Println("GOT INVITE!")
|
|
||||||
replyChan := make(chan string)
|
|
||||||
interruptChan <- Interrupter{
|
|
||||||
MessageType: "invite",
|
|
||||||
Message: fmt.Sprintf("Invite from player %s\nAccept: Y Decline: N", message.Content),
|
|
||||||
ReplyChan: replyChan,
|
|
||||||
}
|
|
||||||
input := <-replyChan
|
|
||||||
if strings.ToLower(input) == "yes" || strings.ToLower(input) == "y" {
|
|
||||||
SendMessageToServer(serverConn, &LobbyMessage{Type: "accept_game", Content: username})
|
|
||||||
SendMessageToServer(serverConn, &LobbyMessage{Type: "quit", Content: username})
|
|
||||||
return true, message.Content
|
|
||||||
} else {
|
|
||||||
SendMessageToServer(serverConn, &LobbyMessage{Type: "decline_game", Content: username})
|
|
||||||
}
|
|
||||||
return false, ""
|
|
||||||
case "accept":
|
|
||||||
fmt.Println(message.Content, "accepted your invite. Game starting...")
|
|
||||||
SendMessageToServer(serverConn, &LobbyMessage{Type: "quit", Content: username})
|
|
||||||
return true, message.Content
|
|
||||||
case "decline_game":
|
|
||||||
fmt.Println("Sorry,", message.Content, "declined your game invite...")
|
|
||||||
return false, ""
|
|
||||||
case "connect":
|
|
||||||
lobby <- LobbyPlayerStatus{Username: message.Content, Status: "connected"}
|
|
||||||
fmt.Println(message.Content, "connected!")
|
|
||||||
return false, ""
|
|
||||||
case "disconnect":
|
|
||||||
lobby <- LobbyPlayerStatus{Username: message.Content, Status: "disconnected"}
|
|
||||||
fmt.Println(message.Content, "disconnected!")
|
|
||||||
return false, ""
|
|
||||||
case "pong":
|
|
||||||
log.Println("PoNg!")
|
|
||||||
return false, ""
|
|
||||||
default:
|
|
||||||
log.Println("Got message", message)
|
|
||||||
}
|
|
||||||
return false, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendMessageToServer(connection net.Conn, message *LobbyMessage) error {
|
|
||||||
bytes, err := proto.Marshal(message)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error marshalling message. Your protobuf is wack yo.")
|
|
||||||
}
|
|
||||||
_, err = connection.Write(bytes)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing to client connection")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package netwrk
|
package netwrk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
@ -14,15 +13,16 @@ func handleLobbyConnection(conn net.Conn) {
|
||||||
|
|
||||||
messageBytes := make([]byte, 4096)
|
messageBytes := make([]byte, 4096)
|
||||||
|
|
||||||
recvMessageChan := make(chan *LobbyMessage)
|
ingress := make(chan *LobbyMessage)
|
||||||
|
egress := make(chan *LobbyMessage)
|
||||||
|
|
||||||
|
// Network Reader
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
fmt.Println("READING!")
|
|
||||||
n, err := conn.Read(messageBytes)
|
n, err := conn.Read(messageBytes)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println("READ something!")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error reading message %v", err)
|
log.Printf("Error reading message %v", err)
|
||||||
return
|
return
|
||||||
|
@ -32,106 +32,103 @@ func handleLobbyConnection(conn net.Conn) {
|
||||||
|
|
||||||
err = proto.Unmarshal(messageBytes[:n], &message)
|
err = proto.Unmarshal(messageBytes[:n], &message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Invalid message received from client")
|
log.Println("Invalid message received from client", err)
|
||||||
}
|
}
|
||||||
recvMessageChan <- &message
|
ingress <- &message
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
// Network Writer
|
||||||
|
go func() {
|
||||||
select {
|
for {
|
||||||
case msg := <-recvMessageChan:
|
msg := <-egress
|
||||||
if isDone, err := handleClientLobbyMessage(conn, msg); err != nil || isDone {
|
bytes, err := proto.Marshal(msg)
|
||||||
log.Println(err)
|
if err != nil {
|
||||||
return
|
log.Println("Error marshalling message to send to user...", err)
|
||||||
|
}
|
||||||
|
_, err = conn.Write(bytes)
|
||||||
|
if err == io.EOF {
|
||||||
|
log.Println("User has disconnected", err)
|
||||||
|
ingress <- &LobbyMessage{Type: "disconnect"}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error writing to user...", err)
|
||||||
}
|
}
|
||||||
fmt.Println("Handled message")
|
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
|
|
||||||
|
// Client message handler
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
msg := <-ingress
|
||||||
|
serverMsg, err := handleClientLobbyMessage(msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error handling client lobby message...", err)
|
||||||
|
}
|
||||||
|
if serverMsg != nil {
|
||||||
|
egress <- serverMsg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a bool of whether the player has disconnected from the lobby and an error
|
// Returns a bool of whether the player has disconnected from the lobby and an error
|
||||||
func handleClientLobbyMessage(playerConnection net.Conn, message *LobbyMessage) (bool, error) {
|
func handleClientLobbyMessage(message *LobbyMessage) (*LobbyMessage, error) {
|
||||||
switch message.Type {
|
switch message.Type {
|
||||||
case "name":
|
case "name":
|
||||||
_, ok := clientPool.clients[message.Content]
|
_, ok := lobbyMembers.Load(message.Content)
|
||||||
if ok {
|
if ok {
|
||||||
SendMessageToClient(playerConnection, &LobbyMessage{Type: "error", Content: "Sorry, that name is already taken"})
|
return &LobbyMessage{Type: "name_error", Content: "Sorry, that name is already taken, please try a different name"}, nil
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
playerID := message.Content
|
|
||||||
clientPool.clients[playerID] = Client{
|
|
||||||
name: playerID,
|
|
||||||
conn: playerConnection,
|
|
||||||
ready: false,
|
|
||||||
}
|
|
||||||
for _, player := range clientPool.clients {
|
|
||||||
err := SendMessageToClient(playerConnection, &LobbyMessage{PlayerId: player.name, Type: "connect", Content: player.name})
|
|
||||||
if err != nil {
|
|
||||||
log.Println("There was an error sending the list of lobby players to client", message.Content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
username := message.Content
|
||||||
|
|
||||||
|
// Send all client messages
|
||||||
|
lobbyMembers.Range(func(lobbyUsername string, client Client) bool {
|
||||||
|
externalMessageChan <- ExternalMessage{Target: username, Message: &LobbyMessage{Type: "connect", Content: lobbyUsername}}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
log.Println("Broadcasting new player", message.Content)
|
log.Println("Broadcasting new player", message.Content)
|
||||||
|
|
||||||
broadcastToLobby(&LobbyMessage{PlayerId: "", Type: "connect", Content: playerID})
|
broadcastToLobby(&LobbyMessage{PlayerId: "", Type: "connect", Content: username})
|
||||||
|
|
||||||
return false, SendMessageToClient(playerConnection, &LobbyMessage{PlayerId: playerID, Type: "name", Content: playerID})
|
return &LobbyMessage{PlayerId: username, Type: "name", Content: username}, nil
|
||||||
case "invite":
|
case "invite":
|
||||||
log.Println("Got invite for player:", message.Content)
|
log.Println("Got invite for player:", message.Content)
|
||||||
invitee, ok := clientPool.clients[message.Content]
|
invitee, ok := lobbyMembers[message.Content]
|
||||||
if !ok {
|
if !ok {
|
||||||
SendMessageToClient(playerConnection, &LobbyMessage{Type: "text", Content: "Sorry, that player is not available..."})
|
return &LobbyMessage{Type: "text", Content: "Sorry, that player is not available..."}, nil
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
SendMessageToClient(invitee.conn, &LobbyMessage{Type: "invite", Content: message.PlayerId})
|
return &LobbyMessage{Type: "invite", Content: message.PlayerId}, nil
|
||||||
return false, nil
|
|
||||||
case "accept_game":
|
case "accept_game":
|
||||||
player := clientPool.clients[message.Content]
|
player := lobbyMembers[message.Content]
|
||||||
|
|
||||||
if err := SendMessageToClient(player.conn, &LobbyMessage{Type: "accept", Content: ""}); err != nil {
|
return &LobbyMessage{Type: "accept", Content: ""}, nil
|
||||||
SendMessageToClient(playerConnection, &LobbyMessage{Type: "error", Content: "Sorry that game is no longer available..."})
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
case "chat":
|
case "chat":
|
||||||
broadcastToLobby(&LobbyMessage{PlayerId: message.PlayerId, Type: "text", Content: message.Content})
|
broadcastToLobby(&LobbyMessage{PlayerId: message.PlayerId, Type: "text", Content: message.Content})
|
||||||
return false, nil
|
return nil, nil
|
||||||
case "decline_game":
|
case "decline_game":
|
||||||
inviter := clientPool.clients[message.Content]
|
inviter := lobbyMembers[message.Content]
|
||||||
SendMessageToClient(inviter.conn, &LobbyMessage{Type: "decline_game", Content: message.PlayerId})
|
return &LobbyMessage{Type: "decline_game", Content: message.PlayerId}, nil
|
||||||
return false, nil
|
|
||||||
case "quit":
|
case "quit":
|
||||||
delete(clientPool.clients, message.PlayerId)
|
delete(lobbyMembers, message.PlayerId)
|
||||||
broadcastToLobby(&LobbyMessage{Type: "disconnect", Content: message.PlayerId})
|
broadcastToLobby(&LobbyMessage{Type: "disconnect", Content: message.PlayerId})
|
||||||
return true, nil
|
return nil, nil
|
||||||
case "ping":
|
case "ping":
|
||||||
SendMessageToClient(playerConnection, &LobbyMessage{Type: "pong", Content: "pong"})
|
return &LobbyMessage{Type: "pong", Content: "pong"}, nil
|
||||||
return false, nil
|
|
||||||
default:
|
default:
|
||||||
SendMessageToClient(playerConnection, &LobbyMessage{Type: "pong", Content: "pong"})
|
return &LobbyMessage{Type: "pong", Content: "pong"}, nil
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendMessageToClient(connection net.Conn, message *LobbyMessage) error {
|
|
||||||
bytes, err := proto.Marshal(message)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error marshalling message. Your protobuf is wack yo.")
|
|
||||||
}
|
|
||||||
_, err = connection.Write(bytes)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error writing to client connection")
|
|
||||||
}
|
|
||||||
fmt.Println("Sent message to client")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func broadcastToLobby(message *LobbyMessage) {
|
func broadcastToLobby(message *LobbyMessage) {
|
||||||
for _, player := range clientPool.clients {
|
for _, player := range lobbyMembers {
|
||||||
err := SendMessageToClient(player.conn, message)
|
bytes, err := proto.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error marshalling broadcast message", err)
|
||||||
|
}
|
||||||
|
_, err = player.Conn.Write(bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error broadcasting to clients...", err)
|
log.Println("Error broadcasting to clients...", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,36 +3,40 @@ package netwrk
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
sync "sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
name string
|
Username string
|
||||||
conn net.Conn
|
Conn net.Conn
|
||||||
ready bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientPool struct {
|
type LobbyPlayersMessage struct {
|
||||||
clients map[string]Client
|
Type string
|
||||||
|
Username string
|
||||||
|
IsAvailable chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type GameClients struct {
|
type ExternalMessage struct {
|
||||||
client1 chan GameMessage
|
Target string
|
||||||
client2 chan GameMessage
|
Message *LobbyMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
type GameChans struct {
|
var lobbyListener chan LobbyPlayersMessage
|
||||||
games map[string]GameClients
|
var externalMessageChan chan ExternalMessage
|
||||||
}
|
|
||||||
|
|
||||||
var clientPool *ClientPool
|
var lobbyMembers sync.Map
|
||||||
var gameChans *GameChans
|
|
||||||
|
func init() {
|
||||||
|
lobbyListener = make(chan LobbyPlayersMessage)
|
||||||
|
externalMessageChan = make(chan ExternalMessage)
|
||||||
|
|
||||||
|
lobbyMembers = sync.Map{}
|
||||||
|
}
|
||||||
|
|
||||||
// Starts listening on port 12345 for TCP connections
|
// Starts listening on port 12345 for TCP connections
|
||||||
// Also creates client pool and game connection singletons
|
// Also creates client pool and game connection singletons
|
||||||
func Listen() {
|
func LobbyListen() {
|
||||||
clientPool = &ClientPool{
|
|
||||||
clients: map[string]Client{},
|
|
||||||
}
|
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", "127.0.0.1:12345")
|
listener, err := net.Listen("tcp", "127.0.0.1:12345")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -41,21 +45,18 @@ func Listen() {
|
||||||
|
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
go func() {
|
for {
|
||||||
for {
|
conn, err := listener.Accept()
|
||||||
conn, err := listener.Accept()
|
log.Println("got a connection!")
|
||||||
log.Println("got a connection!")
|
if err != nil {
|
||||||
if err != nil {
|
log.Println(err)
|
||||||
log.Println(err)
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
go handleLobbyConnection(conn)
|
|
||||||
}
|
}
|
||||||
}()
|
go handleLobbyConnection(conn)
|
||||||
|
|
||||||
gameChans = &GameChans{
|
|
||||||
games: map[string]GameClients{},
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GamesListen() {
|
||||||
|
|
||||||
gameListener, err := net.Listen("tcp", "127.0.0.1:42069")
|
gameListener, err := net.Listen("tcp", "127.0.0.1:42069")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user