diff --git a/go.mod b/go.mod index 690fa91..21ae057 100644 --- a/go.mod +++ b/go.mod @@ -5,14 +5,14 @@ go 1.18 require ( github.com/aaronland/go-roster v1.0.0 github.com/aaronland/go-sqlite v0.2.2 - github.com/paulmach/orb v0.9.0 - github.com/sfomuseum/go-sfomuseum-writer/v3 v3.0.0 - github.com/tidwall/gjson v1.14.4 + github.com/paulmach/orb v0.10.0 + github.com/sfomuseum/go-sfomuseum-writer/v3 v3.0.1 + github.com/tidwall/gjson v1.17.0 github.com/whosonfirst/go-reader v1.0.2 - github.com/whosonfirst/go-whosonfirst-export/v2 v2.7.0 + github.com/whosonfirst/go-whosonfirst-export/v2 v2.7.1 github.com/whosonfirst/go-whosonfirst-feature v0.0.26 - github.com/whosonfirst/go-whosonfirst-id v1.2.0 - github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.3.2 + github.com/whosonfirst/go-whosonfirst-id v1.2.2 + github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.3.4 github.com/whosonfirst/go-whosonfirst-reader v1.0.1 github.com/whosonfirst/go-whosonfirst-sqlite-features v0.10.1 github.com/whosonfirst/go-whosonfirst-sqlite-features-index v1.5.1 @@ -23,23 +23,24 @@ require ( require ( github.com/aaronland/go-artisanal-integers v0.9.1 // indirect - github.com/aaronland/go-brooklynintegers-api v1.2.6 // indirect - github.com/aaronland/go-json-query v0.1.3 // indirect + github.com/aaronland/go-brooklynintegers-api v1.2.7 // indirect + github.com/aaronland/go-json-query v0.1.4 // indirect + github.com/aaronland/go-log/v2 v2.0.0 // indirect github.com/aaronland/go-pool/v2 v2.0.0 // indirect github.com/aaronland/go-string v1.0.0 // indirect - github.com/aaronland/go-uid v0.3.0 // indirect - github.com/aaronland/go-uid-artisanal v0.0.2 // indirect - github.com/aaronland/go-uid-proxy v0.0.2 // indirect - github.com/aaronland/go-uid-whosonfirst v0.0.2 // indirect - github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/aaronland/go-uid v0.4.0 // indirect + github.com/aaronland/go-uid-artisanal v0.0.4 // indirect + github.com/aaronland/go-uid-proxy v0.1.1 // indirect + github.com/aaronland/go-uid-whosonfirst v0.0.4 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/g8rswimmer/error-chain v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/natefinch/atomic v1.0.1 // indirect github.com/sfomuseum/go-edtf v1.1.1 // indirect - github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.7 // indirect + github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.8 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect @@ -51,8 +52,8 @@ require ( github.com/whosonfirst/go-whosonfirst-names v0.1.0 // indirect github.com/whosonfirst/go-whosonfirst-sources v0.1.0 // indirect github.com/whosonfirst/go-whosonfirst-spr/v2 v2.3.3 // indirect - github.com/whosonfirst/go-whosonfirst-writer/v3 v3.0.0 // indirect + github.com/whosonfirst/go-whosonfirst-writer/v3 v3.1.0 // indirect github.com/whosonfirst/walk v0.0.2 // indirect - go.mongodb.org/mongo-driver v1.11.1 // indirect - go.uber.org/ratelimit v0.2.0 // indirect + go.mongodb.org/mongo-driver v1.11.4 // indirect + go.uber.org/ratelimit v0.3.0 // indirect ) diff --git a/go.sum b/go.sum index e953e21..b1512be 100644 --- a/go.sum +++ b/go.sum @@ -1,46 +1,35 @@ -github.com/aaronland/go-artisanal-integers v0.1.1/go.mod h1:ZTeFI+Ck+q+Dp11Htld5aU6V+YwEzxzprsBO0t9GPp8= github.com/aaronland/go-artisanal-integers v0.9.1 h1:VnTR0sTbgCKlFS3dDv3MEJ5KZn9K7llzAlTyJW3W07A= github.com/aaronland/go-artisanal-integers v0.9.1/go.mod h1:/KpdlAI8n4re3/aSkz5koLU+UxXDwPpP7Nxzmg89UMA= -github.com/aaronland/go-artisanal-integers-proxy v0.2.5/go.mod h1:mldeud4G0Yn4a+VKZ+CHrg5mw3u5OIOok25q5OKsOrM= -github.com/aaronland/go-brooklynintegers-api v1.2.1/go.mod h1:vFyhY89Uc0LDZEaEam5EQ+2La2VlkTvSfExuZgZhmX4= -github.com/aaronland/go-brooklynintegers-api v1.2.4/go.mod h1:hNUn5nueKQM23ptExy20p5qDpRPhWg8RbjwW2BuXWmw= -github.com/aaronland/go-brooklynintegers-api v1.2.6 h1:Hb+JrAA77ZLvcLnoRryAX2J1rjcPYoXlWD3u7AFQwzE= -github.com/aaronland/go-brooklynintegers-api v1.2.6/go.mod h1:HwGtLOIxqBXN+jmOzg5/VYuNbD9yg03t30hC+jlfwpI= +github.com/aaronland/go-brooklynintegers-api v1.2.7 h1:NpMlXLI9UU0l+IfA8Vy9EB3PCEedL1sEvSa2Ois3BSE= +github.com/aaronland/go-brooklynintegers-api v1.2.7/go.mod h1:qH7vwhOM1OXFYsDZqy32R52rsPLU19CXjLZ5qjvuX5k= github.com/aaronland/go-json-query v0.1.2/go.mod h1:kkCl5KrO+fVSL2M8b/i3qO5PsnCpmajGXkbJHpEQPY8= -github.com/aaronland/go-json-query v0.1.3 h1:wBqGF4d+Qy1+/YFqiFEKL7ja4iaaZi9E/CWaO3s7G4U= -github.com/aaronland/go-json-query v0.1.3/go.mod h1:+T7tN35K0RtLt92MlNM+N2sr6pxsQMJc6Fd4PsKaVtw= -github.com/aaronland/go-londonintegers-api v0.1.1/go.mod h1:N7Y0jrx+ouRAMrFcdH4nvJH6vrszj8/3yOOe0F8EV1E= -github.com/aaronland/go-missionintegers-api v0.1.1/go.mod h1:CvByrizvklOxK6QD+Z4RNqACxHqqVjiB/GdWQfrB4Mc= -github.com/aaronland/go-pool v1.0.0/go.mod h1:5EzZAfp1v2N+EyyGQ3868fxNxBL5+b4OUmVgnJZpMFo= +github.com/aaronland/go-json-query v0.1.4 h1:iM5GkF0VDsOeVgp0/WrDaFUB64ubJvmm+TZ0H4OQxxM= +github.com/aaronland/go-json-query v0.1.4/go.mod h1:S7V5eQko+XDPq+dfdSYub5mZI0VapVgUH2NLG0buZr4= +github.com/aaronland/go-log/v2 v2.0.0 h1:lMoaVDHd4Etaz2+ibze3ReqvHHG68z2SpuxYXv12WlE= +github.com/aaronland/go-log/v2 v2.0.0/go.mod h1:jOLBCaHVyOC7DQpbVFFQSiuU8CA8MRMrqA1mMSJQtLs= github.com/aaronland/go-pool/v2 v2.0.0 h1:3nYPErb875nXxrEGKhSNFqxR7rt9bMmeusbU8RuEksg= github.com/aaronland/go-pool/v2 v2.0.0/go.mod h1:2Yx7B3wLvg4qjxMDvDRseob7p0pgf/btsLfZ3NnIDlg= -github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= github.com/aaronland/go-roster v1.0.0 h1:FRDGrTqsYySKjWnAhbBGXyeGlI/o5/t9FZYCbUmyQtI= github.com/aaronland/go-roster v1.0.0/go.mod h1:KIsYZgrJlAsyb9LsXSCvlqvbcCBVjCSqcQiZx42i9ro= github.com/aaronland/go-sqlite v0.1.1/go.mod h1:EoqGJ9v4WGF9Gwln7g6b0ANsIED2sBit7p4VMtnD/yU= github.com/aaronland/go-sqlite v0.2.2 h1:lWLgp4ZpVQkVWUI+F3f3/MNKKOkaTr6iLHGBGg7sm8s= github.com/aaronland/go-sqlite v0.2.2/go.mod h1:GPFZKO98fn7onei3ypYioxxni/0Hbvq+6Z8YaaL1cQY= -github.com/aaronland/go-string v0.1.2/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= github.com/aaronland/go-string v1.0.0 h1:fPHmC1i9JhGzgi4qdCSXKc4xTCaLLe0uvlJMu9dHhco= github.com/aaronland/go-string v1.0.0/go.mod h1:URh3Au/fNbM0++WjBseurE3QTp875wiJ9ImrecD+7tI= -github.com/aaronland/go-uid v0.0.3/go.mod h1:VccCcqEWQgE9fr42fwnWIPBRMQlN1Yx+GLUQBPR3xNA= -github.com/aaronland/go-uid v0.3.0 h1:RI/MyMobd21V9bRQ0iDbVf1lu7vtESwVhfVqipY1jfs= -github.com/aaronland/go-uid v0.3.0/go.mod h1:HwQ09mooJ8j684z3W5lPKO6Odf557O6h3P3o1PquqXE= -github.com/aaronland/go-uid-artisanal v0.0.1/go.mod h1:WbAHDcfpYJ673t5kXgZn0zH7XiBjoLdvOMgngVQpCcg= -github.com/aaronland/go-uid-artisanal v0.0.2 h1:5r+gY/A94syru6KhkZYpgxadgc90tMmGVBc3TSuNVD8= -github.com/aaronland/go-uid-artisanal v0.0.2/go.mod h1:QJmPg7wefb68nBfuWvk/Uv6SZlI/63UxAjjNp5IygnU= -github.com/aaronland/go-uid-proxy v0.0.2 h1:Drj2wQNy8v+pRjIqTDjxgqIY+/HihuCiBgoYYdL0+PU= -github.com/aaronland/go-uid-proxy v0.0.2/go.mod h1:Vnl8FFfOmphD/s7tg7wEH8nigsJn8KovPFbhc3rnAUA= -github.com/aaronland/go-uid-whosonfirst v0.0.2 h1:CPm7/4GzwbUhfl4vW0tkuzCRmM1iaRfKpm2uyBEfQ6s= -github.com/aaronland/go-uid-whosonfirst v0.0.2/go.mod h1:j0nwjYlTGQPm4PBaIfsvUk47vXmYHTbojL+r5BzZMng= -github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= -github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/aaronland/go-uid v0.4.0 h1:2qQ2yRQarrUCEU9ApvBpaC9osAcqTCCvD77rOkDp7m0= +github.com/aaronland/go-uid v0.4.0/go.mod h1:HwQ09mooJ8j684z3W5lPKO6Odf557O6h3P3o1PquqXE= +github.com/aaronland/go-uid-artisanal v0.0.4 h1:I/29nzNnj32gax6rkBLeNtnwtXLqLAIE0mOlMq6KWWY= +github.com/aaronland/go-uid-artisanal v0.0.4/go.mod h1:fNtTeUssikRxhttmzQeR3yDLJpSchzwTVqvsOIlglks= +github.com/aaronland/go-uid-proxy v0.1.1 h1:poBS9ssktRE37bFzoHgJ4l6FL++e8/1zf8OcgKOsmR0= +github.com/aaronland/go-uid-proxy v0.1.1/go.mod h1:4IiRyYi56RyikBHThRsSMqcKSzydG8ffTB4jzqia8Qc= +github.com/aaronland/go-uid-whosonfirst v0.0.4 h1:FE9AZBw0Lq5XCDqK4/lSNLlzAhWL4nCzQpKXN5k9tg0= +github.com/aaronland/go-uid-whosonfirst v0.0.4/go.mod h1:2lyRTjFRNxS2hggKl60UZzVfzGoePeLBp/dt6d5rx00= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= -github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= @@ -72,8 +61,8 @@ github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0 github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= github.com/paulmach/orb v0.6.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A= github.com/paulmach/orb v0.7.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A= -github.com/paulmach/orb v0.9.0 h1:MwA1DqOKtvCgm7u9RZ/pnYejTeDJPnr0+0oFajBbJqk= -github.com/paulmach/orb v0.9.0/go.mod h1:SudmOk85SXtmXAB3sLGyJ6tZy/8pdfrV0o6ef98Xc30= +github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s= +github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -82,35 +71,28 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= -github.com/sfomuseum/go-edtf v1.0.0/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-edtf v1.1.1 h1:R5gElndHGDaK/rGSh2X+ulaLtlcHCdQA1cTzB8e9wv8= github.com/sfomuseum/go-edtf v1.1.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= github.com/sfomuseum/go-flags v0.8.3/go.mod h1:VXOnnX1/yxQpX2yiwHaBV6aCmhtszQOL5bL1/nNo3co= -github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.7 h1:Iyww9GEtv6AvQTaPdZRsWA6lnlsapt/GyUhp8ie8z/c= -github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.7/go.mod h1:M7HapFTwSdWsufgXrQpSOsuoq+bFjLZb31Y+uWAQYis= -github.com/sfomuseum/go-sfomuseum-writer/v3 v3.0.0 h1:zgg8K941EleE2uuOH8NZuJxlUBfXW3CsMdYhTtE4FnI= -github.com/sfomuseum/go-sfomuseum-writer/v3 v3.0.0/go.mod h1:GODuw5cVxyg3aIDfApNhDx9wUAFLSHPVVzWKKjGPDYI= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.8 h1:6xxStvwAyZdjOYcFw99Ae/gERRBByK3vtT9IORJbo1k= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.8/go.mod h1:nv3Sf2bFGT1G/tr34EfN1tDQ5pZQJ2hMaDxqUeI2EHE= +github.com/sfomuseum/go-sfomuseum-writer/v3 v3.0.1 h1:IPgC1TaHGdlYqdtMPwViT603VsiqBCHGn4tbavuTS4M= +github.com/sfomuseum/go-sfomuseum-writer/v3 v3.0.1/go.mod h1:PoyUPP3KsQDCcRRXHLdWCxkpqmbIviUWg/g3ViEM9Xg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/whosonfirst/go-ioutil v1.0.1/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= @@ -124,24 +106,21 @@ github.com/whosonfirst/go-rfc-5646 v0.1.0/go.mod h1:JZj//FV9YeV3fkyOY/82V53EMLQX github.com/whosonfirst/go-whosonfirst-crawl v0.2.1/go.mod h1:MTD1TCgAkXlAtysPU98ylrz9Y5+ZCfRrsrBnRyiH/t8= github.com/whosonfirst/go-whosonfirst-crawl v0.2.2 h1:7nwpNV/BFoPR0R7KMMy1iiYAer7wlHJBUOiL+NLzIFs= github.com/whosonfirst/go-whosonfirst-crawl v0.2.2/go.mod h1:2GZkaK9jaOisWRnBQGWzmb7H55TUFl9y9F30lrk2hwk= -github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.5/go.mod h1:WETCjYIg2wlYc1KcnFgF7dKCZ/dUKO+SMEU4h0OXF+A= -github.com/whosonfirst/go-whosonfirst-export/v2 v2.7.0 h1:WuneueMbfjVWKh4sESLBfSFm+0rhIsgYdy0K2JLeLm4= -github.com/whosonfirst/go-whosonfirst-export/v2 v2.7.0/go.mod h1:w0O954Le3iSTHX0Ivfg6SVuzd7oUne6QmELfsfhAjZc= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.7.1 h1:XM/TKVfj4Pknc6QgNgFNhw00zbAO1cC6gC8or1LFv0E= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.7.1/go.mod h1:RaY70vL/lqS2osrECto6rwb1CIeynJgBIo7yf1um3+E= github.com/whosonfirst/go-whosonfirst-feature v0.0.23/go.mod h1:3cvRigFFG2a99M64lZzfy5amHacWu8Os5fXZdGjPnLM= github.com/whosonfirst/go-whosonfirst-feature v0.0.26 h1:Dba+7aNMzxAaSVh9WzlPdrYhwT8T03cjNANjZvhcNsY= github.com/whosonfirst/go-whosonfirst-feature v0.0.26/go.mod h1:ntGT7tkg89WyEalg+Aocl0R27tPx2wBp7Prfx9a5tUg= github.com/whosonfirst/go-whosonfirst-flags v0.4.3/go.mod h1:pL17Ryo60FH8RYaQRgfu5XnxhrNRK3x+rn03TYD6Gc8= github.com/whosonfirst/go-whosonfirst-flags v0.4.4 h1:pwUnE8btx4Po6N5+uq0IrKVF0WraY5YW3tc3saIDg3A= github.com/whosonfirst/go-whosonfirst-flags v0.4.4/go.mod h1:C9X7vQvNR/u55AfOHYUT8o7dRACWV++ZV4B0kylnIaY= -github.com/whosonfirst/go-whosonfirst-format v0.3.7/go.mod h1:lMBIXCnD9ZA+wCNtu6XFYoq5DTfnEALO8k6OkEn11MM= github.com/whosonfirst/go-whosonfirst-format v0.4.1 h1:TVSrbbB/sXhAgyaTenaS93lERRITGQHBKIDwoEgxoqA= github.com/whosonfirst/go-whosonfirst-format v0.4.1/go.mod h1:lMBIXCnD9ZA+wCNtu6XFYoq5DTfnEALO8k6OkEn11MM= -github.com/whosonfirst/go-whosonfirst-id v0.0.4/go.mod h1:APHWvXV+DOqANgD1Lq615oJpLtdRjKdVV5cV7OgzER0= -github.com/whosonfirst/go-whosonfirst-id v1.2.0 h1:Nc+1g0DoWcd7H5nzxWrWodMoWThhXtH3lA7xQhdtcPc= -github.com/whosonfirst/go-whosonfirst-id v1.2.0/go.mod h1:+kuvLrDIOdeGZETl4MUX4EOoHKCPlj18GO4pL3rSpko= +github.com/whosonfirst/go-whosonfirst-id v1.2.2 h1:pyfwE26+W+A9qg11WlzBBsviBr7NhhJrbvhPWyf/2EE= +github.com/whosonfirst/go-whosonfirst-id v1.2.2/go.mod h1:R8MSXRw7dXWf2gcmyx1shzGVcn7RbTim6uctTp6658I= github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.2/go.mod h1:wkoAmndZ3l67zjUmjzw3Km8OzFt/TTJiVDSrYC8b9XY= -github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.3.2 h1:We3TSq7Tl+Ntk0pr9ZuPMRfBy0X9s4eO2VknCLWuCZc= -github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.3.2/go.mod h1:PtzP7XhL6LudTnfZhU7AnKDjGqy0Bp/oB2HLyuzpSQk= +github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.3.4 h1:fEhr0jwqxXvG7Nb7id4Q26ucdBZD51TcFNIiU+VNopM= +github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.3.4/go.mod h1:kDIvHxJTo6XgFKmLHliGLxlqeeHhxuYtdeVZBAcP68g= github.com/whosonfirst/go-whosonfirst-log v0.1.0/go.mod h1:pmgBbxZSnjGVy2nsUJBBMcFagxwIKLlmRsW7ClkXmac= github.com/whosonfirst/go-whosonfirst-names v0.1.0 h1:uXop/DwQqH60uDBZvHCPg1yRSQLScbm6VZyqcaED2KE= github.com/whosonfirst/go-whosonfirst-names v0.1.0/go.mod h1:0z86/nedM9T/5C8cAdbCMfRuBrkc33oEQ6vdJ6WybSg= @@ -163,8 +142,8 @@ github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApd github.com/whosonfirst/go-whosonfirst-uri v1.2.0/go.mod h1:CuVygTCUpMG945MMvqHyqxvc/L5YkDaMrrVpRFr7ZxY= github.com/whosonfirst/go-whosonfirst-uri v1.3.0 h1:LYOVLqP9rWQxauYVkdw65j5LZxEi8OK0GHh/qCEpX4g= github.com/whosonfirst/go-whosonfirst-uri v1.3.0/go.mod h1:CuVygTCUpMG945MMvqHyqxvc/L5YkDaMrrVpRFr7ZxY= -github.com/whosonfirst/go-whosonfirst-writer/v3 v3.0.0 h1:snhEF7nNPP1E0reD8cbwRHdFpk9WaNmljvlZF6yFvU8= -github.com/whosonfirst/go-whosonfirst-writer/v3 v3.0.0/go.mod h1:zr1HVHJ0Q8/azLtC0aeu8zgeALqPxrgPgxUe1SKnDyo= +github.com/whosonfirst/go-whosonfirst-writer/v3 v3.1.0 h1:0MKJgExBAfjZNbMj13V5o8Y6M4UWwvHrnRllHQ91HX0= +github.com/whosonfirst/go-whosonfirst-writer/v3 v3.1.0/go.mod h1:YJ3yxrk+6rYHNwIcYQfpVJR7CNR2faIy/Vt3byCsfdw= github.com/whosonfirst/go-writer/v3 v3.1.0 h1:lEZ6TIYvZb5NJ6e2OXYRM1j+MM2svKCSlb+6Vzbz+/M= github.com/whosonfirst/go-writer/v3 v3.1.0/go.mod h1:TmYoKR7RvrzJaj3eOgMhgXHFE+R1yuO/4smxKHFhv14= github.com/whosonfirst/walk v0.0.1/go.mod h1:1KtP/VeooSlFOI61p+THc/C16Ra8Z5MjpjI0tsd3c1M= @@ -177,22 +156,17 @@ github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgk github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8= -go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas= +go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= -go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= -go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +go.uber.org/ratelimit v0.3.0 h1:IdZd9wqvFXnvLvSEBo0KPcGfkoBGNkpTHlrE3Rcjkjw= +go.uber.org/ratelimit v0.3.0/go.mod h1:So5LG7CV1zWpY1sHe+DXTJqQvOx+FFPFaAs2SnoyBaI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -214,8 +188,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/.gitignore b/vendor/github.com/aaronland/go-brooklynintegers-api/.gitignore index 4389d1a..ca41b64 100644 --- a/vendor/github.com/aaronland/go-brooklynintegers-api/.gitignore +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/.gitignore @@ -1,4 +1,3 @@ *~ pkg -src -!vendor/src +.DS_Store \ No newline at end of file diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/api.go b/vendor/github.com/aaronland/go-brooklynintegers-api/api.go index e1731b0..a20ee62 100644 --- a/vendor/github.com/aaronland/go-brooklynintegers-api/api.go +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/api.go @@ -3,19 +3,63 @@ package api import ( "context" "fmt" - "github.com/aaronland/go-artisanal-integers/client" - "github.com/cenkalti/backoff/v4" - "github.com/tidwall/gjson" - "go.uber.org/ratelimit" "io" "log" "net/http" "net/url" + "sync" + + "github.com/aaronland/go-artisanal-integers/client" + "github.com/cenkalti/backoff/v4" + "github.com/tidwall/gjson" + "go.uber.org/ratelimit" ) +// In principle this could also be done with a sync.OnceFunc call but that will +// require that everyone uses Go 1.21 (whose package import changes broke everything) +// which is literally days old as I write this. So maybe a few releases after 1.21. + +var register_mu = new(sync.RWMutex) +var register_map = map[string]bool{} + func init() { + ctx := context.Background() - client.RegisterClient(ctx, "brooklynintegers", NewAPIClient) + err := RegisterClientSchemes(ctx) + + if err != nil { + panic(err) + } +} + +// RegisterClientSchemes will explicitly register all the schemes associated with the `client.Client` interface. +func RegisterClientSchemes(ctx context.Context) error { + + roster := map[string]client.ClientInitializeFunc{ + "brooklynintegers": NewAPIClient, + } + + register_mu.Lock() + defer register_mu.Unlock() + + for scheme, fn := range roster { + + _, exists := register_map[scheme] + + if exists { + continue + } + + err := client.RegisterClient(ctx, scheme, fn) + + if err != nil { + return fmt.Errorf("Failed to register client for '%s', %w", scheme, err) + } + + register_map[scheme] = true + } + + return nil } type APIClient struct { diff --git a/vendor/github.com/aaronland/go-log/v2/.gitignore b/vendor/github.com/aaronland/go-log/v2/.gitignore new file mode 100644 index 0000000..e4e5f6c --- /dev/null +++ b/vendor/github.com/aaronland/go-log/v2/.gitignore @@ -0,0 +1 @@ +*~ \ No newline at end of file diff --git a/vendor/github.com/aaronland/go-log/v2/LICENSE b/vendor/github.com/aaronland/go-log/v2/LICENSE new file mode 100644 index 0000000..583915d --- /dev/null +++ b/vendor/github.com/aaronland/go-log/v2/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2022, Aaron Straup Cope +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/aaronland/go-log/v2/README.md b/vendor/github.com/aaronland/go-log/v2/README.md new file mode 100644 index 0000000..3ec4d61 --- /dev/null +++ b/vendor/github.com/aaronland/go-log/v2/README.md @@ -0,0 +1,52 @@ +# go-log + +Opinionated Go package for doing minimal structured logging and prefixing of log messages with Emoji for easier filtering. It's possible this package will become irrelevant if and when Go [slog](https://github.com/golang/go/issues/56345) package because part of "core". Until then it does what I need. + +## Documentation + +[![Go Reference](https://pkg.go.dev/badge/github.com/aaronland/go-log.svg)](https://pkg.go.dev/github.com/aaronland/go-log) + +## Example + +``` +import ( + "log" + + aa_log "github.com/aaronland/go-log/v2" +) + +func main(){ + + logger := log.Default() + + aa_log.SetMinLevelWithPrefix(aa_log.WARNING_PREFIX) + + // No output + aa_log.Debug(logger, "This is a test") + + aa_log.UnsetMinLevel() + + // prints "💬 Hello, world" + aa_log.Info(logger, "Hello, %w", "world") + + // prints "🪵 This is a second test" + aa_log.Debug(logger, "This is a second test") + + // prints "🧯 This is an error" + aa_log.Warning(logger, fmt.Errorf("This is an error")) + + // Emits errors using the default Go *log.Logger instance + // prints "{YYYY}/{MM}/{DD} {HH}:{MM}:{SS} 🧯 This is a second error" + aa_log.Warning(fmt.Errorf("This is a second error")) +} +``` + +## Prefixes + +| Log level | Prefix | +| --- | --- | +| debug | 🪵 | +| info | 💬 | +| warning | 🧯 | +| error | 🔥 | +| fatal | 💥 | diff --git a/vendor/github.com/aaronland/go-log/v2/log.go b/vendor/github.com/aaronland/go-log/v2/log.go new file mode 100644 index 0000000..00f44c7 --- /dev/null +++ b/vendor/github.com/aaronland/go-log/v2/log.go @@ -0,0 +1,195 @@ +package log + +import ( + "fmt" + "log" + "os" +) + +// DEBUG_LEVEL is the numeric level associated with "debug" messages. +const DEBUG_LEVEL int = 10 + +// INFO_LEVEL is the numeric level associated with "info" messages. +const INFO_LEVEL int = 20 + +// WARNING_LEVEL is the numeric level associated with "warning" messages. +const WARNING_LEVEL int = 30 + +// ERROR_LEVEL is the numeric level associated with "error" messages. +const ERROR_LEVEL int = 40 + +// FATAL_LEVEL is the numeric level associated with "fatal" messages. +const FATAL_LEVEL int = 50 + +// DEBUG_PREFIX is the string prefix to prepend "debug" messages with. +const DEBUG_PREFIX string = "🪵" // "🦜" + +// INFO_PREFIX is the string prefix to prepend "info" messages with. +const INFO_PREFIX string = "💬" + +// WARNING_PREFIX is the string prefix to prepend "warning" messages with. +const WARNING_PREFIX string = "🧯" + +// ERROR_PREFIX is the string prefix to prepend "error" messages with. +const ERROR_PREFIX string = "🔥" + +// FATAL_PREFIX is the string prefix to prepend "fatal" messages with. +const FATAL_PREFIX string = "💥" + +var minLevel int + +// UnsetMinLevel resets the minimum level log level allowing all messages to be emitted. +func UnsetMinLevel() { + minLevel = 0 +} + +// SetMinLevel assigns the minimum log level to 'l'. Log events with a lower level will not be emitted. +func SetMinLevel(l int) error { + + switch l { + case DEBUG_LEVEL, INFO_LEVEL, WARNING_LEVEL, ERROR_LEVEL, FATAL_LEVEL: + minLevel = l + default: + return fmt.Errorf("Invalid level") + } + + return nil +} + +// SetMinLevelStringWithPrefix assigns the minimum log level associated with 'prefix'. Log events with a lower level will not be emitted. +func SetMinLevelWithPrefix(prefix string) error { + + switch prefix { + case DEBUG_PREFIX: + return SetMinLevel(DEBUG_LEVEL) + case INFO_PREFIX: + return SetMinLevel(INFO_LEVEL) + case WARNING_PREFIX: + return SetMinLevel(WARNING_LEVEL) + case ERROR_PREFIX: + return SetMinLevel(ERROR_LEVEL) + case FATAL_PREFIX: + return SetMinLevel(FATAL_LEVEL) + default: + return fmt.Errorf("Invalid level") + } +} + +func emit(prefix string, args ...interface{}) { + + count_args := len(args) + + var logger *log.Logger + var msg string + var extras []interface{} + + // Nothing to do. Go home. + + if count_args == 0 { + return + } + + // Check to see whether first arg is a *log.Logger instance + // If not create a logger and check whether first argument + // is an error. + + if count_args >= 1 { + + switch args[0].(type) { + case *log.Logger: + logger = args[0].(*log.Logger) + default: + + // See the way we are calling log.New rather than log.Default? + // That's mostly so for the tests so that we can capture STDERR + // The value if log.Default is a global singleton in log/log.go + // which references an instance os.Stderr which doesn't seem to + // get updated when we reassign it in the tests. I suppose this + // might be the cause of "hilarity" in the future but it will + // do for now... + // https://cs.opensource.google/go/go/+/refs/tags/go1.20:src/log/log.go;l=89 + + logger = log.New(os.Stderr, "", log.LstdFlags) + + switch args[0].(type) { + case string: + msg = args[0].(string) + default: + msg = fmt.Sprintf("%v", args[0]) + } + } + } + + // Check to see whether second arg is a log formatting string + // or an error (or really anything other than a string) + + if count_args >= 2 { + + switch args[1].(type) { + case string: + msg = args[1].(string) + default: + msg = fmt.Sprintf("%v", args[1]) + } + } + + // Anything else + + if count_args >= 3 { + extras = args[2:] + } + + msg = fmt.Sprintf("%s %s", prefix, msg) + logger.Printf(msg, extras...) +} + +// Emit a "debug" log message. +func Debug(args ...interface{}) { + + if minLevel > DEBUG_LEVEL { + return + } + + emit(DEBUG_PREFIX, args...) +} + +// Emit a "info" log message. +func Info(args ...interface{}) { + + if minLevel > INFO_LEVEL { + return + } + + emit(INFO_PREFIX, args...) +} + +// Emit a "warning" log message. +func Warning(args ...interface{}) { + + if minLevel > WARNING_LEVEL { + return + } + + emit(WARNING_PREFIX, args...) +} + +// Emit an "error" log message. +func Error(args ...interface{}) { + + if minLevel > ERROR_LEVEL { + return + } + + emit(ERROR_PREFIX, args...) +} + +// Emit an "fatal" log message. +func Fatal(args ...interface{}) { + + if minLevel > FATAL_LEVEL { + return + } + + emit(FATAL_PREFIX, args...) + os.Exit(1) +} diff --git a/vendor/github.com/aaronland/go-uid-artisanal/.gitignore b/vendor/github.com/aaronland/go-uid-artisanal/.gitignore index e4e5f6c..4df8f53 100644 --- a/vendor/github.com/aaronland/go-uid-artisanal/.gitignore +++ b/vendor/github.com/aaronland/go-uid-artisanal/.gitignore @@ -1 +1,2 @@ -*~ \ No newline at end of file +*~ +.DS_Store \ No newline at end of file diff --git a/vendor/github.com/aaronland/go-uid-artisanal/artisanal.go b/vendor/github.com/aaronland/go-uid-artisanal/artisanal.go index 63b4bb3..99ae08b 100644 --- a/vendor/github.com/aaronland/go-uid-artisanal/artisanal.go +++ b/vendor/github.com/aaronland/go-uid-artisanal/artisanal.go @@ -3,21 +3,64 @@ package artisanal import ( "context" "fmt" - "github.com/aaronland/go-artisanal-integers/client" - "github.com/aaronland/go-uid" _ "net/url" "strings" + "sync" + + "github.com/aaronland/go-artisanal-integers/client" + "github.com/aaronland/go-uid" ) const ARTISANAL_SCHEME string = "artisanal" +// In principle this could also be done with a sync.OnceFunc call but that will +// require that everyone uses Go 1.21 (whose package import changes broke everything) +// which is literally days old as I write this. So maybe a few releases after 1.21. + +var register_mu = new(sync.RWMutex) +var register_map = map[string]bool{} + func init() { + ctx := context.Background() + err := RegisterProviderSchemes(ctx) + + if err != nil { + panic(err) + } +} + +// RegisterProviderSchemes will explicitly register all the schemes associated with the `uid.Provider` interface. +func RegisterProviderSchemes(ctx context.Context) error { + + roster := map[string]uid.ProviderInitializationFunc{} for _, s := range client.Schemes() { s = strings.Replace(s, "://", "", 1) - uid.RegisterProvider(ctx, s, NewArtisanalProvider) + roster[s] = NewArtisanalProvider } + + register_mu.Lock() + defer register_mu.Unlock() + + for scheme, fn := range roster { + + _, exists := register_map[scheme] + + if exists { + continue + } + + err := uid.RegisterProvider(ctx, scheme, fn) + + if err != nil { + return fmt.Errorf("Failed to register client for '%s', %w", scheme, err) + } + + register_map[scheme] = true + } + + return nil } type ArtisanalProvider struct { diff --git a/vendor/github.com/aaronland/go-uid-proxy/proxy.go b/vendor/github.com/aaronland/go-uid-proxy/proxy.go index 3385e51..a4c0f1b 100644 --- a/vendor/github.com/aaronland/go-uid-proxy/proxy.go +++ b/vendor/github.com/aaronland/go-uid-proxy/proxy.go @@ -3,13 +3,16 @@ package proxy import ( "context" "fmt" - "github.com/aaronland/go-pool/v2" - "github.com/aaronland/go-uid" "io" "log" "net/url" + "strconv" "sync" "time" + + aa_log "github.com/aaronland/go-log/v2" + "github.com/aaronland/go-pool/v2" + "github.com/aaronland/go-uid" ) const PROXY_SCHEME string = "proxy" @@ -31,6 +34,9 @@ type ProxyProvider struct { func NewProxyProvider(ctx context.Context, uri string) (uid.Provider, error) { + workers := 10 + minimum := 0 + u, err := url.Parse(uri) if err != nil { @@ -51,6 +57,32 @@ func NewProxyProvider(ctx context.Context, uri string) (uid.Provider, error) { pool_uri = "memory://" } + str_workers := q.Get("workers") + + if str_workers != "" { + + v, err := strconv.Atoi(str_workers) + + if err != nil { + return nil, fmt.Errorf("Invalid ?workers parameter") + } + + workers = v + } + + str_minimum := q.Get("minimum") + + if str_minimum != "" { + + v, err := strconv.Atoi(str_minimum) + + if err != nil { + return nil, fmt.Errorf("Invalid ?minimum parameter") + } + + minimum = v + } + source_pr, err := uid.NewProvider(ctx, source_uri) if err != nil { @@ -65,9 +97,6 @@ func NewProxyProvider(ctx context.Context, uri string) (uid.Provider, error) { logger := log.New(io.Discard, "", 0) - workers := 10 - minimum := 0 - refill := make(chan bool) pr := &ProxyProvider{ @@ -94,7 +123,7 @@ func (pr *ProxyProvider) UID(ctx context.Context, args ...interface{}) (uid.UID, if pr.pool.Length(ctx) == 0 { - pr.logger.Printf("pool length is 0 so fetching integer from source") + aa_log.Warning(pr.logger, "pool length is 0 so fetching integer from source") go pr.refillPool(ctx) return pr.provider.UID(ctx, args...) @@ -104,7 +133,7 @@ func (pr *ProxyProvider) UID(ctx context.Context, args ...interface{}) (uid.UID, if !ok { - pr.logger.Printf("failed to pop UID!") + aa_log.Info(pr.logger, "failed to pop UID!") go pr.refillPool(ctx) return pr.provider.UID(ctx, args...) @@ -125,7 +154,7 @@ func (pr *ProxyProvider) status(ctx context.Context) { case <-ctx.Done(): return case <-time.After(5 * time.Second): - pr.logger.Printf("pool length: %d", pr.pool.Length(ctx)) + aa_log.Debug(pr.logger, "Pool length: %d", pr.pool.Length(ctx)) } } } @@ -156,8 +185,12 @@ func (pr *ProxyProvider) refillPool(ctx context.Context) { // and refill the pool simultaneously. First, we block until a slot opens // up. + aa_log.Debug(pr.logger, "Refill pool. Waiting for work queue.") + <-pr.refill + aa_log.Debug(pr.logger, "Refill pool. Starting.") + t1 := time.Now() // Figure out how many integers we need to get *at this moment* which when @@ -191,7 +224,7 @@ func (pr *ProxyProvider) refillPool(ctx context.Context) { wg := new(sync.WaitGroup) - pr.logger.Printf("refill poll w/ %d integers and %d workers", todo, workers) + aa_log.Info(pr.logger, "refill poll w/ %d integers and %d workers", todo, workers) success := 0 failed := 0 @@ -212,7 +245,7 @@ func (pr *ProxyProvider) refillPool(ctx context.Context) { // First check that we still actually need to keep fetching integers if pr.pool.Length(ctx) >= int64(pr.minimum) { - pr.logger.Printf("pool is full (%d) stopping after %d iterations", pr.pool.Length(ctx), j) + aa_log.Info(pr.logger, "pool is full (%d) stopping after %d iterations", pr.pool.Length(ctx), j) break } @@ -239,7 +272,7 @@ func (pr *ProxyProvider) refillPool(ctx context.Context) { pr.refill <- true t2 := time.Since(t1) - pr.logger.Printf("time to refill the pool with %d integers (success: %d failed: %d): %v (pool length is now %d)", todo, success, failed, t2, pr.pool.Length(ctx)) + aa_log.Debug(pr.logger, "Time to refill the pool with %d integers (success: %d failed: %d): %v (pool length is now %d)", todo, success, failed, t2, pr.pool.Length(ctx)) } @@ -248,7 +281,7 @@ func (pr *ProxyProvider) addToPool(ctx context.Context) bool { i, err := pr.provider.UID(ctx) if err != nil { - pr.logger.Printf("Failed to create new UID to add to pool, %v", err) + aa_log.Error(pr.logger, "Failed to create new UID to add to pool, %v", err) return false } diff --git a/vendor/github.com/aaronland/go-uid-whosonfirst/whosonfirst.go b/vendor/github.com/aaronland/go-uid-whosonfirst/whosonfirst.go index 78f73bb..ab52cab 100644 --- a/vendor/github.com/aaronland/go-uid-whosonfirst/whosonfirst.go +++ b/vendor/github.com/aaronland/go-uid-whosonfirst/whosonfirst.go @@ -1,16 +1,23 @@ package whosonfirst +import () + import ( "context" - _ "github.com/aaronland/go-brooklynintegers-api" + + "github.com/aaronland/go-brooklynintegers-api" "github.com/aaronland/go-uid" - _ "github.com/aaronland/go-uid-artisanal" + "github.com/aaronland/go-uid-artisanal" ) const WHOSONFIRST_SCHEME string = "whosonfirst" func init() { ctx := context.Background() + + api.RegisterClientSchemes(ctx) + artisanal.RegisterProviderSchemes(ctx) + uid.RegisterProvider(ctx, WHOSONFIRST_SCHEME, NewWhosOnFirstProvider) } diff --git a/vendor/github.com/aaronland/go-uid/int.go b/vendor/github.com/aaronland/go-uid/int.go new file mode 100644 index 0000000..29f1c72 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/int.go @@ -0,0 +1,28 @@ +package uid + +import ( + "context" + "strconv" +) + +type Int64UID struct { + UID + int64 int64 +} + +func NewInt64UID(ctx context.Context, i int64) (UID, error) { + + u := Int64UID{ + int64: i, + } + + return &u, nil +} + +func (u *Int64UID) Value() any { + return u.int64 +} + +func (u *Int64UID) String() string { + return strconv.FormatInt(u.int64, 10) +} diff --git a/vendor/github.com/aaronland/go-uid/multi.go b/vendor/github.com/aaronland/go-uid/multi.go new file mode 100644 index 0000000..465cd6b --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/multi.go @@ -0,0 +1,40 @@ +package uid + +import ( + "context" + "fmt" + "strings" +) + +type MultiUID struct { + UID + uids []UID +} + +func NewMultiUID(ctx context.Context, uids ...UID) UID { + + r := &MultiUID{ + uids: uids, + } + + return r +} + +func (r *MultiUID) Value() any { + return r.uids +} + +func (r *MultiUID) String() string { + + pairs := make([]string, len(r.uids)) + + for idx, uid := range r.uids { + + uid_t := fmt.Sprintf("%T", uid) + label := strings.Replace(uid_t, "*uid.", "", 1) + + pairs[idx] = fmt.Sprintf("%s#%s", label, uid.String()) + } + + return strings.Join(pairs, " ") +} diff --git a/vendor/github.com/aaronland/go-uid/null.go b/vendor/github.com/aaronland/go-uid/null.go index 950cc43..145b0d8 100644 --- a/vendor/github.com/aaronland/go-uid/null.go +++ b/vendor/github.com/aaronland/go-uid/null.go @@ -6,6 +6,7 @@ import ( "log" ) +// NULL_SCHEME is the URI scheme used to identify NullProvider instances. const NULL_SCHEME string = "null" func init() { @@ -13,14 +14,19 @@ func init() { RegisterProvider(ctx, NULL_SCHEME, NewNullProvider) } +// type NullProvider implements the Provider interface to return empty (null) identifiers. type NullProvider struct { Provider } +// type NullProvider implements the UID interface to return empty (null) identifiers. type NullUID struct { UID } +// NewNullProvider +// +// null:// func NewNullProvider(ctx context.Context, uri string) (Provider, error) { pr := &NullProvider{} return pr, nil diff --git a/vendor/github.com/andres-erbsen/clock/.travis.yml b/vendor/github.com/andres-erbsen/clock/.travis.yml deleted file mode 100644 index ca785e5..0000000 --- a/vendor/github.com/andres-erbsen/clock/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go -go: - - 1.3 - - 1.4 - - release - - tip -sudo: false diff --git a/vendor/github.com/andres-erbsen/clock/LICENSE b/vendor/github.com/benbjohnson/clock/LICENSE similarity index 94% rename from vendor/github.com/andres-erbsen/clock/LICENSE rename to vendor/github.com/benbjohnson/clock/LICENSE index ddf4e00..ce212cb 100644 --- a/vendor/github.com/andres-erbsen/clock/LICENSE +++ b/vendor/github.com/benbjohnson/clock/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Ben Johnson, Copyright (c) 2015 Yahoo Inc. +Copyright (c) 2014 Ben Johnson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/andres-erbsen/clock/README.md b/vendor/github.com/benbjohnson/clock/README.md similarity index 69% rename from vendor/github.com/andres-erbsen/clock/README.md rename to vendor/github.com/benbjohnson/clock/README.md index f744e76..4f1f82f 100644 --- a/vendor/github.com/andres-erbsen/clock/README.md +++ b/vendor/github.com/benbjohnson/clock/README.md @@ -1,22 +1,25 @@ -clock [![Build Status](https://travis-ci.org/andres-erbsen/clock.svg)](https://travis-ci.org/andres-erbsen/clock) [![Coverage Status](https://coveralls.io/repos/andres-erbsen/clock/badge.png?branch=master)](https://coveralls.io/r/andres-erbsen/clock?branch=master) [![GoDoc](https://godoc.org/github.com/andres-erbsen/clock?status.png)](https://godoc.org/github.com/andres-erbsen/clock) ![Project status](http://img.shields.io/status/experimental.png?color=red) +clock ===== +[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/mod/github.com/benbjohnson/clock) + Clock is a small library for mocking time in Go. It provides an interface around the standard library's [`time`][time] package so that the application can use the realtime clock while tests can use the mock clock. -[time]: http://golang.org/pkg/time/ +The module is currently maintained by @djmitche. +[time]: https://pkg.go.dev/github.com/benbjohnson/clock ## Usage ### Realtime Clock Your application can maintain a `Clock` variable that will allow realtime and -mock clocks to be interchangable. For example, if you had an `Application` type: +mock clocks to be interchangeable. For example, if you had an `Application` type: ```go -import "github.com/andres-erbsen/clock" +import "github.com/benbjohnson/clock" type Application struct { Clock clock.Clock @@ -43,7 +46,7 @@ In your tests, you will want to use a `Mock` clock: import ( "testing" - "github.com/andres-erbsen/clock" + "github.com/benbjohnson/clock" ) func TestApplication_DoSomething(t *testing.T) { @@ -55,7 +58,7 @@ func TestApplication_DoSomething(t *testing.T) { Now that you've initialized your application to use the mock clock, you can adjust the time programmatically. The mock clock always starts from the Unix -epoch (midnight, Jan 1, 1970 UTC). +epoch (midnight UTC on Jan 1, 1970). ### Controlling time @@ -80,13 +83,13 @@ mock.Now().UTC() // 1970-01-01 02:00:00 +0000 UTC Timers and Tickers are also controlled by this same mock clock. They will only execute when the clock is moved forward: -``` +```go mock := clock.NewMock() count := 0 // Kick off a timer to increment every 1 mock second. go func() { - ticker := clock.Ticker(1 * time.Second) + ticker := mock.Ticker(1 * time.Second) for { <-ticker.C count++ @@ -94,11 +97,9 @@ go func() { }() runtime.Gosched() -// Move the clock forward 10 second. +// Move the clock forward 10 seconds. mock.Add(10 * time.Second) // This prints 10. fmt.Println(count) ``` - - diff --git a/vendor/github.com/andres-erbsen/clock/clock.go b/vendor/github.com/benbjohnson/clock/clock.go similarity index 68% rename from vendor/github.com/andres-erbsen/clock/clock.go rename to vendor/github.com/benbjohnson/clock/clock.go index b58b703..40555b3 100644 --- a/vendor/github.com/andres-erbsen/clock/clock.go +++ b/vendor/github.com/benbjohnson/clock/clock.go @@ -1,24 +1,32 @@ package clock import ( + "context" "sort" "sync" "time" ) +// Re-export of time.Duration +type Duration = time.Duration + // Clock represents an interface to the functions in the standard library time // package. Two implementations are available in the clock package. The first // is a real-time clock which simply wraps the time package's functions. The -// second is a mock clock which will only make forward progress when +// second is a mock clock which will only change when // programmatically adjusted. type Clock interface { After(d time.Duration) <-chan time.Time AfterFunc(d time.Duration, f func()) *Timer Now() time.Time + Since(t time.Time) time.Duration + Until(t time.Time) time.Duration Sleep(d time.Duration) Tick(d time.Duration) <-chan time.Time Ticker(d time.Duration) *Ticker Timer(d time.Duration) *Timer + WithDeadline(parent context.Context, d time.Time) (context.Context, context.CancelFunc) + WithTimeout(parent context.Context, t time.Duration) (context.Context, context.CancelFunc) } // New returns an instance of a real-time clock. @@ -37,6 +45,10 @@ func (c *clock) AfterFunc(d time.Duration, f func()) *Timer { func (c *clock) Now() time.Time { return time.Now() } +func (c *clock) Since(t time.Time) time.Duration { return time.Since(t) } + +func (c *clock) Until(t time.Time) time.Duration { return time.Until(t) } + func (c *clock) Sleep(d time.Duration) { time.Sleep(d) } func (c *clock) Tick(d time.Duration) <-chan time.Time { return time.Tick(d) } @@ -51,6 +63,14 @@ func (c *clock) Timer(d time.Duration) *Timer { return &Timer{C: t.C, timer: t} } +func (c *clock) WithDeadline(parent context.Context, d time.Time) (context.Context, context.CancelFunc) { + return context.WithDeadline(parent, d) +} + +func (c *clock) WithTimeout(parent context.Context, t time.Duration) (context.Context, context.CancelFunc) { + return context.WithTimeout(parent, t) +} + // Mock represents a mock clock that only moves forward programmically. // It can be preferable to a real-time clock when testing time-based functionality. type Mock struct { @@ -65,7 +85,7 @@ func NewMock() *Mock { return &Mock{now: time.Unix(0, 0)} } -// Add moves the current time of the mock clock forward by the duration. +// Add moves the current time of the mock clock forward by the specified duration. // This should only be called from a single goroutine at a time. func (m *Mock) Add(d time.Duration) { // Calculate the final current time. @@ -83,11 +103,11 @@ func (m *Mock) Add(d time.Duration) { m.now = t m.mu.Unlock() - // Give a small buffer to make sure the other goroutines get handled. + // Give a small buffer to make sure that other goroutines get handled. gosched() } -// Sets the current time of the mock clock to a specific one. +// Set sets the current time of the mock clock to a specific one. // This should only be called from a single goroutine at a time. func (m *Mock) Set(t time.Time) { // Continue to execute timers until there are no more before the new time. @@ -102,13 +122,13 @@ func (m *Mock) Set(t time.Time) { m.now = t m.mu.Unlock() - // Give a small buffer to make sure the other goroutines get handled. + // Give a small buffer to make sure that other goroutines get handled. gosched() } // runNextTimer executes the next timer in chronological order and moves the // current time to the timer's next tick time. The next time is not executed if -// it's next time if after the max time. Returns true if a timer is executed. +// its next time is after the max time. Returns true if a timer was executed. func (m *Mock) runNextTimer(max time.Time) bool { m.mu.Lock() @@ -158,6 +178,16 @@ func (m *Mock) Now() time.Time { return m.now } +// Since returns time since `t` using the mock clock's wall time. +func (m *Mock) Since(t time.Time) time.Duration { + return m.Now().Sub(t) +} + +// Until returns time until `t` using the mock clock's wall time. +func (m *Mock) Until(t time.Time) time.Duration { + return t.Sub(m.Now()) +} + // Sleep pauses the goroutine for the given duration on the mock clock. // The clock must be moved forward in a separate goroutine. func (m *Mock) Sleep(d time.Duration) { @@ -188,30 +218,23 @@ func (m *Mock) Ticker(d time.Duration) *Ticker { // Timer creates a new instance of Timer. func (m *Mock) Timer(d time.Duration) *Timer { + m.mu.Lock() + defer m.mu.Unlock() ch := make(chan time.Time, 1) t := &Timer{ - C: ch, - c: ch, - mock: m, - next: m.Now().Add(d), + C: ch, + c: ch, + mock: m, + next: m.now.Add(d), + stopped: false, } - m.addTimer((*internalTimer)(t)) + m.timers = append(m.timers, (*internalTimer)(t)) return t } -func (m *Mock) addTimer(t *internalTimer) { - m.mu.Lock() - defer m.mu.Unlock() - m.timers = append(m.timers, t) -} - -func (m *Mock) removeClockTimer(t clockTimer) bool { - m.mu.Lock() - defer m.mu.Unlock() - ret := false +func (m *Mock) removeClockTimer(t clockTimer) { for i, timer := range m.timers { if timer == t { - ret = true copy(m.timers[i:], m.timers[i+1:]) m.timers[len(m.timers)-1] = nil m.timers = m.timers[:len(m.timers)-1] @@ -219,7 +242,6 @@ func (m *Mock) removeClockTimer(t clockTimer) bool { } } sort.Sort(m.timers) - return ret } // clockTimer represents an object with an associated start time. @@ -238,48 +260,66 @@ func (a clockTimers) Less(i, j int) bool { return a[i].Next().Before(a[j].Next() // Timer represents a single event. // The current time will be sent on C, unless the timer was created by AfterFunc. type Timer struct { - C <-chan time.Time - c chan time.Time - timer *time.Timer // realtime impl, if set - next time.Time // next tick time - mock *Mock // mock clock, if set - fn func() // AfterFunc function, if set + C <-chan time.Time + c chan time.Time + timer *time.Timer // realtime impl, if set + next time.Time // next tick time + mock *Mock // mock clock, if set + fn func() // AfterFunc function, if set + stopped bool // True if stopped, false if running } -// Stop turns off the timer. +// Stop turns off the ticker. func (t *Timer) Stop() bool { if t.timer != nil { return t.timer.Stop() } - return t.mock.removeClockTimer((*internalTimer)(t)) + + t.mock.mu.Lock() + registered := !t.stopped + t.mock.removeClockTimer((*internalTimer)(t)) + t.stopped = true + t.mock.mu.Unlock() + return registered } -// Reset changes the timer to expire after duration d. It returns true if the -// timer had been active, false if the timer had expired or been stopped. +// Reset changes the expiry time of the timer func (t *Timer) Reset(d time.Duration) bool { if t.timer != nil { return t.timer.Reset(d) } - ret := t.mock.removeClockTimer((*internalTimer)(t)) - t.next = t.mock.Now().Add(d) - t.mock.addTimer((*internalTimer)(t)) - return ret + + t.mock.mu.Lock() + t.next = t.mock.now.Add(d) + defer t.mock.mu.Unlock() + + registered := !t.stopped + if t.stopped { + t.mock.timers = append(t.mock.timers, (*internalTimer)(t)) + } + + t.stopped = false + return registered } type internalTimer Timer func (t *internalTimer) Next() time.Time { return t.next } func (t *internalTimer) Tick(now time.Time) { + // a gosched() after ticking, to allow any consequences of the + // tick to complete + defer gosched() + + t.mock.mu.Lock() if t.fn != nil { - t.fn() + // defer function execution until the lock is released, and + defer t.fn() } else { - select { - case t.c <- now: - default: - } + t.c <- now } t.mock.removeClockTimer((*internalTimer)(t)) - gosched() + t.stopped = true + t.mock.mu.Unlock() } // Ticker holds a channel that receives "ticks" at regular intervals. @@ -297,8 +337,24 @@ func (t *Ticker) Stop() { if t.ticker != nil { t.ticker.Stop() } else { + t.mock.mu.Lock() t.mock.removeClockTimer((*internalTicker)(t)) + t.mock.mu.Unlock() + } +} + +// Reset resets the ticker to a new duration. +func (t *Ticker) Reset(dur time.Duration) { + if t.ticker != nil { + t.ticker.Reset(dur) + return } + + t.mock.mu.Lock() + defer t.mock.mu.Unlock() + + t.d = dur + t.next = t.mock.now.Add(dur) } type internalTicker Ticker @@ -315,3 +371,8 @@ func (t *internalTicker) Tick(now time.Time) { // Sleep momentarily so that other goroutines can process. func gosched() { time.Sleep(1 * time.Millisecond) } + +var ( + // type checking + _ Clock = &Mock{} +) diff --git a/vendor/github.com/benbjohnson/clock/context.go b/vendor/github.com/benbjohnson/clock/context.go new file mode 100644 index 0000000..eb67594 --- /dev/null +++ b/vendor/github.com/benbjohnson/clock/context.go @@ -0,0 +1,86 @@ +package clock + +import ( + "context" + "fmt" + "sync" + "time" +) + +func (m *Mock) WithTimeout(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) { + return m.WithDeadline(parent, m.Now().Add(timeout)) +} + +func (m *Mock) WithDeadline(parent context.Context, deadline time.Time) (context.Context, context.CancelFunc) { + if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { + // The current deadline is already sooner than the new one. + return context.WithCancel(parent) + } + ctx := &timerCtx{clock: m, parent: parent, deadline: deadline, done: make(chan struct{})} + propagateCancel(parent, ctx) + dur := m.Until(deadline) + if dur <= 0 { + ctx.cancel(context.DeadlineExceeded) // deadline has already passed + return ctx, func() {} + } + ctx.Lock() + defer ctx.Unlock() + if ctx.err == nil { + ctx.timer = m.AfterFunc(dur, func() { + ctx.cancel(context.DeadlineExceeded) + }) + } + return ctx, func() { ctx.cancel(context.Canceled) } +} + +// propagateCancel arranges for child to be canceled when parent is. +func propagateCancel(parent context.Context, child *timerCtx) { + if parent.Done() == nil { + return // parent is never canceled + } + go func() { + select { + case <-parent.Done(): + child.cancel(parent.Err()) + case <-child.Done(): + } + }() +} + +type timerCtx struct { + sync.Mutex + + clock Clock + parent context.Context + deadline time.Time + done chan struct{} + + err error + timer *Timer +} + +func (c *timerCtx) cancel(err error) { + c.Lock() + defer c.Unlock() + if c.err != nil { + return // already canceled + } + c.err = err + close(c.done) + if c.timer != nil { + c.timer.Stop() + c.timer = nil + } +} + +func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true } + +func (c *timerCtx) Done() <-chan struct{} { return c.done } + +func (c *timerCtx) Err() error { return c.err } + +func (c *timerCtx) Value(key interface{}) interface{} { return c.parent.Value(key) } + +func (c *timerCtx) String() string { + return fmt.Sprintf("clock.WithDeadline(%s [%s])", c.deadline, c.deadline.Sub(c.clock.Now())) +} diff --git a/vendor/github.com/cenkalti/backoff/v4/.travis.yml b/vendor/github.com/cenkalti/backoff/v4/.travis.yml deleted file mode 100644 index c79105c..0000000 --- a/vendor/github.com/cenkalti/backoff/v4/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go -go: - - 1.13 - - 1.x - - tip -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover -script: - - $HOME/gopath/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/cenkalti/backoff/v4/retry.go b/vendor/github.com/cenkalti/backoff/v4/retry.go index 1ce2507..b9c0c51 100644 --- a/vendor/github.com/cenkalti/backoff/v4/retry.go +++ b/vendor/github.com/cenkalti/backoff/v4/retry.go @@ -5,10 +5,20 @@ import ( "time" ) +// An OperationWithData is executing by RetryWithData() or RetryNotifyWithData(). +// The operation will be retried using a backoff policy if it returns an error. +type OperationWithData[T any] func() (T, error) + // An Operation is executing by Retry() or RetryNotify(). // The operation will be retried using a backoff policy if it returns an error. type Operation func() error +func (o Operation) withEmptyData() OperationWithData[struct{}] { + return func() (struct{}, error) { + return struct{}{}, o() + } +} + // Notify is a notify-on-error function. It receives an operation error and // backoff delay if the operation failed (with an error). // @@ -28,18 +38,41 @@ func Retry(o Operation, b BackOff) error { return RetryNotify(o, b, nil) } +// RetryWithData is like Retry but returns data in the response too. +func RetryWithData[T any](o OperationWithData[T], b BackOff) (T, error) { + return RetryNotifyWithData(o, b, nil) +} + // RetryNotify calls notify function with the error and wait duration // for each failed attempt before sleep. func RetryNotify(operation Operation, b BackOff, notify Notify) error { return RetryNotifyWithTimer(operation, b, notify, nil) } +// RetryNotifyWithData is like RetryNotify but returns data in the response too. +func RetryNotifyWithData[T any](operation OperationWithData[T], b BackOff, notify Notify) (T, error) { + return doRetryNotify(operation, b, notify, nil) +} + // RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer // for each failed attempt before sleep. // A default timer that uses system timer is used when nil is passed. func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error { - var err error - var next time.Duration + _, err := doRetryNotify(operation.withEmptyData(), b, notify, t) + return err +} + +// RetryNotifyWithTimerAndData is like RetryNotifyWithTimer but returns data in the response too. +func RetryNotifyWithTimerAndData[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) { + return doRetryNotify(operation, b, notify, t) +} + +func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) { + var ( + err error + next time.Duration + res T + ) if t == nil { t = &defaultTimer{} } @@ -52,21 +85,22 @@ func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer b.Reset() for { - if err = operation(); err == nil { - return nil + res, err = operation() + if err == nil { + return res, nil } var permanent *PermanentError if errors.As(err, &permanent) { - return permanent.Err + return res, permanent.Err } if next = b.NextBackOff(); next == Stop { if cerr := ctx.Err(); cerr != nil { - return cerr + return res, cerr } - return err + return res, err } if notify != nil { @@ -77,7 +111,7 @@ func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer select { case <-ctx.Done(): - return ctx.Err() + return res, ctx.Err() case <-t.C(): } } diff --git a/vendor/github.com/paulmach/orb/CHANGELOG.md b/vendor/github.com/paulmach/orb/CHANGELOG.md index 70db8e8..fa7453c 100644 --- a/vendor/github.com/paulmach/orb/CHANGELOG.md +++ b/vendor/github.com/paulmach/orb/CHANGELOG.md @@ -2,6 +2,25 @@ All notable changes to this project will be documented in this file. +## [v0.10.0](https://github.com/paulmach/orb/compare/v0.9.2...v0.10.0) - 2023-07-16 + +### Added + +- add ChildrenInZoomRange method to maptile.Tile by [@peitili](https://github.com/peitili) in https://github.com/paulmach/orb/pull/133 + +## [v0.9.2](https://github.com/paulmach/orb/compare/v0.9.1...v0.9.2) - 2023-05-04 + +### Fixed + +- encoding/wkt: better handling/validation of missing parens by [@paulmach](https://github.com/paulmach) in https://github.com/paulmach/orb/pull/131 + +## [v0.9.1](https://github.com/paulmach/orb/compare/v0.9.0...v0.9.1) - 2023-04-26 + +### Fixed + +- Bump up mongo driver to 1.11.4 by [@m-pavel](https://github.com/m-pavel) in https://github.com/paulmach/orb/pull/129 +- encoding/wkt: split strings with regexp by [@m-pavel](https://github.com/m-pavel) in https://github.com/paulmach/orb/pull/128 + ## [v0.9.0](https://github.com/paulmach/orb/compare/v0.8.0...v0.9.0) - 2023-02-19 ### Added diff --git a/vendor/github.com/paulmach/orb/encoding/wkt/unmarshal.go b/vendor/github.com/paulmach/orb/encoding/wkt/unmarshal.go index e615352..b0d12f6 100644 --- a/vendor/github.com/paulmach/orb/encoding/wkt/unmarshal.go +++ b/vendor/github.com/paulmach/orb/encoding/wkt/unmarshal.go @@ -2,6 +2,7 @@ package wkt import ( "errors" + "regexp" "strconv" "strings" @@ -18,6 +19,10 @@ var ( // ErrUnsupportedGeometry is returned when geometry type is not supported by this lib. ErrUnsupportedGeometry = errors.New("wkt: unsupported geometry") + + doubleParen = regexp.MustCompile(`\)[\s|\t]*\)([\s|\t]*,[\s|\t]*)\([\s|\t]*\(`) + singleParen = regexp.MustCompile(`\)([\s|\t]*,[\s|\t]*)\(`) + noParen = regexp.MustCompile(`([\s|\t]*,[\s|\t]*)`) ) // UnmarshalPoint returns the point represented by the wkt string. @@ -120,19 +125,24 @@ func UnmarshalCollection(s string) (p orb.Collection, err error) { } // trimSpaceBrackets trim space and brackets -func trimSpaceBrackets(s string) string { +func trimSpaceBrackets(s string) (string, error) { s = strings.Trim(s, " ") if len(s) == 0 { - return "" + return "", nil } + if s[0] == '(' { s = s[1:] + } else { + return "", ErrNotWKT } + if s[len(s)-1] == ')' { s = s[:len(s)-1] + } else { + return "", ErrNotWKT } - - return strings.Trim(s, " ") + return strings.Trim(s, " "), nil } // parsePoint pase point by (x y) @@ -189,136 +199,214 @@ func Unmarshal(s string) (geom orb.Geometry, err error) { if s == "GEOMETRYCOLLECTION EMPTY" { return orb.Collection{}, nil } - s = strings.Replace(s, "GEOMETRYCOLLECTION", "", -1) + + s = strings.ReplaceAll(s, "GEOMETRYCOLLECTION", "") if len(s) == 0 { return nil, ErrNotWKT } - c := orb.Collection{} - ms := splitGeometryCollection(s) - if len(ms) == 0 { + + tc := orb.Collection{} + geometries := splitGeometryCollection(s) + if len(geometries) == 0 { return nil, err } - for _, v := range ms { - if len(v) == 0 { + + for _, g := range geometries { + if len(g) == 0 { continue } - g, err := Unmarshal(v) + + tg, err := Unmarshal(g) if err != nil { return nil, err } - c = append(c, g) + + tc = append(tc, tg) } - geom = c + + geom = tc case strings.Contains(s, "MULTIPOINT"): if s == "MULTIPOINT EMPTY" { return orb.MultiPoint{}, nil } - s = strings.Replace(s, "MULTIPOINT", "", -1) - s = trimSpaceBrackets(s) - ps := strings.Split(s, ",") - mp := orb.MultiPoint{} + + s, err := trimSpaceBrackets(strings.ReplaceAll(s, "MULTIPOINT", "")) + if err != nil { + return nil, err + } + + ps := splitByRegexp(s, noParen) + tmp := orb.MultiPoint{} for _, p := range ps { - tp, err := parsePoint(trimSpaceBrackets(p)) + p, err := trimSpaceBrackets(p) + if err != nil { + return nil, err + } + + tp, err := parsePoint(p) if err != nil { return nil, err } - mp = append(mp, tp) + + tmp = append(tmp, tp) } - geom = mp + + geom = tmp case strings.Contains(s, "POINT"): - s = strings.Replace(s, "POINT", "", -1) - tp, err := parsePoint(trimSpaceBrackets(s)) + s, err := trimSpaceBrackets(strings.ReplaceAll(s, "POINT", "")) if err != nil { return nil, err } + + tp, err := parsePoint(s) + if err != nil { + return nil, err + } + geom = tp case strings.Contains(s, "MULTILINESTRING"): if s == "MULTILINESTRING EMPTY" { return orb.MultiLineString{}, nil } - s = strings.Replace(s, "MULTILINESTRING", "", -1) - ml := orb.MultiLineString{} - for _, l := range strings.Split(trimSpaceBrackets(s), "),(") { - tl := orb.LineString{} - for _, p := range strings.Split(trimSpaceBrackets(l), ",") { - tp, err := parsePoint(trimSpaceBrackets(p)) + + s, err := trimSpaceBrackets(strings.ReplaceAll(s, "MULTILINESTRING", "")) + if err != nil { + return nil, err + } + + tmls := orb.MultiLineString{} + for _, ls := range splitByRegexp(s, singleParen) { + ls, err := trimSpaceBrackets(ls) + if err != nil { + return nil, err + } + + tls := orb.LineString{} + for _, p := range splitByRegexp(ls, noParen) { + tp, err := parsePoint(p) if err != nil { return nil, err } - tl = append(tl, tp) + tls = append(tls, tp) } - ml = append(ml, tl) + tmls = append(tmls, tls) } - geom = ml + + geom = tmls case strings.Contains(s, "LINESTRING"): if s == "LINESTRING EMPTY" { return orb.LineString{}, nil } - s = strings.Replace(s, "LINESTRING", "", -1) - s = trimSpaceBrackets(s) - ps := strings.Split(s, ",") - ls := orb.LineString{} - for _, p := range ps { - tp, err := parsePoint(trimSpaceBrackets(p)) + + s, err := trimSpaceBrackets(strings.ReplaceAll(s, "LINESTRING", "")) + if err != nil { + return nil, err + } + + ls := splitByRegexp(s, noParen) + tls := orb.LineString{} + for _, p := range ls { + tp, err := parsePoint(p) if err != nil { return nil, err } - ls = append(ls, tp) + + tls = append(tls, tp) } - geom = ls + + geom = tls case strings.Contains(s, "MULTIPOLYGON"): if s == "MULTIPOLYGON EMPTY" { return orb.MultiPolygon{}, nil } - s = strings.Replace(s, "MULTIPOLYGON", "", -1) - mpol := orb.MultiPolygon{} - for _, ps := range strings.Split(trimSpaceBrackets(s), ")),((") { - pol := orb.Polygon{} - for _, ls := range strings.Split(trimSpaceBrackets(ps), "),(") { - ring := orb.Ring{} - for _, p := range strings.Split(ls, ",") { - tp, err := parsePoint(trimSpaceBrackets(p)) + + s, err := trimSpaceBrackets(strings.ReplaceAll(s, "MULTIPOLYGON", "")) + if err != nil { + return nil, err + } + + tmpoly := orb.MultiPolygon{} + for _, poly := range splitByRegexp(s, doubleParen) { + poly, err := trimSpaceBrackets(poly) + if err != nil { + return nil, err + } + + tpoly := orb.Polygon{} + for _, r := range splitByRegexp(poly, singleParen) { + r, err := trimSpaceBrackets(r) + if err != nil { + return nil, err + } + + tr := orb.Ring{} + for _, p := range splitByRegexp(r, noParen) { + tp, err := parsePoint(p) if err != nil { return nil, err } - ring = append(ring, tp) + + tr = append(tr, tp) } - pol = append(pol, ring) + + tpoly = append(tpoly, tr) } - mpol = append(mpol, pol) + + tmpoly = append(tmpoly, tpoly) } - geom = mpol + + geom = tmpoly case strings.Contains(s, "POLYGON"): if s == "POLYGON EMPTY" { return orb.Polygon{}, nil } - s = strings.Replace(s, "POLYGON", "", -1) - s = trimSpaceBrackets(s) - - rs := strings.Split(s, "),(") - pol := make(orb.Polygon, 0, len(rs)) - for _, r := range rs { - ps := strings.Split(trimSpaceBrackets(r), ",") - ring := orb.Ring{} + + s, err := trimSpaceBrackets(strings.ReplaceAll(s, "POLYGON", "")) + if err != nil { + return nil, err + } + + rings := splitByRegexp(s, singleParen) + tpoly := make(orb.Polygon, 0, len(rings)) + for _, r := range rings { + r, err := trimSpaceBrackets(r) + if err != nil { + return nil, err + } + + ps := splitByRegexp(r, noParen) + tring := orb.Ring{} for _, p := range ps { - tp, err := parsePoint(trimSpaceBrackets(p)) + tp, err := parsePoint(p) if err != nil { return nil, err } - ring = append(ring, tp) + tring = append(tring, tp) } - pol = append(pol, ring) + tpoly = append(tpoly, tring) } - geom = pol + geom = tpoly default: return nil, ErrUnsupportedGeometry } return } + +func splitByRegexp(s string, re *regexp.Regexp) []string { + indexes := re.FindAllStringSubmatchIndex(s, -1) + start := 0 + result := make([]string, len(indexes)+1) + for i, element := range indexes { + result[i] = s[start:element[2]] + start = element[3] + } + result[len(indexes)] = s[start:] + return result +} diff --git a/vendor/github.com/tidwall/gjson/README.md b/vendor/github.com/tidwall/gjson/README.md index c8db11f..96b2e4d 100644 --- a/vendor/github.com/tidwall/gjson/README.md +++ b/vendor/github.com/tidwall/gjson/README.md @@ -211,6 +211,7 @@ There are currently the following built-in modifiers: - `@tostr`: Converts json to a string. Wraps a json string. - `@fromstr`: Converts a string from json. Unwraps a json string. - `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db). +- `@dig`: Search for a value without providing its entire path. See [e8e87f2](https://github.com/tidwall/gjson/commit/e8e87f2a00dc41f3aba5631094e21f59a8cf8cbf). ### Modifier arguments @@ -426,16 +427,6 @@ if result.Index > 0 { This is a best-effort no allocation sub slice of the original json. This method utilizes the `result.Index` field, which is the position of the raw data in the original json. It's possible that the value of `result.Index` equals zero, in which case the `result.Raw` is converted to a `[]byte`. -## Get multiple values at once - -The `GetMany` function can be used to get multiple values at the same time. - -```go -results := gjson.GetMany(json, "name.first", "name.last", "age") -``` - -The return value is a `[]Result`, which will always contain exactly the same number of items as the input paths. - ## Performance Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/), diff --git a/vendor/github.com/tidwall/gjson/SYNTAX.md b/vendor/github.com/tidwall/gjson/SYNTAX.md index 7a9b6a2..6721d7f 100644 --- a/vendor/github.com/tidwall/gjson/SYNTAX.md +++ b/vendor/github.com/tidwall/gjson/SYNTAX.md @@ -137,12 +137,21 @@ next major release.* The `~` (tilde) operator will convert a value to a boolean before comparison. +Supported tilde comparison type are: + +``` +~true Converts true-ish values to true +~false Converts false-ish and non-existent values to true +~null Converts null and non-existent values to true +~* Converts any existing value to true +``` + For example, using the following JSON: ```json { "vals": [ - { "a": 1, "b": true }, + { "a": 1, "b": "data" }, { "a": 2, "b": true }, { "a": 3, "b": false }, { "a": 4, "b": "0" }, @@ -157,15 +166,23 @@ For example, using the following JSON: } ``` -You can now query for all true(ish) or false(ish) values: +To query for all true-ish or false-ish values: ``` -vals.#(b==~true)#.a >> [1,2,6,7,8] +vals.#(b==~true)#.a >> [2,6,7,8] vals.#(b==~false)#.a >> [3,4,5,9,10,11] ``` The last value which was non-existent is treated as `false` +To query for null and explicit value existence: + +``` +vals.#(b==~null)#.a >> [10,11] +vals.#(b==~*)#.a >> [1,2,3,4,5,6,7,8,9,10] +vals.#(b!=~*)#.a >> [11] +``` + ### Dot vs Pipe The `.` is standard separator, but it's also possible to use a `|`. @@ -241,6 +258,7 @@ There are currently the following built-in modifiers: - `@tostr`: Converts json to a string. Wraps a json string. - `@fromstr`: Converts a string from json. Unwraps a json string. - `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db). +- `@dig`: Search for a value without providing its entire path. See [e8e87f2](https://github.com/tidwall/gjson/commit/e8e87f2a00dc41f3aba5631094e21f59a8cf8cbf). #### Modifier arguments diff --git a/vendor/github.com/tidwall/gjson/gjson.go b/vendor/github.com/tidwall/gjson/gjson.go index 53cbd23..7949825 100644 --- a/vendor/github.com/tidwall/gjson/gjson.go +++ b/vendor/github.com/tidwall/gjson/gjson.go @@ -645,9 +645,9 @@ func tostr(json string) (raw string, str string) { // Exists returns true if value exists. // -// if gjson.Get(json, "name.last").Exists(){ -// println("value exists") -// } +// if gjson.Get(json, "name.last").Exists(){ +// println("value exists") +// } func (t Result) Exists() bool { return t.Type != Null || len(t.Raw) != 0 } @@ -661,7 +661,6 @@ func (t Result) Exists() bool { // nil, for JSON null // map[string]interface{}, for JSON objects // []interface{}, for JSON arrays -// func (t Result) Value() interface{} { if t.Type == String { return t.Str @@ -826,19 +825,28 @@ func parseArrayPath(path string) (r arrayPathResult) { } // splitQuery takes a query and splits it into three parts: -// path, op, middle, and right. +// +// path, op, middle, and right. +// // So for this query: -// #(first_name=="Murphy").last +// +// #(first_name=="Murphy").last +// // Becomes -// first_name # path -// =="Murphy" # middle -// .last # right +// +// first_name # path +// =="Murphy" # middle +// .last # right +// // Or, -// #(service_roles.#(=="one")).cap +// +// #(service_roles.#(=="one")).cap +// // Becomes -// service_roles.#(=="one") # path -// # middle -// .cap # right +// +// service_roles.#(=="one") # path +// # middle +// .cap # right func parseQuery(query string) ( path, op, value, remain string, i int, vesc, ok bool, ) { @@ -1251,15 +1259,74 @@ func matchLimit(str, pattern string) bool { return matched } +func falseish(t Result) bool { + switch t.Type { + case Null: + return true + case False: + return true + case String: + b, err := strconv.ParseBool(strings.ToLower(t.Str)) + if err != nil { + return false + } + return !b + case Number: + return t.Num == 0 + default: + return false + } +} + +func trueish(t Result) bool { + switch t.Type { + case True: + return true + case String: + b, err := strconv.ParseBool(strings.ToLower(t.Str)) + if err != nil { + return false + } + return b + case Number: + return t.Num != 0 + default: + return false + } +} + +func nullish(t Result) bool { + return t.Type == Null +} + func queryMatches(rp *arrayPathResult, value Result) bool { rpv := rp.query.value - if len(rpv) > 0 && rpv[0] == '~' { - // convert to bool - rpv = rpv[1:] - if value.Bool() { - value = Result{Type: True} - } else { - value = Result{Type: False} + if len(rpv) > 0 { + if rpv[0] == '~' { + // convert to bool + rpv = rpv[1:] + var ish, ok bool + switch rpv { + case "*": + ish, ok = value.Exists(), true + case "null": + ish, ok = nullish(value), true + case "true": + ish, ok = trueish(value), true + case "false": + ish, ok = falseish(value), true + } + if ok { + rpv = "true" + if ish { + value = Result{Type: True} + } else { + value = Result{Type: False} + } + } else { + rpv = "" + value = Result{} + } } } if !value.Exists() { @@ -1918,23 +1985,23 @@ type parseContext struct { // the '#' character. // The dot and wildcard character can be escaped with '\'. // -// { -// "name": {"first": "Tom", "last": "Anderson"}, -// "age":37, -// "children": ["Sara","Alex","Jack"], -// "friends": [ -// {"first": "James", "last": "Murphy"}, -// {"first": "Roger", "last": "Craig"} -// ] -// } -// "name.last" >> "Anderson" -// "age" >> 37 -// "children" >> ["Sara","Alex","Jack"] -// "children.#" >> 3 -// "children.1" >> "Alex" -// "child*.2" >> "Jack" -// "c?ildren.0" >> "Sara" -// "friends.#.first" >> ["James","Roger"] +// { +// "name": {"first": "Tom", "last": "Anderson"}, +// "age":37, +// "children": ["Sara","Alex","Jack"], +// "friends": [ +// {"first": "James", "last": "Murphy"}, +// {"first": "Roger", "last": "Craig"} +// ] +// } +// "name.last" >> "Anderson" +// "age" >> 37 +// "children" >> ["Sara","Alex","Jack"] +// "children.#" >> 3 +// "children.1" >> "Alex" +// "child*.2" >> "Jack" +// "c?ildren.0" >> "Sara" +// "friends.#.first" >> ["James","Roger"] // // This function expects that the json is well-formed, and does not validate. // Invalid json will not panic, but it may return back unexpected results. @@ -2126,8 +2193,7 @@ func unescape(json string) string { // The caseSensitive paramater is used when the tokens are Strings. // The order when comparing two different type is: // -// Null < False < Number < String < True < JSON -// +// Null < False < Number < String < True < JSON func (t Result) Less(token Result, caseSensitive bool) bool { if t.Type < token.Type { return true @@ -2556,11 +2622,10 @@ func validnull(data []byte, i int) (outi int, ok bool) { // Valid returns true if the input is valid json. // -// if !gjson.Valid(json) { -// return errors.New("invalid json") -// } -// value := gjson.Get(json, "name.last") -// +// if !gjson.Valid(json) { +// return errors.New("invalid json") +// } +// value := gjson.Get(json, "name.last") func Valid(json string) bool { _, ok := validpayload(stringBytes(json), 0) return ok @@ -2568,13 +2633,12 @@ func Valid(json string) bool { // ValidBytes returns true if the input is valid json. // -// if !gjson.Valid(json) { -// return errors.New("invalid json") -// } -// value := gjson.Get(json, "name.last") +// if !gjson.Valid(json) { +// return errors.New("invalid json") +// } +// value := gjson.Get(json, "name.last") // // If working with bytes, this method preferred over ValidBytes(string(data)) -// func ValidBytes(json []byte) bool { _, ok := validpayload(json, 0) return ok @@ -2690,6 +2754,7 @@ func execModifier(json, path string) (pathOut, res string, ok bool) { var parsedArgs bool switch pathOut[0] { case '{', '[', '"': + // json arg res := Parse(pathOut) if res.Exists() { args = squash(pathOut) @@ -2698,14 +2763,20 @@ func execModifier(json, path string) (pathOut, res string, ok bool) { } } if !parsedArgs { - idx := strings.IndexByte(pathOut, '|') - if idx == -1 { - args = pathOut - pathOut = "" - } else { - args = pathOut[:idx] - pathOut = pathOut[idx:] + // simple arg + i := 0 + for ; i < len(pathOut); i++ { + if pathOut[i] == '|' { + break + } + switch pathOut[i] { + case '{', '[', '"', '(': + s := squash(pathOut[i:]) + i += len(s) - 1 + } } + args = pathOut[:i] + pathOut = pathOut[i:] } } return pathOut, fn(json, args), true @@ -2725,19 +2796,24 @@ func unwrap(json string) string { // DisableModifiers will disable the modifier syntax var DisableModifiers = false -var modifiers = map[string]func(json, arg string) string{ - "pretty": modPretty, - "ugly": modUgly, - "reverse": modReverse, - "this": modThis, - "flatten": modFlatten, - "join": modJoin, - "valid": modValid, - "keys": modKeys, - "values": modValues, - "tostr": modToStr, - "fromstr": modFromStr, - "group": modGroup, +var modifiers map[string]func(json, arg string) string + +func init() { + modifiers = map[string]func(json, arg string) string{ + "pretty": modPretty, + "ugly": modUgly, + "reverse": modReverse, + "this": modThis, + "flatten": modFlatten, + "join": modJoin, + "valid": modValid, + "keys": modKeys, + "values": modValues, + "tostr": modToStr, + "fromstr": modFromStr, + "group": modGroup, + "dig": modDig, + } } // AddModifier binds a custom modifier command to the GJSON syntax. @@ -2848,9 +2924,13 @@ func modReverse(json, arg string) string { } // @flatten an array with child arrays. -// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,[6,7]] +// +// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,[6,7]] +// // The {"deep":true} arg can be provide for deep flattening. -// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,6,7] +// +// [1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,6,7] +// // The original json is returned when the json is not an array. func modFlatten(json, arg string) string { res := Parse(json) @@ -2895,7 +2975,8 @@ func modFlatten(json, arg string) string { } // @keys extracts the keys from an object. -// {"first":"Tom","last":"Smith"} -> ["first","last"] +// +// {"first":"Tom","last":"Smith"} -> ["first","last"] func modKeys(json, arg string) string { v := Parse(json) if !v.Exists() { @@ -2922,7 +3003,8 @@ func modKeys(json, arg string) string { } // @values extracts the values from an object. -// {"first":"Tom","last":"Smith"} -> ["Tom","Smith"] +// +// {"first":"Tom","last":"Smith"} -> ["Tom","Smith"] func modValues(json, arg string) string { v := Parse(json) if !v.Exists() { @@ -2947,11 +3029,17 @@ func modValues(json, arg string) string { } // @join multiple objects into a single object. -// [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"} +// +// [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"} +// // The arg can be "true" to specify that duplicate keys should be preserved. -// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":37,"age":41} +// +// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":37,"age":41} +// // Without preserved keys: -// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":41} +// +// [{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":41} +// // The original json is returned when the json is not an object. func modJoin(json, arg string) string { res := Parse(json) @@ -3024,7 +3112,8 @@ func modValid(json, arg string) string { } // @fromstr converts a string to json -// "{\"id\":1023,\"name\":\"alert\"}" -> {"id":1023,"name":"alert"} +// +// "{\"id\":1023,\"name\":\"alert\"}" -> {"id":1023,"name":"alert"} func modFromStr(json, arg string) string { if !Valid(json) { return "" @@ -3033,7 +3122,8 @@ func modFromStr(json, arg string) string { } // @tostr converts a string to json -// {"id":1023,"name":"alert"} -> "{\"id\":1023,\"name\":\"alert\"}" +// +// {"id":1023,"name":"alert"} -> "{\"id\":1023,\"name\":\"alert\"}" func modToStr(str, arg string) string { return string(AppendJSONString(nil, str)) } @@ -3210,11 +3300,11 @@ func revSquash(json string) string { // Paths returns the original GJSON paths for a Result where the Result came // from a simple query path that returns an array, like: // -// gjson.Get(json, "friends.#.first") +// gjson.Get(json, "friends.#.first") // // The returned value will be in the form of a JSON array: // -// ["friends.0.first","friends.1.first","friends.2.first"] +// ["friends.0.first","friends.1.first","friends.2.first"] // // The param 'json' must be the original JSON used when calling Get. // @@ -3239,11 +3329,11 @@ func (t Result) Paths(json string) []string { // Path returns the original GJSON path for a Result where the Result came // from a simple path that returns a single value, like: // -// gjson.Get(json, "friends.#(last=Murphy)") +// gjson.Get(json, "friends.#(last=Murphy)") // // The returned value will be in the form of a JSON string: // -// "friends.0" +// "friends.0" // // The param 'json' must be the original JSON used when calling Get. // @@ -3320,7 +3410,7 @@ func (t Result) Path(json string) string { if !rcomp.Exists() { goto fail } - comp := escapeComp(rcomp.String()) + comp := Escape(rcomp.String()) path = append(path, '.') path = append(path, comp...) } @@ -3335,17 +3425,31 @@ fail: // isSafePathKeyChar returns true if the input character is safe for not // needing escaping. func isSafePathKeyChar(c byte) bool { - return c <= ' ' || c > '~' || c == '_' || c == '-' || c == ':' || - (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c <= ' ' || c > '~' || c == '_' || + c == '-' || c == ':' } -// escapeComp escaped a path compontent, making it safe for generating a -// path for later use. -func escapeComp(comp string) string { +// Escape returns an escaped path component. +// +// json := `{ +// "user":{ +// "first.name": "Janet", +// "last.name": "Prichard" +// } +// }` +// user := gjson.Get(json, "user") +// println(user.Get(gjson.Escape("first.name")) +// println(user.Get(gjson.Escape("last.name")) +// // Output: +// // Janet +// // Prichard +func Escape(comp string) string { for i := 0; i < len(comp); i++ { if !isSafePathKeyChar(comp[i]) { - ncomp := []byte(comp[:i]) + ncomp := make([]byte, len(comp)+1) + copy(ncomp, comp[:i]) + ncomp = ncomp[:i] for ; i < len(comp); i++ { if !isSafePathKeyChar(comp[i]) { ncomp = append(ncomp, '\\') @@ -3357,3 +3461,30 @@ func escapeComp(comp string) string { } return comp } + +func parseRecursiveDescent(all []Result, parent Result, path string) []Result { + if res := parent.Get(path); res.Exists() { + all = append(all, res) + } + if parent.IsArray() || parent.IsObject() { + parent.ForEach(func(_, val Result) bool { + all = parseRecursiveDescent(all, val, path) + return true + }) + } + return all +} + +func modDig(json, arg string) string { + all := parseRecursiveDescent(nil, Parse(json), arg) + var out []byte + out = append(out, '[') + for i, res := range all { + if i > 0 { + out = append(out, ',') + } + out = append(out, res.Raw...) + } + out = append(out, ']') + return string(out) +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-id/id.go b/vendor/github.com/whosonfirst/go-whosonfirst-id/id.go index 0023f5d..d383e48 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-id/id.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-id/id.go @@ -1,17 +1,15 @@ package id -// The two import statements to ensure that packages are loaded -// in the correct order. - import ( _ "github.com/aaronland/go-uid-whosonfirst" + _ "github.com/aaronland/go-uid-proxy" ) import ( "context" "fmt" + "github.com/aaronland/go-uid" - _ "github.com/aaronland/go-uid-proxy" ) // type Provider is an interface for providing uniquer identifiers. diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/directory.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/directory.go index fed1e7c..0224d3e 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/directory.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/directory.go @@ -3,10 +3,11 @@ package emitter import ( "context" "fmt" - "github.com/whosonfirst/go-whosonfirst-crawl" - "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" "os" "path/filepath" + + "github.com/whosonfirst/go-whosonfirst-crawl" + "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" ) func init() { @@ -98,7 +99,7 @@ func (idx *DirectoryEmitter) WalkURI(ctx context.Context, index_cb EmitterCallba err = index_cb(ctx, path, fh) if err != nil { - return fmt.Errorf("Failed to invoke callback fir '%s', %w", abs_path, err) + return fmt.Errorf("Failed to invoke callback for '%s', %w", abs_path, err) } return nil diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/featurecollection.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/featurecollection.go index 18a1542..560c95c 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/featurecollection.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/featurecollection.go @@ -5,9 +5,10 @@ import ( "context" "encoding/json" "fmt" + "io" + "github.com/whosonfirst/go-ioutil" "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" - "io" ) func init() { diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/file.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/file.go index d9c3f82..e37b270 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/file.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/file.go @@ -3,6 +3,7 @@ package emitter import ( "context" "fmt" + "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" ) diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/filelist.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/filelist.go index bc91299..45350a7 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/filelist.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/filelist.go @@ -4,8 +4,9 @@ import ( "bufio" "context" "fmt" - "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" "path/filepath" + + "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" ) func init() { diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/geojsonls.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/geojsonls.go index 11886b1..0f731f5 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/geojsonls.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/geojsonls.go @@ -5,9 +5,10 @@ import ( "bytes" "context" "fmt" + "io" + "github.com/whosonfirst/go-ioutil" "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" - "io" ) func init() { diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/query.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/query.go index 1d4aac5..2ce65c8 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/query.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/query.go @@ -3,9 +3,10 @@ package filters import ( "context" "fmt" - "github.com/aaronland/go-json-query" "io" "net/url" + + "github.com/aaronland/go-json-query" ) // type QueryFilters implements the `Filters` interface for filtering documents using `aaronland/go-json-query` query strings. @@ -50,8 +51,33 @@ func NewQueryFiltersFromQuery(ctx context.Context, q url.Values) (Filters, error f := &QueryFilters{} - includes := q["include"] - excludes := q["exclude"] + q_includes := q["include"] + q_excludes := q["exclude"] + + includes := make([]string, len(q_includes)) + excludes := make([]string, len(q_excludes)) + + for idx, q_enc := range q_includes { + + q, err := url.QueryUnescape(q_enc) + + if err != nil { + return nil, fmt.Errorf("Failed to unescape '%s' include parameter, %w", q_enc, err) + } + + includes[idx] = q + } + + for idx, q_enc := range q_excludes { + + q, err := url.QueryUnescape(q_enc) + + if err != nil { + return nil, fmt.Errorf("Failed to unescape '%s' exclude parameter, %w", q_enc, err) + } + + excludes[idx] = q + } if len(includes) > 0 { diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator/iterator.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator/iterator.go index 9291f6f..c877d4b 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator/iterator.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator/iterator.go @@ -6,7 +6,6 @@ package iterator import ( "context" "fmt" - "github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter" "io" "log" "net/url" @@ -15,6 +14,8 @@ import ( "strconv" "sync/atomic" "time" + + "github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter" ) // type Iterator provides a struct that can be used for iterating over a collection of records diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-writer/v3/writer.go b/vendor/github.com/whosonfirst/go-whosonfirst-writer/v3/writer.go index 22d4cb0..154329a 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-writer/v3/writer.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-writer/v3/writer.go @@ -4,8 +4,10 @@ import ( "bytes" "context" "fmt" + "github.com/paulmach/orb/geojson" "github.com/whosonfirst/go-whosonfirst-export/v2" + "github.com/whosonfirst/go-whosonfirst-feature/alt" "github.com/whosonfirst/go-whosonfirst-feature/properties" "github.com/whosonfirst/go-whosonfirst-uri" go_writer "github.com/whosonfirst/go-writer/v3" @@ -62,12 +64,36 @@ func WriteBytesWithExporter(ctx context.Context, wr go_writer.Writer, ex export. return -1, fmt.Errorf("Failed to derive ID, %w", err) } - rel_path, err := uri.Id2RelPath(id) + // START OF put me in a function somewhere... + + var rel_path string + + if alt.IsAlt(body) { + + alt_label, err := properties.AltLabel(body) + + if err != nil { + return -1, fmt.Errorf("Failed to derive alt label, %w", err) + } + + uri_args, err := uri.NewAlternateURIArgsFromAltLabel(alt_label) + + if err != nil { + return -1, fmt.Errorf("Failed to derive URI args from label '%s', %w", alt_label, err) + } + + rel_path, err = uri.Id2RelPath(id, uri_args) + + } else { + rel_path, err = uri.Id2RelPath(id) + } if err != nil { return -1, fmt.Errorf("Failed to derive relative path, %w", err) } + // END OF put me in a function somewhere... + br := bytes.NewReader(body) _, err = wr.Write(ctx, rel_path, br) diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go index be3f208..da1ae18 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_codec.go @@ -326,7 +326,12 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r } field = field.Addr() - dctx := DecodeContext{Registry: r.Registry, Truncate: fd.truncate || r.Truncate} + dctx := DecodeContext{ + Registry: r.Registry, + Truncate: fd.truncate || r.Truncate, + defaultDocumentType: r.defaultDocumentType, + } + if fd.decoder == nil { return newDecodeError(fd.name, ErrNoDecoder{Type: field.Elem().Type()}) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/value.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/value.go index 54aa617..789d2b9 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/value.go +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/value.go @@ -323,7 +323,7 @@ func (v Value) String() string { if !ok { return "" } - return fmt.Sprintf(`{"$timestamp":{"t":"%s","i":"%s"}}`, strconv.FormatUint(uint64(t), 10), strconv.FormatUint(uint64(i), 10)) + return fmt.Sprintf(`{"$timestamp":{"t":%v,"i":%v}}`, t, i) case bsontype.Int64: i64, ok := v.Int64OK() if !ok { diff --git a/vendor/go.uber.org/ratelimit/.gitignore b/vendor/go.uber.org/ratelimit/.gitignore index aa346ac..23bd489 100644 --- a/vendor/go.uber.org/ratelimit/.gitignore +++ b/vendor/go.uber.org/ratelimit/.gitignore @@ -2,5 +2,10 @@ /vendor cover.html cover.out +profile.out +stat.csv +stat.txt +stat.html *.swp +.idea diff --git a/vendor/go.uber.org/ratelimit/CHANGELOG.md b/vendor/go.uber.org/ratelimit/CHANGELOG.md index b2b89cf..e7ef957 100644 --- a/vendor/go.uber.org/ratelimit/CHANGELOG.md +++ b/vendor/go.uber.org/ratelimit/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## v0.3.0 - 2023-07-08 +### Changed +- Switched to a more efficient internal implementation. No API or behavior changes. + [#100](https://github.com/uber-go/ratelimit/pull/100) + ## v0.2.0 - 2021-03-02 ### Added - Allow configuring the limiter with custom slack. diff --git a/vendor/go.uber.org/ratelimit/Makefile b/vendor/go.uber.org/ratelimit/Makefile index 5bab5d7..7eb6d24 100644 --- a/vendor/go.uber.org/ratelimit/Makefile +++ b/vendor/go.uber.org/ratelimit/Makefile @@ -6,8 +6,18 @@ GO_FILES := $(shell \ -o -name '*.go' -print | cut -b3-) .PHONY: bench -bench: - go test -bench=. ./... +bench: bin/benchstat bin/benchart + go test -timeout 3h -count=5 -run=xxx -bench=BenchmarkRateLimiter ./... | tee stat.txt + @$(GOBIN)/benchstat stat.txt + @$(GOBIN)/benchstat -csv stat.txt > stat.csv + @$(GOBIN)/benchart 'RateLimiter;xAxisType=log' stat.csv stat.html + @open stat.html + +bin/benchstat: tools/go.mod + @cd tools && go install golang.org/x/perf/cmd/benchstat + +bin/benchart: tools/go.mod + @cd tools && go install github.com/storozhukBM/benchart bin/golint: tools/go.mod @cd tools && go install golang.org/x/lint/golint diff --git a/vendor/go.uber.org/ratelimit/README.md b/vendor/go.uber.org/ratelimit/README.md index a05a2a8..84a273f 100644 --- a/vendor/go.uber.org/ratelimit/README.md +++ b/vendor/go.uber.org/ratelimit/README.md @@ -39,8 +39,20 @@ func main() { } ``` +## FAQ: +- What's the major diff v.s. https://pkg.go.dev/golang.org/x/time/rate? (based on #77) + + This ratelimiter was meant to have a (1) simple API and (2) minimal overhead. For more complex use-cases [x/time/rate] is a great choice. See [here][redit] for historical context, and [here][bench] for benchmarks (from 2016). + +- Why does example_test.go fail when I run it locally on Windows? (based on #80) + + Windows has some known issues with timers precision. See golang/go#44343. We don't expect to work around it. + [cov-img]: https://codecov.io/gh/uber-go/ratelimit/branch/master/graph/badge.svg?token=zhLeUjjrm2 [cov]: https://codecov.io/gh/uber-go/ratelimit [doc-img]: https://pkg.go.dev/badge/go.uber.org/ratelimit [doc]: https://pkg.go.dev/go.uber.org/ratelimit [test-img]: https://github.com/uber-go/ratelimit/workflows/test/badge.svg +[redit]: https://www.reddit.com/r/golang/comments/59k2bi/ubergoratelimit_a_golang_blocking_leakybucket/d99ob9q +[x/time/rate]: https://pkg.go.dev/golang.org/x/time/rate +[bench]: https://gist.github.com/prashantv/26016a7dbc6fc1ec52d8c2b6591f3582 diff --git a/vendor/go.uber.org/ratelimit/limiter_atomic.go b/vendor/go.uber.org/ratelimit/limiter_atomic.go index 745aa4c..ac6465c 100644 --- a/vendor/go.uber.org/ratelimit/limiter_atomic.go +++ b/vendor/go.uber.org/ratelimit/limiter_atomic.go @@ -64,7 +64,7 @@ func newAtomicBased(rate int, opts ...Option) *atomicLimiter { } // Take blocks to ensure that the time spent between multiple -// Take calls is on average time.Second/rate. +// Take calls is on average per/rate. func (t *atomicLimiter) Take() time.Time { var ( newState state diff --git a/vendor/go.uber.org/ratelimit/limiter_atomic_int64.go b/vendor/go.uber.org/ratelimit/limiter_atomic_int64.go new file mode 100644 index 0000000..8f2e66c --- /dev/null +++ b/vendor/go.uber.org/ratelimit/limiter_atomic_int64.go @@ -0,0 +1,93 @@ +// Copyright (c) 2022 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package ratelimit // import "go.uber.org/ratelimit" + +import ( + "time" + + "sync/atomic" +) + +type atomicInt64Limiter struct { + //lint:ignore U1000 Padding is unused but it is crucial to maintain performance + // of this rate limiter in case of collocation with other frequently accessed memory. + prepadding [64]byte // cache line size = 64; created to avoid false sharing. + state int64 // unix nanoseconds of the next permissions issue. + //lint:ignore U1000 like prepadding. + postpadding [56]byte // cache line size - state size = 64 - 8; created to avoid false sharing. + + perRequest time.Duration + maxSlack time.Duration + clock Clock +} + +// newAtomicBased returns a new atomic based limiter. +func newAtomicInt64Based(rate int, opts ...Option) *atomicInt64Limiter { + // TODO consider moving config building to the implementation + // independent code. + config := buildConfig(opts) + perRequest := config.per / time.Duration(rate) + l := &atomicInt64Limiter{ + perRequest: perRequest, + maxSlack: time.Duration(config.slack) * perRequest, + clock: config.clock, + } + atomic.StoreInt64(&l.state, 0) + return l +} + +// Take blocks to ensure that the time spent between multiple +// Take calls is on average time.Second/rate. +func (t *atomicInt64Limiter) Take() time.Time { + var ( + newTimeOfNextPermissionIssue int64 + now int64 + ) + for { + now = t.clock.Now().UnixNano() + timeOfNextPermissionIssue := atomic.LoadInt64(&t.state) + + switch { + case timeOfNextPermissionIssue == 0 || (t.maxSlack == 0 && now-timeOfNextPermissionIssue > int64(t.perRequest)): + // if this is our first call or t.maxSlack == 0 we need to shrink issue time to now + newTimeOfNextPermissionIssue = now + case t.maxSlack > 0 && now-timeOfNextPermissionIssue > int64(t.maxSlack): + // a lot of nanoseconds passed since the last Take call + // we will limit max accumulated time to maxSlack + newTimeOfNextPermissionIssue = now - int64(t.maxSlack) + default: + // calculate the time at which our permission was issued + newTimeOfNextPermissionIssue = timeOfNextPermissionIssue + int64(t.perRequest) + } + + if atomic.CompareAndSwapInt64(&t.state, timeOfNextPermissionIssue, newTimeOfNextPermissionIssue) { + break + } + } + + sleepDuration := time.Duration(newTimeOfNextPermissionIssue - now) + if sleepDuration > 0 { + t.clock.Sleep(sleepDuration) + return time.Unix(0, newTimeOfNextPermissionIssue) + } + // return now if we don't sleep as atomicLimiter does + return time.Unix(0, now) +} diff --git a/vendor/go.uber.org/ratelimit/limiter_mutexbased.go b/vendor/go.uber.org/ratelimit/limiter_mutexbased.go index 1408f1c..62c5a73 100644 --- a/vendor/go.uber.org/ratelimit/limiter_mutexbased.go +++ b/vendor/go.uber.org/ratelimit/limiter_mutexbased.go @@ -49,7 +49,7 @@ func newMutexBased(rate int, opts ...Option) *mutexLimiter { } // Take blocks to ensure that the time spent between multiple -// Take calls is on average time.Second/rate. +// Take calls is on average per/rate. func (t *mutexLimiter) Take() time.Time { t.Lock() defer t.Unlock() diff --git a/vendor/go.uber.org/ratelimit/ratelimit.go b/vendor/go.uber.org/ratelimit/ratelimit.go index b5b16e5..22b88ec 100644 --- a/vendor/go.uber.org/ratelimit/ratelimit.go +++ b/vendor/go.uber.org/ratelimit/ratelimit.go @@ -23,7 +23,7 @@ package ratelimit // import "go.uber.org/ratelimit" import ( "time" - "github.com/andres-erbsen/clock" + "github.com/benbjohnson/clock" ) // Note: This file is inspired by: @@ -54,7 +54,7 @@ type config struct { // New returns a Limiter that will limit to the given RPS. func New(rate int, opts ...Option) Limiter { - return newAtomicBased(rate, opts...) + return newAtomicInt64Based(rate, opts...) } // buildConfig combines defaults with options. diff --git a/vendor/modules.txt b/vendor/modules.txt index 0f8155f..de5b04e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,12 +1,15 @@ # github.com/aaronland/go-artisanal-integers v0.9.1 ## explicit; go 1.16 github.com/aaronland/go-artisanal-integers/client -# github.com/aaronland/go-brooklynintegers-api v1.2.6 -## explicit; go 1.16 +# github.com/aaronland/go-brooklynintegers-api v1.2.7 +## explicit; go 1.18 github.com/aaronland/go-brooklynintegers-api -# github.com/aaronland/go-json-query v0.1.3 +# github.com/aaronland/go-json-query v0.1.4 ## explicit; go 1.18 github.com/aaronland/go-json-query +# github.com/aaronland/go-log/v2 v2.0.0 +## explicit; go 1.18 +github.com/aaronland/go-log/v2 # github.com/aaronland/go-pool/v2 v2.0.0 ## explicit; go 1.18 github.com/aaronland/go-pool/v2 @@ -20,23 +23,23 @@ github.com/aaronland/go-sqlite/database # github.com/aaronland/go-string v1.0.0 ## explicit; go 1.16 github.com/aaronland/go-string/random -# github.com/aaronland/go-uid v0.3.0 +# github.com/aaronland/go-uid v0.4.0 ## explicit; go 1.18 github.com/aaronland/go-uid -# github.com/aaronland/go-uid-artisanal v0.0.2 +# github.com/aaronland/go-uid-artisanal v0.0.4 ## explicit; go 1.18 github.com/aaronland/go-uid-artisanal -# github.com/aaronland/go-uid-proxy v0.0.2 +# github.com/aaronland/go-uid-proxy v0.1.1 ## explicit; go 1.18 github.com/aaronland/go-uid-proxy -# github.com/aaronland/go-uid-whosonfirst v0.0.2 +# github.com/aaronland/go-uid-whosonfirst v0.0.4 ## explicit; go 1.18 github.com/aaronland/go-uid-whosonfirst -# github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 -## explicit -github.com/andres-erbsen/clock -# github.com/cenkalti/backoff/v4 v4.1.3 -## explicit; go 1.13 +# github.com/benbjohnson/clock v1.3.0 +## explicit; go 1.15 +github.com/benbjohnson/clock +# github.com/cenkalti/backoff/v4 v4.2.1 +## explicit; go 1.18 github.com/cenkalti/backoff/v4 # github.com/g8rswimmer/error-chain v1.0.0 ## explicit @@ -53,7 +56,7 @@ github.com/mattn/go-sqlite3 # github.com/natefinch/atomic v1.0.1 ## explicit; go 1.12 github.com/natefinch/atomic -# github.com/paulmach/orb v0.9.0 +# github.com/paulmach/orb v0.10.0 ## explicit; go 1.15 github.com/paulmach/orb github.com/paulmach/orb/encoding/wkt @@ -71,14 +74,14 @@ github.com/sfomuseum/go-edtf/level2 github.com/sfomuseum/go-edtf/parser github.com/sfomuseum/go-edtf/re github.com/sfomuseum/go-edtf/tests -# github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.7 -## explicit; go 1.16 +# github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.8 +## explicit; go 1.18 github.com/sfomuseum/go-sfomuseum-export/v2 github.com/sfomuseum/go-sfomuseum-export/v2/properties -# github.com/sfomuseum/go-sfomuseum-writer/v3 v3.0.0 +# github.com/sfomuseum/go-sfomuseum-writer/v3 v3.0.1 ## explicit; go 1.18 github.com/sfomuseum/go-sfomuseum-writer/v3 -# github.com/tidwall/gjson v1.14.4 +# github.com/tidwall/gjson v1.17.0 ## explicit; go 1.12 github.com/tidwall/gjson # github.com/tidwall/match v1.1.1 @@ -102,7 +105,7 @@ github.com/whosonfirst/go-rfc-5646 # github.com/whosonfirst/go-whosonfirst-crawl v0.2.2 ## explicit; go 1.18 github.com/whosonfirst/go-whosonfirst-crawl -# github.com/whosonfirst/go-whosonfirst-export/v2 v2.7.0 +# github.com/whosonfirst/go-whosonfirst-export/v2 v2.7.1 ## explicit; go 1.18 github.com/whosonfirst/go-whosonfirst-export/v2 github.com/whosonfirst/go-whosonfirst-export/v2/properties @@ -118,10 +121,10 @@ github.com/whosonfirst/go-whosonfirst-flags/existential # github.com/whosonfirst/go-whosonfirst-format v0.4.1 ## explicit; go 1.16 github.com/whosonfirst/go-whosonfirst-format -# github.com/whosonfirst/go-whosonfirst-id v1.2.0 +# github.com/whosonfirst/go-whosonfirst-id v1.2.2 ## explicit; go 1.18 github.com/whosonfirst/go-whosonfirst-id -# github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.3.2 +# github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.3.4 ## explicit; go 1.18 github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter github.com/whosonfirst/go-whosonfirst-iterate/v2/filters @@ -153,7 +156,7 @@ github.com/whosonfirst/go-whosonfirst-sqlite-index/v3 # github.com/whosonfirst/go-whosonfirst-uri v1.3.0 ## explicit; go 1.13 github.com/whosonfirst/go-whosonfirst-uri -# github.com/whosonfirst/go-whosonfirst-writer/v3 v3.0.0 +# github.com/whosonfirst/go-whosonfirst-writer/v3 v3.1.0 ## explicit; go 1.18 github.com/whosonfirst/go-whosonfirst-writer/v3 # github.com/whosonfirst/go-writer/v3 v3.1.0 @@ -162,7 +165,7 @@ github.com/whosonfirst/go-writer/v3 # github.com/whosonfirst/walk v0.0.2 ## explicit; go 1.18 github.com/whosonfirst/walk -# go.mongodb.org/mongo-driver v1.11.1 +# go.mongodb.org/mongo-driver v1.11.4 ## explicit; go 1.13 go.mongodb.org/mongo-driver/bson go.mongodb.org/mongo-driver/bson/bsoncodec @@ -171,6 +174,6 @@ go.mongodb.org/mongo-driver/bson/bsonrw go.mongodb.org/mongo-driver/bson/bsontype go.mongodb.org/mongo-driver/bson/primitive go.mongodb.org/mongo-driver/x/bsonx/bsoncore -# go.uber.org/ratelimit v0.2.0 -## explicit; go 1.14 +# go.uber.org/ratelimit v0.3.0 +## explicit; go 1.18 go.uber.org/ratelimit