Developers Club geek daily blog

1 year, 3 months ago
As I rewrote 8 months the cryptocurrency to PHP for Go. Part 1

"Do not call and do not write me more!!!!" — SMS from my girl Katya came. Through a couple of hours I realized that now I had a heap of free time and I decided to rewrite Dcoin on Go.

Introduction


4,5 years ago I had imprudence to begin to write the cryptocurrency in language, absolutely improper for this business — for PHP. As a result, of course, wrote (I stubborn), but the crutch on a crutch turned out and the fact that it in general worked was just some magic.
At once I want to warn, the programmer I am self-educated person half-educated person and I write a code, to tell softly, is imperfect.

For those to whom it is interesting that there with Katya, I made spoilers and to whom should pay attention to Katya.

Result of 8 months: the application works at Win (64/32), OSX(64/32), Linux(64/32), FreeBSD(64/32), Android, IOS (will be abruptly if someone throws in App Store).
The general code ~ 73k lines, a code under different OS about several hundred lines.
40k — processing/generation of blocks / tr-y, 17.5k — controllers for the interface, 15.5k — templates
PostgreSQL, SQLite, MySQL are supported.

I warn those who will test my creation — there can be bugs and if you have time, strike about them, please, on darwin@dcoin.club or in a pm on Habré. Wishes and councils are welcomed too.

And now I will tell the story as I wrote all this what I learned new and so forth. I hope someone will gather something useful to itself from my articles.

Start


There passed several hours after a sms on Katya. The decision to rewrite Dcoin was already made. It was necessary to begin with something. Began to google how to study Go from scratch. http://golang-book.ru/ and https://tour.golang.org / studied about 2-3 days, then downloaded this book, on it about 2 weeks left, executed only examples, missed independent work. It was difficult, but it is interesting. There was a wish to start the rewriting of my PHP-source codes already as soon as possible.

I studied nothing new for a long time, the brain did not get used to such mode. Purchased in a drugstore the Omega-3 and Nootropil, at me under them better info is remembered though can do it and auto-suggestion.

Read up the final chapter. At last it was possible to start the most interesting.
The task is quite clear: to rewrite several tens of thousands of lines of a PHP-code. But with what to begin, it is not clear at all. Decided to begin with the simplest — from the Web server.

About Katya
I will tell at first as everything began. I got acquainted with it on the Internet on a dating site at the beginning of the 2015th. Fell in love almost at once. Painfully externally it was in we wash taste. Walked in the park, joked, laughed, kidding, it became cold, there was no wish to leave. Called to himself animated cartoons to look. Sat down in a taxi, arrived. Included "Three athletes: A knight's move", very ridiculous animated cartoon, lay on a bed, laughed to got down.


Revel


By description not really understood for what it. Put, experimented, it became clear — definitely does not approach. Revel for the websites.

Beego


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

Gorilla


mux — good piece, but for itself could not find applications.

As a result html/template stopped on pure net/http +

Web server


The Web server in Go it is very simple to lift the. Here 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)
}
  

Cleaned error handling for simplicity. On the 8000th port in a root you will have a listing of a directory where the application with an opportunity to download any file is started.
As I rewrote 8 months the cryptocurrency to PHP for Go. Part 1

Controller challenge on the transferred name


At me 170 controllers turned out. Each controller is caused through one of 6 HandleFunc, for example content.go. The controller name in HandleFunc undertakes from request POST or GET here so of tplName: = r.FormValue ("tpl_name"). Then CallController (c, tplName) which causes one of 170 controllers which in turn issues a ready html-code is caused, and content.go having received HTML writes it through w.Write ([] byte(html)) and issues to the browser. Well somehow so.

About Katya
Late evening, I am sure that Katya will stay overnight. But she for some reason began to repeat that it is necessary to it home. I told that I want to feed her with a breakfast in a bed. Agree that tomorrow morning she will come to have breakfast. Called a taxi, she left. Fell asleep happy since found to itself the beautiful girl with whom it is cheerful and interesting. Next day from it SMS "Hi came. What do you do?". I remember the feelings, I was written by the girl who very much is pleasant to me, it was kayfovo. And we had to meet it again soon …


Sessions


Thanks to the session module from beego 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")


Processing of files


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")  


Code of the server which receives from the client 3gp and returns mp4 (suddenly it is useful to 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)
    }
}



Base64 conversion to the picture


In crop_photo.go I needed to accept the picture in base64 and to receive from it normal png

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 did not meet. And on following too. I do not know what at it occurred in the head, but she constantly transferred appointments. Even did not congratulate on February 23.
Decided it to stir up somehow. Wrote to Katya a sms: "I will be soon, of course I will take"
She answered: "in sense?"
Я: "oops, not there"
It: "here means as"
At it the jealousy joined. Every other day suggested to meet, she agreed.


Bindata


When skompilit the Web server and transferred to one of notes, nothing worked. It became clear that all templates, pictures and so forth in a binarnik are not packed.
Puguglil, found https://github.com/jteeuwen/go-bindata
Tulza very convenient and simple, she generates the go-file where templates, pictures and so forth are written to variables in the form of a set of bytes. As a result after compilation one binarnik turns out. If it is necessary that files undertook from a disk, then it is necessary to add parameter "-debug=true".
I use an unpretentious bash-script that every time not to enter a way, where to put the go-file

#!/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 was required to me that files from a directory of static could be received request of localhost:8089/static/img.png. For this purpose there is go-bindata-assetfs. Here an example for static directory:

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

About Katya
Having analyzed her behavior and, it is a little pogugliv, I came across here this book "New rules. Secrets of the successful relations for modern girls"
In an evening read and understood that she for some reason gets me to fall in love using councils from the book.
Continuation in the following part.


Conclusion


In the following articles I will tell about html/template, a DB, smooth end of the application through signals, processing of blocks from a blokcheyn, enciphering in GO and interpretation in JS, how I, changed gomobile a little, having added notifications and work in a background for IOS and Android of applications.

This article is a translation of the original post at habrahabr.ru/post/272695/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus