diff --git a/LICENSE b/LICENSE index 18da0a3..9595756 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 RockSteady, The TurtleCoin Developers +Copyright (c) 2020 RockSteadyTC, The TurtleCoin Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/api.go b/api.go index e534f96..4f3e940 100644 --- a/api.go +++ b/api.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "net/http" "strconv" @@ -48,22 +47,11 @@ func restAPI(keyCollection *ED25519Keys) { // Version api.HandleFunc("/version", returnVersion).Methods(http.MethodGet) - // Peer - api.HandleFunc("/peer", func(w http.ResponseWriter, r *http.Request) { - returnPeerID(w, r, keyCollection.publicKey) - }).Methods(http.MethodGet) - // Stats api.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) { returnStatsWeb(w, r, keyCollection) }).Methods(http.MethodGet) - // REMOVED: https://discord.com/channels/388915017187328002/453726546868305962/761045558336421918 - // // Transactions - // api.HandleFunc("/transactions", func(w http.ResponseWriter, r *http.Request) { - // returnTransactions(w, r) - // }).Methods(http.MethodGet) - // Transaction by ID api.HandleFunc("/transaction/{hash}", func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -71,7 +59,7 @@ func restAPI(keyCollection *ED25519Keys) { returnSingleTransaction(w, r, hash) }).Methods(http.MethodGet) - // Transaction by ID + // Transaction by qty api.HandleFunc("/transactions/{number}", func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) number := vars["number"] @@ -83,7 +71,7 @@ func restAPI(keyCollection *ED25519Keys) { upgrader.CheckOrigin = func(r *http.Request) bool { return true } conn, _ := upgrader.Upgrade(w, r, nil) defer conn.Close() - fmt.Printf(brightgreen+"\n[%s] [%s] Peer socket opened!\n"+white, timeStamp(), conn.RemoteAddr()) + // fmt.Printf(brightgreen+"\n[%s] [%s] Peer socket opened!"+white, timeStamp(), conn.RemoteAddr()) socketAuthAgent(conn, keyCollection) }) diff --git a/clientops.go b/clientops.go deleted file mode 100644 index 705addb..0000000 --- a/clientops.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "fmt" - "net/url" - "strings" - - "github.com/gorilla/websocket" -) - -func joinChannel(ktx, pubKey, signedKey, ktxCertFileName string, keyCollection *ED25519Keys) *websocket.Conn { - // if isCoordinator { - // fmt.Printf(brightred + "\nThis is for nodes running in client mode only.") - // return nil - // } - fmt.Printf(brightcyan+"\nConnecting:"+white+" %s", ktx) - - // request a websocket connection - var conn = requestSocket(ktx, "1") - - // using that connection, attempt to join the channel - var joinedChannel = joinStatement(conn, pubKey[:64]) - - // parse channel messages - socketMsgParser(ktx, pubKey, signedKey, joinedChannel, keyCollection) - - // return the connection - return conn -} - -func joinStatement(conn *websocket.Conn, pubKey string) *websocket.Conn { - - // new users should send JOIN with the pubkey - if isFNG { - joinReq := "JOIN " + pubKey[:64] - _ = conn.WriteMessage(1, []byte(joinReq)) - } - // returning users should send RTRN and the signed CA cert - if !isFNG { - certString := readFile(selfCertFilePath) - rtrnReq := "RTRN " + pubKey[:64] + " " + certString - _ = conn.WriteMessage(1, []byte(rtrnReq)) - } - return conn -} - -func returnMessage(conn *websocket.Conn, pubKey string) *websocket.Conn { - if !isFNG { - certString := readFile(selfCertFilePath) - rtrnReq := "RTRN " + pubKey[:64] + " " + certString - _ = conn.WriteMessage(1, []byte(rtrnReq)) - } - return conn -} - -func requestSocket(ktx, protocolVersion string) *websocket.Conn { - urlConnection := url.URL{Scheme: "ws", Host: ktx, Path: "/api/v" + protocolVersion + "/channel"} - conn, _, err := websocket.DefaultDialer.Dial(urlConnection.String(), nil) - handle(brightred+"There was a problem connecting to the channel: "+brightcyan, err) - return conn -} - -func socketMsgParser(ktx, pubKey, signedKey string, conn *websocket.Conn, keyCollection *ED25519Keys) { - _, joinResponse, err := conn.ReadMessage() - handle("There was a problem reading the socket: ", err) - if strings.HasPrefix(string(joinResponse), "WCBK") { - isTrusted = true - isFNG = false - fmt.Printf(brightgreen + " ✔️\nConnected!\n" + white) - fmt.Printf("\nType `"+brightpurple+"send %s "+white+"` to send a transaction.\n\n", ktx) - } - if strings.Contains(string(joinResponse), string(capkMsg)) { - convertjoinResponseString := string(joinResponse) - trimNewLinejoinResponse := strings.TrimRight(convertjoinResponseString, "\n") - trimCmdPrefix := strings.TrimPrefix(trimNewLinejoinResponse, "CAPK ") - ncasMsgtring := signKey(keyCollection, trimCmdPrefix[:64]) - composedNcasMsgtring := string(ncasMsg) + " " + ncasMsgtring - _ = conn.WriteMessage(1, []byte(composedNcasMsgtring)) - _, certResponse, err := conn.ReadMessage() - isFNG = false - convertStringcertResponse := string(certResponse) // keys := generateKeys() - trimNewLinecertResponse := strings.TrimRight(convertStringcertResponse, "\n") - trimCmdPrefixcertResponse := strings.TrimPrefix(trimNewLinecertResponse, "CERT ") - handle("There was an error receiving the certificate: ", err) - ktxCertFileName := p2pConfigDir + "/" + ktx + ".cert" - createFile(ktxCertFileName) - writeFile(ktxCertFileName, trimCmdPrefixcertResponse[:192]) - fmt.Printf(brightgreen + "\nCert Name: ") - fmt.Printf(white+"%s", ktxCertFileName) - fmt.Printf(brightgreen + "\nCert Body: ") - fmt.Printf(white+"%s", trimCmdPrefixcertResponse[:192]) - } -} - -// Send Takes a data string and a websocket connection -func sendV1Transaction(msg string, conn *websocket.Conn) { - err := conn.WriteMessage(1, []byte(msg)) - handle("There was a problem sending your transaction ", err) -} diff --git a/config.go b/config.go index 80448ba..ff5579e 100644 --- a/config.go +++ b/config.go @@ -25,8 +25,6 @@ const ( privKeyFilePath = certPathSelfDir + "/" + "priv.key" signedKeyFilePath = certPathSelfDir + "/" + "signed.key" selfCertFilePath = certPathSelfDir + "/" + "self.cert" - currentJSON = "./config/milestone.json" - p2pConfigFile = "peer.id" ) // Channel values @@ -38,29 +36,21 @@ const ( // Coordinator values var ( - nodePubKeySignature []byte - dbUser string = "postgres" - dbName string = "karai" - dbSSL string = "disable" - joinMsg []byte = []byte("JOIN") - ncasMsg []byte = []byte("NCAS") - capkMsg []byte = []byte("CAPK") - certMsg []byte = []byte("CERT") - peerMsg []byte = []byte("PEER") - pubkMsg []byte = []byte("PUBK") - nsigMsg []byte = []byte("NSIG") - sendMsg []byte = []byte("send") - rtrnMsg []byte = []byte("RTRN") - numTx int - consumeData bool = false - // isCoordinator bool = false - wantsClean bool = false - graphDir string = "" - batchDir string = "" - showIP bool = false - chunkSize int + dbUser string = "postgres" + dbName string = "karai" + dbSSL string = "disable" + joinMsg []byte = []byte("JOIN") + ncasMsg []byte = []byte("NCAS") + capkMsg []byte = []byte("CAPK") + certMsg []byte = []byte("CERT") + peerMsg []byte = []byte("PEER") + pubkMsg []byte = []byte("PUBK") + nsigMsg []byte = []byte("NSIG") + sendMsg []byte = []byte("SEND") + rtrnMsg []byte = []byte("RTRN") + numTx int + wantsClean bool = false karaiAPIPort int - p2pPeerID string upgrader = websocket.Upgrader{ EnableCompression: true, ReadBufferSize: 1024, @@ -68,13 +58,6 @@ var ( } ) -// Client Values -var ( - trimmedPubKey string - isFNG = true - isTrusted = false -) - // Matrix Values var ( wantsMatrix bool = false @@ -88,8 +71,6 @@ var ( var ( thisSubgraph string = "" thisSubgraphShortName string = "" - // poolSubLeader string = "" - arrangePool bool = false - poolInterval int = 10 // seconds - txCount int = 0 + poolInterval int = 10 // seconds + txCount int = 0 ) diff --git a/db.go b/db.go index d01dfdf..d5456af 100644 --- a/db.go +++ b/db.go @@ -33,17 +33,6 @@ type Transaction struct { Lead bool `json:"lead" db:"tx_lead"` } -// MilestoneData is a struct that defines the contents of the data field to be parsed -type MilestoneData struct { - TxInterval int -} - -// SubGraph defines participants and child transactions of a subgraph -type SubGraph struct { - PubKeys []string - Children []string -} - // connect will create an active DB connection func connect() (*sqlx.DB, error) { connectParams := fmt.Sprintf("user=%s dbname=%s sslmode=%s", dbUser, dbName, dbSSL) @@ -51,46 +40,6 @@ func connect() (*sqlx.DB, error) { return db, err } -// verifyGraph will check each transaction in the graph -func verifyGraph() (bool, error) { - return true, nil -} - -// loadGraphArray outputs the entire graph as an array of Transactions -func loadGraphArray() []byte { - db, connectErr := connect() - defer db.Close() - handle("Error creating a DB connection: ", connectErr) - - graph := []Transaction{} - err := db.Select(&graph, "SELECT * FROM transactions") - graphJSON, _ := json.MarshalIndent(&graph, "", " ") - switch { - case err != nil: - handle("There was a problem loading the graph: ", err) - return graphJSON - default: - return graphJSON - } -} - -// loadGraphElementsArray outputs the entire graph as an array of Transactions -func loadGraphElementsArray(number string) []byte { - db, connectErr := connect() - defer db.Close() - handle("Error creating a DB connection: ", connectErr) - graph := []Transaction{} - err := db.Select(&graph, "SELECT * FROM transactions ORDER BY tx_time DESC LIMIT $1", number) - graphJSON, _ := json.MarshalIndent(&graph, "", " ") - switch { - case err != nil: - handle("There was a problem loading the graph: ", err) - return graphJSON[0:0] - default: - return graphJSON - } -} - // addBulkTransactions adds $number of tx to the graph immediately func addBulkTransactions(number int) { sum := 0 @@ -137,15 +86,6 @@ func generateRandomTransactions() { generateRandomTransactions() } -func createBenchmark(number int) { - // start := time.Now() - - addBulkTransactions(10) - // t := time.Now() - // elapsed := t.Sub(start) - // fmt.Printf(brightcyan+"\nBenchmark\nFinished %v operations in %s\n"+nc, number, elapsed) -} - // createRoot Transaction channels start with a rootTx transaction always func createRoot() error { db, connectErr := connect() @@ -184,7 +124,7 @@ func createRoot() error { } // createTransaction This will add a transaction to the graph -func createTransaction(txType, data string) { +func createTransaction(txType, data string) bool { var txData string var txSubg string var txPrev string @@ -226,10 +166,12 @@ func createTransaction(txType, data string) { txSubg = thisSubgraph thisSubgraphShortName = thisSubgraph[0:4] } + tx.MustExec("INSERT INTO transactions (tx_time, tx_type, tx_hash, tx_data, tx_prev, tx_epoc, tx_subg, tx_prnt, tx_mile, tx_lead ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", txTime, txType, txHash, txData, txPrev, txEpoc, txSubg, txPrnt, txMile, txLead) tx.Commit() txCount++ } + return true } // newSubGraphTimer timer for collection interval diff --git a/flags.go b/flags.go index 39986f5..6f8960f 100644 --- a/flags.go +++ b/flags.go @@ -6,16 +6,10 @@ import "flag" // and assigns the values of those flags according to sane defaults. func flags() { flag.StringVar(&matrixToken, "matrixToken", "", "Matrix homeserver token") - flag.StringVar(&graphDir, "graphDir", "./graph", "Path where graph objects should be saved") - flag.StringVar(&batchDir, "batchDir", "./graph/batch", "Path where batched transactions should be saved") flag.StringVar(&matrixURL, "matrixURL", "", "Matrix homeserver URL") flag.StringVar(&matrixRoomID, "matrixRoomID", "", "Room ID for matrix publishd events") - flag.IntVar(&chunkSize, "chunkSize", 100, "Number of transactions per batch on disk.") flag.IntVar(&karaiAPIPort, "apiport", 4200, "Port to run Karai Coordinator API on.") - flag.BoolVar(&consumeData, "consume", false, "Consume data from sources.") - // flag.BoolVar(&isCoordinator, "coordinator", false, "Run as coordinator.") - flag.BoolVar(&wantsClean, "clean", false, "Clear all peer certs and graph objects") - flag.BoolVar(&wantsFiles, "write", true, "Write each graph object to disk.") + flag.BoolVar(&wantsClean, "clean", false, "Clear all peer certs") flag.BoolVar(&wantsMatrix, "matrix", false, "Enable Matrix functions. Requires -matrixToken, -matrixURL, and -matrixRoomID") flag.Parse() } diff --git a/gather.go b/gather.go index 2cdd91a..cfb21e4 100644 --- a/gather.go +++ b/gather.go @@ -1,80 +1,46 @@ package main -// import ( -// "fmt" -// "io/ioutil" -// "net/http" -// "time" -// ) +import ( + "fmt" + "io/ioutil" + "net/http" + "time" +) -// var readyCovid bool -// var readyBtc bool +func getDataCovid19(seconds time.Duration) { + dateTime := time.Now() + fmt.Printf(white+"\n[%s] COVID\t", dateTime.Format("2006-01-02-15:04:05")) + fmt.Printf(green + "✔️ " + white) + req, _ := http.NewRequest( + "GET", + "https://covidtracking.com/api/v1/us/current.json", + nil) + client := &http.Client{Timeout: time.Second * 5} + resp, err := client.Do(req) + handle("Error: ", err) + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + handle("Error: ", err) + createTransaction("2", string(body)) + delay(seconds) + go getDataCovid19(seconds) +} -// func consume(graph *InMemoryGraph) { -// if isCoordinator { -// if consumeData { -// go getDataCovid19(5000, graph) -// go getDataBitcoin(120, graph) -// go getDataOgre(120, graph) -// } -// } -// } - -// func getDataCovid19(seconds time.Duration, graph *InMemoryGraph) { -// dateTime := time.Now() -// fmt.Printf(white+"\n[%s] COVID\t", dateTime.Format("2006-01-02-15:04:05")) -// fmt.Printf(green + "✔️ " + white) -// req, _ := http.NewRequest( -// "GET", -// "https://covidtracking.com/api/v1/us/current.json", -// nil) -// client := &http.Client{Timeout: time.Second * 5} -// resp, err := client.Do(req) -// handle("Error: ", err) -// defer resp.Body.Close() -// body, err := ioutil.ReadAll(resp.Body) -// handle("Error: ", err) -// graph.addTx("2", string(body)) -// delay(seconds) -// go getDataCovid19(seconds, graph) -// } - -// func getDataBitcoin(seconds time.Duration, graph *InMemoryGraph) { -// dateTime := time.Now() -// fmt.Printf(white+"\n[%s] BTC\t", dateTime.Format("2006-01-02-15:04:05")) -// fmt.Printf(green + "✔️ " + white) -// req, _ := http.NewRequest( -// "GET", -// "https://api.coindesk.com/v1/bpi/currentprice.json", -// nil) -// client := &http.Client{Timeout: time.Second * 5} -// resp, err := client.Do(req) -// handle("Error: ", err) -// defer resp.Body.Close() -// body, err := ioutil.ReadAll(resp.Body) -// handle("Error: ", err) -// graph.addTx("2", string(body)) -// delay(seconds) -// go getDataBitcoin(seconds, graph) -// } - -// func getDataOgre(seconds time.Duration, graph *InMemoryGraph) { -// dateTime := time.Now() -// fmt.Printf(white+"\n[%s] OGRE\t", dateTime.Format("2006-01-02-15:04:05")) -// fmt.Printf(green + "✔️ " + white) -// req, _ := http.NewRequest( -// "GET", -// "https://tradeogre.com/api/v1/markets", -// nil) -// client := &http.Client{Timeout: time.Second * 5} -// resp, err := client.Do(req) -// handle("Error: ", err) -// defer resp.Body.Close() -// body, err := ioutil.ReadAll(resp.Body) -// handle("Error: ", err) -// // i think i should json parse here to remove the slashes -// // but there is no json.Parse in go i dont think -// graph.addTx("2", string(body)) -// delay(seconds) -// go getDataOgre(seconds, graph) -// } +func getDataOgre(seconds time.Duration) { + dateTime := time.Now() + fmt.Printf(white+"\n[%s] OGRE\t", dateTime.Format("2006-01-02-15:04:05")) + fmt.Printf(green + "✔️ " + white) + req, _ := http.NewRequest( + "GET", + "https://tradeogre.com/api/v1/markets", + nil) + client := &http.Client{Timeout: time.Second * 5} + resp, err := client.Do(req) + handle("Error: ", err) + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + handle("Error: ", err) + createTransaction("2", string(body)) + delay(seconds) + go getDataOgre(seconds) +} diff --git a/handlers.go b/handlers.go index a81d992..493477c 100644 --- a/handlers.go +++ b/handlers.go @@ -1,44 +1,12 @@ package main import ( - "bytes" "encoding/json" "fmt" "net/http" - - "github.com/gorilla/websocket" + "strconv" ) -func txParser(msg []byte) bool { - trimMsg := bytes.TrimRight(msg, "\n") - data := string(trimMsg) - if validJSON(data) { - fmt.Printf("\nSubmitting transaction: %s", data) - createTransaction("2", string(msg)) - return true - } - fmt.Printf("\nJSON Error: %s", string(msg)) - return false -} - -func trustedSessionParser(conn *websocket.Conn, keyCollection *ED25519Keys) { - fmt.Printf(brightgreen+"\n[%s] [%s] New socket session"+white, timeStamp(), conn.RemoteAddr()) - for { - defer conn.Close() - _, msg, err := conn.ReadMessage() - if err != nil { - fmt.Printf(brightyellow+"\n[%s] [%s] socket: %s\n"+white, timeStamp(), conn.RemoteAddr(), err) - break - } - if txParser(msg) { - fmt.Printf(brightgreen+"\n[%s] [%s] Tx Good! \n"+white, timeStamp(), conn.RemoteAddr()) - - } else { - fmt.Printf("\n Oh no, something has gone very wrong..\n %s", msg) - } - } -} - // home This is the home route, it can be used as a // health check to see if a coordinator is responding. func home(w http.ResponseWriter, r *http.Request) { @@ -76,17 +44,6 @@ func returnVersion(w http.ResponseWriter, r *http.Request) { w.Write([]byte("{\"karai_version\": \"" + semverInfo() + "\"}")) } -// // returnTransactions This will print the contents of all of -// // the trasnsactions in the graph as an array of JSON objects. -// func returnTransactions(w http.ResponseWriter, r *http.Request) { -// w.Header().Set("Content-Type", "application/json") -// w.WriteHeader(http.StatusOK) -// reportRequest("transactions/", w, r) -// var graph []byte -// graph = loadGraphArray() -// w.Write([]byte(graph)) -// } - // returnTransactions This will print the contents of all of // the trasnsactions in the graph as an array of JSON objects. func returnNTransactions(w http.ResponseWriter, r *http.Request, number string) { @@ -115,7 +72,6 @@ func returnSingleTransaction(w http.ResponseWriter, r *http.Request, hash string idVal := 1 existEval := id == idVal if existEval { - fmt.Printf("we can do it %d", id) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) reportRequest("transactions/"+hash, w, r) @@ -151,3 +107,40 @@ func returnStatsWeb(w http.ResponseWriter, r *http.Request, keys *ED25519Keys) { infoJSON, _ := json.Marshal(infoStruct) w.Write([]byte(infoJSON)) } + +// loadGraphElementsArray outputs the entire graph as an array of Transactions +func loadGraphElementsArray(number string) []byte { + amount, _ := strconv.Atoi(number) + if amount <= 300 { + db, connectErr := connect() + defer db.Close() + handle("Error creating a DB connection: ", connectErr) + graph := []Transaction{} + err := db.Select(&graph, "SELECT * FROM transactions ORDER BY tx_time DESC LIMIT $1", number) + graphJSON, _ := json.MarshalIndent(&graph, "", " ") + switch { + case err != nil: + handle("There was a problem loading the graph: ", err) + return graphJSON[0:0] + default: + return graphJSON + } + } else { + // if they request more than 300, return 300 + number = "300" + db, connectErr := connect() + defer db.Close() + handle("Error creating a DB connection: ", connectErr) + graph := []Transaction{} + err := db.Select(&graph, "SELECT * FROM transactions ORDER BY tx_time DESC LIMIT $1", number) + graphJSON, _ := json.MarshalIndent(&graph, "", " ") + switch { + case err != nil: + handle("There was a problem loading the graph: ", err) + return graphJSON[0:0] + default: + return graphJSON + } + } + +} diff --git a/ipfs.go b/ipfs.go deleted file mode 100644 index c7afea5..0000000 --- a/ipfs.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -// // createCID This will take all of the transactions in the -// // graph directory and call createCIDforTx for each file. -// func createCID() { -// start := time.Now() -// matches, _ := filepath.Glob(graphDir + "/*.json") -// for _, match := range matches { -// createCIDforTx(match) -// } -// end := time.Since(start) -// fmt.Printf("\nFinished in: ", end) -// } - -// // createCIDforTx This will take a file as a parameter and -// // generate IPFS Content IDs for each file given to it. -// func createCIDforTx(file string) string { -// dat, _ := ioutil.ReadFile(file) -// fmt.Print(brightblack + string(dat) + "\n") -// sh := shell.NewShell("localhost:5001") -// cid, err := sh.Add(strings.NewReader(string(dat))) -// handle("Something went wrong pushing the tx: ", err) -// fmt.Printf(brightgreen+"%v %v\n%v %v", brightyellow+"Tx:", brightgreen+file, brightyellow+"CID: ", brightgreen+cid) -// appendGraphCID(cid) -// return cid -// } - -// appendGraphCID This function will take an IPFS content -// ID as a string and append it to a file containing a list -// of all graph TX's. This is probably not a good idea and -// can be done a different way later when we're more coupled -// with ipfs/libp2p -// func appendGraphCID(cid string) { -// if !isCoordinator { -// fmt.Printf("\nIt looks like you're not a channel coordinator. \n Run Karai with '-coordinator' option to run this command.") -// } else { -// hashfile, err := os.OpenFile(hashDat, -// os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) -// handle("Something went wrong appending the graph CID: ", err) -// defer hashfile.Close() -// if fileContainsString(cid, hashDat) { -// fmt.Printf("%v", brightred+"\nDuplicate! Skipping...\n") -// } else { -// hashfile.WriteString(cid + "\n") -// } -// } -// } diff --git a/main.go b/main.go index c247745..d2f8b16 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,8 @@ func main() { createRoot() go restAPI(keys) ascii() + go getDataCovid19(1000) + go getDataOgre(500) go generateRandomTransactions() inputHandler(keys) } diff --git a/math.go b/math.go index f494d94..cc1c6fd 100644 --- a/math.go +++ b/math.go @@ -31,9 +31,6 @@ func portToHex(port string) string { // generatePointer create the TRTL <=> Karai pointer func generatePointer() { - // if !isCoordinator { - // fmt.Printf("\nIt looks like you're not a channel coordinator. \n Run Karai with '-coordinator' option to run this command.") - // } else { readerKtxIP := bufio.NewReader(os.Stdin) fmt.Printf("\nEnter Karai Coordinator IP: ") ktxIP, _ := readerKtxIP.ReadString('\n') @@ -47,5 +44,3 @@ func generatePointer() { fmt.Printf("\nHex:\t6b747828%s%s29", ip, port) fmt.Printf("\nAscii:\tktx(" + strings.TrimRight(ktxIP, "\n") + ":" + strings.TrimRight(ktxPort, "\n") + ")") } - -// } diff --git a/menu.go b/menu.go index 4d93493..fa3bb24 100644 --- a/menu.go +++ b/menu.go @@ -6,22 +6,14 @@ import ( "os" "strings" "time" - - "github.com/gorilla/websocket" ) -type v1Tx struct { - channel string - msg string -} - // inputHandler This is a basic input loop that listens for // a few words that correspond to functions in the app. When // a command isn't understood, it displays the help menu and // returns to listening to input. func inputHandler(keyCollection *ED25519Keys) { reader := bufio.NewReader(os.Stdin) - var conn *websocket.Conn fmt.Printf("\n\n%v%v%v\n", white+"Type '", brightgreen+"menu", white+"' to view a list of commands") for { @@ -46,36 +38,12 @@ func inputHandler(keyCollection *ED25519Keys) { menuVersion() } else if strings.Compare("license", text) == 0 { printLicense() - } else if strings.Compare("upgrade", text) == 0 { - returnMessage(conn, keyCollection.publicKey) } else if strings.Compare("a", text) == 0 { - // if isCoordinator { start := time.Now() txint := 50 addBulkTransactions(txint) - elapsed := time.Since(start) fmt.Printf("\nWriting %v objects to memory took %s seconds.\n", txint, elapsed) - // } else { - // fmt.Printf("It looks like you're not a channel coordinator. \nRun Karai with '-coordinator' option to run this command.\n") - // } - } else if strings.HasPrefix(text, "connect") { - ktxAddressString := strings.TrimPrefix(text, "connect ") - if strings.Contains(ktxAddressString, ":") { - var justTheDomainPartNotThePort = strings.Split(ktxAddressString, ":") - var ktxCertFileName = certPathDir + "/remote/" + justTheDomainPartNotThePort[0] + ".cert" - if !fileExists(ktxCertFileName) { - joinChannel(ktxAddressString, keyCollection.publicKey, keyCollection.signedKey, "", keyCollection) - } - if fileExists(ktxCertFileName) { - isFNG = false - joinChannel(ktxAddressString, keyCollection.publicKey, keyCollection.signedKey, ktxCertFileName, keyCollection) - } - - } - if !strings.Contains(ktxAddressString, ":") { - fmt.Printf("\nDid you forget to include the port?\n") - } } else if strings.HasPrefix(text, "ban ") { bannedPeer := strings.TrimPrefix(text, "ban ") banPeer(bannedPeer) @@ -92,9 +60,6 @@ func inputHandler(keyCollection *ED25519Keys) { whiteList() } else if strings.Compare("exit", text) == 0 { menuExit() - } else if strings.Compare("create-channel", text) == 0 { - fmt.Printf(brightcyan + "Creating channel...\n" + white) - // spawnChannel() } else if strings.Compare("generate-pointer", text) == 0 { generatePointer() } else if strings.Compare("quit", text) == 0 { @@ -105,12 +70,97 @@ func inputHandler(keyCollection *ED25519Keys) { } } +// func inputHandler(keyCollection *ED25519Keys) { +// reader := bufio.NewReader(os.Stdin) +// var conn *websocket.Conn + +// fmt.Printf("\n\n%v%v%v\n", white+"Type '", brightgreen+"menu", white+"' to view a list of commands") +// for { +// // if isCoordinator { +// fmt.Print(brightred + "#> " + nc) +// // } +// // if !isCoordinator { +// // fmt.Print(brightgreen + "$> " + nc) +// // } +// text, _ := reader.ReadString('\n') +// text = strings.TrimSpace(text) +// if strings.Compare("help", text) == 0 { +// menu() +// } else if strings.Compare("?", text) == 0 { +// menu() +// } else if strings.Compare("peer", text) == 0 { +// fmt.Printf(brightcyan + "Peer ID: ") +// fmt.Printf(cyan+"%s\n", keyCollection.publicKey) +// } else if strings.Compare("menu", text) == 0 { +// menu() +// } else if strings.Compare("version", text) == 0 { +// menuVersion() +// } else if strings.Compare("license", text) == 0 { +// printLicense() +// } else if strings.Compare("upgrade", text) == 0 { +// returnMessage(conn, keyCollection.publicKey) +// } else if strings.Compare("a", text) == 0 { +// // if isCoordinator { +// start := time.Now() +// txint := 50 +// addBulkTransactions(txint) + +// elapsed := time.Since(start) +// fmt.Printf("\nWriting %v objects to memory took %s seconds.\n", txint, elapsed) +// // } else { +// // fmt.Printf("It looks like you're not a channel coordinator. \nRun Karai with '-coordinator' option to run this command.\n") +// // } +// } else if strings.HasPrefix(text, "connect") { +// ktxAddressString := strings.TrimPrefix(text, "connect ") +// if strings.Contains(ktxAddressString, ":") { +// var justTheDomainPartNotThePort = strings.Split(ktxAddressString, ":") +// var ktxCertFileName = certPathDir + "/remote/" + justTheDomainPartNotThePort[0] + ".cert" +// if !fileExists(ktxCertFileName) { +// joinChannel(ktxAddressString, keyCollection.publicKey, keyCollection.signedKey, "", keyCollection) +// } +// if fileExists(ktxCertFileName) { +// isFNG = false +// joinChannel(ktxAddressString, keyCollection.publicKey, keyCollection.signedKey, ktxCertFileName, keyCollection) +// } + +// } +// if !strings.Contains(ktxAddressString, ":") { +// fmt.Printf("\nDid you forget to include the port?\n") +// } +// } else if strings.HasPrefix(text, "ban ") { +// bannedPeer := strings.TrimPrefix(text, "ban ") +// banPeer(bannedPeer) +// } else if strings.HasPrefix(text, "unban ") { +// unBannedPeer := strings.TrimPrefix(text, "unban ") +// unBanPeer(unBannedPeer) +// } else if strings.HasPrefix(text, "blacklist") { +// blackList() +// } else if strings.Compare("clear blacklist", text) == 0 { +// clearBlackList() +// } else if strings.Compare("clear peerlist", text) == 0 { +// clearPeerList() +// } else if strings.Compare("peerlist", text) == 0 { +// whiteList() +// } else if strings.Compare("exit", text) == 0 { +// menuExit() +// } else if strings.Compare("create-channel", text) == 0 { +// fmt.Printf(brightcyan + "Creating channel...\n" + white) +// // spawnChannel() +// } else if strings.Compare("generate-pointer", text) == 0 { +// generatePointer() +// } else if strings.Compare("quit", text) == 0 { +// menuExit() +// } else if strings.Compare("close", text) == 0 { +// menuExit() +// } +// } +// } + func menu() { menuOptions := []string{"LAUNCH_PARAMETERS", "CHANNEL_OPTIONS", "WALLET_API_OPTIONS", "KARAI_OPTIONS", "GENERAL_OPTIONS"} menuData := map[string][][]string{ "LAUNCH_PARAMETERS": { { - "-coordinator \t\t Run Karai as Coordinator", "-https \t\t\t Use HTTPS for Coordinator API", "-matrix \t\t Send event messages to Matrix homeserver", "-matrixtoken \t\t Matrix homeserver token string", @@ -122,25 +172,21 @@ func menu() { }, "CHANNEL_OPTIONS": { { - "create-channel \t\t Create a karai transaction channel", "generate-pointer \t Generate a Karai <=> TRTL pointer", - "benchmark \t\t Conducts timed benchmark", - "push-graph \t\t Prints graph history", }, {}, }, "WALLET_API_OPTIONS": { {}, { - "open-wallet \t\t Open a TRTL wallet", - "open-wallet-info \t Show wallet and connection info", - "create-wallet \t\t Create a TRTL wallet", - "wallet-balance \t\t Displays wallet balance", + // "open-wallet \t\t Open a TRTL wallet", + // "open-wallet-info \t Show wallet and connection info", + // "create-wallet \t\t Create a TRTL wallet", + // "wallet-balance \t\t Displays wallet balance", }, }, "KARAI_OPTIONS": { { - "connect \t\t Connects to channel where is ip.ip.ip.ip:port", "peerlist \t\t Lists known peers.", "blacklist \t\t Lists banned peers.", "clear blacklist \t Unbans all blacklist peer certificates.", diff --git a/net.go b/net.go index 2faff5d..4f11175 100644 --- a/net.go +++ b/net.go @@ -9,25 +9,6 @@ import ( "strings" ) -// func p2pTCPDialer(ip, port, message string, pubKey string) { -// var dialer net.Dialer -// ctx, cancel := context.WithTimeout(context.Background(), time.Minute) -// defer cancel() -// connection, _ := dialer.DialContext(ctx, "tcp", ip+":"+port) -// connection.Close() -// } - -// func p2pListener() { -// listen, err := net.Listen("tcp", ":"+strconv.Itoa(karaiP2PPort)) -// handle("Something went wrong creating a listener: ", err) -// defer listen.Close() -// for { -// listenerConnection, err := listen.Accept() -// handle("Something went wrong accepting a connection: ", err) -// go handleConnection(listenerConnection) -// } -// } - func banPeer(peerPubKey string) { fmt.Printf("\nBanning peer: %s" + peerPubKey[:8] + "...") whitelist := p2pWhitelistDir + "/" + peerPubKey + ".cert" diff --git a/queue.go b/queue.go deleted file mode 100644 index dea6672..0000000 --- a/queue.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import ( - "fmt" - "sync" -) - -type workQueue struct { - stack []string - lock sync.RWMutex -} - -func (c *workQueue) push(object string) { - c.lock.Lock() - defer c.lock.Unlock() - c.stack = append(c.stack, object) -} - -func (c *workQueue) pop() error { - len := len(c.stack) - if len > 0 { - c.lock.Lock() - defer c.lock.Unlock() - c.stack = c.stack[:len-1] - return nil - } - return fmt.Errorf("Pop Error: Queue is empty") -} - -func (c *workQueue) front() (string, error) { - len := len(c.stack) - if len > 0 { - c.lock.Lock() - defer c.lock.Unlock() - return c.stack[len-1], nil - } - return "", fmt.Errorf("Peep Error: Queue is empty") -} - -func (c *workQueue) size() int { - return len(c.stack) -} - -func (c *workQueue) empty() bool { - return len(c.stack) == 0 -} - -func queue() { - customQueue := &workQueue{ - stack: make([]string, 0), - } - fmt.Printf("Push: A\n") - customQueue.push("A") - fmt.Printf("Pop: B\n") - customQueue.push("B") - fmt.Printf("Size: %d\n", customQueue.size()) - for customQueue.size() > 0 { - frontVal, _ := customQueue.front() - fmt.Printf("Front: %s\n", frontVal) - fmt.Printf("Pop: %s\n", frontVal) - customQueue.pop() - } - fmt.Printf("Size: %d\n", customQueue.size()) -} diff --git a/socket.go b/socket.go index fd86bc0..58c489d 100644 --- a/socket.go +++ b/socket.go @@ -2,7 +2,6 @@ package main import ( "bytes" - "crypto/sha512" "encoding/hex" "fmt" "regexp" @@ -17,7 +16,7 @@ func socketAuthAgent(conn *websocket.Conn, keyCollection *ED25519Keys) { msgType, msg, err := conn.ReadMessage() if err != nil { fmt.Printf(brightyellow+"\n[%s] [%s] Peer disconnected\n"+white, timeStamp(), conn.RemoteAddr()) - break + return } if bytes.HasPrefix(msg, joinMsg) { msgToString := string(msg) @@ -39,7 +38,7 @@ func socketAuthAgent(conn *websocket.Conn, keyCollection *ED25519Keys) { return } if !fileExists(whitelistPeerCertFile) { - fmt.Printf("\nCreating cert: %s", trimmedPubKey[:64]) + fmt.Printf("\nCreating cert: %s.cert", trimmedPubKey[:64]) capkMsgString := string(capkMsg) + " " + keyCollection.publicKey _ = conn.WriteMessage(msgType, []byte(capkMsgString)) _, receiveNCAS, _ := conn.ReadMessage() @@ -56,7 +55,8 @@ func socketAuthAgent(conn *websocket.Conn, keyCollection *ED25519Keys) { createFile(whitelistPeerCertFile) writeFile(whitelistPeerCertFile, certBody[:192]) fmt.Printf("\nCert Name: %s", whitelistPeerCertFile) - fmt.Printf("\nCert Body: %s", certBody[:192]) + fmt.Printf("\nCert Body: %s\n", certBody[:192]) + sessionAgent(conn, trimmedPubKey) } if !verifySignedKey(keyCollection.publicKey[:64], trimmedPubKey[:64], nCASig) { fmt.Printf("\nSignature does not verify!") @@ -72,28 +72,20 @@ func socketAuthAgent(conn *websocket.Conn, keyCollection *ED25519Keys) { } else { var wbPeerMsg = "WCBK " + trimmedPubKey[:8] conn.WriteMessage(1, []byte(wbPeerMsg)) - trustedSessionParser(conn, keyCollection) + sessionAgent(conn, trimmedPubKey) } } if bytes.HasPrefix(msg, rtrnMsg) { fmt.Printf("\nreturn message: %s", string(msg)) - // strip away the `RTRN` command prefix input := strings.TrimLeft(string(msg), "RTRN ") - trimmedInput := strings.TrimSuffix(input, "\n") - // fmt.Printf("\ntrimmedInput: %s", trimmedInput) - var cert = strings.Split(trimmedInput, " ") - - trimmer := strings.TrimSuffix(cert[1], "\n") - trimmedBytes := []byte(trimmer) + var cert = strings.Split(input, " ") - var hashOfTrimmer = sha512.Sum512(trimmedBytes) - var encodedHashOfTrimmer = hex.EncodeToString(hashOfTrimmer[:]) - if !verifySignature(encodedHashOfTrimmer, keyCollection.publicKey, cert[0]) { + if !verifySignature(cert[0], keyCollection.publicKey, cert[1]) { fmt.Printf("\nsig doesnt verify") } - if verifySignature(encodedHashOfTrimmer, keyCollection.publicKey, cert[0]) { + if verifySignature(cert[0], keyCollection.publicKey, cert[1]) { fmt.Printf("\nsig verifies") } } @@ -106,3 +98,55 @@ func socketAuthAgent(conn *websocket.Conn, keyCollection *ED25519Keys) { } } + +func sessionAgent(conn *websocket.Conn, sessionPubKey string) { + fmt.Printf(brightgreen+"\n[%s] [%s] New socket session"+white, timeStamp(), conn.RemoteAddr()) + for { + defer conn.Close() + _, msg, err := conn.ReadMessage() + if err != nil { + fmt.Printf(brightyellow+"\n[%s] [%s] socket: %s\n"+white, timeStamp(), conn.RemoteAddr(), err) + break + } + if txParser(msg) { + fmt.Printf(brightgreen+"\n[%s] [%s] Tx Good! \n"+white, timeStamp(), conn.RemoteAddr()) + okbyte := []byte("OK " + sessionPubKey) + _ = conn.WriteMessage(1, okbyte) + } else if !txParser(msg) { + fmt.Printf("\nThis transaction has failed to parse:\n %s", msg) + } + } +} + +func txParser(msg []byte) bool { + // SEND + if bytes.HasPrefix(msg, sendMsg) { + + // Remove the SEND command + input := strings.TrimLeft(string(msg), "SEND ") + + // Split the remaining texts + var sendString = strings.Split(input, " ") + + // Use the sender pubkey to look for a matching cert + pubkey := sendString[0] + fileNamePubKey := pubkey[:64] + fileName := p2pWhitelistDir + "/" + fileNamePubKey + ".cert" + readCert := readFile(fileName) + + // If the cert in our records matches the cert the sender gave us, + // the sender is verified. + certChecksOut := readCert == sendString[1] + if !certChecksOut { + fmt.Printf("\nTx signature does not verify.") + return false + } + if certChecksOut { + decodedBytes, _ := hex.DecodeString(sendString[2]) + transactionBody := strings.TrimRight(string(decodedBytes), "\n") + fmt.Printf(brightgreen+"\nTX signature verified for pubkey %s\n%s", brightcyan+pubkey[:4]+"..."+pubkey[60:64]+nc, brightwhite+transactionBody+nc) + createTransaction("2", transactionBody) + } + } + return true +} diff --git a/trtl.go b/trtl.go deleted file mode 100644 index f72448a..0000000 --- a/trtl.go +++ /dev/null @@ -1,106 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "io/ioutil" - "net/http" - "time" -) - -// menuCreateWallet Create a wallet in the wallet-api container -func menuCreateWallet() { - url := "http://127.0.0.1:8070/wallet/create" - data := []byte(`{"daemonHost": "127.0.0.1", "daemonPort": 11898, "filename": "karai-wallet.wallet", "password": "supersecretpassword"}`) - req, err := http.NewRequest("POST", url, bytes.NewBuffer(data)) - handle("Error creating wallet: ", err) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-API-KEY", "pineapples") - client := &http.Client{Timeout: time.Second * 10} - resp, err := client.Do(req) - handle("Error creating wallet: ", err) - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - handle("Error creating wallet: ", err) - fmt.Printf("%s\n", body) -} - -// menuOpenWallet Open a wallet file -func menuOpenWallet() { - url := "http://127.0.0.1:8070/wallet/open" - data := []byte(`{"daemonHost": "127.0.0.1", "daemonPort": 11898, "filename": "karai-wallet.wallet", "password": "supersecretpassword"}`) - req, err := http.NewRequest("POST", url, bytes.NewBuffer(data)) - handle("Error opening wallet: ", err) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-API-KEY", "pineapples") - client := &http.Client{Timeout: time.Second * 10} - resp, err := client.Do(req) - handle("Error opening wallet: ", err) - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - handle("Error opening wallet: ", err) - fmt.Printf("%s\n", body) -} - -// menuOpenWalletInfo Some basic TRTL API stats -func menuOpenWalletInfo() { - walletInfoPrimaryAddressBalance() - getNodeInfo() - getWalletAPIStatus() -} - -// menuGetContainerTransactions Get Wallet-API transactions -func menuGetContainerTransactions() { - req, err := http.NewRequest("GET", "http://127.0.0.1:8070/transactions", nil) - handle("Error getting container transactions: ", err) - req.Header.Set("X-API-KEY", "pineapples") - client := &http.Client{Timeout: time.Second * 10} - resp, err := client.Do(req) - handle("Error getting container transactions: ", err) - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - handle("Error getting container transactions: ", err) - fmt.Printf("%s\n", body) -} - -// getWalletAPIStatus Get Wallet-API status -func getWalletAPIStatus() { - req, err := http.NewRequest("GET", "http://127.0.0.1:8070/status", nil) - handle("Error getting Wallet-API status: ", err) - req.Header.Set("X-API-KEY", "pineapples") - client := &http.Client{Timeout: time.Second * 10} - resp, err := client.Do(req) - handle("Error getting Wallet-API status: ", err) - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - handle("Error getting Wallet-API status: ", err) - fmt.Printf("%s\n", body) -} - -// getNodeInfo Get TRTL Node Info -func getNodeInfo() { - req, err := http.NewRequest("GET", "http://127.0.0.1:8070/node", nil) - handle("Error getting node info: ", err) - req.Header.Set("X-API-KEY", "pineapples") - client := &http.Client{Timeout: time.Second * 10} - resp, err := client.Do(req) - handle("Error getting node info: ", err) - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - handle("Error getting node info: ", err) - fmt.Printf("%s\n", body) -} - -// walletInfoPrimaryAddressBalance Get primary TRTL address balance -func walletInfoPrimaryAddressBalance() { - req, err := http.NewRequest("GET", "http://127.0.0.1:8070/balances", nil) - handle("Error getting wallet info primary address: ", err) - req.Header.Set("X-API-KEY", "pineapples") - client := &http.Client{Timeout: time.Second * 10} - resp, err := client.Do(req) - handle("Error getting wallet info primary address: ", err) - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - handle("Error getting wallet info primary address: ", err) - fmt.Printf("%s\n", body) -} diff --git a/util.go b/util.go index 930a8f2..69f83b4 100644 --- a/util.go +++ b/util.go @@ -3,7 +3,6 @@ package main import ( "encoding/json" "fmt" - "io" "io/ioutil" "os" "regexp" @@ -18,12 +17,7 @@ func ascii() { fmt.Printf(green + "| |/ / / /\\ \\ | |) ) / /\\ \\ | |\n") fmt.Printf(brightgreen + "|__|\\__\\/__/¯¯\\__\\|__|\\__\\/__/¯¯\\__\\|__| \n") fmt.Printf(brightred + "v" + semverInfo() + white) - // if isCoordinator { fmt.Printf(brightred + " coordinator") - // } - // if !isCoordinator { - // fmt.Printf(brightgreen + " client") - // } } @@ -87,11 +81,6 @@ func unixTimeStampNano() string { return timestamp } -// Split helps me split up the args after a command -func Split(r rune) bool { - return r == ':' || r == '.' -} - func writeTxToDisk(gtxType, gtxHash, gtxData, gtxPrev string) { timeNano := unixTimeStampNano() txFileName := timeNano + ".json" @@ -110,8 +99,6 @@ func createDirIfItDontExist(dir string) { // checkDirs Check if directory exists func checkDirs() { - createDirIfItDontExist(graphDir) - createDirIfItDontExist(batchDir) createDirIfItDontExist(configDir) createDirIfItDontExist(p2pConfigDir) createDirIfItDontExist(p2pWhitelistDir) @@ -160,39 +147,14 @@ func writeFileBytes(filename string, bytesToWrite []byte) { // readFile Generic file handler func readFile(filename string) string { - var file, err = os.OpenFile(filename, os.O_RDWR, 0644) - handle("", err) - defer file.Close() - var text = make([]byte, 1024) - for { - _, err = file.Read(text) - if err == io.EOF { - break - } - if err != nil && err != io.EOF { - handle("", err) - break - } - } + text, err := ioutil.ReadFile(filename) + handle("Couldnt read the file: ", err) return string(text) } func readFileBytes(filename string) []byte { - var file, err = os.OpenFile(filename, os.O_RDWR, 0644) - handle("", err) - defer file.Close() - var text = make([]byte, 1024) - for { - _, err = file.Read(text) - if err == io.EOF { - break - } - if err != nil && err != io.EOF { - handle("", err) - break - } - } - // fmt.Printf(string(text)) + text, err := ioutil.ReadFile(filename) + handle("Couldnt read the file: ", err) return text } @@ -203,28 +165,9 @@ func deleteFile(filename string) { } func validJSON(stringToValidate string) bool { - // var jsonString json.RawMessage - // return json.Unmarshal([]byte(stringToValidate), &jsonString) == nil - return json.Valid([]byte(stringToValidate)) -} - -func zValidJSON(stringToValidate string) bool { - // var jsonData map[string]string - // err := json.Unmarshal([]byte(stringToValidate), &jsonData) - // if err == nil { - // fmt.Printf("\nJSON is valid") - // return true - // } - // fmt.Printf("\nJSON is NOT valid: %s", stringToValidate) - // return false return json.Valid([]byte(stringToValidate)) } -func countFilesOnDisk(directory string) string { - files, _ := ioutil.ReadDir(directory) - return strconv.Itoa(len(files)) -} - func countWhitelistPeers() int { directory := p2pWhitelistDir + "/" dirRead, _ := os.Open(directory) @@ -267,22 +210,5 @@ func cleanData() { } fmt.Printf(brightyellow+"\nCerts clear: %s"+white, brightgreen+"✔️") - // cleanse the batches - batchObjects, _ := ioutil.ReadDir(batchDir + "/") - for _, f := range batchObjects { - fileToDelete := batchDir + "/" + f.Name() - fmt.Printf("\nDeleting file: %s", fileToDelete) - deleteFile(fileToDelete) - } - fmt.Printf(brightyellow+"\nBatches clear: %s"+white, brightgreen+"✔️") - - // cleanse the graph - graphObjects, _ := ioutil.ReadDir(graphDir + "/") - for _, f := range graphObjects { - fileToDelete := graphDir + "/" + f.Name() - fmt.Printf("\nDeleting file: %s", fileToDelete) - deleteFile(fileToDelete) - } - fmt.Printf(brightyellow+"\nGraph clear: %s"+white, brightgreen+"✔️") } } diff --git a/version.go b/version.go index a53eef2..0c6e744 100644 --- a/version.go +++ b/version.go @@ -3,8 +3,8 @@ package main // semverInfo Version string constructor func semverInfo() string { majorSemver := "0" - minorSemver := "21" - patchSemver := "2" + minorSemver := "22" + patchSemver := "0" wholeString := majorSemver + "." + minorSemver + "." + patchSemver return wholeString }