From 834321cc8d798d8c10599261d7ac2198d8609b69 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 5 Oct 2023 23:29:38 -0400 Subject: [PATCH] fixed bugs with /list/, /add/, got /remove/ working --- client.go | 66 +++++++++++++++++-------------- server.go | 113 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 113 insertions(+), 66 deletions(-) diff --git a/client.go b/client.go index ad5449c..7149dee 100644 --- a/client.go +++ b/client.go @@ -1,10 +1,11 @@ // ============================================================================= // Auth: alex // File: client.go -// Revn: 10-02-2023 1.0 +// Revn: 10-05-2023 2.0 // Func: ask server for a message of the day quote // // TODO: document +// expand on /ba/ failures // add more flags? // log errors in logfile // ============================================================================= @@ -23,6 +24,9 @@ // imported check() from soary // 09-29-2023: commented handle() //*10-02-2023: commented main(), and friends +//*10-05-2023: /remove/ works +// removed -d flag +// commented // // ============================================================================= @@ -41,7 +45,6 @@ import ( ) - // print errors if they occur, quit func check( err error ) { @@ -72,12 +75,32 @@ func check( err error ) { } +// get user input +func in( prompt string ) string { + fmt.Print( prompt ) // print user prompt + var input string // declare var to hold user input + fmt.Scanln( &input ) // get user input + // try to convert to an int, discard results + _, err := strconv.Atoi( input ) + // if there was an error, user didn't input an int + if err != nil { + // warn user against this + fmt.Println( "Input must be a number" ) + input = in( prompt ) // try to get user input again + // this, like handle() calling handle(), seems like a super + // bad idea, stack-wise... + } + // once user has properly inputted a number, return string of num + return input +} + + // seed and get a new rng func seed() *rand.Rand { // use current time to seed random number s := rand.NewSource( time.Now().UnixNano() ) r := rand.New( s ) // create new random number from seed - return r // return random number + return r // return random number } @@ -85,16 +108,9 @@ func seed() *rand.Rand { func draw() string { rn := seed() // get a random seed r := rn.Intn( qsize ) // get a random number using seed - if debug { // XXX debug print - fmt.Println( "random number: ", r ) - } // convert random number to ascii, because converting // ints to bytes ( for networking ) and back is obnoxious rsz := strconv.Itoa( r ) - if debug { // XXX debug print - fmt.Println( "converted size var" ) - fmt.Printf( rsz + ": %T\n", rsz ) - } return rsz // return rand size } @@ -137,7 +153,7 @@ func handle( conn net.Conn ) { quotes := strings.Split( msg[1], "\n" ) for p, v := range quotes { // iterate over quotes // print num of quote, followed by that quote - fmt.Println( p+1, "\t", v ) + fmt.Println( p + 1, "\t", v ) } resp = "te@success" // set transaction end message case "aa": // /aa/, add answer @@ -163,15 +179,18 @@ func handle( conn net.Conn ) { // more simply, but this, I feel, has some nuance to it that I // actually like // redo /la/, list all quotes + // split recv'd message over newline to create quote list quotes := strings.Split( msg[1], "\n" ) - for p, v := range quotes { - fmt.Println( p+1, "\t", v ) + for p, v := range quotes { // iterate over quotes + // print num of quote, followed by that quote + fmt.Println( p + 1, "\t", v ) } - // TODO get user input + // ask user which quote to remove + resp = "r2@" + in( "\n-> " ) case "r2": // /r2/, remove ( second transaction ) // if server says remove succeeded if msg[1] == "success" { - fmt.Println( "Remove successful" ) // print success + fmt.Println( "Remove successful\n" ) // success // list all quotes to validate remove succeeded // TODO should /aa/ also make /lr/ before /te/? resp = "lr@dumvar" // set transaction end message @@ -193,17 +212,12 @@ func handle( conn net.Conn ) { resp = "te@error" // set transaction end message default: // something undefined entirely // TODO write out to file - fmt.Println( "Message header not recognized" ) - fmt.Println( msg ) + //fmt.Println( "Message header not recognized" ) + //fmt.Println( msg ) conn.Close() // TODO how important is this line return // dead return, essentially lets program quit } - if debug { // XXX debug print - fmt.Print( "raw read: " + strconv.Itoa( n ) + " bytes " ) - fmt.Println( buffer[:n] ) - } - // send formulated response back to server _, err = conn.Write( []byte( resp ) ) check( err ) // make sure write worked @@ -218,7 +232,6 @@ var conn net.Conn // keep track of connection // global flag variables -var debug bool // debug prints useful information var add bool // add new quotes to quote file ( on server ) var remove bool // remove quotes from quote file ( on server ) var list bool // request entire quote file from server @@ -228,17 +241,12 @@ var dest string // provide a new destination ip and port func main() { // define flags - flag.BoolVar( &debug, "d", false, "print debug info" ) flag.BoolVar( &add, "a", false, "add quote to list" ) flag.BoolVar( &remove, "r", false, "remove quote from list" ) flag.BoolVar( &list, "l", false, "print quote list" ) flag.StringVar( &dest, "ip", ":1300", "ip:port of server" ) flag.Parse() // process flags - if debug { // XXX debug print - fmt.Println( "ip:port = ", dest ) - } - service := dest // declare server ip:port // create address object @@ -273,7 +281,7 @@ func main() { } case remove: // if remove flag is active // if arguments were specified - if len( flag.Args() ) >= 0 { + if len( flag.Args() ) > 0 { // argument is supposed to the number of the quote to // be removed, get first arg // cast to int just to make sure it's a valid number diff --git a/server.go b/server.go index 891e758..ba5a942 100644 --- a/server.go +++ b/server.go @@ -1,13 +1,13 @@ // ============================================================================= // Auth: Alex Celani // File: server.go -// Revn: 10-02-2023 1.0 +// Revn: 10-05-2023 2.0 // Func: host connection, reply to speak.go // -// TODO: fix remove -// write back to file, re-read file -// add more /codes/ to handle +// TODO: add more /codes/ to handle // add flags +// write usage and errors to logfile +// send logfile to client on request // ============================================================================= // CHANGE LOG // ----------------------------------------------------------------------------- @@ -24,12 +24,20 @@ //*10-02-2023: commented handle() // added checks to /qr/ and /r2/ to make sure recv'd // length is valid +// wrote writeFile() +//*10-05-2023: commented +// imported check() to ignore EOF +// fixed bug in /r2/ where removing quote at final +// position would break +// removed deadcode from /r2/, unused "quit" bool? +// // ============================================================================= package main import ( "fmt" // Println + "io" // io.EOF "io/ioutil" // ReadFile "net" // ResovleTCPAddr, ListenTCP, listener.Accept // conn.Read,Write @@ -49,6 +57,37 @@ func check( err error ) { } +// FIXME clean this two check() shit up +// print errors if they occur, quit +func checkN( err error, conn net.Conn ) { + + var errep string // declare error report string + switch err { // switch case over error input + case nil: // if there was no error + // then there was no error + errep = "err is nil" + case io.EOF: // if there was an End Of File error + errep = "Error: " + err.Error() // document error + conn.Close() // close connection + default: // anything besides those are a big deal + errep = "Fatal: " + err.Error() + } + + var critical bool // declare critical error flag + // must be neither nil nor EOF + critical = err != nil && err != io.EOF + if critical { // XXX critical print + // TODO at some point, critical should be logging instead of + // printing, only verbose should print + fmt.Println( "check() -> ", errep ) + } + + if critical { // if there was a critical error + os.Exit( 1 ) // cut and run + } +} + + // read file and create quote list func fread() string { // open file "quotes", read entire file as bytes into qfile @@ -69,10 +108,12 @@ func fread() string { // write qfile back to file func writeFile( f string ) { - file, err := os.Create( "quotes" ) - check( err ) + // open file list.q as variable file + file, err := os.Create( "list.q" ) + check( err ) // make sure open worked + // write input string ( quote file ) back to file _, err = file.WriteString( f ) - check( err ) + check( err ) // make sure writeback worked } @@ -83,7 +124,7 @@ func handle( conn net.Conn ) { var buffer [256]byte // read n bytes from client n, err := conn.Read( buffer[:] ) - check( err ) // make sure read worked + checkN( err, conn ) // make sure read worked // cast message to string, take first n bytes, split over @ command := strings.Split( string( buffer[:n] ), "@" ) @@ -105,7 +146,7 @@ func handle( conn net.Conn ) { if nerr != nil { // formulate an error message // TODO flesh this out more - resp = "ba@Number not understood" // bad answer + resp = "ba@qr@!" // bad answer } else { // comm[1] was a number, but... switch { // how do we know it's a valid number case num > len( qlist ): @@ -114,7 +155,7 @@ func handle( conn net.Conn ) { // why bad? num is > case num < 0: // bad answer in quote request - resp = "bad@qr@-" + resp = "ba@qr@-" // why bad? num is - default: // good num, get quote, send off @@ -123,13 +164,14 @@ func handle( conn net.Conn ) { } case "lr": // /lr/, list request // just concat entire list to send - resp = "la@" + qfile[:len( qfile ) - 1] // list answer + //resp = "la@" + qfile[:len( qfile ) - 1] // list answer + resp = "la@" + qfile // list answer // TODO what happens if this is longer than 256 char? case "ar": // /ar/, add request // append new quote to list qlist = append( qlist, command[1] ) // also append new quote to file variable - qfile = qfile + command[1] + "\n" + qfile = qfile + "\n" + command[1] writeFile( qfile ) resp = "aa@success" // add answer // TODO write to file @@ -144,9 +186,11 @@ func handle( conn net.Conn ) { if nerr != nil { // formulate an error message // TODO flesh this out more - resp = "ba@Number not understood" // bad answer + resp = "ba@r2@!" // bad answer } else { // comm[1] was a number, but... + num = num - 1 switch { // how do we know it's a valid number + // valid numbers are from 0 - len-1 case num > len( qlist ): // bad answer in quote request resp = "ba@r2@>" @@ -155,36 +199,32 @@ func handle( conn net.Conn ) { // bad answer in quote request resp = "ba@r2@-" // why bad? num is - + // if num is not OUT OF RANGE, must be in range default: - qlist[num + 1] = qlist[len( qlist ) - 1] + // replace the quote at that position with + // final quote + qlist[num] = qlist[len( qlist ) - 1] + // remove second copy of quote qlist = qlist[:len( qlist ) - 1] - var f string = "" + // O(1) remove from list at any position + // must entirely recreate quote string + var f string = "" // init empty string + // iterate over list, disregard index for _, v := range qlist { + // add next quote to file and separate + // quotes with newline f = f + v + "\n" } - f = f[:len( f ) - 1] + // remove trailing newline, to prevent ghost + f = f[:len( f ) - 1] // quote in lr + // reassign global string variable to + // recreated quote string qfile = f - writeFile( qfile ) - resp = "r2@" + qfile + writeFile( qfile ) // write back to file + // let client know remove was successful + resp = "r2@success" } } - /* - resp = "r2@" // remove request 2 - // - index, nerr := strconv.Atoi( command[1] ) - if nerr == nil { - if index < len( qlist ) { - qlist[index] = qlist[len( qlist ) - 1] - qlist = qlist[:len( qlist ) - 1] - //writeFile() //TODO - resp = resp + "success" - } else { - resp = resp + "error" - } - } else { - resp = resp + "error" - } - */ case "te": // /te/, transaction end // TODO should I be sending something? // TODO is it better to close now or outside of handle() @@ -197,7 +237,7 @@ func handle( conn net.Conn ) { // write response to client _, err = conn.Write( []byte( resp ) ) - check( err ) // make sure write worked + checkN( err, conn ) // make sure write worked handle( conn ) // call handle() again to get response from client @@ -207,7 +247,6 @@ func handle( conn net.Conn ) { // globals var qlist []string // list of quotes var qfile string // file object -var quit bool // main, create port and wait for connection