This commit is contained in:
aceberg 2024-08-21 19:44:06 +07:00
parent e6a5bf852b
commit 73db704cf7
16 changed files with 290 additions and 77 deletions

17
go.mod
View file

@ -5,7 +5,9 @@ go 1.22.6
require (
github.com/gin-gonic/gin v1.10.0
github.com/google/gopacket v1.1.19
github.com/jmoiron/sqlx v1.4.0
github.com/spf13/viper v1.19.0
modernc.org/sqlite v1.32.0
)
require (
@ -13,6 +15,7 @@ require (
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
@ -20,6 +23,8 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
@ -29,7 +34,9 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
@ -43,11 +50,17 @@ require (
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.55.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)

60
go.sum
View file

@ -1,3 +1,5 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
@ -10,6 +12,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
@ -28,6 +32,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@ -35,8 +41,16 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@ -49,10 +63,14 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -60,11 +78,15 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
@ -110,10 +132,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w=
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
@ -123,12 +147,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
@ -140,5 +166,31 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
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=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s=
modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View file

@ -17,7 +17,7 @@ func scanIface(iface string) string {
return string(cmd)
}
func parseOutput(text string) []models.Host {
func parseOutput(text, iface string) []models.Host {
var foundHosts = []models.Host{}
perString := strings.Split(text, "\n")
@ -27,6 +27,7 @@ func parseOutput(text string) []models.Host {
if host != "" {
var oneHost models.Host
p := strings.Split(host, " ")
oneHost.Iface = iface
oneHost.IP = p[0]
oneHost.Mac = p[1]
oneHost.Hw = p[2]
@ -40,17 +41,19 @@ func parseOutput(text string) []models.Host {
}
// Scan all interfaces
func Scan(ifaces []string) []models.Host {
func Scan(ifaces string) []models.Host {
var text string
var foundHosts = []models.Host{}
for _, iface := range ifaces {
perString := strings.Split(ifaces, " ")
for _, iface := range perString {
text = scanIface(iface)
log.Println("INFO: scanning interface", iface)
log.Println("INFO: found IPs:", text)
foundHosts = append(foundHosts, parseOutput(text)...)
foundHosts = append(foundHosts, parseOutput(text, iface)...)
}
return foundHosts

View file

@ -11,6 +11,8 @@ import (
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/aceberg/WatchYourLAN/internal/check"
)
// GoScan - scan iface
@ -131,8 +133,9 @@ func writeARP(handle *pcap.Handle, iface *net.Interface, addr *net.IPNet) error
// Send one packet for every address.
for _, ip := range ips(addr) {
arp.DstProtAddress = []byte(ip)
gopacket.SerializeLayers(buf, opts, &eth, &arp)
if err := handle.WritePacketData(buf.Bytes()); err != nil {
err := gopacket.SerializeLayers(buf, opts, &eth, &arp)
check.IfError(err)
if err = handle.WritePacketData(buf.Bytes()); err != nil {
return err
}
}

View file

@ -15,6 +15,9 @@ func Get(path string) (config models.Conf) {
viper.SetDefault("THEME", "solar")
viper.SetDefault("COLOR", "dark")
viper.SetDefault("NODEPATH", "")
viper.SetDefault("SCANER", "arpscan")
viper.SetDefault("ARPARGS", "")
viper.SetDefault("IFACES", "")
viper.SetConfigFile(path)
viper.SetConfigType("yaml")
@ -28,6 +31,9 @@ func Get(path string) (config models.Conf) {
config.Theme = viper.Get("THEME").(string)
config.Color = viper.Get("COLOR").(string)
config.NodePath = viper.Get("NODEPATH").(string)
config.Scaner = viper.Get("SCANER").(string)
config.ArpArgs = viper.Get("ARPARGS").(string)
config.Ifaces = viper.Get("IFACES").(string)
return config
}
@ -43,6 +49,9 @@ func Write(config models.Conf) {
viper.Set("THEME", config.Theme)
viper.Set("COLOR", config.Color)
viper.Set("NODEPATH", config.NodePath)
viper.Set("SCANER", config.Scaner)
viper.Set("ARPARGS", config.ArpArgs)
viper.Set("IFACES", config.Ifaces)
err := viper.WriteConfig()
check.IfError(err)

61
internal/db/edit.go Normal file
View file

@ -0,0 +1,61 @@
package db
import (
"fmt"
"github.com/aceberg/WatchYourLAN/internal/models"
)
// Create - create DB if not exists
func Create(path string) {
sqlStatement := `CREATE TABLE IF NOT EXISTS "now" (
"ID" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
"NAME" TEXT NOT NULL,
"IFACE" TEXT,
"IP" TEXT,
"MAC" TEXT,
"HW" TEXT,
"DATE" TEXT,
"KNOWN" INTEGER DEFAULT 0,
"NOW" INTEGER DEFAULT 0
);`
dbExec(path, sqlStatement)
}
// Insert - insert host into table
func Insert(path string, oneHost models.Host) {
oneHost.Name = quoteStr(oneHost.Name)
oneHost.Hw = quoteStr(oneHost.Hw)
sqlStatement := `INSERT INTO "now" (NAME, IFACE, IP, MAC, HW, DATE, KNOWN, NOW)
VALUES ('%s','%s','%s','%s','%s','%s','%d','%d');`
sqlStatement = fmt.Sprintf(sqlStatement, oneHost.Name, oneHost.Iface, oneHost.IP, oneHost.Mac, oneHost.Hw, oneHost.Date, oneHost.Known, oneHost.Now)
dbExec(path, sqlStatement)
}
// Update - update host
func Update(path string, oneHost models.Host) {
oneHost.Name = quoteStr(oneHost.Name)
oneHost.Hw = quoteStr(oneHost.Hw)
sqlStatement := `UPDATE "now" set
NAME = '%s', IFACE = '%s', IP = '%s', MAC = '%s', HW = '%s', DATE = '%s',
KNOWN = '%d', NOW = '%d'
WHERE ID = '%d';`
sqlStatement = fmt.Sprintf(sqlStatement, oneHost.Name, oneHost.Iface, oneHost.IP, oneHost.Mac, oneHost.Hw, oneHost.Date, oneHost.Known, oneHost.Now, oneHost.ID)
dbExec(path, sqlStatement)
}
// Delete - delete host from DB
func Delete(path string, id int) {
sqlStatement := `DELETE FROM "now" WHERE ID='%d';`
sqlStatement = fmt.Sprintf(sqlStatement, id)
dbExec(path, sqlStatement)
}
// Clear - delete all hosts from table
func Clear(path string) {
sqlStatement := `DELETE FROM "now";`
dbExec(path, sqlStatement)
}

7
internal/db/quote_str.go Normal file
View file

@ -0,0 +1,7 @@
package db
import "strings"
func quoteStr(str string) string {
return strings.ReplaceAll(str, "'", "''")
}

45
internal/db/sqlite.go Normal file
View file

@ -0,0 +1,45 @@
package db
import (
"sync"
"github.com/jmoiron/sqlx"
// Import sqlite module
_ "modernc.org/sqlite"
"github.com/aceberg/WatchYourLAN/internal/check"
"github.com/aceberg/WatchYourLAN/internal/models"
)
var mu sync.Mutex
func dbExec(path, sqlStatement string) {
mu.Lock()
db, err := sqlx.Connect("sqlite", path)
check.IfError(err)
defer db.Close()
_, err = db.Exec(sqlStatement)
mu.Unlock()
check.IfError(err)
}
// Select - select all hosts
func Select(path string) (dbHosts []models.Host) {
sqlStatement := `SELECT * FROM "now" ORDER BY DATE DESC`
mu.Lock()
db, _ := sqlx.Connect("sqlite", path)
defer db.Close()
err := db.Select(&dbHosts, sqlStatement)
mu.Unlock()
check.IfError(err)
return dbHosts
}

View file

@ -10,15 +10,16 @@ type Conf struct {
ConfPath string
DBPath string
NodePath string
Ifaces []string
ScanMethod string
ArpArgs string
Ifaces string
Scaner string
ArpArgs string
}
// Host - one host
type Host struct {
ID int `db:"ID"`
Name string `db:"NAME"`
Iface string `db:"IFACE"`
IP string `db:"IP"`
Mac string `db:"MAC"`
Hw string `db:"HW"`

View file

@ -9,4 +9,4 @@ import (
func apiAll(c *gin.Context) {
c.IndentedJSON(http.StatusOK, allHosts)
}
}

View file

@ -3,7 +3,6 @@ package web
import (
"log/slog"
"net/http"
// "strconv"
"github.com/gin-gonic/gin"
@ -35,6 +34,9 @@ func saveConfigHandler(c *gin.Context) {
appConfig.Theme = c.PostForm("theme")
appConfig.Color = c.PostForm("color")
appConfig.NodePath = c.PostForm("node")
appConfig.Scaner = c.PostForm("scaner")
appConfig.ArpArgs = c.PostForm("arpargs")
appConfig.Ifaces = c.PostForm("ifaces")
conf.Write(appConfig)

View file

@ -1,12 +1,10 @@
package web
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/aceberg/WatchYourLAN/internal/arp"
"github.com/aceberg/WatchYourLAN/internal/models"
)
@ -14,11 +12,6 @@ func indexHandler(c *gin.Context) {
var guiData models.GuiData
guiData.Config = appConfig
allHosts = arp.Scan(appConfig.Ifaces)
log.Println("ARPSCAN:", allHosts)
go arp.GoScan()
c.HTML(http.StatusOK, "header.html", guiData)
c.HTML(http.StatusOK, "index.html", guiData)
}

View file

@ -15,6 +15,7 @@ function createHTML(addr, i) {
<tr>
<td style="opacity: 45%;">${i}.</td>
<td>${addr.Name}</td>
<td>${addr.Iface}</td>
<td>
<a href="http://${addr.IP}">${addr.IP}</a>
</td>

View file

@ -1,72 +1,85 @@
{{ define "config.html" }}
<body>
<div class="container-lg">
<div class="container-lg">
<div class="row">
<div class="col-md mt-4">
<div class="col-md mt-4">
<div class="card border-primary">
<div class="card-header">Config</div>
<div class="card-body table-responsive">
<table class="table table-borderless">
<form action="/config/" method="post">
<div class="card-header">Config</div>
<div class="card-body table-responsive">
<table class="table table-borderless">
<form action="/config/" method="post">
<tr>
<td>Host</td>
<td><input name="host" type="text" class="form-control" value="{{ .Config.Host }}"></td>
<td>Host</td>
<td><input name="host" type="text" class="form-control" value="{{ .Config.Host }}"></td>
</tr>
<tr>
<td>Port</td>
<td><input name="port" type="text" class="form-control" value="{{ .Config.Port }}"></td>
<td>Port</td>
<td><input name="port" type="text" class="form-control" value="{{ .Config.Port }}"></td>
</tr>
<tr>
<td>Theme</td>
<td><select name="theme" class="form-select">
<option selected>{{ .Config.Theme }}</option>
{{ range .Themes }}
<option value="{{ . }}">{{ . }}</option>
{{ end }}
</select></td>
<td>Theme</td>
<td><select name="theme" class="form-select">
<option selected>{{ .Config.Theme }}</option>
{{ range .Themes }}
<option value="{{ . }}">{{ . }}</option>
{{ end }}
</select></td>
</tr>
<tr>
<td>Color mode</td>
<td><select name="color" class="form-select">
<option selected>{{ .Config.Color }}</option>
<option value="light">light</option>
<option value="dark">dark</option>
</select></td>
<td>Color mode</td>
<td><select name="color" class="form-select">
<option selected>{{ .Config.Color }}</option>
<option value="light">light</option>
<option value="dark">dark</option>
</select></td>
</tr>
<tr>
<td>Local node-bootstrap url</td>
<td><input name="node" type="text" class="form-control" value="{{ .Config.NodePath }}"></td>
<td>Local node-bootstrap url</td>
<td><input name="node" type="text" class="form-control" value="{{ .Config.NodePath }}"></td>
</tr>
<tr>
<td><button type="submit" class="btn btn-primary">Save</button></td>
<td></td>
<td>Interfaces</td>
<td><input name="ifaces" type="text" class="form-control" value="{{ .Config.Ifaces }}"></td>
</tr>
</form>
</table>
<tr>
<td>Scaner</td>
<td><select name="scaner" class="form-select">
<option selected>{{ .Config.Scaner }}</option>
<option value="arpscan">arpscan</option>
<option value="golang">golang (experimental)</option>
</select></td>
</tr>
<tr>
<td>Args for arpscan</td>
<td><input name="arpargs" type="text" class="form-control" value="{{ .Config.ArpArgs }}"></td>
</tr>
<tr>
<td><button type="submit" class="btn btn-primary">Save</button></td>
<td></td>
</tr>
</form>
</table>
</div>
</div>
</div>
<div class="card border-primary mt-4">
<div class="card-header">Version</div>
<div class="card-body">
<a href="https://github.com/aceberg/WatchYourLAN/releases/tag/{{ .Version }}" target="_blank">{{ .Version }}</a>
</div>
</div>
</div>
<div class="col-md mt-4">
<div class="card border-primary mt-4 mb-4">
<div class="card-header">About</div>
<div class="card-body">
<p>● After changing <b>Host</b> or <b>Port</b> the app must be restarted</p>
<p><b>Timeout (minutes)</b> - how often watched ports are scanned</p>
<p><b>Trim History</b> - how many port states are saved in memory and displayed on the <a href="/history/">History</a> page</p>
<p>● If you find this app useful, please, <a href="https://github.com/aceberg#donate" target="_blank">donate</a></p>
<p>● Commission you own app (Golang, HTML/JS). Contact and prices <a href="https://github.com/aceberg" target="_blank">here</a></p>
</div>
</div>
</div>
</div>
</div>
<div class="col-md mt-4 mb-4">
<div class="card border-primary">
<div class="card-header">
About (<a href="https://github.com/aceberg/WatchYourLAN/releases/tag/{{ .Version }}" target="_blank">v{{ .Version }}</a>)
</div>
<div class="card-body">
<p>● After changing <b>Host</b> or <b>Port</b> the app must be restarted</p>
<p><b>Timeout (minutes)</b> - how often watched ports are scanned</p>
<p><b>Trim History</b> - how many port states are saved in memory and displayed on the <a href="/history/">History</a> page</p>
<p>● If you find this app useful, please, <a href="https://github.com/aceberg#donate" target="_blank">donate</a></p>
<p>● Commission you own app (Golang, HTML/JS). Contact and prices <a href="https://github.com/aceberg" target="_blank">here</a></p>
</div>
</div>
</div>
</div>
</div>
{{ template "footer.html" }}
{{ end }}

View file

@ -12,6 +12,7 @@
<thead>
<th style="width: 3em;"></th>
<th>Name <i class="bi bi-sort-down-alt" onclick="sortBy('Name')"></i></th>
<th>Iface <i class="bi bi-sort-down-alt" onclick="sortBy('Iface')"></i></th>
<th>IP <i class="bi bi-sort-down-alt" onclick="sortBy('IP')"></i></th>
<th>MAC <i class="bi bi-sort-down-alt" onclick="sortBy('Mac')"></i></th>
<th>Hardware <i class="bi bi-sort-down-alt" onclick="sortBy('Hw')"></i></th>

View file

@ -7,8 +7,10 @@ import (
"github.com/gin-gonic/gin"
"github.com/aceberg/WatchYourLAN/internal/arp"
"github.com/aceberg/WatchYourLAN/internal/check"
"github.com/aceberg/WatchYourLAN/internal/conf"
"github.com/aceberg/WatchYourLAN/internal/db"
)
// Gui - start web server
@ -21,11 +23,9 @@ func Gui(dirPath, nodePath string) {
appConfig.DirPath = dirPath
appConfig.ConfPath = confPath
appConfig.DBPath = dirPath + "/scan.db"
appConfig.NodePath = nodePath
// temp
appConfig.Ifaces = append(appConfig.Ifaces, "enp4s0")
slog.Info("config", "path", appConfig.DirPath)
address := appConfig.Host + ":" + appConfig.Port
@ -34,6 +34,11 @@ func Gui(dirPath, nodePath string) {
slog.Info("Web GUI at http://" + address)
slog.Info("=================================== ")
updateAllHosts()
// Run scan
allHosts = arp.Scan(appConfig.Ifaces)
slog.Info("ARPSCAN:", "found", allHosts)
gin.SetMode(gin.ReleaseMode)
router := gin.Default()
@ -52,3 +57,7 @@ func Gui(dirPath, nodePath string) {
err := router.Run(address)
check.IfError(err)
}
func updateAllHosts() {
allHosts = db.Select(appConfig.DBPath)
}