go 1.24
require (
- github.com/francoispqt/gojay v1.2.13
github.com/prometheus/client_golang v1.19.1
github.com/quic-go/qpack v0.5.1
github.com/stretchr/testify v1.9.0
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/kr/text v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
-dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
-dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
-dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
-dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
-git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
-github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
-github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
-github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
-github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
-github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
-github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
-github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
-github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
-github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
-github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
-github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
-github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
-github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
-github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
-github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
-github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
-github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
-github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
-github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
-github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
-github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
-github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
-github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
-github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
-github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
-github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
-github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
-github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
-github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
-go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
-go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
-golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
-golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
-google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
-google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
-sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
"github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/internal/wire"
"github.com/quic-go/quic-go/logging"
-
- "github.com/francoispqt/gojay"
)
type connectionTracer struct {
}
func (t *connectionTracer) sentPacket(
- hdr gojay.MarshalerJSONObject,
+ hdr jsontextEncoder,
size, payloadLen logging.ByteCount,
ecn logging.ECN,
ack *logging.AckFrame,
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/logging"
-
- "github.com/francoispqt/gojay"
+ "github.com/quic-go/quic-go/qlog/jsontext"
)
func milliseconds(dur time.Duration) float64 { return float64(dur.Nanoseconds()) / 1e6 }
type eventDetails interface {
Name() string
- gojay.MarshalerJSONObject
+ Encode(*jsontext.Encoder) error
}
type event struct {
eventDetails
}
-var _ gojay.MarshalerJSONObject = event{}
+type jsontextEncoder interface {
+ Encode(*jsontext.Encoder) error
+}
+
+type encoderHelper struct {
+ enc *jsontext.Encoder
+ err error
+}
-func (e event) IsNil() bool { return false }
-func (e event) MarshalJSONObject(enc *gojay.Encoder) {
- enc.Float64Key("time", milliseconds(e.RelativeTime))
- enc.StringKey("name", e.Name())
- enc.ObjectKey("data", e.eventDetails)
+func (h *encoderHelper) WriteToken(t jsontext.Token) {
+ if h.err != nil {
+ return
+ }
+ h.err = h.enc.WriteToken(t)
+}
+
+func (e event) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("time"))
+ h.WriteToken(jsontext.Float(milliseconds(e.RelativeTime)))
+ h.WriteToken(jsontext.String("name"))
+ h.WriteToken(jsontext.String(e.Name()))
+ h.WriteToken(jsontext.String("data"))
+ if err := e.eventDetails.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type versions []version
-func (v versions) IsNil() bool { return false }
-func (v versions) MarshalJSONArray(enc *gojay.Encoder) {
+func (v versions) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginArray)
for _, e := range v {
- enc.AddString(e.String())
+ h.WriteToken(jsontext.String(e.String()))
}
+ h.WriteToken(jsontext.EndArray)
+ return h.err
}
type rawInfo struct {
PayloadLength logging.ByteCount // length of the packet payload, excluding AEAD tag
}
-func (i rawInfo) IsNil() bool { return false }
-func (i rawInfo) MarshalJSONObject(enc *gojay.Encoder) {
- enc.Uint64Key("length", uint64(i.Length))
- enc.Uint64KeyOmitEmpty("payload_length", uint64(i.PayloadLength))
+func (i rawInfo) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Uint(uint64(i.Length)))
+ if i.PayloadLength != 0 {
+ h.WriteToken(jsontext.String("payload_length"))
+ h.WriteToken(jsontext.Uint(uint64(i.PayloadLength)))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventConnectionStarted struct {
- SrcAddr *net.UDPAddr
- DestAddr *net.UDPAddr
-
+ SrcAddr *net.UDPAddr
+ DestAddr *net.UDPAddr
SrcConnectionID protocol.ConnectionID
DestConnectionID protocol.ConnectionID
}
-var _ eventDetails = &eventConnectionStarted{}
-
func (e eventConnectionStarted) Name() string { return "transport:connection_started" }
-func (e eventConnectionStarted) IsNil() bool { return false }
-func (e eventConnectionStarted) MarshalJSONObject(enc *gojay.Encoder) {
+func (e eventConnectionStarted) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
if e.SrcAddr.IP.To4() != nil {
- enc.StringKey("ip_version", "ipv4")
+ h.WriteToken(jsontext.String("ip_version"))
+ h.WriteToken(jsontext.String("ipv4"))
} else {
- enc.StringKey("ip_version", "ipv6")
+ h.WriteToken(jsontext.String("ip_version"))
+ h.WriteToken(jsontext.String("ipv6"))
}
- enc.StringKey("src_ip", e.SrcAddr.IP.String())
- enc.IntKey("src_port", e.SrcAddr.Port)
- enc.StringKey("dst_ip", e.DestAddr.IP.String())
- enc.IntKey("dst_port", e.DestAddr.Port)
- enc.StringKey("src_cid", e.SrcConnectionID.String())
- enc.StringKey("dst_cid", e.DestConnectionID.String())
+ h.WriteToken(jsontext.String("src_ip"))
+ h.WriteToken(jsontext.String(e.SrcAddr.IP.String()))
+ h.WriteToken(jsontext.String("src_port"))
+ h.WriteToken(jsontext.Int(int64(e.SrcAddr.Port)))
+ h.WriteToken(jsontext.String("dst_ip"))
+ h.WriteToken(jsontext.String(e.DestAddr.IP.String()))
+ h.WriteToken(jsontext.String("dst_port"))
+ h.WriteToken(jsontext.Int(int64(e.DestAddr.Port)))
+ h.WriteToken(jsontext.String("src_cid"))
+ h.WriteToken(jsontext.String(e.SrcConnectionID.String()))
+ h.WriteToken(jsontext.String("dst_cid"))
+ h.WriteToken(jsontext.String(e.DestConnectionID.String()))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventVersionNegotiated struct {
}
func (e eventVersionNegotiated) Name() string { return "transport:version_information" }
-func (e eventVersionNegotiated) IsNil() bool { return false }
-func (e eventVersionNegotiated) MarshalJSONObject(enc *gojay.Encoder) {
+func (e eventVersionNegotiated) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
if len(e.clientVersions) > 0 {
- enc.ArrayKey("client_versions", versions(e.clientVersions))
+ h.WriteToken(jsontext.String("client_versions"))
+ if err := versions(e.clientVersions).Encode(enc); err != nil {
+ return err
+ }
}
if len(e.serverVersions) > 0 {
- enc.ArrayKey("server_versions", versions(e.serverVersions))
+ h.WriteToken(jsontext.String("server_versions"))
+ if err := versions(e.serverVersions).Encode(enc); err != nil {
+ return err
+ }
}
- enc.StringKey("chosen_version", e.chosenVersion.String())
+ h.WriteToken(jsontext.String("chosen_version"))
+ h.WriteToken(jsontext.String(e.chosenVersion.String()))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventConnectionClosed struct {
}
func (e eventConnectionClosed) Name() string { return "transport:connection_closed" }
-func (e eventConnectionClosed) IsNil() bool { return false }
-func (e eventConnectionClosed) MarshalJSONObject(enc *gojay.Encoder) {
+func (e eventConnectionClosed) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
var (
statelessResetErr *quic.StatelessResetError
handshakeTimeoutErr *quic.HandshakeTimeoutError
)
switch {
case errors.As(e.e, &statelessResetErr):
- enc.StringKey("owner", ownerRemote.String())
- enc.StringKey("trigger", "stateless_reset")
+ h.WriteToken(jsontext.String("owner"))
+ h.WriteToken(jsontext.String(ownerRemote.String()))
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String("stateless_reset"))
case errors.As(e.e, &handshakeTimeoutErr):
- enc.StringKey("owner", ownerLocal.String())
- enc.StringKey("trigger", "handshake_timeout")
+ h.WriteToken(jsontext.String("owner"))
+ h.WriteToken(jsontext.String(ownerLocal.String()))
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String("handshake_timeout"))
case errors.As(e.e, &idleTimeoutErr):
- enc.StringKey("owner", ownerLocal.String())
- enc.StringKey("trigger", "idle_timeout")
+ h.WriteToken(jsontext.String("owner"))
+ h.WriteToken(jsontext.String(ownerLocal.String()))
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String("idle_timeout"))
case errors.As(e.e, &applicationErr):
owner := ownerLocal
if applicationErr.Remote {
owner = ownerRemote
}
- enc.StringKey("owner", owner.String())
- enc.Uint64Key("application_code", uint64(applicationErr.ErrorCode))
- enc.StringKey("reason", applicationErr.ErrorMessage)
+ h.WriteToken(jsontext.String("owner"))
+ h.WriteToken(jsontext.String(owner.String()))
+ h.WriteToken(jsontext.String("application_code"))
+ h.WriteToken(jsontext.Uint(uint64(applicationErr.ErrorCode)))
+ h.WriteToken(jsontext.String("reason"))
+ h.WriteToken(jsontext.String(applicationErr.ErrorMessage))
case errors.As(e.e, &transportErr):
owner := ownerLocal
if transportErr.Remote {
owner = ownerRemote
}
- enc.StringKey("owner", owner.String())
- enc.StringKey("connection_code", transportError(transportErr.ErrorCode).String())
- enc.StringKey("reason", transportErr.ErrorMessage)
+ h.WriteToken(jsontext.String("owner"))
+ h.WriteToken(jsontext.String(owner.String()))
+ h.WriteToken(jsontext.String("connection_code"))
+ h.WriteToken(jsontext.String(transportError(transportErr.ErrorCode).String()))
+ h.WriteToken(jsontext.String("reason"))
+ h.WriteToken(jsontext.String(transportErr.ErrorMessage))
case errors.As(e.e, &versionNegotiationErr):
- enc.StringKey("trigger", "version_mismatch")
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String("version_mismatch"))
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventPacketSent struct {
- Header gojay.MarshalerJSONObject // either a shortHeader or a packetHeader
+ Header jsontextEncoder // either a shortHeader or a packetHeader
Length logging.ByteCount
PayloadLength logging.ByteCount
Frames frames
Trigger string
}
-var _ eventDetails = eventPacketSent{}
-
func (e eventPacketSent) Name() string { return "transport:packet_sent" }
-func (e eventPacketSent) IsNil() bool { return false }
-func (e eventPacketSent) MarshalJSONObject(enc *gojay.Encoder) {
- enc.ObjectKey("header", e.Header)
- enc.ObjectKey("raw", rawInfo{Length: e.Length, PayloadLength: e.PayloadLength})
- enc.ArrayKeyOmitEmpty("frames", e.Frames)
- enc.BoolKeyOmitEmpty("is_coalesced", e.IsCoalesced)
+func (e eventPacketSent) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("raw"))
+ if err := (rawInfo{Length: e.Length, PayloadLength: e.PayloadLength}).Encode(enc); err != nil {
+ return err
+ }
+ if len(e.Frames) > 0 {
+ h.WriteToken(jsontext.String("frames"))
+ if err := e.Frames.Encode(enc); err != nil {
+ return err
+ }
+ }
+ if e.IsCoalesced {
+ h.WriteToken(jsontext.String("is_coalesced"))
+ h.WriteToken(jsontext.True)
+ }
if e.ECN != logging.ECNUnsupported {
- enc.StringKey("ecn", ecn(e.ECN).String())
+ h.WriteToken(jsontext.String("ecn"))
+ h.WriteToken(jsontext.String(ecn(e.ECN).String()))
}
- enc.StringKeyOmitEmpty("trigger", e.Trigger)
+ if e.Trigger != "" {
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(e.Trigger))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventPacketReceived struct {
- Header gojay.MarshalerJSONObject // either a shortHeader or a packetHeader
+ Header jsontextEncoder // either a shortHeader or a packetHeader
Length logging.ByteCount
PayloadLength logging.ByteCount
Frames frames
Trigger string
}
-var _ eventDetails = eventPacketReceived{}
-
func (e eventPacketReceived) Name() string { return "transport:packet_received" }
-func (e eventPacketReceived) IsNil() bool { return false }
-func (e eventPacketReceived) MarshalJSONObject(enc *gojay.Encoder) {
- enc.ObjectKey("header", e.Header)
- enc.ObjectKey("raw", rawInfo{Length: e.Length, PayloadLength: e.PayloadLength})
- enc.ArrayKeyOmitEmpty("frames", e.Frames)
- enc.BoolKeyOmitEmpty("is_coalesced", e.IsCoalesced)
+func (e eventPacketReceived) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("raw"))
+ if err := (rawInfo{Length: e.Length, PayloadLength: e.PayloadLength}).Encode(enc); err != nil {
+ return err
+ }
+ if len(e.Frames) > 0 {
+ h.WriteToken(jsontext.String("frames"))
+ if err := e.Frames.Encode(enc); err != nil {
+ return err
+ }
+ }
+ if e.IsCoalesced {
+ h.WriteToken(jsontext.String("is_coalesced"))
+ h.WriteToken(jsontext.True)
+ }
if e.ECN != logging.ECNUnsupported {
- enc.StringKey("ecn", ecn(e.ECN).String())
+ h.WriteToken(jsontext.String("ecn"))
+ h.WriteToken(jsontext.String(ecn(e.ECN).String()))
+ }
+ if e.Trigger != "" {
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(e.Trigger))
}
- enc.StringKeyOmitEmpty("trigger", e.Trigger)
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventRetryReceived struct {
}
func (e eventRetryReceived) Name() string { return "transport:packet_received" }
-func (e eventRetryReceived) IsNil() bool { return false }
-func (e eventRetryReceived) MarshalJSONObject(enc *gojay.Encoder) {
- enc.ObjectKey("header", e.Header)
+func (e eventRetryReceived) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventVersionNegotiationReceived struct {
}
func (e eventVersionNegotiationReceived) Name() string { return "transport:packet_received" }
-func (e eventVersionNegotiationReceived) IsNil() bool { return false }
-func (e eventVersionNegotiationReceived) MarshalJSONObject(enc *gojay.Encoder) {
- enc.ObjectKey("header", e.Header)
- enc.ArrayKey("supported_versions", versions(e.SupportedVersions))
+func (e eventVersionNegotiationReceived) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("supported_versions"))
+ if err := versions(e.SupportedVersions).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventVersionNegotiationSent struct {
}
func (e eventVersionNegotiationSent) Name() string { return "transport:packet_sent" }
-func (e eventVersionNegotiationSent) IsNil() bool { return false }
-func (e eventVersionNegotiationSent) MarshalJSONObject(enc *gojay.Encoder) {
- enc.ObjectKey("header", e.Header)
- enc.ArrayKey("supported_versions", versions(e.SupportedVersions))
+func (e eventVersionNegotiationSent) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("supported_versions"))
+ if err := versions(e.SupportedVersions).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventPacketBuffered struct {
}
func (e eventPacketBuffered) Name() string { return "transport:packet_buffered" }
-func (e eventPacketBuffered) IsNil() bool { return false }
-func (e eventPacketBuffered) MarshalJSONObject(enc *gojay.Encoder) {
- //nolint:gosimple
- enc.ObjectKey("header", packetHeaderWithType{PacketType: e.PacketType, PacketNumber: protocol.InvalidPacketNumber})
- enc.ObjectKey("raw", rawInfo{Length: e.PacketSize})
- enc.StringKey("trigger", "keys_unavailable")
+func (e eventPacketBuffered) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := (packetHeaderWithType{
+ PacketType: e.PacketType,
+ PacketNumber: protocol.InvalidPacketNumber,
+ }).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("raw"))
+ if err := (rawInfo{Length: e.PacketSize}).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String("keys_unavailable"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventPacketDropped struct {
}
func (e eventPacketDropped) Name() string { return "transport:packet_dropped" }
-func (e eventPacketDropped) IsNil() bool { return false }
-func (e eventPacketDropped) MarshalJSONObject(enc *gojay.Encoder) {
- enc.ObjectKey("header", packetHeaderWithType{
+func (e eventPacketDropped) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := (packetHeaderWithType{
PacketType: e.PacketType,
PacketNumber: e.PacketNumber,
- })
- enc.ObjectKey("raw", rawInfo{Length: e.PacketSize})
- enc.StringKey("trigger", e.Trigger.String())
+ }).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("raw"))
+ if err := (rawInfo{Length: e.PacketSize}).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(e.Trigger.String()))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type metrics struct {
- MinRTT time.Duration
- SmoothedRTT time.Duration
- LatestRTT time.Duration
- RTTVariance time.Duration
-
+ MinRTT time.Duration
+ SmoothedRTT time.Duration
+ LatestRTT time.Duration
+ RTTVariance time.Duration
CongestionWindow protocol.ByteCount
BytesInFlight protocol.ByteCount
PacketsInFlight int
}
func (e eventMTUUpdated) Name() string { return "recovery:mtu_updated" }
-func (e eventMTUUpdated) IsNil() bool { return false }
-func (e eventMTUUpdated) MarshalJSONObject(enc *gojay.Encoder) {
- enc.Uint64Key("mtu", uint64(e.mtu))
- enc.BoolKey("done", e.done)
+func (e eventMTUUpdated) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("mtu"))
+ h.WriteToken(jsontext.Uint(uint64(e.mtu)))
+ h.WriteToken(jsontext.String("done"))
+ h.WriteToken(jsontext.Bool(e.done))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventMetricsUpdated struct {
}
func (e eventMetricsUpdated) Name() string { return "recovery:metrics_updated" }
-func (e eventMetricsUpdated) IsNil() bool { return false }
-func (e eventMetricsUpdated) MarshalJSONObject(enc *gojay.Encoder) {
+func (e eventMetricsUpdated) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
if e.Last == nil || e.Last.MinRTT != e.Current.MinRTT {
- enc.FloatKey("min_rtt", milliseconds(e.Current.MinRTT))
+ h.WriteToken(jsontext.String("min_rtt"))
+ h.WriteToken(jsontext.Float(milliseconds(e.Current.MinRTT)))
}
if e.Last == nil || e.Last.SmoothedRTT != e.Current.SmoothedRTT {
- enc.FloatKey("smoothed_rtt", milliseconds(e.Current.SmoothedRTT))
+ h.WriteToken(jsontext.String("smoothed_rtt"))
+ h.WriteToken(jsontext.Float(milliseconds(e.Current.SmoothedRTT)))
}
if e.Last == nil || e.Last.LatestRTT != e.Current.LatestRTT {
- enc.FloatKey("latest_rtt", milliseconds(e.Current.LatestRTT))
+ h.WriteToken(jsontext.String("latest_rtt"))
+ h.WriteToken(jsontext.Float(milliseconds(e.Current.LatestRTT)))
}
if e.Last == nil || e.Last.RTTVariance != e.Current.RTTVariance {
- enc.FloatKey("rtt_variance", milliseconds(e.Current.RTTVariance))
+ h.WriteToken(jsontext.String("rtt_variance"))
+ h.WriteToken(jsontext.Float(milliseconds(e.Current.RTTVariance)))
}
-
if e.Last == nil || e.Last.CongestionWindow != e.Current.CongestionWindow {
- enc.Uint64Key("congestion_window", uint64(e.Current.CongestionWindow))
+ h.WriteToken(jsontext.String("congestion_window"))
+ h.WriteToken(jsontext.Uint(uint64(e.Current.CongestionWindow)))
}
if e.Last == nil || e.Last.BytesInFlight != e.Current.BytesInFlight {
- enc.Uint64Key("bytes_in_flight", uint64(e.Current.BytesInFlight))
+ h.WriteToken(jsontext.String("bytes_in_flight"))
+ h.WriteToken(jsontext.Uint(uint64(e.Current.BytesInFlight)))
}
if e.Last == nil || e.Last.PacketsInFlight != e.Current.PacketsInFlight {
- enc.Uint64Key("packets_in_flight", uint64(e.Current.PacketsInFlight))
+ h.WriteToken(jsontext.String("packets_in_flight"))
+ h.WriteToken(jsontext.Uint(uint64(e.Current.PacketsInFlight)))
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventUpdatedPTO struct {
}
func (e eventUpdatedPTO) Name() string { return "recovery:metrics_updated" }
-func (e eventUpdatedPTO) IsNil() bool { return false }
-func (e eventUpdatedPTO) MarshalJSONObject(enc *gojay.Encoder) {
- enc.Uint32Key("pto_count", e.Value)
+func (e eventUpdatedPTO) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("pto_count"))
+ h.WriteToken(jsontext.Uint(uint64(e.Value)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventPacketLost struct {
}
func (e eventPacketLost) Name() string { return "recovery:packet_lost" }
-func (e eventPacketLost) IsNil() bool { return false }
-func (e eventPacketLost) MarshalJSONObject(enc *gojay.Encoder) {
- enc.ObjectKey("header", packetHeaderWithTypeAndPacketNumber{
+func (e eventPacketLost) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := (packetHeaderWithTypeAndPacketNumber{
PacketType: e.PacketType,
PacketNumber: e.PacketNumber,
- })
- enc.StringKey("trigger", e.Trigger.String())
+ }).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(e.Trigger.String()))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventSpuriousLoss struct {
}
func (e eventSpuriousLoss) Name() string { return "recovery:spurious_loss" }
-func (e eventSpuriousLoss) IsNil() bool { return false }
-func (e eventSpuriousLoss) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel))
- enc.Uint64Key("packet_number", uint64(e.PacketNumber))
- enc.Uint64Key("reordering_packets", e.Reordering)
- enc.Float64Key("reordering_time", milliseconds(e.Duration))
+func (e eventSpuriousLoss) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("packet_number_space"))
+ h.WriteToken(jsontext.String(encLevelToPacketNumberSpace(e.EncLevel)))
+ h.WriteToken(jsontext.String("packet_number"))
+ h.WriteToken(jsontext.Uint(uint64(e.PacketNumber)))
+ h.WriteToken(jsontext.String("reordering_packets"))
+ h.WriteToken(jsontext.Uint(e.Reordering))
+ h.WriteToken(jsontext.String("reordering_time"))
+ h.WriteToken(jsontext.Float(milliseconds(e.Duration)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventKeyUpdated struct {
}
func (e eventKeyUpdated) Name() string { return "security:key_updated" }
-func (e eventKeyUpdated) IsNil() bool { return false }
-func (e eventKeyUpdated) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("trigger", e.Trigger.String())
- enc.StringKey("key_type", e.KeyType.String())
+func (e eventKeyUpdated) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(e.Trigger.String()))
+ h.WriteToken(jsontext.String("key_type"))
+ h.WriteToken(jsontext.String(e.KeyType.String()))
if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT {
- enc.Uint64Key("key_phase", uint64(e.KeyPhase))
+ h.WriteToken(jsontext.String("key_phase"))
+ h.WriteToken(jsontext.Uint(uint64(e.KeyPhase)))
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventKeyDiscarded struct {
}
func (e eventKeyDiscarded) Name() string { return "security:key_discarded" }
-func (e eventKeyDiscarded) IsNil() bool { return false }
-func (e eventKeyDiscarded) MarshalJSONObject(enc *gojay.Encoder) {
+func (e eventKeyDiscarded) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
if e.KeyType != keyTypeClient1RTT && e.KeyType != keyTypeServer1RTT {
- enc.StringKey("trigger", "tls")
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String("tls"))
}
- enc.StringKey("key_type", e.KeyType.String())
+ h.WriteToken(jsontext.String("key_type"))
+ h.WriteToken(jsontext.String(e.KeyType.String()))
if e.KeyType == keyTypeClient1RTT || e.KeyType == keyTypeServer1RTT {
- enc.Uint64Key("key_phase", uint64(e.KeyPhase))
+ h.WriteToken(jsontext.String("key_phase"))
+ h.WriteToken(jsontext.Uint(uint64(e.KeyPhase)))
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventTransportParameters struct {
- Restore bool
- Owner owner
- SentBy protocol.Perspective
-
+ Restore bool
+ Owner owner
+ SentBy protocol.Perspective
OriginalDestinationConnectionID protocol.ConnectionID
InitialSourceConnectionID protocol.ConnectionID
RetrySourceConnectionID *protocol.ConnectionID
-
- StatelessResetToken *protocol.StatelessResetToken
- DisableActiveMigration bool
- MaxIdleTimeout time.Duration
- MaxUDPPayloadSize protocol.ByteCount
- AckDelayExponent uint8
- MaxAckDelay time.Duration
- ActiveConnectionIDLimit uint64
-
- InitialMaxData protocol.ByteCount
- InitialMaxStreamDataBidiLocal protocol.ByteCount
- InitialMaxStreamDataBidiRemote protocol.ByteCount
- InitialMaxStreamDataUni protocol.ByteCount
- InitialMaxStreamsBidi int64
- InitialMaxStreamsUni int64
-
- PreferredAddress *preferredAddress
-
- MaxDatagramFrameSize protocol.ByteCount
- EnableResetStreamAt bool
+ StatelessResetToken *protocol.StatelessResetToken
+ DisableActiveMigration bool
+ MaxIdleTimeout time.Duration
+ MaxUDPPayloadSize protocol.ByteCount
+ AckDelayExponent uint8
+ MaxAckDelay time.Duration
+ ActiveConnectionIDLimit uint64
+ InitialMaxData protocol.ByteCount
+ InitialMaxStreamDataBidiLocal protocol.ByteCount
+ InitialMaxStreamDataBidiRemote protocol.ByteCount
+ InitialMaxStreamDataUni protocol.ByteCount
+ InitialMaxStreamsBidi int64
+ InitialMaxStreamsUni int64
+ PreferredAddress *preferredAddress
+ MaxDatagramFrameSize protocol.ByteCount
+ EnableResetStreamAt bool
}
func (e eventTransportParameters) Name() string {
return "transport:parameters_set"
}
-func (e eventTransportParameters) IsNil() bool { return false }
-
-func (e eventTransportParameters) MarshalJSONObject(enc *gojay.Encoder) {
+func (e eventTransportParameters) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
if !e.Restore {
- enc.StringKey("owner", e.Owner.String())
+ h.WriteToken(jsontext.String("owner"))
+ h.WriteToken(jsontext.String(e.Owner.String()))
if e.SentBy == protocol.PerspectiveServer {
- enc.StringKey("original_destination_connection_id", e.OriginalDestinationConnectionID.String())
+ h.WriteToken(jsontext.String("original_destination_connection_id"))
+ h.WriteToken(jsontext.String(e.OriginalDestinationConnectionID.String()))
if e.StatelessResetToken != nil {
- enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", e.StatelessResetToken[:]))
+ h.WriteToken(jsontext.String("stateless_reset_token"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", e.StatelessResetToken[:])))
}
if e.RetrySourceConnectionID != nil {
- enc.StringKey("retry_source_connection_id", (*e.RetrySourceConnectionID).String())
+ h.WriteToken(jsontext.String("retry_source_connection_id"))
+ h.WriteToken(jsontext.String((*e.RetrySourceConnectionID).String()))
}
}
- enc.StringKey("initial_source_connection_id", e.InitialSourceConnectionID.String())
- }
- enc.BoolKey("disable_active_migration", e.DisableActiveMigration)
- enc.FloatKeyOmitEmpty("max_idle_timeout", milliseconds(e.MaxIdleTimeout))
- enc.Int64KeyNullEmpty("max_udp_payload_size", int64(e.MaxUDPPayloadSize))
- enc.Uint8KeyOmitEmpty("ack_delay_exponent", e.AckDelayExponent)
- enc.FloatKeyOmitEmpty("max_ack_delay", milliseconds(e.MaxAckDelay))
- enc.Uint64KeyOmitEmpty("active_connection_id_limit", e.ActiveConnectionIDLimit)
-
- enc.Int64KeyOmitEmpty("initial_max_data", int64(e.InitialMaxData))
- enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_local", int64(e.InitialMaxStreamDataBidiLocal))
- enc.Int64KeyOmitEmpty("initial_max_stream_data_bidi_remote", int64(e.InitialMaxStreamDataBidiRemote))
- enc.Int64KeyOmitEmpty("initial_max_stream_data_uni", int64(e.InitialMaxStreamDataUni))
- enc.Int64KeyOmitEmpty("initial_max_streams_bidi", e.InitialMaxStreamsBidi)
- enc.Int64KeyOmitEmpty("initial_max_streams_uni", e.InitialMaxStreamsUni)
-
+ h.WriteToken(jsontext.String("initial_source_connection_id"))
+ h.WriteToken(jsontext.String(e.InitialSourceConnectionID.String()))
+ }
+ h.WriteToken(jsontext.String("disable_active_migration"))
+ h.WriteToken(jsontext.Bool(e.DisableActiveMigration))
+ if e.MaxIdleTimeout != 0 {
+ h.WriteToken(jsontext.String("max_idle_timeout"))
+ h.WriteToken(jsontext.Float(milliseconds(e.MaxIdleTimeout)))
+ }
+ if e.MaxUDPPayloadSize != 0 {
+ h.WriteToken(jsontext.String("max_udp_payload_size"))
+ h.WriteToken(jsontext.Int(int64(e.MaxUDPPayloadSize)))
+ }
+ if e.AckDelayExponent != 0 {
+ h.WriteToken(jsontext.String("ack_delay_exponent"))
+ h.WriteToken(jsontext.Uint(uint64(e.AckDelayExponent)))
+ }
+ if e.MaxAckDelay != 0 {
+ h.WriteToken(jsontext.String("max_ack_delay"))
+ h.WriteToken(jsontext.Float(milliseconds(e.MaxAckDelay)))
+ }
+ if e.ActiveConnectionIDLimit != 0 {
+ h.WriteToken(jsontext.String("active_connection_id_limit"))
+ h.WriteToken(jsontext.Uint(e.ActiveConnectionIDLimit))
+ }
+ if e.InitialMaxData != 0 {
+ h.WriteToken(jsontext.String("initial_max_data"))
+ h.WriteToken(jsontext.Int(int64(e.InitialMaxData)))
+ }
+ if e.InitialMaxStreamDataBidiLocal != 0 {
+ h.WriteToken(jsontext.String("initial_max_stream_data_bidi_local"))
+ h.WriteToken(jsontext.Int(int64(e.InitialMaxStreamDataBidiLocal)))
+ }
+ if e.InitialMaxStreamDataBidiRemote != 0 {
+ h.WriteToken(jsontext.String("initial_max_stream_data_bidi_remote"))
+ h.WriteToken(jsontext.Int(int64(e.InitialMaxStreamDataBidiRemote)))
+ }
+ if e.InitialMaxStreamDataUni != 0 {
+ h.WriteToken(jsontext.String("initial_max_stream_data_uni"))
+ h.WriteToken(jsontext.Int(int64(e.InitialMaxStreamDataUni)))
+ }
+ if e.InitialMaxStreamsBidi != 0 {
+ h.WriteToken(jsontext.String("initial_max_streams_bidi"))
+ h.WriteToken(jsontext.Int(e.InitialMaxStreamsBidi))
+ }
+ if e.InitialMaxStreamsUni != 0 {
+ h.WriteToken(jsontext.String("initial_max_streams_uni"))
+ h.WriteToken(jsontext.Int(e.InitialMaxStreamsUni))
+ }
if e.PreferredAddress != nil {
- enc.ObjectKey("preferred_address", e.PreferredAddress)
+ h.WriteToken(jsontext.String("preferred_address"))
+ if err := e.PreferredAddress.Encode(enc); err != nil {
+ return err
+ }
}
if e.MaxDatagramFrameSize != protocol.InvalidByteCount {
- enc.Int64Key("max_datagram_frame_size", int64(e.MaxDatagramFrameSize))
+ h.WriteToken(jsontext.String("max_datagram_frame_size"))
+ h.WriteToken(jsontext.Int(int64(e.MaxDatagramFrameSize)))
}
if e.EnableResetStreamAt {
- enc.BoolKey("reset_stream_at", true)
+ h.WriteToken(jsontext.String("reset_stream_at"))
+ h.WriteToken(jsontext.True)
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type preferredAddress struct {
StatelessResetToken protocol.StatelessResetToken
}
-var _ gojay.MarshalerJSONObject = &preferredAddress{}
-
-func (a preferredAddress) IsNil() bool { return false }
-func (a preferredAddress) MarshalJSONObject(enc *gojay.Encoder) {
+func (a preferredAddress) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
if a.IPv4.IsValid() {
- enc.StringKey("ip_v4", a.IPv4.Addr().String())
- enc.Uint16Key("port_v4", a.IPv4.Port())
+ h.WriteToken(jsontext.String("ip_v4"))
+ h.WriteToken(jsontext.String(a.IPv4.Addr().String()))
+ h.WriteToken(jsontext.String("port_v4"))
+ h.WriteToken(jsontext.Uint(uint64(a.IPv4.Port())))
}
if a.IPv6.IsValid() {
- enc.StringKey("ip_v6", a.IPv6.Addr().String())
- enc.Uint16Key("port_v6", a.IPv6.Port())
+ h.WriteToken(jsontext.String("ip_v6"))
+ h.WriteToken(jsontext.String(a.IPv6.Addr().String()))
+ h.WriteToken(jsontext.String("port_v6"))
+ h.WriteToken(jsontext.Uint(uint64(a.IPv6.Port())))
}
- enc.StringKey("connection_id", a.ConnectionID.String())
- enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", a.StatelessResetToken))
+ h.WriteToken(jsontext.String("connection_id"))
+ h.WriteToken(jsontext.String(a.ConnectionID.String()))
+ h.WriteToken(jsontext.String("stateless_reset_token"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", a.StatelessResetToken)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventLossTimerSet struct {
}
func (e eventLossTimerSet) Name() string { return "recovery:loss_timer_updated" }
-func (e eventLossTimerSet) IsNil() bool { return false }
-func (e eventLossTimerSet) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("event_type", "set")
- enc.StringKey("timer_type", e.TimerType.String())
- enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel))
- enc.Float64Key("delta", milliseconds(e.Delta))
+func (e eventLossTimerSet) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("event_type"))
+ h.WriteToken(jsontext.String("set"))
+ h.WriteToken(jsontext.String("timer_type"))
+ h.WriteToken(jsontext.String(e.TimerType.String()))
+ h.WriteToken(jsontext.String("packet_number_space"))
+ h.WriteToken(jsontext.String(encLevelToPacketNumberSpace(e.EncLevel)))
+ h.WriteToken(jsontext.String("delta"))
+ h.WriteToken(jsontext.Float(milliseconds(e.Delta)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventLossTimerExpired struct {
}
func (e eventLossTimerExpired) Name() string { return "recovery:loss_timer_updated" }
-func (e eventLossTimerExpired) IsNil() bool { return false }
-func (e eventLossTimerExpired) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("event_type", "expired")
- enc.StringKey("timer_type", e.TimerType.String())
- enc.StringKey("packet_number_space", encLevelToPacketNumberSpace(e.EncLevel))
+func (e eventLossTimerExpired) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("event_type"))
+ h.WriteToken(jsontext.String("expired"))
+ h.WriteToken(jsontext.String("timer_type"))
+ h.WriteToken(jsontext.String(e.TimerType.String()))
+ h.WriteToken(jsontext.String("packet_number_space"))
+ h.WriteToken(jsontext.String(encLevelToPacketNumberSpace(e.EncLevel)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventLossTimerCanceled struct{}
func (e eventLossTimerCanceled) Name() string { return "recovery:loss_timer_updated" }
-func (e eventLossTimerCanceled) IsNil() bool { return false }
-func (e eventLossTimerCanceled) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("event_type", "cancelled")
+func (e eventLossTimerCanceled) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("event_type"))
+ h.WriteToken(jsontext.String("cancelled"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventCongestionStateUpdated struct {
}
func (e eventCongestionStateUpdated) Name() string { return "recovery:congestion_state_updated" }
-func (e eventCongestionStateUpdated) IsNil() bool { return false }
-func (e eventCongestionStateUpdated) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("new", e.state.String())
+func (e eventCongestionStateUpdated) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("new"))
+ h.WriteToken(jsontext.String(e.state.String()))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventECNStateUpdated struct {
}
func (e eventECNStateUpdated) Name() string { return "recovery:ecn_state_updated" }
-func (e eventECNStateUpdated) IsNil() bool { return false }
-func (e eventECNStateUpdated) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("new", ecnState(e.state).String())
- enc.StringKeyOmitEmpty("trigger", ecnStateTrigger(e.trigger).String())
+func (e eventECNStateUpdated) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("new"))
+ h.WriteToken(jsontext.String(ecnState(e.state).String()))
+ if e.trigger != 0 {
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(ecnStateTrigger(e.trigger).String()))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventALPNInformation struct {
}
func (e eventALPNInformation) Name() string { return "transport:alpn_information" }
-func (e eventALPNInformation) IsNil() bool { return false }
-func (e eventALPNInformation) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("chosen_alpn", e.chosenALPN)
+func (e eventALPNInformation) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("chosen_alpn"))
+ h.WriteToken(jsontext.String(e.chosenALPN))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type eventGeneric struct {
}
func (e eventGeneric) Name() string { return "transport:" + e.name }
-func (e eventGeneric) IsNil() bool { return false }
-func (e eventGeneric) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("details", e.msg)
+func (e eventGeneric) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("details"))
+ h.WriteToken(jsontext.String(e.msg))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
"testing"
"time"
- "github.com/francoispqt/gojay"
+ "github.com/quic-go/quic-go/qlog/jsontext"
+
"github.com/stretchr/testify/require"
)
var _ eventDetails = mevent{}
-func (mevent) Name() string { return "foobar:mevent" }
-func (mevent) IsNil() bool { return false }
-func (mevent) MarshalJSONObject(enc *gojay.Encoder) { enc.StringKey("event", "details") }
+func (mevent) Name() string { return "foobar:mevent" }
+func (mevent) Encode(enc *jsontext.Encoder) error {
+ if err := enc.WriteToken(jsontext.BeginObject); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String("event")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String("details")); err != nil {
+ return err
+ }
+ return enc.WriteToken(jsontext.EndObject)
+}
func TestEventMarshaling(t *testing.T) {
buf := &bytes.Buffer{}
- enc := gojay.NewEncoder(buf)
- err := enc.Encode(event{
+ enc := jsontext.NewEncoder(buf)
+ err := (event{
RelativeTime: 1337 * time.Microsecond,
eventDetails: mevent{},
- })
+ }).Encode(enc)
require.NoError(t, err)
var decoded map[string]any
"github.com/quic-go/quic-go/internal/wire"
"github.com/quic-go/quic-go/logging"
-
- "github.com/francoispqt/gojay"
+ "github.com/quic-go/quic-go/qlog/jsontext"
)
type frame struct {
Frame logging.Frame
}
-var _ gojay.MarshalerJSONObject = frame{}
-
-var _ gojay.MarshalerJSONArray = frames{}
-
-func (f frame) MarshalJSONObject(enc *gojay.Encoder) {
+func (f frame) Encode(enc *jsontext.Encoder) error {
switch frame := f.Frame.(type) {
case *logging.PingFrame:
- marshalPingFrame(enc, frame)
+ return encodePingFrame(enc, frame)
case *logging.AckFrame:
- marshalAckFrame(enc, frame)
+ return encodeAckFrame(enc, frame)
case *logging.ResetStreamFrame:
- marshalResetStreamFrame(enc, frame)
+ return encodeResetStreamFrame(enc, frame)
case *logging.StopSendingFrame:
- marshalStopSendingFrame(enc, frame)
+ return encodeStopSendingFrame(enc, frame)
case *logging.CryptoFrame:
- marshalCryptoFrame(enc, frame)
+ return encodeCryptoFrame(enc, frame)
case *logging.NewTokenFrame:
- marshalNewTokenFrame(enc, frame)
+ return encodeNewTokenFrame(enc, frame)
case *logging.StreamFrame:
- marshalStreamFrame(enc, frame)
+ return encodeStreamFrame(enc, frame)
case *logging.MaxDataFrame:
- marshalMaxDataFrame(enc, frame)
+ return encodeMaxDataFrame(enc, frame)
case *logging.MaxStreamDataFrame:
- marshalMaxStreamDataFrame(enc, frame)
+ return encodeMaxStreamDataFrame(enc, frame)
case *logging.MaxStreamsFrame:
- marshalMaxStreamsFrame(enc, frame)
+ return encodeMaxStreamsFrame(enc, frame)
case *logging.DataBlockedFrame:
- marshalDataBlockedFrame(enc, frame)
+ return encodeDataBlockedFrame(enc, frame)
case *logging.StreamDataBlockedFrame:
- marshalStreamDataBlockedFrame(enc, frame)
+ return encodeStreamDataBlockedFrame(enc, frame)
case *logging.StreamsBlockedFrame:
- marshalStreamsBlockedFrame(enc, frame)
+ return encodeStreamsBlockedFrame(enc, frame)
case *logging.NewConnectionIDFrame:
- marshalNewConnectionIDFrame(enc, frame)
+ return encodeNewConnectionIDFrame(enc, frame)
case *logging.RetireConnectionIDFrame:
- marshalRetireConnectionIDFrame(enc, frame)
+ return encodeRetireConnectionIDFrame(enc, frame)
case *logging.PathChallengeFrame:
- marshalPathChallengeFrame(enc, frame)
+ return encodePathChallengeFrame(enc, frame)
case *logging.PathResponseFrame:
- marshalPathResponseFrame(enc, frame)
+ return encodePathResponseFrame(enc, frame)
case *logging.ConnectionCloseFrame:
- marshalConnectionCloseFrame(enc, frame)
+ return encodeConnectionCloseFrame(enc, frame)
case *logging.HandshakeDoneFrame:
- marshalHandshakeDoneFrame(enc, frame)
+ return encodeHandshakeDoneFrame(enc, frame)
case *logging.DatagramFrame:
- marshalDatagramFrame(enc, frame)
+ return encodeDatagramFrame(enc, frame)
case *logging.AckFrequencyFrame:
- marshalAckFrequencyFrame(enc, frame)
+ return encodeAckFrequencyFrame(enc, frame)
case *logging.ImmediateAckFrame:
- marshalImmediateAckFrame(enc, frame)
+ return encodeImmediateAckFrame(enc, frame)
default:
panic("unknown frame type")
}
}
-func (f frame) IsNil() bool { return false }
-
type frames []frame
-func (fs frames) IsNil() bool { return fs == nil }
-func (fs frames) MarshalJSONArray(enc *gojay.Encoder) {
+func (fs frames) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginArray)
for _, f := range fs {
- enc.Object(f)
+ if err := f.Encode(enc); err != nil {
+ return err
+ }
}
+ h.WriteToken(jsontext.EndArray)
+ return h.err
}
-func marshalPingFrame(enc *gojay.Encoder, _ *wire.PingFrame) {
- enc.StringKey("frame_type", "ping")
+func encodePingFrame(enc *jsontext.Encoder, _ *logging.PingFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("ping"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type ackRanges []wire.AckRange
-func (ars ackRanges) MarshalJSONArray(enc *gojay.Encoder) {
+func (ars ackRanges) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginArray)
for _, r := range ars {
- enc.Array(ackRange(r))
+ if err := ackRange(r).Encode(enc); err != nil {
+ return err
+ }
}
+ h.WriteToken(jsontext.EndArray)
+ return h.err
}
-func (ars ackRanges) IsNil() bool { return false }
-
type ackRange wire.AckRange
-func (ar ackRange) MarshalJSONArray(enc *gojay.Encoder) {
- enc.AddInt64(int64(ar.Smallest))
+func (ar ackRange) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginArray)
+ h.WriteToken(jsontext.Int(int64(ar.Smallest)))
if ar.Smallest != ar.Largest {
- enc.AddInt64(int64(ar.Largest))
+ h.WriteToken(jsontext.Int(int64(ar.Largest)))
}
+ h.WriteToken(jsontext.EndArray)
+ return h.err
}
-func (ar ackRange) IsNil() bool { return false }
-
-func marshalAckFrame(enc *gojay.Encoder, f *logging.AckFrame) {
- enc.StringKey("frame_type", "ack")
- enc.FloatKeyOmitEmpty("ack_delay", milliseconds(f.DelayTime))
- enc.ArrayKey("acked_ranges", ackRanges(f.AckRanges))
- if hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0; hasECN {
- enc.Uint64Key("ect0", f.ECT0)
- enc.Uint64Key("ect1", f.ECT1)
- enc.Uint64Key("ce", f.ECNCE)
+func encodeAckFrame(enc *jsontext.Encoder, f *logging.AckFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("ack"))
+ if f.DelayTime != 0 {
+ h.WriteToken(jsontext.String("ack_delay"))
+ h.WriteToken(jsontext.Float(milliseconds(f.DelayTime)))
+ }
+ h.WriteToken(jsontext.String("acked_ranges"))
+ if err := ackRanges(f.AckRanges).Encode(enc); err != nil {
+ return err
+ }
+ hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0
+ if hasECN {
+ h.WriteToken(jsontext.String("ect0"))
+ h.WriteToken(jsontext.Uint(f.ECT0))
+ h.WriteToken(jsontext.String("ect1"))
+ h.WriteToken(jsontext.Uint(f.ECT1))
+ h.WriteToken(jsontext.String("ce"))
+ h.WriteToken(jsontext.Uint(f.ECNCE))
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalResetStreamFrame(enc *gojay.Encoder, f *logging.ResetStreamFrame) {
+func encodeResetStreamFrame(enc *jsontext.Encoder, f *logging.ResetStreamFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
if f.ReliableSize > 0 {
- enc.StringKey("frame_type", "reset_stream_at")
+ h.WriteToken(jsontext.String("reset_stream_at"))
} else {
- enc.StringKey("frame_type", "reset_stream")
+ h.WriteToken(jsontext.String("reset_stream"))
}
- enc.Int64Key("stream_id", int64(f.StreamID))
- enc.Int64Key("error_code", int64(f.ErrorCode))
- enc.Int64Key("final_size", int64(f.FinalSize))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.Uint(uint64(f.ErrorCode)))
+ h.WriteToken(jsontext.String("final_size"))
+ h.WriteToken(jsontext.Uint(uint64(f.FinalSize)))
if f.ReliableSize > 0 {
- enc.Int64Key("reliable_size", int64(f.ReliableSize))
+ h.WriteToken(jsontext.String("reliable_size"))
+ h.WriteToken(jsontext.Uint(uint64(f.ReliableSize)))
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalStopSendingFrame(enc *gojay.Encoder, f *logging.StopSendingFrame) {
- enc.StringKey("frame_type", "stop_sending")
- enc.Int64Key("stream_id", int64(f.StreamID))
- enc.Int64Key("error_code", int64(f.ErrorCode))
+func encodeStopSendingFrame(enc *jsontext.Encoder, f *logging.StopSendingFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("stop_sending"))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.Uint(uint64(f.ErrorCode)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalCryptoFrame(enc *gojay.Encoder, f *logging.CryptoFrame) {
- enc.StringKey("frame_type", "crypto")
- enc.Int64Key("offset", int64(f.Offset))
- enc.Int64Key("length", int64(f.Length))
+func encodeCryptoFrame(enc *jsontext.Encoder, f *logging.CryptoFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("crypto"))
+ h.WriteToken(jsontext.String("offset"))
+ h.WriteToken(jsontext.Uint(uint64(f.Offset)))
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Uint(uint64(f.Length)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalNewTokenFrame(enc *gojay.Encoder, f *logging.NewTokenFrame) {
- enc.StringKey("frame_type", "new_token")
- enc.ObjectKey("token", &token{Raw: f.Token})
+func encodeNewTokenFrame(enc *jsontext.Encoder, f *logging.NewTokenFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("new_token"))
+ h.WriteToken(jsontext.String("token"))
+ if err := (token{Raw: f.Token}).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalStreamFrame(enc *gojay.Encoder, f *logging.StreamFrame) {
- enc.StringKey("frame_type", "stream")
- enc.Int64Key("stream_id", int64(f.StreamID))
- enc.Int64Key("offset", int64(f.Offset))
- enc.IntKey("length", int(f.Length))
- enc.BoolKeyOmitEmpty("fin", f.Fin)
+func encodeStreamFrame(enc *jsontext.Encoder, f *logging.StreamFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("stream"))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
+ h.WriteToken(jsontext.String("offset"))
+ h.WriteToken(jsontext.Uint(uint64(f.Offset)))
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Uint(uint64(f.Length)))
+ if f.Fin {
+ h.WriteToken(jsontext.String("fin"))
+ h.WriteToken(jsontext.True)
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalMaxDataFrame(enc *gojay.Encoder, f *logging.MaxDataFrame) {
- enc.StringKey("frame_type", "max_data")
- enc.Int64Key("maximum", int64(f.MaximumData))
+func encodeMaxDataFrame(enc *jsontext.Encoder, f *logging.MaxDataFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("max_data"))
+ h.WriteToken(jsontext.String("maximum"))
+ h.WriteToken(jsontext.Uint(uint64(f.MaximumData)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalMaxStreamDataFrame(enc *gojay.Encoder, f *logging.MaxStreamDataFrame) {
- enc.StringKey("frame_type", "max_stream_data")
- enc.Int64Key("stream_id", int64(f.StreamID))
- enc.Int64Key("maximum", int64(f.MaximumStreamData))
+func encodeMaxStreamDataFrame(enc *jsontext.Encoder, f *logging.MaxStreamDataFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("max_stream_data"))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
+ h.WriteToken(jsontext.String("maximum"))
+ h.WriteToken(jsontext.Uint(uint64(f.MaximumStreamData)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalMaxStreamsFrame(enc *gojay.Encoder, f *logging.MaxStreamsFrame) {
- enc.StringKey("frame_type", "max_streams")
- enc.StringKey("stream_type", streamType(f.Type).String())
- enc.Int64Key("maximum", int64(f.MaxStreamNum))
+func encodeMaxStreamsFrame(enc *jsontext.Encoder, f *logging.MaxStreamsFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("max_streams"))
+ h.WriteToken(jsontext.String("stream_type"))
+ h.WriteToken(jsontext.String(streamType(f.Type).String()))
+ h.WriteToken(jsontext.String("maximum"))
+ h.WriteToken(jsontext.Uint(uint64(f.MaxStreamNum)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalDataBlockedFrame(enc *gojay.Encoder, f *logging.DataBlockedFrame) {
- enc.StringKey("frame_type", "data_blocked")
- enc.Int64Key("limit", int64(f.MaximumData))
+func encodeDataBlockedFrame(enc *jsontext.Encoder, f *logging.DataBlockedFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("data_blocked"))
+ h.WriteToken(jsontext.String("limit"))
+ h.WriteToken(jsontext.Uint(uint64(f.MaximumData)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalStreamDataBlockedFrame(enc *gojay.Encoder, f *logging.StreamDataBlockedFrame) {
- enc.StringKey("frame_type", "stream_data_blocked")
- enc.Int64Key("stream_id", int64(f.StreamID))
- enc.Int64Key("limit", int64(f.MaximumStreamData))
+func encodeStreamDataBlockedFrame(enc *jsontext.Encoder, f *logging.StreamDataBlockedFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("stream_data_blocked"))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
+ h.WriteToken(jsontext.String("limit"))
+ h.WriteToken(jsontext.Uint(uint64(f.MaximumStreamData)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalStreamsBlockedFrame(enc *gojay.Encoder, f *logging.StreamsBlockedFrame) {
- enc.StringKey("frame_type", "streams_blocked")
- enc.StringKey("stream_type", streamType(f.Type).String())
- enc.Int64Key("limit", int64(f.StreamLimit))
+func encodeStreamsBlockedFrame(enc *jsontext.Encoder, f *logging.StreamsBlockedFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("streams_blocked"))
+ h.WriteToken(jsontext.String("stream_type"))
+ h.WriteToken(jsontext.String(streamType(f.Type).String()))
+ h.WriteToken(jsontext.String("limit"))
+ h.WriteToken(jsontext.Uint(uint64(f.StreamLimit)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalNewConnectionIDFrame(enc *gojay.Encoder, f *logging.NewConnectionIDFrame) {
- enc.StringKey("frame_type", "new_connection_id")
- enc.Int64Key("sequence_number", int64(f.SequenceNumber))
- enc.Int64Key("retire_prior_to", int64(f.RetirePriorTo))
- enc.IntKey("length", f.ConnectionID.Len())
- enc.StringKey("connection_id", f.ConnectionID.String())
- enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", f.StatelessResetToken))
+func encodeNewConnectionIDFrame(enc *jsontext.Encoder, f *logging.NewConnectionIDFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("new_connection_id"))
+ h.WriteToken(jsontext.String("sequence_number"))
+ h.WriteToken(jsontext.Uint(f.SequenceNumber))
+ h.WriteToken(jsontext.String("retire_prior_to"))
+ h.WriteToken(jsontext.Uint(f.RetirePriorTo))
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Int(int64(f.ConnectionID.Len())))
+ h.WriteToken(jsontext.String("connection_id"))
+ h.WriteToken(jsontext.String(f.ConnectionID.String()))
+ h.WriteToken(jsontext.String("stateless_reset_token"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", f.StatelessResetToken)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalRetireConnectionIDFrame(enc *gojay.Encoder, f *logging.RetireConnectionIDFrame) {
- enc.StringKey("frame_type", "retire_connection_id")
- enc.Int64Key("sequence_number", int64(f.SequenceNumber))
+func encodeRetireConnectionIDFrame(enc *jsontext.Encoder, f *logging.RetireConnectionIDFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("retire_connection_id"))
+ h.WriteToken(jsontext.String("sequence_number"))
+ h.WriteToken(jsontext.Uint(f.SequenceNumber))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalPathChallengeFrame(enc *gojay.Encoder, f *logging.PathChallengeFrame) {
- enc.StringKey("frame_type", "path_challenge")
- enc.StringKey("data", fmt.Sprintf("%x", f.Data[:]))
+func encodePathChallengeFrame(enc *jsontext.Encoder, f *logging.PathChallengeFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("path_challenge"))
+ h.WriteToken(jsontext.String("data"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", f.Data[:])))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalPathResponseFrame(enc *gojay.Encoder, f *logging.PathResponseFrame) {
- enc.StringKey("frame_type", "path_response")
- enc.StringKey("data", fmt.Sprintf("%x", f.Data[:]))
+func encodePathResponseFrame(enc *jsontext.Encoder, f *logging.PathResponseFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("path_response"))
+ h.WriteToken(jsontext.String("data"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", f.Data[:])))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalConnectionCloseFrame(enc *gojay.Encoder, f *logging.ConnectionCloseFrame) {
+func encodeConnectionCloseFrame(enc *jsontext.Encoder, f *logging.ConnectionCloseFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("connection_close"))
+ h.WriteToken(jsontext.String("error_space"))
errorSpace := "transport"
if f.IsApplicationError {
errorSpace = "application"
}
- enc.StringKey("frame_type", "connection_close")
- enc.StringKey("error_space", errorSpace)
- if errName := transportError(f.ErrorCode).String(); len(errName) > 0 {
- enc.StringKey("error_code", errName)
+ h.WriteToken(jsontext.String(errorSpace))
+ errName := transportError(f.ErrorCode).String()
+ if len(errName) > 0 {
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.String(errName))
} else {
- enc.Uint64Key("error_code", f.ErrorCode)
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.Uint(f.ErrorCode))
}
- enc.Uint64Key("raw_error_code", f.ErrorCode)
- enc.StringKey("reason", f.ReasonPhrase)
+ h.WriteToken(jsontext.String("raw_error_code"))
+ h.WriteToken(jsontext.Uint(f.ErrorCode))
+ h.WriteToken(jsontext.String("reason"))
+ h.WriteToken(jsontext.String(f.ReasonPhrase))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalHandshakeDoneFrame(enc *gojay.Encoder, _ *logging.HandshakeDoneFrame) {
- enc.StringKey("frame_type", "handshake_done")
+func encodeHandshakeDoneFrame(enc *jsontext.Encoder, _ *logging.HandshakeDoneFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("handshake_done"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalDatagramFrame(enc *gojay.Encoder, f *logging.DatagramFrame) {
- enc.StringKey("frame_type", "datagram")
- enc.Int64Key("length", int64(f.Length))
+func encodeDatagramFrame(enc *jsontext.Encoder, f *logging.DatagramFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("datagram"))
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Uint(uint64(f.Length)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalAckFrequencyFrame(enc *gojay.Encoder, f *logging.AckFrequencyFrame) {
- enc.StringKey("frame_type", "ack_frequency")
- enc.Uint64Key("sequence_number", f.SequenceNumber)
- enc.Uint64Key("ack_eliciting_threshold", f.AckElicitingThreshold)
- enc.Float64Key("request_max_ack_delay", milliseconds(f.RequestMaxAckDelay))
- enc.Uint64Key("reordering_threshold", uint64(f.ReorderingThreshold))
+func encodeAckFrequencyFrame(enc *jsontext.Encoder, f *logging.AckFrequencyFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("ack_frequency"))
+ h.WriteToken(jsontext.String("sequence_number"))
+ h.WriteToken(jsontext.Uint(f.SequenceNumber))
+ h.WriteToken(jsontext.String("ack_eliciting_threshold"))
+ h.WriteToken(jsontext.Uint(f.AckElicitingThreshold))
+ h.WriteToken(jsontext.String("request_max_ack_delay"))
+ h.WriteToken(jsontext.Float(milliseconds(f.RequestMaxAckDelay)))
+ h.WriteToken(jsontext.String("reordering_threshold"))
+ h.WriteToken(jsontext.Uint(uint64(f.ReorderingThreshold)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func marshalImmediateAckFrame(enc *gojay.Encoder, _ *logging.ImmediateAckFrame) {
- enc.StringKey("frame_type", "immediate_ack")
+func encodeImmediateAckFrame(enc *jsontext.Encoder, _ *logging.ImmediateAckFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("immediate_ack"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
"testing"
"time"
- "github.com/francoispqt/gojay"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/logging"
+
+ "github.com/quic-go/quic-go/qlog/jsontext"
+
"github.com/stretchr/testify/require"
)
func check(t *testing.T, f logging.Frame, expected map[string]any) {
buf := &bytes.Buffer{}
- enc := gojay.NewEncoder(buf)
- err := enc.Encode(frame{Frame: f})
+ enc := jsontext.NewEncoder(buf)
+ err := (frame{Frame: f}).Encode(enc)
require.NoError(t, err)
data := buf.Bytes()
require.True(t, json.Valid(data))
}
func checkEncoding(t *testing.T, data []byte, expected map[string]any) {
+ t.Helper()
+
m := make(map[string]any)
require.NoError(t, json.Unmarshal(data, &m))
require.Len(t, m, len(expected))
}
func exportAndParse(t *testing.T, buf *bytes.Buffer) []entry {
+ t.Helper()
+
m := make(map[string]any)
line, err := buf.ReadBytes('\n')
require.NoError(t, err)
}
func exportAndParseSingle(t *testing.T, buf *bytes.Buffer) entry {
+ t.Helper()
+
entries := exportAndParse(t, buf)
require.Len(t, entries, 1)
return entries[0]
--- /dev/null
+// Package jsontext provides a fast JSON encoder providing only the necessary features
+// for qlog encoding. No efforts are made to add any features beyond qlog's requirements.
+//
+// The API aims to be compatible with the standard library's encoding/json/jsontext package.
+package jsontext
+
+import (
+ "fmt"
+ "io"
+ "strconv"
+ "unsafe"
+)
+
+type kind uint8
+
+const (
+ kindString kind = iota
+ kindInt
+ kindUint
+ kindFloat
+ kindBool
+ kindObjectStart
+ kindObjectEnd
+ kindArrayStart
+ kindArrayEnd
+)
+
+// Token represents a JSON token.
+type Token struct {
+ kind kind
+ str string
+ i64 int64
+ u64 uint64
+ f64 float64
+ b bool
+}
+
+// String creates a string token.
+func String(s string) Token {
+ return Token{kind: kindString, str: s}
+}
+
+// Int creates an int token.
+func Int(i int64) Token {
+ return Token{kind: kindInt, i64: i}
+}
+
+// Uint creates a uint token.
+func Uint(u uint64) Token {
+ return Token{kind: kindUint, u64: u}
+}
+
+// Float creates a float token.
+func Float(f float64) Token {
+ return Token{kind: kindFloat, f64: f}
+}
+
+// Bool creates a bool token.
+func Bool(b bool) Token {
+ return Token{kind: kindBool, b: b}
+}
+
+// BeginObject is the begin object token.
+var BeginObject Token = Token{kind: kindObjectStart}
+
+// EndObject is the end object token.
+var EndObject Token = Token{kind: kindObjectEnd}
+
+// BeginArray is the begin array token.
+var BeginArray Token = Token{kind: kindArrayStart}
+
+// EndArray is the end array token.
+var EndArray Token = Token{kind: kindArrayEnd}
+
+// True is a true token.
+var True Token = Bool(true)
+
+// False is a false token.
+var False Token = Bool(false)
+
+var hexDigits = [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}
+
+var (
+ commaByte = []byte(",")
+ quoteByte = []byte(`"`)
+ colonByte = []byte(":")
+ trueByte = []byte("true")
+ falseByte = []byte("false")
+ openObjectByte = []byte("{")
+ closeObjectByte = []byte("}")
+ openArrayByte = []byte("[")
+ closeArrayByte = []byte("]")
+ newlineByte = []byte("\n")
+ escapeQuote = []byte(`\"`)
+ escapeBackslash = []byte(`\\`)
+ escapeBackspace = []byte(`\b`)
+ escapeFormfeed = []byte(`\f`)
+ escapeNewline = []byte(`\n`)
+ escapeCarriage = []byte(`\r`)
+ escapeTab = []byte(`\t`)
+ escapeUnicode = []byte(`\u00`)
+)
+
+type context struct {
+ isObject bool
+ needsComma bool
+ expectKey bool
+}
+
+// Encoder encodes JSON to an io.Writer.
+type Encoder struct {
+ w io.Writer
+ buf [64]byte // scratch buffer for number formatting
+ stack []context
+}
+
+// NewEncoder creates a new Encoder.
+func NewEncoder(w io.Writer) *Encoder {
+ stack := make([]context, 0, 8)
+ stack = append(stack, context{isObject: false, needsComma: false, expectKey: false})
+ return &Encoder{
+ w: w,
+ stack: stack,
+ }
+}
+
+// WriteToken writes a token to the encoder.
+func (e *Encoder) WriteToken(t Token) error {
+ if len(e.stack) == 0 {
+ return fmt.Errorf("empty stack")
+ }
+ curr := &e.stack[len(e.stack)-1]
+ isClosing := t.kind == kindObjectEnd || t.kind == kindArrayEnd
+ if !isClosing && curr.needsComma {
+ if _, err := e.w.Write(commaByte); err != nil {
+ return err
+ }
+ curr.needsComma = false
+ }
+ var err error
+ switch t.kind {
+ case kindString:
+ data := stringToBytes(t.str)
+ needsEscape := false
+ for _, b := range data {
+ if b == '"' || b == '\\' || b < 0x20 {
+ needsEscape = true
+ break
+ }
+ }
+ if !needsEscape {
+ if _, err = e.w.Write(quoteByte); err != nil {
+ return err
+ }
+ if _, err = e.w.Write(data); err != nil {
+ return err
+ }
+ if _, err = e.w.Write(quoteByte); err != nil {
+ return err
+ }
+ } else {
+ if _, err = e.w.Write(quoteByte); err != nil {
+ return err
+ }
+ for i := 0; i < len(t.str); i++ {
+ c := t.str[i]
+ switch c {
+ case '"':
+ if _, err = e.w.Write(escapeQuote); err != nil {
+ return err
+ }
+ case '\\':
+ if _, err = e.w.Write(escapeBackslash); err != nil {
+ return err
+ }
+ case '\b':
+ if _, err = e.w.Write(escapeBackspace); err != nil {
+ return err
+ }
+ case '\f':
+ if _, err = e.w.Write(escapeFormfeed); err != nil {
+ return err
+ }
+ case '\n':
+ if _, err = e.w.Write(escapeNewline); err != nil {
+ return err
+ }
+ case '\r':
+ if _, err = e.w.Write(escapeCarriage); err != nil {
+ return err
+ }
+ case '\t':
+ if _, err = e.w.Write(escapeTab); err != nil {
+ return err
+ }
+ default:
+ if c < 0x20 {
+ if _, err = e.w.Write(escapeUnicode); err != nil {
+ return err
+ }
+ if _, err = e.w.Write([]byte{hexDigits[c>>4], hexDigits[c&0xf]}); err != nil {
+ return err
+ }
+ } else {
+ if _, err = e.w.Write([]byte{c}); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ if _, err = e.w.Write(quoteByte); err != nil {
+ return err
+ }
+ }
+ if curr.isObject {
+ if curr.expectKey {
+ // key
+ if _, err = e.w.Write(colonByte); err != nil {
+ return err
+ }
+ curr.expectKey = false
+ return nil // do not call afterValue for keys
+ } else {
+ // value
+ e.afterValue()
+ }
+ } else {
+ e.afterValue()
+ }
+ case kindInt:
+ b := strconv.AppendInt(e.buf[:0], t.i64, 10)
+ if _, err = e.w.Write(b); err != nil {
+ return err
+ }
+ e.afterValue()
+ case kindUint:
+ b := strconv.AppendUint(e.buf[:0], t.u64, 10)
+ if _, err = e.w.Write(b); err != nil {
+ return err
+ }
+ e.afterValue()
+ case kindFloat:
+ b := strconv.AppendFloat(e.buf[:0], t.f64, 'g', -1, 64)
+ if _, err = e.w.Write(b); err != nil {
+ return err
+ }
+ e.afterValue()
+ case kindBool:
+ if t.b {
+ if _, err = e.w.Write(trueByte); err != nil {
+ return err
+ }
+ } else {
+ if _, err = e.w.Write(falseByte); err != nil {
+ return err
+ }
+ }
+ e.afterValue()
+ case kindObjectStart:
+ if _, err = e.w.Write(openObjectByte); err != nil {
+ return err
+ }
+ e.stack = append(e.stack, context{isObject: true, needsComma: false, expectKey: true})
+ return nil
+ case kindObjectEnd:
+ if _, err = e.w.Write(closeObjectByte); err != nil {
+ return err
+ }
+ e.stack = e.stack[:len(e.stack)-1]
+ e.afterValue()
+ if len(e.stack) == 1 {
+ if _, err = e.w.Write(newlineByte); err != nil {
+ return err
+ }
+ }
+ return nil
+ case kindArrayStart:
+ if _, err = e.w.Write(openArrayByte); err != nil {
+ return err
+ }
+ e.stack = append(e.stack, context{isObject: false, needsComma: false, expectKey: false})
+ return nil
+ case kindArrayEnd:
+ if _, err = e.w.Write(closeArrayByte); err != nil {
+ return err
+ }
+ e.stack = e.stack[:len(e.stack)-1]
+ e.afterValue()
+ if len(e.stack) == 1 {
+ if _, err = e.w.Write(newlineByte); err != nil {
+ return err
+ }
+ }
+ return nil
+ default:
+ return fmt.Errorf("unknown token kind")
+ }
+ return err
+}
+
+// afterValue updates the state after encoding a value
+func (e *Encoder) afterValue() {
+ if len(e.stack) > 1 {
+ curr := &e.stack[len(e.stack)-1]
+ curr.needsComma = true
+ if curr.isObject {
+ curr.expectKey = true
+ }
+ }
+}
+
+func stringToBytes(s string) []byte {
+ return unsafe.Slice(unsafe.StringData(s), len(s))
+}
--- /dev/null
+package jsontext_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "testing"
+
+ "github.com/quic-go/quic-go/qlog/jsontext"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestEncoderSimpleObject(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ enc.WriteToken(jsontext.BeginObject)
+ enc.WriteToken(jsontext.String("foo"))
+ enc.WriteToken(jsontext.String("bar"))
+ enc.WriteToken(jsontext.String("foo2"))
+ enc.WriteToken(jsontext.String("bar2"))
+ enc.WriteToken(jsontext.EndObject)
+ output := buf.String()
+
+ var got map[string]string
+ require.NoError(t, json.Unmarshal([]byte(output), &got))
+ require.Equal(t, map[string]string{"foo": "bar", "foo2": "bar2"}, got)
+}
+
+func TestEncoderArrayInts(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ enc.WriteToken(jsontext.BeginArray)
+ enc.WriteToken(jsontext.Int(1))
+ enc.WriteToken(jsontext.Int(2))
+ enc.WriteToken(jsontext.Int(3))
+ enc.WriteToken(jsontext.EndArray)
+ output := buf.String()
+
+ var got []int
+ require.NoError(t, json.Unmarshal([]byte(output), &got))
+ require.Equal(t, []int{1, 2, 3}, got)
+}
+
+func TestEncoderArrayStrings(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ enc.WriteToken(jsontext.BeginArray)
+ enc.WriteToken(jsontext.String("one"))
+ enc.WriteToken(jsontext.String("two"))
+ enc.WriteToken(jsontext.EndArray)
+ output := buf.String()
+
+ var got []string
+ err := json.Unmarshal([]byte(output), &got)
+ require.NoError(t, err)
+ require.Equal(t, []string{"one", "two"}, got)
+}
+
+func TestEncoderNestedObject(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ enc.WriteToken(jsontext.BeginObject)
+ enc.WriteToken(jsontext.String("outer"))
+ enc.WriteToken(jsontext.BeginObject)
+ enc.WriteToken(jsontext.String("inner"))
+ enc.WriteToken(jsontext.String("value"))
+ enc.WriteToken(jsontext.EndObject)
+ enc.WriteToken(jsontext.EndObject)
+ output := buf.String()
+
+ var got map[string]map[string]string
+ require.NoError(t, json.Unmarshal([]byte(output), &got))
+ require.Equal(t, map[string]map[string]string{"outer": {"inner": "value"}}, got)
+}
+
+func TestEncoderNumbersAndBool(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ enc.WriteToken(jsontext.BeginObject)
+ enc.WriteToken(jsontext.String("int"))
+ enc.WriteToken(jsontext.Int(42))
+ enc.WriteToken(jsontext.String("uint"))
+ enc.WriteToken(jsontext.Uint(100))
+ enc.WriteToken(jsontext.String("float"))
+ enc.WriteToken(jsontext.Float(3.14))
+ enc.WriteToken(jsontext.String("true"))
+ enc.WriteToken(jsontext.True)
+ enc.WriteToken(jsontext.String("false"))
+ enc.WriteToken(jsontext.False)
+ enc.WriteToken(jsontext.EndObject)
+ output := buf.String()
+
+ var got map[string]any
+ require.NoError(t, json.Unmarshal([]byte(output), &got))
+ require.Equal(t, map[string]any{
+ "int": float64(42), // json.Unmarshal decodes numbers as float64
+ "uint": float64(100),
+ "float": 3.14,
+ "true": true,
+ "false": false,
+ }, got)
+}
+
+func TestEncoderEmptyObject(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ enc.WriteToken(jsontext.BeginObject)
+ enc.WriteToken(jsontext.EndObject)
+ output := buf.String()
+
+ var got map[string]any
+ require.NoError(t, json.Unmarshal([]byte(output), &got))
+ require.Equal(t, map[string]any{}, got)
+}
+
+func TestEncoderEmptyArray(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ enc.WriteToken(jsontext.BeginArray)
+ enc.WriteToken(jsontext.EndArray)
+ output := buf.String()
+
+ var got []any
+ require.NoError(t, json.Unmarshal([]byte(output), &got))
+ require.Equal(t, []any{}, got)
+}
+
+func TestEncoderEscapedStrings(t *testing.T) {
+ t.Run("no escapes", func(t *testing.T) {
+ testEncoderEscapedStrings(t, "simplekey", "simplevalue")
+ })
+
+ t.Run("basic escapes", func(t *testing.T) {
+ key := `key"\/`
+ value := `value"\/`
+ testEncoderEscapedStrings(t, key, value)
+ })
+
+ t.Run("control characters", func(t *testing.T) {
+ key := "key\b\f\n\r\t"
+ value := "value\b\f\n\r\t"
+ testEncoderEscapedStrings(t, key, value)
+ })
+
+ t.Run("unicode low", func(t *testing.T) {
+ key := "key\u0007\u001f"
+ value := "value\u0007\u001f"
+ testEncoderEscapedStrings(t, key, value)
+ })
+
+ t.Run("mixed all", func(t *testing.T) {
+ key := `key"\\\/\b\f\n\r\t\u0007\u001f`
+ value := `value"\\\/\b\f\n\r\t\u0007\u001f`
+ testEncoderEscapedStrings(t, key, value)
+ })
+}
+
+func testEncoderEscapedStrings(t *testing.T, key, value string) {
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ enc.WriteToken(jsontext.BeginObject)
+ enc.WriteToken(jsontext.String(key))
+ enc.WriteToken(jsontext.String(value))
+ enc.WriteToken(jsontext.EndObject)
+ output := buf.String()
+
+ var got map[string]string
+ err := json.Unmarshal([]byte(output), &got)
+ require.NoError(t, err)
+ expected := map[string]string{key: value}
+ require.Equal(t, expected, got)
+}
+
+func encodeValue(t testing.TB, enc *jsontext.Encoder, v any) (isSupported bool) {
+ t.Helper()
+
+ switch val := v.(type) {
+ case map[string]any:
+ require.NoError(t, enc.WriteToken(jsontext.BeginObject))
+ for k, vv := range val {
+ require.NoError(t, enc.WriteToken(jsontext.String(k)))
+ if !encodeValue(t, enc, vv) {
+ return false
+ }
+ }
+ require.NoError(t, enc.WriteToken(jsontext.EndObject))
+ return true
+ case []any:
+ require.NoError(t, enc.WriteToken(jsontext.BeginArray))
+ for _, vv := range val {
+ if !encodeValue(t, enc, vv) {
+ return false // Propagate unsupported if any nested value fails
+ }
+ }
+ require.NoError(t, enc.WriteToken(jsontext.EndArray))
+ return true
+ case string:
+ require.NoError(t, enc.WriteToken(jsontext.String(val)))
+ return true
+ case int64:
+ require.NoError(t, enc.WriteToken(jsontext.Int(val)))
+ return true
+ case uint64:
+ require.NoError(t, enc.WriteToken(jsontext.Uint(val)))
+ return true
+ case float64:
+ require.NoError(t, enc.WriteToken(jsontext.Float(val)))
+ return true
+ case bool:
+ require.NoError(t, enc.WriteToken(jsontext.Bool(val)))
+ return true
+ default:
+ return false
+ }
+}
+
+type errorWriter struct {
+ N int
+}
+
+func (w *errorWriter) Write(p []byte) (int, error) {
+ n := min(len(p), w.N)
+ w.N -= n
+ if w.N <= 0 {
+ return n, assert.AnError
+ }
+ return n, nil
+}
+
+func TestEncoderComprehensive(t *testing.T) {
+ // encodes an object with all token types and nested structures
+ encode := func(enc *jsontext.Encoder) error {
+ if err := enc.WriteToken(jsontext.BeginObject); err != nil {
+ return err
+ }
+
+ if err := enc.WriteToken(jsontext.String("simple")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String("value")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String("escaped")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String(`"quoted\"string"`)); err != nil {
+ return err
+ }
+
+ if err := enc.WriteToken(jsontext.String("int")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.Int(-42)); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String("uint")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.Uint(100)); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String("float")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.Float(3.14)); err != nil {
+ return err
+ }
+
+ if err := enc.WriteToken(jsontext.String("true")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.True); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String("false")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.False); err != nil {
+ return err
+ }
+
+ if err := enc.WriteToken(jsontext.String("array")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.BeginArray); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.String("item1")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.Int(1)); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.EndArray); err != nil {
+ return err
+ }
+
+ if err := enc.WriteToken(jsontext.String("nested")); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.BeginObject); err != nil {
+ return err
+ }
+ if err := enc.WriteToken(jsontext.EndObject); err != nil {
+ return err
+ }
+
+ if err := enc.WriteToken(jsontext.EndObject); err != nil {
+ return err
+ }
+ return nil
+ }
+
+ buf := bytes.NewBuffer(nil)
+ enc := jsontext.NewEncoder(buf)
+ require.NoError(t, encode(enc))
+
+ for i := range buf.Len() {
+ enc := jsontext.NewEncoder(&errorWriter{N: i})
+ require.ErrorIs(t, encode(enc), assert.AnError)
+ }
+}
+
+func FuzzEncoder(f *testing.F) {
+ examples := []string{
+ `{"hello": "world"}`,
+ `{"foo": 123, "bar": [1, 2, 3]}`,
+ `{"nested": {"a": 1, "b": [true, false, "foobar"]}}`,
+ `[{"x": 1}, {"y": "foo"}]`,
+ `["foo", "bar"]`,
+ `["a", {"b": [1, 2, {"c": "d"}]}, 3]`,
+ `{"emptyObj": {}, "emptyArr": []}`,
+ `{"mixed": [1, "two", {"three": 3}]}`,
+ }
+ for _, tc := range examples {
+ // first test that
+ // 1. it's valid JSON
+ d := json.NewDecoder(bytes.NewReader([]byte(tc)))
+ var expected any
+ require.NoError(f, d.Decode(&expected), "corpus entry `%s` is not valid JSON", tc)
+ // 2. the jsontext encoder can handle
+ enc := jsontext.NewEncoder(&bytes.Buffer{})
+ require.True(f, encodeValue(f, enc, expected), "expected `%s` to be supported", tc)
+
+ f.Add([]byte(tc))
+ }
+
+ var stdlibBuf, ourBuf bytes.Buffer
+
+ f.Fuzz(func(t *testing.T, b []byte) {
+ stdlibBuf.Truncate(0)
+ ourBuf.Truncate(0)
+ stdlibBuf.Grow(len(b))
+ ourBuf.Grow(len(b))
+
+ d := json.NewDecoder(bytes.NewReader(b))
+ var expected any
+ if err := d.Decode(&expected); err != nil {
+ return // invalid JSON
+ }
+
+ // only attempt to handle inputs that the standard library can handle
+ stdlibEnc := json.NewEncoder(&stdlibBuf)
+ require.NoError(t, stdlibEnc.Encode(expected))
+ if !json.Valid(stdlibBuf.Bytes()) {
+ return
+ }
+
+ // then encode using the jsontext encoder
+ enc := jsontext.NewEncoder(&ourBuf)
+ if isSupported := encodeValue(t, enc, expected); !isSupported {
+ return
+ }
+
+ output := ourBuf.Bytes()
+ require.Truef(t, json.Valid(output), "produced invalid JSON: %s", output)
+
+ var got any
+ require.NoError(t, json.Unmarshal(output, &got))
+ require.JSONEq(t, ourBuf.String(), stdlibBuf.String())
+ })
+}
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/logging"
-
- "github.com/francoispqt/gojay"
+ "github.com/quic-go/quic-go/qlog/jsontext"
)
func getPacketTypeFromEncryptionLevel(encLevel protocol.EncryptionLevel) logging.PacketType {
Raw []byte
}
-var _ gojay.MarshalerJSONObject = &token{}
-
-func (t token) IsNil() bool { return false }
-func (t token) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("data", fmt.Sprintf("%x", t.Raw))
+func (t token) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("data"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", t.Raw)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
// PacketHeader is a QUIC packet header.
// TODO: make this a long header
type packetHeader struct {
- PacketType logging.PacketType
-
- KeyPhaseBit logging.KeyPhaseBit
- PacketNumber logging.PacketNumber
-
+ PacketType logging.PacketType
+ KeyPhaseBit logging.KeyPhaseBit
+ PacketNumber logging.PacketNumber
Version logging.Version
SrcConnectionID logging.ConnectionID
DestConnectionID logging.ConnectionID
-
- Token *token
+ Token *token
}
func transformHeader(hdr *logging.Header) *packetHeader {
- h := &packetHeader{
+ ph := &packetHeader{
PacketType: logging.PacketTypeFromHeader(hdr),
SrcConnectionID: hdr.SrcConnectionID,
DestConnectionID: hdr.DestConnectionID,
Version: hdr.Version,
}
if len(hdr.Token) > 0 {
- h.Token = &token{Raw: hdr.Token}
+ ph.Token = &token{Raw: hdr.Token}
}
- return h
+ return ph
}
func transformLongHeader(hdr *logging.ExtendedHeader) *packetHeader {
- h := transformHeader(&hdr.Header)
- h.PacketNumber = hdr.PacketNumber
- h.KeyPhaseBit = hdr.KeyPhase
- return h
-}
-
-func (h packetHeader) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("packet_type", packetType(h.PacketType).String())
- if h.PacketType != logging.PacketTypeRetry {
- enc.Int64Key("packet_number", int64(h.PacketNumber))
+ ph := transformHeader(&hdr.Header)
+ ph.PacketNumber = hdr.PacketNumber
+ ph.KeyPhaseBit = hdr.KeyPhase
+ return ph
+}
+
+func (ph packetHeader) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("packet_type"))
+ h.WriteToken(jsontext.String(packetType(ph.PacketType).String()))
+ if ph.PacketType != logging.PacketTypeRetry {
+ h.WriteToken(jsontext.String("packet_number"))
+ h.WriteToken(jsontext.Int(int64(ph.PacketNumber)))
}
- if h.Version != 0 {
- enc.StringKey("version", version(h.Version).String())
+ if ph.Version != 0 {
+ h.WriteToken(jsontext.String("version"))
+ h.WriteToken(jsontext.String(version(ph.Version).String()))
}
- if h.PacketType != logging.PacketType1RTT {
- enc.IntKey("scil", h.SrcConnectionID.Len())
- if h.SrcConnectionID.Len() > 0 {
- enc.StringKey("scid", h.SrcConnectionID.String())
+ if ph.PacketType != logging.PacketType1RTT {
+ h.WriteToken(jsontext.String("scil"))
+ h.WriteToken(jsontext.Int(int64(ph.SrcConnectionID.Len())))
+ if ph.SrcConnectionID.Len() > 0 {
+ h.WriteToken(jsontext.String("scid"))
+ h.WriteToken(jsontext.String(ph.SrcConnectionID.String()))
}
}
- enc.IntKey("dcil", h.DestConnectionID.Len())
- if h.DestConnectionID.Len() > 0 {
- enc.StringKey("dcid", h.DestConnectionID.String())
+ h.WriteToken(jsontext.String("dcil"))
+ h.WriteToken(jsontext.Int(int64(ph.DestConnectionID.Len())))
+ if ph.DestConnectionID.Len() > 0 {
+ h.WriteToken(jsontext.String("dcid"))
+ h.WriteToken(jsontext.String(ph.DestConnectionID.String()))
}
- if h.KeyPhaseBit == logging.KeyPhaseZero || h.KeyPhaseBit == logging.KeyPhaseOne {
- enc.StringKey("key_phase_bit", h.KeyPhaseBit.String())
+ if ph.KeyPhaseBit == logging.KeyPhaseZero || ph.KeyPhaseBit == logging.KeyPhaseOne {
+ h.WriteToken(jsontext.String("key_phase_bit"))
+ h.WriteToken(jsontext.String(ph.KeyPhaseBit.String()))
}
- if h.Token != nil {
- enc.ObjectKey("token", h.Token)
+ if ph.Token != nil {
+ h.WriteToken(jsontext.String("token"))
+ if err := ph.Token.Encode(enc); err != nil {
+ return err
+ }
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type packetHeaderVersionNegotiation struct {
DestConnectionID logging.ArbitraryLenConnectionID
}
-func (h packetHeaderVersionNegotiation) IsNil() bool { return false }
-func (h packetHeaderVersionNegotiation) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("packet_type", "version_negotiation")
- enc.IntKey("scil", h.SrcConnectionID.Len())
- enc.StringKey("scid", h.SrcConnectionID.String())
- enc.IntKey("dcil", h.DestConnectionID.Len())
- enc.StringKey("dcid", h.DestConnectionID.String())
+func (phvn packetHeaderVersionNegotiation) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("packet_type"))
+ h.WriteToken(jsontext.String("version_negotiation"))
+ h.WriteToken(jsontext.String("scil"))
+ h.WriteToken(jsontext.Int(int64(phvn.SrcConnectionID.Len())))
+ h.WriteToken(jsontext.String("scid"))
+ h.WriteToken(jsontext.String(phvn.SrcConnectionID.String()))
+ h.WriteToken(jsontext.String("dcil"))
+ h.WriteToken(jsontext.Int(int64(phvn.DestConnectionID.Len())))
+ h.WriteToken(jsontext.String("dcid"))
+ h.WriteToken(jsontext.String(phvn.DestConnectionID.String()))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
// a minimal header that only outputs the packet type, and potentially a packet number
PacketNumber logging.PacketNumber
}
-func (h packetHeaderWithType) IsNil() bool { return false }
-func (h packetHeaderWithType) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("packet_type", packetType(h.PacketType).String())
- if h.PacketNumber != protocol.InvalidPacketNumber {
- enc.Int64Key("packet_number", int64(h.PacketNumber))
+func (phwt packetHeaderWithType) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("packet_type"))
+ h.WriteToken(jsontext.String(packetType(phwt.PacketType).String()))
+ if phwt.PacketNumber != protocol.InvalidPacketNumber {
+ h.WriteToken(jsontext.String("packet_number"))
+ h.WriteToken(jsontext.Int(int64(phwt.PacketNumber)))
}
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
// a minimal header that only outputs the packet type
PacketNumber logging.PacketNumber
}
-func (h packetHeaderWithTypeAndPacketNumber) IsNil() bool { return false }
-func (h packetHeaderWithTypeAndPacketNumber) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("packet_type", packetType(h.PacketType).String())
- enc.Int64Key("packet_number", int64(h.PacketNumber))
+func (phwtpn packetHeaderWithTypeAndPacketNumber) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("packet_type"))
+ h.WriteToken(jsontext.String(packetType(phwtpn.PacketType).String()))
+ h.WriteToken(jsontext.String("packet_number"))
+ h.WriteToken(jsontext.Int(int64(phwtpn.PacketNumber)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type shortHeader struct {
}
}
-func (h shortHeader) IsNil() bool { return false }
-func (h shortHeader) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("packet_type", packetType(logging.PacketType1RTT).String())
- if h.DestConnectionID.Len() > 0 {
- enc.StringKey("dcid", h.DestConnectionID.String())
+func (sh shortHeader) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("packet_type"))
+ h.WriteToken(jsontext.String(packetType(logging.PacketType1RTT).String()))
+ if sh.DestConnectionID.Len() > 0 {
+ h.WriteToken(jsontext.String("dcid"))
+ h.WriteToken(jsontext.String(sh.DestConnectionID.String()))
}
- enc.Int64Key("packet_number", int64(h.PacketNumber))
- enc.StringKey("key_phase_bit", h.KeyPhaseBit.String())
+ h.WriteToken(jsontext.String("packet_number"))
+ h.WriteToken(jsontext.Int(int64(sh.PacketNumber)))
+ h.WriteToken(jsontext.String("key_phase_bit"))
+ h.WriteToken(jsontext.String(sh.KeyPhaseBit.String()))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
"encoding/json"
"testing"
- "github.com/francoispqt/gojay"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/wire"
"github.com/quic-go/quic-go/logging"
+
+ "github.com/quic-go/quic-go/qlog/jsontext"
+
"github.com/stretchr/testify/require"
)
func checkHeader(t *testing.T, hdr *wire.ExtendedHeader, expected map[string]any) {
buf := &bytes.Buffer{}
- enc := gojay.NewEncoder(buf)
- require.NoError(t, enc.Encode(transformLongHeader(hdr)))
+ enc := jsontext.NewEncoder(buf)
+ require.NoError(t, transformLongHeader(hdr).Encode(enc))
data := buf.Bytes()
require.True(t, json.Valid(data))
checkEncoding(t, data, expected)
"time"
"github.com/quic-go/quic-go/logging"
-
- "github.com/francoispqt/gojay"
+ "github.com/quic-go/quic-go/qlog/jsontext"
)
// Setting of this only works when quic-go is used as a library.
trace trace
}
-func (topLevel) IsNil() bool { return false }
-func (l topLevel) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("qlog_format", "JSON-SEQ")
- enc.StringKey("qlog_version", "0.3")
- enc.StringKeyOmitEmpty("title", "quic-go qlog")
- enc.ObjectKey("configuration", configuration{Version: quicGoVersion})
- enc.ObjectKey("trace", l.trace)
+func (l topLevel) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("qlog_format"))
+ h.WriteToken(jsontext.String("JSON-SEQ"))
+ h.WriteToken(jsontext.String("qlog_version"))
+ h.WriteToken(jsontext.String("0.3"))
+ h.WriteToken(jsontext.String("title"))
+ h.WriteToken(jsontext.String("quic-go qlog"))
+ h.WriteToken(jsontext.String("configuration"))
+ if err := (configuration{Version: quicGoVersion}).Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("trace"))
+ if err := l.trace.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type configuration struct {
Version string
}
-func (c configuration) IsNil() bool { return false }
-func (c configuration) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKey("code_version", c.Version)
+func (c configuration) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("code_version"))
+ h.WriteToken(jsontext.String(c.Version))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type vantagePoint struct {
Type string
}
-func (p vantagePoint) IsNil() bool { return false }
-func (p vantagePoint) MarshalJSONObject(enc *gojay.Encoder) {
- enc.StringKeyOmitEmpty("name", p.Name)
- enc.StringKeyOmitEmpty("type", p.Type)
+func (p vantagePoint) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ if p.Name != "" {
+ h.WriteToken(jsontext.String("name"))
+ h.WriteToken(jsontext.String(p.Name))
+ }
+ if p.Type != "" {
+ h.WriteToken(jsontext.String("type"))
+ h.WriteToken(jsontext.String(p.Type))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
type commonFields struct {
ReferenceTime time.Time
}
-func (f commonFields) MarshalJSONObject(enc *gojay.Encoder) {
+func (f commonFields) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
if f.ODCID != nil {
- enc.StringKey("ODCID", f.ODCID.String())
- enc.StringKey("group_id", f.ODCID.String())
+ h.WriteToken(jsontext.String("ODCID"))
+ h.WriteToken(jsontext.String(f.ODCID.String()))
+ h.WriteToken(jsontext.String("group_id"))
+ h.WriteToken(jsontext.String(f.ODCID.String()))
}
- enc.StringKeyOmitEmpty("protocol_type", f.ProtocolType)
- enc.Float64Key("reference_time", float64(f.ReferenceTime.UnixNano())/1e6)
- enc.StringKey("time_format", "relative")
+ if f.ProtocolType != "" {
+ h.WriteToken(jsontext.String("protocol_type"))
+ h.WriteToken(jsontext.String(f.ProtocolType))
+ }
+ h.WriteToken(jsontext.String("reference_time"))
+ h.WriteToken(jsontext.Float(float64(f.ReferenceTime.UnixNano()) / 1e6))
+ h.WriteToken(jsontext.String("time_format"))
+ h.WriteToken(jsontext.String("relative"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
-func (f commonFields) IsNil() bool { return false }
-
type trace struct {
VantagePoint vantagePoint
CommonFields commonFields
}
-func (trace) IsNil() bool { return false }
-func (t trace) MarshalJSONObject(enc *gojay.Encoder) {
- enc.ObjectKey("vantage_point", t.VantagePoint)
- enc.ObjectKey("common_fields", t.CommonFields)
+func (t trace) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("vantage_point"))
+ if err := t.VantagePoint.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("common_fields"))
+ if err := t.CommonFields.Encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
}
"log"
"time"
- "github.com/francoispqt/gojay"
+ "github.com/quic-go/quic-go/qlog/jsontext"
)
const eventChanSize = 50
func (w *writer) Run() {
defer close(w.runStopped)
buf := &bytes.Buffer{}
- enc := gojay.NewEncoder(buf)
+ enc := jsontext.NewEncoder(buf)
if err := writeRecordSeparator(buf); err != nil {
panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
}
- if err := enc.Encode(&topLevel{trace: *w.tr}); err != nil {
- panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
- }
- if err := buf.WriteByte('\n'); err != nil {
+ if err := (&topLevel{trace: *w.tr}).Encode(enc); err != nil {
panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
}
if _, err := w.w.Write(buf.Bytes()); err != nil {
w.encodeErr = err
}
- enc = gojay.NewEncoder(w.w)
+ enc = jsontext.NewEncoder(w.w)
for ev := range w.events {
if w.encodeErr != nil { // if encoding failed, just continue draining the event channel
continue
w.encodeErr = err
continue
}
- if err := enc.Encode(ev); err != nil {
+ if err := ev.Encode(enc); err != nil {
w.encodeErr = err
continue
}
- if _, err := w.w.Write([]byte{'\n'}); err != nil {
- w.encodeErr = err
- }
}
}