Start the Go rewrite: jsjson, awg-ctrl port, differential bench
ci / check (push) Successful in 6m6s

- internal/jsjson: JSON.stringify-compatible encoder and order-preserving decoder,
  tested against fixtures produced by Node itself
- internal/ctrl: awg-ctrl in Go (params, vpn:// keys, users, peers, sync, 3.1
  upgrade, CAKE shaping, metrics, monitor job, Express-compatible HTTP layer)
- internal/iauth, internal/logx: internal Ed25519 tokens and logging
- tools/diffbench: Docker bench with stubbed awg/ip/tc/nft that runs one scenario
  against the TS and Go implementations for comparison

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 15:27:05 +03:00
co-authored by Claude Sonnet 5.5
parent e9df363dd2
commit 18106115f7
28 changed files with 4960 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
package jsjson
import (
"bytes"
"encoding/json"
"errors"
"io"
)
// Decode разбирает JSON с сохранением порядка ключей: объекты — Object, массивы —
// []any, числа — float64, как JSON.parse. Нужен, чтобы JSON.stringify(JSON.parse(x))
// воспроизводился точно (например, сохранённый профиль сервера с ключами awg).
func Decode(data []byte) (any, error) {
d := json.NewDecoder(bytes.NewReader(data))
d.UseNumber()
v, err := decodeValue(d)
if err != nil {
return nil, err
}
if _, err := d.Token(); err != io.EOF {
return nil, errors.New("jsjson: trailing data")
}
return v, nil
}
func decodeValue(d *json.Decoder) (any, error) {
t, err := d.Token()
if err != nil {
return nil, err
}
switch x := t.(type) {
case json.Delim:
switch x {
case '{':
obj := Object{}
for d.More() {
kt, err := d.Token()
if err != nil {
return nil, err
}
key, ok := kt.(string)
if !ok {
return nil, errors.New("jsjson: object key is not a string")
}
val, err := decodeValue(d)
if err != nil {
return nil, err
}
// повторный ключ в JS перезаписывает значение, оставаясь на первом месте
replaced := false
for i := range obj {
if obj[i].Key == key {
obj[i].Val = val
replaced = true
break
}
}
if !replaced {
obj = append(obj, KV{key, val})
}
}
if _, err := d.Token(); err != nil {
return nil, err
}
return obj, nil
case '[':
arr := []any{}
for d.More() {
val, err := decodeValue(d)
if err != nil {
return nil, err
}
arr = append(arr, val)
}
if _, err := d.Token(); err != nil {
return nil, err
}
return arr, nil
}
return nil, errors.New("jsjson: unexpected delimiter")
case json.Number:
return x.Float64()
default:
return x, nil // string, bool, nil
}
}