From f65a9a5e21860f179859b0be75f7bb30a0253b65 Mon Sep 17 00:00:00 2001
From: owenw2 <owenw2@sp25-cs425-0601.cs.illinois.edu>
Date: Wed, 7 May 2025 17:48:02 -0500
Subject: [PATCH] finished client-side code

---
 mp3/Client/client.go      | 196 ++++++++++++++++++++++++++++++++++++++
 mp3/Makefile              |  13 +++
 mp3/Server/coordinator.go |   1 +
 mp3/Server/receiver.go    |   1 +
 mp3/Server/server.go      |   5 +
 5 files changed, 216 insertions(+)
 create mode 100644 mp3/Client/client.go
 create mode 100644 mp3/Makefile
 create mode 100644 mp3/Server/coordinator.go
 create mode 100644 mp3/Server/receiver.go
 create mode 100644 mp3/Server/server.go

diff --git a/mp3/Client/client.go b/mp3/Client/client.go
new file mode 100644
index 0000000..3c580a5
--- /dev/null
+++ b/mp3/Client/client.go
@@ -0,0 +1,196 @@
+package main
+
+import (
+	"bufio"
+	"encoding/gob"
+	"fmt"
+	"net"
+	"os"
+	"strconv"
+	"strings"
+)
+
+type Client struct {
+	Name         string        // unique identifier for client
+	Connection   net.Conn      // tcp connection to server
+	Connected    bool          // true if established connection
+	Servers      []string      // server ip addresses and ports
+	ResponseChan chan Response // channel for responses from server
+}
+
+type Request struct {
+	Transaction string // type of transaction
+	Branch      string
+	Account     string
+	Amount      int
+}
+
+type Response struct {
+	Result  bool
+	Message bool
+}
+
+func (client *Client) run_server() {
+	// place server responses into channel
+	for {
+		response := Response{}
+		dec := gob.NewDecoder(client.Connection)
+		dec.Decode(&response)
+		client.ResponseChan <- response
+	}
+}
+
+func (client *Client) connect() {
+	request := Request{}
+	response := Response{}
+
+	request.Transaction = "BEGIN"
+	request.Branch = client.Name
+	request.Account = client.Name
+
+	for _, server := range client.Servers {
+		connection, err := net.Dial("tcp", server)
+		if err != nil {
+			continue
+		}
+
+		// send connection request
+		enc := gob.NewEncoder(connection)
+		enc.Encode(&request)
+		// receive connection response
+		dec := gob.NewDecoder(connection)
+		dec.Decode(&response)
+
+		if response.Result {
+			client.Connection = connection
+			client.ResponseChan <- response
+			go client.run_server() // start server if valid connection response
+			return
+		}
+	}
+	client.ResponseChan <- response
+}
+
+func (client *Client) send_request(transaction string, account string, amount int) {
+	request := Request{}
+	request.Transaction = transaction
+	request.Amount = amount
+
+	if transaction == "COMMIT" || transaction == "ABORT" {
+		request.Account = ""
+		request.Branch = ""
+	} else {
+		substrings := strings.Split(account, ".")
+		request.Account = substrings[1]
+		request.Branch = substrings[0]
+	}
+
+	enc := gob.NewEncoder(client.Connection)
+	enc.Encode(&request)
+}
+
+func (client *Client) 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 < 5; i++ {
+		text, serr := reader.ReadString('\n')
+		substrings := strings.Split(text, " ")
+		if serr != nil && i < 4 {
+			fmt.Println("failed to read config")
+		}
+		// remove new line char from port
+		substrings[2] = strings.ReplaceAll(substrings[2], "\n", "")
+
+		// formatteed server address as sp25-cs425-0601.cs.illinois.edu:1234
+		client.Servers = append(client.Servers, substrings[1]+":"+substrings[2])
+	}
+
+	config.Close()
+}
+
+func main() {
+	// init client
+	client := Client{
+		Name:         "",
+		ResponseChan: make(chan Response),
+	}
+
+	// read config and attach server:port
+	client.read_file("config.txt")
+	reader := bufio.NewReader(os.Stdin)
+
+	// get user inputs
+	for {
+		input, _ := reader.ReadString('\n')
+		substrings := strings.Split(input, " ")
+
+		// handle user input
+		if substrings[0] == "BEGIN" {
+			// check if connection exists
+			if client.Connected {
+				continue
+			}
+			// setup server connection
+			go client.connect()
+			response := <-client.ResponseChan
+			if response.Result {
+				client.Connected = true
+				fmt.Println("OK")
+			} else {
+				fmt.Println("ABORTED")
+				return
+			}
+		} else if substrings[0] == "COMMIT" {
+			go client.send_request(substrings[0], "", 0)
+			response := <-client.ResponseChan
+			if response.Result {
+				fmt.Println("COMMIT OK")
+				return
+			} else {
+				fmt.Println("ABORTED")
+				return
+			}
+		} else if substrings[0] == "ABORT" {
+			go client.send_request(substrings[0], "", 0)
+			<-client.ResponseChan
+			fmt.Println("ABORTED")
+			return
+		} else if substrings[0] == "DEPOSIT" {
+			amount, _ := strconv.Atoi(substrings[2])
+			go client.send_request(substrings[0], substrings[1], amount)
+			response := <-client.ResponseChan
+			if response.Result {
+				fmt.Println("OK")
+			} else {
+				fmt.Println("ABORTED")
+				return
+			}
+		} else if substrings[0] == "BALANCE" {
+			go client.send_request(substrings[0], substrings[1], 0)
+			response := <-client.ResponseChan
+			if response.Result {
+				fmt.Println(response.Message)
+			} else {
+				fmt.Println("NOT FOUND, ABORTED")
+				return
+			}
+		} else if substrings[0] == "WITHDRAW" {
+			amount, _ := strconv.Atoi(substrings[2])
+			go client.send_request(substrings[0], substrings[1], amount)
+			response := <-client.ResponseChan
+			if response.Result {
+				fmt.Println("OK")
+			} else {
+				fmt.Println("NOT FOUND, ABORTED")
+				return
+			}
+		}
+	}
+}
diff --git a/mp3/Makefile b/mp3/Makefile
new file mode 100644
index 0000000..c58ea65
--- /dev/null
+++ b/mp3/Makefile
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+.PHONY: server client clean
+
+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
+
+clean:
+	rm -f server client
+
diff --git a/mp3/Server/coordinator.go b/mp3/Server/coordinator.go
new file mode 100644
index 0000000..4c7185b
--- /dev/null
+++ b/mp3/Server/coordinator.go
@@ -0,0 +1 @@
+package Server
diff --git a/mp3/Server/receiver.go b/mp3/Server/receiver.go
new file mode 100644
index 0000000..4c7185b
--- /dev/null
+++ b/mp3/Server/receiver.go
@@ -0,0 +1 @@
+package Server
diff --git a/mp3/Server/server.go b/mp3/Server/server.go
new file mode 100644
index 0000000..e6ac37b
--- /dev/null
+++ b/mp3/Server/server.go
@@ -0,0 +1,5 @@
+package Server
+
+func main() {
+
+}
-- 
GitLab