📜 ⬆️ ⬇️

As I have been rewriting my cryptocurrency with PHP for Go for 8 months. Part 1



“Do not call and do not write me more !!!!” - came sms from my girlfriend Katie. After a couple of hours, I realized that now I had a lot of free time and I decided to rewrite Dcoin to Go.



Introduction


4.5 years ago I had the imprudence to start writing my cryptocurrency in a completely inappropriate language for this business - in PHP. As a result, of course, I wrote (I am stubborn), but it turned out to be a crutch on a crutch and that it worked at all was just some kind of magic.
I just want to warn you, I’m a self-taught programmer and I write code, to say the least, imperfectly.

For those who are interested in what's up with Katya, I made spoilers, and who are not interested, just do not pay attention to Katya.


')

A total of 8 months: the application runs on Win ( 64/32 ), OSX (64/32), Linux (64/32), FreeBSD (64/32), Android , IOS (it will be cool if someone throws on the App Store ).
General code ~ 73k lines, code for different OS somewhere a few hundred lines.
40k - processing / generation of blocks / tr-y, 17.5k - controllers for the interface, 15.5k - templates
PostgreSQL, SQLite, MySQL are supported.



Those who will test my creation, I warn you - there may be bugs, and if you have time, write about them, please, at darwin@dcoin.club or in a personal on Habré. Suggestions and advice are also welcome.



Well, now I’ll tell my story, how I wrote all this, what I learned new, etc. I hope someone will get something useful for myself from my articles.



Start


It took several hours after sms-ki. The decision to rewrite Dcoin has already been made. It was necessary to start somewhere. Began to google how to study Go from scratch. Somewhere for 2-3 days I studied http://golang-book.ru/ and https://tour.golang.org/ , then I downloaded this book , it took about 2 weeks, performed only examples, independent work missed. It was difficult, but interesting. I wanted to start rewriting my PHP sources as soon as possible.



I have not learned anything new for a long time, the brain has not become accustomed to such a regime. I bought Omega-3 and Nootropil in the pharmacy, I remember the infa better under them, although it may be a self-suggestion.



I read the last chapter. Finally, it was possible to get down to the most interesting.
The task is quite clear: rewrite several tens of thousands of lines of PHP-code. But where to start is completely unclear. I decided to start with the simplest - from a web server.



About Katya
I'll tell you first how it all began. I met her on the Internet on a dating site in early 2015. Fell in love almost immediately. It hurt outwardly she was in my taste. We walked in the park, joked, laughed, made fun, it became cold, we did not want to part. He called me to watch cartoons. We got into a taxi, we arrived. Turned on "Three heroes: Knight's move", a very funny cartoon, lay on the bed, laughing to tears.


Revel


According to the description, I didn’t really understand why. Put, experimented, it became clear - definitely not suitable. Revel for sites.



Beego


Works on modules. There are quite good docks in Russian . I took 2 config and session modules.



Gorilla


mux is a good thing, but I could not find any applications for myself.



As a result, stopped on a clean net / http + html / template



Web server


It's easy to raise your web server in Go. Here is an example of a file server:

package main import "net/http" func main() { changeHeaderThenServe := func(h http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { h.ServeHTTP(w, r) } } http.Handle("/", changeHeaderThenServe(http.FileServer(http.Dir(".")))) http.ListenAndServe(":8000", nil) } 

Error handling removed for simplicity. At the 8000th port in the root you will have a listing of the directory where the application is running with the ability to download any file.

Call the controller by the transferred name


I got 170 controllers . Each controller is called through one of 6 HandleFunc, for example content.go . The name of the controller in HandleFunc is taken from a POST or GET request like this tplName: = r.FormValue ("tpl_name"). Then CallController (c, tplName) is called, which calls one of 170 controllers, which in turn issues ready-made html-code, and content.go receives HTML and writes it through w.Write ([] byte (html)) and issues it to the browser. Well, something like this.



About Katya
Late evening, I am sure that Katya will stay overnight. But for some reason she began to repeat that she needed to go home. I said I wanted to feed her breakfast in bed. Agree that tomorrow morning she will arrive for breakfast. Called a taxi, she left. I fell asleep happy because I found a beautiful girl with whom it is fun and interesting. The next day, a text message came from her “Hello. What are you doing?". I remember my feelings, because I wrote a girl who I really like, it was kayfovo. And soon we were to meet with her again ...


Sessions


Thanks to the beego session module, everything is very simple.



 //      ,        globalSessions, _ = session.NewManager("memory", `{"cookieName":"gosessionid","gclifetime":86400}`) go globalSessions.GC() //    sess.Set("username", 1000) sess, _ := globalSessions.SessionStart(w, r) defer sess.SessionRelease(w) //    username := sess.Get("username") 


File processing


In the upload_video.go controller , I needed to accept the file.


 //    . 32Mb r.ParseMultipartForm(32 << 20) //    multipart.File file, _, _ := r.FormFile("file") buffer := new(bytes.Buffer) //    _, err = io.Copy(buffer, file) defer file.Close() //   binaryFile = buffer.Bytes() //   fileName := r.MultipartForm.File["file"][0].Filename // Content-Type contentType := r.MultipartForm.File["file"][0].Header.Get("Content-Type") 


Server code that receives 3gp from the client and returns mp4 (it will suddenly come in handy for someone)
 package main import ( "io" "io/ioutil" "fmt" "net" "github.com/c-darwin/dcoin-go/packages/utils" "os" "os/exec" ) func handleRequest(conn net.Conn) { //   buf := make([]byte, 4) n, err := conn.Read(buf) if err != nil { fmt.Printf("%v", utils.ErrInfo(err)) } size := utils.BinToDec(buf) fmt.Printf("get data size: %v / n: %v\n", size, n) if size < 10485760 { //   binaryData := make([]byte, size) n, err = io.ReadFull(conn, binaryData) fmt.Printf("n: %v\n", n) if err != nil { fmt.Printf("%v", utils.ErrInfo(err)) } gp3, err := ioutil.TempFile(os.TempDir(), "temp") if err != nil { fmt.Printf("%v", utils.ErrInfo(err)) } mp4, err := ioutil.TempFile(os.TempDir(), "temp") if err != nil { fmt.Printf("%v", utils.ErrInfo(err)) } err = ioutil.WriteFile(gp3.Name()+".3gp", binaryData, 0644) if err != nil { fmt.Printf("%v", utils.ErrInfo(err)) } out, err := exec.Command("/usr/bin/ffmpeg", "-i", gp3.Name()+".3gp", mp4.Name()+".mp4").Output() if err != nil { fmt.Println("/usr/bin/ffmpeg", "-i", gp3.Name()+".3gp", mp4.Name()+".mp4") fmt.Printf("%v\n", utils.ErrInfo(err)) } fmt.Printf("out: %v\n", out) data, err := ioutil.ReadFile(mp4.Name()+".mp4") if err != nil { fmt.Println(err) } //  4-    ,    size := utils.DecToBin(len(data), 4) n, err = conn.Write(size) if err != nil { fmt.Println(err) } fmt.Printf("n: %v\n", n) //     n, err = conn.Write(data) if err != nil { fmt.Println(err) } fmt.Printf("n: %v\n", n) } } func main() { //   TCP-     l, err := net.Listen("tcp", ":8099") if err != nil { fmt.Printf("Error listening: %v\n", err) panic(err) os.Exit(1) } defer l.Close() for { conn, err := l.Accept() if err != nil { fmt.Println("Error accepting: ", err.Error()) os.Exit(1) } go handleRequest(conn) } } 



Convert Base64 to Image


In crop_photo.go, I needed to take a picture in base64 and get an ordinary png from it



 b64, _ := base64.StdEncoding.DecodeString(r.FormValue("b64Img")) img, _, _ := image.Decode(bytes.NewReader(b64)) out, _ := os.Create("img.png") //  img.png    png.Encode(out, img) 

About Katya
That day we never met. And the next one too. I do not know what was going on in her head, but she constantly endured dating. Not even congratulated on February 23.
I decided to shake it up somehow. Wrote Kate sms-ku: "I will soon, of course, grab"
She replied: "in a sense?"
I: “Oops, not there”
She: "that means how"
She got jealous. A day later offered to meet, she agreed.


Bindata


When the web server was compiled and transferred to one of the nodes, nothing worked. It turned out that all templates, images, etc., are not packed into the binary themselves.


Puguglil, found https://github.com/jteeuwen/go-bindata


Tulsa is very convenient and simple, it generates a go-file, where templates, images, etc. are written to variables as a set of bytes. As a result, after compilation, one binary is obtained.

If you want the files to be taken from disk, you need to add the parameter "-debug = true".
I use a simple bash script to not enter the path where to put the go-file each time.



 #!/bin/bash if [ $# -gt 0 ] && [ $1 = "debug" ] then DEBUG="-debug=true" fi go-bindata -o="packages/static/static.go" -pkg="static" $DEBUG static/... 

Then it took me so that the files from the static directory could be obtained by a request localhost : 8089 / static / img.png. For this there is a go-bindata-assetfs . Here is an example for the static directory:

 http.Handle("/static/", http.FileServer(&assetfs.AssetFS{Asset: static.Asset, AssetDir: static.AssetDir, Prefix: ""})) 

About Katya
After analyzing her behavior and, a little googling, I came across this book " New rules. Secrets of successful relationships for modern girls "
During the evening I read and understood that for some reason she fell in love with herself using the advice from the book.
Continued in the next part.


Conclusion


In the next articles I will talk about html / template, database, smooth application termination via signals, blockchain block processing, GO encryption and JS decryption, how I changed gomobile a little, adding notifications and work in the background for IOS and Android applications.

Source: https://habr.com/ru/post/272695/


All Articles