diff --git a/.air.toml b/.air.toml index ad439e1..317e6ef 100644 --- a/.air.toml +++ b/.air.toml @@ -3,42 +3,42 @@ testdata_dir = "testdata" tmp_dir = "tmp" [build] - args_bin = [] - bin = "./tmp/main" - cmd = "go build -o ./tmp/main ." - delay = 0 - exclude_dir = ["assets", "tmp", "vendor", "testdata"] - exclude_file = [] - exclude_regex = ["_test.go"] - exclude_unchanged = false - follow_symlink = false - full_bin = "" - include_dir = [] - include_ext = ["go", "tpl", "tmpl", "html"] - include_file = [] - kill_delay = "0s" - log = "build-errors.log" - poll = false - poll_interval = 0 - rerun = false - rerun_delay = 500 - send_interrupt = false - stop_on_error = false +args_bin = [] +bin = "./tmp/main" +cmd = "go build -o ./tmp/main ." +delay = 100 +exclude_dir = ["assets", "tmp", "vendor", "testdata"] +exclude_file = [] +exclude_regex = ["_test.go"] +exclude_unchanged = false +follow_symlink = false +full_bin = "" +include_dir = [] +include_ext = ["go", "tpl", "tmpl", "html"] +include_file = [] +kill_delay = "0s" +log = "build-errors.log" +poll = false +poll_interval = 0 +rerun = false +rerun_delay = 500 +send_interrupt = false +stop_on_error = false [color] - app = "" - build = "yellow" - main = "magenta" - runner = "green" - watcher = "cyan" +app = "" +build = "yellow" +main = "magenta" +runner = "green" +watcher = "cyan" [log] - main_only = false - time = false +main_only = false +time = false [misc] - clean_on_exit = false +clean_on_exit = false [screen] - clear_on_rebuild = false - keep_scroll = true +clear_on_rebuild = false +keep_scroll = true diff --git a/.gitignore b/.gitignore index a9a5aec..35400df 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ tmp + +imap-sync diff --git a/go.mod b/go.mod index 9a3c416..fe76179 100644 --- a/go.mod +++ b/go.mod @@ -3,25 +3,27 @@ module imap-sync go 1.21.0 require ( + github.com/gin-contrib/pprof v1.4.0 github.com/gin-gonic/gin v1.9.1 + github.com/lithammer/fuzzysearch v1.1.8 github.com/sirupsen/logrus v1.9.3 ) require ( - github.com/bytedance/sonic v1.9.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/bytedance/sonic v1.10.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.15.4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/leodido/go-urn v1.2.4 // indirect - github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -29,12 +31,11 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.12.0 // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/arch v0.5.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/sys v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/protobuf v1.31.0 // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a4aaad7..5890276 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,39 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= +github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg= +github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs= +github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -32,16 +44,24 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ 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= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -49,11 +69,14 @@ 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/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= @@ -63,6 +86,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -72,32 +96,36 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y= +golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 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-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.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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-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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -109,6 +137,7 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -121,12 +150,18 @@ 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/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/admin.go b/internal/admin.go new file mode 100644 index 0000000..ee88fab --- /dev/null +++ b/internal/admin.go @@ -0,0 +1,7 @@ +package internal + +import "github.com/gin-gonic/gin" + +func handleAdmin(ctx *gin.Context) { + ctx.HTML(200, "admin.html", nil) +} diff --git a/internal/flags.go b/internal/flags.go new file mode 100644 index 0000000..fc79c1e --- /dev/null +++ b/internal/flags.go @@ -0,0 +1,19 @@ +package internal + +import "flag" + +var ( + port = flag.String("port", "8080", "Port to listen on") + source_server = flag.String("source_server", "", "Source server") + source_account = flag.String("source_account", "", "Source account") + source_password = flag.String("source_password", "", "Source password") + destination_server = flag.String("destination_server", "", "Destination server") + destination_account = flag.String("destination_account", "", "Destination account") + destination_password = flag.String("destination_password", "", "Destination password") +) + +type Credentials struct { + Server string + Account string + Password string +} diff --git a/logger.go b/internal/logger.go similarity index 76% rename from logger.go rename to internal/logger.go index e8a3bed..93a415a 100644 --- a/logger.go +++ b/internal/logger.go @@ -1,4 +1,4 @@ -package main +package internal import ( "runtime" @@ -10,9 +10,9 @@ import ( var log = logrus.New() -func SetupLogger() { +func SetupLogger(logger *logrus.Logger) { - log.SetFormatter(&logrus.TextFormatter{ + logger.SetFormatter(&logrus.TextFormatter{ ForceColors: true, // Enable colors in the console output FullTimestamp: true, // Show full timestamp with date and time TimestampFormat: "2006-01-02 15:04:05", @@ -24,6 +24,6 @@ func SetupLogger() { }, }) - log.SetReportCaller(true) - log.SetLevel(logrus.TraceLevel) + logger.SetReportCaller(true) + logger.SetLevel(logrus.TraceLevel) } diff --git a/internal/pagination.go b/internal/pagination.go new file mode 100644 index 0000000..cb77a61 --- /dev/null +++ b/internal/pagination.go @@ -0,0 +1,36 @@ +package internal + +import ( + "strconv" + + "github.com/gin-gonic/gin" +) + +// Updates pagination buttons +func handlePagination(ctx *gin.Context) { + index, _ := strconv.Atoi(ctx.Request.FormValue("page")) + pages := []Pagination{} + startPage := index - 2 + endPage := index + 2 + + if startPage < 1 { + startPage = 1 + } + + if endPage > queue.Len()/PageSize { + endPage = queue.Len() / PageSize + } + + if (index <= 2 || index >= endPage-2 || index == endPage || index == endPage-1) && endPage-startPage+1 < 5 && endPage < queue.Len()/PageSize { + endPage = startPage + 4 + } + + for i := startPage; i <= endPage; i++ { + pages = append(pages, Pagination{ + Number: i, + Active: i == index, + }) + } + + ctx.HTML(200, "pagination.html", pages) +} diff --git a/internal/polling.go b/internal/polling.go new file mode 100644 index 0000000..435b2ae --- /dev/null +++ b/internal/polling.go @@ -0,0 +1,25 @@ +package internal + +import ( + "strconv" + + "github.com/gin-gonic/gin" +) + +func handleQueuePolling(ctx *gin.Context) { + index, _ := strconv.Atoi(ctx.Request.FormValue("page")) + + if queue.Len() == 0 { + ctx.String(200, "") + return + } + + tasks := getPageByIndex(index) + + data := PageData{ + Index: index, + Tasks: tasks, + } + + ctx.HTML(200, "tbody.html", data) +} diff --git a/internal/queue.go b/internal/queue.go new file mode 100644 index 0000000..4861a2f --- /dev/null +++ b/internal/queue.go @@ -0,0 +1,64 @@ +package internal + +import ( + "container/list" + "strconv" + + "github.com/gin-gonic/gin" +) + +var queue *list.List + +const PageSize = 20 + +// Send only one page +func handleQueue(ctx *gin.Context) { + index, _ := strconv.Atoi(ctx.Request.FormValue("page")) + + go addOneTask() + + if queue.Len() == 0 { + ctx.String(200, "") + return + } + + tasks := getPageByIndex(index) + + data := PageData{ + Index: index, + Tasks: tasks, + } + + ctx.HTML(200, "queue.html", data) +} + +func getPageByIndex(index int) []Task { + var tasks []Task + start := (index - 1) * PageSize + end := start + PageSize + + for i, e := 0, queue.Front(); i < end && e != nil; i, e = i+1, e.Next() { + if i >= start { + tasks = append(tasks, e.Value.(Task)) + } + } + + return tasks +} + +func initQueue() { + queue = list.New() + for i := 0; i < 2000; i++ { + addOneTask() + } +} + +func addOneTask() { + task := Task{ + ID: queue.Len() + 1, + Account: "jomo", + Server: "imap.gmail.com", + Status: "In progress", + } + queue.PushFront(task) +} diff --git a/internal/root.go b/internal/root.go new file mode 100644 index 0000000..5466de9 --- /dev/null +++ b/internal/root.go @@ -0,0 +1,26 @@ +package internal + +import "github.com/gin-gonic/gin" + +func handleRoot(ctx *gin.Context) { + sourceDetails := Credentials{ + Server: *source_server, + Account: *source_account, + Password: *source_password, + } + + destinationDetails := Credentials{ + Server: *destination_server, + Account: *destination_account, + Password: *destination_password, + } + + data := struct { + SourceDetails Credentials + DestinationDetails Credentials + }{ + SourceDetails: sourceDetails, + DestinationDetails: destinationDetails, + } + ctx.HTML(200, "index.html", data) +} diff --git a/internal/router.go b/internal/router.go new file mode 100644 index 0000000..34e8e77 --- /dev/null +++ b/internal/router.go @@ -0,0 +1,34 @@ +package internal + +import ( + "github.com/gin-gonic/gin" +) + +func InitServer() { + SetupLogger(log) + + gin.SetMode(gin.ReleaseMode) + router := gin.Default() + + router.LoadHTMLGlob("templates/*") + + router.GET("/", handleRoot) + router.GET("/admin", handleAdmin) + router.GET("/favicon.ico", func(ctx *gin.Context) { + ctx.File("favicon.ico") + }) + + go initQueue() + // API endpoints + router.GET("/api/queue", handleQueue) + router.GET("/api/queuepoll", handleQueuePolling) + router.GET("/api/pagination", handlePagination) + router.POST("/api/validate", handleValidate) + router.POST("/api/search", handleSearch) + + log.Info("Server starting on http://localhost:" + *port) + + if err := router.Run(":" + *port); err != nil { + log.Fatal(err) + } +} diff --git a/internal/search.go b/internal/search.go new file mode 100644 index 0000000..6dc04db --- /dev/null +++ b/internal/search.go @@ -0,0 +1,86 @@ +package internal + +import ( + "strconv" + "sync" + + "github.com/gin-gonic/gin" + "github.com/lithammer/fuzzysearch/fuzzy" +) + +func handleSearch(ctx *gin.Context) { + searchQuery := ctx.PostForm("search-input") + + if searchQuery == "" { + handleQueue(ctx) + return + } + + results := searchChunk(searchQuery) + + data := PageData{ + Index: 1, + Tasks: results, + } + + ctx.HTML(200, "queue.html", data) +} + +func searchInQueue(searchQuery string) []Task { + var results []Task + chunkSize := 100 // number of tasks to process in each chunk + numChunks := (queue.Len() + chunkSize - 1) / chunkSize // round up division + chunkResults := make([][]Task, numChunks) + var wg sync.WaitGroup + for i := 0; i < numChunks; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + start := i * chunkSize + end := start + chunkSize + if end > queue.Len() { + end = queue.Len() + } + for j, e := 0, queue.Front(); j < end && e != nil; j, e = j+1, e.Next() { + if j >= start { + task := e.Value.(Task) + if fuzzy.Match(searchQuery, strconv.Itoa(task.ID)) || + fuzzy.Match(searchQuery, task.Account) || + fuzzy.Match(searchQuery, task.Server) || + fuzzy.Match(searchQuery, task.Status) { + chunkResults[i] = append(chunkResults[i], task) + } + } + } + }(i) + + if len(results) > 150 { + break + } + } + + wg.Wait() + for _, chunkResult := range chunkResults { + results = append(results, chunkResult...) + } + return results +} + +// Fuzzy match each field in the queue +func searchChunk(searchQuery string) []Task { + var results []Task + for e := queue.Front(); e != nil; e = e.Next() { + task := e.Value.(Task) + if fuzzy.Match(searchQuery, strconv.Itoa(task.ID)) || + fuzzy.Match(searchQuery, task.Account) || + fuzzy.Match(searchQuery, task.Server) || + fuzzy.Match(searchQuery, task.Status) { + results = append(results, task) + } + + if len(results) > 100 { + break + } + } + return results +} diff --git a/internal/structs.go b/internal/structs.go new file mode 100644 index 0000000..217aaff --- /dev/null +++ b/internal/structs.go @@ -0,0 +1,18 @@ +package internal + +type Task struct { + ID int + Account string + Server string + Status string +} + +type Pagination struct { + Number int + Active bool +} + +type PageData struct { + Index int + Tasks []Task +} diff --git a/transfer.go b/internal/transfer.go similarity index 87% rename from transfer.go rename to internal/transfer.go index 91366bb..f6fb6bd 100644 --- a/transfer.go +++ b/internal/transfer.go @@ -1,4 +1,4 @@ -package main +package internal func transferFiles(sourceDetails Credentials, destinationDetails Credentials, files []string) error { return nil diff --git a/validate.go b/internal/validate.go similarity index 98% rename from validate.go rename to internal/validate.go index b3100a5..c856fc8 100644 --- a/validate.go +++ b/internal/validate.go @@ -1,4 +1,4 @@ -package main +package internal import ( "errors" diff --git a/main.go b/main.go index be5e243..832f2f7 100644 --- a/main.go +++ b/main.go @@ -2,32 +2,10 @@ package main import ( "flag" -) - -type Credentials struct { - Server string - Account string - Password string -} - -var ( - port = flag.String("port", "8080", "Port to listen on") - source_server = flag.String("source_server", "", "Source server") - source_account = flag.String("source_account", "", "Source account") - source_password = flag.String("source_password", "", "Source password") - destination_server = flag.String("destination_server", "", "Destination server") - destination_account = flag.String("destination_account", "", "Destination account") - destination_password = flag.String("destination_password", "", "Destination password") + "imap-sync/internal" ) func main() { flag.Parse() - - SetupLogger() - - log.Info("Starting server") - - router := initServer() - - router.Run(":" + *port) + internal.InitServer() } diff --git a/queue.go b/queue.go deleted file mode 100644 index 328f986..0000000 --- a/queue.go +++ /dev/null @@ -1,137 +0,0 @@ -package main - -import ( - "container/list" - "strconv" - - "github.com/gin-gonic/gin" -) - -type Task struct { - ID int - Account string - Server string - Status string -} - -type Pagination struct { - Number int - Active bool -} - -type PageData struct { - Index int - Tasks []Task -} - -var queue *list.List - -const PageSize = 20 - -func handleQueuePoll(ctx *gin.Context) { - ctx.Header("Content-Type", "text/html; charset=utf-8") - index, _ := strconv.Atoi(ctx.Request.FormValue("page")) - - if queue.Len() == 0 { - ctx.String(200, "") - return - } - - tasks := getPageByIndex(index) - - data := PageData{ - Index: index, - Tasks: tasks, - } - - ctx.HTML(200, "tbody.html", data) -} - -// Send only one page -func handleQueue(ctx *gin.Context) { - ctx.Header("Content-Type", "text/html; charset=utf-8") - index, _ := strconv.Atoi(ctx.Request.FormValue("page")) - - addOneTask() - - if queue.Len() == 0 { - ctx.String(200, "") - return - } - - tasks := getPageByIndex(index) - - data := PageData{ - Index: index, - Tasks: tasks, - } - - ctx.HTML(200, "queue.html", data) -} - -func getPageByIndex(index int) []Task { - var tasks []Task - start := (index - 1) * PageSize - end := start + PageSize - - for i, e := 0, queue.Front(); i < end && e != nil; i, e = i+1, e.Next() { - if i >= start { - tasks = append(tasks, e.Value.(Task)) - } - } - - return tasks -} - -func initQueue() { - queue = list.New() - for i := 0; i < 140; i++ { - task := Task{ - ID: i + 1, - Account: "jomo", - Server: "imap.gmail.com", - Status: "In progress", - } - queue.PushFront(task) - } -} - -func addOneTask() { - task := Task{ - ID: queue.Len() + 1, - Account: "jomo", - Server: "imap.gmail.com", - Status: "In progress", - } - queue.PushFront(task) -} - -// Updates pagination buttons -func handlePagination(ctx *gin.Context) { - ctx.Header("Content-Type", "text/html; charset=utf-8") - index, _ := strconv.Atoi(ctx.Request.FormValue("page")) - pages := []Pagination{} - startPage := index - 2 - endPage := index + 2 - - if startPage < 1 { - startPage = 1 - } - - if endPage > queue.Len()/PageSize { - endPage = queue.Len() / PageSize - } - - if (index <= 2 || index >= endPage-2 || index == endPage || index == endPage-1) && endPage-startPage+1 < 5 && endPage < queue.Len()/PageSize { - endPage = startPage + 4 - } - - for i := startPage; i <= endPage; i++ { - pages = append(pages, Pagination{ - Number: i, - Active: i == index, - }) - } - - ctx.HTML(200, "pagination.html", pages) -} diff --git a/search.go b/search.go deleted file mode 100644 index 7c66bb4..0000000 --- a/search.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/gin-gonic/gin" - "github.com/lithammer/fuzzysearch/fuzzy" -) - -func handleSearch(ctx *gin.Context) { - searchQuery := ctx.PostForm("search-input") - - if searchQuery == "" { - handleQueue(ctx) - return - } - - results := searchInQueue(searchQuery) - - data := PageData{ - Index: 1, - Tasks: results, - } - - ctx.HTML(200, "queue.html", data) -} - -// Fuzzy match each field in the queue -func searchInQueue(searchQuery string) []Task { - var results []Task - for e := queue.Front(); e != nil; e = e.Next() { - task := e.Value.(Task) - if fuzzy.Match(searchQuery, fmt.Sprint(task.ID)) || - fuzzy.Match(searchQuery, task.Account) || - fuzzy.Match(searchQuery, task.Server) || - fuzzy.Match(searchQuery, task.Status) { - results = append(results, task) - } - } - return results -} diff --git a/server.go b/server.go deleted file mode 100644 index c903033..0000000 --- a/server.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "github.com/gin-gonic/gin" -) - -func initServer() *gin.Engine { - gin.SetMode(gin.ReleaseMode) - router := gin.Default() - - router.LoadHTMLGlob("templates/*") - - router.GET("/", handleRoot) - router.GET("/admin", handleAdmin) - router.GET("/favicon.ico", func(ctx *gin.Context) { - ctx.File("favicon.ico") - }) - - initQueue() - // API endpoints - router.GET("/api/queue", handleQueue) - router.GET("/api/queuepoll", handleQueuePoll) - router.GET("/api/pagination", handlePagination) - router.POST("/api/validate", handleValidate) - router.POST("/api/search", handleSearch) - - return router -} - -func handleRoot(ctx *gin.Context) { - sourceDetails := Credentials{ - Server: *source_server, - Account: *source_account, - Password: *source_password, - } - - destinationDetails := Credentials{ - Server: *destination_server, - Account: *destination_account, - Password: *destination_password, - } - - data := struct { - SourceDetails Credentials - DestinationDetails Credentials - }{ - SourceDetails: sourceDetails, - DestinationDetails: destinationDetails, - } - ctx.HTML(200, "index.html", data) -} - -func handleAdmin(ctx *gin.Context) { - ctx.HTML(200, "admin.html", nil) -} diff --git a/templates/admin.html b/templates/admin.html index 76d3c81..749a6fb 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -101,6 +101,19 @@