diff --git a/dev/seq/Makefile b/dev/seq/Makefile deleted file mode 100644 index 1611425..0000000 --- a/dev/seq/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: client server - -client: - go build -o ekho client.go - -server: - go build -o motd server.go diff --git a/dev/seq/client.go b/dev/seq/client.go deleted file mode 100644 index 7149dee..0000000 --- a/dev/seq/client.go +++ /dev/null @@ -1,321 +0,0 @@ -// ============================================================================= -// Auth: alex -// File: client.go -// 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 -// ============================================================================= -// CHANGE LOG -// ----------------------------------------------------------------------------- -// 05-11-2022: init -// 05-17-2022: changed an entry in the response table -// 08-16-2023: copied from speak.go -// gutted, rewrote -// 09-12-2023: added size conversation -// added -d, -l, and -dest flags -// commented -// 09-21-2023: began complete-ass overhaul of handle() system -// wrote draft of draw() -// 09-26-2023: made draw return size and reference globals -// 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 -// -// ============================================================================= - -package main - -import ( - "io" // io.EOF - "flag" // BoolVar, StringVar, Parse - "fmt" // Println - "math/rand" // NewSource, New, Intn, *rand.Rand - "net" // ResolveTCPAddr, DialTCP, conn.Write,Read - "os" // Exit - "strconv" // Atoi, Itoa - "strings" // Split - "time" // Now, UnixNano -) - - -// print errors if they occur, quit -func check( err error ) { - - 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 - } -} - - -// 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 -} - - -// get a random number -func draw() string { - rn := seed() // get a random seed - r := rn.Intn( qsize ) // get a random number using seed - // convert random number to ascii, because converting - // ints to bytes ( for networking ) and back is obnoxious - rsz := strconv.Itoa( r ) - return rsz // return rand size -} - - -// get server response and print -func handle( conn net.Conn ) { - - var buffer [512]byte // create buffer to hold response - // read n bytes from server into buffer ( byte slice ) - n, err := conn.Read( buffer[:] ) - check( err ) // check for errors - - // split recv'd message over @, separate header from message - msg := strings.Split( string( buffer[:n] ), "@" ) - - var resp string // declare response variable - switch msg[0] { // switch/case over the header - // if message is... - case "sa": // /sa/, size answer - // convert back half to int, catch error - size, nerr := strconv.Atoi( msg[1] ) - if nerr == nil { // if there was no error - qsize = size // set size global to recv'd size - } else { - // if int conversion failed, just quit - // TODO make more robust - os.Exit( 1 ) - } - req := draw() // draw a random number - resp = "qr@" + req // create quote query with rng - case "ba": // /ba/, bad answer - // TODO create server-side, and handle client-side - fmt.Println( "error in " + msg[1] + ": " + msg[2] ) - resp = "te@error" // set transaction end message - case "qa": // /qa/, quote answer - fmt.Println( msg[1] ) // whole-ass just print quote - resp = "te@success" // set transaction end message - case "la": // /la/, list answer - // split recv'd message over newline to create quote list - 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 ) - } - resp = "te@success" // set transaction end message - case "aa": // /aa/, add answer - // if server says add succeeded - if msg[1] == "success" { - fmt.Println( "Add successful" ) // print success - resp = "te@success" // set transaction end message - // if server says add failed - } else if msg[1] == "error" { - fmt.Println( "Add failed" ) // print fail - resp = "te@error" // set transaction end message - // unknown status message - } else { - // print unknown status - fmt.Println( "Unknown status code: " + msg[1] ) - // TODO should this be unknown instead of error? - resp = "te@error" // set transaction end message - } - case "r1": // /r1/, remove ( first transaction ) - // the idea is that if the user doesn't specify which quote to - // remove, list all quotes and let the user choose the quote - // to remove. There was probably a way to handle this a little - // 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 { // iterate over quotes - // print num of quote, followed by that quote - fmt.Println( p + 1, "\t", v ) - } - // 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\n" ) // success - // list all quotes to validate remove succeeded - // TODO should /aa/ also make /lr/ before /te/? - resp = "lr@dumvar" // set transaction end message - // if server says remove failed - } else if msg[1] == "error" { - fmt.Println( "Remove failed" ) // print failure - resp = "te@error" // set transaction end message - // if unknown status message - } else { - // print unknown status - fmt.Println( "Unknown error code: " + msg[1] ) - // TODO should this be unknown instead of error? - resp = "te@error" // set transaction end message - } - case "br": // /br/, bad request - // client has asked for something nonsensical - // TODO write out to file - fmt.Println( "Client sent a bad request" ) - 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 ) - conn.Close() // TODO how important is this line - return // dead return, essentially lets program quit - } - - // send formulated response back to server - _, err = conn.Write( []byte( resp ) ) - check( err ) // make sure write worked - - handle( conn ) // call handle again -} - - -// globals -var qsize int // keep track of num of quotes -var conn net.Conn // keep track of connection - - -// global flag variables -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 -var dest string // provide a new destination ip and port - - -func main() { - - // define flags - 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 - - service := dest // declare server ip:port - - // create address object - addr, err := net.ResolveTCPAddr( "tcp", service ) - check( err ) // check for errors - - // make connection with object - conn, err = net.DialTCP( "tcp", nil, addr ) - check( err ) // check for errors - - // block for all flags - var command string - switch { // empty switch statement is basically an if - case list: // if list flag is active - command = "lr@dumvar" // list request - // TODO come up with a useful argument, instead of dumvar - case add: // if add flag is active - // if arguments were specified - if len( flag.Args() ) != 0 { - command = "ar@" // preface command w/ add request - // need to concat flag.args - for _, v := range flag.Args() { - // add the string and a space to command - command = command + v + " " - } - // remove the trailing space - command = command[:len( command ) - 1] - } else { // if no arguments were specified - // print that you need args and bail - fmt.Println( "/a/ flag must be used with an arugment" ) - os.Exit( 1 ) - } - case remove: // if remove flag is active - // if arguments were specified - 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 - // assuming the user knows what they're doing - _, rerr := strconv.Atoi( flag.Args()[0] ) - // if there was an error, just pretend there's no args - if rerr != nil { - command = "r1@dumvar" // remove request 1 - // TODO come up w/ useful argument, replace dumvar - } else { - // if user knows the number, take care of it - // arg[0] is a string, so concat is cool - // jump right into remove request 2 - command = "r2@" + flag.Args()[0] - } - } else { // if no argument was specified for remove - // jump right into remove request 1 - command = "r1@dumvar" - } - default: // if no flag was specified - // begin transaction for quote request - command = "sr@please" // size request - } - - // write command to server, beginning transaction - _, err = conn.Write( []byte( command ) ) - check( err ) // make sure write worked - - handle( conn ) // handle response - // TODO stack trace when handle returns, should probably be - // updated - conn.Close() // close connection when finished - - os.Exit( 0 ) // exit - -} - diff --git a/dev/seq/ekho b/dev/seq/ekho deleted file mode 100755 index dd6a82f..0000000 Binary files a/dev/seq/ekho and /dev/null differ diff --git a/dev/seq/motd b/dev/seq/motd deleted file mode 100755 index 465376a..0000000 Binary files a/dev/seq/motd and /dev/null differ diff --git a/dev/seq/pieces/client b/dev/seq/pieces/client deleted file mode 100755 index c53e43f..0000000 Binary files a/dev/seq/pieces/client and /dev/null differ diff --git a/dev/seq/pieces/client.go b/dev/seq/pieces/client.go deleted file mode 100644 index 29b45be..0000000 --- a/dev/seq/pieces/client.go +++ /dev/null @@ -1,190 +0,0 @@ -// ============================================================================= -// Auth: alex -// File: client.go -// Revn: 05-19-2024 0.2 -// Func: ask server for a message of the day quote -// -// TODO: gut -// write -// ============================================================================= -// CHANGE LOG -// ----------------------------------------------------------------------------- -// 05-18-2024: gutted -// 05-19-2024: fixed -// commented -// -// ============================================================================= - -package main - -import ( - //"io" // io.EOF - "flag" // BoolVar, StringVar, Parse - "fmt" // Println - "net" // ResolveTCPAddr, DialTCP, conn.Write,Read - "os" // Exit - //"strconv" // Atoi, Itoa - //"strings" // Split -) - - -/* -// print errors if they occur, quit -func check( err error ) { - - 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 - } -} - - -// get server response and print -func handle( conn net.Conn ) { - - var buffer [tsize]byte // create buffer to hold response - // read n bytes from server into buffer ( byte slice ) - n, err := conn.Read( buffer[:] ) - check( err ) // check for errors - - // split recv'd message over @, separate header from message - msg := strings.Split( string( buffer[:n] ), "@" ) - - var resp string // declare response variable - switch msg[0] { // switch/case over the header - case "la": // /la/, list answer - if len( msg ) > 2 { - resp = "lr@" - - } else { - // split recv'd message over newline to create quote list - 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 ) - } - resp = "te@success" - } - default: // something undefined entirely - // TODO write out to file - //fmt.Println( "Message header not recognized" ) - //fmt.Println( msg ) - conn.Close() // TODO how important is this line - return // dead return, essentially lets program quit - } - - // send formulated response back to server - _, err = conn.Write( []byte( resp ) ) - check( err ) // make sure write worked - - handle( conn ) // call handle again -} -*/ - - -// quick check for errors -func check( err error ) { - if err != nil { // err should be nil, !nil is bad - // print error and ditch - fmt.Println( "fatal::", err ) - os.Exit( 1 ) - } -} - - -// level 4 handle -func handle( conn net.Conn ) { - // create byte array of pre-ordained size - buf := make( []byte, tsize ) - - // read from connection into byte array - _, err := conn.Read( buf ) - check( err ) // routine check for errors - - msg := string( buf ) // convert to string - -/* - // iterate over message string - for p, c := range msg { - // cast char ( rune ) to string and see if it's the end char - if string( c ) == "|" { - // if end char, print everything BUT char and exit - fmt.Println( msg[:p] ) - return - } - } -*/ - - // iterate over message string - for _, c := range msg { - // cast char ( rune ) to string and see if it's the end char - if string( c ) == "X" { - // if end char, print everything BUT char and exit - fmt.Println( msg ) - return - } - } - - fmt.Println( msg ) // if char is not found, print entire - handle( conn ) // message and recursively call level4 -} - - - -// globals -var tsize int -var dest string // provide a new destination ip and port - - -func main() { - - // define flags - flag.IntVar( &tsize, "s", 10, "tx size" ) - flag.StringVar( &dest, "ip", ":1300", "ip:port of server" ) - flag.Parse() // process flags - - service := dest // declare server ip:port - - // create address object - addr, err := net.ResolveTCPAddr( "tcp", service ) - check( err ) // check for errors - - // make connection with object - conn, err := net.DialTCP( "tcp", nil, addr ) - check( err ) // check for errors - - //command := "lr@pls" - - // write command to server, beginning transaction - //_, err = conn.Write( []byte( command ) ) - //check( err ) // make sure write worked - - handle( conn ) // handle response - // TODO stack trace when handle returns, should probably be - // updated - conn.Close() // close connection when finished - - os.Exit( 0 ) // exit - -} - diff --git a/dev/seq/pieces/test b/dev/seq/pieces/test deleted file mode 100755 index d933964..0000000 Binary files a/dev/seq/pieces/test and /dev/null differ diff --git a/dev/seq/pieces/test.go b/dev/seq/pieces/test.go deleted file mode 100644 index 3b15a4d..0000000 --- a/dev/seq/pieces/test.go +++ /dev/null @@ -1,268 +0,0 @@ -// ============================================================================= -// Auth: Alex Celani -// File: test.go -// Revn: 05-19-2024 0.4 -// Func: explore bounding on piecewise file transmission ( PWFT ) -// -// TODO: implement -// ============================================================================= -// CHANGE LOG -// ----------------------------------------------------------------------------- -// 04-19-2024: bones -// level 0 PWFT -// level 1 PWFT -// level 2 PWFT -// 05-13-2024: comment level 1 and level 2 PWFT -// level 3 PWFT -// 05-18-2024: began level 4 changes -// 05-19-2024: got level 4 working -// commented -// wrote level 5 -// commented -// wrote level 6! -// commented -// -// ============================================================================= - -package main - -import ( - "flag" - "fmt" - "math/rand" - "net" // ResovleTCPAddr, ListenTCP, listener.Accept - // conn.Read,Write - "os" // Exit - "strconv" -) - - -/* -func makedata() { - for c := 0; c < dsize; c++ { - datum[c] = rand.Intn( dsize ) - } -} -*/ - -// special make function for strings -func makedatatx() { - // classic iteration of length dsize, toss in same-sized array - for c := 0; c < dsize; c++ { - // toss in same size array - // rand int picks letter, 0x61 -> lowercase ascii, cast byte - datumtx[c] = byte( rand.Intn( 26 ) + 0x61 ) - } - // cast to string and print ( as slice ) - fmt.Println( string( datumtx[:] ) ) -} - - -// handle errors catastrophically -func check( err error ) { - if err != nil { // error is not nil on error - // print error - fmt.Println( "Fatal: ", err.Error() ) - os.Exit( 1 ) // bail - } -} - - -// Levels of PWFT -// 0. print everything indescriminately -// 1. printing piecewise -// 2. printing piecewise with header -// 3. printing piecewise with variable size header -// 4. file tx piecewise -// 5. file tx piecewise with header -// 6. file tx piecewise with variable header - - -// level 0 PWFT -func level0( data []int) { - fmt.Println( data ) // level 0 sux -} - - -// level 1 PWFT -func level1() { - tsize := 5 // print 5 chars at a time - txn := dsize / tsize // amount of prints needed - for c := 0; c < txn; c++ { // iterate that amount of times - // print ( using wrapper ) n-1 data points of size tsize - level0( datum[c*tsize:(c+1)*tsize] ) - } - level0( datum[txn*tsize:] ) // print nth data point -} - - -// level 2 PWFT -func level2() { - var bsize int = 10 // total transmission size - var header string = "Lr@x@" // static header - // calculate usable header size - var tsize int = bsize - len( header ) - txn := dsize / tsize // amount of prints needed - for c := 0; c < txn; c++ { // iterate that amount of times - fmt.Print( header ) // print static header - // exact same print statement from level 1 - level0( datum[c*tsize:(c+1)*tsize] ) - } - fmt.Print( header ) // print nth static header - level0( datum[txn*tsize:] ) // print nth data point again -} - - -// level 3 PWFT -func level3() { - var header string // declare header - var bsize int = 10 // total transmission size - var hhead, htail string = "Lr@", "@" // static pieces of header - txn := 1 // init transmission number - pos := 0 // init position tracker - - for { // easier to do an infinite loop and break later - // combine both static parts of the header with the tx number - header = hhead + strconv.Itoa( txn ) + htail - hlen := len( header ) // keep track of total header length - fmt.Print( header ) // print header - - // level0 print ( bsize - hlen ) units of data, starting at - // the noted position - level0( datum[ pos:(pos + bsize - hlen) ] ) - // update position as last position printed - pos = pos + bsize - hlen - txn++ // update transmission number - - // check to see if *updated* position goes out of bounds - if pos + bsize - hlen > dsize { - break // break if'n - } - } - // print nth header ( X denotes final transmission ) - fmt.Print( hhead + "X" + htail ) - level0( datum[pos:] ) // print from final position to end -} - - -// level 4 PWFT -func level4( conn net.Conn ) { - txn := dsize / tsize // amount of transmissions - - // iterate for number of transmissions - for c := 0; c < txn; c++ { - // write that amount of times, very specific slice - _, err := conn.Write( datumtx[c*tsize:(c+1)*tsize] ) - check( err ) // routine error check - } - - // write final of last chunk of data - _, err := conn.Write( datumtx[txn * tsize:] ) - check( err ) // routine error check - _, err = conn.Write( []byte( "|" ) ) // write end char - check( err ) // routine error check -} - - -// level 5 PWFT -func level5( conn net.Conn ) { - header := "la@x@" // static header - psize := tsize - len( header ) // calculate payload size - - txn := dsize / psize // amount of transmissions - - // iterate for number of transmissions - for c := 0; c < txn; c++ { - // concat header with payload, easier as string, cast to byte - packet := header + string( datumtx[c*psize:(c+1)*psize] ) - // write that amount of times, very specific slice - _, err := conn.Write( []byte( packet ) ) - check( err ) // routine error check - } - - // concat last payload - packet := header + string( datumtx[txn*psize:] ) - // write final of last chunk of data - _, err := conn.Write( []byte( packet ) ) - check( err ) // routine error check - _, err = conn.Write( []byte( "|" ) ) // write end char - check( err ) // routine error check -} - - -// level 6 PWFT -func level6( conn net.Conn ) { - var header string // declare header - var hhead, htail string = "la@", "@" // static pieces of header - txn := 1 // init transmission number - pos := 0 // init position tracker - - for { // easier to do an infinite loop and break later - // combine both static parts of the header with the tx number - header = hhead + strconv.Itoa( txn ) + htail - hlen := len( header ) // keep track of total header length - - // craft packet - packet := header + string( datumtx[pos:( pos + tsize - hlen )] ) - - // cast packet to byte array and send - _, err := conn.Write( []byte( packet ) ) - check( err ) // routine error check - - // update position as last position printed - pos = pos + tsize - hlen - txn++ // update transmission number - - // check to see if *updated* position goes out of bounds - if pos + tsize - hlen > dsize { - break // break if'n - } - } - // print nth header ( X denotes final transmission ) - header = hhead + "X" + htail - packet := header + string( datumtx[pos:] ) - // cast data to string, concat, cast to byte array, send - _, err := conn.Write( []byte( packet ) ) - check( err ) // routine error check - -} - - -// size variables -var dsize int = 104 -// data global -var datum = make( []int, dsize ) -var datumtx = make( []byte, dsize ) -var tsize int - - -func main() { - - flag.IntVar( &tsize, "s", 10, "tx size" ) - flag.Parse() - - makedatatx() // fill global with data - - service := ":1300" // create service on ip and port - - // resolve ip address and port - addr, err := net.ResolveTCPAddr( "tcp", service ) - check( err ) // make sure ip resolves - - // create listener object from ip:port - listener, err := net.ListenTCP( "tcp", addr ) - - // print global data to show that PWFT works as intended - //level0( datum ) - - //level3() // do the thing - - for { - // wait, create connection when found - conn, err := listener.Accept() - check( err ) // make sure connection works - - go level6( conn ) // handle connection - } -} - diff --git a/dev/seq/server.go b/dev/seq/server.go deleted file mode 100644 index e58d40b..0000000 --- a/dev/seq/server.go +++ /dev/null @@ -1,281 +0,0 @@ -// ============================================================================= -// Auth: Alex Celani -// File: server.go -// Revn: 10-17-2023 3.0 -// Func: host connection, reply to speak.go -// -// TODO: add more /codes/ to handle -// add flags? -// write usage and errors to logfile -// send logfile to client on request -// ============================================================================= -// CHANGE LOG -// ----------------------------------------------------------------------------- -// 05-13-2022: init -// 08-29-2023: gutted and rewrote -// commented -// 09-12-2023: imported io/ioutil, strings, strconv -// added size conversation -// added file read function, fread() -// commented -// 09-21-2023: began rewrite of handle() -// 09-26-2023: got /list/ command working -// got /add/ command (mostly) working -//*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? -//*10-17-2023: fixed bug where quotes are read from and saved to two -// different files -// removed implicit newline at end of qfile to stop ghost -// line bug in /la/ -// removed dead debug print in fread() -// -// ============================================================================= - -package main - -import ( - "fmt" // Println - "io" // io.EOF - "io/ioutil" // ReadFile - "net" // ResovleTCPAddr, ListenTCP, listener.Accept - // conn.Read,Write - "os" // Exit - "strconv" // Itoa - "strings" // Split -) - - -// handle errors catastrophically -func check( err error ) { - if err != nil { // error is not nil on error - // print error - fmt.Println( "Fatal: ", err.Error() ) - os.Exit( 1 ) // bail - } -} - - -// 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 - qfile, err := ioutil.ReadFile( "list.q" ) - check( err ) // make sure read works - // there is a trailing newline in the file, not removing it caused - // bugs where a blank item was introduced into qlist and calling - // /la/ would produce a blank line on the client side that didn't - // really exist - qfile = qfile[:len( qfile ) - 1] - // cast bytes to string, split string over newline into array - qlist = strings.Split( string( qfile ), "\n" ) - // deal with the trailing - return string( qfile ) // return file as string -} - - -// write qfile back to file -func writeFile( f string ) { - // 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 ) // make sure writeback worked -} - - -// handle connections ( new and improved ) -func handle( conn net.Conn ) { - - // create buffer to hold read message - var buffer [256]byte - // read n bytes from client - n, err := conn.Read( buffer[:] ) - checkN( err, conn ) // make sure read worked - - // cast message to string, take first n bytes, split over @ - command := strings.Split( string( buffer[:n] ), "@" ) - - // declare response string - var resp string - switch command[0] { // switch/case over opcode - case "sr": // /sr/, size request - // get length of list, convert to string - // XXX probably no reason to have this declaration scheme - var num string = strconv.Itoa( len( qlist ) ) - // concat and send - resp = "sa@" + num // size answer - case "qr": // /qr/, quote request - // convert message argument to string to make sure it's a - // valid number - num, nerr := strconv.Atoi( command[1] ) - // nerr will not be nil if comm[1] is not a number - if nerr != nil { - // formulate an error message - // TODO flesh this out more - 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 ): - // bad answer in quote request - resp = "ba@qr@>" - // why bad? num is > - case num < 0: - // bad answer in quote request - resp = "ba@qr@-" - // why bad? num is - - default: - // good num, get quote, send off - resp = "qa@" + qlist[num] // quote answer - } - } - case "lr": // /lr/, list request - // just concat entire list to send - //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 + "\n" + command[1] - writeFile( qfile ) - resp = "aa@success" // add answer - // TODO write to file - case "r1": // /r1/, remove request 1 - // same as list, just send whole file - resp = "r1@" + qfile // remove request 1 - case "r2": // /r2/, remove request 2 - // convert message argument to string to make sure it's a - // valid number - num, nerr := strconv.Atoi( command[1] ) - // nerr will not be nil if comm[1] is not a number - if nerr != nil { - // formulate an error message - // TODO flesh this out more - 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@>" - // why bad? num is > - case num < 0: - // bad answer in quote request - resp = "ba@r2@-" - // why bad? num is - - // if num is not OUT OF RANGE, must be in range - default: - // 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] - // 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" - } - // 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 ) // write back to file - // let client know remove was successful - resp = "r2@success" - } - } - case "te": // /te/, transaction end - // TODO should I be sending something? - // TODO is it better to close now or outside of handle() - conn.Close() // close connection and leave - return // return from handle(), finish connection - default: // opcode not recognized - // TODO there should be more being down, here, right? - return // return from handle(), finish connection - } - - // write response to client - _, err = conn.Write( []byte( resp ) ) - checkN( err, conn ) // make sure write worked - - handle( conn ) // call handle() again to get response from client - -} - - -// globals -var qlist []string // list of quotes -var qfile string // file object - - -// main, create port and wait for connection -func main() { - - qfile = fread() // read quote file, init ( global ) list of quotes - - service := ":1300" // create service on ip and port - - // resolve ip address and port - addr, err := net.ResolveTCPAddr( "tcp", service ) - check( err ) // make sure ip resolves - - // create listener object from ip:port - listener, err := net.ListenTCP( "tcp", addr ) - - for { - // wait, create connection when found - conn, err := listener.Accept() - check( err ) // make sure connection works - - go handle( conn ) // handle connection - } - - os.Exit( 0 ) // exeunt - -} -