So habe ich meine Kryptowährung für 8 Monate von PHP to Go umgeschrieben. Teil 1



    "Rufen Sie nicht an und schreiben Sie mir nicht mehr !!!!" - SMS kam von meiner Freundin Katie. Nach ein paar Stunden wurde mir klar, dass ich jetzt viel Freizeit hatte und ich beschloss, Dcoin nach Go zu transferieren.



    Einleitung


    Vor 4,5 Jahren hatte ich den Mut, meine Kryptowährung in einer für dieses Unternehmen völlig unangemessenen Sprache zu schreiben - in PHP. Am Ende schrieb ich natürlich (ich bin hartnäckig), aber ich bekam eine Krücke an einer Krücke und die Tatsache, dass es im Allgemeinen funktionierte, war nur eine Art von Magie.
    Ich möchte Sie sofort warnen, ich bin ein Autodidakt, ein halbgebildeter Programmierer, und das Schreiben von Code ist, gelinde gesagt, nicht ideal.

    Für diejenigen, die daran interessiert sind, was mit Katya passiert, habe ich Spoiler gemacht, aber die nicht interessiert sind, schenken Sie einfach Katya keine Aufmerksamkeit.



    Insgesamt 8 Monate: eine Anwendung auf einem Win (läuft 64 / 32 ), OSX ( 64 / 32 ), Linux ( 64 / 32 ), FreeBSD ( 64 / 32 ), Alle Android , die IOS (wäre cool , wenn jemand in den App Store werfen )
    Der Gesamtcode ist ~ 73k Zeilen, der Code für verschiedene Betriebssysteme ist ungefähr ein paar hundert Zeilen.
    40k - Processing / Blockgenerierung / th, 17.5k - Controller für das Interface, 15.5k - Templates
    PostgreSQL, SQLite, MySQL werden unterstützt.



    Ich warne diejenigen, die meine Kreation testen werden - es kann Fehler geben, und wenn Sie Zeit haben, schreiben Sie bitte an darwin@dcoin.club oder in der PM im Hub darüber. Vorschläge und Ratschläge sind ebenfalls willkommen.



    Nun erzähle ich meine Geschichte, wie ich das alles geschrieben habe, was ich neu gelernt habe usw. Ich hoffe, jemand zieht aus meinen Artikeln etwas Nützliches für sich.



    Starten Sie


    Mehrere Stunden vergingen nach SMS auf Kati. Die Entscheidung, Dcoin umzuschreiben, wurde bereits getroffen. Es war notwendig, irgendwo anzufangen. Ich fing an zu googeln und zu lernen, wie man von vorne anfängt. Ich habe ungefähr 2-3 Tage lang http://golang-book.ru/ und https://tour.golang.org/ studiert , dann habe ich dieses Buch heruntergeladen , es hat ungefähr 2 Wochen gedauert, ich habe nur Beispiele aufgeführt, ich bin unabhängig verpasste Arbeit. Es war schwierig, aber interessant. Ich wollte meine PHP-Quellen so schnell wie möglich umschreiben.



    Ich habe lange nichts Neues studiert, mein Gehirn ist an ein solches Regime nicht gewöhnt. Ich habe Omega-3 und Nootropil in der Apotheke gekauft. Es ist besser, wenn ich mich an die Informationen unter ihnen erinnere, auch wenn es sich möglicherweise um Selbsthypnose handelt.



    Ich habe das letzte Kapitel gelesen. Endlich war es möglich, zu den interessantesten zu gelangen.
    Die Aufgabe ist durchaus verständlich: mehrere Zehntausend Zeilen PHP-Code neu zu schreiben. Aber wo ich anfangen soll, ist völlig unklar. Ich habe beschlossen, mit dem Einfachsten zu beginnen - von einem Webserver.



    Über Katya
    Ich erzähle Ihnen zuerst, wie alles begann. Ich habe sie Anfang 2015 auf einer Dating-Website im Internet getroffen. Fast sofort verliebt. Äußerlich war sie nach meinem Geschmack. Wir gingen durch den Park, scherzten, lachten, steckten fest, es wurde kalt, ich wollte mich nicht trennen. Ich rief an, um Cartoons anzuschauen. Wir stiegen in ein Taxi und kamen an. Er schaltete "Drei Helden: Reiten" ein, einen sehr lustigen Cartoon, der auf dem Bett lag und zu Tränen lachte.


    Schwelgen


    Nach der Beschreibung habe ich nicht ganz verstanden, wofür er war. Ich sagte es, experimentierte, es wurde klar - es passte definitiv nicht. Suchen Sie nach Websites.



    Beego


    Angetrieben durch Module. Es gibt gute Docks in russischer Sprache . Ich habe 2 Konfigurations- und Sitzungsmodule genommen.



    Gorilla


    mux ist eine gute sache, konnte aber keine anwendungen für sich finden.



    Infolgedessen habe ich mich für pure net / http + html / template entschieden



    Webserver


    Das Erhöhen Ihres Webservers in Go ist ganz einfach. Hier ist ein Beispiel für einen Dateiserver:

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

    Fehlerbehandlung der Einfachheit halber entfernt. Auf dem 8000. Port haben Sie eine Root-Liste des Verzeichnisses, in dem die Anwendung ausgeführt wird, und können eine beliebige Datei herunterladen.

    Aufruf der Steuerung mit Namen


    Ich habe 170 Controller . Jeder Controller wird über eines von 6 HandleFunc aufgerufen, zum Beispiel content.go . Der Controller-Name in HandleFunc stammt aus einer POST- oder GET-Anforderung wie folgt: tplName: = r.FormValue ("tpl_name"). Dann wird CallController (c, tplName) aufgerufen, der einen der 170 Controller aufruft, der wiederum den fertigen HTML-Code ausgibt, und content.go, der den HTML-Code empfängt, schreibt ihn über w.Write ([] Byte (html)) und gibt ihn an den Browser weiter. Nun, so etwas.



    Über Katya
    Ich bin sicher, dass Katya am späten Abend die Nacht bleiben wird. Aber aus irgendeinem Grund begann sie zu wiederholen, dass sie nach Hause gehen musste. Ich sagte, ich möchte ihr Frühstück im Bett füttern. Vereinbaren Sie, dass sie morgen früh zum Frühstück kommt. Ich rief ein Taxi, sie ging. Ich bin glücklich eingeschlafen, weil Ich fand mich ein schönes Mädchen, mit dem es lustig und interessant ist. Am nächsten Tag erscheint eine SMS mit dem Titel „Hallo. Was machst du?". Ich erinnere mich an meine Gefühle, weil ich ein Mädchen geschrieben habe, das ich wirklich mag, es hat Spaß gemacht. Und bald sollten wir uns wieder mit ihr treffen ...


    Sitzungen


    Dank des Session-Moduls von beego ist alles sehr einfach



    // Сессии у меня хранятся в памяти, но можно хранить в файлах или БД
    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")


    Dateiverarbeitung


    Im upload_video.go- Controller musste ich die Datei akzeptieren.


    // Выделяем память под файл. 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")  
    


    Der Server-Code, der 3gp vom Client empfängt und mp4 zurückgibt (plötzlich wird es für jemanden nützlich sein)
    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)
        }
    }
    



    Konvertieren Sie Base64 in Bild


    In crop_photo.go musste ich ein Bild in base64 machen und das übliche PNG daraus holen



    b64, _ := base64.StdEncoding.DecodeString(r.FormValue("b64Img"))
    img, _, _ := image.Decode(bytes.NewReader(b64))
    out, _ := os.Create("img.png")
    // в img.png сохраняется наша картинка
    png.Encode(out, img)

    Über Katya
    An diesem Tag haben wir uns nie getroffen. Und der nächste auch. Ich weiß nicht, was in ihrem Kopf vorging, aber sie ertrug ständig Verabredungen. Ich habe am 23. Februar nicht einmal gratuliert.
    Ich beschloss, es irgendwie aufzurühren. Kate schrieb sms-ku, „bald sicher greifen“
    Sie antwortete : „Was?“
    Ich: „oops, gehen Sie nicht dort“
    Sie: „Also das ist , was“
    sie Eifersucht verbunden. Einen Tag später, zu einem Treffen eingeladen, stimmte sie zu.


    Bindata


    Als ich den Webserver kompilierte und auf einen der Knoten übertrug, funktionierte nichts. Es stellte sich heraus, dass nicht alle Vorlagen, Bilder usw. selbst in die Binärdatei gepackt sind.


    Googelt, gefunden https://github.com/jteeuwen/go-bindata


    Tulsa ist sehr praktisch und einfach. Es generiert eine Go-Datei, in der Vorlagen, Bilder usw. als eine Menge von Bytes in Variablen geschrieben werden. Als Ergebnis wird nach der Kompilierung eine Binärdatei erhalten.

    Wenn Sie die Dateien von der Festplatte nehmen möchten, müssen Sie die Option "-debug = true" hinzufügen.
    Ich benutze ein einfaches Bash-Skript, um nicht jedes Mal den Pfad einzugeben, in dem die Go-Datei abgelegt werden soll



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

    Dann brauchte ich, damit die Dateien aus dem statischen Verzeichnis mit der localhost- Anfrage empfangen werden konnten : 8089 / static / img.png. Dafür gibt es go-bindata-assetfs . Hier ist ein Beispiel für das statische Verzeichnis:

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

    Über Katya
    Nachdem ich ihr Verhalten analysiert und ein wenig gegoogelt hatte, stieß ich auf das Buch „ Neue Regeln. Geheimnisse erfolgreicher Beziehungen für moderne Mädchen “.
    Am Abend las ich und erkannte, dass sie aus irgendeinem Grund mit den Ratschlägen aus dem Buch in mich verliebt war.
    Fortsetzung im nächsten Teil.


    Fazit


    In den folgenden Artikeln werde ich über HTML / Template, eine Datenbank, die reibungslose Vervollständigung von Anwendungen durch Signale, die Verarbeitung von Blöcken aus einer Blockchain, die Verschlüsselung in GO und die Entschlüsselung in JS, darüber sprechen, wie ich Gomobile ein wenig verändert habe, Benachrichtigungen hinzufüge und Hintergrundarbeit für IOS und Android Apps.


    Jetzt auch beliebt: