diff --git a/mp3/Client/client.go b/mp3/Client/client.go index 3c580a58405fb150a27a9f8947128017b8ec3676..2a892ce8abf58e7ea2536b427c0c3a8a538828c3 100644 --- a/mp3/Client/client.go +++ b/mp3/Client/client.go @@ -8,10 +8,12 @@ import ( "os" "strconv" "strings" + "time" ) type Client struct { Name string // unique identifier for client + Timestamp time.Time // timestamp of creation Connection net.Conn // tcp connection to server Connected bool // true if established connection Servers []string // server ip addresses and ports @@ -36,6 +38,7 @@ func (client *Client) run_server() { response := Response{} dec := gob.NewDecoder(client.Connection) dec.Decode(&response) + fmt.Println("Received result", response.Result, response.Message) client.ResponseChan <- response } } @@ -48,13 +51,17 @@ func (client *Client) connect() { request.Branch = client.Name request.Account = client.Name + fmt.Println("Attempting connections") + for _, server := range client.Servers { + fmt.Println("Sending connection request to", server) connection, err := net.Dial("tcp", server) if err != nil { + fmt.Println("Failed to connect to", server) continue } - // send connection request + // send begin request enc := gob.NewEncoder(connection) enc.Encode(&request) // receive connection response @@ -68,6 +75,7 @@ func (client *Client) connect() { return } } + fmt.Println("Was not able to connect to any servers") client.ResponseChan <- response } @@ -99,7 +107,7 @@ func (client *Client) read_file(config_name string) { reader := bufio.NewReader(config) // assumption that only ever have 5 servers (no more, no less) - for i := 0; i < 5; i++ { + for i := 0; i < 1; i++ { text, serr := reader.ReadString('\n') substrings := strings.Split(text, " ") if serr != nil && i < 4 { @@ -119,11 +127,19 @@ func main() { // init client client := Client{ Name: "", + Timestamp: time.Time{}, ResponseChan: make(chan Response), } + clientName := os.Args[0] + configPath := os.Args[2] + // read config and attach server:port - client.read_file("config.txt") + client.Name = clientName + client.read_file(configPath) + + fmt.Println("Client State:", client.Name, client.Timestamp, client.Connection, client.Connected, client.Servers, len(client.Servers)) + reader := bufio.NewReader(os.Stdin) // get user inputs @@ -131,6 +147,14 @@ func main() { input, _ := reader.ReadString('\n') substrings := strings.Split(input, " ") + if len(substrings) == 1 { + substrings[0] = strings.ReplaceAll(substrings[0], "\n", "") + } else if len(substrings) == 2 { + substrings[1] = strings.ReplaceAll(substrings[1], "\n", "") + } else if len(substrings) == 3 { + substrings[2] = strings.ReplaceAll(substrings[2], "\n", "") + } + // handle user input if substrings[0] == "BEGIN" { // check if connection exists @@ -138,16 +162,18 @@ func main() { continue } // setup server connection + fmt.Println("HERE") go client.connect() response := <-client.ResponseChan if response.Result { client.Connected = true - fmt.Println("OK") + client.Timestamp = time.Now() + } else { fmt.Println("ABORTED") return } - } else if substrings[0] == "COMMIT" { + } else if substrings[0] == "COMMIT" && client.Connected { go client.send_request(substrings[0], "", 0) response := <-client.ResponseChan if response.Result { @@ -157,12 +183,12 @@ func main() { fmt.Println("ABORTED") return } - } else if substrings[0] == "ABORT" { + } else if substrings[0] == "ABORT" && client.Connected { go client.send_request(substrings[0], "", 0) <-client.ResponseChan fmt.Println("ABORTED") return - } else if substrings[0] == "DEPOSIT" { + } else if substrings[0] == "DEPOSIT" && client.Connected { amount, _ := strconv.Atoi(substrings[2]) go client.send_request(substrings[0], substrings[1], amount) response := <-client.ResponseChan @@ -172,7 +198,7 @@ func main() { fmt.Println("ABORTED") return } - } else if substrings[0] == "BALANCE" { + } else if substrings[0] == "BALANCE" && client.Connected { go client.send_request(substrings[0], substrings[1], 0) response := <-client.ResponseChan if response.Result { @@ -181,7 +207,7 @@ func main() { fmt.Println("NOT FOUND, ABORTED") return } - } else if substrings[0] == "WITHDRAW" { + } else if substrings[0] == "WITHDRAW" && client.Connected { amount, _ := strconv.Atoi(substrings[2]) go client.send_request(substrings[0], substrings[1], amount) response := <-client.ResponseChan diff --git a/mp3/Makefile b/mp3/Makefile index c58ea652b0c9c50ede2a006ac5f936ec80344202..7f1c8e1340239a05e159daedbd9cb0d0ea888983 100644 --- a/mp3/Makefile +++ b/mp3/Makefile @@ -5,8 +5,8 @@ client : Client/client.go go build -o client Client/client.go -server : Server/server.go Server/coordinator.go Server/receiver.go - go build -o server Server/server.go Server/coordinator.go Server/receiver.go +server : Server/server.go + go build -o server Server/server.go clean: rm -f server client diff --git a/mp3/Server/coordinator.go b/mp3/Server/coordinator.go deleted file mode 100644 index 4c7185bc2e7077da9eb9c127efe6d092c32a5798..0000000000000000000000000000000000000000 --- a/mp3/Server/coordinator.go +++ /dev/null @@ -1 +0,0 @@ -package Server diff --git a/mp3/Server/receiver.go b/mp3/Server/receiver.go deleted file mode 100644 index 4c7185bc2e7077da9eb9c127efe6d092c32a5798..0000000000000000000000000000000000000000 --- a/mp3/Server/receiver.go +++ /dev/null @@ -1 +0,0 @@ -package Server diff --git a/mp3/Server/server.go b/mp3/Server/server.go index e6ac37bff89f1f3d01b4cd8c68370590d5afba49..7b354e3f6f9d861a8b28609970dd0ec368e1ed09 100644 --- a/mp3/Server/server.go +++ b/mp3/Server/server.go @@ -1,5 +1,166 @@ -package Server +package main + +import ( + "bufio" + "encoding/gob" + "fmt" + "net" + "os" + "strings" + "sync" + "time" +) + +type Server struct { + BranchName string + Address string + BranchNameToAddress map[string]string + Accounts map[string]*Account + Peers map[string]net.Conn // Connected peers + PeerLock sync.Mutex // Lock for peer map + ClientChan chan Request + // PeerChan chan PeerReque + + // ClientListener net.Listener + // PeerListener net.Listener +} + +type WriteEntry struct { + Timestamp time.Time + OperationValue int +} + +type Account struct { + Name string + Balance int + CreatedBy string + RTS []string + TW map[string]*WriteEntry // tentative writes + WriteTimestampCommitted []time.Time +} + +type Request struct { + Transaction string // type of transaction + Branch string + Account string + Amount int +} + +type Response struct { + Result bool + Message bool +} + +func (server *Server) handle_transaction() { + +} + +func (server *Server) handle_client(clientConn net.Conn) { + request := Request{} + + dec := gob.NewDecoder(clientConn) + dec.Decode(&request) + + fmt.Println("Got client message") +} + +// listens to tcp netConn from client and then handles (this is only necessary if it is a coordinator server) +func (server *Server) listen_to_clients() { + input, err := net.Listen("tcp", server.Address) + if err != nil { + fmt.Println("Listening on server failed") + } + + defer input.Close() + for { + conn, err := input.Accept() + if err != nil { + fmt.Println("Error accepting client connection", err) + continue + } + fmt.Println("Received connection", conn) + go server.handle_client(conn) + } +} + +// lsiten to tcp from other servers and handle necessary transactions +func (server *Server) connect_to_peers() { + for address := range server.Peers { + go func(peerAddr string) { + var conn net.Conn + var err error + for { + conn, err = net.Dial("tcp", peerAddr) + if err == nil { + break + } + time.Sleep(2 * time.Second) + } + server.PeerLock.Lock() + server.Peers[peerAddr] = conn + server.PeerLock.Unlock() + fmt.Println("Connected to peer", peerAddr) + // Handle peer communication here if needed + }(address) + } +} + +func (server *Server) read_file(config_name string) { + config, error := os.Open(config_name) + if error != nil { + fmt.Println("failed to open config") + return + } + + reader := bufio.NewReader(config) + + // assumption that only ever have 5 servers (no more, no less) + for i := 0; i < 1; i++ { + text, serr := reader.ReadString('\n') + if serr != nil && i < 4 { + fmt.Println("failed to read config", serr) + } + substrings := strings.Split(text, " ") + // remove new line char from port + substrings[2] = strings.ReplaceAll(substrings[2], "\n", "") + + if substrings[0] == server.BranchName { + server.Address = substrings[1] + ":" + substrings[2] + continue + } + + // formatteed server address as sp25-cs425-0601.cs.illinois.edu:1234 + server.Peers[substrings[1]+":"+substrings[2]] = nil + server.BranchNameToAddress[substrings[0]] = substrings[1] + ":" + substrings[2] + } + + config.Close() +} func main() { + // init server + server := Server{} + + branchName := os.Args[0] + configPath := os.Args[2] + + server.BranchName = branchName + server.BranchNameToAddress = make(map[string]string) + server.Accounts = make(map[string]*Account) + server.Peers = make(map[string]net.Conn) + server.read_file(configPath) + + fmt.Println("Server State:", server.BranchName, server.Address, server.BranchNameToAddress, server.Accounts, server.Peers) + + go server.listen_to_clients() + // go server.connect_to_peers() + + for { + continue + } + // timstamped concurrency + // init RTS and TW lists (ordered by timestamp) + //=\ + // Strict Timestamp Ordering } diff --git a/mp3/client b/mp3/client new file mode 100755 index 0000000000000000000000000000000000000000..f781997471f0e2377f37798542f1e3e0c0aa0639 Binary files /dev/null and b/mp3/client differ diff --git a/mp3/config.txt b/mp3/config.txt index 036d1dba0f487b6d650500e0be82bc613213e4cd..c279cbab78ae8d978d13bd8cddd0fd27292a88f5 100644 --- a/mp3/config.txt +++ b/mp3/config.txt @@ -2,4 +2,14 @@ A sp25-cs425-0601.cs.illinois.edu 1234 B sp25-cs425-0602.cs.illinois.edu 1234 C sp25-cs425-0603.cs.illinois.edu 1234 D sp25-cs425-0604.cs.illinois.edu 1234 -E sp25-cs425-0605.cs.illinois.edu 1234 \ No newline at end of file +E sp25-cs425-0605.cs.illinois.edu 1234 + + +A localhost 1000 +B localhost 1001 +C localhost 1002 +D localhost 1003 +E localhost 1004 + +go run ./Client/client.go abcd config_test.txt +go run ./Server/server.go A config_test.txt \ No newline at end of file diff --git a/mp3/config_test.txt b/mp3/config_test.txt new file mode 100644 index 0000000000000000000000000000000000000000..65e28db7a53e6595b4d0c902c13a6a81a3a18b09 --- /dev/null +++ b/mp3/config_test.txt @@ -0,0 +1 @@ +A sp25-cs425-0601.cs.illinois.edu 1234 \ No newline at end of file