blob: 8faa8b12db78527ddc1899361c4cb8b9e64fa5ae [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#include "UtilAll.h"
#include <chrono>
namespace rocketmq {
//<!************************************************************************
std::string UtilAll::s_localHostName;
std::string UtilAll::s_localIpAddress;
bool UtilAll::startsWith_retry(const string& topic) {
return topic.find(RETRY_GROUP_TOPIC_PREFIX) == 0;
}
string UtilAll::getRetryTopic(const string& consumerGroup) {
return RETRY_GROUP_TOPIC_PREFIX + consumerGroup;
}
void UtilAll::Trim(string& str) {
str.erase(0, str.find_first_not_of(' ')); // prefixing spaces
str.erase(str.find_last_not_of(' ') + 1); // surfixing spaces
}
bool UtilAll::isBlank(const string& str) {
if (str.empty()) {
return true;
}
string::size_type left = str.find_first_not_of(WHITESPACE);
if (left == string::npos) {
return true;
}
return false;
}
const int hex2int[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
-1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
uint64 UtilAll::hexstr2ull(const char* str) {
uint64 num = 0;
unsigned char* ch = (unsigned char*)str;
while (*ch != '\0') {
num = (num << 4) + hex2int[*ch];
ch++;
}
return num;
}
int64 UtilAll::str2ll(const char* str) {
return boost::lexical_cast<int64>(str);
}
string UtilAll::bytes2string(const char* bytes, int len) {
if (bytes == NULL || len <= 0) {
return string();
}
#ifdef WIN32
string buffer;
for (int i = 0; i < len; i++) {
char tmp[3];
sprintf(tmp, "%02X", (unsigned char)bytes[i]);
buffer.append(tmp);
}
return buffer;
#else
static const char hex_str[] = "0123456789ABCDEF";
char result[len * 2 + 1];
result[len * 2] = 0;
for (int i = 0; i < len; i++) {
result[i * 2 + 0] = hex_str[(bytes[i] >> 4) & 0x0F];
result[i * 2 + 1] = hex_str[(bytes[i]) & 0x0F];
}
string buffer(result);
return buffer;
#endif
}
bool UtilAll::SplitURL(const string& serverURL, string& addr, short& nPort) {
size_t pos = serverURL.find(':');
if (pos == string::npos) {
return false;
}
addr = serverURL.substr(0, pos);
if (0 == addr.compare("localhost")) {
addr = "127.0.0.1";
}
pos++;
string port = serverURL.substr(pos, serverURL.length() - pos);
nPort = atoi(port.c_str());
if (nPort == 0) {
return false;
}
return true;
}
int UtilAll::Split(vector<string>& ret_, const string& strIn, const char sep) {
if (strIn.empty())
return 0;
string tmp;
string::size_type pos_begin = strIn.find_first_not_of(sep);
string::size_type comma_pos = 0;
while (pos_begin != string::npos) {
comma_pos = strIn.find(sep, pos_begin);
if (comma_pos != string::npos) {
tmp = strIn.substr(pos_begin, comma_pos - pos_begin);
pos_begin = comma_pos + 1;
} else {
tmp = strIn.substr(pos_begin);
pos_begin = comma_pos;
}
if (!tmp.empty()) {
ret_.push_back(tmp);
tmp.clear();
}
}
return ret_.size();
}
int UtilAll::Split(vector<string>& ret_, const string& strIn, const string& sep) {
if (strIn.empty())
return 0;
string tmp;
string::size_type pos_begin = strIn.find_first_not_of(sep);
string::size_type comma_pos = 0;
while (pos_begin != string::npos) {
comma_pos = strIn.find(sep, pos_begin);
if (comma_pos != string::npos) {
tmp = strIn.substr(pos_begin, comma_pos - pos_begin);
pos_begin = comma_pos + sep.length();
} else {
tmp = strIn.substr(pos_begin);
pos_begin = comma_pos;
}
if (!tmp.empty()) {
ret_.push_back(tmp);
tmp.clear();
}
}
return ret_.size();
}
bool UtilAll::StringToInt32(const std::string& str, int32_t& out) {
out = 0;
if (str.empty()) {
return false;
}
char* end = NULL;
errno = 0;
long l = strtol(str.c_str(), &end, 10);
/* Both checks are needed because INT_MAX == LONG_MAX is possible. */
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
return false;
if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
return false;
if (*end != '\0')
return false;
out = l;
return true;
}
bool UtilAll::StringToInt64(const std::string& str, int64_t& val) {
char* endptr = NULL;
errno = 0; /* To distinguish success/failure after call */
val = strtoll(str.c_str(), &endptr, 10);
/* Check for various possible errors */
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) {
return false;
}
/*no digit was found Or Further characters after number*/
if (endptr == str.c_str()) {
return false;
}
/*no digit was found Or Further characters after number*/
if (*endptr != '\0') {
return false;
}
/* If we got here, strtol() successfully parsed a number */
return true;
}
string UtilAll::getLocalHostName() {
if (s_localHostName.empty()) {
// boost::system::error_code error;
// s_localHostName = boost::asio::ip::host_name(error);
char name[1024];
boost::system::error_code ec;
if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) {
return std::string();
}
s_localHostName.append(name, strlen(name));
}
return s_localHostName;
}
string UtilAll::getLocalAddress() {
if (s_localIpAddress.empty()) {
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(getLocalHostName(), "");
boost::system::error_code error;
boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query, error);
if (error) {
return "";
}
boost::asio::ip::tcp::resolver::iterator end; // End marker.
boost::asio::ip::tcp::endpoint ep;
while (iter != end) {
ep = *iter++;
}
s_localIpAddress = ep.address().to_string();
}
return s_localIpAddress;
}
string UtilAll::getHomeDirectory() {
#ifndef WIN32
char* homeEnv = getenv("HOME");
string homeDir;
if (homeEnv == NULL) {
homeDir.append(getpwuid(getuid())->pw_dir);
} else {
homeDir.append(homeEnv);
}
#else
string homeDir(getenv("USERPROFILE"));
#endif
return homeDir;
}
string UtilAll::getProcessName() {
#ifndef WIN32
char buf[PATH_MAX + 1] = {0};
int count = PATH_MAX + 1;
char procpath[PATH_MAX + 1] = {0};
sprintf(procpath, "/proc/%d/exe", getpid());
if (access(procpath, F_OK) == -1) {
return "";
}
int retval = readlink(procpath, buf, count - 1);
if ((retval < 0 || retval >= count - 1)) {
return "";
}
if (!strcmp(buf + retval - 10, " (deleted)"))
buf[retval - 10] = '\0'; // remove last " (deleted)"
else
buf[retval] = '\0';
char* process_name = strrchr(buf, '/');
if (process_name) {
return std::string(process_name + 1);
} else {
return "";
}
#else
TCHAR szFileName[MAX_PATH + 1];
GetModuleFileName(NULL, szFileName, MAX_PATH + 1);
return std::string(szFileName);
#endif
}
uint64_t UtilAll::currentTimeMillis() {
auto since_epoch =
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
return static_cast<uint64_t>(since_epoch.count());
}
uint64_t UtilAll::currentTimeSeconds() {
auto since_epoch =
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
return static_cast<uint64_t>(since_epoch.count());
}
bool UtilAll::deflate(std::string& input, std::string& out, int level) {
boost::iostreams::zlib_params zlibParams(level, boost::iostreams::zlib::deflated);
boost::iostreams::filtering_ostream compressingStream;
compressingStream.push(boost::iostreams::zlib_compressor(zlibParams));
compressingStream.push(boost::iostreams::back_inserter(out));
compressingStream << input;
boost::iostreams::close(compressingStream);
return true;
}
bool UtilAll::inflate(std::string& input, std::string& out) {
boost::iostreams::filtering_ostream decompressingStream;
decompressingStream.push(boost::iostreams::zlib_decompressor());
decompressingStream.push(boost::iostreams::back_inserter(out));
decompressingStream << input;
boost::iostreams::close(decompressingStream);
return true;
}
bool UtilAll::ReplaceFile(const std::string& from_path, const std::string& to_path) {
#ifdef WIN32
// Try a simple move first. It will only succeed when |to_path| doesn't
// already exist.
if (::MoveFile(from_path.c_str(), to_path.c_str()))
return true;
// Try the full-blown replace if the move fails, as ReplaceFile will only
// succeed when |to_path| does exist. When writing to a network share, we may
// not be able to change the ACLs. Ignore ACL errors then
// (REPLACEFILE_IGNORE_MERGE_ERRORS).
if (::ReplaceFile(to_path.c_str(), from_path.c_str(), NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) {
return true;
}
return false;
#else
if (rename(from_path.c_str(), to_path.c_str()) == 0)
return true;
return false;
#endif
}
std::map<std::string, std::string> UtilAll::ReadProperties(const std::string& path) {
std::map<std::string, std::string> property_map;
std::ifstream property_file;
property_file.open(path);
std::string line_buffer;
if (property_file.is_open()) {
while (!property_file.eof()) {
std::getline(property_file, line_buffer);
std::size_t pos{0};
pos = line_buffer.find('#');
if (pos != string::npos) {
line_buffer = line_buffer.substr(0, pos);
}
if (line_buffer.empty()) {
continue;
}
pos = line_buffer.find('=');
if (pos != string::npos) {
std::string key = boost::trim_copy(line_buffer.substr(0, pos));
std::string value = boost::trim_copy(line_buffer.substr(pos + 1));
property_map[key] = value;
}
}
}
return property_map;
}
} // namespace rocketmq