“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.
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.
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.
According to the description, I didn’t really understand why. Put, experimented, it became clear - definitely not suitable. Revel for sites.
Works on modules. There are quite good docks in Russian . I took 2 config and session modules.
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
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) }
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.
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")
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")
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) } }
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)
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/...
http.Handle("/static/", http.FileServer(&assetfs.AssetFS{Asset: static.Asset, AssetDir: static.AssetDir, Prefix: ""}))
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/