Pull to refresh

Как я 8 месяцев переписывал свою криптовалюту с PHP на Go. Часть 2

Reading time 7 min
Views 45K


2-я часть истории, которая началась с смс-ки от Кати «Не звони и не пиши мне больше!!!!»

Первая часть тут. Для тех, кому лень читать, приведу краткое изложение:

4,5 года назад я имел неосторожность начать писать свою криптовалюту на совсем неподходящем для этого дела языке — на PHP. В итоге, конечно, написал (я упрямый), но получился костыль на костыле и то, что оно вообще работало было просто какой-то магией.
Сразу хочу предупредить, программер я самоучка-недоучка и пишу код, мягко сказать, неидеально.

Началось всё с того, что я расстался с девушкой, по имени Катя и в этот же день (4 апреля 2015-го) решил изучить Go и переписать свою криптовалюту. Для тех, кому интересно, что там с Катей, я сделал спойлеры, ну а кому не интересно, просто не обращайте внимание на Катю

Для тех, кто не читал 1-ю часть про Катю
Расскажу сперва как всё началось. Познакомился я с ней в интернете на сайте знакомств в начале 2015-го. Влюбился почти сразу. Уж больно внешне она была в моем вкусе. Гуляли по парку, шутили, смеялись, прикалывались, стало холодно, расставаться не хотелось. Позвал к себе мультики смотреть. Сели в такси, приехали. Включил «Три богатыря: Ход конем», очень смешной мультик, лежали на кровати, смеялись до слез.

Поздний вечер, я уверен, что Катя останется на ночь. Но она почему-то стала твердить, что ей надо домой. Я сказал, что хочу накормить её завтраком в постели. Договорись, что завтра утром она приедет завтракать. Вызвал такси, она уехала. Уснул счастливым, т.к. нашел себе красивую девушку, с которой весело и интересно. На следующий день от неё пришла смс-ка «Привет. Чем занимаешься?». Помню свои ощущения, ведь мне написала девушка, которая мне очень нравится, это было кайфово. И скоро мы с ней должны были снова встретиться…

В тот день мы так и не встретились. И на следующий тоже. Я не знаю, что у неё происходило в голове, но она постоянно переносила свидания. Даже не поздравила с 23 февраля.
Решил её как-то растормошить. Написал Кате смс-ку: «скоро буду, конечно захвачу»
Она ответила: «в смысле?»
Я: «упс, не туда»
Она: «вот значит как»
У неё включилась ревность. Через день предложил встретиться, она согласилась.

Проанализировав её поведение и, немного погуглив, я наткнулся на книгу «Новые правила. Секреты успешных отношений для современных девушек»
За вечер прочитал и понял, что она меня зачем-то в себя влюбляет, используя советы из этой книжки.

Итог 8 месяцев: приложение работает на Win (64/32), OSX(64/32), Linux(64/32), FreeBSD(64/32), Android, IOS (будет круто, если кто-то закинет в App Store).
Общего кода ~73к строк, кода под разные ОС где-то несколько сотен строчек.
40к — обработка/генерация блоков/тр-ий, 17.5к — контроллеры для интерфейса, 15.5к — шаблоны
Поддерживаются PostgreSQL, SQLite, MySQL.

Тех, кто будет тестировать мое творение, предупреждаю — могут быть баги, и если у Вас есть время, чиркните о них, пожалуйста, на darwin@dcoin.club или в личку на хабре. Пожелания и советы тоже приветствуются.

В первой части я рассказал про то, как в dcoin функционирует веб-сервер.

В этой статье опишу, как я использую html/template

Шаблоны


Для генерации html-страниц в Go есть очень удобный пакет — html/template. Проще всего понять, как он работает, можно поэкспериментировав вот с этим примером. Как правило, шаблоны хранятся в отдельных html-файлах, но в примерах на play.golang.org, для наглядности, шаблоны вставлены в go-код.

Большую часть информации по шаблонам я получил с gohugo.io/templates/go-templates

Шаблоны у меня лежат тут. Каждый шаблон начинается с определения его имени {{ define «templateName» }}, а заканчивается {{end}}

Контроллеры, которые использует шаблоны получают html код через функцию makeTemplate. В неё я передаю название html-файла, имя шаблона (которое в {{define}} указано), параметры.

TemplateStr, err := makeTemplate("template_name", "templateName", &tplPage{
		Alert:          c.Alert,
		Lang:           c.Lang,
		TxType:         txType,
		TxTypeId:       txTypeId})

Полученный в TemplateStr набор байт передается content.go и в итоге браузер получает сформированную html-страничку

В makeTemplate для всех шаблонов я подключаю дополнительные шаблоны, такие как signatures.html, alert_success.html. А также, добавляю пользовательские функции (FuncMap), которые используются для обработки данных в шаблонах.

Про Катю
На втором свидании мы просто гуляли, болтали. Всё было хорошо. Про мою смс-ку «скоро буду, конечно захвачу» она, к моему счастью, ничего не сказала.
Мне не давал покоя вопрос о книге, по которой она, как мне казалось, влюбляет меня в себя. Спросить прямо я не решился. Поинтересовался, чего читает. Она назвала каких-то авторов. На вопрос о книгах про психологию, ответила, что почитывает для себя.
Было холодно. Проводил до дома. Договорились на днях пойти на каток.

Включения в шаблоны


Чтобы включить в шаблон другой шаблон нужно использовать такую конструкцию {{ template «signatures». }}. Точка в конце говорит о том, что нужно обработать все параметры в шаблоне signatures, без точки параметры не будут обработаны. signatures я добавляю практически во все шаблоны, вот пример

Параметры


Сравнение. Приведу сразу несколько примеров, чтобы показать, как всё просто:
{{if not .UserID}} <span>Пусто</span> {{end}}
{{if .UserID}} <span>Не пусто</span> {{end}}
{{if eq .UserID 0}} <span>UserID == 0</span> {{end}}
{{if ne .UserID 0}} <span>UserID != 0</span> {{end}}
{{if lt .UserID 0}} <span>UserID < 0</span> {{end}}
{{if le .UserID 0}} <span>UserID <= 0</span> {{end}}
{{if gt .UserID 0}} <span>UserID > 0</span> {{end}}
{{if ge .UserID 0}} <span>UserID >= 0</span> {{end}}

{{.Lang.pool} — Lang — это карта. Т.е. через точку мы получаем значение, у которого ключ «pool»

Про Катю
Примерно неделю я не писал и не звонил ей. Решил проверить, позвонит ли она первой. Было капец как сложно, мучился, но ждал её звонка, хотел что бы она нарушила правила из книжки.
В итоге сдался. Написал ей, позвал в кино. Она сказала, что сегодня не может, т.к. переезжает. От помощи с переездом отказалась.

Забегу немного вперед и скажу, что после той самой смс-ки «Не звони и не пиши мне больше!!!!», я в ВК переманил на свою сторону её подружку, с которой она жила 2 года, чтобы та помогала мне вернуть Катю. Так вот, её подружка, сказала, что всю ту неделю, когда я не звонил, Катя очень переживала и ждала звонка от меня. Еще она рассказала, что после первого свидания Катя буквально светилась от радости. Также она добавила, что никакую книгу по соблазнению она не читала.

Пользовательские функции


html-код в переменных нужно дизэскейпить. Для этого необходимо добавить функцию:

funcMap := template.FuncMap{
	"noescape": func(s string) template.HTML {
		return template.HTML(s)
	},
}

Все пользовательские функции у меня собраны в makeTemplate. Использовать так:

{{noescape .Lang.htmlText}}

Про Катю
Близилось 8-е марта. Катя всё никак не хотела со мной встретиться. А я очень хотел поздравить её с праздником. В итоге я поставил вопрос ребром. Либо встречаемся 8-го марта, либо я ей больше не позвоню. Договорились отметить праздник у меня.

Купил её любимые цветы, вино и пр. Хотел весь день провести с ней, но к обеду она была еще не готова, через час тоже и через два. К моему удивлению, к шести часам она, наконец, собралась. Я вызвал ей такси.

Range


Чтобы разобрать какую-нибудь карту используется Range. Вот пример, взятый отсюда:

{{range $k, $country := .Countries}}
<option value='{{$k}}' {{if eq $k $.MyCountry}} selected {{end}}>{{$country}}</option>
{{end}}

Из кода, наверное, понятно, что происходит. Но хочу обратить особое внимание на $.MyCountry. Если не добавить $, тогда доступа к параметру .MyCountry не будет. Я по началу очень часто об этом забывал и долго думал, что не так. За пределами range доступ к MyCountry снова получается через {{.MyCountry}}

Про Катю
Приехала, вручил цветы, подарки. Открыл бутылку вина. Она увидела на одном из мониторов мои старые PHP-исходники. Спросила — «Что это?». Я рассказал ей про блокчейн, про то, как Dcoin, благодаря природному желанию людей получать прибыль («не вставая с дивана»), сможет завладеть умами миллионов, плавно заменив обычные валюты на децентрализованные, затем эмиссия остановится и у нас будет новый мир с прозрачной финансовой системой. Катя ничего не поняла. Потом смотрели какой-то фильм, целовались. Вдруг закончилось вино, я просил, хочет ли она еще, она сказала, что хочет. Я ушел в магазин.

Переменные


В шаблонах можно создавать свои переменные. Вот пример, взятый отсюда:

{{range $i, $pageType := .PagesArray}}
	{{$counter := ""}}
	{{if eq $pageType "funders"}}
		{{$counter := " <span class='count h6 bg-grey-dark white'>{{$.ProjectCountFunders}}</span>"}}
	{{else if eq $pageType "comments"}}
		{{$counter := " <span class='count h6 bg-grey-dark white'>{{$.ProjectCountComments}}</span>"}}
	{{end}}
	{{$counter}}
{{end}}

В данном примере создается новая переменная $counter, которой присваивается значение, в зависимости от условия, и ниже выводится ее результат

and/or


Несколько непривычной для меня оказалась логика работы and/or.
Примеры:

{{if and (eq .Start 1) (ne .BlockId 1) (gt .UserId 0)}}

Если .Start == 1 и .BlockId != 1 и .UserId > 0

{{if or (eq .Start 1) (ne .BlockId 1) (gt .UserId 0)}}

Если .Start == 1 или .BlockId != 1 или .UserId > 0

JS-код


Еще одна проблема отняла у меня довольно много времени. Если в контроллере нужно сформировать какой-то js-код, например:

var x="1";

То при выводе его в шаблоне через {{.SomeJSCode}} мы получим

"var x=\"1\";"

Решение 1


noescape тут не поможет. Нужно добавить новую пользовательскую функцию:

"js": func(s string) template.JS {
			return template.JS(s)
		},

И в шаблоне использовать {{js .SomeJSCode}}

Решение 2


В контроллере использовать тип template.JS. Предварительно преобразовав переменную string: template.JS(SomeJsStringVariable). В самом шаблоне в таком случае нужно выводить {{.SomeJSCode}}

Про Катю
Вернулся, допили вино. Достал массажное масло. Около часа делал массаж (на днях специально изучил вот это видео). Массаж плавно перевел в кое-что более интимное, в результате чего она испытала резкий выброс эндорфинов, и сразу после этого сказала, что хочет спать. «Что за фигня?» — подумал я. В общем, легли спать.
Продолжение в следующей части.

Заключение


В следующих статьях я расскажу про БД, плавное завершение приложения через сигналы, обработку блоков из блокчейна, шифрование в GO и расшифровку в JS, про то, как я, немного изменил gomobile, добавив уведомления и работу в фоне для IOS и Android приложений.
Tags:
Hubs:
+27
Comments 62
Comments Comments 62

Articles