1 /* 2 * Copyright (C) 2019, HuntLabs 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 module hunt.database.base.Util; 19 20 import hunt.Byte; 21 import hunt.net.buffer.ByteBuf; 22 import hunt.net.buffer.ByteBufUtil; 23 import hunt.text.Charset; 24 import hunt.util.TypeUtils; 25 26 import std.algorithm; 27 import std.conv; 28 import std.variant; 29 30 import core.stdc.stdio; 31 import core.stdc.stdarg; 32 import core.stdc.time; 33 34 import hunt.logging; 35 36 37 /** 38 * 39 */ 40 class Util { 41 42 private enum byte ZERO = 0; 43 44 static string readCString(ByteBuf src, Charset charset) { 45 string data; 46 int len = src.bytesBefore(ZERO); 47 48 version(HUNT_DB_DEBUG_MORE) { 49 tracef("len: %d, buffer: %s", len, src); 50 } 51 52 string s = src.readCharSequence(len, charset); 53 src.readByte(); 54 return s; 55 } 56 57 static string readCStringUTF8(ByteBuf src) { 58 return readCString(src, StandardCharsets.UTF_8); 59 } 60 61 static void writeCString(ByteBuf dst, string s, Charset charset) { 62 dst.writeCharSequence(s, charset); 63 dst.writeByte(0); 64 } 65 66 static void writeCString(ByteBuf dst, ByteBuf buf) { 67 // Important : won't not change data index 68 dst.writeBytes(buf, buf.readerIndex(), buf.readableBytes()); 69 dst.writeByte(0); 70 } 71 72 static void writeCStringUTF8(ByteBuf dst, string s) { 73 dst.writeCharSequence(s, StandardCharsets.UTF_8); 74 dst.writeByte(0); 75 } 76 77 static void writeCString(ByteBuf dst, byte[] bytes) { 78 dst.writeBytes(bytes, 0, cast(int)bytes.length); 79 dst.writeByte(0); 80 } 81 82 static string buildInvalidArgsError(Variant[] values, string[] types) { 83 import std.format; 84 // string str = types.to!string(); 85 string str = format("[%-(%s / %)]", types); 86 return "Values [" ~ values.map!(v => v.to!string() ~ " : "~ v.type.toString() ).joiner(", ").to!string() ~ 87 "] cannot be coerced to " ~ str; 88 } 89 90 static string buildInvalidArgsError(T)(T[] values, TypeInfo[] types) { 91 return "Values [" ~ values.map!(v => v.to!string()).joiner(", ").to!string() ~ 92 "] cannot be coerced to [" ~ types.map!(t => TypeUtils.getSimpleName(t)) 93 .joiner(", ").to!string() ~ "]"; 94 } 95 96 // private enum int FIRST_HALF_BYTE_MASK = 0x0F; 97 98 // static int writeHexString(Buffer buffer, ByteBuf to) { 99 // int len = buffer.length(); 100 // for (int i = 0; i < len; i++) { 101 // int b = Byte.toUnsignedInt(buffer.getByte(i)); 102 // int firstDigit = b >> 4; 103 // byte firstHexDigit = cast(byte)bin2hex(firstDigit); 104 // int secondDigit = b & FIRST_HALF_BYTE_MASK; 105 // byte secondHexDigit = cast(byte)bin2hex(secondDigit); 106 // to.writeByte(firstHexDigit); 107 // to.writeByte(secondHexDigit); 108 // } 109 // return len; 110 // } 111 112 // private static int bin2hex(int digit){ 113 // int isLessOrEqual9 =(digit-10)>>31; 114 // //isLessOrEqual9==0xff<->digit<=9 115 // //bin2hexAsciiDistance=digit<=9?48:87; 116 // int bin2hexAsciiDistance = 48+((~isLessOrEqual9)&39); 117 // return digit+bin2hexAsciiDistance; 118 // } 119 120 121 extern(C) @nogc nothrow { 122 static void info(string file = __FILE__, size_t line = __LINE__, 123 string func = __FUNCTION__)(cstring msg) { 124 version(Windows) { 125 doLog!("info", file, line, func)( msg); 126 } else { 127 doLog!("info", CONSOLE_COLOR_BLUE, file, line, func)(msg); 128 } 129 } 130 131 static void infof(string file = __FILE__, size_t line = __LINE__, 132 string func = __FUNCTION__)(cstring fmt, ...) { 133 va_list args; 134 va_start(args, fmt); 135 char[512] buffer; 136 vsnprintf(buffer.ptr, buffer.length, fmt, args); 137 version(Windows) { 138 doLog!("info", file, line, func)(buffer.ptr); 139 } else { 140 doLog!("info", CONSOLE_COLOR_BLUE, file, line, func)(buffer.ptr); 141 } 142 va_end(args); 143 } 144 145 version(Windows) { 146 static private void doLog(string level, string file = __FILE__, size_t line = __LINE__, 147 string func = __FUNCTION__)(cstring msg) { 148 time_t now; 149 tm ts; 150 char[24] buf; 151 152 // Get current time 153 time(&now); 154 155 ts = *localtime(&now); 156 strftime(buf.ptr, buf.length, "%m-%d %H:%M:%S", &ts); 157 158 printf("%s.%d | %s | %d | %s | %s | %s:%d\n", buf.ptr, 0, level.ptr, 159 getTid(), cast(cstring)func.ptr, msg, cast(cstring)file.ptr, line); 160 } 161 162 } else { 163 164 static private void doLog(string level, string leadingColor, string file = __FILE__, size_t line = __LINE__, 165 string func = __FUNCTION__)(cstring msg) { 166 time_t now; 167 tm ts; 168 char[24] buf; 169 170 // Get current time 171 time(&now); 172 173 ts = *localtime(&now); 174 strftime(buf.ptr, buf.length, "%m-%d %H:%M:%S", &ts); 175 176 version(X86_64) { 177 printf("%s%s.%d | %s | %llu | %s | %s | %s:%llu%s\n", leadingColor.ptr, buf.ptr, 0, level.ptr, 178 getTid(), cast(cstring)func.ptr, msg, 179 cast(cstring)file.ptr, line, CONSOLE_COLOR_NONE.ptr); 180 } else { 181 printf("%s%s.%d | %s | %u | %s | %s | %s:%u%s\n", leadingColor.ptr, buf.ptr, 0, level.ptr, 182 getTid(), cast(cstring)func.ptr, msg, 183 cast(cstring)file.ptr, line, CONSOLE_COLOR_NONE.ptr); 184 } 185 186 } 187 188 } 189 } 190 } 191 192 private alias cstring = const(char)*; 193 194 extern(C) @nogc nothrow : // 195 196 197 version (Posix) { 198 import core.sys.posix.sys.types : pthread_t; 199 size_t syscall(size_t ident, ...); 200 201 ThreadID getTid() { 202 version(FreeBSD) { 203 long tid; 204 enum SYS_thr_self = 432; 205 syscall(SYS_thr_self, &tid); 206 return cast(ThreadID)tid; 207 } else version(OSX) { 208 enum SYS_thread_selfid = 372; 209 return cast(ThreadID)syscall(SYS_thread_selfid); 210 } else version(linux) { 211 enum __NR_gettid = 186; 212 return cast(ThreadID)syscall(__NR_gettid); 213 } else { 214 return 0; 215 } 216 } 217 218 // https://misc.flogisoft.com/bash/tip_colors_and_formatting 219 // https://solarianprogrammer.com/2019/04/08/c-programming-ansi-escape-codes-windows-macos-linux-terminals/ 220 // https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences?redirectedfrom=MSDN 221 enum CONSOLE_COLOR_NONE = "\033[m"; 222 enum CONSOLE_COLOR_RED = "\033[0;32;31m"; 223 enum CONSOLE_COLOR_GREEN = "\033[0;32;32m"; 224 enum CONSOLE_COLOR_YELLOW = "\033[1;33m"; 225 enum CONSOLE_COLOR_BLUE = "\033[34m"; 226 227 alias ThreadID = pthread_t; 228 229 } else { 230 231 import core.sys.windows.wincon; 232 import core.sys.windows.winbase; 233 import core.sys.windows.windef; 234 235 alias ThreadID = uint; 236 237 ThreadID getTid() { 238 return GetCurrentThreadId(); 239 } 240 }