diff options
author | Alexander Neonxp Kiryukhin <i@neonxp.ru> | 2024-12-11 01:21:22 +0300 |
---|---|---|
committer | Alexander Neonxp Kiryukhin <i@neonxp.ru> | 2024-12-11 01:21:22 +0300 |
commit | a79499018bed35bab05f888ce0103b37655e2852 (patch) | |
tree | d182886009aeafffb247a68ff425c740b3cb6a31 /content | |
parent | 418eac8c0b978089644f48e27a0fbdd20e18ac91 (diff) |
Auto-commit 2024-12-11
Diffstat (limited to 'content')
-rw-r--r-- | content/go/collection.md | 7 | ||||
-rw-r--r-- | content/go/expression.md | 23 | ||||
-rw-r--r-- | content/go/extra.md | 11 | ||||
-rw-r--r-- | content/go/framework.md | 25 | ||||
-rw-r--r-- | content/go/jsonrpc2.md | 130 | ||||
-rw-r--r-- | content/go/merger.md | 84 | ||||
-rw-r--r-- | content/go/mux.md | 9 | ||||
-rw-r--r-- | content/go/objectid.md | 74 | ||||
-rw-r--r-- | content/go/unilex.md | 13 | ||||
-rw-r--r-- | content/go/workflow.md | 4 |
10 files changed, 376 insertions, 4 deletions
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 |