Commit 527c92e4 by 孙龙

init 2

parent f82dfc47
Showing with 7319 additions and 15 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 controller
import (
"fmt"
"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"
"strings"
"time"
)
type ServiceController struct{}
func ServiceRegister(group *gin.RouterGroup) {
service := &ServiceController{}
group.GET("/service_list", service.ServiceList)
group.GET("/service_delete", service.ServiceDelete)
group.GET("/service_detail", service.ServiceDetail)
group.GET("/service_stat", service.ServiceStat)
group.POST("/service_add_http", service.ServiceAddHTTP)
group.POST("/service_update_http", service.ServiceUpdateHTTP)
group.POST("/service_add_tcp", service.ServiceAddTcp)
group.POST("/service_update_tcp", service.ServiceUpdateTcp)
group.POST("/service_add_grpc", service.ServiceAddGrpc)
group.POST("/service_update_grpc", service.ServiceUpdateGrpc)
}
// ServiceList godoc
// @Summary 服务列表
// @Description 服务列表
// @Tags 服务管理
// @ID /service/service_list
// @Accept json
// @Produce json
// @Param info query string false "关键词"
// @Param page_size query int true "每页个数"
// @Param page_no query int true "当前页数"
// @Success 200 {object} middleware.Response{data=dto.ServiceListOutput} "success"
// @Router /service/service_list [get]
func (service *ServiceController) ServiceList(c *gin.Context) {
params := &dto.ServiceListInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
//从db中分页读取基本信息
serviceInfo := &dao.ServiceInfo{}
list, total, err := serviceInfo.PageList(c, tx, params)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
//格式化输出信息
outList := []dto.ServiceListItemOutput{}
for _, listItem := range list {
serviceDetail, err := listItem.ServiceDetail(c, tx, &listItem)
if err != nil {
middleware.ResponseError(c, 2003, err)
return
}
//1、http后缀接入 clusterIP+clusterPort+path
//2、http域名接入 domain
//3、tcp、grpc接入 clusterIP+servicePort
serviceAddr := "unknow"
clusterIP := lib.GetStringConf("base.cluster.cluster_ip")
clusterPort := lib.GetStringConf("base.cluster.cluster_port")
clusterSSLPort := lib.GetStringConf("base.cluster.cluster_ssl_port")
if serviceDetail.Info.LoadType == public.LoadTypeHTTP &&
serviceDetail.HTTPRule.RuleType == public.HTTPRuleTypePrefixURL &&
serviceDetail.HTTPRule.NeedHttps == 1 {
serviceAddr = fmt.Sprintf("%s:%s%s", clusterIP, clusterSSLPort, serviceDetail.HTTPRule.Rule)
}
if serviceDetail.Info.LoadType == public.LoadTypeHTTP &&
serviceDetail.HTTPRule.RuleType == public.HTTPRuleTypePrefixURL &&
serviceDetail.HTTPRule.NeedHttps == 0 {
serviceAddr = fmt.Sprintf("%s:%s%s", clusterIP, clusterPort, serviceDetail.HTTPRule.Rule)
}
if serviceDetail.Info.LoadType == public.LoadTypeHTTP &&
serviceDetail.HTTPRule.RuleType == public.HTTPRuleTypeDomain {
serviceAddr = serviceDetail.HTTPRule.Rule
}
if serviceDetail.Info.LoadType == public.LoadTypeTCP {
serviceAddr = fmt.Sprintf("%s:%d", clusterIP, serviceDetail.TCPRule.Port)
}
if serviceDetail.Info.LoadType == public.LoadTypeGRPC {
serviceAddr = fmt.Sprintf("%s:%d", clusterIP, serviceDetail.GRPCRule.Port)
}
ipList := serviceDetail.LoadBalance.GetIPListByModel()
counter, err := public.FlowCounterHandler.GetCounter(public.FlowServicePrefix + listItem.ServiceName)
if err != nil {
middleware.ResponseError(c, 2004, err)
return
}
outItem := dto.ServiceListItemOutput{
ID: listItem.ID,
LoadType: listItem.LoadType,
ServiceName: listItem.ServiceName,
ServiceDesc: listItem.ServiceDesc,
ServiceAddr: serviceAddr,
Qps: counter.QPS,
Qpd: counter.TotalCount,
TotalNode: len(ipList),
}
outList = append(outList, outItem)
}
out := &dto.ServiceListOutput{
Total: total,
List: outList,
}
middleware.ResponseSuccess(c, out)
}
// ServiceDelete godoc
// @Summary 服务删除
// @Description 服务删除
// @Tags 服务管理
// @ID /service/service_delete
// @Accept json
// @Produce json
// @Param id query string true "服务ID"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /service/service_delete [get]
func (service *ServiceController) ServiceDelete(c *gin.Context) {
params := &dto.ServiceDeleteInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
//读取基本信息
serviceInfo := &dao.ServiceInfo{ID: params.ID}
serviceInfo, err = serviceInfo.Find(c, tx, serviceInfo)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
serviceInfo.IsDelete = 1
if err := serviceInfo.Save(c, tx); err != nil {
middleware.ResponseError(c, 2003, err)
return
}
middleware.ResponseSuccess(c, "")
}
// ServiceDetail godoc
// @Summary 服务详情
// @Description 服务详情
// @Tags 服务管理
// @ID /service/service_detail
// @Accept json
// @Produce json
// @Param id query string true "服务ID"
// @Success 200 {object} middleware.Response{data=dao.ServiceDetail} "success"
// @Router /service/service_detail [get]
func (service *ServiceController) ServiceDetail(c *gin.Context) {
params := &dto.ServiceDeleteInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
//读取基本信息
serviceInfo := &dao.ServiceInfo{ID: params.ID}
serviceInfo, err = serviceInfo.Find(c, tx, serviceInfo)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
serviceDetail, err := serviceInfo.ServiceDetail(c, tx, serviceInfo)
if err != nil {
middleware.ResponseError(c, 2003, err)
return
}
middleware.ResponseSuccess(c, serviceDetail)
}
// ServiceStat godoc
// @Summary 服务统计
// @Description 服务统计
// @Tags 服务管理
// @ID /service/service_stat
// @Accept json
// @Produce json
// @Param id query string true "服务ID"
// @Success 200 {object} middleware.Response{data=dto.ServiceStatOutput} "success"
// @Router /service/service_stat [get]
func (service *ServiceController) ServiceStat(c *gin.Context) {
params := &dto.ServiceDeleteInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
//读取基本信息
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
serviceInfo := &dao.ServiceInfo{ID: params.ID}
serviceDetail, err := serviceInfo.ServiceDetail(c, tx, serviceInfo)
if err != nil {
middleware.ResponseError(c, 2003, err)
return
}
counter, err := public.FlowCounterHandler.GetCounter(public.FlowServicePrefix + serviceDetail.Info.ServiceName)
if err != nil {
middleware.ResponseError(c, 2004, 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,
})
}
// ServiceAddHTTP godoc
// @Summary 添加HTTP服务
// @Description 添加HTTP服务
// @Tags 服务管理
// @ID /service/service_add_http
// @Accept json
// @Produce json
// @Param body body dto.ServiceAddHTTPInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /service/service_add_http [post]
func (service *ServiceController) ServiceAddHTTP(c *gin.Context) {
params := &dto.ServiceAddHTTPInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
if len(strings.Split(params.IpList, ",")) != len(strings.Split(params.WeightList, ",")) {
middleware.ResponseError(c, 2004, errors.New("IP列表与权重列表数量不一致"))
return
}
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2001, err)
return
}
tx = tx.Begin()
serviceInfo := &dao.ServiceInfo{ServiceName: params.ServiceName}
if _, err = serviceInfo.Find(c, tx, serviceInfo); err == nil {
tx.Rollback()
middleware.ResponseError(c, 2002, errors.New("服务已存在"))
return
}
httpUrl := &dao.HttpRule{RuleType: params.RuleType, Rule: params.Rule}
if _, err := httpUrl.Find(c, tx, httpUrl); err == nil {
tx.Rollback()
middleware.ResponseError(c, 2003, errors.New("服务接入前缀或域名已存在"))
return
}
serviceModel := &dao.ServiceInfo{
ServiceName: params.ServiceName,
ServiceDesc: params.ServiceDesc,
}
if err := serviceModel.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2005, err)
return
}
//serviceModel.ID
httpRule := &dao.HttpRule{
ServiceID: serviceModel.ID,
RuleType: params.RuleType,
Rule: params.Rule,
NeedHttps: params.NeedHttps,
NeedStripUri: params.NeedStripUri,
NeedWebsocket: params.NeedWebsocket,
UrlRewrite: params.UrlRewrite,
HeaderTransfor: params.HeaderTransfor,
}
if err := httpRule.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2006, err)
return
}
accessControl := &dao.AccessControl{
ServiceID: serviceModel.ID,
OpenAuth: params.OpenAuth,
BlackList: params.BlackList,
WhiteList: params.WhiteList,
ClientIPFlowLimit: params.ClientipFlowLimit,
ServiceFlowLimit: params.ServiceFlowLimit,
}
if err := accessControl.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2007, err)
return
}
loadbalance := &dao.LoadBalance{
ServiceID: serviceModel.ID,
RoundType: params.RoundType,
IpList: params.IpList,
WeightList: params.WeightList,
UpstreamConnectTimeout: params.UpstreamConnectTimeout,
UpstreamHeaderTimeout: params.UpstreamHeaderTimeout,
UpstreamIdleTimeout: params.UpstreamIdleTimeout,
UpstreamMaxIdle: params.UpstreamMaxIdle,
}
if err := loadbalance.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2008, err)
return
}
tx.Commit()
middleware.ResponseSuccess(c, "")
}
// ServiceUpdateHTTP godoc
// @Summary 修改HTTP服务
// @Description 修改HTTP服务
// @Tags 服务管理
// @ID /service/service_update_http
// @Accept json
// @Produce json
// @Param body body dto.ServiceUpdateHTTPInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /service/service_update_http [post]
func (service *ServiceController) ServiceUpdateHTTP(c *gin.Context) {
params := &dto.ServiceUpdateHTTPInput{}
if err := params.BindValidParam(c); err != nil {
middleware.ResponseError(c, 2000, err)
return
}
if len(strings.Split(params.IpList, ",")) != len(strings.Split(params.WeightList, ",")) {
middleware.ResponseError(c, 2001, errors.New("IP列表与权重列表数量不一致"))
return
}
tx, err := lib.GetGormPool("default")
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
tx = tx.Begin()
serviceInfo := &dao.ServiceInfo{ServiceName: params.ServiceName}
serviceInfo, err = serviceInfo.Find(c, tx, serviceInfo)
if err != nil {
tx.Rollback()
middleware.ResponseError(c, 2003, errors.New("服务不存在"))
return
}
serviceDetail, err := serviceInfo.ServiceDetail(c, tx, serviceInfo)
if err != nil {
tx.Rollback()
middleware.ResponseError(c, 2004, errors.New("服务不存在"))
return
}
info := serviceDetail.Info
info.ServiceDesc = params.ServiceDesc
if err := info.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2005, err)
return
}
httpRule := serviceDetail.HTTPRule
httpRule.NeedHttps = params.NeedHttps
httpRule.NeedStripUri = params.NeedStripUri
httpRule.NeedWebsocket = params.NeedWebsocket
httpRule.UrlRewrite = params.UrlRewrite
httpRule.HeaderTransfor = params.HeaderTransfor
if err := httpRule.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2006, err)
return
}
accessControl := serviceDetail.AccessControl
accessControl.OpenAuth = params.OpenAuth
accessControl.BlackList = params.BlackList
accessControl.WhiteList = params.WhiteList
accessControl.ClientIPFlowLimit = params.ClientipFlowLimit
accessControl.ServiceFlowLimit = params.ServiceFlowLimit
if err := accessControl.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2007, err)
return
}
loadbalance := serviceDetail.LoadBalance
loadbalance.RoundType = params.RoundType
loadbalance.IpList = params.IpList
loadbalance.WeightList = params.WeightList
loadbalance.UpstreamConnectTimeout = params.UpstreamConnectTimeout
loadbalance.UpstreamHeaderTimeout = params.UpstreamHeaderTimeout
loadbalance.UpstreamIdleTimeout = params.UpstreamIdleTimeout
loadbalance.UpstreamMaxIdle = params.UpstreamMaxIdle
if err := loadbalance.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2008, err)
return
}
tx.Commit()
middleware.ResponseSuccess(c, "")
}
// ServiceAddHttp godoc
// @Summary tcp服务添加
// @Description tcp服务添加
// @Tags 服务管理
// @ID /service/service_add_tcp
// @Accept json
// @Produce json
// @Param body body dto.ServiceAddTcpInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /service/service_add_tcp [post]
func (admin *ServiceController) ServiceAddTcp(c *gin.Context) {
params := &dto.ServiceAddTcpInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
//验证 service_name 是否被占用
infoSearch := &dao.ServiceInfo{
ServiceName: params.ServiceName,
IsDelete: 0,
}
if _, err := infoSearch.Find(c, lib.GORMDefaultPool, infoSearch); err == nil {
middleware.ResponseError(c, 2002, errors.New("服务名被占用,请重新输入"))
return
}
//验证端口是否被占用?
tcpRuleSearch := &dao.TcpRule{
Port: params.Port,
}
if _, err := tcpRuleSearch.Find(c, lib.GORMDefaultPool, tcpRuleSearch); err == nil {
middleware.ResponseError(c, 2003, errors.New("服务端口被占用,请重新输入"))
return
}
grpcRuleSearch := &dao.GrpcRule{
Port: params.Port,
}
if _, err := grpcRuleSearch.Find(c, lib.GORMDefaultPool, grpcRuleSearch); err == nil {
middleware.ResponseError(c, 2004, errors.New("服务端口被占用,请重新输入"))
return
}
//ip与权重数量一致
if len(strings.Split(params.IpList, ",")) != len(strings.Split(params.WeightList, ",")) {
middleware.ResponseError(c, 2005, errors.New("ip列表与权重设置不匹配"))
return
}
tx := lib.GORMDefaultPool.Begin()
info := &dao.ServiceInfo{
LoadType: public.LoadTypeTCP,
ServiceName: params.ServiceName,
ServiceDesc: params.ServiceDesc,
}
if err := info.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2006, err)
return
}
loadBalance := &dao.LoadBalance{
ServiceID: info.ID,
RoundType: params.RoundType,
IpList: params.IpList,
WeightList: params.WeightList,
ForbidList: params.ForbidList,
}
if err := loadBalance.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2007, err)
return
}
httpRule := &dao.TcpRule{
ServiceID: info.ID,
Port: params.Port,
}
if err := httpRule.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2008, err)
return
}
accessControl := &dao.AccessControl{
ServiceID: info.ID,
OpenAuth: params.OpenAuth,
BlackList: params.BlackList,
WhiteList: params.WhiteList,
WhiteHostName: params.WhiteHostName,
ClientIPFlowLimit: params.ClientIPFlowLimit,
ServiceFlowLimit: params.ServiceFlowLimit,
}
if err := accessControl.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2009, err)
return
}
tx.Commit()
middleware.ResponseSuccess(c, "")
return
}
// ServiceUpdateTcp godoc
// @Summary tcp服务更新
// @Description tcp服务更新
// @Tags 服务管理
// @ID /service/service_update_tcp
// @Accept json
// @Produce json
// @Param body body dto.ServiceUpdateTcpInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /service/service_update_tcp [post]
func (admin *ServiceController) ServiceUpdateTcp(c *gin.Context) {
params := &dto.ServiceUpdateTcpInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
//ip与权重数量一致
if len(strings.Split(params.IpList, ",")) != len(strings.Split(params.WeightList, ",")) {
middleware.ResponseError(c, 2002, errors.New("ip列表与权重设置不匹配"))
return
}
tx := lib.GORMDefaultPool.Begin()
service := &dao.ServiceInfo{
ID: params.ID,
}
detail, err := service.ServiceDetail(c, lib.GORMDefaultPool, service)
if err != nil {
middleware.ResponseError(c, 2002, err)
return
}
info := detail.Info
info.ServiceDesc = params.ServiceDesc
if err := info.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2003, err)
return
}
loadBalance := &dao.LoadBalance{}
if detail.LoadBalance != nil {
loadBalance = detail.LoadBalance
}
loadBalance.ServiceID = info.ID
loadBalance.RoundType = params.RoundType
loadBalance.IpList = params.IpList
loadBalance.WeightList = params.WeightList
loadBalance.ForbidList = params.ForbidList
if err := loadBalance.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2004, err)
return
}
tcpRule := &dao.TcpRule{}
if detail.TCPRule != nil {
tcpRule = detail.TCPRule
}
tcpRule.ServiceID = info.ID
tcpRule.Port = params.Port
if err := tcpRule.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2005, err)
return
}
accessControl := &dao.AccessControl{}
if detail.AccessControl != nil {
accessControl = detail.AccessControl
}
accessControl.ServiceID = info.ID
accessControl.OpenAuth = params.OpenAuth
accessControl.BlackList = params.BlackList
accessControl.WhiteList = params.WhiteList
accessControl.WhiteHostName = params.WhiteHostName
accessControl.ClientIPFlowLimit = params.ClientIPFlowLimit
accessControl.ServiceFlowLimit = params.ServiceFlowLimit
if err := accessControl.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2006, err)
return
}
tx.Commit()
middleware.ResponseSuccess(c, "")
return
}
// ServiceAddHttp godoc
// @Summary grpc服务添加
// @Description grpc服务添加
// @Tags 服务管理
// @ID /service/service_add_grpc
// @Accept json
// @Produce json
// @Param body body dto.ServiceAddGrpcInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /service/service_add_grpc [post]
func (admin *ServiceController) ServiceAddGrpc(c *gin.Context) {
params := &dto.ServiceAddGrpcInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
//验证 service_name 是否被占用
infoSearch := &dao.ServiceInfo{
ServiceName: params.ServiceName,
IsDelete: 0,
}
if _, err := infoSearch.Find(c, lib.GORMDefaultPool, infoSearch); err == nil {
middleware.ResponseError(c, 2002, errors.New("服务名被占用,请重新输入"))
return
}
//验证端口是否被占用?
tcpRuleSearch := &dao.TcpRule{
Port: params.Port,
}
if _, err := tcpRuleSearch.Find(c, lib.GORMDefaultPool, tcpRuleSearch); err == nil {
middleware.ResponseError(c, 2003, errors.New("服务端口被占用,请重新输入"))
return
}
grpcRuleSearch := &dao.GrpcRule{
Port: params.Port,
}
if _, err := grpcRuleSearch.Find(c, lib.GORMDefaultPool, grpcRuleSearch); err == nil {
middleware.ResponseError(c, 2004, errors.New("服务端口被占用,请重新输入"))
return
}
//ip与权重数量一致
if len(strings.Split(params.IpList, ",")) != len(strings.Split(params.WeightList, ",")) {
middleware.ResponseError(c, 2005, errors.New("ip列表与权重设置不匹配"))
return
}
tx := lib.GORMDefaultPool.Begin()
info := &dao.ServiceInfo{
LoadType: public.LoadTypeGRPC,
ServiceName: params.ServiceName,
ServiceDesc: params.ServiceDesc,
}
if err := info.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2006, err)
return
}
loadBalance := &dao.LoadBalance{
ServiceID: info.ID,
RoundType: params.RoundType,
IpList: params.IpList,
WeightList: params.WeightList,
ForbidList: params.ForbidList,
}
if err := loadBalance.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2007, err)
return
}
grpcRule := &dao.GrpcRule{
ServiceID: info.ID,
Port: params.Port,
HeaderTransfor: params.HeaderTransfor,
}
if err := grpcRule.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2008, err)
return
}
accessControl := &dao.AccessControl{
ServiceID: info.ID,
OpenAuth: params.OpenAuth,
BlackList: params.BlackList,
WhiteList: params.WhiteList,
WhiteHostName: params.WhiteHostName,
ClientIPFlowLimit: params.ClientIPFlowLimit,
ServiceFlowLimit: params.ServiceFlowLimit,
}
if err := accessControl.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2009, err)
return
}
tx.Commit()
middleware.ResponseSuccess(c, "")
return
}
// ServiceUpdateTcp godoc
// @Summary grpc服务更新
// @Description grpc服务更新
// @Tags 服务管理
// @ID /service/service_update_grpc
// @Accept json
// @Produce json
// @Param body body dto.ServiceUpdateGrpcInput true "body"
// @Success 200 {object} middleware.Response{data=string} "success"
// @Router /service/service_update_grpc [post]
func (admin *ServiceController) ServiceUpdateGrpc(c *gin.Context) {
params := &dto.ServiceUpdateGrpcInput{}
if err := params.GetValidParams(c); err != nil {
middleware.ResponseError(c, 2001, err)
return
}
//ip与权重数量一致
if len(strings.Split(params.IpList, ",")) != len(strings.Split(params.WeightList, ",")) {
middleware.ResponseError(c, 2002, errors.New("ip列表与权重设置不匹配"))
return
}
tx := lib.GORMDefaultPool.Begin()
service := &dao.ServiceInfo{
ID: params.ID,
}
detail, err := service.ServiceDetail(c, lib.GORMDefaultPool, service)
if err != nil {
middleware.ResponseError(c, 2003, err)
return
}
info := detail.Info
info.ServiceDesc = params.ServiceDesc
if err := info.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2004, err)
return
}
loadBalance := &dao.LoadBalance{}
if detail.LoadBalance != nil {
loadBalance = detail.LoadBalance
}
loadBalance.ServiceID = info.ID
loadBalance.RoundType = params.RoundType
loadBalance.IpList = params.IpList
loadBalance.WeightList = params.WeightList
loadBalance.ForbidList = params.ForbidList
if err := loadBalance.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2005, err)
return
}
grpcRule := &dao.GrpcRule{}
if detail.GRPCRule != nil {
grpcRule = detail.GRPCRule
}
grpcRule.ServiceID = info.ID
//grpcRule.Port = params.Port
grpcRule.HeaderTransfor = params.HeaderTransfor
if err := grpcRule.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2006, err)
return
}
accessControl := &dao.AccessControl{}
if detail.AccessControl != nil {
accessControl = detail.AccessControl
}
accessControl.ServiceID = info.ID
accessControl.OpenAuth = params.OpenAuth
accessControl.BlackList = params.BlackList
accessControl.WhiteList = params.WhiteList
accessControl.WhiteHostName = params.WhiteHostName
accessControl.ClientIPFlowLimit = params.ClientIPFlowLimit
accessControl.ServiceFlowLimit = params.ServiceFlowLimit
if err := accessControl.Save(c, tx); err != nil {
tx.Rollback()
middleware.ResponseError(c, 2007, err)
return
}
tx.Commit()
middleware.ResponseSuccess(c, "")
return
}
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
package dto
import (
"ichunt-micro/public"
"github.com/gin-gonic/gin"
)
func (param *ServiceUpdateHTTPInput) BindValidParam(c *gin.Context) error {
return public.DefaultGetValidParams(c, param)
}
type ServiceUpdateHTTPInput struct {
ID int64 `json:"id" form:"id" comment:"服务ID" example:"62" validate:"required,min=1"` //服务ID
ServiceName string `json:"service_name" form:"service_name" comment:"服务名" example:"test_http_service_indb" validate:"required,valid_service_name"` //服务名
ServiceDesc string `json:"service_desc" form:"service_desc" comment:"服务描述" example:"test_http_service_indb" validate:"required,max=255,min=1"` //服务描述
RuleType int `json:"rule_type" form:"rule_type" comment:"接入类型" example:"" validate:"max=1,min=0"` //接入类型
Rule string `json:"rule" form:"rule" comment:"接入路径:域名或者前缀" example:"/test_http_service_indb" validate:"required,valid_rule"` //域名或者前缀
NeedHttps int `json:"need_https" form:"need_https" comment:"支持https" example:"" validate:"max=1,min=0"` //支持https
NeedStripUri int `json:"need_strip_uri" form:"need_strip_uri" comment:"启用strip_uri" example:"" validate:"max=1,min=0"` //启用strip_uri
NeedWebsocket int `json:"need_websocket" form:"need_websocket" comment:"是否支持websocket" example:"" validate:"max=1,min=0"` //是否支持websocket
UrlRewrite string `json:"url_rewrite" form:"url_rewrite" comment:"url重写功能" example:"" validate:"valid_url_rewrite"` //url重写功能
HeaderTransfor string `json:"header_transfor" form:"header_transfor" comment:"header转换" example:"" validate:"valid_header_transfor"` //header转换
OpenAuth int `json:"open_auth" form:"open_auth" comment:"是否开启权限" example:"" validate:"max=1,min=0"` //关键词
BlackList string `json:"black_list" form:"black_list" comment:"黑名单ip" example:"" validate:""` //黑名单ip
WhiteList string `json:"white_list" form:"white_list" comment:"白名单ip" example:"" validate:""` //白名单ip
ClientipFlowLimit int `json:"clientip_flow_limit" form:"clientip_flow_limit" comment:"客户端ip限流 " example:"" validate:"min=0"` //客户端ip限流
ServiceFlowLimit int `json:"service_flow_limit" form:"service_flow_limit" comment:"服务端限流" example:"" validate:"min=0"` //服务端限流
RoundType int `json:"round_type" form:"round_type" comment:"轮询方式" example:"" validate:"max=3,min=0"` //轮询方式
IpList string `json:"ip_list" form:"ip_list" comment:"ip列表" example:"127.0.0.1:80" validate:"required,valid_ipportlist"` //ip列表
WeightList string `json:"weight_list" form:"weight_list" comment:"权重列表" example:"50" validate:"required,valid_weightlist"` //权重列表
UpstreamConnectTimeout int `json:"upstream_connect_timeout" form:"upstream_connect_timeout" comment:"建立连接超时, 单位s" example:"" validate:"min=0"` //建立连接超时, 单位s
UpstreamHeaderTimeout int `json:"upstream_header_timeout" form:"upstream_header_timeout" comment:"获取header超时, 单位s" example:"" validate:"min=0"` //获取header超时, 单位s
UpstreamIdleTimeout int `json:"upstream_idle_timeout" form:"upstream_idle_timeout" comment:"链接最大空闲时间, 单位s" example:"" validate:"min=0"` //链接最大空闲时间, 单位s
UpstreamMaxIdle int `json:"upstream_max_idle" form:"upstream_max_idle" comment:"最大空闲链接数" example:"" validate:"min=0"` //最大空闲链接数
}
func (param *ServiceAddHTTPInput) BindValidParam(c *gin.Context) error {
return public.DefaultGetValidParams(c, param)
}
type ServiceAddHTTPInput struct {
ServiceName string `json:"service_name" form:"service_name" comment:"服务名" example:"" validate:"required,valid_service_name"` //服务名
ServiceDesc string `json:"service_desc" form:"service_desc" comment:"服务描述" example:"" validate:"required,max=255,min=1"` //服务描述
RuleType int `json:"rule_type" form:"rule_type" comment:"接入类型" example:"" validate:"max=1,min=0"` //接入类型
Rule string `json:"rule" form:"rule" comment:"接入路径:域名或者前缀" example:"" validate:"required,valid_rule"` //域名或者前缀
NeedHttps int `json:"need_https" form:"need_https" comment:"支持https" example:"" validate:"max=1,min=0"` //支持https
NeedStripUri int `json:"need_strip_uri" form:"need_strip_uri" comment:"启用strip_uri" example:"" validate:"max=1,min=0"` //启用strip_uri
NeedWebsocket int `json:"need_websocket" form:"need_websocket" comment:"是否支持websocket" example:"" validate:"max=1,min=0"` //是否支持websocket
UrlRewrite string `json:"url_rewrite" form:"url_rewrite" comment:"url重写功能" example:"" validate:"valid_url_rewrite"` //url重写功能
HeaderTransfor string `json:"header_transfor" form:"header_transfor" comment:"header转换" example:"" validate:"valid_header_transfor"` //header转换
OpenAuth int `json:"open_auth" form:"open_auth" comment:"是否开启权限" example:"" validate:"max=1,min=0"` //关键词
BlackList string `json:"black_list" form:"black_list" comment:"黑名单ip" example:"" validate:""` //黑名单ip
WhiteList string `json:"white_list" form:"white_list" comment:"白名单ip" example:"" validate:""` //白名单ip
ClientipFlowLimit int `json:"clientip_flow_limit" form:"clientip_flow_limit" comment:"客户端ip限流 " example:"" validate:"min=0"` //客户端ip限流
ServiceFlowLimit int `json:"service_flow_limit" form:"service_flow_limit" comment:"服务端限流" example:"" validate:"min=0"` //服务端限流
RoundType int `json:"round_type" form:"round_type" comment:"轮询方式" example:"" validate:"max=3,min=0"` //轮询方式
IpList string `json:"ip_list" form:"ip_list" comment:"ip列表" example:"" validate:"required,valid_ipportlist"` //ip列表
WeightList string `json:"weight_list" form:"weight_list" comment:"权重列表" example:"" validate:"required,valid_weightlist"` //权重列表
UpstreamConnectTimeout int `json:"upstream_connect_timeout" form:"upstream_connect_timeout" comment:"建立连接超时, 单位s" example:"" validate:"min=0"` //建立连接超时, 单位s
UpstreamHeaderTimeout int `json:"upstream_header_timeout" form:"upstream_header_timeout" comment:"获取header超时, 单位s" example:"" validate:"min=0"` //获取header超时, 单位s
UpstreamIdleTimeout int `json:"upstream_idle_timeout" form:"upstream_idle_timeout" comment:"链接最大空闲时间, 单位s" example:"" validate:"min=0"` //链接最大空闲时间, 单位s
UpstreamMaxIdle int `json:"upstream_max_idle" form:"upstream_max_idle" comment:"最大空闲链接数" example:"" validate:"min=0"` //最大空闲链接数
}
type ServiceDeleteInput struct {
ID int64 `json:"id" form:"id" comment:"服务ID" example:"56" validate:"required"` //服务ID
}
func (param *ServiceDeleteInput) BindValidParam(c *gin.Context) error {
return public.DefaultGetValidParams(c, param)
}
type ServiceListInput struct {
Info string `json:"info" form:"info" comment:"关键词" example:"" validate:""` //关键词
PageNo int `json:"page_no" form:"page_no" comment:"页数" example:"1" validate:"required"` //页数
PageSize int `json:"page_size" form:"page_size" comment:"每页条数" example:"20" validate:"required"` //每页条数
}
func (param *ServiceListInput) BindValidParam(c *gin.Context) error {
return public.DefaultGetValidParams(c, param)
}
type ServiceListItemOutput struct {
ID int64 `json:"id" form:"id"` //id
ServiceName string `json:"service_name" form:"service_name"` //服务名称
ServiceDesc string `json:"service_desc" form:"service_desc"` //服务描述
LoadType int `json:"load_type" form:"load_type"` //类型
ServiceAddr string `json:"service_addr" form:"service_addr"` //服务地址
Qps int64 `json:"qps" form:"qps"` //qps
Qpd int64 `json:"qpd" form:"qpd"` //qpd
TotalNode int `json:"total_node" form:"total_node"` //节点数
}
type ServiceListOutput struct {
Total int64 `json:"total" form:"total" comment:"总数" example:"" validate:""` //总数
List []ServiceListItemOutput `json:"list" form:"list" comment:"列表" example:"" validate:""` //列表
}
type ServiceStatOutput struct {
Today []int64 `json:"today" form:"today" comment:"今日流量" example:"" validate:""` //列表
Yesterday []int64 `json:"yesterday" form:"yesterday" comment:"昨日流量" example:"" validate:""` //列表
}
type ServiceAddGrpcInput struct {
ServiceName string `json:"service_name" form:"service_name" comment:"服务名称" validate:"required,valid_service_name"`
ServiceDesc string `json:"service_desc" form:"service_desc" comment:"服务描述" validate:"required"`
Port int `json:"port" form:"port" comment:"端口,需要设置8001-8999范围内" validate:"required,min=8001,max=8999"`
HeaderTransfor string `json:"header_transfor" form:"header_transfor" comment:"metadata转换" validate:"valid_header_transfor"`
OpenAuth int `json:"open_auth" form:"open_auth" comment:"是否开启权限验证" validate:""`
BlackList string `json:"black_list" form:"black_list" comment:"黑名单IP,以逗号间隔,白名单优先级高于黑名单" validate:"valid_iplist"`
WhiteList string `json:"white_list" form:"white_list" comment:"白名单IP,以逗号间隔,白名单优先级高于黑名单" validate:"valid_iplist"`
WhiteHostName string `json:"white_host_name" form:"white_host_name" comment:"白名单主机,以逗号间隔" validate:"valid_iplist"`
ClientIPFlowLimit int `json:"clientip_flow_limit" form:"clientip_flow_limit" comment:"客户端IP限流" validate:""`
ServiceFlowLimit int `json:"service_flow_limit" form:"service_flow_limit" comment:"服务端限流" validate:""`
RoundType int `json:"round_type" form:"round_type" comment:"轮询策略" validate:""`
IpList string `json:"ip_list" form:"ip_list" comment:"IP列表" validate:"required,valid_ipportlist"`
WeightList string `json:"weight_list" form:"weight_list" comment:"权重列表" validate:"required,valid_weightlist"`
ForbidList string `json:"forbid_list" form:"forbid_list" comment:"禁用IP列表" validate:"valid_iplist"`
}
func (params *ServiceAddGrpcInput) GetValidParams(c *gin.Context) error {
return public.DefaultGetValidParams(c, params)
}
type ServiceUpdateGrpcInput struct {
ID int64 `json:"id" form:"id" comment:"服务ID" validate:"required"`
ServiceName string `json:"service_name" form:"service_name" comment:"服务名称" validate:"required,valid_service_name"`
ServiceDesc string `json:"service_desc" form:"service_desc" comment:"服务描述" validate:"required"`
Port int `json:"port" form:"port" comment:"端口,需要设置8001-8999范围内" validate:"required,min=8001,max=8999"`
HeaderTransfor string `json:"header_transfor" form:"header_transfor" comment:"metadata转换" validate:"valid_header_transfor"`
OpenAuth int `json:"open_auth" form:"open_auth" comment:"是否开启权限验证" validate:""`
BlackList string `json:"black_list" form:"black_list" comment:"黑名单IP,以逗号间隔,白名单优先级高于黑名单" validate:"valid_iplist"`
WhiteList string `json:"white_list" form:"white_list" comment:"白名单IP,以逗号间隔,白名单优先级高于黑名单" validate:"valid_iplist"`
WhiteHostName string `json:"white_host_name" form:"white_host_name" comment:"白名单主机,以逗号间隔" validate:"valid_iplist"`
ClientIPFlowLimit int `json:"clientip_flow_limit" form:"clientip_flow_limit" comment:"客户端IP限流" validate:""`
ServiceFlowLimit int `json:"service_flow_limit" form:"service_flow_limit" comment:"服务端限流" validate:""`
RoundType int `json:"round_type" form:"round_type" comment:"轮询策略" validate:""`
IpList string `json:"ip_list" form:"ip_list" comment:"IP列表" validate:"required,valid_ipportlist"`
WeightList string `json:"weight_list" form:"weight_list" comment:"权重列表" validate:"required,valid_weightlist"`
ForbidList string `json:"forbid_list" form:"forbid_list" comment:"禁用IP列表" validate:"valid_iplist"`
}
func (params *ServiceUpdateGrpcInput) GetValidParams(c *gin.Context) error {
return public.DefaultGetValidParams(c, params)
}
type ServiceAddTcpInput struct {
ServiceName string `json:"service_name" form:"service_name" comment:"服务名称" validate:"required,valid_service_name"`
ServiceDesc string `json:"service_desc" form:"service_desc" comment:"服务描述" validate:"required"`
Port int `json:"port" form:"port" comment:"端口,需要设置8001-8999范围内" validate:"required,min=8001,max=8999"`
HeaderTransfor string `json:"header_transfor" form:"header_transfor" comment:"header头转换" validate:"
"`
OpenAuth int `json:"open_auth" form:"open_auth" comment:"是否开启权限验证" validate:""`
BlackList string `json:"black_list" form:"black_list" comment:"黑名单IP,以逗号间隔,白名单优先级高于黑名单" validate:"valid_iplist"`
WhiteList string `json:"white_list" form:"white_list" comment:"白名单IP,以逗号间隔,白名单优先级高于黑名单" validate:"valid_iplist"`
WhiteHostName string `json:"white_host_name" form:"white_host_name" comment:"白名单主机,以逗号间隔" validate:"valid_iplist"`
ClientIPFlowLimit int `json:"clientip_flow_limit" form:"clientip_flow_limit" comment:"客户端IP限流" validate:""`
ServiceFlowLimit int `json:"service_flow_limit" form:"service_flow_limit" comment:"服务端限流" validate:""`
RoundType int `json:"round_type" form:"round_type" comment:"轮询策略" validate:""`
IpList string `json:"ip_list" form:"ip_list" comment:"IP列表" validate:"required,valid_ipportlist"`
WeightList string `json:"weight_list" form:"weight_list" comment:"权重列表" validate:"required,valid_weightlist"`
ForbidList string `json:"forbid_list" form:"forbid_list" comment:"禁用IP列表" validate:"valid_iplist"`
}
func (params *ServiceAddTcpInput) GetValidParams(c *gin.Context) error {
return public.DefaultGetValidParams(c, params)
}
type ServiceUpdateTcpInput struct {
ID int64 `json:"id" form:"id" comment:"服务ID" validate:"required"`
ServiceName string `json:"service_name" form:"service_name" comment:"服务名称" validate:"required,valid_service_name"`
ServiceDesc string `json:"service_desc" form:"service_desc" comment:"服务描述" validate:"required"`
Port int `json:"port" form:"port" comment:"端口,需要设置8001-8999范围内" validate:"required,min=8001,max=8999"`
OpenAuth int `json:"open_auth" form:"open_auth" comment:"是否开启权限验证" validate:""`
BlackList string `json:"black_list" form:"black_list" comment:"黑名单IP,以逗号间隔,白名单优先级高于黑名单" validate:"valid_iplist"`
WhiteList string `json:"white_list" form:"white_list" comment:"白名单IP,以逗号间隔,白名单优先级高于黑名单" validate:"valid_iplist"`
WhiteHostName string `json:"white_host_name" form:"white_host_name" comment:"白名单主机,以逗号间隔" validate:"valid_iplist"`
ClientIPFlowLimit int `json:"clientip_flow_limit" form:"clientip_flow_limit" comment:"客户端IP限流" validate:""`
ServiceFlowLimit int `json:"service_flow_limit" form:"service_flow_limit" comment:"服务端限流" validate:""`
RoundType int `json:"round_type" form:"round_type" comment:"轮询策略" validate:""`
IpList string `json:"ip_list" form:"ip_list" comment:"IP列表" validate:"required,valid_ipportlist"`
WeightList string `json:"weight_list" form:"weight_list" comment:"权重列表" validate:"required,valid_weightlist"`
ForbidList string `json:"forbid_list" form:"forbid_list" comment:"禁用IP列表" validate:"valid_iplist"`
}
func (params *ServiceUpdateTcpInput) GetValidParams(c *gin.Context) error {
return public.DefaultGetValidParams(c, params)
}
......@@ -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
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.25+incompatible h1:0GQEw6h3YnuOVdtwygkIfJ+Omx0tZ8/QkVyXI4LkbeY=
github.com/coreos/etcd v3.3.25+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/e421083458/go_gateway v0.0.0-20200620084504-d602eb8bc883 h1:KDff/I19pvGg3ydEhrm9HDg+ZDKx50mfV7hLPXyWxBc=
github.com/e421083458/go_gateway v0.0.0-20200620084504-d602eb8bc883/go.mod h1:lKtoF6+E628dTHByfLIH7JS68+EgXwYkLxSbsnbhf8A=
github.com/e421083458/gorm v1.0.1 h1:xP3phpVGFa/HUXFK/9UlvVohvrDFdhTZF12XKK+1tJQ=
github.com/e421083458/gorm v1.0.1/go.mod h1:fKRc3akGVO0fLrVXYIVFtIrDniw2IASHwTJNnffphJg=
github.com/e421083458/grpc-proxy v0.2.0/go.mod h1:9/MdR/QZY8COiGUgRUEv7O4QBeRpXEjSPQEd8yuFPzk=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=
github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg=
github.com/gin-gonic/contrib v0.0.0-20201005132743-ca038bbf2944 h1:CUXsTZuAAdpQinpKgInZqKTOfn/jkIA9DLnozeybVRQ=
github.com/gin-gonic/contrib v0.0.0-20201005132743-ca038bbf2944/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg=
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
......@@ -33,79 +123,311 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U=
github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI=
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY=
github.com/syyongx/php2go v0.9.4 h1:qUtETTHzqHzxZK8plkbkb0YawD8bpLpxNsbzHQmb22Y=
github.com/syyongx/php2go v0.9.4/go.mod h1:meN2eIhhUoxOd2nMxbpe8g6cFPXI5O9/UAAuz7oDdzw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d h1:92D1fum1bJLKSdr11OJ+54YeCMCGYIygTA7R/YZxH5M=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
......@@ -121,11 +443,27 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
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 (
"bytes"
"crypto/md5"
"encoding/binary"
"encoding/hex"
"fmt"
dlog "ichunt-micro/golang_common/log"
"io/ioutil"
"log"
"math/rand"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
)
var TimeLocation *time.Location
var TimeFormat = "2006-01-02 15:04:05"
var DateFormat = "2006-01-02"
var LocalIP = net.ParseIP("127.0.0.1")
//函数传入配置文件 InitModule("./conf/dev/")
func InitModule(configPath string) error {
return initModule(configPath, []string{"base", "mysql", "redis"})
}
func initModule(configPath string, modules []string) error {
if configPath == "" {
fmt.Println("input config file like ./conf/dev/")
os.Exit(1)
}
log.Println("------------------------------------------------------------------------")
log.Printf("[INFO] config=%s\n", configPath)
log.Printf("[INFO] %s\n", " start loading resources.")
// 设置ip信息,优先设置便于日志打印
ips := GetLocalIPs()
if len(ips) > 0 {
LocalIP = ips[0]
}
// 解析配置文件目录
if err := ParseConfPath(configPath); err != nil {
return err
}
//初始化配置文件
if err := InitViperConf(); err != nil {
return err
}
// 加载base配置
if InArrayString("base", modules) {
if err := InitBaseConf(GetConfPath("base")); err != nil {
fmt.Printf("[ERROR] %s%s\n", time.Now().Format(TimeFormat), " InitBaseConf:"+err.Error())
}
}
// 加载redis配置
if InArrayString("redis", modules) {
if err := InitRedisConf(GetConfPath("redis_map")); err != nil {
fmt.Printf("[ERROR] %s%s\n", time.Now().Format(TimeFormat), " InitRedisConf:"+err.Error())
}
}
// 加载mysql配置并初始化实例
if InArrayString("mysql", modules) {
if err := InitDBPool(GetConfPath("mysql_map")); err != nil {
fmt.Printf("[ERROR] %s%s\n", time.Now().Format(TimeFormat), " InitDBPool:"+err.Error())
}
}
// 设置时区
if location, err := time.LoadLocation(ConfBase.TimeLocation); err != nil {
return err
} else {
TimeLocation = location
}
log.Printf("[INFO] %s\n", " success loading resources.")
log.Println("------------------------------------------------------------------------")
return nil
}
//公共销毁函数
func Destroy() {
log.Println("------------------------------------------------------------------------")
log.Printf("[INFO] %s\n", " start destroy resources.")
CloseDB()
dlog.Close()
log.Printf("[INFO] %s\n", " success destroy resources.")
}
func HttpGET(trace *TraceContext, urlString string, urlParams url.Values, msTimeout int, header http.Header) (*http.Response, []byte, error) {
startTime := time.Now().UnixNano()
client := http.Client{
Timeout: time.Duration(msTimeout) * time.Millisecond,
}
urlString = AddGetDataToUrl(urlString, urlParams)
req, err := http.NewRequest("GET", urlString, nil)
if err != nil {
Log.TagWarn(trace, DLTagHTTPFailed, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "GET",
"args": urlParams,
"err": err.Error(),
})
return nil, nil, err
}
if len(header) > 0 {
req.Header = header
}
req = addTrace2Header(req, trace)
resp, err := client.Do(req)
if err != nil {
Log.TagWarn(trace, DLTagHTTPFailed, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "GET",
"args": urlParams,
"err": err.Error(),
})
return nil, nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
Log.TagWarn(trace, DLTagHTTPFailed, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "GET",
"args": urlParams,
"result": Substr(string(body), 0, 1024),
"err": err.Error(),
})
return nil, nil, err
}
Log.TagInfo(trace, DLTagHTTPSuccess, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "GET",
"args": urlParams,
"result": Substr(string(body), 0, 1024),
})
return resp, body, nil
}
func HttpPOST(trace *TraceContext, urlString string, urlParams url.Values, msTimeout int, header http.Header, contextType string) (*http.Response, []byte, error) {
startTime := time.Now().UnixNano()
client := http.Client{
Timeout: time.Duration(msTimeout) * time.Millisecond,
}
if contextType == "" {
contextType = "application/x-www-form-urlencoded"
}
urlParamEncode := urlParams.Encode()
req, err := http.NewRequest("POST", urlString, strings.NewReader(urlParamEncode))
if len(header) > 0 {
req.Header = header
}
req = addTrace2Header(req, trace)
req.Header.Set("Content-Type", contextType)
resp, err := client.Do(req)
if err != nil {
Log.TagWarn(trace, DLTagHTTPFailed, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "POST",
"args": Substr(urlParamEncode, 0, 1024),
"err": err.Error(),
})
return nil, nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
Log.TagWarn(trace, DLTagHTTPFailed, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "POST",
"args": Substr(urlParamEncode, 0, 1024),
"result": Substr(string(body), 0, 1024),
"err": err.Error(),
})
return nil, nil, err
}
Log.TagInfo(trace, DLTagHTTPSuccess, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "POST",
"args": Substr(urlParamEncode, 0, 1024),
"result": Substr(string(body), 0, 1024),
})
return resp, body, nil
}
func HttpJSON(trace *TraceContext, urlString string, jsonContent string, msTimeout int, header http.Header) (*http.Response, []byte, error) {
startTime := time.Now().UnixNano()
client := http.Client{
Timeout: time.Duration(msTimeout) * time.Millisecond,
}
req, err := http.NewRequest("POST", urlString, strings.NewReader(jsonContent))
if len(header) > 0 {
req.Header = header
}
req = addTrace2Header(req, trace)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
Log.TagWarn(trace, DLTagHTTPFailed, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "POST",
"args": Substr(jsonContent, 0, 1024),
"err": err.Error(),
})
return nil, nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
Log.TagWarn(trace, DLTagHTTPFailed, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "POST",
"args": Substr(jsonContent, 0, 1024),
"result": Substr(string(body), 0, 1024),
"err": err.Error(),
})
return nil, nil, err
}
Log.TagInfo(trace, DLTagHTTPSuccess, map[string]interface{}{
"url": urlString,
"proc_time": float32(time.Now().UnixNano()-startTime) / 1.0e9,
"method": "POST",
"args": Substr(jsonContent, 0, 1024),
"result": Substr(string(body), 0, 1024),
})
return resp, body, nil
}
func AddGetDataToUrl(urlString string, data url.Values) string {
if strings.Contains(urlString, "?") {
urlString = urlString + "&"
} else {
urlString = urlString + "?"
}
return fmt.Sprintf("%s%s", urlString, data.Encode())
}
func addTrace2Header(request *http.Request, trace *TraceContext) *http.Request {
traceId := trace.TraceId
cSpanId := NewSpanId()
if traceId != "" {
request.Header.Set("didi-header-rid", traceId)
}
if cSpanId != "" {
request.Header.Set("didi-header-spanid", cSpanId)
}
trace.CSpanId = cSpanId
return request
}
func GetMd5Hash(text string) string {
hasher := md5.New()
hasher.Write([]byte(text))
return hex.EncodeToString(hasher.Sum(nil))
}
func Encode(data string) (string, error) {
h := md5.New()
_, err := h.Write([]byte(data))
if err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}
func ParseServerAddr(serverAddr string) (host, port string) {
serverInfo := strings.Split(serverAddr, ":")
if len(serverInfo) == 2 {
host = serverInfo[0]
port = serverInfo[1]
} else {
host = serverAddr
port = ""
}
return host, port
}
func NewTrace() *TraceContext {
trace := &TraceContext{}
trace.TraceId = GetTraceId()
trace.SpanId = NewSpanId()
return trace
}
func NewSpanId() string {
timestamp := uint32(time.Now().Unix())
ipToLong := binary.BigEndian.Uint32(LocalIP.To4())
b := bytes.Buffer{}
b.WriteString(fmt.Sprintf("%08x", ipToLong^timestamp))
b.WriteString(fmt.Sprintf("%08x", rand.Int31()))
return b.String()
}
func GetTraceId() (traceId string) {
return calcTraceId(LocalIP.String())
}
func calcTraceId(ip string) (traceId string) {
now := time.Now()
timestamp := uint32(now.Unix())
timeNano := now.UnixNano()
pid := os.Getpid()
b := bytes.Buffer{}
netIP := net.ParseIP(ip)
if netIP == nil {
b.WriteString("00000000")
} else {
b.WriteString(hex.EncodeToString(netIP.To4()))
}
b.WriteString(fmt.Sprintf("%08x", timestamp&0xffffffff))
b.WriteString(fmt.Sprintf("%04x", timeNano&0xffff))
b.WriteString(fmt.Sprintf("%04x", pid&0xffff))
b.WriteString(fmt.Sprintf("%06x", rand.Int31n(1<<24)))
b.WriteString("b0") // 末两位标记来源,b0为go
return b.String()
}
func GetLocalIPs() (ips []net.IP) {
interfaceAddr, err := net.InterfaceAddrs()
if err != nil {
return nil
}
for _, address := range interfaceAddr {
ipNet, isValidIpNet := address.(*net.IPNet)
if isValidIpNet && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
ips = append(ips, ipNet.IP)
}
}
}
return ips
}
func InArrayString(s string, arr []string) bool {
for _, i := range arr {
if i == s {
return true
}
}
return false
}
//Substr 字符串的截取
func Substr(str string, start int64, end int64) string {
length := int64(len(str))
if start < 0 || start > length {
return ""
}
if end < 0 {
return ""
}
if end > length {
end = length
}
return string(str[start:end])
}
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.
[ERROR][2020-11-04T14:21:31.578][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:21:32.412][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:21:32.412][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:21:33.077][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:22:39.001][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:27:40.554][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:28:47.317][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:31:36.110][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:32:18.509][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:32.209][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:44.013][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:51.124][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:51.124][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:52.475][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:52.475][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:52.475][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:53.157][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:53.157][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:35:53.157][http_access_mode.go:18] not matched service
[ERROR][2020-11-04T14:36:48.273][http_access_mode.go:17] not matched service
[ERROR][2020-11-04T15:09:21.629][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/ichunt_http_api/test
[ERROR][2020-11-04T15:09:23.249][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/ichunt_http_api/test
[ERROR][2020-11-04T15:09:23.249][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/ichunt_http_api/test
[ERROR][2020-11-04T15:09:23.249][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/ichunt_http_api/test
[ERROR][2020-11-04T15:09:23.249][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/ichunt_http_api/test
[ERROR][2020-11-04T15:09:24.153][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/ichunt_http_api/test
[ERROR][2020-11-04T15:09:24.153][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/ichunt_http_api/test
[ERROR][2020-11-04T15:32:30.624][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:32:31.836][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:32:32.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:32:32.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:32:32.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:32:32.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:32:32.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:32:32.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:33:17.048][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:33:17.048][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:33:18.302][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:33:18.302][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-04T15:33:18.302][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/comment_service/test
[ERROR][2020-11-05T15:12:33.393][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:37.553][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:38.169][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:38.169][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:38.169][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:39.231][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:39.231][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:39.231][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:39.231][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:40.109][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:40.109][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:40.109][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:40.109][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:40.109][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:41.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:41.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:41.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:41.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:41.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:42.145][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:12:42.145][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:10.063][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:10.063][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:11.417][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:12.135][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:12.135][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:13.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:13.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:13.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:13.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:13.064][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:14.076][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:14.076][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:14.076][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:14.076][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:14.076][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:15.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:15.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:15.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:15.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:15.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:16.016][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:16.016][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:16.016][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:16.016][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:16.016][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:17.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:17.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:17.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:17.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:15:17.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:14.049][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:14.049][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:14.049][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:16.583][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:16.583][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:17.351][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:38.825][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:39.151][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:39.151][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:39.151][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:39.151][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:40.142][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:40.142][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:40.142][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:40.142][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:41.078][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:41.078][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:41.078][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:41.078][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:42.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:42.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:42.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:43.231][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:43.231][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:44.062][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:44.062][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:44.062][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:45.238][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:45.238][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:45.238][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:46.174][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:46.174][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:46.174][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:46.174][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:47.198][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:47.198][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:47.198][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:47.198][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:48.175][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:48.175][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:48.175][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:48.175][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:49.183][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:49.183][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:49.183][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:49.183][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:22:50.078][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:01.496][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:02.182][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:02.182][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:03.158][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:03.158][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:03.158][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:04.015][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:04.015][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:04.015][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:04.015][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:05.024][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:05.024][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:05.024][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:05.024][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:05.024][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:06.150][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:06.150][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:06.150][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:06.150][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:07.041][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:07.041][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:07.041][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:23:07.041][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:26:47.163][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T15:44:00.646][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T16:04:39.181][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T16:04:50.404][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T16:05:41.155][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T16:05:59.827][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T16:59:08.281][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T16:59:10.511][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:54.701][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:54.701][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:55.047][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:55.047][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:55.047][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:55.047][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:55.047][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:55.047][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:56.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:56.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:56.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:56.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:56.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:56.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:57.022][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:57.022][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:57.022][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:57.022][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:57.022][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:58.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:58.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:58.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:58.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:58.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:58.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:59.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:59.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:59.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:59.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:59.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:01:59.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:00.100][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:00.100][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:00.100][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:00.100][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:00.100][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:01.000][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:01.000][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:01.000][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:01.000][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:01.000][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:01.000][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:02.068][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:02.068][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:02.068][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:02.068][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:03.001][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:03.001][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:03.001][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:03.001][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:03.001][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:03.001][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:04.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:04.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:04.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:04.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:04.044][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:05.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:05.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:05.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:05.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:05.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:05.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:06.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:06.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:06.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:06.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:06.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:07.112][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:08.581][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:08.581][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:08.581][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:09.140][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:09.140][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:09.140][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:09.140][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:09.140][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:10.101][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:10.101][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:10.101][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:10.101][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:10.101][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:11.020][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:11.020][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:11.020][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:11.020][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:11.020][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:11.020][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:12.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:12.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:12.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:12.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:12.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:13.133][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:13.133][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:13.133][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:13.133][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:02:58.774][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:07.119][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:10.186][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:13.265][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:16.136][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:18.813][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:22.249][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:28.196][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:32.146][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:03:34.036][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:25.701][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:26.882][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:32.108][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:33.134][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:34.068][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:35.781][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:38.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:39.702][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:41.479][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:44.097][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:44.097][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:46.087][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:46.087][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:47.097][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:49.144][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:50.143][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:51.090][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:52.003][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:52.003][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:53.058][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:54.575][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:56.101][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:04:56.101][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:05:50.881][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/test
[ERROR][2020-11-05T17:05:51.553][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:20.183][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,//comment_service/tst
[ERROR][2020-11-05T17:06:20.183][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:24.270][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,//comment_service/test
[ERROR][2020-11-05T17:06:24.270][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:27.933][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,//comment_service/test
[ERROR][2020-11-05T17:06:27.933][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:32.612][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:38.960][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:41.221][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:44.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:44.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:45.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:47.096][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:48.095][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:49.099][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:49.099][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:51.102][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:06:51.102][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:07:02.487][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:07:03.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:07:03.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:07:03.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:19.698][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:20.828][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:21.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:21.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:21.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:21.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:21.027][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:22.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:22.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:22.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:22.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:22.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:27:22.012][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:36.198][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:39.556][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:39.556][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:40.308][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:40.308][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:40.308][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:41.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:41.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:41.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:41.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:41.148][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:42.108][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:42.108][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:42.108][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:42.108][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:42.108][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:43.028][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:43.028][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:43.028][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:43.028][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:43.028][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:43.028][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:44.159][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:44.159][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:44.159][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:50:44.159][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:39.333][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:40.100][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:40.100][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:40.100][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:41.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:41.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:41.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:41.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:41.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:41.004][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:42.085][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:42.085][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:42.085][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:42.085][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:58.829][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:59.443][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:59.443][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:51:59.443][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:00.053][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:00.053][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:00.053][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:00.053][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:00.053][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:01.007][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:01.007][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:01.007][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:11.293][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:11.293][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:11.293][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:11.293][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:12.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:12.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:12.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:12.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:12.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:12.008][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:35.317][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:35.317][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
[ERROR][2020-11-05T17:52:36.190][http_access_mode.go:15] 没有匹配的服务 192.168.2.246,/favicon.ico
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))
}
package middleware
import (
"errors"
"ichunt-micro/public"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
)
func SessionAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
session := sessions.Default(c)
if adminInfo, ok := session.Get(public.AdminSessionInfoKey).(string); !ok || adminInfo == "" {
ResponseError(c, InternalErrorCode, errors.New("user not login"))
c.Abort()
return
}
c.Next()
}
}
package middleware
import (
"fmt"
"ichunt-micro/public"
"github.com/gin-gonic/gin"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
"github.com/go-playground/universal-translator"
"gopkg.in/go-playground/validator.v9"
en_translations "gopkg.in/go-playground/validator.v9/translations/en"
zh_translations "gopkg.in/go-playground/validator.v9/translations/zh"
"reflect"
"regexp"
"strings"
)
//设置Translation
func TranslationMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
//参照:https://github.com/go-playground/validator/blob/v9/_examples/translations/main.go
//设置支持语言
en := en.New()
zh := zh.New()
//设置国际化翻译器
uni := ut.New(zh, zh, en)
val := validator.New()
//根据参数取翻译器实例
locale := c.DefaultQuery("locale", "zh")
trans, _ := uni.GetTranslator(locale)
//翻译器注册到validator
switch locale {
case "en":
en_translations.RegisterDefaultTranslations(val, trans)
val.RegisterTagNameFunc(func(fld reflect.StructField) string {
return fld.Tag.Get("en_comment")
})
break
default:
zh_translations.RegisterDefaultTranslations(val, trans)
val.RegisterTagNameFunc(func(fld reflect.StructField) string {
return fld.Tag.Get("comment")
})
//自定义验证方法
//https://github.com/go-playground/validator/blob/v9/_examples/custom-validation/main.go
val.RegisterValidation("valid_username", func(fl validator.FieldLevel) bool {
return fl.Field().String() == "admin"
})
val.RegisterValidation("valid_service_name", func(fl validator.FieldLevel) bool {
matched, _ := regexp.Match(`^[a-zA-Z0-9_]{6,128}$`, []byte(fl.Field().String()))
return matched
})
val.RegisterValidation("valid_rule", func(fl validator.FieldLevel) bool {
matched, _ := regexp.Match(`^\S+$`, []byte(fl.Field().String()))
return matched
})
val.RegisterValidation("valid_url_rewrite", func(fl validator.FieldLevel) bool {
if fl.Field().String() == "" {
return true
}
for _, ms := range strings.Split(fl.Field().String(), ",") {
if len(strings.Split(ms, " ")) != 2 {
return false
}
}
return true
})
val.RegisterValidation("valid_header_transfor", func(fl validator.FieldLevel) bool {
if fl.Field().String() == "" {
return true
}
for _, ms := range strings.Split(fl.Field().String(), ",") {
if len(strings.Split(ms, " ")) != 3 {
return false
}
}
return true
})
val.RegisterValidation("valid_ipportlist", func(fl validator.FieldLevel) bool {
for _, ms := range strings.Split(fl.Field().String(), ",") {
if matched, _ := regexp.Match(`^\S+\:\d+$`, []byte(ms)); !matched {
return false
}
}
return true
})
val.RegisterValidation("valid_iplist", func(fl validator.FieldLevel) bool {
if fl.Field().String() == "" {
return true
}
for _, item := range strings.Split(fl.Field().String(), ",") {
matched, _ := regexp.Match(`\S+`, []byte(item)) //ip_addr
if !matched {
return false
}
}
return true
})
val.RegisterValidation("valid_weightlist", func(fl validator.FieldLevel) bool {
fmt.Println(fl.Field().String())
for _, ms := range strings.Split(fl.Field().String(), ",") {
if matched, _ := regexp.Match(`^\d+$`, []byte(ms)); !matched {
return false
}
}
return true
})
//自定义翻译器
//https://github.com/go-playground/validator/blob/v9/_examples/translations/main.go
val.RegisterTranslation("valid_username", trans, func(ut ut.Translator) error {
return ut.Add("valid_username", "{0} 填写不正确哦", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("valid_username", fe.Field())
return t
})
val.RegisterTranslation("valid_service_name", trans, func(ut ut.Translator) error {
return ut.Add("valid_service_name", "{0} 不符合输入格式", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("valid_service_name", fe.Field())
return t
})
val.RegisterTranslation("valid_rule", trans, func(ut ut.Translator) error {
return ut.Add("valid_rule", "{0} 必须是非空字符", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("valid_rule", fe.Field())
return t
})
val.RegisterTranslation("valid_url_rewrite", trans, func(ut ut.Translator) error {
return ut.Add("valid_url_rewrite", "{0} 不符合输入格式", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("valid_url_rewrite", fe.Field())
return t
})
val.RegisterTranslation("valid_header_transfor", trans, func(ut ut.Translator) error {
return ut.Add("valid_header_transfor", "{0} 不符合输入格式", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("valid_header_transfor", fe.Field())
return t
})
val.RegisterTranslation("valid_ipportlist", trans, func(ut ut.Translator) error {
return ut.Add("valid_ipportlist", "{0} 不符合输入格式", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("valid_ipportlist", fe.Field())
return t
})
val.RegisterTranslation("valid_iplist", trans, func(ut ut.Translator) error {
return ut.Add("valid_iplist", "{0} 不符合输入格式", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("valid_iplist", fe.Field())
return t
})
val.RegisterTranslation("valid_weightlist", trans, func(ut ut.Translator) error {
return ut.Add("valid_weightlist", "{0} 不符合输入格式", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("valid_weightlist", fe.Field())
return t
})
break
}
c.Set(public.TranslatorKey, trans)
c.Set(public.ValidatorKey, val)
c.Next()
}
}
package proxy
import (
"bytes"
"compress/gzip"
"context"
"errors"
"github.com/gin-gonic/gin"
"github.com/syyongx/php2go"
"ichunt-micro/dao"
"ichunt-micro/golang_common/log"
"ichunt-micro/middleware"
"ichunt-micro/proxy/load_balance"
"io/ioutil"
"net"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"strings"
"time"
)
var (
transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second, //连接超时
KeepAlive: 30 * time.Second, //长连接超时时间
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100, //最大空闲连接
IdleConnTimeout: 60 * time.Second, //空闲超时时间
TLSHandshakeTimeout: 10 * time.Second, //tls握手超时时间
ExpectContinueTimeout: 1 * time.Second, //100-continue状态码超时时间
}
)
func NewMultipleHostsReverseProxy(c *gin.Context) (*httputil.ReverseProxy, error) {
//请求协调者
service,exists := c.Get("service")
if !exists {
err := errors.New("get service fail")
log.Error("%s", err)
return nil,err
}
service_,ok := service.(*dao.ServiceDetail)
if !ok{
err := errors.New("get service fail")
log.Error("%s", err)
return nil,err
}
//数据库中的rule字段 前缀匹配
rule := service_.HTTPRule.Rule
rule_ := php2go.Trim(rule,"/")
nextAddr, err := load_balance.LoadBalanceConfig.GetService(context.TODO(), rule_)
if err != nil || nextAddr == "" {
err = errors.New("get next addr fail")
log.Error("%s", err)
return nil,err
}
director := func(req *http.Request) {
target, err := url.Parse("http://"+nextAddr)
if err != nil {
log.Error("func NewMultipleHostsReverseProxy 匿名函数director url.Parse地址解析失败 失败 %s",err)
}
//http://192.168.1.234:2004
targetQuery := target.RawQuery
//http
req.URL.Scheme = target.Scheme
//192.168.1.234:2004
req.URL.Host = target.Host
///comment_service/test
req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
//req.URL.Path = php2go.StrReplace(rule,"",req.URL.Path,-1)
log.Info("target %s",target)
log.Info("targetQuery %s",targetQuery)
log.Info("req.URL.Scheme %s",req.URL.Scheme)
log.Info("req.URL.Host %s",req.URL.Host)
log.Info("req.URL.Path %s",req.URL.Path)
if targetQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
}
if _, ok := req.Header["User-Agent"]; !ok {
req.Header.Set("User-Agent", "user-agent")
}
//只在第一代理中设置此header头
req.Header.Set("X-Real-Ip", req.RemoteAddr)
}
//更改内容
modifyFunc := func(resp *http.Response) error {
if strings.Contains(resp.Header.Get("Connection"), "Upgrade") {
return nil
}
var payload []byte
var readErr error
if strings.Contains(resp.Header.Get("Content-Encoding"), "gzip") {
gr, err := gzip.NewReader(resp.Body)
if err != nil {
return err
}
payload, readErr = ioutil.ReadAll(gr)
resp.Header.Del("Content-Encoding")
} else {
payload, readErr = ioutil.ReadAll(resp.Body)
}
if readErr != nil {
return readErr
}
//异常请求时设置StatusCode
if resp.StatusCode != 200 {
payload = []byte("StatusCode error:" + string(payload))
}
resp.Body = ioutil.NopCloser(bytes.NewBuffer(payload))
resp.ContentLength = int64(len(payload))
resp.Header.Set("Content-Length", strconv.FormatInt(int64(len(payload)), 10))
return nil
}
//错误回调 :关闭real_server时测试,错误回调
//范围:transport.RoundTrip发生的错误、以及ModifyResponse发生的错误
errFunc := func(w http.ResponseWriter, r *http.Request, err error) {
//todo 如果是权重的负载则调整临时权重
//http.Error(w, "ErrorHandler error:"+err.Error(), 500)
middleware.ResponseError(c,500,err)
}
return &httputil.ReverseProxy{Director: director, Transport:transport, ModifyResponse: modifyFunc, ErrorHandler: errFunc},nil
}
func singleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}
......@@ -48,6 +48,9 @@ func (s *LoadBalanceEtcdConf) Attach(o Observer) {
//更新配置时,通知监听者也更新
func (s *LoadBalanceEtcdConf) UpdateConf(serviceInfo *registry.AllServiceInfo) {
if len(serviceInfo.ServiceMap) == 0 {
return
}
s.value.Store(serviceInfo)
for _, obs := range s.observers {
obs.Update()
......@@ -73,13 +76,8 @@ func (s *LoadBalanceEtcdConf) GetService(ctx context.Context,name string)(node s
fmt.Printf("get service failed, err:%v", err)
return
}
node ,err =s.GetLoadBalance().Get(name)
//fmt.Println(node,err)
return node,err
//for _, node := range service.Nodes {
// fmt.Printf("服务名:%s, 节点::%#v\n", service.Name, node)
//}
}
......
......@@ -3,6 +3,7 @@ package load_balance
import (
"errors"
"fmt"
"log"
"strconv"
"sync"
)
......@@ -101,7 +102,7 @@ func (r *WeightRoundRobinBalance) Update() {
r.lock.Lock()
defer r.lock.Unlock()
fmt.Println("更新负载均衡配置.....")
log.Print("[INFO] 更新负载均衡配置 ")
allServiceInfo := LoadBalanceConfig.GetLoadBalanceList()
if allServiceInfo == nil || allServiceInfo.ServiceMap == nil{
return
......
package public
const (
ValidatorKey = "ValidatorKey"
TranslatorKey = "TranslatorKey"
AdminSessionInfoKey = "AdminSessionInfoKey"
LoadTypeHTTP = 0
LoadTypeTCP = 1
LoadTypeGRPC = 2
HTTPRuleTypePrefixURL = 0
HTTPRuleTypeDomain = 1
RedisFlowDayKey = "flow_day_count"
RedisFlowHourKey = "flow_hour_count"
FlowTotal = "flow_total"
FlowServicePrefix = "flow_service_"
FlowAppPrefix = "flow_app_"
JwtSignKey = "my_sign_key"
JwtExpires = 60*60
)
var (
LoadTypeMap = map[int]string{
LoadTypeHTTP: "HTTP",
LoadTypeTCP: "TCP",
LoadTypeGRPC: "GRPC",
}
)
package public
import (
"sync"
"time"
)
var FlowCounterHandler *FlowCounter
type FlowCounter struct {
RedisFlowCountMap map[string]*RedisFlowCountService
RedisFlowCountSlice []*RedisFlowCountService
Locker sync.RWMutex
}
func NewFlowCounter() *FlowCounter {
return &FlowCounter{
RedisFlowCountMap: map[string]*RedisFlowCountService{},
RedisFlowCountSlice: []*RedisFlowCountService{},
Locker: sync.RWMutex{},
}
}
func init() {
FlowCounterHandler = NewFlowCounter()
}
func (counter *FlowCounter) GetCounter(serverName string) (*RedisFlowCountService, error) {
for _, item := range counter.RedisFlowCountSlice {
if item.AppID == serverName {
return item, nil
}
}
newCounter:=NewRedisFlowCountService(serverName,1*time.Second)
counter.RedisFlowCountSlice = append(counter.RedisFlowCountSlice, newCounter)
counter.Locker.Lock()
defer counter.Locker.Unlock()
counter.RedisFlowCountMap[serverName] = newCounter
return newCounter, nil
}
package public
import (
"golang.org/x/time/rate"
"sync"
)
var FlowLimiterHandler *FlowLimiter
type FlowLimiter struct {
FlowLmiterMap map[string]*FlowLimiterItem
FlowLmiterSlice []*FlowLimiterItem
Locker sync.RWMutex
}
type FlowLimiterItem struct {
ServiceName string
Limter *rate.Limiter
}
func NewFlowLimiter() *FlowLimiter {
return &FlowLimiter{
FlowLmiterMap: map[string]*FlowLimiterItem{},
FlowLmiterSlice: []*FlowLimiterItem{},
Locker: sync.RWMutex{},
}
}
func init() {
FlowLimiterHandler = NewFlowLimiter()
}
func (counter *FlowLimiter) GetLimiter(serverName string, qps float64) (*rate.Limiter, error) {
for _, item := range counter.FlowLmiterSlice {
if item.ServiceName == serverName {
return item.Limter, nil
}
}
newLimiter := rate.NewLimiter(rate.Limit(qps), int(qps*3))
item := &FlowLimiterItem{
ServiceName: serverName,
Limter: newLimiter,
}
counter.FlowLmiterSlice = append(counter.FlowLmiterSlice, item)
counter.Locker.Lock()
defer counter.Locker.Unlock()
counter.FlowLmiterMap[serverName] = item
return newLimiter, nil
}
package public
import (
"errors"
"github.com/dgrijalva/jwt-go"
)
func JwtDecode(tokenString string) (*jwt.StandardClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(JwtSignKey), nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*jwt.StandardClaims); ok {
return claims, nil
} else {
return nil, errors.New("token is not jwt.StandardClaims")
}
}
func JwtEncode(claims jwt.StandardClaims) (string, error) {
mySigningKey := []byte(JwtSignKey)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(mySigningKey)
}
package public
import (
"context"
"ichunt-micro/golang_common/lib"
"github.com/gin-gonic/gin"
)
//错误日志
func ContextWarning(c context.Context, dltag string, m map[string]interface{}) {
v:=c.Value("trace")
traceContext,ok := v.(*lib.TraceContext)
if !ok{
traceContext = lib.NewTrace()
}
lib.Log.TagWarn(traceContext, dltag, m)
}
//错误日志
func ContextError(c context.Context, dltag string, m map[string]interface{}) {
v:=c.Value("trace")
traceContext,ok := v.(*lib.TraceContext)
if !ok{
traceContext = lib.NewTrace()
}
lib.Log.TagError(traceContext, dltag, m)
}
//普通日志
func ContextNotice(c context.Context, dltag string, m map[string]interface{}) {
v:=c.Value("trace")
traceContext,ok := v.(*lib.TraceContext)
if !ok{
traceContext = lib.NewTrace()
}
lib.Log.TagInfo(traceContext, dltag, m)
}
//错误日志
func ComLogWarning(c *gin.Context, dltag string, m map[string]interface{}) {
traceContext := GetGinTraceContext(c)
lib.Log.TagError(traceContext, dltag, m)
}
//普通日志
func ComLogNotice(c *gin.Context, dltag string, m map[string]interface{}) {
traceContext := GetGinTraceContext(c)
lib.Log.TagInfo(traceContext, dltag, m)
}
// 从gin的Context中获取数据
func GetGinTraceContext(c *gin.Context) *lib.TraceContext {
// 防御
if c == nil {
return lib.NewTrace()
}
traceContext, exists := c.Get("trace")
if exists {
if tc, ok := traceContext.(*lib.TraceContext); ok {
return tc
}
}
return lib.NewTrace()
}
// 从Context中获取数据
func GetTraceContext(c context.Context) *lib.TraceContext {
if c == nil {
return lib.NewTrace()
}
traceContext:=c.Value("trace")
if tc, ok := traceContext.(*lib.TraceContext); ok {
return tc
}
return lib.NewTrace()
}
package public
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/universal-translator"
"github.com/pkg/errors"
"gopkg.in/go-playground/validator.v9"
"strings"
)
func DefaultGetValidParams(c *gin.Context, params interface{}) error {
if err := c.ShouldBind(params); err != nil {
return err
}
//获取验证器
valid, err := GetValidator(c)
if err != nil {
return err
}
//获取翻译器
trans, err := GetTranslation(c)
if err != nil {
return err
}
err = valid.Struct(params)
if err != nil {
errs := err.(validator.ValidationErrors)
sliceErrs := []string{}
for _, e := range errs {
sliceErrs = append(sliceErrs, e.Translate(trans))
}
return errors.New(strings.Join(sliceErrs, ","))
}
return nil
}
func GetValidator(c *gin.Context) (*validator.Validate, error) {
val, ok := c.Get(ValidatorKey)
if !ok {
return nil, errors.New("未设置验证器")
}
validator, ok := val.(*validator.Validate)
if !ok {
return nil, errors.New("获取验证器失败")
}
return validator, nil
}
func GetTranslation(c *gin.Context) (ut.Translator, error) {
trans, ok := c.Get(TranslatorKey)
if !ok {
return nil, errors.New("未设置翻译器")
}
translator, ok := trans.(ut.Translator)
if !ok {
return nil, errors.New("获取翻译器失败")
}
return translator, nil
}
package public
import (
"ichunt-micro/golang_common/lib"
"github.com/garyburd/redigo/redis"
)
func RedisConfPipline(pip ...func(c redis.Conn)) error {
c, err := lib.RedisConnFactory("default")
if err != nil {
return err
}
defer c.Close()
for _, f := range pip {
f(c)
}
c.Flush()
return nil
}
func RedisConfDo(commandName string, args ...interface{}) (interface{}, error) {
c, err := lib.RedisConnFactory("default")
if err != nil {
return nil,err
}
defer c.Close()
return c.Do(commandName, args...)
}
package public
import (
"fmt"
"ichunt-micro/golang_common/lib"
"github.com/garyburd/redigo/redis"
"sync/atomic"
"time"
)
type RedisFlowCountService struct {
AppID string
Interval time.Duration
QPS int64
Unix int64
TickerCount int64
TotalCount int64
}
func NewRedisFlowCountService(appID string, interval time.Duration) *RedisFlowCountService {
reqCounter := &RedisFlowCountService{
AppID: appID,
Interval: interval,
QPS: 0,
Unix: 0,
}
go func() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
ticker := time.NewTicker(interval)
for {
<-ticker.C
tickerCount := atomic.LoadInt64(&reqCounter.TickerCount) //获取数据
atomic.StoreInt64(&reqCounter.TickerCount, 0) //重置数据
currentTime := time.Now()
dayKey := reqCounter.GetDayKey(currentTime)
hourKey := reqCounter.GetHourKey(currentTime)
if err := RedisConfPipline(func(c redis.Conn) {
c.Send("INCRBY", dayKey, tickerCount)
c.Send("EXPIRE", dayKey, 86400*2)
c.Send("INCRBY", hourKey, tickerCount)
c.Send("EXPIRE", hourKey, 86400*2)
}); err != nil {
fmt.Println("RedisConfPipline err",err)
continue
}
totalCount, err := reqCounter.GetDayData(currentTime)
if err != nil {
fmt.Println("reqCounter.GetDayData err",err)
continue
}
nowUnix := time.Now().Unix()
if reqCounter.Unix == 0 {
reqCounter.Unix = time.Now().Unix()
continue
}
tickerCount = totalCount - reqCounter.TotalCount
if nowUnix > reqCounter.Unix {
reqCounter.TotalCount = totalCount
reqCounter.QPS = tickerCount / (nowUnix - reqCounter.Unix)
reqCounter.Unix = time.Now().Unix()
}
}
}()
return reqCounter
}
func (o *RedisFlowCountService) GetDayKey(t time.Time) string {
dayStr := t.In(lib.TimeLocation).Format("20060102")
return fmt.Sprintf("%s_%s_%s", RedisFlowDayKey, dayStr, o.AppID)
}
func (o *RedisFlowCountService) GetHourKey(t time.Time) string {
hourStr := t.In(lib.TimeLocation).Format("2006010215")
return fmt.Sprintf("%s_%s_%s", RedisFlowHourKey, hourStr, o.AppID)
}
func (o *RedisFlowCountService) GetHourData(t time.Time) (int64,error) {
return redis.Int64(RedisConfDo("GET", o.GetHourKey(t)))
}
func (o *RedisFlowCountService) GetDayData(t time.Time) (int64,error) {
return redis.Int64(RedisConfDo("GET", o.GetDayKey(t)))
}
//原子增加
func (o *RedisFlowCountService) Increase() {
go func() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
atomic.AddInt64(&o.TickerCount, 1)
}()
}
package public
import (
"crypto/md5"
"crypto/sha256"
"encoding/json"
"fmt"
"io"
)
func GenSaltPassword(salt, password string) string {
s1 := sha256.New()
s1.Write([]byte(password))
str1 := fmt.Sprintf("%x", s1.Sum(nil))
s2 := sha256.New()
s2.Write([]byte(str1 + salt))
return fmt.Sprintf("%x", s2.Sum(nil))
}
//MD5 md5加密
func MD5(s string) string {
h := md5.New()
io.WriteString(h, s)
return fmt.Sprintf("%x", h.Sum(nil))
}
func Obj2Json(s interface{}) string {
bts, _ := json.Marshal(s)
return string(bts)
}
func InStringSlice(slice []string,str string) bool{
for _,item:=range slice{
if str==item{
return true
}
}
return false
}
......@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"github.com/coreos/etcd/clientv3"
"ichunt-micro/golang_common/log"
"ichunt-micro/proxy/load_balance"
"ichunt-micro/registry"
"path"
......@@ -77,13 +78,24 @@ func (e *EtcdRegistry) Init(ctx context.Context, opts ...registry.Option) (err e
opt(e.options)
}
e.client, err = clientv3.New(clientv3.Config{
clientConfig := clientv3.Config{
Endpoints: e.options.Addrs,
DialTimeout: e.options.Timeout,
})
}
e.client, err = clientv3.New(clientConfig)
if err != nil {
log.Error("初始化etcd失败, err:%v", err)
panic(fmt.Sprintf("初始化etcd失败, err:%v", err))
return
}
//下面代码 是因为当etcd ip链接不同 不报错导致超时 阻塞的办法
timeoutCtx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
defer cancel()
_, err =e.client.Status(timeoutCtx, clientConfig.Endpoints[0])
if err != nil {
err = fmt.Errorf("init etcd failed, err:%v", err)
log.Error("etcd启动失败 %s",err)
panic(fmt.Sprintf("etcd启动失败 %s",err))
return
}
......
......@@ -5,8 +5,8 @@ import (
"fmt"
"testing"
"time"
"github.com/ichunt2019/ichunt-micro-service/registry"
"github.com/ichunt2019/ichunt-micro-service/proxy/load_balance"
"ichunt-micro/registry"
"ichunt-micro/proxy/load_balance"
)
func TestRegister(t *testing.T) {
......
......@@ -17,3 +17,5 @@ type Registry interface {
//服务发现:通过服务的名字获取服务的位置信息(ip和port列表)
GetService(ctx context.Context, name string) (service *Service, err error)
}
SET CGO_ENABLED=0
SET GOOS=windows
SET GOARCH=amd64
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