github.com/fumiama/NanoBot@v0.0.0-20231122134259-c22d8183efca/helper.go (about) 1 package nano 2 3 import ( 4 "encoding/base64" 5 "encoding/hex" 6 "hash/crc64" 7 "net/url" 8 "regexp" 9 "runtime" 10 "strings" 11 "unsafe" 12 ) 13 14 func getFuncAndFileNameWithSkip(n int) (string, string) { 15 pc, fn, _, ok := runtime.Caller(n) 16 if !ok { 17 return "", "" 18 } 19 i := strings.LastIndex(fn, "/") + 1 20 if i > 0 { 21 fn = strings.TrimSuffix(fn[i:], ".go") 22 } 23 fullname := runtime.FuncForPC(pc).Name() 24 i = strings.LastIndex(fullname, ".") + 1 25 if i <= 0 || i >= len(fullname) { 26 return fullname, fn 27 } 28 return fullname[i:], fn 29 } 30 31 // getThisFuncName 获取正在执行的函数名 32 func getThisFuncName() string { 33 x, _ := getFuncAndFileNameWithSkip(2) 34 return x 35 } 36 37 // getCallerFuncName 获取调用者函数名 38 func getCallerFuncName() string { 39 x, _ := getFuncAndFileNameWithSkip(3) 40 return x 41 } 42 43 // getLogHeader [文件名.函数名] 44 func getLogHeader() string { 45 funcname, filename := getFuncAndFileNameWithSkip(2) 46 return "[" + filename + "." + funcname + "]" 47 } 48 49 // MessageEscape 消息转义 50 // 51 // https://bot.q.qq.com/wiki/develop/api/openapi/message/message_format.html 52 func MessageEscape(text string) string { 53 text = strings.ReplaceAll(text, "&", "&") 54 text = strings.ReplaceAll(text, "<", "<") 55 text = strings.ReplaceAll(text, ">", ">") 56 return text 57 } 58 59 // MessageUnescape 消息解转义 60 // 61 // https://bot.q.qq.com/wiki/develop/api/openapi/message/message_format.html 62 func MessageUnescape(text string) string { 63 text = strings.ReplaceAll(text, "&", "&") 64 text = strings.ReplaceAll(text, "<", "<") 65 text = strings.ReplaceAll(text, ">", ">") 66 return text 67 } 68 69 // HideURL 转义 URL 以避免审核 70 func HideURL(s string) string { 71 s = strings.ReplaceAll(s, ".", "…") 72 s = strings.ReplaceAll(s, "http://", "🔗📄:") 73 s = strings.ReplaceAll(s, "https://", "🔗🔒:") 74 return s 75 } 76 77 // UnderlineToCamel convert abc_def to AbcDef 78 func UnderlineToCamel(s string) string { 79 sb := strings.Builder{} 80 isnextupper := true 81 for _, c := range []byte(strings.ToLower(s)) { 82 if c == '_' { 83 isnextupper = true 84 continue 85 } 86 if isnextupper { 87 sb.WriteString(strings.ToUpper(string(c))) 88 isnextupper = false 89 continue 90 } 91 sb.WriteByte(c) 92 } 93 return sb.String() 94 } 95 96 // resolveURI github.com/wdvxdr1123/ZeroBot/driver/uri.go 97 func resolveURI(addr string) (network, address string) { 98 network, address = "tcp", addr 99 uri, err := url.Parse(addr) 100 if err == nil && uri.Scheme != "" { 101 scheme, ext, _ := strings.Cut(uri.Scheme, "+") 102 if ext != "" { 103 network = ext 104 uri.Scheme = scheme // remove `+unix`/`+tcp4` 105 if ext == "unix" { 106 uri.Host, uri.Path, _ = strings.Cut(uri.Path, ":") 107 uri.Host = base64.StdEncoding.EncodeToString(StringToBytes(uri.Host)) // special handle for unix 108 } 109 address = uri.String() 110 } 111 } 112 return 113 } 114 115 // slice is the runtime representation of a slice. 116 // It cannot be used safely or portably and its representation may 117 // change in a later release. 118 // 119 // Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the 120 // data it references will not be garbage collected. 121 type slice struct { 122 data unsafe.Pointer 123 len int 124 cap int 125 } 126 127 // BytesToString 没有内存开销的转换 128 func BytesToString(b []byte) string { 129 return *(*string)(unsafe.Pointer(&b)) 130 } 131 132 // StringToBytes 没有内存开销的转换 133 func StringToBytes(s string) (b []byte) { 134 bh := (*slice)(unsafe.Pointer(&b)) 135 sh := (*slice)(unsafe.Pointer(&s)) 136 bh.data = sh.data 137 bh.len = sh.len 138 bh.cap = sh.len 139 return b 140 } 141 142 // DigestID 归一化 id 为 uint64 143 func DigestID(id string) uint64 { 144 b, err := hex.DecodeString(id) 145 if err != nil || len(b) < 8 { 146 return 0 147 } 148 return crc64.Checksum(b, crc64.MakeTable(crc64.ECMA)) 149 } 150 151 const mediafilebed = `https://multimedia.nt.qq.com.cn` 152 153 var mediafileinfourlre = regexp.MustCompile(`/download\?appid=\d+&fileid=[0-9A-Za-z-_]+&rkey=[0-9A-Za-z-_]+`) 154 155 // mediaURL 从 fileinfo 得到 URL 156 func mediaURL(fileinfo string) (string, error) { 157 sb := strings.Builder{} 158 data, err := base64.StdEncoding.DecodeString(fileinfo) 159 if err != nil { 160 return "", err 161 } 162 sb.WriteString(mediafilebed) 163 sb.Write(mediafileinfourlre.Find(data)) 164 return sb.String(), nil 165 }