diff --git a/components/service/go-service/go-service b/components/service/go-service/go-service index 99da5a3..6437bea 100755 Binary files a/components/service/go-service/go-service and b/components/service/go-service/go-service differ diff --git a/components/service/go-service/go.mod b/components/service/go-service/go.mod index 30b22ac..a8cf60c 100644 --- a/components/service/go-service/go.mod +++ b/components/service/go-service/go.mod @@ -4,7 +4,9 @@ go 1.21 require ( github.com/gin-gonic/gin v1.9.1 + github.com/lib/pq v1.10.9 github.com/spf13/viper v1.18.2 + go.mongodb.org/mongo-driver v1.17.6 ) require ( @@ -17,8 +19,10 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -26,6 +30,7 @@ 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/montanaflynn/stats v0.7.1 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -36,14 +41,19 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.26.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/components/service/go-service/go.sum b/components/service/go-service/go.sum index 6572359..c775a29 100644 --- a/components/service/go-service/go.sum +++ b/components/service/go-service/go.sum @@ -29,14 +29,18 @@ github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QX 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= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/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/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 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= @@ -46,6 +50,8 @@ 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.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= @@ -57,6 +63,8 @@ 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/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -95,6 +103,17 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 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/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= +go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= @@ -102,18 +121,43 @@ go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTV 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/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= 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/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +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.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +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.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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-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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.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/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.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/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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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/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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= diff --git a/components/service/go-service/microzoo.yml b/components/service/go-service/microzoo.yml index 0ce8d76..036a5fe 100644 --- a/components/service/go-service/microzoo.yml +++ b/components/service/go-service/microzoo.yml @@ -16,6 +16,20 @@ interfaces: upstream: base: protocol: http-rest +databases: + postgres: + environment: + MICROZOO_DB_HOST: "{{database.id}}" + MICROZOO_DB_PORT: "{{manifest.constants.port}}" + MICROZOO_DB_NAME: "{{manifest.constants.db}}" + MICROZOO_DB_USER: "{{manifest.constants.userName}}" + MICROZOO_DB_PASS: "{{manifest.constants.password}}" + WAIT_FOR: "{{database.id}}:{{manifest.constants.port}}" + mongodb: + environment: + MICROZOO_MONGO_URI: "mongodb://{{database.id}}:{{manifest.constants.port}}" + MICROZOO_MONGO_DBNAME: "{{manifest.constants.db}}" + WAIT_FOR: "{{database.id}}:{{manifest.constants.port}}" config: requestDelay: string responseDelay: string diff --git a/components/service/go-service/src/main.go b/components/service/go-service/src/main.go index d56aacd..a2eeb61 100644 --- a/components/service/go-service/src/main.go +++ b/components/service/go-service/src/main.go @@ -1,6 +1,8 @@ package main import ( + "context" + "database/sql" "fmt" "log" "net/http" @@ -10,34 +12,51 @@ import ( "time" "github.com/gin-gonic/gin" + _ "github.com/lib/pq" // PostgreSQL driver "github.com/spf13/viper" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" ) -// MicrozooConfigProperties entspricht der Konfiguration aus der Java-Anwendung +// MicrozooConfigProperties mirrors the configuration from the Java application type MicrozooConfigProperties struct { - RequestDelay time.Duration - ResponseDelay time.Duration + RequestDelay time.Duration + ResponseDelay time.Duration UpstreamServices []string - EntityCount int - PayloadSize int + EntityCount int + PayloadSize int + // Database Configuration + DBHost string // For PostgreSQL + DBPort string // For PostgreSQL + DBName string // For PostgreSQL + DBUser string // For PostgreSQL + DBPass string // For PostgreSQL + // MongoDB Configuration + MongoURI string + MongoDBName string } -// BaseDto entspricht der Datenstruktur aus der Java-Anwendung +// BaseDto mirrors the data structure from the Java application type BaseDto struct { - ID string `json:"id"` - Name string `json:"name"` - Payload string `json:"payload"` + ID string `json:"id" bson:"_id"` + Name string `json:"name" bson:"name"` + Payload string `json:"payload" bson:"payload"` } var config MicrozooConfigProperties +var sqlDB *sql.DB +var mongoClient *mongo.Client +var mongoCollection *mongo.Collection func loadConfig() { + // Load configuration from environment variables viper.SetDefault("microzoo.requestDelay", "0ms") viper.SetDefault("microzoo.responseDelay", "0ms") viper.SetDefault("microzoo.entityCount", 1) viper.SetDefault("microzoo.payloadSize", 100) - // Konfiguration aus Umgebungsvariablen laden + // Load configuration from environment variables viper.AutomaticEnv() viper.SetEnvPrefix("MICROZOO") viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) @@ -49,7 +68,7 @@ func loadConfig() { } reqDelay, err := time.ParseDuration(reqDelayStr) if err != nil { - log.Printf("WARN: Konnte RequestDelay nicht parsen: %v. Verwende 0ms.", err) + log.Printf("WARN: Could not parse RequestDelay: %v. Using 0ms.", err) reqDelay = 0 } config.RequestDelay = reqDelay @@ -61,7 +80,7 @@ func loadConfig() { } respDelay, err := time.ParseDuration(respDelayStr) if err != nil { - log.Printf("WARN: Konnte ResponseDelay nicht parsen: %v. Verwende 0ms.", err) + log.Printf("WARN: Could not parse ResponseDelay: %v. Using 0ms.", err) respDelay = 0 } config.ResponseDelay = respDelay @@ -79,7 +98,7 @@ func loadConfig() { if entityCountStr != "" { config.EntityCount, err = strconv.Atoi(entityCountStr) if err != nil { - log.Printf("WARN: Konnte EntityCount nicht parsen: %v. Verwende 1.", err) + log.Printf("WARN: Could not parse EntityCount: %v. Using 1.", err) config.EntityCount = 1 } } else { @@ -91,14 +110,88 @@ func loadConfig() { if payloadSizeStr != "" { config.PayloadSize, err = strconv.Atoi(payloadSizeStr) if err != nil { - log.Printf("WARN: Konnte PayloadSize nicht parsen: %v. Verwende 100.", err) + log.Printf("WARN: Could not parse PayloadSize: %v. Using 100.", err) config.PayloadSize = 100 } } else { config.PayloadSize = 100 } - log.Printf("Konfiguration geladen: %+v", config) + // Database Configuration (PostgreSQL) + config.DBHost = viper.GetString("DB_HOST") + config.DBPort = viper.GetString("DB_PORT") + config.DBName = viper.GetString("DB_NAME") + config.DBUser = viper.GetString("DB_USER") + config.DBPass = viper.GetString("DB_PASS") + + // MongoDB Configuration + config.MongoURI = viper.GetString("MONGO_URI") + config.MongoDBName = viper.GetString("MONGO_DBNAME") + + log.Printf("Configuration loaded: %+v", config) +} + +func initDB() { + // 1. MongoDB Initialization + if config.MongoURI != "" && config.MongoDBName != "" { + log.Println("INFO: MongoDB configuration found. Attempting connection...") + clientOptions := options.Client().ApplyURI(config.MongoURI) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + var err error + mongoClient, err = mongo.Connect(ctx, clientOptions) + if err != nil { + log.Fatalf("ERROR: Could not connect to MongoDB: %v", err) + } + + err = mongoClient.Ping(ctx, nil) + if err != nil { + log.Fatalf("ERROR: MongoDB ping failed: %v", err) + } + + mongoCollection = mongoClient.Database(config.MongoDBName).Collection("base") + log.Println("INFO: MongoDB connection established successfully.") + return + } + + // 2. PostgreSQL Initialization (Fallback) + if config.DBHost != "" { + log.Println("INFO: PostgreSQL configuration found. Attempting connection...") + connStr := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", + config.DBHost, config.DBPort, config.DBUser, config.DBPass, config.DBName) + + var err error + sqlDB, err = sql.Open("postgres", connStr) + if err != nil { + log.Fatalf("ERROR: Could not connect to database: %v", err) + } + + // Test connection + err = sqlDB.Ping() + if err != nil { + log.Fatalf("ERROR: Database ping failed: %v", err) + } + + log.Println("INFO: PostgreSQL connection established successfully.") + + // Create table if not exists + createTableSQL := ` + CREATE TABLE IF NOT EXISTS base ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(255), + payload TEXT + );` + _, err = sqlDB.Exec(createTableSQL) + if err != nil { + log.Fatalf("ERROR: Could not create table: %v", err) + } + log.Println("INFO: Table 'base' created or already exists.") + return + } + + log.Println("INFO: No database configuration found. Database functionality disabled.") } func generateBaseDto(id int) BaseDto { @@ -110,50 +203,129 @@ func generateBaseDto(id int) BaseDto { } } +func isDBActive() bool { + return sqlDB != nil || mongoClient != nil +} + +// --- SQL (PostgreSQL) Logic --- + +func getAllFromSQL() ([]BaseDto, error) { + log.Println("Fetching entities from PostgreSQL") + rows, err := sqlDB.Query("SELECT id, name, payload FROM base") + if err != nil { + return nil, err + } + defer rows.Close() + + var dtos []BaseDto + for rows.Next() { + var dto BaseDto + if err := rows.Scan(&dto.ID, &dto.Name, &dto.Payload); err != nil { + return nil, err + } + dtos = append(dtos, dto) + } + return dtos, nil +} + +func saveToSQL(dto BaseDto) (BaseDto, error) { + log.Printf("Saving entity with id %s in PostgreSQL", dto.ID) + insertSQL := `INSERT INTO base (id, name, payload) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET name = $2, payload = $3` + _, err := sqlDB.Exec(insertSQL, dto.ID, dto.Name, dto.Payload) + if err != nil { + return BaseDto{}, err + } + return dto, nil +} + +// --- MongoDB Logic --- + +func getAllFromMongo() ([]BaseDto, error) { + log.Println("Fetching entities from MongoDB") + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + cursor, err := mongoCollection.Find(ctx, bson.M{}) + if err != nil { + return nil, err + } + defer cursor.Close(ctx) + + var dtos []BaseDto + if err = cursor.All(ctx, &dtos); err != nil { + return nil, err + } + return dtos, nil +} + +func saveToMongo(dto BaseDto) (BaseDto, error) { + log.Printf("Saving entity with id %s in MongoDB", dto.ID) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // MongoDB uses upsert for saving/updating + filter := bson.M{"_id": dto.ID} + update := bson.M{"$set": dto} + opts := options.Update().SetUpsert(true) + + _, err := mongoCollection.UpdateOne(ctx, filter, update, opts) + if err != nil { + return BaseDto{}, err + } + return dto, nil +} + +// --- Controller Logic --- + func getAll(c *gin.Context) { log.Println("Entered GET /api/base") time.Sleep(config.RequestDelay) - // Simuliere die Logik aus BaseService.java - // Da wir keine Datenbank haben, simulieren wir nur die "No-Database"-Logik und Upstream-Aufrufe + var result []BaseDto + var err error + + // Case 1: Database is active + if isDBActive() { + if mongoClient != nil { + result, err = getAllFromMongo() + } else if sqlDB != nil { + result, err = getAllFromSQL() + } - // 1. Fall: Upstream-Services sind konfiguriert - if len(config.UpstreamServices) > 0 { + if err != nil { + log.Printf("ERROR fetching from DB: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) + return + } + } else if len(config.UpstreamServices) > 0 { + // Case 2: Upstream services are configured log.Println("Fetching entities from upstream services") var dtos []BaseDto - // Hier müsste die Logik für FeignClients/HTTP-Aufrufe zu Upstream-Services implementiert werden. - // Für diese Demonstration wird dies vereinfacht und nur die Struktur gezeigt. - // In einer vollständigen Implementierung würde man hier HTTP-Clients verwenden. - - // Simuliere den Aufruf und die Aggregation + // Simulate call and aggregation for _, serviceURL := range config.UpstreamServices { log.Printf("Delegating call to %s/api/base", serviceURL) - // Echter HTTP-Aufruf würde hier erfolgen - // Für die Demo geben wir einfach ein Dummy-Ergebnis zurück + // Actual HTTP call would happen here dtos = append(dtos, BaseDto{ ID: fmt.Sprintf("upstream-%s-1", serviceURL), Name: fmt.Sprintf("Upstream Entity from %s", serviceURL), Payload: strings.Repeat("y", config.PayloadSize), }) } - - time.Sleep(config.ResponseDelay) - log.Println("Exiting GET /api/base (Upstream)") - c.JSON(http.StatusOK, dtos) - return - } - - // 2. Fall: Keine Datenbank, keine Upstream-Services (Generierung von Dummy-Daten) - log.Println("Generating dummy entities") - var dtos []BaseDto - for i := 1; i <= config.EntityCount; i++ { - dtos = append(dtos, generateBaseDto(i)) + result = dtos + } else { + // Case 3: No database, no upstream services (generate dummy data) + log.Println("Generating dummy entities") + var dtos []BaseDto + for i := 1; i <= config.EntityCount; i++ { + dtos = append(dtos, generateBaseDto(i)) + } + result = dtos } time.Sleep(config.ResponseDelay) - log.Println("Exiting GET /api/base (Dummy)") - c.JSON(http.StatusOK, dtos) + log.Println("Exiting GET /api/base") + c.JSON(http.StatusOK, result) } func create(c *gin.Context) { @@ -166,46 +338,57 @@ func create(c *gin.Context) { return } - // Simuliere die Logik aus BaseService.java - // 1. Fall: Upstream-Services sind konfiguriert - if len(config.UpstreamServices) > 0 { + var result BaseDto + var err error + + // Case 1: Database is active + if isDBActive() { + if mongoClient != nil { + result, err = saveToMongo(baseDto) + } else if sqlDB != nil { + result, err = saveToSQL(baseDto) + } + + if err != nil { + log.Printf("ERROR saving to DB: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) + return + } + } else if len(config.UpstreamServices) > 0 { + // Case 2: Upstream services are configured log.Printf("Posting dto with id %s to upstream services", baseDto.ID) - // Hier müsste die Logik für FeignClients/HTTP-Aufrufe zu Upstream-Services implementiert werden. - // Für diese Demonstration wird dies vereinfacht. - - // Simuliere den Aufruf und die Rückgabe + // Simulate call and return for _, serviceURL := range config.UpstreamServices { log.Printf("Posting dto with id %s to service %s", baseDto.ID, serviceURL) - // Echter HTTP-Aufruf würde hier erfolgen + // Actual HTTP call would happen here } - - time.Sleep(config.ResponseDelay) - log.Println("Exiting POST /api/base (Upstream)") - c.JSON(http.StatusCreated, baseDto) - return + result = baseDto + } else { + // Case 3: No database, no upstream services (simple return) + result = baseDto } - // 2. Fall: Keine Datenbank, keine Upstream-Services (einfache Rückgabe) time.Sleep(config.ResponseDelay) - log.Println("Exiting POST /api/base (No-DB)") - c.JSON(http.StatusCreated, baseDto) + log.Println("Exiting POST /api/base") + c.JSON(http.StatusCreated, result) } func main() { loadConfig() + initDB() // Initialize database connection - // Gin im Release-Modus für weniger Log-Ausgabe + // Gin in release mode for less log output gin.SetMode(gin.ReleaseMode) router := gin.New() router.Use(gin.Logger(), gin.Recovery()) - // Health Check Endpunkt + // Health Check Endpoint router.GET("/actuator/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "UP"}) }) - // REST Endpunkte + // REST Endpoints api := router.Group("/api/base") { api.GET("/", getAll) @@ -217,8 +400,8 @@ func main() { port = "8080" } - log.Printf("Go Service gestartet auf Port %s", port) + log.Printf("Go Service started on port %s", port) if err := router.Run(":" + port); err != nil { - log.Fatalf("Konnte Server nicht starten: %v", err) + log.Fatalf("Could not start server: %v", err) } }