aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Neonxp Kiryukhin <i@neonxp.ru>2024-12-11 01:21:22 +0300
committerAlexander Neonxp Kiryukhin <i@neonxp.ru>2024-12-11 01:21:22 +0300
commita79499018bed35bab05f888ce0103b37655e2852 (patch)
treed182886009aeafffb247a68ff425c740b3cb6a31
parent418eac8c0b978089644f48e27a0fbdd20e18ac91 (diff)
Auto-commit 2024-12-11
-rw-r--r--archetypes/go.md7
-rw-r--r--content/go/collection.md7
-rw-r--r--content/go/expression.md23
-rw-r--r--content/go/extra.md11
-rw-r--r--content/go/framework.md25
-rw-r--r--content/go/jsonrpc2.md130
-rw-r--r--content/go/merger.md84
-rw-r--r--content/go/mux.md9
-rw-r--r--content/go/objectid.md74
-rw-r--r--content/go/unilex.md13
-rw-r--r--content/go/workflow.md4
-rw-r--r--hugo.toml7
-rw-r--r--layouts/go/single.htm4
-rw-r--r--layouts/go/single.html34
14 files changed, 423 insertions, 9 deletions
diff --git a/archetypes/go.md b/archetypes/go.md
new file mode 100644
index 0000000..e525746
--- /dev/null
+++ b/archetypes/go.md
@@ -0,0 +1,7 @@
++++
+title = "{{ replace .Name "-" " " | title }}"
+name = "{{ .Name }}"
+repository = "https://git.neonxp.ru/{{ .Name }}.git"
+description = ""
+gomod = true
++++ \ No newline at end of file
diff --git a/content/go/collection.md b/content/go/collection.md
new file mode 100644
index 0000000..9375e05
--- /dev/null
+++ b/content/go/collection.md
@@ -0,0 +1,7 @@
++++
+title = "Collection"
+name = "collection"
+repository = "https://git.neonxp.ru/collection.git"
+description = "Генерики для коллекций"
+gomod = true
++++ \ No newline at end of file
diff --git a/content/go/expression.md b/content/go/expression.md
new file mode 100644
index 0000000..c0e65bf
--- /dev/null
+++ b/content/go/expression.md
@@ -0,0 +1,23 @@
++++
+title = "Expression"
+name = "expression"
+repository = "https://git.neonxp.ru/expression.git"
+description = "Простой исполнитель выражений"
+gomod = true
++++
+
+Простой исполнитель выражений
+
+## Использование
+
+```go
+import "neonxp.ru/go/expression"
+...
+e := expression.New()
+result, err := e.Eval(`2 + 2`) // 4, nil
+...
+```
+
+## Умолчания
+
+Стандартные функции в /defaults.go, но можно определить свои
diff --git a/content/go/extra.md b/content/go/extra.md
new file mode 100644
index 0000000..bd78ace
--- /dev/null
+++ b/content/go/extra.md
@@ -0,0 +1,11 @@
++++
+title = "Extra"
+name = "extra"
+repository = "https://git.neonxp.ru/extra.git"
+description = "Пакет с разными полезными функциями без дополнительных зависимостей"
+gomod = true
++++
+
+Пакет с разными полезными функциями без дополнительных зависимостей.
+
+Большинство функций написаны с использованием обобщенных типов. Другие - вызовы этих же функций с конкретными типами для упрощения использования. \ No newline at end of file
diff --git a/content/go/framework.md b/content/go/framework.md
new file mode 100644
index 0000000..c1f9d9a
--- /dev/null
+++ b/content/go/framework.md
@@ -0,0 +1,25 @@
++++
+title = "API шаблон"
+name = "framework"
+repository = "https://git.neonxp.ru/framework.git"
+description = "Базовый проект API"
+gomod = true
++++
+
+```sh
+go install golang.org/x/tools/cmd/gonew@latest
+gonew neonxp.ru/go/framework example.com/myproject
+```
+
+Запуск БД для разработки:
+
+```sh
+make dev-infra-up
+```
+
+Миграция
+
+```sh
+make init-dev
+make migrate-dev
+```
diff --git a/content/go/jsonrpc2.md b/content/go/jsonrpc2.md
new file mode 100644
index 0000000..471c4c9
--- /dev/null
+++ b/content/go/jsonrpc2.md
@@ -0,0 +1,130 @@
++++
+title = "JSON-RPC 2.0"
+name = "jsonrpc2"
+repository = "https://git.neonxp.ru/jsonrpc2.git"
+description = "JSON-RPC 2.0 сервер на генериках"
+gomod = true
++++
+Реализация сервера JSON-RPC 2.0 на Go с использованием дженериков.
+
+Требуется версия Go 1.18+
+Возможности:
+
+- [x] Транспорт HTTP/HTTPS
+- [x] Транспорт TCP
+- [ ] Транспорт WebSocket
+
+## Использование (транспорт HTTP)
+
+1. Создайте сервер JSON-RPC с параметрами:
+ ```go
+ import "neonxp.ru/go/jsonrpc2/rpc"
+ ...
+ s := rpc.New(
+ rpc.WithTransport(&transport.HTTP{
+ Bind: ":8000", // Порт для привязки
+ CORSOrigin: "*", // Источник CORS
+ TLS: &tls.Config{}, // Опциональный конфигурационный файл TLS (по умолчанию nil)
+ Parallel: true, // Разрешить параллельное выполнение пакетных методов (по умолчанию false)
+ }),
+ // Другие параметры, такие как транспорты/средства обработки промежуточного ПО...
+ )
+ ```
+2. Добавьте необходимые транспорты:
+ ```go
+ import "neonxp.ru/go/jsonrpc2/transport"
+ ...
+ s.Use(
+ rpc.WithTransport(&transport.TCP{Bind: ":3000"}),
+ //...
+ )
+ ```
+3. Напишите обработчики:
+ ```go
+ // Этот обработчик поддерживает параметры запроса
+ func Multiply(ctx context.Context, args *Args) (int, error) {
+ return args.A * args.B, nil
+ }
+
+ // Этот обработчик не имеет параметров запроса
+ func Hello(ctx context.Context) (string, error) {
+ return "Мир", nil
+ }
+ ```
+ Обработчик должен иметь контекст в качестве первого параметра и может иметь второй параметр, представляющий параметры запроса (вход любого типа, сериализуемого в JSON). Обработчик всегда возвращает ровно два значения (выход любого типа, сериализуемого в JSON, и ошибку).
+4. Оберните обработчик одной из двух функций rpc.H (с поддержкой параметров запроса) или rpc.HS (без параметров) и зарегистрируйте его на сервере:
+ ```go
+ // обработчик с параметрами
+ s.Register("multiply", rpc.H(Multiply))
+
+ // обработчик без параметров
+ s.Register("hello", rpc.HS(Hello))
+ ```
+5. Запустите сервер RPC:
+ ```go
+ s.Run(ctx)
+ ```
+
+## Пользовательский транспорт
+
+Любой транспорт должен реализовывать простой интерфейс transport.Transport:
+
+```go
+type Transport interface {
+ Run(ctx context.Context, resolver Resolver) error
+}
+```
+Полный пример
+
+```go
+package main
+
+import (
+ "context"
+
+ "neonxp.ru/go/jsonrpc2/rpc"
+ "neonxp.ru/go/jsonrpc2/rpc/middleware"
+ "neonxp.ru/go/jsonrpc2/transport"
+)
+
+func main() {
+ s := rpc.New(
+ rpc.WithLogger(rpc.StdLogger), // Опциональный логгер
+ rpc.WithTransport(&transport.HTTP{Bind: ":8000"}), // Транспорт HTTP
+ )
+
+ // Установите параметры после конструктора
+ s.Use(
+ rpc.WithTransport(&transport.TCP{Bind: ":3000"}), // Транспорт TCP
+ rpc.WithMiddleware(middleware.Logger(rpc.StdLogger)), // Логгер промежуточного ПО
+ )
+
+ s.Register("multiply", rpc.H(Multiply))
+ s.Register("divide", rpc.H(Divide))
+ s.Register("hello", rpc.HS(Hello))
+
+ s.Run(context.Background())
+}
+
+func Multiply(ctx context.Context, args *Args) (int, error) {
+ //...
+}
+
+func Divide(ctx context.Context, args *Args) (*Quotient, error) {
+ //...
+}
+
+func Hello(ctx context.Context) (string, error) {
+ // ...
+}
+
+type Args struct {
+ A int `json:"a"`
+ B int `json:"b"`
+}
+
+type Quotient struct {
+ Quo int `json:"quo"`
+ Rem int `json:"rem"`
+}
+``` \ No newline at end of file
diff --git a/content/go/merger.md b/content/go/merger.md
new file mode 100644
index 0000000..ce355c4
--- /dev/null
+++ b/content/go/merger.md
@@ -0,0 +1,84 @@
++++
+title = "Merger"
+name = "merger"
+repository = "https://git.neonxp.ru/merger.git"
+description = "Простейший мерджер yaml'ов"
+gomod = true
++++
+
+Простейший мерджер yaml'ов
+
+## Установка
+
+```
+go install neonxp.ru/go/merger@latest
+```
+
+## Использование
+
+```
+merger -i file1.yaml -i file2.yaml -i fileN.yaml -o output.yaml
+```
+
+Есть ещё ключи:
+
+- `-replace_arrays false` - если true то массивы по одинаковым ключам будут перезатираться. По умолчанию - соединяться.
+- `-out_type` - выходной формат `yaml` (умолчание) или `json`
+
+## Пример
+
+file1.yaml
+```yaml
+a1:
+ a11:
+ - one
+ - two
+ a12: "one"
+a2:
+ a21:
+ - one
+ - two
+ a22: "one"
+ a23:
+ a231: 231
+ a232: 232
+ a233: 233
+```
+
+file2.yaml
+```yaml
+a1:
+ a11:
+ - three
+ - four
+ a12: "two"
+a2:
+ a23:
+ a231: "!!!"
+ a232: "???"
+ a233:
+ sub: tree
+ to: merge
+```
+
+output.yaml
+```yaml
+a1:
+ a11:
+ - one
+ - two
+ - three
+ - four
+ a12: two
+a2:
+ a21:
+ - one
+ - two
+ a22: one
+ a23:
+ a231: '!!!'
+ a232: ???
+ a233:
+ sub: tree
+ to: merge
+```
diff --git a/content/go/mux.md b/content/go/mux.md
new file mode 100644
index 0000000..2114c9e
--- /dev/null
+++ b/content/go/mux.md
@@ -0,0 +1,9 @@
++++
+title = "Mux"
+name = "mux"
+repository = "https://git.neonxp.ru/mux.git"
+description = "Полезные инструменты для стандартного ServeMux"
+gomod = true
++++
+
+TBA \ No newline at end of file
diff --git a/content/go/objectid.md b/content/go/objectid.md
new file mode 100644
index 0000000..b668d92
--- /dev/null
+++ b/content/go/objectid.md
@@ -0,0 +1,74 @@
++++
+title = "ObjectID"
+name = "objectid"
+repository = "https://git.neonxp.ru/objectid.git"
+description = "Генерация ObjectID на основе даты. Глобально уникальные."
+gomod = true
++++
+
+Простая библиотека для генерации псевдослучайных глобально уникальных идентификаторов.
+Полученные идентификаторы реализуют функцию сравнения, таким образом поддаются сортировке.
+Так же из идентификатора можно получить время его генерации, а так же порядковый номер генерации в пределах сессии. Счетчик используемый при генерации идентификаторов потокобезопасный.
+
+## API
+
+```go package objectid // import "neonxp.ru/go/objectid"```
+
+
+Функции
+
+```go func Seed()```
+ необходимо вызвать в начале сессии
+
+```go func New() ID```
+ возвращает новый идентификатор
+
+```go func FromString(s string) (ID, error)```
+ возвращает идентификатор из base64 представления
+
+```go func FromTime(t time.Time) ID```
+ возвращает идентификатор на основе переданного времени
+
+Типы и методы
+
+```go type ID []byte``` тип представляющий собой идентификатор
+
+```go func (i ID) Counter() uint64```
+ возвращает порядковый номер идентификатора в сессии
+
+```go func (i ID) Less(i2 ID) bool```
+ возвращает true если i2 > i
+
+```go func (i ID) MarshalJSON() ([]byte, error)```
+ формирует json представление идентификатора
+
+```go func (i ID) String() string```
+ возвращает base64 представление идентификатора
+
+```go func (i ID) Time() time.Time```
+ возвращает время создания идентификатора
+
+```go func (i *ID) UnmarshalJSON(b []byte) error```
+ парсит идентификатор из json
+
+Примеры
+
+```go
+import "neonxp.ru/go/objectid"
+
+objectid.Seed()
+
+id1 := objectid.New()
+
+fmt.Printf("Идентификатор сгенерированный сегодня: %s в %s\n", id1, id1.Time()) // пример: Идентификатор сгенерированный сегодня: AAXwV/DVGwXtTj0FRm92SQF3MiquMPlK в 2022-12-21 18:09:36.872197 +0300 MSK
+
+id2 := objectid.FromTime(time.Now().Add(-24 * time.Hour))
+
+fmt.Printf("Идентификатор сгенерированный вчера: %s в %s\n", id2, id2.Time()) // пример: Идентификатор сгенерированный вчера: AAXwQ+U14N8mbGoVPiiNqyZCss7lEV0Z в 2022-12-20 18:14:42.541791 +0300 MSK
+
+r := "id2 > id1"
+if id2.Less(id1) {
+ r = "id2 < id1"
+}
+fmt.Print(r) // выведет: id2 < id1
+```
diff --git a/content/go/unilex.md b/content/go/unilex.md
new file mode 100644
index 0000000..f05e158
--- /dev/null
+++ b/content/go/unilex.md
@@ -0,0 +1,13 @@
++++
+title = "Unilex"
+name = "unilex"
+repository = "https://git.neonxp.ru/unilex.git"
+description = "Универсальный лексер"
+gomod = true
++++
+
+Universal lexer for Golang
+
+Based on Rob Pike's awesome video [Lexical Scanning in Go](https://www.youtube.com/watch?v=HxaD_trXwRE)
+
+Examples: /examples directory. \ No newline at end of file
diff --git a/content/go/workflow.md b/content/go/workflow.md
index 76bc519..9b846bf 100644
--- a/content/go/workflow.md
+++ b/content/go/workflow.md
@@ -7,10 +7,6 @@ gomod = true
outputs = ["html"]
+++
-# Workflow for Go
-
-[![GoDoc](https://godoc.org/github.com/neonxp/workflow?status.svg)](https://godoc.org/github.com/neonxp/workflow)
-
Simple state machine. Inspired by [Symfony Workflow](https://github.com/symfony/workflow).
## Example usage
diff --git a/hugo.toml b/hugo.toml
index afaad4d..5b26f94 100644
--- a/hugo.toml
+++ b/hugo.toml
@@ -73,9 +73,14 @@ url = 'https://git.neonxp.ru'
weight = 50
[[menus.sections]]
+name = 'Мои Go модули'
+url = 'https://neonxp.ru/go/'
+weight = 60
+
+[[menus.sections]]
name = 'Игры'
pageRef = '/projects/games'
-weight = 60
+weight = 70
[[menus.sections]]
name = 'Архив блога'
diff --git a/layouts/go/single.htm b/layouts/go/single.htm
deleted file mode 100644
index 2a5ea73..0000000
--- a/layouts/go/single.htm
+++ /dev/null
@@ -1,4 +0,0 @@
-<html><head>
- <meta name="go-import" content="neonxp.ru/go/{{.Params.Name}} git {{.Params.Repository}}">
- <meta name="go-source" content="neonxp.ru/go/{{.Params.Name}} {{.Params.Repository}}/tree/">
-</head></html> \ No newline at end of file
diff --git a/layouts/go/single.html b/layouts/go/single.html
new file mode 100644
index 0000000..6b287cb
--- /dev/null
+++ b/layouts/go/single.html
@@ -0,0 +1,34 @@
+{{ define "main" }}
+<div class="row">
+ <div class="col-xs-12 col-sm-12 col-md-4 col-lg-4 last-xs last-sm first-md first-lg sidebar">
+ {{ if .Params.toc }}
+ <article>
+ <header>Содержание</header>
+ <aside>{{ .TableOfContents }}</aside>
+ </article>
+ {{ end }}
+ <article>
+ <header>Навигатор</header>
+ {{ partial "menu.html" (dict "menuID" "sections" "page" .) }}
+ </article>
+ </div>
+ <div class="h-entry col-xs-12 col-sm-12 col-md-8 col-lg-8">
+ <article>
+ <header>
+ <div class="row between-xs">
+ <span class="p-name"> {{ .Title }} </span>
+ <a href="https://godoc.neonxp.ru/neonxp.ru/go/{{ .Params.Name }}"><img src="https://godoc.neonxp.ru/neonxp.ru/go/{{ .Params.Name }}?status.svg" /></a>
+ </div>
+ </header>
+ {{ if .Params.Image }}
+ <img src="{{.Params.Image}}" />
+ {{ end }}
+ <div class="p-summary">{{ .Summary }}</div>
+ <div class="e-content">{{ .Content }}</div>
+ <footer>
+ </footer>
+ </article>
+ {{ if .Params.comments }} {{ partial "comments.html" . }} {{ end }}
+ </div>
+</div>
+{{ end }}