Commit 527c92e4 by 孙龙

init 2

parent f82dfc47
Showing with 4732 additions and 4 deletions
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build -o .\cmd\ichunt-micro .\main.go
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIDATCCAemgAwIBAgIJAKCCwAOLbkgiMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV
BAMMDGV4YW1wbGUxLmNvbTAeFw0yMDAzMzExNTQzMzZaFw0zMzEyMDgxNTQzMzZa
MBcxFTATBgNVBAMMDGV4YW1wbGUxLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAK0bl7z0oPQYOj2XSiFljYifyzReev77cmYfGg+GQF3WZqIbYppD
ajMi88gOidfcUDZGQI/tPgO8tB5M5TetP/q+apSu6VK7fMpeia417VBvL9T05yCK
R9ylqDzg+he4DFxdruIu8Q4MhhFNoPSw4DGoNYjQw76UFu1x2h4X01MFm9sJ3hhG
LmcTUb27p3EEbi2s/8TZVsTIuBF6GeJrNxDMBRRvgOm4/NCSWQSVPGGOdYJroQJG
FKxSHb+VjAh1GfSD4np7lTgfMGlLvhTt1meynEUYorV15xnoyeD077NM0OX2JG0Z
1HbBUqVd2EO4WFX3kXZDGBB8C3wPg2zYtCUCAwEAAaNQME4wHQYDVR0OBBYEFMOA
FTyjXBBcvO0Z5nY34ITA/vwZMB8GA1UdIwQYMBaAFMOAFTyjXBBcvO0Z5nY34ITA
/vwZMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAG/kIiQalUfXPT4/
QQAMk6msDETY9wEDwnTIsHyXQlZiKxroIgplDHuhlVjRww2Fa0JHqXuRpIJN9UR1
mLZubn3oCMk/hWkgfb714f3/YFho4vyjzfMQ8rwCwrD/r3ZnlMSj39a7bTA7YKW4
Hni4fooM/ny//c+xXeif64yTkmsYCqxSwtVZLvCRJMxfrbgo3f7ILn5rTB7hsUfG
tcwu4g8bNkFnXrVGS1OLBNd53jDDSmPs1pdx9jekR3o8l7Sr5BPo3C/CPOiXdfjJ
Tqm+I2wo6pr/SKbZsslxajGBXjSwhjgkjYRBCLu7wxCJsbxHnl5ORs6O7eoINpcM
e6JTUfY=
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEArRuXvPSg9Bg6PZdKIWWNiJ/LNF56/vtyZh8aD4ZAXdZmohti
mkNqMyLzyA6J19xQNkZAj+0+A7y0HkzlN60/+r5qlK7pUrt8yl6JrjXtUG8v1PTn
IIpH3KWoPOD6F7gMXF2u4i7xDgyGEU2g9LDgMag1iNDDvpQW7XHaHhfTUwWb2wne
GEYuZxNRvbuncQRuLaz/xNlWxMi4EXoZ4ms3EMwFFG+A6bj80JJZBJU8YY51gmuh
AkYUrFIdv5WMCHUZ9IPienuVOB8waUu+FO3WZ7KcRRiitXXnGejJ4PTvs0zQ5fYk
bRnUdsFSpV3YQ7hYVfeRdkMYEHwLfA+DbNi0JQIDAQABAoIBABSNcx2PGdEBU2De
poGCkiRHfJPSJ95AMlvnk2uGb/v0KalTgQh5upEptDHrb/g+AxP+kUnFTBibffMf
BBPxMOhvVS4j+jXFZtKMGOKjKnLjUJWDIjHd2RxcWrYnq+nHA0iwIsRd+GbHm99Q
DS0gFu4uX3TH/IWTBYnZe6EZCRERJmoL3T8oIqW9V8M3lszoQ8UormPAXIH3g+k2
3L3Dy/Eo8IxoFmsYiCWf8ec16lCyOTS9zLvdNGK26SGU7J/w7x7fhqlZ6zLS97lH
KMgVQtoZWz7S9NrrMRpdDbdgz/KVnm465o7E+X2PuwjJsyG3gCjrsNgq4wJgfZzF
QJmE48ECgYEA1lrLUg2hebSaBHbnYKphpEd9jGA1FMDl6S93kwZvQKUhqEBlK5gv
Ty+4R+/Pvc0qtAj+bLwrL8fFwQ0l3sXtpGbpt1jPVO87ui5ikP0Orfc300asjtp2
JViYgaHHW4phWmlqtQGswaXsDFx608a/OrFw3IwlKDUzGtOEb+b6u/ECgYEAzr1U
6OtgDHKD6YlPUwgSujENadZ0BFk6wW91DjEldb9eXycgYenWKg2vJZskylRpvzSQ
uKTtQLAxj7WxCymrtrPpA4XvWbFG3p2mSYLt1XO63UE0MJ1f5FDBW/Co4TM7YMbs
Eknqapwm4ahOtDrSbb3uL95yMJBBRkpJjxKIv3UCgYAxxVkqTzHsIWwVl0o4HreX
PmY/XuNUU0nO8A+Sms7gMrdy6qjTC34Io+rlASC6UFYXAXOZ6cMZUAhxv8zIQirg
nmisArn5Xab/nt+SDMAI0rsqmmFctgrytvSKPPceIS5joNB/AMmNGSqK4DpAzAgA
58xt2TiTcm7QTsaUeQxE8QKBgQCPFk1hVB9LHischLOJRUoo4fBls07i/5sB7JF4
vB0wLL41X1AzVHOs8YGqpoFFJD14X/pWQZgPsKLs0xTxI+s77bM1hAqP6nmhdD12
HY9cr9fCcPGdQB7xV88sQhmwnBPZvHQBiHUdSmxCvImUhi3EVLM5IF2qLP1wl9Pn
mS1aTQKBgDkTOc3Sod1Zj42MBvJQO8uDAjwx/CJDKEh1v2v1roOt0m2H/peJJ9HY
SXB/fk3oXnUyKn23jl9HOwEgArHGTxwnorH7VVOjN8PA5VyPnZzbyRCbo4P24mNT
5GJjUyHXtAKfYn/vL4XneNo8htRmgO/buDA9Mz03LGFZjHn+/sB7
-----END RSA PRIVATE KEY-----
EB10040B98B12C16
package cert_file
import (
"path/filepath"
"runtime"
)
// basepath is the root directory of this package.
var basepath string
func init() {
_, currentFile, _, _ := runtime.Caller(0)
basepath = filepath.Dir(currentFile)
}
func Path(rel string) string {
if filepath.IsAbs(rel) {
return rel
}
return filepath.Join(basepath, rel)
}
-----BEGIN CERTIFICATE-----
MIICqjCCAZICCQDrEAQLmLEsFTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxl
eGFtcGxlMS5jb20wHhcNMjAwMzI5MTMxNTQyWhcNMzMxMjA2MTMxNTQyWjAXMRUw
EwYDVQQDDAxleGFtcGxlMS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDmMVbGx9gdqb3l+WcQAVht5YvIfPhrUx8/PjZ8XUFwqIt8s4JJcmCoYrpi
QwYjckajLNEfeovieFPlx1EpDbMa9C3QFeuqCI453w2InAEiCU6VGKqftSy/OQM0
19fNOX7ec9uB+64AjifSkyjr3GnmJjSHZS8XczKZk4XZV8vA1oUwMvW7shbDL8ar
Qw7MEALFzCFgz7Ff5/Hfpm0gHY0A2ychUTn/w6zB/fTTV5+kYtZNnmFP5zPBdOVX
soNYRY3GXGRAvoJy3o9tzPWetL/0Uzjmc1HU+kHVp2vVhyfsuZldHxgTY9KRA22m
/5jdVPJX5Z4UBEaW5+hrhh8T6BQJAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAETU
I5Tkek8W+I86arMmswXTm+/CsJdpoXAm3xuhXoUQo7QfZI0lQ/vbsSMc26GUn8ho
NLMJvBv31QYIq39dQypFKAloA9mml91jUwMno9L0nsEyYMXcFaUvs2YE5v2RZghN
j86FBGOt0Ou3UDGhvzbQUvIS53gurCavDCFSHVuFxKeLhyVRCoESWClRX426mVv7
lPfHXfAIOs0yZxvxRA/fVokGfqhmTjPIeLPuDTxoR4uVqV/kRJ7tb6mrNAGVhDZJ
BzrhvZ8DbF56sImetftbkMdzIumddy2H3emd8syEf+zy8LLMfXnLS9QXkFD2+RRJ
EaC4UfgFTEcvooUO6/s=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIICXDCCAUQCAQAwFzEVMBMGA1UEAwwMZXhhbXBsZTEuY29tMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5jFWxsfYHam95flnEAFYbeWLyHz4a1MfPz42
fF1BcKiLfLOCSXJgqGK6YkMGI3JGoyzRH3qL4nhT5cdRKQ2zGvQt0BXrqgiOOd8N
iJwBIglOlRiqn7UsvzkDNNfXzTl+3nPbgfuuAI4n0pMo69xp5iY0h2UvF3MymZOF
2VfLwNaFMDL1u7IWwy/Gq0MOzBACxcwhYM+xX+fx36ZtIB2NANsnIVE5/8Oswf30
01efpGLWTZ5hT+czwXTlV7KDWEWNxlxkQL6Cct6Pbcz1nrS/9FM45nNR1PpB1adr
1Ycn7LmZXR8YE2PSkQNtpv+Y3VTyV+WeFARGlufoa4YfE+gUCQIDAQABoAAwDQYJ
KoZIhvcNAQELBQADggEBALEp4ePq57a+XRa7GSS6WUMX5HibHNSqy1VrA5h8LdTP
zFv8ZnasuCgWh3Z7w7j8TeBgygO4wwldbafdXS234rzYas5wXlVFW7tY4jX/jCDy
7ftypbYGnKCMScQ34FKRB2WOZvWEdMYN5i8EyKaBy0Bitc+kZ+yCGSNH57QptOgR
oRMK/r6Z+TGucF6EpLhxgOknUCitGme9FP96A6gs3lLrPQ1yOYE456ubTzq6svVo
5viGzSZwADzGzBNQ0GDr7Fv9boLEKyK+wCB+8us0PDVDid9ryIokjxT+Ddnv19MS
fEL9GdJTyQCu/JWWynQgh1t5uF4vyUgi6wlU8Ermjnw=
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA5jFWxsfYHam95flnEAFYbeWLyHz4a1MfPz42fF1BcKiLfLOC
SXJgqGK6YkMGI3JGoyzRH3qL4nhT5cdRKQ2zGvQt0BXrqgiOOd8NiJwBIglOlRiq
n7UsvzkDNNfXzTl+3nPbgfuuAI4n0pMo69xp5iY0h2UvF3MymZOF2VfLwNaFMDL1
u7IWwy/Gq0MOzBACxcwhYM+xX+fx36ZtIB2NANsnIVE5/8Oswf3001efpGLWTZ5h
T+czwXTlV7KDWEWNxlxkQL6Cct6Pbcz1nrS/9FM45nNR1PpB1adr1Ycn7LmZXR8Y
E2PSkQNtpv+Y3VTyV+WeFARGlufoa4YfE+gUCQIDAQABAoIBAQDh1I/EjnTIjSl/
QBHLUvaVQjjDpU71w+OI4RkFI1w7ES9fVKDCO5L2P32JPyX7inYgSayUDF7F/LSa
XdOSyhznmZyEY60C8EfQILMfTaWS5byRa1ShQFY4987cfdD6RqjfxpwYRnirlMse
vD7OPjwqjVrFZhAwGlUO8/rBgm+jqzUWL4aGoGuH2M/6XP6rUN42GFrLxQnshxpq
CiGTnyB1nYYdQKSEWSBoEthQKNXR/MyTQDHt05EpAu8TQFGi/oXytFzu6LlVlQVB
OdfDAXDcLqF1VyEndjdCNp8i8jWVdvNuHCm/dw2v286HADq8ZnaspG6ghxvegHSF
CPWlAvdxAoGBAPnd2UWFpo95EdvsDo2MKkgJRmqyjx2kkUPjClgZgz6sfrjufV71
Axonj8SCM4QmnjvZN8tdjKc7N1xYOShDAlIUkuAKNw/uxyzuj98Fi5SwEfCrCowT
MlJEliRFcRhSDKJdUwhz+gX3f/SFHLUOT8S2VR3kssesklznB0k9R6CtAoGBAOvX
3EmZd4vDijDLmZ5hz5fmsI9/LYrDSzd5+D0nYHrt0l81Yn69T4TNU6pau3Qv6ZET
5PyDiuDSTi2XLV3TPgeGqimU6E3MzH2ZX69Sqz74JNSrOj2xmiLTHpjFLx2HgYBo
2r/4qaX3UbeLosU+OAgTZz7tAUu8oKaVNWAMp8BNAoGBAMrF+CoMUWRDq3OfORwz
8KgvJr82EyDKSb0fBmkCo1j8YYawvHuQOKlEC888npQTRvxoxne6fofEbaP6UMBU
yRBVc/BvOcorS+Yx3/3soR7UWGrIU7HjbkYHNRVQaXyEMY6eT+EfRXsMJQIJ+IcS
izenhKHS1Cdo7AqKzoXoPjWtAoGBAOY6toBewZX90GRsDU3Q/B+0gv3CUEoa9c11
UwEX9JZsnaZ17e39jqf87UTrB/2XXDJVMn/TRfrNMqZM42upcO9V5b1r8Q8p8yJV
XFRBpox1HzdA5D0fqHGAmWjXbXQtOR2KvqkS7UHoWqyMMtzMLVSs5GhIY7B0tnuI
Qy+9ivEtAoGAdvwxqztV2UTTszPhBZZ5rWhMB1W4DAW4SkqVtChsaVgjPO+w1RCz
sRauu3pewdyhseOouDvGB7nRdozfusr8gE1qimj7T+bvBAz67jfLdjIB/EWt73UM
rypIzF6D7FQMx1FTD1VDBqE3dmkDbTj6A3vrcv9FrqqS+IirNlbwdbk=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIICqjCCAZICCQDrEAQLmLEsFjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxl
eGFtcGxlMS5jb20wHhcNMjAwMzMxMTU0NTA5WhcNMzMxMjA4MTU0NTA5WjAXMRUw
EwYDVQQDDAxleGFtcGxlMS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDMfuI0VxqOmpgFa65BMa6pv5rYYLLAVuQeGNPbl19sZeSNlfR0Zupk2jmg
MTK4F6R77bCpv3505txFxFxn8vFVJcOSDwpZCCl0iTI9jZoYugYh2Mk2bslHCxV0
k/yzVhCCIvxeKFb3/XSUSu4YZ76D9PmqSxGUqKUqXv5lgI3QWDMO3/CwWP6I0SWv
tyxB63mM3UfjfHw301syvJuPxWfAMdCHnxiAa8RlLcoKMawMQUyZqOP5dHmL565V
izHDbrB+B2D2gznoazV95rW7adlpf9cIsQI30ExksL+FnDcmlsChpjooHLJGF8Wg
XZNU1RTfp9oOpA7/K0ul5D9BYGgfAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAXt
FToCcyVURZXKNDKJEw8qHMJshwygtHnnxrZtioGuy2T767PAMWoi7yrv4WSRGnWn
lhM6nx3iUBDRJ7UNEbn3bOQJm5kAVGTb+/dB7rm7slwsQ6Es2Tl+cnr9ySruIs0s
jPRr48ufD3C1275d7KhDXXT2l9un+w5G8a55EfXt5qN5tQByR5jNNsSkYnBhtrbk
VvjSpTm4n98qI3PfMd4JyAJjkxm/qvgeCS6XZS7LdTwf5LTOaEg/+0BZ0KoQC0uu
C35qUJv3hUEXm3bUz/HD2CrFloskD+jcnLcqIWjQ79uFfgJVH4fH+Tl1P+/+N0zp
TEGij1GvoSfrnq30qpc=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIICXDCCAUQCAQAwFzEVMBMGA1UEAwwMZXhhbXBsZTEuY29tMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzH7iNFcajpqYBWuuQTGuqb+a2GCywFbkHhjT
25dfbGXkjZX0dGbqZNo5oDEyuBeke+2wqb9+dObcRcRcZ/LxVSXDkg8KWQgpdIky
PY2aGLoGIdjJNm7JRwsVdJP8s1YQgiL8XihW9/10lEruGGe+g/T5qksRlKilKl7+
ZYCN0FgzDt/wsFj+iNElr7csQet5jN1H43x8N9NbMrybj8VnwDHQh58YgGvEZS3K
CjGsDEFMmajj+XR5i+euVYsxw26wfgdg9oM56Gs1fea1u2nZaX/XCLECN9BMZLC/
hZw3JpbAoaY6KByyRhfFoF2TVNUU36faDqQO/ytLpeQ/QWBoHwIDAQABoAAwDQYJ
KoZIhvcNAQELBQADggEBAGL7N5UnX0K1i0OH+dJmTR2o14qFoub/eb3vXFZmLdmS
KIR3eHBfnQPLwD6cOaoQiOZgBXOLjbV3lXyogDETUtRxBx+8nb4AX63oPyiHCu3M
htJlxvB1tLZRvWePqypKNZ8hJy8c9c71ZvZggj7uzTT/yupjbs/u1s64NSGtEjio
jXhlxOcClqn0NGIzVyyByVKTFCmOqNKBz5ohqCN78DnxRwzB8SOMLT9gzzXemVXg
vOtctJo55KG6D35Ra5I6FVU68851W8o0FQy9Il+2GrbL0Lw8NpEbbGnfbD65fkKZ
33xk9GCEWmCYtL7XkCV1cvRWgKGrmoBK9LsScbH0O2A=
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAzH7iNFcajpqYBWuuQTGuqb+a2GCywFbkHhjT25dfbGXkjZX0
dGbqZNo5oDEyuBeke+2wqb9+dObcRcRcZ/LxVSXDkg8KWQgpdIkyPY2aGLoGIdjJ
Nm7JRwsVdJP8s1YQgiL8XihW9/10lEruGGe+g/T5qksRlKilKl7+ZYCN0FgzDt/w
sFj+iNElr7csQet5jN1H43x8N9NbMrybj8VnwDHQh58YgGvEZS3KCjGsDEFMmajj
+XR5i+euVYsxw26wfgdg9oM56Gs1fea1u2nZaX/XCLECN9BMZLC/hZw3JpbAoaY6
KByyRhfFoF2TVNUU36faDqQO/ytLpeQ/QWBoHwIDAQABAoIBABMQqUoz7Lfq1c17
ko1lcmFFCcyuhzvDXhUoP2gznqPehAZnOpk3lxa7+a9jptTe72jWaigJQGLpuxOO
EQdn8PP9R1RwrohKaIMC33o5n2o6vaOeMHQws/c5o1BxE5gsp/FaDalBnYoVSS8i
JTyFP4/R4QztXsA7UNq4bINODuqjg8O6Fc7AQhXLOe7It8rQxbuNKF0Pps2RwzEL
yTS1Ehi3Rujhb/uBVEnzYZluhylYUZJ2sE7SijNxHGp9sHe6l/YkKC1GLf+7SxvA
3vWC4SU/REnCbfpUKkm8eV2276frvvY9IJSgWaINLOnRrFKfYTEvuuIBm5Bav5Sl
1htTUBECgYEA6L+bwhLy5RD38xjuAIt4a1E7KIU5cDA/a8DUM5rTN3IZqlkbprRl
wSe9MzsudFQd33qzyJXalhvWevrJiycOc3pZ92KDd5cnsh5a+JQkOO68evxyrPpx
+d7+K31fu0qBBxfO26RPMGLOL/7CXfVBOeJZAWH0lO+uI5n8Aphv2TsCgYEA4Oy6
MBaRDWYyM5gZbJdWSk1G9HR3rV8fQgjz9aMQksaJdV0Bm1IgqzMQEuDFr43tK89s
UV/2W4ULl5esKJq9RBs4KsERIrARXgooU2Kw3A3PRzkg7mOS68qL/ESOtxF9F+UC
PSyH8ehdfN6WAdNlxloIXsLJjkHWfJ9/ivYkHm0CgYA2T8gL8JoHg/8oFhArxl/y
QwFYAkaV/FxAS7340M8q6BA/JQ4Dx6LbAOfwlYXQlXRnGt3rF7TrRFG3XuA6/YEs
x0dJKA7fkEEuGlFGImOVeXg4BsLHxKVmFngfM+Fr9gXH3vFhZaUo+FV+86btf/aZ
iE0WuoH1YzyyiBM7k9C90wKBgQDFYDcKl+L15SZMjD5TQoJgdWu8fK/AneZqJj0e
4tdaVYquSM1uJSWx1f9W8ZPIOD1V4pFk31bqfNftURWsFA3eRByHuCB3VhYHddZp
RgN5N00bbRBu4UY+T+GDoA20rE4ft8C9OeSZ7ZSMTS9Jrt5yrvMFZN1GTpQPjE95
/AE6CQKBgDEmZCoZt8vgzqWjsylzuQpx2gWnZT+5rXi3gOGZmzvqdZdOloZqxgVs
EdCP2ZMcwcXecsraoEjdLMCjRVlgw1cCd+ag4yX93FQTcqClx8oqSBSpcoAab7xo
COBb/9wUo4Dl7JztpX3UJacEf0QQpMUcfUAvs+w3rDkRlu0QeLz/
-----END RSA PRIVATE KEY-----
The file could not be displayed because it is too large.
......@@ -8,6 +8,7 @@ import (
_ "ichunt-micro/registry/etcd"
_"github.com/imroc/req"
"io"
"io/ioutil"
"log"
"net/http"
"os"
......@@ -71,7 +72,7 @@ func register(){
&registry.Node{
IP: "192.168.2.246",
Port: 2004,
Weight:2,
Weight:4,
},
)
registryInst.Register(context.TODO(), service)
......@@ -96,8 +97,23 @@ func (r *RealServer) HelloHandler(w http.ResponseWriter, req *http.Request) {
//127.0.0.1:8008/abc?sdsdsa=11
//r.Addr=127.0.0.1:8008
//req.URL.Path=/abc
//time.Sleep(time.Second)
fmt.Println("host:",req.Host)
fmt.Println("header:",req.Header)
fmt.Println("cookie:",req.Cookies())
fmt.Println(req.ParseForm())
fmt.Println("post params: ",req.PostForm)
fmt.Println("url :",req.URL)
fmt.Println("url rawpath :",req.URL.RawPath)
fmt.Println("query :",req.URL.Query())
body, err := ioutil.ReadAll(req.Body)
if err != nil {
fmt.Printf("read body err, %v\n", err)
return
}
println("json:", string(body))
fmt.Println(req.Host)
upath := fmt.Sprintf("http://%s%s\n", r.Addr, req.URL.Path)
realIP := fmt.Sprintf("RemoteAddr=%s,X-Forwarded-For=%v,X-Real-Ip=%v\n", req.RemoteAddr, req.Header.Get("X-Forwarded-For"),
req.Header.Get("X-Real-Ip"))
......
# This is base config
[base]
debug_mode="debug"
time_location="Asia/Chongqing"
[http]
addr =":2002" # 监听地址, default ":8700"
read_timeout = 10 # 读取超时时长
write_timeout = 10 # 写入超时时长
max_header_bytes = 20 # 最大的header大小,二进制位长度
allow_ip = [ # 白名单ip列表
"127.0.0.1",
"192.168.1.1",
]
[session]
redis_server = "192.168.1.235:6379" #redis session server
redis_password = "icDb29mLy2s"
[log]
log_level = "trace" #日志打印最低级别
[log.file_writer] #文件写入配置
on = true
log_path = "./logs/go_gateway.inf.log"
rotate_log_path = "./logs/go_gateway.inf.log.%Y%M%D%H"
wf_log_path = "./logs/go_gateway.wf.log"
rotate_wf_log_path = "./logs/go_gateway.wf.log.%Y%M%D%H"
[log.console_writer] #工作台输出
on = false
color = false
[cluster]
cluster_ip="127.0.0.1"
cluster_port="8080"
cluster_ssl_port="4433"
[swagger]
title="go_gateway swagger API"
desc="This is a sample server celler server."
host="127.0.0.1:8880"
base_path=""
[etcd]
addrs = [
"192.168.2.232:2379"
]
# this is mysql config
[list]
[list.default]
driver_name = "mysql"
data_source_name = "micro_service:lie_micro_service#zsyM@tcp(192.168.2.232:3306)/lie_micro_service?charset=utf8&parseTime=true&loc=Asia%2FChongqing"
max_open_conn = 20
max_idle_conn = 10
max_conn_life_time = 100
\ No newline at end of file
# This is base config
[base]
debug_mode="release"
time_location="Asia/Chongqing"
[http]
addr ="192.168.2.246:2002" # 监听地址, default ":8700"
read_timeout = 10 # 读取超时时长
write_timeout = 10 # 写入超时时长
max_header_bytes = 20 # 最大的header大小,二进制位长度
[https]
addr =":4433" # 监听地址, default ":8700"
read_timeout = 10 # 读取超时时长
write_timeout = 10 # 写入超时时长
max_header_bytes = 20 # 最大的header大小,二进制位长度
\ No newline at end of file
# this is redis config file
[list]
[list.default]
proxy_list = ["192.168.1.235:6379,192.168.1.237:6379"]
conn_timeout = 500
password = "icDb29mLy2s"
db = 0
read_timeout = 1000
write_timeout = 1000
max_active = 200
max_idle = 500
\ No newline at end of file
package controller
import (
"encoding/json"
"fmt"
"ichunt-micro/dao"
"ichunt-micro/dto"
"ichunt-micro/middleware"
"ichunt-micro/public"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
)
type AdminController struct{}
func AdminRegister(group *gin.RouterGroup) {
adminLogin := &AdminController{}
group.GET("/admin_info", adminLogin.AdminInfo)
group.POST("/change_pwd", adminLogin.ChangePwd)
}
// AdminInfo godoc
// @Summary 管理员信息
// @Description 管理员信息
// @Tags 管理员接口
// @ID /admin/admin_info
// @Accept json
// @Produce json
// @Success 200 {object} middleware.Response{data=dto.AdminInfoOutput} "success"
// @Router /admin/admin_info [get]
func (adminlogin *AdminController) AdminInfo(c *gin.Context) {
sess := sessions.Default(c)
sessInfo := sess.Get(public.AdminSessionInfoKey)
adminSessionInfo := &dto.AdminSessionInfo{}
if err := json.Unmarshal([]byte(fmt.Sprint(sessInfo)), adminSessionInfo); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
//1. 读取sessionKey对应json 转换为结构体
//2. 取出数据然后封装输出结构体
//Avatar string `json:"avatar"`
//Introduction string `json:"introduction"`
//Roles []string `json:"roles"`
out := &dto.AdminInfoOutput{
ID: adminSessionInfo.ID,
Name: adminSessionInfo.UserName,
LoginTime: adminSessionInfo.LoginTime,
Avatar: "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
Introduction: "I am a super administrator",
Roles: []string{"admin"},
}
middleware.ResponseSuccess(c, out)
}
// ChangePwd godoc
// @Summary 修改密码
// @Description 修改密码
// @Tags 管理员接口
// @ID /admin/change_pwd
// @Accept json
// @Produce json
// @Param body body dto.ChangePwdInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /admin/change_pwd [post]
func (adminlogin *AdminController) ChangePwd(c *gin.Context) {
params := &dto.ChangePwdInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
//1. session读取用户信息到结构体 sessInfo
//2. sessInfo.ID 读取数据库信息 adminInfo
//3. params.password+adminInfo.salt sha256 saltPassword
//4. saltPassword==> adminInfo.password 执行数据保存
//session读取用户信息到结构体
sess := sessions.Default(c)
sessInfo := sess.Get(public.AdminSessionInfoKey)
adminSessionInfo := &dto.AdminSessionInfo{}
if err := json.Unmarshal([]byte(fmt.Sprint(sessInfo)), adminSessionInfo); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
//从数据库中读取 adminInfo
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
adminInfo := &dao.Admin{}
adminInfo, err = adminInfo.Find(c, tx, (&dao.Admin{UserName: adminSessionInfo.UserName}))
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
//生成新密码 saltPassword
saltPassword := public.GenSaltPassword(adminInfo.Salt, params.Password)
adminInfo.Password = saltPassword
//执行数据保存
if err := adminInfo.Save(c, tx); err != nil {
middleware.ResponseError(c, 2003, err)
return
}
middleware.ResponseSuccess(c, "")
}
package controller
import (
"encoding/json"
"ichunt-micro/dao"
"ichunt-micro/dto"
"ichunt-micro/middleware"
"ichunt-micro/public"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
"time"
)
type AdminLoginController struct{}
func AdminLoginRegister(group *gin.RouterGroup) {
adminLogin := &AdminLoginController{}
group.POST("/login", adminLogin.AdminLogin)
group.GET("/logout", adminLogin.AdminLoginOut)
}
// AdminLogin godoc
// @Summary 管理员登陆
// @Description 管理员登陆
// @Tags 管理员接口
// @ID /admin_login/login
// @Accept json
// @Produce json
// @Param body body dto.AdminLoginInput true "body"
// @Success 200 {object} middleware.Response{data=dto.AdminLoginOutput} "success"
// @Router /admin_login/login [post]
func (adminlogin *AdminLoginController) AdminLogin(c *gin.Context) {
params := &dto.AdminLoginInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
//1. params.UserName 取得管理员信息 admininfo
//2. admininfo.salt + params.Password sha256 => saltPassword
//3. saltPassword==admininfo.password
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
admin := &dao.Admin{}
admin, err = admin.LoginCheck(c, tx, params)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
//设置session
sessInfo := &dto.AdminSessionInfo{
ID: admin.Id,
UserName: admin.UserName,
LoginTime: time.Now(),
}
sessBts, err := json.Marshal(sessInfo)
if err != nil {
middleware.ResponseError(c, 2003, err)
return
}
sess := sessions.Default(c)
sess.Set(public.AdminSessionInfoKey, string(sessBts))
sess.Save()
out := &dto.AdminLoginOutput{Token: admin.UserName}
middleware.ResponseSuccess(c, out)
}
// AdminLogin godoc
// @Summary 管理员退出
// @Description 管理员退出
// @Tags 管理员接口
// @ID /admin_login/logout
// @Accept json
// @Produce json
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /admin_login/logout [get]
func (adminlogin *AdminLoginController) AdminLoginOut(c *gin.Context) {
sess := sessions.Default(c)
sess.Delete(public.AdminSessionInfoKey)
sess.Save()
middleware.ResponseSuccess(c, "")
}
package controller
import (
"ichunt-micro/dao"
"ichunt-micro/dto"
"ichunt-micro/middleware"
"ichunt-micro/public"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"time"
)
//APPControllerRegister admin路由注册
func APPRegister(router *gin.RouterGroup) {
admin := APPController{}
router.GET("/app_list", admin.APPList)
router.GET("/app_detail", admin.APPDetail)
router.GET("/app_stat", admin.AppStatistics)
router.GET("/app_delete", admin.APPDelete)
router.POST("/app_add", admin.AppAdd)
router.POST("/app_update", admin.AppUpdate)
}
type APPController struct {
}
// APPList godoc
// @Summary 租户列表
// @Description 租户列表
// @Tags 租户管理
// @ID /app/app_list
// @Accept json
// @Produce json
// @Param info query string false "关键词"
// @Param page_size query string true "每页多少条"
// @Param page_no query string true "页码"
// @Success 200 {object} middleware.Response{data=dto.APPListOutput} "success"
// @Router /app/app_list [get]
func (admin *APPController) APPList(c *gin.Context) {
params := &dto.APPListInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
info := &dao.App{}
list, total, err := info.APPList(c, lib.GORMDefaultPool, params)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
outputList := []dto.APPListItemOutput{}
for _, item := range list {
appCounter, err := public.FlowCounterHandler.GetCounter(public.FlowAppPrefix + item.AppID)
if err != nil {
middleware.ResponseError(c, 2003, err)
c.Abort()
return
}
outputList = append(outputList, dto.APPListItemOutput{
ID: item.ID,
AppID: item.AppID,
Name: item.Name,
Secret: item.Secret,
WhiteIPS: item.WhiteIPS,
Qpd: item.Qpd,
Qps: item.Qps,
RealQpd: appCounter.TotalCount,
RealQps: appCounter.QPS,
})
}
output := dto.APPListOutput{
List: outputList,
Total: total,
}
middleware.ResponseSuccess(c, output)
return
}
// APPDetail godoc
// @Summary 租户详情
// @Description 租户详情
// @Tags 租户管理
// @ID /app/app_detail
// @Accept json
// @Produce json
// @Param id query string true "租户ID"
// @Success 200 {object} middleware.Response{data=dao.App} "success"
// @Router /app/app_detail [get]
func (admin *APPController) APPDetail(c *gin.Context) {
params := &dto.APPDetailInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
search := &dao.App{
ID: params.ID,
}
detail, err := search.Find(c, lib.GORMDefaultPool, search)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
middleware.ResponseSuccess(c, detail)
return
}
// APPDelete godoc
// @Summary 租户删除
// @Description 租户删除
// @Tags 租户管理
// @ID /app/app_delete
// @Accept json
// @Produce json
// @Param id query string true "租户ID"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /app/app_delete [get]
func (admin *APPController) APPDelete(c *gin.Context) {
params := &dto.APPDetailInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
search := &dao.App{
ID: params.ID,
}
info, err := search.Find(c, lib.GORMDefaultPool, search)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
info.IsDelete = 1
if err := info.Save(c, lib.GORMDefaultPool); err != nil {
middleware.ResponseError(c, 2003, err)
return
}
middleware.ResponseSuccess(c, "")
return
}
// AppAdd godoc
// @Summary 租户添加
// @Description 租户添加
// @Tags 租户管理
// @ID /app/app_add
// @Accept json
// @Produce json
// @Param body body dto.APPAddHttpInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /app/app_add [post]
func (admin *APPController) AppAdd(c *gin.Context) {
params := &dto.APPAddHttpInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
//验证app_id是否被占用
search := &dao.App{
AppID: params.AppID,
}
if _, err := search.Find(c, lib.GORMDefaultPool, search); err == nil {
middleware.ResponseError(c, 2002, errors.New("租户ID被占用,请重新输入"))
return
}
if params.Secret == "" {
params.Secret = public.MD5(params.AppID)
}
tx := lib.GORMDefaultPool
info := &dao.App{
AppID: params.AppID,
Name: params.Name,
Secret: params.Secret,
WhiteIPS: params.WhiteIPS,
Qps: params.Qps,
Qpd: params.Qpd,
}
if err := info.Save(c, tx); err != nil {
middleware.ResponseError(c, 2003, err)
return
}
middleware.ResponseSuccess(c, "")
return
}
// AppUpdate godoc
// @Summary 租户更新
// @Description 租户更新
// @Tags 租户管理
// @ID /app/app_update
// @Accept json
// @Produce json
// @Param body body dto.APPUpdateHttpInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /app/app_update [post]
func (admin *APPController) AppUpdate(c *gin.Context) {
params := &dto.APPUpdateHttpInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
search := &dao.App{
ID: params.ID,
}
info, err := search.Find(c, lib.GORMDefaultPool, search)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
if params.Secret == "" {
params.Secret = public.MD5(params.AppID)
}
info.Name = params.Name
info.Secret = params.Secret
info.WhiteIPS = params.WhiteIPS
info.Qps = params.Qps
info.Qpd = params.Qpd
if err := info.Save(c, lib.GORMDefaultPool); err != nil {
middleware.ResponseError(c, 2003, err)
return
}
middleware.ResponseSuccess(c, "")
return
}
// AppStatistics godoc
// @Summary 租户统计
// @Description 租户统计
// @Tags 租户管理
// @ID /app/app_stat
// @Accept json
// @Produce json
// @Param id query string true "租户ID"
// @Success 200 {object} middleware.Response{data=dto.StatisticsOutput} "success"
// @Router /app/app_stat [get]
func (admin *APPController) AppStatistics(c *gin.Context) {
params := &dto.APPDetailInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
search := &dao.App{
ID: params.ID,
}
detail, err := search.Find(c, lib.GORMDefaultPool, search)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
//今日流量全天小时级访问统计
todayStat := []int64{}
counter, err := public.FlowCounterHandler.GetCounter(public.FlowAppPrefix + detail.AppID)
if err != nil {
middleware.ResponseError(c, 2002, err)
c.Abort()
return
}
currentTime:= time.Now()
for i := 0; i <= time.Now().In(lib.TimeLocation).Hour(); i++ {
dateTime:=time.Date(currentTime.Year(),currentTime.Month(),currentTime.Day(),i,0,0,0,lib.TimeLocation)
hourData,_:=counter.GetHourData(dateTime)
todayStat = append(todayStat, hourData)
}
//昨日流量全天小时级访问统计
yesterdayStat := []int64{}
yesterTime:= currentTime.Add(-1*time.Duration(time.Hour*24))
for i := 0; i <= 23; i++ {
dateTime:=time.Date(yesterTime.Year(),yesterTime.Month(),yesterTime.Day(),i,0,0,0,lib.TimeLocation)
hourData,_:=counter.GetHourData(dateTime)
yesterdayStat = append(yesterdayStat, hourData)
}
stat := dto.StatisticsOutput{
Today: todayStat,
Yesterday: yesterdayStat,
}
middleware.ResponseSuccess(c, stat)
return
}
package controller
import (
"ichunt-micro/dao"
"ichunt-micro/dto"
"ichunt-micro/middleware"
"ichunt-micro/public"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"time"
)
type DashboardController struct{}
func DashboardRegister(group *gin.RouterGroup) {
service := &DashboardController{}
group.GET("/panel_group_data", service.PanelGroupData)
group.GET("/flow_stat", service.FlowStat)
group.GET("/service_stat", service.ServiceStat)
}
// PanelGroupData godoc
// @Summary 指标统计
// @Description 指标统计
// @Tags 首页大盘
// @ID /dashboard/panel_group_data
// @Accept json
// @Produce json
// @Success 200 {object} middleware.Response{data=dto.PanelGroupDataOutput} "success"
// @Router /dashboard/panel_group_data [get]
func (service *DashboardController) PanelGroupData(c *gin.Context) {
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
serviceInfo := &dao.ServiceInfo{}
_, serviceNum, err := serviceInfo.PageList(c, tx, &dto.ServiceListInput{PageSize: 1, PageNo: 1})
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
app := &dao.App{}
_, appNum, err := app.APPList(c, tx, &dto.APPListInput{PageNo: 1, PageSize: 1})
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
counter, err := public.FlowCounterHandler.GetCounter(public.FlowTotal)
if err != nil {
middleware.ResponseError(c, 2003, err)
return
}
out := &dto.PanelGroupDataOutput{
ServiceNum: serviceNum,
AppNum: appNum,
TodayRequestNum: counter.TotalCount,
CurrentQPS: counter.QPS,
}
middleware.ResponseSuccess(c, out)
}
// ServiceStat godoc
// @Summary 服务统计
// @Description 服务统计
// @Tags 首页大盘
// @ID /dashboard/service_stat
// @Accept json
// @Produce json
// @Success 200 {object} middleware.Response{data=dto.DashServiceStatOutput} "success"
// @Router /dashboard/service_stat [get]
func (service *DashboardController) ServiceStat(c *gin.Context) {
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
serviceInfo := &dao.ServiceInfo{}
list, err := serviceInfo.GroupByLoadType(c, tx)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
legend := []string{}
for index, item := range list {
name, ok := public.LoadTypeMap[item.LoadType]
if !ok {
middleware.ResponseError(c, 2003, errors.New("load_type not found"))
return
}
list[index].Name = name
legend = append(legend, name)
}
out := &dto.DashServiceStatOutput{
Legend: legend,
Data: list,
}
middleware.ResponseSuccess(c, out)
}
// FlowStat godoc
// @Summary 服务统计
// @Description 服务统计
// @Tags 首页大盘
// @ID /dashboard/flow_stat
// @Accept json
// @Produce json
// @Success 200 {object} middleware.Response{data=dto.ServiceStatOutput} "success"
// @Router /dashboard/flow_stat [get]
func (service *DashboardController) FlowStat(c *gin.Context) {
counter, err := public.FlowCounterHandler.GetCounter(public.FlowTotal)
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
todayList := []int64{}
currentTime := time.Now()
for i := 0; i <= currentTime.Hour(); i++ {
dateTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), i, 0, 0, 0, lib.TimeLocation)
hourData, _ := counter.GetHourData(dateTime)
todayList = append(todayList, hourData)
}
yesterdayList := []int64{}
yesterTime := currentTime.Add(-1 * time.Duration(time.Hour*24))
for i := 0; i <= 23; i++ {
dateTime := time.Date(yesterTime.Year(), yesterTime.Month(), yesterTime.Day(), i, 0, 0, 0, lib.TimeLocation)
hourData, _ := counter.GetHourData(dateTime)
yesterdayList = append(yesterdayList, hourData)
}
middleware.ResponseSuccess(c, &dto.ServiceStatOutput{
Today: todayList,
Yesterday: yesterdayList,
})
}
package controller
import (
"encoding/base64"
"github.com/dgrijalva/jwt-go"
"ichunt-micro/dao"
"ichunt-micro/dto"
"ichunt-micro/middleware"
"ichunt-micro/public"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"strings"
"time"
)
type OAuthController struct{}
func OAuthRegister(group *gin.RouterGroup) {
oauth := &OAuthController{}
group.POST("/tokens", oauth.Tokens)
}
// Tokens godoc
// @Summary 获取TOKEN
// @Description 获取TOKEN
// @Tags OAUTH
// @ID /oauth/tokens
// @Accept json
// @Produce json
// @Param body body dto.TokensInput true "body"
// @Success 200 {object} middleware.Response{data=dto.TokensOutput} "success"
// @Router /oauth/tokens [post]
func (oauth *OAuthController) Tokens(c *gin.Context) {
params := &dto.TokensInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
splits := strings.Split(c.GetHeader("Authorization"), " ")
if len(splits) != 2 {
middleware.ResponseError(c, 2001, errors.New("用户名或密码格式错误"))
return
}
appSecret, err := base64.StdEncoding.DecodeString(splits[1])
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
//fmt.Println("appSecret", string(appSecret))
// 取出 app_id secret
// 生成 app_list
// 匹配 app_id
// 基于 jwt生成token
// 生成 output
parts := strings.Split(string(appSecret), ":")
if len(parts) != 2 {
middleware.ResponseError(c, 2003, errors.New("用户名或密码格式错误"))
return
}
appList := dao.AppManagerHandler.GetAppList()
for _, appInfo := range appList {
if appInfo.AppID == parts[0] && appInfo.Secret == parts[1] {
claims := jwt.StandardClaims{
Issuer: appInfo.AppID,
ExpiresAt: time.Now().Add(public.JwtExpires * time.Second).In(lib.TimeLocation).Unix(),
}
token,err:=public.JwtEncode(claims)
if err != nil {
middleware.ResponseError(c, 2004, err)
return
}
output := &dto.TokensOutput{
ExpiresIn:public.JwtExpires,
TokenType:"Bearer",
AccessToken:token,
Scope:"read_write",
}
middleware.ResponseSuccess(c, output)
return
}
}
middleware.ResponseError(c, 2005,errors.New("未匹配正确APP信息"))
}
// AdminLogin godoc
// @Summary 管理员退出
// @Description 管理员退出
// @Tags 管理员接口
// @ID /admin_login/logout
// @Accept json
// @Produce json
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /admin_login/logout [get]
func (adminlogin *OAuthController) AdminLoginOut(c *gin.Context) {
sess := sessions.Default(c)
sess.Delete(public.AdminSessionInfoKey)
sess.Save()
middleware.ResponseSuccess(c, "")
}
package dao
import (
"ichunt-micro/dto"
"ichunt-micro/public"
"github.com/e421083458/gorm"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"time"
)
type Admin struct {
Id int `json:"id" gorm:"primary_key" description:"自增主键"`
UserName string `json:"user_name" gorm:"column:user_name" description:"管理员用户名"`
Salt string `json:"salt" gorm:"column:salt" description:"盐"`
Password string `json:"password" gorm:"column:password" description:"密码"`
UpdatedAt time.Time `json:"update_at" gorm:"column:update_at" description:"更新时间"`
CreatedAt time.Time `json:"create_at" gorm:"column:create_at" description:"创建时间"`
IsDelete int `json:"is_delete" gorm:"column:is_delete" description:"是否删除"`
}
func (t *Admin) TableName() string {
return "gateway_admin"
}
func (t *Admin) LoginCheck(c *gin.Context, tx *gorm.DB, param *dto.AdminLoginInput) (*Admin, error) {
adminInfo, err := t.Find(c, tx, (&Admin{UserName: param.UserName, IsDelete: 0}))
if err != nil {
return nil, errors.New("用户信息不存在")
}
saltPassword := public.GenSaltPassword(adminInfo.Salt, param.Password)
if adminInfo.Password != saltPassword {
return nil, errors.New("密码错误,请重新输入")
}
return adminInfo, nil
}
func (t *Admin) Find(c *gin.Context, tx *gorm.DB, search *Admin) (*Admin, error) {
out := &Admin{}
err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(out).Error
if err != nil {
return nil, err
}
return out, nil
}
func (t *Admin) Save(c *gin.Context, tx *gorm.DB) error {
return tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error
}
package dao
import (
"ichunt-micro/dto"
"ichunt-micro/public"
"ichunt-micro/golang_common/lib"
"github.com/e421083458/gorm"
"github.com/gin-gonic/gin"
"net/http/httptest"
"sync"
"time"
)
type App struct {
ID int64 `json:"id" gorm:"primary_key"`
AppID string `json:"app_id" gorm:"column:app_id" description:"租户id "`
Name string `json:"name" gorm:"column:name" description:"租户名称 "`
Secret string `json:"secret" gorm:"column:secret" description:"密钥"`
WhiteIPS string `json:"white_ips" gorm:"column:white_ips" description:"ip白名单,支持前缀匹配"`
Qpd int64 `json:"qpd" gorm:"column:qpd" description:"日请求量限制"`
Qps int64 `json:"qps" gorm:"column:qps" description:"每秒请求量限制"`
CreatedAt time.Time `json:"create_at" gorm:"column:create_at" description:"添加时间 "`
UpdatedAt time.Time `json:"update_at" gorm:"column:update_at" description:"更新时间"`
IsDelete int8 `json:"is_delete" gorm:"column:is_delete" description:"是否已删除;0:否;1:是"`
}
func (t *App) TableName() string {
return "gateway_app"
}
func (t *App) Find(c *gin.Context, tx *gorm.DB, search *App) (*App, error) {
model := &App{}
err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(model).Error
return model, err
}
func (t *App) Save(c *gin.Context, tx *gorm.DB) error {
if err := tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error; err != nil {
return err
}
return nil
}
func (t *App) APPList(c *gin.Context, tx *gorm.DB, params *dto.APPListInput) ([]App, int64, error) {
var list []App
var count int64
pageNo := params.PageNo
pageSize := params.PageSize
//limit offset,pagesize
offset := (pageNo - 1) * pageSize
query := tx.SetCtx(public.GetGinTraceContext(c))
query = query.Table(t.TableName()).Select("*")
query = query.Where("is_delete=?", 0)
if params.Info != "" {
query = query.Where(" (name like ? or app_id like ?)", "%"+params.Info+"%", "%"+params.Info+"%")
}
err := query.Limit(pageSize).Offset(offset).Order("id desc").Find(&list).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, 0, err
}
errCount := query.Count(&count).Error
if errCount != nil {
return nil, 0, err
}
return list, count, nil
}
var AppManagerHandler *AppManager
func init() {
AppManagerHandler = NewAppManager()
}
type AppManager struct {
AppMap map[string]*App
AppSlice []*App
Locker sync.RWMutex
init sync.Once
err error
}
func NewAppManager() *AppManager {
return &AppManager{
AppMap: map[string]*App{},
AppSlice: []*App{},
Locker: sync.RWMutex{},
init: sync.Once{},
}
}
func (s *AppManager) GetAppList() []*App {
return s.AppSlice
}
func (s *AppManager) LoadOnce() error {
s.init.Do(func() {
appInfo := &App{}
c, _ := gin.CreateTestContext(httptest.NewRecorder())
tx, err := lib.GetGormPool("default")
if err != nil {
s.err = err
return
}
params := &dto.APPListInput{PageNo: 1, PageSize: 99999}
list, _, err := appInfo.APPList(c, tx, params)
if err != nil {
s.err = err
return
}
s.Locker.Lock()
defer s.Locker.Unlock()
for _, listItem := range list {
tmpItem := listItem
s.AppMap[listItem.AppID] = &tmpItem
s.AppSlice = append(s.AppSlice, &tmpItem)
}
})
return s.err
}
package dao
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"ichunt-micro/dto"
"ichunt-micro/golang_common/lib"
"ichunt-micro/public"
"net/http/httptest"
"strings"
"sync"
)
type ServiceDetail struct {
Info *ServiceInfo `json:"info" description:"基本信息"`
HTTPRule *HttpRule `json:"http_rule" description:"http_rule"`
TCPRule *TcpRule `json:"tcp_rule" description:"tcp_rule"`
GRPCRule *GrpcRule `json:"grpc_rule" description:"grpc_rule"`
LoadBalance *LoadBalance `json:"load_balance" description:"load_balance"`
AccessControl *AccessControl `json:"access_control" description:"access_control"`
}
var ServiceManagerHandler *ServiceManager
func init() {
ServiceManagerHandler = NewServiceManager()
}
type ServiceManager struct {
ServiceMap map[string]*ServiceDetail
ServiceSlice []*ServiceDetail
Locker sync.RWMutex
init sync.Once
err error
}
func NewServiceManager() *ServiceManager {
return &ServiceManager{
ServiceMap: map[string]*ServiceDetail{},
ServiceSlice: []*ServiceDetail{},
Locker: sync.RWMutex{},
init: sync.Once{},
}
}
func (s *ServiceManager) GetTcpServiceList() []*ServiceDetail {
list := []*ServiceDetail{}
for _, serverItem := range s.ServiceSlice {
tempItem := serverItem
if tempItem.Info.LoadType == public.LoadTypeTCP {
list = append(list, tempItem)
}
}
return list
}
func (s *ServiceManager) GetGrpcServiceList() []*ServiceDetail {
list := []*ServiceDetail{}
for _, serverItem := range s.ServiceSlice {
tempItem := serverItem
if tempItem.Info.LoadType == public.LoadTypeGRPC {
list = append(list, tempItem)
}
}
return list
}
func (s *ServiceManager) HTTPAccessMode(c *gin.Context) (*ServiceDetail, error) {
//1、前缀匹配 /abc ==> serviceSlice.rule
//2、域名匹配 www.test.com ==> serviceSlice.rule
//ex http://192.168.2.246:2002/ichuntMicroService/test?a=1
//host c.Request.Host 192.168.2.246:2002
//path c.Request.URL.Path
host := c.Request.Host
//192.168.2.246:2002
host = host[0:strings.Index(host, ":")]
//192.168.2.246
path := c.Request.URL.Path
// /ichuntMicroService/test
for _, serviceItem := range s.ServiceSlice {
//负载类型 0=http 1=tcp 2=grpc
//不等于http
if serviceItem.Info.LoadType != public.LoadTypeHTTP {
continue
}
//匹配类型 domain=域名, url_prefix=url前缀
//域名
if serviceItem.HTTPRule.RuleType == public.HTTPRuleTypeDomain {
if serviceItem.HTTPRule.Rule == host {
return serviceItem, nil
}
}
//前缀
if serviceItem.HTTPRule.RuleType == public.HTTPRuleTypePrefixURL {
if strings.HasPrefix(path, serviceItem.HTTPRule.Rule) {
return serviceItem, nil
}
}
}
return nil, errors.New(fmt.Sprintf("没有匹配的服务 %s,%s",host,path))
}
func (s *ServiceManager) LoadOnce() error {
s.init.Do(func() {
serviceInfo := &ServiceInfo{}
c, _ := gin.CreateTestContext(httptest.NewRecorder())
tx, err := lib.GetGormPool("default")
if err != nil {
s.err = err
return
}
params := &dto.ServiceListInput{PageNo: 1, PageSize: 99999}
list, _, err := serviceInfo.PageList(c, tx, params)
if err != nil {
s.err = err
return
}
s.Locker.Lock()
defer s.Locker.Unlock()
for _, listItem := range list {
tmpItem := listItem
serviceDetail, err := tmpItem.ServiceDetail(c, tx, &tmpItem)
//fmt.Println("serviceDetail")
//fmt.Println(public.Obj2Json(serviceDetail))
if err != nil {
s.err = err
return
}
//fmt.Println(public.Obj2Json(serviceDetail))
s.ServiceMap[listItem.ServiceName] = serviceDetail
s.ServiceSlice = append(s.ServiceSlice, serviceDetail)
}
})
return s.err
}
package dao
import (
"ichunt-micro/public"
"github.com/e421083458/gorm"
"github.com/gin-gonic/gin"
)
type AccessControl struct {
ID int64 `json:"id" gorm:"primary_key"`
ServiceID int64 `json:"service_id" gorm:"column:service_id" description:"服务id"`
OpenAuth int `json:"open_auth" gorm:"column:open_auth" description:"是否开启权限 1=开启"`
BlackList string `json:"black_list" gorm:"column:black_list" description:"黑名单ip "`
WhiteList string `json:"white_list" gorm:"column:white_list" description:"白名单ip "`
WhiteHostName string `json:"white_host_name" gorm:"column:white_host_name" description:"白名单主机 "`
ClientIPFlowLimit int `json:"clientip_flow_limit" gorm:"column:clientip_flow_limit" description:"客户端ip限流 "`
ServiceFlowLimit int `json:"service_flow_limit" gorm:"column:service_flow_limit" description:"服务端限流 "`
}
func (t *AccessControl) TableName() string {
return "gateway_service_access_control"
}
func (t *AccessControl) Find(c *gin.Context, tx *gorm.DB, search *AccessControl) (*AccessControl, error) {
model := &AccessControl{}
err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(model).Error
return model, err
}
func (t *AccessControl) Save(c *gin.Context, tx *gorm.DB) error {
if err := tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error; err != nil {
return err
}
return nil
}
func (t *AccessControl) ListBYServiceID(c *gin.Context, tx *gorm.DB, serviceID int64) ([]AccessControl, int64, error) {
var list []AccessControl
var count int64
query := tx.SetCtx(public.GetGinTraceContext(c))
query = query.Table(t.TableName()).Select("*")
query = query.Where("service_id=?", serviceID)
err := query.Order("id desc").Find(&list).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, 0, err
}
errCount := query.Count(&count).Error
if errCount != nil {
return nil, 0, err
}
return list, count, nil
}
package dao
import (
"ichunt-micro/public"
"github.com/e421083458/gorm"
"github.com/gin-gonic/gin"
)
type GrpcRule struct {
ID int64 `json:"id" gorm:"primary_key"`
ServiceID int64 `json:"service_id" gorm:"column:service_id" description:"服务id "`
Port int `json:"port" gorm:"column:port" description:"端口 "`
HeaderTransfor string `json:"header_transfor" gorm:"column:header_transfor" description:"header转换支持增加(add)、删除(del)、修改(edit) 格式: add headname headvalue"`
}
func (t *GrpcRule) TableName() string {
return "gateway_service_grpc_rule"
}
func (t *GrpcRule) Find(c *gin.Context, tx *gorm.DB, search *GrpcRule) (*GrpcRule, error) {
model := &GrpcRule{}
err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(model).Error
return model, err
}
func (t *GrpcRule) Save(c *gin.Context, tx *gorm.DB) error {
if err := tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error; err != nil {
return err
}
return nil
}
func (t *GrpcRule) ListByServiceID(c *gin.Context, tx *gorm.DB, serviceID int64) ([]GrpcRule, int64, error) {
var list []GrpcRule
var count int64
query := tx.SetCtx(public.GetGinTraceContext(c))
query = query.Table(t.TableName()).Select("*")
query = query.Where("service_id=?", serviceID)
err := query.Order("id desc").Find(&list).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, 0, err
}
errCount := query.Count(&count).Error
if errCount != nil {
return nil, 0, err
}
return list, count, nil
}
package dao
import (
"ichunt-micro/public"
"github.com/e421083458/gorm"
"github.com/gin-gonic/gin"
)
type HttpRule struct {
ID int64 `json:"id" gorm:"primary_key"`
ServiceID int64 `json:"service_id" gorm:"column:service_id" description:"服务id"`
RuleType int `json:"rule_type" gorm:"column:rule_type" description:"匹配类型 domain=域名, url_prefix=url前缀"`
Rule string `json:"rule" gorm:"column:rule" description:"type=domain表示域名,type=url_prefix时表示url前缀"`
NeedHttps int `json:"need_https" gorm:"column:need_https" description:"type=支持https 1=支持"`
NeedWebsocket int `json:"need_websocket" gorm:"column:need_websocket" description:"启用websocket 1=启用"`
NeedStripUri int `json:"need_strip_uri" gorm:"column:need_strip_uri" description:"启用strip_uri 1=启用"`
UrlRewrite string `json:"url_rewrite" gorm:"column:url_rewrite" description:"url重写功能,每行一个 "`
HeaderTransfor string `json:"header_transfor" gorm:"column:header_transfor" description:"header转换支持增加(add)、删除(del)、修改(edit) 格式: add headname headvalue "`
}
func (t *HttpRule) TableName() string {
return "gateway_service_http_rule"
}
func (t *HttpRule) Find(c *gin.Context, tx *gorm.DB, search *HttpRule) (*HttpRule, error) {
model := &HttpRule{}
err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(model).Error
return model, err
}
func (t *HttpRule) Save(c *gin.Context, tx *gorm.DB) error {
if err := tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error; err != nil {
return err
}
return nil
}
func (t *HttpRule) ListByServiceID(c *gin.Context, tx *gorm.DB, serviceID int64) ([]HttpRule, int64, error) {
var list []HttpRule
var count int64
query := tx.SetCtx(public.GetGinTraceContext(c))
query = query.Table(t.TableName()).Select("*")
query = query.Where("service_id=?", serviceID)
err := query.Order("id desc").Find(&list).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, 0, err
}
errCount := query.Count(&count).Error
if errCount != nil {
return nil, 0, err
}
return list, count, nil
}
package dao
import (
"ichunt-micro/dto"
"ichunt-micro/public"
"github.com/e421083458/gorm"
"github.com/gin-gonic/gin"
"time"
)
type ServiceInfo struct {
ID int64 `json:"id" gorm:"primary_key"`
LoadType int `json:"load_type" gorm:"column:load_type" description:"负载类型 0=http 1=tcp 2=grpc"`
ServiceName string `json:"service_name" gorm:"column:service_name" description:"服务名称"`
ServiceDesc string `json:"service_desc" gorm:"column:service_desc" description:"服务描述"`
UpdatedAt time.Time `json:"create_at" gorm:"column:create_at" description:"更新时间"`
CreatedAt time.Time `json:"update_at" gorm:"column:update_at" description:"添加时间"`
IsDelete int8 `json:"is_delete" gorm:"column:is_delete" description:"是否已删除;0:否;1:是"`
}
func (t *ServiceInfo) TableName() string {
return "gateway_service_info"
}
func (t *ServiceInfo) ServiceDetail(c *gin.Context, tx *gorm.DB, search *ServiceInfo) (*ServiceDetail, error) {
if search.ServiceName == "" {
info, err := t.Find(c, tx, search)
if err != nil {
return nil, err
}
search = info
}
httpRule := &HttpRule{ServiceID: search.ID}
httpRule, err := httpRule.Find(c, tx, httpRule)
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
tcpRule := &TcpRule{ServiceID: search.ID}
tcpRule, err = tcpRule.Find(c, tx, tcpRule)
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
grpcRule := &GrpcRule{ServiceID: search.ID}
grpcRule, err = grpcRule.Find(c, tx, grpcRule)
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
accessControl := &AccessControl{ServiceID: search.ID}
accessControl, err = accessControl.Find(c, tx, accessControl)
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
loadBalance := &LoadBalance{ServiceID: search.ID}
loadBalance, err = loadBalance.Find(c, tx, loadBalance)
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
detail := &ServiceDetail{
Info: search,
HTTPRule: httpRule,
TCPRule: tcpRule,
GRPCRule: grpcRule,
LoadBalance: loadBalance,
AccessControl: accessControl,
}
return detail, nil
}
func (t *ServiceInfo) GroupByLoadType(c *gin.Context, tx *gorm.DB) ([]dto.DashServiceStatItemOutput, error) {
list := []dto.DashServiceStatItemOutput{}
query := tx.SetCtx(public.GetGinTraceContext(c))
if err := query.Table(t.TableName()).Where("is_delete=0").Select("load_type, count(*) as value").Group("load_type").Scan(&list).Error; err != nil {
return nil, err
}
return list, nil
}
func (t *ServiceInfo) PageList(c *gin.Context, tx *gorm.DB, param *dto.ServiceListInput) ([]ServiceInfo, int64, error) {
total := int64(0)
list := []ServiceInfo{}
offset := (param.PageNo - 1) * param.PageSize
query := tx.SetCtx(public.GetGinTraceContext(c))
query = query.Table(t.TableName()).Where("is_delete=0")
if param.Info != "" {
query = query.Where("(service_name like ? or service_desc like ?)", "%"+param.Info+"%", "%"+param.Info+"%")
}
if err := query.Limit(param.PageSize).Offset(offset).Order("id desc").Find(&list).Error; err != nil && err != gorm.ErrRecordNotFound {
return nil, 0, err
}
query.Limit(param.PageSize).Offset(offset).Count(&total)
return list, total, nil
}
func (t *ServiceInfo) Find(c *gin.Context, tx *gorm.DB, search *ServiceInfo) (*ServiceInfo, error) {
out := &ServiceInfo{}
err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(out).Error
if err != nil {
return nil, err
}
return out, nil
}
func (t *ServiceInfo) Save(c *gin.Context, tx *gorm.DB) error {
return tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error
}
package dao
import (
"ichunt-micro/public"
"ichunt-micro/proxy/load_balance"
"github.com/e421083458/gorm"
"github.com/gin-gonic/gin"
"net"
"net/http"
"strings"
"sync"
"time"
)
type LoadBalance struct {
ID int64 `json:"id" gorm:"primary_key"`
ServiceID int64 `json:"service_id" gorm:"column:service_id" description:"服务id "`
CheckMethod int `json:"check_method" gorm:"column:check_method" description:"检查方法 tcpchk=检测端口是否握手成功 "`
CheckTimeout int `json:"check_timeout" gorm:"column:check_timeout" description:"check超时时间 "`
CheckInterval int `json:"check_interval" gorm:"column:check_interval" description:"检查间隔, 单位s "`
RoundType int `json:"round_type" gorm:"column:round_type" description:"轮询方式 round/weight_round/random/ip_hash"`
IpList string `json:"ip_list" gorm:"column:ip_list" description:"ip列表"`
WeightList string `json:"weight_list" gorm:"column:weight_list" description:"权重列表"`
ForbidList string `json:"forbid_list" gorm:"column:forbid_list" description:"禁用ip列表"`
UpstreamConnectTimeout int `json:"upstream_connect_timeout" gorm:"column:upstream_connect_timeout" description:"下游建立连接超时, 单位s"`
UpstreamHeaderTimeout int `json:"upstream_header_timeout" gorm:"column:upstream_header_timeout" description:"下游获取header超时, 单位s "`
UpstreamIdleTimeout int `json:"upstream_idle_timeout" gorm:"column:upstream_idle_timeout" description:"下游链接最大空闲时间, 单位s "`
UpstreamMaxIdle int `json:"upstream_max_idle" gorm:"column:upstream_max_idle" description:"下游最大空闲链接数"`
}
func (t *LoadBalance) TableName() string {
return "gateway_service_load_balance"
}
func (t *LoadBalance) Find(c *gin.Context, tx *gorm.DB, search *LoadBalance) (*LoadBalance, error) {
model := &LoadBalance{}
err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(model).Error
return model, err
}
func (t *LoadBalance) Save(c *gin.Context, tx *gorm.DB) error {
if err := tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error; err != nil {
return err
}
return nil
}
func (t *LoadBalance) GetIPListByModel() []string {
return strings.Split(t.IpList, ",")
}
func (t *LoadBalance) GetWeightListByModel() []string {
return strings.Split(t.WeightList, ",")
}
var LoadBalancerHandler *LoadBalancer
type LoadBalancer struct {
LoadBanlanceMap map[string]*LoadBalancerItem
LoadBanlanceSlice []*LoadBalancerItem
Locker sync.RWMutex
}
type LoadBalancerItem struct {
LoadBanlance load_balance.LoadBalance
ServiceName string
}
func NewLoadBalancer() *LoadBalancer {
return &LoadBalancer{
LoadBanlanceMap: map[string]*LoadBalancerItem{},
LoadBanlanceSlice: []*LoadBalancerItem{},
Locker: sync.RWMutex{},
}
}
func init() {
LoadBalancerHandler = NewLoadBalancer()
}
func (lbr *LoadBalancer) GetLoadBalancer(service *ServiceDetail) (load_balance.LoadBalance, error) {
//for _, lbrItem := range lbr.LoadBanlanceSlice {
// if lbrItem.ServiceName == service.Info.ServiceName {
// return lbrItem.LoadBanlance, nil
// }
//}
//schema := "http://"
//if service.HTTPRule.NeedHttps == 1 {
// schema = "https://"
//}
//if service.Info.LoadType==public.LoadTypeTCP || service.Info.LoadType==public.LoadTypeGRPC{
// schema = ""
//}
//ipList := service.LoadBalance.GetIPListByModel()
//weightList := service.LoadBalance.GetWeightListByModel()
//ipConf := map[string]string{}
//for ipIndex, ipItem := range ipList {
// ipConf[ipItem] = weightList[ipIndex]
//}
////fmt.Println("ipConf", ipConf)
//mConf, err := load_balance.NewLoadBalanceCheckConf(fmt.Sprintf("%s%s", schema, "%s"), ipConf)
//if err != nil {
// return nil, err
//}
//lb := load_balance.LoadBanlanceFactorWithConf(load_balance.LbType(service.LoadBalance.RoundType), mConf)
//
////save to map and slice
//lbItem := &LoadBalancerItem{
// LoadBanlance: lb,
// ServiceName: service.Info.ServiceName,
//}
//lbr.LoadBanlanceSlice = append(lbr.LoadBanlanceSlice, lbItem)
//
//lbr.Locker.Lock()
//defer lbr.Locker.Unlock()
//lbr.LoadBanlanceMap[service.Info.ServiceName] = lbItem
//return lb, nil
return nil,nil
}
var TransportorHandler *Transportor
type Transportor struct {
TransportMap map[string]*TransportItem
TransportSlice []*TransportItem
Locker sync.RWMutex
}
type TransportItem struct {
Trans *http.Transport
ServiceName string
}
func NewTransportor() *Transportor {
return &Transportor{
TransportMap: map[string]*TransportItem{},
TransportSlice: []*TransportItem{},
Locker: sync.RWMutex{},
}
}
//func init() {
// TransportorHandler = NewTransportor()
//}
func (t *Transportor) GetTrans(service *ServiceDetail) (*http.Transport, error) {
for _, transItem := range t.TransportSlice {
if transItem.ServiceName == service.Info.ServiceName {
return transItem.Trans, nil
}
}
//todo 优化点5
if service.LoadBalance.UpstreamConnectTimeout==0{
service.LoadBalance.UpstreamConnectTimeout = 30
}
if service.LoadBalance.UpstreamMaxIdle==0{
service.LoadBalance.UpstreamMaxIdle = 100
}
if service.LoadBalance.UpstreamIdleTimeout==0{
service.LoadBalance.UpstreamIdleTimeout = 90
}
if service.LoadBalance.UpstreamHeaderTimeout==0{
service.LoadBalance.UpstreamHeaderTimeout = 30
}
trans := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: time.Duration(service.LoadBalance.UpstreamConnectTimeout)*time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: service.LoadBalance.UpstreamMaxIdle,
IdleConnTimeout: time.Duration(service.LoadBalance.UpstreamIdleTimeout)*time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ResponseHeaderTimeout: time.Duration(service.LoadBalance.UpstreamHeaderTimeout)*time.Second,
}
//save to map and slice
transItem := &TransportItem{
Trans: trans,
ServiceName: service.Info.ServiceName,
}
t.TransportSlice = append(t.TransportSlice, transItem)
t.Locker.Lock()
defer t.Locker.Unlock()
t.TransportMap[service.Info.ServiceName] = transItem
return trans, nil
}
package dao
import (
"ichunt-micro/public"
"github.com/e421083458/gorm"
"github.com/gin-gonic/gin"
)
type TcpRule struct {
ID int64 `json:"id" gorm:"primary_key"`
ServiceID int64 `json:"service_id" gorm:"column:service_id" description:"服务id "`
Port int `json:"port" gorm:"column:port" description:"端口 "`
}
func (t *TcpRule) TableName() string {
return "gateway_service_tcp_rule"
}
func (t *TcpRule) Find(c *gin.Context, tx *gorm.DB, search *TcpRule) (*TcpRule, error) {
model := &TcpRule{}
err := tx.SetCtx(public.GetGinTraceContext(c)).Where(search).Find(model).Error
return model, err
}
func (t *TcpRule) Save(c *gin.Context, tx *gorm.DB) error {
if err := tx.SetCtx(public.GetGinTraceContext(c)).Save(t).Error; err != nil {
return err
}
return nil
}
func (t *TcpRule) ListByServiceID(c *gin.Context, tx *gorm.DB, serviceID int64) ([]TcpRule, int64, error) {
var list []TcpRule
var count int64
query := tx.SetCtx(public.GetGinTraceContext(c))
query = query.Table(t.TableName()).Select("*")
query = query.Where("service_id=?", serviceID)
err := query.Order("id desc").Find(&list).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, 0, err
}
errCount := query.Count(&count).Error
if errCount != nil {
return nil, 0, err
}
return list, count, nil
}
package dto
import (
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"time"
)
type AdminInfoOutput struct {
ID int `json:"id"`
Name string `json:"name"`
LoginTime time.Time `json:"login_time"`
Avatar string `json:"avatar"`
Introduction string `json:"introduction"`
Roles []string `json:"roles"`
}
type ChangePwdInput struct {
Password string `json:"password" form:"password" comment:"密码" example:"123456" validate:"required"` //密码
}
func (param *ChangePwdInput) BindValidParam(c *gin.Context) error {
return public.DefaultGetValidParams(c, param)
}
package dto
import (
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"time"
)
type AdminSessionInfo struct {
ID int `json:"id"`
UserName string `json:"user_name"`
LoginTime time.Time `json:"login_time"`
}
type AdminLoginInput struct {
UserName string `json:"username" form:"username" comment:"管理员用户名" example:"admin" validate:"required,valid_username"` //管理员用户名
Password string `json:"password" form:"password" comment:"密码" example:"123456" validate:"required"` //密码
}
func (param *AdminLoginInput) BindValidParam(c *gin.Context) error {
return public.DefaultGetValidParams(c, param)
}
type AdminLoginOutput struct {
Token string `json:"token" form:"token" comment:"token" example:"token" validate:""` //token
}
package dto
import (
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"time"
)
type APPListInput struct {
Info string `json:"info" form:"info" comment:"查找信息" validate:""`
PageSize int `json:"page_size" form:"page_size" comment:"页数" validate:"required,min=1,max=999"`
PageNo int `json:"page_no" form:"page_no" comment:"页码" validate:"required,min=1,max=999"`
}
func (params *APPListInput) GetValidParams(c *gin.Context) error {
return public.DefaultGetValidParams(c, params)
}
type APPListOutput struct {
List []APPListItemOutput `json:"list" form:"list" comment:"租户列表"`
Total int64 `json:"total" form:"total" comment:"租户总数"`
}
type APPListItemOutput struct {
ID int64 `json:"id" gorm:"primary_key"`
AppID string `json:"app_id" gorm:"column:app_id" description:"租户id "`
Name string `json:"name" gorm:"column:name" description:"租户名称 "`
Secret string `json:"secret" gorm:"column:secret" description:"密钥"`
WhiteIPS string `json:"white_ips" gorm:"column:white_ips" description:"ip白名单,支持前缀匹配 "`
Qpd int64 `json:"qpd" gorm:"column:qpd" description:"日请求量限制"`
Qps int64 `json:"qps" gorm:"column:qps" description:"每秒请求量限制"`
RealQpd int64 `json:"real_qpd" description:"日请求量限制"`
RealQps int64 `json:"real_qps" description:"每秒请求量限制"`
UpdatedAt time.Time `json:"create_at" gorm:"column:create_at" description:"添加时间 "`
CreatedAt time.Time `json:"update_at" gorm:"column:update_at" description:"更新时间"`
IsDelete int8 `json:"is_delete" gorm:"column:is_delete" description:"是否已删除;0:否;1:是"`
}
type APPDetailInput struct {
ID int64 `json:"id" form:"id" comment:"租户ID" validate:"required"`
}
func (params *APPDetailInput) GetValidParams(c *gin.Context) error {
return public.DefaultGetValidParams(c, params)
}
type StatisticsOutput struct {
Today []int64 `json:"today" form:"today" comment:"今日统计" validate:"required"`
Yesterday []int64 `json:"yesterday" form:"yesterday" comment:"昨日统计" validate:"required"`
}
type APPAddHttpInput struct {
AppID string `json:"app_id" form:"app_id" comment:"租户id" validate:"required"`
Name string `json:"name" form:"name" comment:"租户名称" validate:"required"`
Secret string `json:"secret" form:"secret" comment:"密钥" validate:""`
WhiteIPS string `json:"white_ips" form:"white_ips" comment:"ip白名单,支持前缀匹配"`
Qpd int64 `json:"qpd" form:"qpd" comment:"日请求量限制" validate:""`
Qps int64 `json:"qps" form:"qps" comment:"每秒请求量限制" validate:""`
}
func (params *APPAddHttpInput) GetValidParams(c *gin.Context) error {
return public.DefaultGetValidParams(c, params)
}
type APPUpdateHttpInput struct {
ID int64 `json:"id" form:"id" gorm:"column:id" comment:"主键ID" validate:"required"`
AppID string `json:"app_id" form:"app_id" gorm:"column:app_id" comment:"租户id" validate:""`
Name string `json:"name" form:"name" gorm:"column:name" comment:"租户名称" validate:"required"`
Secret string `json:"secret" form:"secret" gorm:"column:secret" comment:"密钥" validate:"required"`
WhiteIPS string `json:"white_ips" form:"white_ips" gorm:"column:white_ips" comment:"ip白名单,支持前缀匹配 "`
Qpd int64 `json:"qpd" form:"qpd" gorm:"column:qpd" comment:"日请求量限制"`
Qps int64 `json:"qps" form:"qps" gorm:"column:qps" comment:"每秒请求量限制"`
}
func (params *APPUpdateHttpInput) GetValidParams(c *gin.Context) error {
return public.DefaultGetValidParams(c, params)
}
package dto
type PanelGroupDataOutput struct {
ServiceNum int64 `json:"serviceNum"`
AppNum int64 `json:"appNum"`
CurrentQPS int64 `json:"currentQps"`
TodayRequestNum int64 `json:"todayRequestNum"`
}
type DashServiceStatItemOutput struct {
Name string `json:"name"`
LoadType int `json:"load_type"`
Value int64 `json:"value"`
}
type DashServiceStatOutput struct {
Legend []string `json:"legend"`
Data []DashServiceStatItemOutput `json:"data"`
}
\ No newline at end of file
package dto
import (
"ichunt-micro/public"
"github.com/gin-gonic/gin"
)
type TokensInput struct {
GrantType string `json:"grant_type" form:"grant_type" comment:"授权类型" example:"client_credentials" validate:"required"` //授权类型
Scope string `json:"scope" form:"scope" comment:"权限范围" example:"read_write" validate:"required"` //权限范围
}
func (param *TokensInput) BindValidParam(c *gin.Context) error {
return public.DefaultGetValidParams(c, param)
}
type TokensOutput struct {
AccessToken string `json:"access_token" form:"access_token"` //access_token
ExpiresIn int `json:"expires_in" form:"expires_in"` //expires_in
TokenType string `json:"token_type" form:"token_type"` //token_type
Scope string `json:"scope" form:"scope"` //scope
}
\ No newline at end of file
......@@ -3,21 +3,33 @@ module ichunt-micro
go 1.14
require (
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
github.com/coreos/etcd v3.3.25+incompatible
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/e421083458/gorm v1.0.1 // indirect
github.com/gin-gonic/gin v1.6.3 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/e421083458/gorm v1.0.1
github.com/garyburd/redigo v1.6.2
github.com/gin-gonic/contrib v0.0.0-20201005132743-ca038bbf2944
github.com/gin-gonic/gin v1.6.3
github.com/go-playground/locales v0.13.0
github.com/go-playground/universal-translator v0.17.0
github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/gogo/protobuf v1.3.1 // indirect
github.com/golang/protobuf v1.4.2 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/imroc/req v0.3.0
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/pkg/errors v0.8.1
github.com/spf13/viper v1.7.1
github.com/syyongx/php2go v0.9.4
go.uber.org/zap v1.16.0 // indirect
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d // indirect
google.golang.org/grpc v1.31.1 // indirect
gopkg.in/go-playground/validator.v9 v9.31.0
)
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
package lib
import (
"bytes"
"database/sql"
dlog "ichunt-micro/golang_common/log"
"github.com/e421083458/gorm"
"github.com/spf13/viper"
"io/ioutil"
"os"
"strings"
"time"
)
type BaseConf struct {
DebugMode string `mapstructure:"debug_mode"`
TimeLocation string `mapstructure:"time_location"`
Log LogConfig `mapstructure:"log"`
Base struct {
DebugMode string `mapstructure:"debug_mode"`
TimeLocation string `mapstructure:"time_location"`
} `mapstructure:"base"`
}
type LogConfFileWriter struct {
On bool `mapstructure:"on"`
LogPath string `mapstructure:"log_path"`
RotateLogPath string `mapstructure:"rotate_log_path"`
WfLogPath string `mapstructure:"wf_log_path"`
RotateWfLogPath string `mapstructure:"rotate_wf_log_path"`
}
type LogConfConsoleWriter struct {
On bool `mapstructure:"on"`
Color bool `mapstructure:"color"`
}
type LogConfig struct {
Level string `mapstructure:"log_level"`
FW LogConfFileWriter `mapstructure:"file_writer"`
CW LogConfConsoleWriter `mapstructure:"console_writer"`
}
type MysqlMapConf struct {
List map[string]*MySQLConf `mapstructure:"list"`
}
type MySQLConf struct {
DriverName string `mapstructure:"driver_name"`
DataSourceName string `mapstructure:"data_source_name"`
MaxOpenConn int `mapstructure:"max_open_conn"`
MaxIdleConn int `mapstructure:"max_idle_conn"`
MaxConnLifeTime int `mapstructure:"max_conn_life_time"`
}
type RedisMapConf struct {
List map[string]*RedisConf `mapstructure:"list"`
}
type RedisConf struct {
ProxyList []string `mapstructure:"proxy_list"`
Password string `mapstructure:"password"`
Db int `mapstructure:"db"`
ConnTimeout int `mapstructure:"conn_timeout"`
ReadTimeout int `mapstructure:"read_timeout"`
WriteTimeout int `mapstructure:"write_timeout"`
}
//全局变量
var ConfBase *BaseConf
var DBMapPool map[string]*sql.DB
var GORMMapPool map[string]*gorm.DB
var DBDefaultPool *sql.DB
var GORMDefaultPool *gorm.DB
var ConfRedis *RedisConf
var ConfRedisMap *RedisMapConf
var ViperConfMap map[string]*viper.Viper
//获取基本配置信息
func GetBaseConf() *BaseConf {
return ConfBase
}
func InitBaseConf(path string) error {
ConfBase = &BaseConf{}
err := ParseConfig(path, ConfBase)
if err != nil {
return err
}
if ConfBase.DebugMode == "" {
if ConfBase.Base.DebugMode != "" {
ConfBase.DebugMode = ConfBase.Base.DebugMode
} else {
ConfBase.DebugMode = "debug"
}
}
if ConfBase.TimeLocation == "" {
if ConfBase.Base.TimeLocation != "" {
ConfBase.TimeLocation = ConfBase.Base.TimeLocation
} else {
ConfBase.TimeLocation = "Asia/Chongqing"
}
}
if ConfBase.Log.Level == "" {
ConfBase.Log.Level = "trace"
}
//配置日志
logConf := dlog.LogConfig{
Level: ConfBase.Log.Level,
FW: dlog.ConfFileWriter{
On: ConfBase.Log.FW.On,
LogPath: ConfBase.Log.FW.LogPath,
RotateLogPath: ConfBase.Log.FW.RotateLogPath,
WfLogPath: ConfBase.Log.FW.WfLogPath,
RotateWfLogPath: ConfBase.Log.FW.RotateWfLogPath,
},
CW: dlog.ConfConsoleWriter{
On: ConfBase.Log.CW.On,
Color: ConfBase.Log.CW.Color,
},
}
if err := dlog.SetupDefaultLogWithConf(logConf); err != nil {
panic(err)
}
dlog.SetLayout("2006-01-02T15:04:05.000")
return nil
}
//
//func InitLogger(path string) error {
// if err := dlog.SetupDefaultLogWithFile(path); err != nil {
// panic(err)
// }
// dlog.SetLayout("2006-01-02T15:04:05.000")
// return nil
//}
func InitRedisConf(path string) error {
ConfRedis := &RedisMapConf{}
err := ParseConfig(path, ConfRedis)
if err != nil {
return err
}
ConfRedisMap = ConfRedis
return nil
}
//初始化配置文件
func InitViperConf() error {
f, err := os.Open(ConfEnvPath + "/")
if err != nil {
return err
}
fileList, err := f.Readdir(1024)
if err != nil {
return err
}
for _, f0 := range fileList {
if !f0.IsDir() {
bts, err := ioutil.ReadFile(ConfEnvPath + "/" + f0.Name())
if err != nil {
return err
}
v := viper.New()
v.SetConfigType("toml")
v.ReadConfig(bytes.NewBuffer(bts))
pathArr := strings.Split(f0.Name(), ".")
if ViperConfMap == nil {
ViperConfMap = make(map[string]*viper.Viper)
}
ViperConfMap[pathArr[0]] = v
}
}
return nil
}
//获取get配置信息
func GetStringConf(key string) string {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return ""
}
v, ok := ViperConfMap[keys[0]]
if !ok {
return ""
}
confString := v.GetString(strings.Join(keys[1:len(keys)], "."))
return confString
}
//获取get配置信息
func GetStringMapConf(key string) map[string]interface{} {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return nil
}
v := ViperConfMap[keys[0]]
conf := v.GetStringMap(strings.Join(keys[1:len(keys)], "."))
return conf
}
//获取get配置信息
func GetConf(key string) interface{} {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return nil
}
v := ViperConfMap[keys[0]]
conf := v.Get(strings.Join(keys[1:len(keys)], "."))
return conf
}
//获取get配置信息
func GetBoolConf(key string) bool {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return false
}
v := ViperConfMap[keys[0]]
conf := v.GetBool(strings.Join(keys[1:len(keys)], "."))
return conf
}
//获取get配置信息
func GetFloat64Conf(key string) float64 {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return 0
}
v := ViperConfMap[keys[0]]
conf := v.GetFloat64(strings.Join(keys[1:len(keys)], "."))
return conf
}
//获取get配置信息
func GetIntConf(key string) int {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return 0
}
v := ViperConfMap[keys[0]]
conf := v.GetInt(strings.Join(keys[1:len(keys)], "."))
return conf
}
//获取get配置信息
func GetStringMapStringConf(key string) map[string]string {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return nil
}
v := ViperConfMap[keys[0]]
conf := v.GetStringMapString(strings.Join(keys[1:len(keys)], "."))
return conf
}
//获取get配置信息
func GetStringSliceConf(key string) []string {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return nil
}
v := ViperConfMap[keys[0]]
conf := v.GetStringSlice(strings.Join(keys[1:len(keys)], "."))
return conf
}
//获取get配置信息
func GetTimeConf(key string) time.Time {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return time.Now()
}
v := ViperConfMap[keys[0]]
conf := v.GetTime(strings.Join(keys[1:len(keys)], "."))
return conf
}
//获取时间阶段长度
func GetDurationConf(key string) time.Duration {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return 0
}
v := ViperConfMap[keys[0]]
conf := v.GetDuration(strings.Join(keys[1:len(keys)], "."))
return conf
}
//是否设置了key
func IsSetConf(key string) bool {
keys := strings.Split(key, ".")
if len(keys) < 2 {
return false
}
v := ViperConfMap[keys[0]]
conf := v.IsSet(strings.Join(keys[1:len(keys)], "."))
return conf
}
package lib
import (
"bytes"
"fmt"
"github.com/spf13/viper"
"io/ioutil"
"os"
"strings"
)
var ConfEnvPath string //配置文件夹
var ConfEnv string //配置环境名 比如:dev prod test
// 解析配置文件目录
//
// 配置文件必须放到一个文件夹中
// 如:config=conf/dev/base.json ConfEnvPath=conf/dev ConfEnv=dev
// 如:config=conf/base.json ConfEnvPath=conf ConfEnv=conf
func ParseConfPath(config string) error {
path := strings.Split(config, "/")
prefix := strings.Join(path[:len(path)-1], "/")
ConfEnvPath = prefix
ConfEnv = path[len(path)-2]
return nil
}
//获取配置环境名
func GetConfEnv() string{
return ConfEnv
}
func GetConfPath(fileName string) string {
return ConfEnvPath + "/" + fileName + ".toml"
}
func GetConfFilePath(fileName string) string {
return ConfEnvPath + "/" + fileName
}
//本地解析文件
func ParseLocalConfig(fileName string, st interface{}) error {
path := GetConfFilePath(fileName)
err := ParseConfig(path, st)
if err != nil {
return err
}
return nil
}
func ParseConfig(path string, conf interface{}) error {
file, err := os.Open(path)
if err != nil {
return fmt.Errorf("Open config %v fail, %v", path, err)
}
data, err := ioutil.ReadAll(file)
if err != nil {
return fmt.Errorf("Read config fail, %v", err)
}
v:=viper.New()
v.SetConfigType("toml")
v.ReadConfig(bytes.NewBuffer(data))
if err:=v.Unmarshal(conf);err!=nil{
return fmt.Errorf("Parse config fail, config:%v, err:%v", string(data), err)
}
return nil
}
package lib
import (
"fmt"
dlog "ichunt-micro/golang_common/log"
"strings"
)
// 通用DLTag常量定义
const (
DLTagUndefind = "_undef"
DLTagMySqlFailed = "_com_mysql_failure"
DLTagRedisFailed = "_com_redis_failure"
DLTagMySqlSuccess = "_com_mysql_success"
DLTagRedisSuccess = "_com_redis_success"
DLTagThriftFailed = "_com_thrift_failure"
DLTagThriftSuccess = "_com_thrift_success"
DLTagHTTPSuccess = "_com_http_success"
DLTagHTTPFailed = "_com_http_failure"
DLTagTCPFailed = "_com_tcp_failure"
DLTagRequestIn = "_com_request_in"
DLTagRequestOut = "_com_request_out"
)
const (
_dlTag = "dltag"
_traceId = "traceid"
_spanId = "spanid"
_childSpanId = "cspanid"
_dlTagBizPrefix = "_com_"
_dlTagBizUndef = "_com_undef"
)
var Log *Logger
type Trace struct {
TraceId string
SpanId string
Caller string
SrcMethod string
HintCode int64
HintContent string
}
type TraceContext struct {
Trace
CSpanId string
}
type Logger struct {
}
func (l *Logger) TagInfo(trace *TraceContext, dltag string, m map[string]interface{}) {
m[_dlTag] = checkDLTag(dltag)
m[_traceId] = trace.TraceId
m[_childSpanId] = trace.CSpanId
m[_spanId] = trace.SpanId
dlog.Info(parseParams(m))
}
func (l *Logger) TagWarn(trace *TraceContext, dltag string, m map[string]interface{}) {
m[_dlTag] = checkDLTag(dltag)
m[_traceId] = trace.TraceId
m[_childSpanId] = trace.CSpanId
m[_spanId] = trace.SpanId
dlog.Warn(parseParams(m))
}
func (l *Logger) TagError(trace *TraceContext, dltag string, m map[string]interface{}) {
m[_dlTag] = checkDLTag(dltag)
m[_traceId] = trace.TraceId
m[_childSpanId] = trace.CSpanId
m[_spanId] = trace.SpanId
dlog.Error(parseParams(m))
}
func (l *Logger) TagTrace(trace *TraceContext, dltag string, m map[string]interface{}) {
m[_dlTag] = checkDLTag(dltag)
m[_traceId] = trace.TraceId
m[_childSpanId] = trace.CSpanId
m[_spanId] = trace.SpanId
dlog.Trace(parseParams(m))
}
func (l *Logger) TagDebug(trace *TraceContext, dltag string, m map[string]interface{}) {
m[_dlTag] = checkDLTag(dltag)
m[_traceId] = trace.TraceId
m[_childSpanId] = trace.CSpanId
m[_spanId] = trace.SpanId
dlog.Debug(parseParams(m))
}
func (l *Logger) Close() {
dlog.Close()
}
// 生成业务dltag
func CreateBizDLTag(tagName string) string {
if tagName == "" {
return _dlTagBizUndef
}
return _dlTagBizPrefix + tagName
}
// 校验dltag合法性
func checkDLTag(dltag string) string {
if strings.HasPrefix(dltag, _dlTagBizPrefix) {
return dltag
}
if strings.HasPrefix(dltag, "_com_") {
return dltag
}
if dltag == DLTagUndefind {
return dltag
}
return dltag
}
//map格式化为string
func parseParams(m map[string]interface{}) string {
var dltag string = "_undef"
if _dltag, _have := m["dltag"]; _have {
if __val, __ok := _dltag.(string); __ok {
dltag = __val
}
}
for _key, _val := range m {
if _key == "dltag" {
continue
}
dltag = dltag + "||" + fmt.Sprintf("%v=%+v", _key, _val)
}
dltag = strings.Trim(fmt.Sprintf("%q", dltag), "\"")
return dltag
}
package lib
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"github.com/e421083458/gorm"
_ "github.com/e421083458/gorm/dialects/mysql"
"reflect"
"regexp"
"strconv"
"time"
"unicode"
)
func InitDBPool(path string) error {
//普通的db方式
DbConfMap := &MysqlMapConf{}
err := ParseConfig(path, DbConfMap)
if err != nil {
return err
}
if len(DbConfMap.List) == 0 {
fmt.Printf("[INFO] %s%s\n", time.Now().Format(TimeFormat), " empty mysql config.")
}
DBMapPool = map[string]*sql.DB{}
GORMMapPool = map[string]*gorm.DB{}
for confName, DbConf := range DbConfMap.List {
dbpool, err := sql.Open("mysql", DbConf.DataSourceName)
if err != nil {
return err
}
dbpool.SetMaxOpenConns(DbConf.MaxOpenConn)
dbpool.SetMaxIdleConns(DbConf.MaxIdleConn)
dbpool.SetConnMaxLifetime(time.Duration(DbConf.MaxConnLifeTime) * time.Second)
err = dbpool.Ping()
if err != nil {
return err
}
//gorm连接方式
dbgorm, err := gorm.Open("mysql", DbConf.DataSourceName)
if err != nil {
return err
}
dbgorm.SingularTable(true)
err = dbgorm.DB().Ping()
if err != nil {
return err
}
dbgorm.LogMode(true)
dbgorm.LogCtx(true)
dbgorm.SetLogger(&MysqlGormLogger{Trace: NewTrace()})
dbgorm.DB().SetMaxIdleConns(DbConf.MaxIdleConn)
dbgorm.DB().SetMaxOpenConns(DbConf.MaxOpenConn)
dbgorm.DB().SetConnMaxLifetime(time.Duration(DbConf.MaxConnLifeTime) * time.Second)
DBMapPool[confName] = dbpool
GORMMapPool[confName] = dbgorm
}
//手动配置连接
if dbpool, err := GetDBPool("default"); err == nil {
DBDefaultPool = dbpool
}
if dbpool, err := GetGormPool("default"); err == nil {
GORMDefaultPool = dbpool
}
return nil
}
func GetDBPool(name string) (*sql.DB, error) {
if dbpool, ok := DBMapPool[name]; ok {
return dbpool, nil
}
return nil, errors.New("get pool error")
}
func GetGormPool(name string) (*gorm.DB, error) {
if dbpool, ok := GORMMapPool[name]; ok {
return dbpool, nil
}
return nil, errors.New("get pool error")
}
func CloseDB() error {
for _, dbpool := range DBMapPool {
dbpool.Close()
}
for _, dbpool := range GORMMapPool {
dbpool.Close()
}
return nil
}
func DBPoolLogQuery(trace *TraceContext, sqlDb *sql.DB, query string, args ...interface{}) (*sql.Rows, error) {
startExecTime := time.Now()
rows, err := sqlDb.Query(query, args...)
endExecTime := time.Now()
if err != nil {
Log.TagError(trace, "_com_mysql_success", map[string]interface{}{
"sql": query,
"bind": args,
"proc_time": fmt.Sprintf("%f", endExecTime.Sub(startExecTime).Seconds()),
})
} else {
Log.TagInfo(trace, "_com_mysql_success", map[string]interface{}{
"sql": query,
"bind": args,
"proc_time": fmt.Sprintf("%f", endExecTime.Sub(startExecTime).Seconds()),
})
}
return rows, err
}
//mysql日志打印类
// Logger default logger
type MysqlGormLogger struct {
gorm.Logger
Trace *TraceContext
}
// Print format & print log
func (logger *MysqlGormLogger) Print(values ...interface{}) {
message := logger.LogFormatter(values...)
if message["level"] == "sql" {
Log.TagInfo(logger.Trace, "_com_mysql_success", message)
} else {
Log.TagInfo(logger.Trace, "_com_mysql_failure", message)
}
}
// LogCtx(true) 时会执行改方法
func (logger *MysqlGormLogger) CtxPrint(s *gorm.DB,values ...interface{}) {
ctx,ok:=s.GetCtx()
trace:=NewTrace()
if ok{
trace=ctx.(*TraceContext)
}
message := logger.LogFormatter(values...)
if message["level"] == "sql" {
Log.TagInfo(trace, "_com_mysql_success", message)
} else {
Log.TagInfo(trace, "_com_mysql_failure", message)
}
}
func (logger *MysqlGormLogger) LogFormatter(values ...interface{}) (messages map[string]interface{}) {
if len(values) > 1 {
var (
sql string
formattedValues []string
level = values[0]
currentTime = logger.NowFunc().Format("2006-01-02 15:04:05")
source = fmt.Sprintf("%v", values[1])
)
messages = map[string]interface{}{"level": level, "source": source, "current_time": currentTime}
if level == "sql" {
// duration
//messages = append(messages, fmt.Sprintf("%.2fms", float64(values[2].(time.Duration).Nanoseconds() / 1e4) / 100.0))
messages["proc_time"] = fmt.Sprintf("%fs", values[2].(time.Duration).Seconds())
// sql
for _, value := range values[4].([]interface{}) {
indirectValue := reflect.Indirect(reflect.ValueOf(value))
if indirectValue.IsValid() {
value = indirectValue.Interface()
if t, ok := value.(time.Time); ok {
formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05")))
} else if b, ok := value.([]byte); ok {
if str := string(b); logger.isPrintable(str) {
formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str))
} else {
formattedValues = append(formattedValues, "'<binary>'")
}
} else if r, ok := value.(driver.Valuer); ok {
if value, err := r.Value(); err == nil && value != nil {
formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
} else {
formattedValues = append(formattedValues, "NULL")
}
} else {
formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
}
} else {
formattedValues = append(formattedValues, "NULL")
}
}
// differentiate between $n placeholders or else treat like ?
if regexp.MustCompile(`\$\d+`).MatchString(values[3].(string)) {
sql = values[3].(string)
for index, value := range formattedValues {
placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1)
sql = regexp.MustCompile(placeholder).ReplaceAllString(sql, value+"$1")
}
} else {
formattedValuesLength := len(formattedValues)
for index, value := range regexp.MustCompile(`\?`).Split(values[3].(string), -1) {
sql += value
if index < formattedValuesLength {
sql += formattedValues[index]
}
}
}
messages["sql"] = sql
if len(values) > 5 {
messages["affected_row"] = strconv.FormatInt(values[5].(int64), 10)
}
} else {
messages["ext"] = values
}
}
return
}
func (logger *MysqlGormLogger) NowFunc() time.Time {
return time.Now()
}
func (logger *MysqlGormLogger) isPrintable(s string) bool {
for _, r := range s {
if !unicode.IsPrint(r) {
return false
}
}
return true
}
package lib
import (
"errors"
"fmt"
"github.com/garyburd/redigo/redis"
"math/rand"
"time"
)
func RedisConnFactory(name string) (redis.Conn, error) {
if ConfRedisMap != nil && ConfRedisMap.List != nil {
for confName, cfg := range ConfRedisMap.List {
if name == confName {
randHost := cfg.ProxyList[rand.Intn(len(cfg.ProxyList))]
if cfg.ConnTimeout == 0 {
cfg.ConnTimeout = 50
}
if cfg.ReadTimeout == 0 {
cfg.ReadTimeout = 100
}
if cfg.WriteTimeout == 0 {
cfg.WriteTimeout = 100
}
c, err := redis.Dial(
"tcp",
randHost,
redis.DialConnectTimeout(time.Duration(cfg.ConnTimeout)*time.Millisecond),
redis.DialReadTimeout(time.Duration(cfg.ReadTimeout)*time.Millisecond),
redis.DialWriteTimeout(time.Duration(cfg.WriteTimeout)*time.Millisecond))
if err != nil {
return nil, err
}
if cfg.Password != "" {
if _, err := c.Do("AUTH", cfg.Password); err != nil {
c.Close()
return nil, err
}
}
if cfg.Db != 0 {
if _, err := c.Do("SELECT", cfg.Db); err != nil {
c.Close()
return nil, err
}
}
return c, nil
}
}
}
return nil, errors.New("create redis conn fail")
}
func RedisLogDo(trace *TraceContext, c redis.Conn, commandName string, args ...interface{}) (interface{}, error) {
startExecTime := time.Now()
reply, err := c.Do(commandName, args...)
endExecTime := time.Now()
if err != nil {
Log.TagError(trace, "_com_redis_failure", map[string]interface{}{
"method": commandName,
"err": err,
"bind": args,
"proc_time": fmt.Sprintf("%fs", endExecTime.Sub(startExecTime).Seconds()),
})
} else {
replyStr, _ := redis.String(reply, nil)
Log.TagInfo(trace, "_com_redis_success", map[string]interface{}{
"method": commandName,
"bind": args,
"reply": replyStr,
"proc_time": fmt.Sprintf("%fs", endExecTime.Sub(startExecTime).Seconds()),
})
}
return reply, err
}
//通过配置 执行redis
func RedisConfDo(trace *TraceContext, name string, commandName string, args ...interface{}) (interface{}, error) {
c, err := RedisConnFactory(name)
if err != nil {
Log.TagError(trace, "_com_redis_failure", map[string]interface{}{
"method": commandName,
"err": errors.New("RedisConnFactory_error:" + name),
"bind": args,
})
return nil, err
}
defer c.Close()
startExecTime := time.Now()
reply, err := c.Do(commandName, args...)
endExecTime := time.Now()
if err != nil {
Log.TagError(trace, "_com_redis_failure", map[string]interface{}{
"method": commandName,
"err": err,
"bind": args,
"proc_time": fmt.Sprintf("%fs", endExecTime.Sub(startExecTime).Seconds()),
})
} else {
replyStr, _ := redis.String(reply, nil)
Log.TagInfo(trace, "_com_redis_success", map[string]interface{}{
"method": commandName,
"bind": args,
"reply": replyStr,
"proc_time": fmt.Sprintf("%fs", endExecTime.Sub(startExecTime).Seconds()),
})
}
return reply, err
}
package log
import (
"errors"
)
type ConfFileWriter struct {
On bool `toml:"On"`
LogPath string `toml:"LogPath"`
RotateLogPath string `toml:"RotateLogPath"`
WfLogPath string `toml:"WfLogPath"`
RotateWfLogPath string `toml:"RotateWfLogPath"`
}
type ConfConsoleWriter struct {
On bool `toml:"On"`
Color bool `toml:"Color"`
}
type LogConfig struct {
Level string `toml:"LogLevel"`
FW ConfFileWriter `toml:"FileWriter"`
CW ConfConsoleWriter `toml:"ConsoleWriter"`
}
func SetupLogInstanceWithConf(lc LogConfig, logger *Logger) (err error) {
if lc.FW.On {
if len(lc.FW.LogPath) > 0 {
w := NewFileWriter()
w.SetFileName(lc.FW.LogPath)
w.SetPathPattern(lc.FW.RotateLogPath)
w.SetLogLevelFloor(TRACE)
if len(lc.FW.WfLogPath) > 0 {
w.SetLogLevelCeil(INFO)
} else {
w.SetLogLevelCeil(ERROR)
}
logger.Register(w)
}
if len(lc.FW.WfLogPath) > 0 {
wfw := NewFileWriter()
wfw.SetFileName(lc.FW.WfLogPath)
wfw.SetPathPattern(lc.FW.RotateWfLogPath)
wfw.SetLogLevelFloor(WARNING)
wfw.SetLogLevelCeil(ERROR)
logger.Register(wfw)
}
}
if lc.CW.On {
w := NewConsoleWriter()
w.SetColor(lc.CW.Color)
logger.Register(w)
}
switch lc.Level {
case "trace":
logger.SetLevel(TRACE)
case "debug":
logger.SetLevel(DEBUG)
case "info":
logger.SetLevel(INFO)
case "warning":
logger.SetLevel(WARNING)
case "error":
logger.SetLevel(ERROR)
case "fatal":
logger.SetLevel(FATAL)
default:
err = errors.New("Invalid log level")
}
return
}
func SetupDefaultLogWithConf(lc LogConfig) (err error) {
defaultLoggerInit()
return SetupLogInstanceWithConf(lc, logger_default)
}
package log
import (
"fmt"
"os"
)
type colorRecord Record
func (r *colorRecord) String() string {
switch r.level {
case TRACE:
return fmt.Sprintf("\033[36m%s\033[0m [\033[34m%s\033[0m] \033[47;30m%s\033[0m %s\n",
r.time, LEVEL_FLAGS[r.level], r.code, r.info)
case DEBUG:
return fmt.Sprintf("\033[36m%s\033[0m [\033[34m%s\033[0m] \033[47;30m%s\033[0m %s\n",
r.time, LEVEL_FLAGS[r.level], r.code, r.info)
case INFO:
return fmt.Sprintf("\033[36m%s\033[0m [\033[32m%s\033[0m] \033[47;30m%s\033[0m %s\n",
r.time, LEVEL_FLAGS[r.level], r.code, r.info)
case WARNING:
return fmt.Sprintf("\033[36m%s\033[0m [\033[33m%s\033[0m] \033[47;30m%s\033[0m %s\n",
r.time, LEVEL_FLAGS[r.level], r.code, r.info)
case ERROR:
return fmt.Sprintf("\033[36m%s\033[0m [\033[31m%s\033[0m] \033[47;30m%s\033[0m %s\n",
r.time, LEVEL_FLAGS[r.level], r.code, r.info)
case FATAL:
return fmt.Sprintf("\033[36m%s\033[0m [\033[35m%s\033[0m] \033[47;30m%s\033[0m %s\n",
r.time, LEVEL_FLAGS[r.level], r.code, r.info)
}
return ""
}
type ConsoleWriter struct {
color bool
}
func NewConsoleWriter() *ConsoleWriter {
return &ConsoleWriter{}
}
func (w *ConsoleWriter) Write(r *Record) error {
if w.color {
fmt.Fprint(os.Stdout, ((*colorRecord)(r)).String())
} else {
fmt.Fprint(os.Stdout, r.String())
}
return nil
}
func (w *ConsoleWriter) Init() error {
return nil
}
func (w *ConsoleWriter) SetColor(c bool) {
w.color = c
}
package log
import (
"bufio"
"bytes"
"errors"
"fmt"
"os"
"path"
"time"
)
var pathVariableTable map[byte]func(*time.Time) int
type FileWriter struct {
logLevelFloor int
logLevelCeil int
filename string
pathFmt string
file *os.File
fileBufWriter *bufio.Writer
actions []func(*time.Time) int
variables []interface{}
}
func NewFileWriter() *FileWriter {
return &FileWriter{}
}
func (w *FileWriter) Init() error {
return w.CreateLogFile()
}
func (w *FileWriter) SetFileName(filename string) {
w.filename = filename
}
func (w *FileWriter) SetLogLevelFloor(floor int) {
w.logLevelFloor = floor
}
func (w *FileWriter) SetLogLevelCeil(ceil int) {
w.logLevelCeil = ceil
}
func (w *FileWriter) SetPathPattern(pattern string) error {
n := 0
for _, c := range pattern {
if c == '%' {
n++
}
}
if n == 0 {
w.pathFmt = pattern
return nil
}
w.actions = make([]func(*time.Time) int, 0, n)
w.variables = make([]interface{}, n, n)
tmp := []byte(pattern)
variable := 0
for _, c := range tmp {
if variable == 1 {
act, ok := pathVariableTable[c]
if !ok {
return errors.New("Invalid rotate pattern (" + pattern + ")")
}
w.actions = append(w.actions, act)
variable = 0
continue
}
if c == '%' {
variable = 1
}
}
for i, act := range w.actions {
now := time.Now()
w.variables[i] = act(&now)
}
//fmt.Printf("%v\n", w.variables)
w.pathFmt = convertPatternToFmt(tmp)
return nil
}
func (w *FileWriter) Write(r *Record) error {
if r.level < w.logLevelFloor || r.level > w.logLevelCeil {
return nil
}
if w.fileBufWriter == nil {
return errors.New("no opened file")
}
if _, err := w.fileBufWriter.WriteString(r.String()); err != nil {
return err
}
return nil
}
func (w *FileWriter) CreateLogFile() error {
if err := os.MkdirAll(path.Dir(w.filename), 0755); err != nil {
if !os.IsExist(err) {
return err
}
}
if file, err := os.OpenFile(w.filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644); err != nil {
return err
} else {
w.file = file
}
if w.fileBufWriter = bufio.NewWriterSize(w.file, 8192); w.fileBufWriter == nil {
return errors.New("new fileBufWriter failed.")
}
return nil
}
func (w *FileWriter) Rotate() error {
now := time.Now()
v := 0
rotate := false
old_variables := make([]interface{}, len(w.variables))
copy(old_variables, w.variables)
for i, act := range w.actions {
v = act(&now)
if v != w.variables[i] {
w.variables[i] = v
rotate = true
}
}
//fmt.Printf("%v\n", w.variables)
if rotate == false {
return nil
}
if w.fileBufWriter != nil {
if err := w.fileBufWriter.Flush(); err != nil {
return err
}
}
if w.file != nil {
// 将文件以pattern形式改名并关闭
filePath := fmt.Sprintf(w.pathFmt, old_variables...)
if err := os.Rename(w.filename, filePath); err != nil {
return err
}
if err := w.file.Close(); err != nil {
return err
}
}
return w.CreateLogFile()
}
func (w *FileWriter) Flush() error {
if w.fileBufWriter != nil {
return w.fileBufWriter.Flush()
}
return nil
}
func getYear(now *time.Time) int {
return now.Year()
}
func getMonth(now *time.Time) int {
return int(now.Month())
}
func getDay(now *time.Time) int {
return now.Day()
}
func getHour(now *time.Time) int {
return now.Hour()
}
func getMin(now *time.Time) int {
return now.Minute()
}
func convertPatternToFmt(pattern []byte) string {
pattern = bytes.Replace(pattern, []byte("%Y"), []byte("%d"), -1)
pattern = bytes.Replace(pattern, []byte("%M"), []byte("%02d"), -1)
pattern = bytes.Replace(pattern, []byte("%D"), []byte("%02d"), -1)
pattern = bytes.Replace(pattern, []byte("%H"), []byte("%02d"), -1)
pattern = bytes.Replace(pattern, []byte("%m"), []byte("%02d"), -1)
return string(pattern)
}
func init() {
pathVariableTable = make(map[byte]func(*time.Time) int, 5)
pathVariableTable['Y'] = getYear
pathVariableTable['M'] = getMonth
pathVariableTable['D'] = getDay
pathVariableTable['H'] = getHour
pathVariableTable['m'] = getMin
}
package log
import (
"fmt"
"log"
"path"
"runtime"
"strconv"
"sync"
"time"
)
var (
LEVEL_FLAGS = [...]string{"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
)
const (
TRACE = iota
DEBUG
INFO
WARNING
ERROR
FATAL
)
const tunnel_size_default = 1024
type Record struct {
time string
code string
info string
level int
}
func (r *Record) String() string {
return fmt.Sprintf("[%s][%s][%s] %s\n", LEVEL_FLAGS[r.level], r.time, r.code, r.info)
}
type Writer interface {
Init() error
Write(*Record) error
}
type Rotater interface {
Rotate() error
SetPathPattern(string) error
}
type Flusher interface {
Flush() error
}
type Logger struct {
writers []Writer
tunnel chan *Record
level int
lastTime int64
lastTimeStr string
c chan bool
layout string
recordPool *sync.Pool
}
func NewLogger() *Logger {
if logger_default != nil && takeup == false {
takeup = true //默认启动标志
return logger_default
}
l := new(Logger)
l.writers = []Writer{}
l.tunnel = make(chan *Record, tunnel_size_default)
l.c = make(chan bool, 2)
l.level = DEBUG
l.layout = "2006/01/02 15:04:05"
l.recordPool = &sync.Pool{New: func() interface{} {
return &Record{}
}}
go boostrapLogWriter(l)
return l
}
func (l *Logger) Register(w Writer) {
if err := w.Init(); err != nil {
panic(err)
}
l.writers = append(l.writers, w)
}
func (l *Logger) SetLevel(lvl int) {
l.level = lvl
}
func (l *Logger) SetLayout(layout string) {
l.layout = layout
}
func (l *Logger) Trace(fmt string, args ...interface{}) {
l.deliverRecordToWriter(TRACE, fmt, args...)
}
func (l *Logger) Debug(fmt string, args ...interface{}) {
l.deliverRecordToWriter(DEBUG, fmt, args...)
}
func (l *Logger) Warn(fmt string, args ...interface{}) {
l.deliverRecordToWriter(WARNING, fmt, args...)
}
func (l *Logger) Info(fmt string, args ...interface{}) {
l.deliverRecordToWriter(INFO, fmt, args...)
}
func (l *Logger) Error(fmt string, args ...interface{}) {
l.deliverRecordToWriter(ERROR, fmt, args...)
}
func (l *Logger) Fatal(fmt string, args ...interface{}) {
l.deliverRecordToWriter(FATAL, fmt, args...)
}
func (l *Logger) Close() {
close(l.tunnel)
<-l.c
for _, w := range l.writers {
if f, ok := w.(Flusher); ok {
if err := f.Flush(); err != nil {
log.Println(err)
}
}
}
}
func (l *Logger) deliverRecordToWriter(level int, format string, args ...interface{}) {
var inf, code string
if level < l.level {
return
}
if format != "" {
inf = fmt.Sprintf(format, args...)
} else {
inf = fmt.Sprint(args...)
}
// source code, file and line num
_, file, line, ok := runtime.Caller(2)
if ok {
code = path.Base(file) + ":" + strconv.Itoa(line)
}
// format time
now := time.Now()
if now.Unix() != l.lastTime {
l.lastTime = now.Unix()
l.lastTimeStr = now.Format(l.layout)
}
r := l.recordPool.Get().(*Record)
r.info = inf
r.code = code
r.time = l.lastTimeStr
r.level = level
l.tunnel <- r
}
func boostrapLogWriter(logger *Logger) {
if logger == nil {
panic("logger is nil")
}
var (
r *Record
ok bool
)
if r, ok = <-logger.tunnel; !ok {
logger.c <- true
return
}
for _, w := range logger.writers {
if err := w.Write(r); err != nil {
log.Println(err)
}
}
flushTimer := time.NewTimer(time.Millisecond * 500)
rotateTimer := time.NewTimer(time.Second * 10)
for {
select {
case r, ok = <-logger.tunnel:
if !ok {
logger.c <- true
return
}
for _, w := range logger.writers {
if err := w.Write(r); err != nil {
log.Println(err)
}
}
logger.recordPool.Put(r)
case <-flushTimer.C:
for _, w := range logger.writers {
if f, ok := w.(Flusher); ok {
if err := f.Flush(); err != nil {
log.Println(err)
}
}
}
flushTimer.Reset(time.Millisecond * 1000)
case <-rotateTimer.C:
for _, w := range logger.writers {
if r, ok := w.(Rotater); ok {
if err := r.Rotate(); err != nil {
log.Println(err)
}
}
}
rotateTimer.Reset(time.Second * 10)
}
}
}
// default logger
var (
logger_default *Logger
takeup = false
)
func SetLevel(lvl int) {
defaultLoggerInit()
logger_default.level = lvl
}
func SetLayout(layout string) {
defaultLoggerInit()
logger_default.layout = layout
}
func Trace(fmt string, args ...interface{}) {
defaultLoggerInit()
logger_default.deliverRecordToWriter(TRACE, fmt, args...)
}
func Debug(fmt string, args ...interface{}) {
defaultLoggerInit()
logger_default.deliverRecordToWriter(DEBUG, fmt, args...)
}
func Warn(fmt string, args ...interface{}) {
defaultLoggerInit()
logger_default.deliverRecordToWriter(WARNING, fmt, args...)
}
func Info(fmt string, args ...interface{}) {
defaultLoggerInit()
logger_default.deliverRecordToWriter(INFO, fmt, args...)
}
func Error(fmt string, args ...interface{}) {
defaultLoggerInit()
logger_default.deliverRecordToWriter(ERROR, fmt, args...)
}
func Fatal(fmt string, args ...interface{}) {
defaultLoggerInit()
logger_default.deliverRecordToWriter(FATAL, fmt, args...)
}
func Register(w Writer) {
defaultLoggerInit()
logger_default.Register(w)
}
func Close() {
defaultLoggerInit()
logger_default.Close()
logger_default = nil
takeup = false
}
func defaultLoggerInit() {
if takeup==false{
logger_default = NewLogger()
}
}
package log
import (
"testing"
"time"
)
//测试日志实例打点
func TestLogInstance(t *testing.T) {
nlog:= NewLogger()
logConf:= LogConfig{
Level:"trace",
FW: ConfFileWriter{
On:true,
LogPath:"./log_test.log",
RotateLogPath:"./log_test.log",
WfLogPath:"./log_test.wf.log",
RotateWfLogPath:"./log_test.wf.log",
},
CW: ConfConsoleWriter{
On:true,
Color:true,
},
}
SetupLogInstanceWithConf(logConf,nlog)
nlog.Info("test message")
nlog.Close()
time.Sleep(time.Second)
}
\ No newline at end of file
[INFO][2020/10/29 11:18:13][log_test.go:26] test message
[INFO][2020/10/29 11:18:52][log_test.go:26] test message
[INFO][2020/10/29 11:18:55][log_test.go:26] test message
package http_proxy_middleware
import (
"github.com/gin-gonic/gin"
"ichunt-micro/dao"
"ichunt-micro/golang_common/log"
"ichunt-micro/middleware"
)
//匹配接入方式 基于请求信息
func HTTPAccessModeMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
service, err := dao.ServiceManagerHandler.HTTPAccessMode(c)
if err != nil {
log.Error("%v",err)
middleware.ResponseError(c, 1001, err)
c.Abort()
return
}
c.Set("service", service)
c.Next()
}
}
package http_proxy_middleware
import (
"fmt"
"ichunt-micro/dao"
"ichunt-micro/middleware"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"strings"
)
//匹配接入方式 基于请求信息
func HTTPBlackListMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
serverInterface, ok := c.Get("service")
if !ok {
middleware.ResponseError(c, 2001, errors.New("service not found"))
c.Abort()
return
}
serviceDetail := serverInterface.(*dao.ServiceDetail)
whileIpList := []string{}
if serviceDetail.AccessControl.WhiteList != "" {
whileIpList = strings.Split(serviceDetail.AccessControl.WhiteList, ",")
}
blackIpList := []string{}
if serviceDetail.AccessControl.BlackList != "" {
blackIpList = strings.Split(serviceDetail.AccessControl.BlackList, ",")
}
if serviceDetail.AccessControl.OpenAuth == 1 && len(whileIpList) == 0 && len(blackIpList) > 0 {
if public.InStringSlice(blackIpList, c.ClientIP()) {
middleware.ResponseError(c, 3001, errors.New(fmt.Sprintf("%s in black ip list", c.ClientIP())))
c.Abort()
return
}
}
c.Next()
}
}
package http_proxy_middleware
import (
"ichunt-micro/dao"
"ichunt-micro/middleware"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
)
func HTTPFlowCountMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
serverInterface, ok := c.Get("service")
if !ok {
middleware.ResponseError(c, 2001, errors.New("service not found"))
c.Abort()
return
}
serviceDetail := serverInterface.(*dao.ServiceDetail)
//统计项 1 全站 2 服务 3 租户
totalCounter, err := public.FlowCounterHandler.GetCounter(public.FlowTotal)
if err != nil {
middleware.ResponseError(c, 4001, err)
c.Abort()
return
}
totalCounter.Increase()
//dayCount, _ := totalCounter.GetDayData(time.Now())
//fmt.Printf("totalCounter qps:%v,dayCount:%v", totalCounter.QPS, dayCount)
serviceCounter, err := public.FlowCounterHandler.GetCounter(public.FlowServicePrefix + serviceDetail.Info.ServiceName)
if err != nil {
middleware.ResponseError(c, 4001, err)
c.Abort()
return
}
serviceCounter.Increase()
//dayServiceCount, _ := serviceCounter.GetDayData(time.Now())
//fmt.Printf("serviceCounter qps:%v,dayCount:%v", serviceCounter.QPS, dayServiceCount)
c.Next()
}
}
package http_proxy_middleware
import (
"fmt"
"ichunt-micro/dao"
"ichunt-micro/middleware"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
)
func HTTPFlowLimitMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
serverInterface, ok := c.Get("service")
if !ok {
middleware.ResponseError(c, 2001, errors.New("service not found"))
c.Abort()
return
}
serviceDetail := serverInterface.(*dao.ServiceDetail)
if serviceDetail.AccessControl.ServiceFlowLimit != 0 {
fmt.Println(public.FlowServicePrefix+serviceDetail.Info.ServiceName,float64(serviceDetail.AccessControl.ServiceFlowLimit))
serviceLimiter, err := public.FlowLimiterHandler.GetLimiter(
public.FlowServicePrefix+serviceDetail.Info.ServiceName,
float64(serviceDetail.AccessControl.ServiceFlowLimit))
if err != nil {
middleware.ResponseError(c, 5001, err)
c.Abort()
return
}
if !serviceLimiter.Allow() {
middleware.ResponseError(c, 5002, errors.New(fmt.Sprintf("service flow limit %v", serviceDetail.AccessControl.ServiceFlowLimit), ))
c.Abort()
return
}
}
if serviceDetail.AccessControl.ClientIPFlowLimit > 0 {
clientLimiter, err := public.FlowLimiterHandler.GetLimiter(
public.FlowServicePrefix+serviceDetail.Info.ServiceName+"_"+c.ClientIP(),
float64(serviceDetail.AccessControl.ClientIPFlowLimit))
if err != nil {
middleware.ResponseError(c, 5003, err)
c.Abort()
return
}
if !clientLimiter.Allow() {
middleware.ResponseError(c, 5002, errors.New(fmt.Sprintf("%v flow limit %v", c.ClientIP(), serviceDetail.AccessControl.ClientIPFlowLimit), ))
c.Abort()
return
}
}
c.Next()
}
}
package http_proxy_middleware
import (
"ichunt-micro/dao"
"ichunt-micro/middleware"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"strings"
)
//匹配接入方式 基于请求信息
func HTTPHeaderTransferMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
serverInterface, ok := c.Get("service")
if !ok {
middleware.ResponseError(c, 2001, errors.New("service not found"))
c.Abort()
return
}
serviceDetail := serverInterface.(*dao.ServiceDetail)
for _,item:=range strings.Split(serviceDetail.HTTPRule.HeaderTransfor,","){
items:=strings.Split(item," ")
if len(items)!=3{
continue
}
if items[0]=="add" || items[0]=="edit"{
c.Request.Header.Set(items[1],items[2])
}
if items[0]=="del"{
c.Request.Header.Del(items[1])
}
}
c.Next()
}
}
package http_proxy_middleware
import (
"ichunt-micro/dao"
"ichunt-micro/middleware"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"strings"
)
//jwt auth token
func HTTPJwtAuthTokenMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
serverInterface, ok := c.Get("service")
if !ok {
middleware.ResponseError(c, 2001, errors.New("service not found"))
c.Abort()
return
}
serviceDetail := serverInterface.(*dao.ServiceDetail)
//fmt.Println("serviceDetail",serviceDetail)
// decode jwt token
// app_id 与 app_list 取得 appInfo
// appInfo 放到 gin.context
token:=strings.ReplaceAll(c.GetHeader("Authorization"),"Bearer ","")
//fmt.Println("token",token)
appMatched:=false
if token!=""{
claims,err:=public.JwtDecode(token)
if err!=nil{
middleware.ResponseError(c, 2002, err)
c.Abort()
return
}
//fmt.Println("claims.Issuer",claims.Issuer)
appList:=dao.AppManagerHandler.GetAppList()
for _,appInfo:=range appList{
if appInfo.AppID==claims.Issuer{
c.Set("app",appInfo)
appMatched = true
break
}
}
}
if serviceDetail.AccessControl.OpenAuth==1 && !appMatched{
middleware.ResponseError(c, 2003, errors.New("not match valid app"))
c.Abort()
return
}
c.Next()
}
}
package http_proxy_middleware
import (
"fmt"
"ichunt-micro/dao"
"ichunt-micro/middleware"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
)
func HTTPJwtFlowCountMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
appInterface, ok := c.Get("app")
if !ok {
c.Next()
return
}
appInfo := appInterface.(*dao.App)
appCounter, err := public.FlowCounterHandler.GetCounter(public.FlowAppPrefix + appInfo.AppID)
if err != nil {
middleware.ResponseError(c, 2002, err)
c.Abort()
return
}
appCounter.Increase()
if appInfo.Qpd>0 && appCounter.TotalCount>appInfo.Qpd{
middleware.ResponseError(c, 2003, errors.New(fmt.Sprintf("租户日请求量限流 limit:%v current:%v",appInfo.Qpd,appCounter.TotalCount)))
c.Abort()
return
}
c.Next()
}
}
package http_proxy_middleware
import (
"fmt"
"ichunt-micro/dao"
"ichunt-micro/middleware"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
)
func HTTPJwtFlowLimitMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
appInterface, ok := c.Get("app")
if !ok {
c.Next()
return
}
appInfo := appInterface.(*dao.App)
if appInfo.Qps > 0 {
clientLimiter, err := public.FlowLimiterHandler.GetLimiter(
public.FlowAppPrefix+appInfo.AppID+"_"+c.ClientIP(),
float64(appInfo.Qps))
if err != nil {
middleware.ResponseError(c, 5001, err)
c.Abort()
return
}
if !clientLimiter.Allow() {
middleware.ResponseError(c, 5002, errors.New(fmt.Sprintf("%v flow limit %v", c.ClientIP(), appInfo.Qps), ))
c.Abort()
return
}
}
c.Next()
}
}
package http_proxy_middleware
import (
"ichunt-micro/proxy"
"github.com/gin-gonic/gin"
"log"
)
//匹配接入方式 基于请求信息
func HTTPReverseProxyMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
log.Print("[INFO] 经过反向代理中间件 ")
proxy,err := proxy.NewMultipleHostsReverseProxy(c)
if err != nil{
c.Abort()
return
}
proxy.ServeHTTP(c.Writer, c.Request)
c.Abort()
return
}
}
package http_proxy_middleware
import (
"ichunt-micro/dao"
"ichunt-micro/middleware"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"strings"
)
//匹配接入方式 基于请求信息
func HTTPStripUriMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
serverInterface, ok := c.Get("service")
if !ok {
middleware.ResponseError(c, 2001, errors.New("service not found"))
c.Abort()
return
}
serviceDetail := serverInterface.(*dao.ServiceDetail)
if serviceDetail.HTTPRule.RuleType==public.HTTPRuleTypePrefixURL && serviceDetail.HTTPRule.NeedStripUri==1{
//fmt.Println("c.Request.URL.Path",c.Request.URL.Path)
c.Request.URL.Path = strings.Replace(c.Request.URL.Path,serviceDetail.HTTPRule.Rule,"",1)
//fmt.Println("c.Request.URL.Path",c.Request.URL.Path)
}
//http://127.0.0.1:8080/test_http_string/abbb
//http://127.0.0.1:2004/abbb
c.Next()
}
}
package http_proxy_middleware
import (
"ichunt-micro/dao"
"ichunt-micro/middleware"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"regexp"
"strings"
)
//匹配接入方式 基于请求信息
func HTTPUrlRewriteMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
serverInterface, ok := c.Get("service")
if !ok {
middleware.ResponseError(c, 2001, errors.New("service not found"))
c.Abort()
return
}
serviceDetail := serverInterface.(*dao.ServiceDetail)
for _,item:=range strings.Split(serviceDetail.HTTPRule.UrlRewrite,","){
//fmt.Println("item rewrite",item)
items:=strings.Split(item," ")
if len(items)!=2{
continue
}
regexp,err:=regexp.Compile(items[0])
if err!=nil{
//fmt.Println("regexp.Compile err",err)
continue
}
//fmt.Println("before rewrite",c.Request.URL.Path)
replacePath:=regexp.ReplaceAll([]byte(c.Request.URL.Path),[]byte(items[1]))
c.Request.URL.Path = string(replacePath)
//fmt.Println("after rewrite",c.Request.URL.Path)
}
c.Next()
}
}
package http_proxy_middleware
import (
"fmt"
"ichunt-micro/dao"
"ichunt-micro/middleware"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"strings"
)
//匹配接入方式 基于请求信息
func HTTPWhiteListMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
serverInterface, ok := c.Get("service")
if !ok {
middleware.ResponseError(c, 2001, errors.New("service not found"))
c.Abort()
return
}
serviceDetail := serverInterface.(*dao.ServiceDetail)
iplist := []string{}
if serviceDetail.AccessControl.WhiteList!=""{
iplist = strings.Split(serviceDetail.AccessControl.WhiteList, ",")
}
if serviceDetail.AccessControl.OpenAuth == 1 && len(iplist) > 0 {
if !public.InStringSlice(iplist, c.ClientIP()) {
middleware.ResponseError(c, 3001, errors.New(fmt.Sprintf("%s not in white ip list", c.ClientIP())))
c.Abort()
return
}
}
c.Next()
}
}
package http_proxy_router
import (
"context"
"github.com/gin-gonic/gin"
"ichunt-micro/golang_common/lib"
"ichunt-micro/middleware"
"log"
"net/http"
"time"
)
var (
HttpSrvHandler *http.Server
HttpsSrvHandler *http.Server
)
func HttpServerRun() {
//debug release test 开发使用debug模式
gin.SetMode(lib.GetStringConf("proxy.base.debug_mode"))
r := InitRouter(middleware.RecoveryMiddleware(),
middleware.RequestLog())
HttpSrvHandler = &http.Server{
Addr: lib.GetStringConf("proxy.http.addr"),
//Addr: "192.168.1.234:2002",
Handler: r,
ReadTimeout: time.Duration(lib.GetIntConf("proxy.http.read_timeout")) * time.Second,
WriteTimeout: time.Duration(lib.GetIntConf("proxy.http.write_timeout")) * time.Second,
MaxHeaderBytes: 1 << uint(lib.GetIntConf("proxy.http.max_header_bytes")),
}
log.Printf(" [INFO] http_proxy_run %s\n", lib.GetStringConf("proxy.http.addr"))
if err := HttpSrvHandler.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf(" [ERROR] http_proxy_run %s err:%v\n", lib.GetStringConf("proxy.http.addr"), err)
}
}
func HttpsServerRun() {
gin.SetMode(lib.GetStringConf("proxy.base.debug_mode"))
r := InitRouter(middleware.RecoveryMiddleware(),
middleware.RequestLog())
HttpsSrvHandler = &http.Server{
Addr: lib.GetStringConf("proxy.https.addr"),
Handler: r,
ReadTimeout: time.Duration(lib.GetIntConf("proxy.https.read_timeout")) * time.Second,
WriteTimeout: time.Duration(lib.GetIntConf("proxy.https.write_timeout")) * time.Second,
MaxHeaderBytes: 1 << uint(lib.GetIntConf("proxy.https.max_header_bytes")),
}
log.Printf(" [INFO] https_proxy_run %s\n", lib.GetStringConf("proxy.https.addr"))
//todo 以下命令只在编译机有效,如果是交叉编译情况下需要单独设置路径
//if err := HttpsSrvHandler.ListenAndServeTLS(cert_file.Path("server.crt"), cert_file.Path("server.key")); err != nil && err!=http.ErrServerClosed {
if err := HttpsSrvHandler.ListenAndServeTLS("./cert_file/server.crt", "./cert_file/server.key"); err != nil && err != http.ErrServerClosed {
log.Fatalf(" [ERROR] https_proxy_run %s err:%v\n", lib.GetStringConf("proxy.https.addr"), err)
}
}
func HttpServerStop() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := HttpSrvHandler.Shutdown(ctx); err != nil {
log.Printf(" [ERROR] http_proxy_stop err:%v\n", err)
}
log.Printf(" [INFO] http_proxy_stop %v stopped\n", lib.GetStringConf("proxy.http.addr"))
}
func HttpsServerStop() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := HttpsSrvHandler.Shutdown(ctx); err != nil {
log.Fatalf(" [ERROR] https_proxy_stop err:%v\n", err)
}
log.Printf(" [INFO] https_proxy_stop %v stopped\n", lib.GetStringConf("proxy.https.addr"))
}
package http_proxy_router
import (
"github.com/gin-gonic/gin"
"ichunt-micro/http_proxy_middleware"
)
func InitRouter(middlewares ...gin.HandlerFunc) *gin.Engine {
//todo 优化点1
//router := gin.Default()
router := gin.New()
router.Use(middlewares...)
router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
//router.GET("/test", func(c *gin.Context) {
// c.JSON(200, gin.H{
// "message": "test",
// })
//})
router.Use(
//从数据库中加载所有服务相关的信息
http_proxy_middleware.HTTPAccessModeMiddleware(),
//http_proxy_middleware.HTTPFlowCountMiddleware(),
//客户端 和 服务端 限流
http_proxy_middleware.HTTPFlowLimitMiddleware(),
//http_proxy_middleware.HTTPJwtAuthTokenMiddleware(),
//http_proxy_middleware.HTTPJwtFlowCountMiddleware(),
//http_proxy_middleware.HTTPJwtFlowLimitMiddleware(),
//http_proxy_middleware.HTTPWhiteListMiddleware(),
//http_proxy_middleware.HTTPBlackListMiddleware(),
//请求头header操作 curd
http_proxy_middleware.HTTPHeaderTransferMiddleware(),
//服务名 匹配前缀
http_proxy_middleware.HTTPStripUriMiddleware(),
//伪静态
http_proxy_middleware.HTTPUrlRewriteMiddleware(),
gin.Logger(),
//反向代理
http_proxy_middleware.HTTPReverseProxyMiddleware(),
)
return router
}
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
This diff could not be displayed because it is too large.
package main
import (
"context"
"flag"
"ichunt-micro/dao"
"ichunt-micro/golang_common/lib"
"ichunt-micro/http_proxy_router"
"ichunt-micro/golang_common/log"
"ichunt-micro/proxy/load_balance"
"ichunt-micro/registry"
_ "ichunt-micro/registry/etcd"
"os"
"os/signal"
"syscall"
"time"
)
var (
config = flag.String("config", "./conf/dev/", "input config file like ./conf/dev/")
)
func registryEtcd(){
//初始化注册中心 注册etcd 服务中心
registryInst, err := registry.InitRegistry(context.TODO(), "etcd",
//registry.WithAddrs([]string{"192.168.2.232:2379"}),
registry.WithAddrs(lib.GetStringSliceConf("base.etcd.addrs")),
registry.WithTimeout(5*time.Second),
registry.WithRegistryPath("/ichuntMicroService/"),
registry.WithHeartBeat(5),
)
if err != nil {
log.Error("注册etcd失败 %v",err)
return
}
load_balance.Init(registryInst)
}
func main(){
if *config == "" {
flag.Usage()
os.Exit(1)
}
lib.InitModule(*config)
defer lib.Destroy()
dao.ServiceManagerHandler.LoadOnce()
registryEtcd()
go func() {
http_proxy_router.HttpServerRun()
}()
quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
http_proxy_router.HttpServerStop()
}
package middleware
import (
"errors"
"fmt"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/gin"
)
func IPAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
isMatched := false
for _, host := range lib.GetStringSliceConf("base.http.allow_ip") {
if c.ClientIP() == host {
isMatched = true
}
}
if !isMatched{
ResponseError(c, InternalErrorCode, errors.New(fmt.Sprintf("%v, not in iplist", c.ClientIP())))
c.Abort()
return
}
c.Next()
}
}
package middleware
import (
"errors"
"fmt"
"ichunt-micro/public"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/gin"
"runtime/debug"
)
// RecoveryMiddleware捕获所有panic,并且返回错误信息
func RecoveryMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
//先做一下日志记录
fmt.Println(string(debug.Stack()))
public.ComLogNotice(c, "_com_panic", map[string]interface{}{
"error": fmt.Sprint(err),
"stack": string(debug.Stack()),
})
if lib.ConfBase.DebugMode != "debug" {
ResponseError(c, 500, errors.New("内部错误"))
return
} else {
ResponseError(c, 500, errors.New(fmt.Sprint(err)))
return
}
}
}()
c.Next()
}
}
\ No newline at end of file
package middleware
import (
"bytes"
"ichunt-micro/public"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/gin"
"io/ioutil"
"time"
)
// 请求进入日志
func RequestInLog(c *gin.Context) {
traceContext := lib.NewTrace()
if traceId := c.Request.Header.Get("com-header-rid"); traceId != "" {
traceContext.TraceId = traceId
}
if spanId := c.Request.Header.Get("com-header-spanid"); spanId != "" {
traceContext.SpanId = spanId
}
c.Set("startExecTime", time.Now())
c.Set("trace", traceContext)
bodyBytes, _ := ioutil.ReadAll(c.Request.Body)
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) // Write body back
lib.Log.TagInfo(traceContext, "_com_request_in", map[string]interface{}{
"uri": c.Request.RequestURI,
"method": c.Request.Method,
"args": c.Request.PostForm,
"body": string(bodyBytes),
"from": c.ClientIP(),
})
}
// 请求输出日志
func RequestOutLog(c *gin.Context) {
// after request
endExecTime := time.Now()
response, _ := c.Get("response")
st, _ := c.Get("startExecTime")
startExecTime, _ := st.(time.Time)
public.ComLogNotice(c, "_com_request_out", map[string]interface{}{
"uri": c.Request.RequestURI,
"method": c.Request.Method,
"args": c.Request.PostForm,
"from": c.ClientIP(),
"response": response,
"proc_time": endExecTime.Sub(startExecTime).Seconds(),
})
}
func RequestLog() gin.HandlerFunc {
return func(c *gin.Context) {
//todo 优化点4
if lib.GetBoolConf("base.log.file_writer.on") {
RequestInLog(c)
defer RequestOutLog(c)
}
c.Next()
}
}
package middleware
import (
"encoding/json"
"fmt"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/gin"
"strings"
)
type ResponseCode int
//1000以下为通用码,1000以上为用户自定义码
const (
SuccessCode ResponseCode = iota
UndefErrorCode
ValidErrorCode
InternalErrorCode
InvalidRequestErrorCode ResponseCode = 401
CustomizeCode ResponseCode = 1000
GROUPALL_SAVE_FLOWERROR ResponseCode = 2001
)
type Response struct {
ErrorCode ResponseCode `json:"errno"`
ErrorMsg string `json:"errmsg"`
Data interface{} `json:"data"`
TraceId interface{} `json:"trace_id"`
Stack interface{} `json:"stack"`
}
func ResponseError(c *gin.Context, code ResponseCode, err error) {
trace, _ := c.Get("trace")
traceContext, _ := trace.(*lib.TraceContext)
traceId := ""
if traceContext != nil {
traceId = traceContext.TraceId
}
stack := ""
if c.Query("is_debug") == "1" || lib.GetConfEnv() == "dev" {
stack = strings.Replace(fmt.Sprintf("%+v", err), err.Error()+"\n", "", -1)
}
resp := &Response{ErrorCode: code, ErrorMsg: err.Error(), Data: "", TraceId: traceId, Stack: stack}
c.JSON(200, resp)
response, _ := json.Marshal(resp)
c.Set("response", string(response))
c.AbortWithError(200, err)
}
func ResponseSuccess(c *gin.Context, data interface{}) {
trace, _ := c.Get("trace")
traceContext, _ := trace.(*lib.TraceContext)
traceId := ""
if traceContext != nil {
traceId = traceContext.TraceId
}
resp := &Response{ErrorCode: SuccessCode, ErrorMsg: "", Data: data, TraceId: traceId}
c.JSON(200, resp)
response, _ := json.Marshal(resp)
c.Set("response", string(response))
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment