diff --git a/Makefile b/Makefile index cbecb05..ace9724 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ srv: srv.go internal/*/*.go internal/*/*/*.go - go build -o srv -ldflags '-w -linkmode external -extldflags "-static"' ./ - #go build -o srv ./ + #go build -o srv -ldflags '-w -linkmode external -extldflags "-static"' ./ + go build -o srv ./ go-test: go test ./... diff --git a/README.md b/README.md index 063e505..57b205a 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ You can access the service from a shell or from a Web browser like this: Here is an example weather report: -![Weather Report](San_Francisco.png) +![Weather Report](share/pics/San_Francisco.png) Or in PowerShell: diff --git a/config/services/services.yaml b/config/services/services.yaml new file mode 100644 index 0000000..59affe7 --- /dev/null +++ b/config/services/services.yaml @@ -0,0 +1,37 @@ +services: + - name: "main server" + command: "while true; do sudo /wttr.in/bin/srv big-cache.yaml ; sleep 5; done" + workdir: "$HOME" + port: ... + + - name: "geo server" + command: "while true; do /wttr.in/bin/srv geo.yaml; sleep 5; done" + workdir: "$HOME" + env: + - NOMINATIM_OPENCAGE + port: 8085 + + - name: "proxy" + command: ve/bin/python3 bin/proxy.py + workdir: "/wttr.in/wttr.in-v2-v2" + port: 5001 + + - name: "format=j1" + command: "WTTRIN_SRV_PORT=9003 ve/bin/python3 bin/srv.py" + workdir: "/wttr.in/wttr.in-v2-v2" + port: 9003 + + - name: "format=line" + command: "WTTRIN_SRV_PORT=9004 ve/bin/python3 bin/srv.py" + workdir: "/wttr.in/wttr.in-v2-v2" + port: 9004 + + - name: "format=v1" + command: "WTTRIN_SRV_PORT=9005 ve/bin/python3 bin/srv.py" + workdir: "/wttr.in/wttr.in-v2-v2" + port: 9005 + + - name: "filetype=png" + command: "WTTRIN_SRV_PORT=9006 ve/bin/python3 bin/srv.py" + workdir: "/wttr.in/wttr.in-v2-v2" + port: 9006 diff --git a/go.mod b/go.mod index 3aca09f..2de6e45 100644 --- a/go.mod +++ b/go.mod @@ -3,24 +3,27 @@ module github.com/chubin/wttr.in go 1.16 require ( - github.com/alecthomas/kong v0.7.1 // indirect + github.com/alecthomas/kong v1.7.0 github.com/denisenkom/go-mssqldb v0.0.0-20200910202707-1e08a3fab204 // indirect github.com/go-sql-driver/mysql v1.5.0 // indirect github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect - github.com/hashicorp/golang-lru v0.6.0 + github.com/hashicorp/golang-lru v1.0.2 github.com/itchyny/gojq v0.12.11 // indirect - github.com/klauspost/lctime v0.1.0 // indirect + github.com/klauspost/lctime v0.1.0 github.com/lib/pq v1.8.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/mattn/go-sqlite3 v1.14.16 // indirect + github.com/mattn/go-colorable v0.1.14 + github.com/mattn/go-runewidth v0.0.16 + github.com/mattn/go-sqlite3 v1.14.24 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron v1.2.0 - github.com/samonzeweb/godb v1.0.8 // indirect - github.com/sirupsen/logrus v1.9.0 // indirect + github.com/samonzeweb/godb v1.0.13 + github.com/sirupsen/logrus v1.9.3 github.com/smartystreets/assertions v1.2.0 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect github.com/stretchr/testify v1.8.1 // indirect - github.com/zsefvlol/timezonemapper v1.0.0 // indirect + github.com/zsefvlol/timezonemapper v1.0.0 golang.org/x/crypto v0.17.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + golang.org/x/sys v0.30.0 // indirect + google.golang.org/appengine v1.6.3 // indirect + gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 7e4f2e4..02cc5ec 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,27 @@ github.com/alecthomas/assert/v2 v2.1.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4= github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= +github.com/alecthomas/kong v1.7.0 h1:MnT8+5JxFDCvISeI6vgd/mFbAJwueJ/pqQNzZMsiqZE= +github.com/alecthomas/kong v1.7.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU= github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 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= +github.com/denisenkom/go-mssqldb v0.0.0-20190920000552-128d9f4ae1cd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.0.0-20200910202707-1e08a3fab204/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/itchyny/gojq v0.12.11 h1:YhLueoHhHiN4mkfM+3AyJV6EPcCxKZsOnYf+aVSwaQw= github.com/itchyny/gojq v0.12.11/go.mod h1:o3FT8Gkbg/geT4pLI0tF3hvip5F3Y/uskjRz9OYa38g= @@ -21,31 +30,48 @@ github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2s github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/klauspost/lctime v0.1.0 h1:nINsuFc860M9cyYhT6vfg6U1USh7kiVBj/s/2b04U70= github.com/klauspost/lctime v0.1.0/go.mod h1:OwdMhr8tbQvusAsnilqkkgDQqivWlqyg0w5cfXkLiDk= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/samonzeweb/godb v1.0.8 h1:WRn6nq0FChYOzh+w8SgpXHUkEhL7W6ZqkCf5Ninx7Uc= github.com/samonzeweb/godb v1.0.8/go.mod h1:LNDt3CakfBwpRY4AD0y/QPTbj+jB6O17tSxQES0p47o= +github.com/samonzeweb/godb v1.0.13 h1:dEWijZGizhSN7oOLFYq0+NquG54DCJ9WG55bEcH7GOA= +github.com/samonzeweb/godb v1.0.13/go.mod h1:Dcm9f9+aO6bQin4Ce4X3oOM2gvhGMt2naLIDLPQSaWQ= github.com/samonzeweb/godb v1.0.15 h1:HyNb8o1w109as9KWE8ih1YIBe8jC4luJ22f1XNacW38= github.com/samonzeweb/godb v1.0.15/go.mod h1:SxCHqyireDXNrZApknS9lGUEutA43x9eJF632ecbK5Q= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -56,26 +82,72 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zsefvlol/timezonemapper v1.0.0 h1:HXqkOzf01gXYh2nDQcDSROikFgMaximnhE8BY9SyF6E= github.com/zsefvlol/timezonemapper v1.0.0/go.mod h1:cVUCOLEmc/VvOMusEhpd2G/UBtadL26ZVz2syODXDoQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.3/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/config/config.go b/internal/config/config.go index f96df4a..efc44c9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -62,6 +62,10 @@ type Uplink struct { // for all other queries. Address3 string `yaml:"address3,omitempty"` + // Address4 contains address of the uplink server in form IP:PORT + // for PNG queries. + Address4 string `yaml:"address4,omitempty"` + // Timeout for upstream queries. Timeout int `yaml:"timeout,omitempty"` @@ -152,6 +156,7 @@ func Default() *Config { Address1: "127.0.0.1:9002", Address2: "127.0.0.1:9002", Address3: "127.0.0.1:9002", + Address4: "127.0.0.1:9002", Timeout: 30, PrefetchInterval: 300, }, diff --git a/internal/processor/j1.go b/internal/processor/j1.go index f6afce7..bf23ff6 100644 --- a/internal/processor/j1.go +++ b/internal/processor/j1.go @@ -9,7 +9,7 @@ import ( "time" ) -func getAny(req *http.Request, tr1, tr2, tr3 *http.Transport) (*ResponseWithHeader, error) { +func getAny(req *http.Request, tr1, tr2, tr3, tr4 *http.Transport) (*ResponseWithHeader, error) { uri := strings.ReplaceAll(req.URL.RequestURI(), "%", "%25") u, err := url.Parse(uri) @@ -28,6 +28,10 @@ func getAny(req *http.Request, tr1, tr2, tr3 *http.Transport) (*ResponseWithHead // log.Println(req.URL.Query()) // log.Println() + if checkURLForPNG(req) { + return getDefault(req, tr4) + } + return getDefault(req, tr3) } @@ -87,3 +91,8 @@ func getUpstream(req *http.Request, transport *http.Transport) (*ResponseWithHea StatusCode: res.StatusCode, }, nil } + +func checkURLForPNG(r *http.Request) bool { + url := r.URL.String() + return strings.Contains(url, ".png") && !strings.Contains(url, "/files/") +} diff --git a/internal/processor/processor.go b/internal/processor/processor.go index e9bf886..9bc7e65 100644 --- a/internal/processor/processor.go +++ b/internal/processor/processor.go @@ -60,6 +60,7 @@ type RequestProcessor struct { upstreamTransport1 *http.Transport upstreamTransport2 *http.Transport upstreamTransport3 *http.Transport + upstreamTransport4 *http.Transport config *config.Config geoIPCache *geoip.Cache geoLocation *geoloc.Cache @@ -93,6 +94,11 @@ func NewRequestProcessor(config *config.Config) (*RequestProcessor, error) { return dialer.DialContext(ctx, network, config.Uplink.Address3) }, } + transport4 := &http.Transport{ + DialContext: func(ctx context.Context, network, _ string) (net.Conn, error) { + return dialer.DialContext(ctx, network, config.Uplink.Address4) + }, + } geoCache, err := geoip.NewCache(config) if err != nil { @@ -110,6 +116,7 @@ func NewRequestProcessor(config *config.Config) (*RequestProcessor, error) { upstreamTransport1: transport1, upstreamTransport2: transport2, upstreamTransport3: transport3, + upstreamTransport4: transport4, config: config, geoIPCache: geoCache, geoLocation: geoLocation, @@ -156,7 +163,7 @@ func (rp *RequestProcessor) ProcessRequest(r *http.Request) (*ResponseWithHeader if dontCache(r) { rp.stats.Inc("uncached") - return getAny(r, rp.upstreamTransport1, rp.upstreamTransport2, rp.upstreamTransport3) + return getAny(r, rp.upstreamTransport1, rp.upstreamTransport2, rp.upstreamTransport3, rp.upstreamTransport4) } // processing cached request @@ -247,7 +254,7 @@ func (rp *RequestProcessor) processUncachedRequest(r *http.Request) (*ResponseWi rp.stats.Inc("geoip") } - response, err = getAny(r, rp.upstreamTransport1, rp.upstreamTransport2, rp.upstreamTransport3) + response, err = getAny(r, rp.upstreamTransport1, rp.upstreamTransport2, rp.upstreamTransport3, rp.upstreamTransport4) if err != nil { return nil, err } diff --git a/San_Francisco.png b/share/pics/San_Francisco.png similarity index 100% rename from San_Francisco.png rename to share/pics/San_Francisco.png diff --git a/share/scripts/build-welang.sh b/share/scripts/build-welang.sh new file mode 100644 index 0000000..a330333 --- /dev/null +++ b/share/scripts/build-welang.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# The scipr is used to build a standalone we-lang binary from +# the wttr.in Go source code. The script is needed as long as +# a standalone we-lang binary is used. +# +# The script requires a configured Go compiler in PATH. + + +show_usage() { + cat < main.go +package main + +func main() { + Cmd() +} +EOF +} + +if [[ -z $1 ]]; then + show_usage + exit 0 +fi + +DST_FILE="$1" +DIR=$(mktemp -d /tmp/build-welang-XXXXXXXXX) + +cp -R "internal/view/v1" "$DIR/v1" + +sed -i 's/^package .*/package main/' "$DIR"/v1/*.go + +cd "$DIR"/v1 || fatal "can't change into the build directory" + +go mod init github.com/chubin/we-lang || fatal "Can't do 'go mod init'" +go mod tidy || fatal "Can't do 'go mod tidy'" +add_main +go build -o "$DST_FILE" *.go || fatal "Building error" + +rm -rf "$DIR" + + diff --git a/share/systemd/README.md b/share/systemd/README.md new file mode 100644 index 0000000..0c7c2b1 --- /dev/null +++ b/share/systemd/README.md @@ -0,0 +1,50 @@ +To add **wttr.in** to systemd as a service, do the following steps. + + +1. **Create a systemd service file**: You’ll need to create a service file in `~/.config/systemd/user/` (for user-level) or `/etc/systemd/system/` (for system-wide) directory. Let’s create it for a user. + +Create the directory if it doesn’t exist: + +```bash +mkdir -p ~/.config/systemd/user/ +``` + +Then, create the service file called `myscript.service`: + +```bash +cp share/systemd/wttrin.service ~/.config/systemd/user/wttrin.service +``` + +2. **Reload the systemd daemon**: This will ensure systemd recognizes the new service. + +```bash +systemctl --user daemon-reload +``` + +4. **Enable and start your service**: + +To start the service immediately, run: + +```bash +systemctl --user start wttrin.service +``` + +5. **Check the status**: To verify that your service is running correctly, you can check its status: + +```bash +systemctl --user status wttrin.service +``` + +6. **Start service automatically**: This will ensure the service is running after reboot. + +To enable it to start automatically at boot, run: + +```bash +systemctl --user enable wttrin.service +``` + +Enable user services even if the user is not logged in (specify the user name instead of `USER`): + +```bash +sudo loginctl enable-linger USER +``` diff --git a/share/systemd/wttrin.service b/share/systemd/wttrin.service new file mode 100644 index 0000000..f5f7956 --- /dev/null +++ b/share/systemd/wttrin.service @@ -0,0 +1,11 @@ +[Unit] +Description=wttr.in services + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/home/igor/src/wttr.in/share/systemd/wttrin.sh session1 +ExecStop=/usr/bin/tmux kill-session -t session1 + +[Install] +WantedBy=default.target diff --git a/share/systemd/wttrin.sh b/share/systemd/wttrin.sh new file mode 100755 index 0000000..dd74e19 --- /dev/null +++ b/share/systemd/wttrin.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +SESSION_NAME="" +SRC_DIR=/home/igor/src/wttr.in +SERVICES_FILE=config/services/services.yaml + +start_service() { + local name="$1" + local workdir="$2" + local cmd="$3" + + if [[ -z "$SESSION_NAME" ]]; then + echo Unknown SESSION_NAME. Exiting >&2 + exit 1 + fi + + local WINDOW_NAME="$name" + local TEXT_TO_ENTER="cd $workdir && $cmd" + + if ! tmux has-session -t "$SESSION_NAME" >& /dev/null; then + tmux new-session -d -s "$SESSION_NAME" + fi + + # Create a new window if it doesn't exist + tmux list-windows -t "$SESSION_NAME" | grep -q "^.\+ $WINDOW_NAME " || tmux new-window -t "$SESSION_NAME" -n "$WINDOW_NAME" + + sleep 0.05 + + # Send text to the new window and press Enter + tmux send-keys -t "$SESSION_NAME:$WINDOW_NAME" "$TEXT_TO_ENTER" C-m +} + + +main() { + local name + local cmd + + if [[ -n $1 ]]; then + SESSION_NAME=$1 + else + echo Usage: $0 SESSION_NAME >&2 + exit 1 + fi + + cd "$SRC_DIR" || exit 1 + + while read -r line; do + name=$(jq -r .name <<< "$line") + workdir=$(jq -r .workdir <<< "$line") + cmd=$(jq -r .command <<< "$line") + + start_service "$name" "$workdir" "$cmd" + done <<< "$(yq -c .services[] < "$SERVICES_FILE")" +} + +main "$@" diff --git a/share/translations/de.txt b/share/translations/de.txt index 85f28de..5b4212d 100644 --- a/share/translations/de.txt +++ b/share/translations/de.txt @@ -1,18 +1,23 @@ +: Dunst in der Nähe : Haze in vicinity +: Starker Regen- und Schneeschauer : Heavy rain and snow shower +: Starker Regenschauer : Heavy rain shower +: Leichter Nieselregen und Schneegriesel : Light drizzle and snow grains +: Leichter Regen- und Nebelschauer : Light rain and mist shower +: Leichter Hagel-/Schneegraupelschauer : Light small hail/snow pellets shower +: Leichter Schauer unbekannter Niederschlag : Light unknown precipitation shower +: Regen und leichter Hagel/Schneegraupel mit Gewitter : Rain and small hail/snow pellets with thunderstorm +: Schneeschauer in der Nähe : Snow shower in vicinity +: Gewitterausbrüche in der Nähe : Thundery outbreaks nearby : Bodennahe Schneeverwehung : Low drifting snow : Nebelfelder : Patches of fog : Nieselregen : Drizzle -: Leichter Nieselregen : Light drizzle : Leichter Nieselregen und Regen : Light drizzle and rain : Schnee : Snow : Regen : Rain -: Leichter Regen : Light Rain : Regenschauer : Rain Shower -: Regen in der näheren Umgebung : Shower in vicinity : Sandverwehungen : Blowing sand : Weitläufige Sandverwehungen : Blowing widespread dust : Weitläufige Sandverwehungen in der Nähe : Blowing widespread dust in vicinity -: Klar : Clear -: Wolkig : Cloudy : Nieselregen und Nebel : Drizzle and fog : Nieselregen und Regen : Drizzle and rain : Nieselregen und Regenschauer : Drizzle and rain shower @@ -40,8 +45,6 @@ : Starker Regen und kleiner Hagel mit Gewitter : Heavy rain and small hail/snow pallets with thunderstorm : Starker Regen und Schnee : Heavy rain and snow : Starker Regen und Schnee sowie kleiner Hagel mit Gewitter : Heavy rain and snow and small hail/snow pallets with thunderstorm -: Starker Schneeschauer : Heavy snow shower -: Starker Regen : Heavy rain : Starker Regen mit Gewitter : Heavy rain with thunderstorm : Starker kleiner Hagelschauer : Heavy small hail/snow pallets shower : Starker kleiner Hagel mit Gewitter : Heavy small hail/snow pallets with thunderstorm @@ -104,9 +107,7 @@ : Nebel mit Gewitter : Mist with thunderstorm : Mäßig bis starker Regen mit Gewitter : Moderate or heavy rain in area with thunder : Mäßig bis starker Schnee mit Gewitter : Moderate or heavy snow in area with thunder -: Bedeckt : Overcast : Teilweise Nebel : Partial fog -: Teilweise bewölkt : Partly cloudy : Nebelfelder in der Nähe : Patches of fog in vicinity : Ortsweise gefrierender Nieselregen : Patchy freezing drizzle nearby : Gebietsweise leichter Regen mit Gewitter : Patchy light rain in area with thunder diff --git a/srv.go b/srv.go index b07cbf9..94d2713 100644 --- a/srv.go +++ b/srv.go @@ -6,7 +6,6 @@ import ( "io" stdlog "log" "net/http" - "strings" "time" "github.com/alecthomas/kong" @@ -156,12 +155,6 @@ func mainHandler( log.Println(err) } - if checkURLForPNG(r) { - w.Write([]byte("PNG support temporary disabled")) - - return - } - response, err := rp.ProcessRequest(r) if err != nil { log.Println(err) @@ -259,8 +252,3 @@ func setLogLevel(logLevel string) error { return nil } - -func checkURLForPNG(r *http.Request) bool { - url := r.URL.String() - return strings.Contains(url, ".png") && !strings.Contains(url, "/files/") -}