From 0277eac4a416c72cc3f90978b5f0eac6b6b0fbed Mon Sep 17 00:00:00 2001 From: dragon Date: Fri, 17 Oct 2025 16:37:24 +0800 Subject: [PATCH 1/3] init onebot --- .gitignore | 2 + asset/assets_vfsdata.go | 4 +- config/config.go | 18 +++++ config/notifiers.go | 47 +++++++++++- config/receiver/receiver.go | 4 ++ notify/onebot/onebot.go | 139 ++++++++++++++++++++++++++++++++++++ template/default.tmpl | 17 +++++ 7 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 notify/onebot/onebot.go diff --git a/.gitignore b/.gitignore index 7ef77d321a..abf64b52f2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ /.release /.tarballs /vendor +/.idea +*.iml !.golangci.yml !/cli/testdata/*.yml diff --git a/asset/assets_vfsdata.go b/asset/assets_vfsdata.go index 3dd06e052b..7f9417d3d1 100644 --- a/asset/assets_vfsdata.go +++ b/asset/assets_vfsdata.go @@ -161,9 +161,9 @@ var Assets = func() http.FileSystem { "/templates/default.tmpl": &vfsgen۰CompressedFileInfo{ name: "default.tmpl", modTime: time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC), - uncompressedSize: 8101, + uncompressedSize: 8630, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xec\x59\xcf\x6f\xeb\x36\x0c\xbe\xe7\xaf\x20\xfc\x76\x68\x0e\xf5\x1b\x76\x2c\x50\x0c\x0f\xc3\x7e\x1c\xba\x61\x68\xd1\x5d\x86\x21\x50\x6d\xc6\x55\x2b\x4b\xae\x44\x27\x0d\xd2\xfc\xef\x83\x6c\xc7\x91\x2d\x27\x91\xd3\xec\xb4\xdc\x12\x99\xfc\x48\x7f\x1f\x4d\xca\xf2\x7a\x0d\x29\xce\xb9\x44\x88\x66\x33\x26\x50\x53\xce\x24\xcb\x50\x47\xb0\xd9\x7c\x73\xfe\xaf\xd7\x80\x32\x85\xcd\x66\xb2\xd7\xe5\xf1\xfe\xce\x7a\xad\xd7\x10\xff\xfc\x4e\xa8\x25\x13\x8f\xf7\x77\xb0\xd9\x7c\xfd\xf2\xb5\xb2\x33\x3f\x6a\x4c\x90\x2f\x50\xdf\x5a\xa3\xfb\xe6\x0f\x7c\x40\xa9\xc5\x5b\x89\x7a\x55\xbb\x37\x81\xba\x91\x4c\xf9\xf4\x82\x09\xd9\x08\x7f\x5b\xef\x07\x62\x54\x1a\xf8\x00\x52\x8f\x45\x81\xba\x76\xe5\x73\xc0\xb7\xf6\x62\x34\xe7\x9a\xcb\xcc\xfa\xdc\x58\x9f\xea\x86\x4c\xfc\x4b\xb5\x0a\x1f\x20\x50\xba\x11\xff\x01\x6b\xf4\xab\x56\x65\x71\xc7\x9e\x50\x98\xf8\x41\x69\xc2\xf4\x4f\xc6\xb5\x89\xff\x62\xa2\x44\x1b\xf0\x45\x71\x09\x11\x58\x54\xa8\x43\x66\x04\x57\x16\x2b\xfe\x49\xe5\xb9\x92\xb5\xf3\xb4\x59\x73\xf0\xa6\xb0\xd9\x5c\xad\xd7\xb0\xe4\xf4\xdc\x35\x8e\xef\x31\x57\x0b\xec\x46\xff\x83\xe5\x68\x1a\x46\x87\xa2\xb7\x89\x4f\xdb\x5f\x7b\x64\x4a\xd1\x24\x9a\x17\xc4\x95\x8c\x0e\x70\x4c\xf8\x4e\xb5\xa4\x33\xc1\x0d\x35\xa6\x9a\xc9\x0c\x21\x86\xcd\xa6\xce\xeb\x66\xb2\x5b\xf4\x79\xb2\xac\x5c\x57\x44\xda\xf4\xed\xbf\x5b\x68\x6f\xa0\x49\xac\x0e\xfe\x4d\x4a\x45\xcc\xe6\xd4\x81\x74\x96\x4f\xc3\x7d\x50\xa5\x4e\xf0\xa6\x16\x13\x25\x6a\x46\x4a\xd7\x95\x38\x19\x20\xea\x20\x05\xb3\x9c\xe9\xd7\x54\x2d\xa5\xc7\xc5\x24\x94\x8c\xc0\xac\x27\xe3\xe9\x08\x45\x0e\x22\x64\x32\xcc\x88\x11\x2c\x79\x8d\x53\x9c\xb3\x52\x50\x4c\x9c\x04\x36\x54\x10\xe6\x85\x60\xd4\x7d\x38\xe3\x7d\x35\xd8\xc5\x29\x8d\x6d\x0f\xf9\x10\x54\xb7\x09\x05\xe2\xcd\x99\x10\x4f\x2c\x79\xf5\xf0\x06\xd3\xb7\xa0\xf0\x01\xc7\x0c\x05\x97\xaf\xc1\x19\x24\x4d\x06\x3c\x8d\xc2\x1c\x0a\x8d\xb6\xd6\x02\xad\x9d\x84\x0e\x32\x56\xf5\xe0\xc0\x94\x79\xa2\x24\xe6\xea\x85\x47\xe1\xf6\xa5\x16\xa1\x19\x87\xdf\xdc\x5c\x29\xaa\x27\x8e\x53\x83\xae\x79\x61\x6f\x2d\x2d\x69\xd5\xba\xf8\x0d\x6d\x5c\x39\xfa\x88\x89\xe0\x28\xe9\xf4\x82\xdc\x87\xb8\x9b\x8a\xa7\x69\xe6\xe3\x72\x69\x88\xc9\x04\xcd\x00\xae\xd7\xc1\xe3\xfd\xac\xaa\xc2\x64\x28\x39\xb6\xc0\x39\x1a\xc3\xb2\xd3\x9e\x6f\x0f\xcc\x57\xa8\x19\x78\x7b\x1a\xda\xe0\x84\x9b\xf4\xe6\x6b\x67\x80\x4f\xe1\x7b\xb8\xb6\x8d\xb3\x5a\x84\x7a\xb1\x6a\x9d\x87\x19\xe9\xee\x02\xaa\x20\xd7\xce\x1d\x0d\xc4\xbb\x47\xa3\xc4\x02\xd3\x5e\xc4\xed\x72\x78\xcc\xad\x87\x17\xf5\x3a\x84\x52\x53\xf5\xf1\xf1\xd5\xd4\x51\x7d\x89\xc9\x33\xa3\xb1\x9a\x4f\x2e\xfa\x1d\xd0\xcf\xdd\x28\x3f\x6a\xe1\xe1\x0d\xea\xb3\x47\xf5\x9e\x3e\xa4\x66\x76\x58\xee\xed\xa4\xbe\x79\xc1\x34\xad\x46\xd8\x13\xcb\x42\xad\x59\x86\x92\x66\xfd\x11\xd7\xad\xaf\x05\x4f\x48\x69\x55\x98\x5d\xd9\x12\x23\x9c\x75\x0b\xed\x52\x4b\xe3\x7a\x81\xcf\x2a\x4a\xe2\xb4\x9a\xa5\xdc\x14\x82\xad\x66\x7b\x76\x53\xc7\x1b\xb7\x8f\x9c\x2b\xc9\x49\x59\x42\x66\xa4\x94\x18\x39\x12\x3b\xb3\xab\x34\xcf\x6a\x81\xfa\x0c\xfb\x47\x0f\xea\xbf\xaf\xa7\xf3\x94\x53\x78\x35\x9d\xaf\x98\xfc\x2d\xfd\x21\x26\x77\x7b\xba\x31\x33\xc5\xdd\xcd\x49\xe7\x61\xdf\xbd\xa6\x8f\x7f\x47\x70\x70\x2e\xf2\x8e\x91\xd7\x65\x91\x50\x60\xa6\x59\x3e\x44\xe5\xff\x96\x94\x94\x9b\x44\xe9\x74\xb7\x37\x57\x92\x76\xdb\x7d\xbf\x14\xfb\xf6\xa7\x37\xae\x3e\xd2\x45\x0d\xbb\xad\x78\xc2\xf7\xcb\xa3\xfe\x69\x1e\x73\x43\xc8\x72\xb7\xf9\xe6\x39\xd3\xab\x93\xea\xb4\x8f\x75\x7a\xc5\x7b\x48\xcd\x49\x40\x88\x4c\x5f\x60\x94\x50\xce\xf1\xdc\xa7\x15\x6b\x43\x87\x6a\x36\x10\xfc\x04\xf1\x16\x3f\x9c\x8f\x72\x17\xeb\x42\xfa\x10\xe9\x2f\x5c\xb3\xb3\x3c\x2e\x1d\xa0\xde\x59\xc7\x85\xf3\x49\xf5\x1a\x33\xc8\x55\xa1\xb9\xd2\xdc\xbe\xa1\x5e\x37\x6f\x3b\xdf\x6d\x97\xe0\xe6\x16\xa2\x68\xfb\x12\xb4\x3d\xff\xee\xdc\xad\xf5\x01\x00\xa8\xfc\x0c\x2e\x70\xeb\xc7\x65\x8a\xef\xdb\x23\x78\x88\xb6\x97\xa2\x8e\x07\x9f\xc3\x15\xbe\x39\x8e\x51\xa2\x39\xf1\x84\x89\x68\xda\x1a\xb6\xf0\x6d\x5a\xb7\x10\xfd\xc6\xb3\xe7\x2e\x16\x0a\x83\x15\x20\x93\x69\x1f\x75\xc9\xb4\xe4\x32\x8b\xa6\x70\x25\xd1\x01\xaa\x61\xa6\x47\x62\xfd\x8e\x29\x2f\xf3\xf0\x68\x5c\xce\x95\x0d\x65\x57\x77\xa1\x8e\x86\xb9\x53\xcb\x5e\x0c\x99\xb6\x9a\xb8\xbf\xeb\x6f\x6a\x2e\x74\xc7\xad\xab\x53\x5b\x18\x5e\xec\x51\x6a\x8d\x56\x2c\x40\xb5\xb3\x2b\x17\xa4\xde\xf9\x14\x3c\xae\x62\x5f\xc9\x63\xca\xee\x90\xfa\x57\xdd\x56\xa7\x55\xf2\x8a\xd4\x3d\x36\x3a\x79\x52\x0d\x80\x31\xc1\x99\x39\xfd\xe0\x7d\x5f\x7a\x9f\xfe\x5a\x32\x00\x7c\xf8\x73\xc9\x80\xc3\xb1\x6f\x26\x43\xc9\x7b\x1f\x4e\xfe\x0d\x00\x00\xff\xff\x74\x5d\xc4\xb5\xa5\x1f\x00\x00"), + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xec\x59\x4d\x6f\xe3\x36\x10\xbd\xfb\x57\x0c\xb4\x3d\xc4\x87\x68\x8b\x1e\x03\x04\xc5\xa2\xe8\xc7\x21\x2d\x8a\x04\xe9\xa5\x28\x04\x46\x1a\x2b\x4c\x28\x52\x21\x47\x4e\x0c\x47\xff\xbd\xa0\x24\xcb\xd4\x97\x25\x39\xde\xa2\x45\x7d\xb3\xa9\x99\x37\xa3\xf7\x86\x43\x52\xdc\x6e\x21\xc2\x15\x97\x08\x5e\x10\x30\x81\x9a\x12\x26\x59\x8c\xda\x83\x3c\xff\xe2\xfc\xdf\x6e\x01\x65\x04\x79\xbe\x18\x74\xb9\xbf\xbd\xb1\x5e\xdb\x2d\xf8\x3f\xbe\x11\x6a\xc9\xc4\xfd\xed\x0d\xe4\xf9\xe7\x4f\x9f\x0b\x3b\xf3\xbd\xc6\x10\xf9\x1a\xf5\xb5\x35\xba\xad\xfe\xc0\x3b\x64\x5a\xbc\x64\xa8\x37\xa5\x7b\x15\xa8\x19\xc9\x64\x0f\x4f\x18\x92\x8d\xf0\xa7\xf5\xbe\x23\x46\x99\x81\x77\x20\x75\x9f\xa6\xa8\x4b\x57\xbe\x02\x7c\xa9\x1f\x7a\x2b\xae\xb9\x8c\xad\xcf\x95\xf5\x29\x5e\xc8\xf8\x3f\x15\xa3\xf0\x0e\x02\xa5\x1b\xf1\x2f\xb0\x46\x3f\x6b\x95\xa5\x37\xec\x01\x85\xf1\xef\x94\x26\x8c\x7e\x67\x5c\x1b\xff\x0f\x26\x32\xb4\x01\x9f\x14\x97\xe0\x81\x45\x85\x32\x64\x4c\x70\x61\xb1\xfc\x1f\x54\x92\x28\x59\x3a\x2f\xab\x31\x07\x6f\x09\x79\x7e\xb1\xdd\xc2\x2b\xa7\xc7\xa6\xb1\x7f\x8b\x89\x5a\x63\x33\xfa\x6f\x2c\x41\x53\x31\xda\x17\xbd\x4e\x7c\x59\xff\x1a\x90\x29\x42\x13\x6a\x9e\x12\x57\xd2\x3b\xc0\x31\xe1\x1b\x95\x92\x06\x82\x1b\xaa\x4c\x35\x93\x31\x82\x0f\x79\x5e\xe6\x75\xb5\xd8\x0f\x76\x79\xb2\xac\x5c\x16\x44\xda\xf4\xed\xbf\x6b\xa8\x5f\xa0\x4a\xac\x0c\xfe\x45\x4a\x45\xcc\xe6\xd4\x80\x74\x86\x8f\xc3\xbd\x53\x99\x0e\xf1\xaa\x14\x13\x25\x6a\x46\x4a\x97\x95\xb8\xe8\x21\xea\x20\x05\x41\xc2\xf4\x73\xa4\x5e\x65\x87\x8b\xc5\x54\x32\x26\x66\xbd\x98\x4f\xc7\x54\xe4\x49\x84\x2c\xfa\x19\x31\x82\x85\xcf\x7e\x84\x2b\x96\x09\xf2\x89\x93\xc0\x8a\x0a\xc2\x24\x15\x8c\x9a\x93\xd3\x1f\xaa\xc1\x26\x4e\x66\x6c\x7b\x48\xfa\xa0\x9a\x4d\x68\x22\xde\x8a\x09\xf1\xc0\xc2\xe7\x0e\x5e\x6f\xfa\x16\x14\xde\x61\xcc\x50\x70\xf9\x3c\x39\x83\xb0\xca\x80\x47\xde\x34\x87\x54\xa3\xad\xb5\x89\xd6\x4e\x42\x07\x19\x2b\x7a\xf0\xc4\x94\x79\xa8\x24\x26\xea\x89\x7b\xd3\xed\x33\x2d\xa6\x66\x3c\xfd\xe5\x56\x4a\x51\xb9\xe2\x38\x35\xe8\x9a\xa7\xf6\xd5\xa2\x8c\x36\xb5\x4b\xb7\xa1\xcd\x2b\xc7\x2e\x62\x28\x38\x4a\x3a\xbe\x20\x87\x10\xf7\xab\xe2\x71\x9a\x75\x71\xb9\x34\xc4\x64\x88\xa6\x07\xb7\xd3\xc1\xfd\x61\x56\x95\xc4\x07\x45\x35\x6c\x82\xc6\xb0\x78\x74\x76\x5b\x84\x6a\xe9\x1a\x68\x4d\xbd\x6b\xd5\xa2\xb5\x52\x36\x96\xe2\x25\x7c\x0b\x97\x79\xbe\x00\x00\x28\x1f\x40\xf9\xe0\xaa\x18\x1a\x7d\xc7\xe6\xba\x5e\x04\xbb\x74\xa8\xec\x89\x7b\x8b\x46\x89\x35\x46\x3d\x91\x77\x8f\xe6\xc5\xde\x79\xb5\xa2\xbb\x5b\xa8\x7b\x2d\x8a\xc6\x3e\x5a\x07\xad\xf4\x07\xf4\x22\x15\xd8\x36\x3a\x38\xc7\xba\xe6\x29\xd3\xb4\x39\x30\xcd\x54\x6a\x62\x94\x1c\xe7\x96\x44\x7f\xf8\x36\x58\x77\xca\x7e\xad\x32\x6a\x95\xd0\x3f\x50\x3e\x9d\xd2\xf9\x60\xd9\x0c\x14\x40\x9b\x52\x53\x2c\xec\xf3\xdb\x4b\x43\xf5\x57\x0c\x1f\xd9\xbf\xaa\x0d\xfc\xf7\xf5\x3b\xe5\xb4\x6f\xe9\x33\x36\xed\xbb\xe6\x3d\xd3\xfe\xa0\x3d\xb1\x78\xaa\x35\x8b\x51\x52\xd0\xde\xf3\x34\xeb\x6b\xcd\x43\x52\x5a\xa5\x66\x5f\xb6\xc4\x08\x83\x66\xa1\x9d\x6b\x69\x5e\x2f\xe8\xb2\x8a\x92\x38\x6d\x82\x88\x9b\x54\xb0\x4d\x30\xb0\xbd\x1e\x6f\xdc\x5d\xe4\x44\x49\x4e\xca\x12\x12\x90\x52\x62\xe6\x1e\xa9\xb1\x99\xc9\xcc\xa3\x5a\xa3\x3e\xc1\x81\xa2\x03\xf5\xf5\xeb\xe9\x34\xe5\x34\xbd\x9a\x4e\x57\x4c\xdd\x33\xde\x21\x26\xf7\x9b\xfc\x39\x6b\x8a\xbb\xbd\x97\xce\x64\xdf\x7f\xb7\x99\x7f\x68\x74\x70\xce\xf2\xce\x91\xd7\x65\x91\x50\x60\xac\x59\xd2\x47\xe5\xff\x96\x94\x88\x9b\x50\xe9\x68\x7f\x58\x53\x92\xf6\xe7\xbf\x6e\x29\xb6\xed\x8f\x6f\x5c\x6d\xa4\xb3\x1a\x76\x5b\xf1\x80\x6f\xe7\xa9\xfe\x61\x1e\x13\x43\xc8\x12\xb7\xf9\x26\x09\xd3\x9b\xa3\xea\xb4\x8d\x75\x7c\xc5\x77\x90\xaa\x4f\x43\x53\x64\xfa\x04\xb3\x84\x72\xbe\xd7\x7e\x58\xb1\x4f\x30\x53\xb3\x9e\xe0\x47\x88\xb7\xfe\xee\x74\x94\xbb\x58\x67\xd2\xfb\x48\x7f\xe2\x9a\x9d\x64\xba\x34\x80\x5a\xdf\x3a\xce\x9c\x2f\x8a\x63\x4c\x2f\x57\xa9\xe6\x4a\x73\x7b\x42\xbd\xac\x4e\x3b\xdf\xec\x86\xe0\xea\x1a\x3c\x6f\x77\x08\xda\x5d\x88\x34\xde\x76\xf7\xf1\xae\xf0\x33\xb8\xc6\x9d\x1f\x97\x11\xbe\xed\xee\x64\xc0\xdb\x3d\xf2\x1a\x1e\x7c\x05\x17\xf8\xe2\x38\x7a\xa1\xe6\xc4\x43\x26\xbc\x65\x6d\x58\xc3\xd7\x69\x5d\x83\xf7\x0b\x8f\x1f\x9b\x58\x28\x0c\x16\x80\x4c\x46\x6d\xd4\x57\xa6\x25\x97\xb1\xb7\x84\x0b\x89\x0e\x50\x09\xb3\x1c\x89\xf5\x2b\x46\x3c\x4b\xa6\x47\xe3\x72\xa5\x6c\x28\x3b\xba\x0f\x35\x1a\xe6\x46\xbd\xb6\x62\xc8\xa8\xd6\xc4\xfd\x5d\x5e\xb2\xba\xd0\x0d\xb7\xa6\x4e\x75\x61\x74\x62\xcf\x52\x6b\xb6\x62\x13\x54\x3b\xb9\x72\x93\xd4\x3b\x9d\x82\xe3\x2a\xb6\x95\x1c\x53\x76\x8f\xd4\x7e\xea\xb6\x3a\xad\xc2\x67\xa4\xe6\x67\xa3\xa3\x57\xaa\x1e\x30\x26\x38\x33\xc7\xdf\xc4\x0c\xa5\xf7\xe1\xeb\xb3\x1e\xe0\xc3\xf7\x67\x3d\x0e\x63\x97\x68\x7d\xc9\x77\x6e\xd2\xfe\x0e\x00\x00\xff\xff\x92\xaa\x22\x6d\xb6\x21\x00\x00"), }, "/templates/email.tmpl": &vfsgen۰CompressedFileInfo{ name: "email.tmpl", diff --git a/config/config.go b/config/config.go index 09cd713870..6c2515a27b 100644 --- a/config/config.go +++ b/config/config.go @@ -503,6 +503,21 @@ func (c *Config) UnmarshalYAML(unmarshal func(any) error) error { ogc.APIKeyFile = c.Global.OpsGenieAPIKeyFile } } + for _, oa := range rcv.OnebotConfigs { + if oa.HTTPConfig == nil { + oa.HTTPConfig = c.Global.HTTPConfig + } + if oa.APIURL == nil { + if c.Global.OnebotAPIURL == nil { + return errors.New("no global onebot URL set") + } + oa.APIURL = c.Global.WeChatAPIURL + } + if !strings.HasSuffix(oa.APIURL.Path, "/") { + oa.APIURL.Path += "/" + } + } + for _, wcc := range rcv.WechatConfigs { if wcc.HTTPConfig == nil { wcc.HTTPConfig = c.Global.HTTPConfig @@ -736,6 +751,7 @@ func DefaultGlobalConfig() GlobalConfig { SMTPTLSConfig: &defaultSMTPTLSConfig, PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"), OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"), + OnebotAPIURL: mustParseURL("https://127.0.0.1:3000"), WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"), VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"), TelegramAPIUrl: mustParseURL("https://api.telegram.org"), @@ -859,6 +875,7 @@ type GlobalConfig struct { OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"` OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"` OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"` + OnebotAPIURL *URL `yaml:"onebot_api_url,omitempty" json:"onebot_api_url,omitempty"` WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"` WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"` WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"` @@ -1018,6 +1035,7 @@ type Receiver struct { WebhookConfigs []*WebhookConfig `yaml:"webhook_configs,omitempty" json:"webhook_configs,omitempty"` OpsGenieConfigs []*OpsGenieConfig `yaml:"opsgenie_configs,omitempty" json:"opsgenie_configs,omitempty"` WechatConfigs []*WechatConfig `yaml:"wechat_configs,omitempty" json:"wechat_configs,omitempty"` + OnebotConfigs []*OnebotConfig `yaml:"onebot_configs,omitempty" json:"onebot_configs,omitempty"` PushoverConfigs []*PushoverConfig `yaml:"pushover_configs,omitempty" json:"pushover_configs,omitempty"` VictorOpsConfigs []*VictorOpsConfig `yaml:"victorops_configs,omitempty" json:"victorops_configs,omitempty"` SNSConfigs []*SNSConfig `yaml:"sns_configs,omitempty" json:"sns_configs,omitempty"` diff --git a/config/notifiers.go b/config/notifiers.go index e8b7dcf28c..341acf7992 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -129,7 +129,15 @@ var ( Source: `{{ template "opsgenie.default.source" . }}`, // TODO: Add a details field with all the alerts. } - + // DefaultOnebotConfig defines default values for onebot configurations. + DefaultOnebotConfig = OnebotConfig{ + NotifierConfig: NotifierConfig{ + VSendResolved: false, + }, + Message: `{{ template "onebot.default.message" . }}`, + ToUser: `{{ template "onebot.default.to_user" . }}`, + ToParty: `{{ template "onebot.default.to_party" . }}`, + } // DefaultWechatConfig defines default values for wechat configurations. DefaultWechatConfig = WechatConfig{ NotifierConfig: NotifierConfig{ @@ -330,6 +338,43 @@ func (c *EmailConfig) UnmarshalYAML(unmarshal func(any) error) error { return nil } +type OnebotConfig struct { + NotifierConfig `yaml:",inline" json:",inline"` + + HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"` + + APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` + ToUser string `yaml:"to_user,omitempty" json:"to_user,omitempty"` + ToParty string `yaml:"to_party,omitempty" json:"to_party,omitempty"` + Message string `yaml:"message,omitempty" json:"message,omitempty"` + MessageType string `yaml:"message_type,omitempty" json:"message_type,omitempty"` +} + +const onebotValidTypesRe = `^(text|raw)$` + +var onebotTypeMatcher = regexp.MustCompile(wechatValidTypesRe) + +func (c *OnebotConfig) UnmarshalYAML(unmarshal func(any) error) error { + *c = DefaultOnebotConfig + type plain OnebotConfig + if err := unmarshal((*plain)(c)); err != nil { + return err + } + if c.APIURL == nil || c.APIURL.String() == "" { + return errors.New("`api_url` must be configured") + } + if c.ToUser == "" && c.ToParty == "" { + return errors.New("`to_user` or `to_party` must be configured") + } + if c.MessageType == "" { + c.MessageType = "text" + } + if !onebotTypeMatcher.MatchString(c.MessageType) { + return fmt.Errorf("onebot message type %q does not match valid options %s", c.MessageType, onebotValidTypesRe) + } + return nil +} + // PagerdutyConfig configures notifications via PagerDuty. type PagerdutyConfig struct { NotifierConfig `yaml:",inline" json:",inline"` diff --git a/config/receiver/receiver.go b/config/receiver/receiver.go index 23be2b11c8..f082a3110d 100644 --- a/config/receiver/receiver.go +++ b/config/receiver/receiver.go @@ -16,6 +16,7 @@ package receiver import ( "log/slog" + "github.com/prometheus/alertmanager/notify/onebot" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/common/promslog" @@ -74,6 +75,9 @@ func BuildReceiverIntegrations(nc config.Receiver, tmpl *template.Template, logg for i, c := range nc.OpsGenieConfigs { add("opsgenie", i, c, func(l *slog.Logger) (notify.Notifier, error) { return opsgenie.New(c, tmpl, l, httpOpts...) }) } + for i, c := range nc.OnebotConfigs { + add("onebot", i, c, func(l *slog.Logger) (notify.Notifier, error) { return onebot.New(c, tmpl, l, httpOpts...) }) + } for i, c := range nc.WechatConfigs { add("wechat", i, c, func(l *slog.Logger) (notify.Notifier, error) { return wechat.New(c, tmpl, l, httpOpts...) }) } diff --git a/notify/onebot/onebot.go b/notify/onebot/onebot.go new file mode 100644 index 0000000000..94fb840367 --- /dev/null +++ b/notify/onebot/onebot.go @@ -0,0 +1,139 @@ +// Copyright 2025 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package onebot + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "log/slog" + "net/http" + "strings" + + "github.com/prometheus/alertmanager/config" + "github.com/prometheus/alertmanager/notify" + "github.com/prometheus/alertmanager/template" + "github.com/prometheus/alertmanager/types" + commoncfg "github.com/prometheus/common/config" +) + +// Notifier implements a Notifier for wechat notifications. +type Notifier struct { + conf *config.OnebotConfig + tmpl *template.Template + logger *slog.Logger + client *http.Client +} + +// New returns a new Wechat notifier. +func New(c *config.OnebotConfig, t *template.Template, l *slog.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) { + client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "onebot", httpOpts...) + if err != nil { + return nil, err + } + + return &Notifier{conf: c, tmpl: t, logger: l, client: client}, nil +} + +func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { + key, err := notify.ExtractGroupKey(ctx) + if err != nil { + return false, err + } + + n.logger.Debug("extracted group key", "key", key) + data := notify.GetTemplateData(ctx, n.tmpl, as, n.logger) + tmpl := notify.TmplText(n.tmpl, data, &err) + if err != nil { + return false, err + } + toUser := tmpl(n.conf.ToUser) + if err != nil { + return false, err + } + toParty := tmpl(n.conf.ToParty) + if err != nil { + return false, err + } + msg := tmpl(n.conf.Message) + if err != nil { + return false, err + } + var messages []map[string]any + if msg == "" { + return false, errors.New("message is empty") + } + if n.conf.MessageType == "raw" { + if err := json.Unmarshal([]byte(msg), &messages); err != nil { + return false, err + } + } else { + messages = append(messages, map[string]any{ + "type": "text", + "data": map[string]any{ + "text": msg, + }, + }) + } + + var resp *http.Response + if toUser != "" { + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(map[string]any{ + "user_id": toUser, + "message": messages, + }); err != nil { + return false, err + } + url := n.conf.APIURL.Copy() + url.Path = strings.TrimSuffix(url.Path, "/") + "/send_private_msg" + resp, err = notify.PostJSON(ctx, n.client, url.String(), &buf) + } else if toParty != "" { + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(map[string]any{ + "group_id": toParty, + "message": messages, + }); err != nil { + return false, err + } + url := n.conf.APIURL.Copy() + url.Path = strings.TrimSuffix(url.Path, "/") + "/send_group_msg" + resp, err = notify.PostJSON(ctx, n.client, url.String(), &buf) + } else { + return false, errors.New("no group_id or to_user specified") + } + if err != nil { + return true, notify.RedactURL(err) + } + defer notify.Drain(resp) + if resp.StatusCode != 200 { + return true, notify.NewErrorWithReason(notify.GetFailureReasonFromStatusCode(resp.StatusCode), fmt.Errorf("unexpected status code %v", resp.StatusCode)) + } + body, err := io.ReadAll(resp.Body) + if err != nil { + return true, err + } + n.logger.Debug(string(body), "incident", key) + var onebotResp map[string]any + if err := json.Unmarshal(body, &onebotResp); err != nil { + return true, err + } + if onebotResp["status"] == "ok" { + return false, nil + } + return false, errors.New(fmt.Sprintf("%v", onebotResp["message"])) +} diff --git a/template/default.tmpl b/template/default.tmpl index 57e877c0c2..3ae41c279e 100644 --- a/template/default.tmpl +++ b/template/default.tmpl @@ -40,6 +40,23 @@ Source: {{ .GeneratorURL }} {{ define "pagerduty.default.instances" }}{{ template "__text_alert_list" . }}{{ end }} +{{ define "onebot.default.message" }}{{ template "__subject" . }} +{{ .CommonAnnotations.SortedPairs.Values | join " " }} +{{ if gt (len .Alerts.Firing) 0 -}} + Alerts Firing: + {{ template "__text_alert_list" .Alerts.Firing }} +{{- end }} +{{ if gt (len .Alerts.Resolved) 0 -}} + Alerts Resolved: + {{ template "__text_alert_list" .Alerts.Resolved }} +{{- end }} +AlertmanagerUrl: +{{ template "__alertmanagerURL" . }} +{{- end }} +{{ define "onebot.default.to_user" }}{{ end }} +{{ define "onebot.default.to_party" }}{{ end }} + + {{ define "opsgenie.default.message" }}{{ template "__subject" . }}{{ end }} {{ define "opsgenie.default.description" }}{{ .CommonAnnotations.SortedPairs.Values | join " " }} {{ if gt (len .Alerts.Firing) 0 -}} From e6006d3e014d4960a26299547edf2eb07052e51a Mon Sep 17 00:00:00 2001 From: dragon Date: Fri, 17 Oct 2025 16:51:57 +0800 Subject: [PATCH 2/3] fix ci --- config/config.go | 2 +- config/config_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 6c2515a27b..a8c96259b7 100644 --- a/config/config.go +++ b/config/config.go @@ -751,7 +751,7 @@ func DefaultGlobalConfig() GlobalConfig { SMTPTLSConfig: &defaultSMTPTLSConfig, PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"), OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"), - OnebotAPIURL: mustParseURL("https://127.0.0.1:3000"), + OnebotAPIURL: mustParseURL("http://127.0.0.1:3000"), WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"), VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"), TelegramAPIUrl: mustParseURL("https://api.telegram.org"), diff --git a/config/config_test.go b/config/config_test.go index 113a4777b9..4aea7da889 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -937,6 +937,7 @@ func TestEmptyFieldsAndRegex(t *testing.T) { SMTPRequireTLS: true, PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"), OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"), + OnebotAPIURL: mustParseURL("http://127.0.0.1:3000"), WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"), VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"), TelegramAPIUrl: mustParseURL("https://api.telegram.org"), From 901a84014e53baea585ed11eb01933a442c87da7 Mon Sep 17 00:00:00 2001 From: dragon Date: Fri, 31 Oct 2025 08:59:42 +0800 Subject: [PATCH 3/3] fix ci --- config/receiver/receiver.go | 3 ++- notify/onebot/onebot.go | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/receiver/receiver.go b/config/receiver/receiver.go index f082a3110d..92e9f6156a 100644 --- a/config/receiver/receiver.go +++ b/config/receiver/receiver.go @@ -16,10 +16,11 @@ package receiver import ( "log/slog" - "github.com/prometheus/alertmanager/notify/onebot" commoncfg "github.com/prometheus/common/config" "github.com/prometheus/common/promslog" + "github.com/prometheus/alertmanager/notify/onebot" + "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/notify/discord" diff --git a/notify/onebot/onebot.go b/notify/onebot/onebot.go index 94fb840367..4809f4f697 100644 --- a/notify/onebot/onebot.go +++ b/notify/onebot/onebot.go @@ -24,11 +24,12 @@ import ( "net/http" "strings" + commoncfg "github.com/prometheus/common/config" + "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/template" "github.com/prometheus/alertmanager/types" - commoncfg "github.com/prometheus/common/config" ) // Notifier implements a Notifier for wechat notifications. @@ -135,5 +136,5 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) if onebotResp["status"] == "ok" { return false, nil } - return false, errors.New(fmt.Sprintf("%v", onebotResp["message"])) + return false, fmt.Errorf("notify error: %v", onebotResp["message"]) }