Improved console interface

This commit is contained in:
Thulinma 2017-03-29 12:03:15 +02:00
parent d352c74ad0
commit 831e454ebb
3 changed files with 80 additions and 54 deletions

View file

@ -77,6 +77,9 @@ static inline char yna(std::string & user_input){
case 'a': case 'A': case 'a': case 'A':
return 'a'; return 'a';
break; break;
case 't': case 'T':
return 't';
break;
default: default:
return 'x'; return 'x';
break; break;
@ -91,7 +94,7 @@ void createAccount (std::string account){
if (colon != std::string::npos && colon != 0 && colon != account.size()){ if (colon != std::string::npos && colon != 0 && colon != account.size()){
std::string uname = account.substr(0, colon); std::string uname = account.substr(0, colon);
std::string pword = account.substr(colon + 1, std::string::npos); std::string pword = account.substr(colon + 1, std::string::npos);
Controller::Log("CONF", "Created account " + uname + " through commandline option"); Controller::Log("CONF", "Created account " + uname + " through console interface");
Controller::Storage["account"][uname]["password"] = Secure::md5(pword); Controller::Storage["account"][uname]["password"] = Secure::md5(pword);
} }
} }
@ -155,6 +158,7 @@ void statusMonitor(void * np){
/// shutdown reason /// shutdown reason
/// ~~~~~~~~~~~~~~~ /// ~~~~~~~~~~~~~~~
int main_loop(int argc, char ** argv){ int main_loop(int argc, char ** argv){
Controller::isTerminal = Controller::isColorized = isatty(fileno(stdin));
Controller::Storage = JSON::fromFile("config.json"); Controller::Storage = JSON::fromFile("config.json");
JSON::Value stored_port = JSON::fromString("{\"long\":\"port\", \"short\":\"p\", \"arg\":\"integer\", \"help\":\"TCP port to listen on.\"}"); JSON::Value stored_port = JSON::fromString("{\"long\":\"port\", \"short\":\"p\", \"arg\":\"integer\", \"help\":\"TCP port to listen on.\"}");
stored_port["default"] = Controller::Storage["config"]["controller"]["port"]; stored_port["default"] = Controller::Storage["config"]["controller"]["port"];
@ -193,6 +197,7 @@ int main_loop(int argc, char ** argv){
DEBUG_MSG(DLVL_ERROR, "Could not redirect output to %s: %s",Controller::conf.getString("logfile").c_str(),strerror(errno)); DEBUG_MSG(DLVL_ERROR, "Could not redirect output to %s: %s",Controller::conf.getString("logfile").c_str(),strerror(errno));
return 7; return 7;
}else{ }else{
Controller::isTerminal = Controller::isColorized = false;
dup2(output,STDOUT_FILENO); dup2(output,STDOUT_FILENO);
dup2(output,STDERR_FILENO); dup2(output,STDERR_FILENO);
time_t rawtime; time_t rawtime;
@ -250,67 +255,73 @@ int main_loop(int argc, char ** argv){
createAccount(Controller::conf.getString("account")); createAccount(Controller::conf.getString("account"));
//if a terminal is connected and we're not logging to file //if a terminal is connected and we're not logging to file
if (isatty(fileno(stdin))){ if (Controller::isTerminal){
if (Controller::conf.getString("logfile") == ""){ //check for username
//check for username if ( !Controller::Storage.isMember("account") || Controller::Storage["account"].size() < 1){
if ( !Controller::Storage.isMember("account") || Controller::Storage["account"].size() < 1){ std::string in_string = "";
std::string in_string = ""; while(yna(in_string) == 'x'){
while(yna(in_string) == 'x'){ std::cout << "Account not set, do you want to create an account? (y)es, (n)o, (a)bort: ";
std::cout << "Account not set, do you want to create an account? (y)es, (n)o, (a)bort: "; std::cout.flush();
std::cout.flush(); std::getline(std::cin, in_string);
std::getline(std::cin, in_string); switch (yna(in_string)){
if (yna(in_string) == 'y'){ case 'y':{
//create account //create account
std::string usr_string = ""; std::string usr_string = "";
while(!(Controller::Storage.isMember("account") && Controller::Storage["account"].size() > 0)){ while(!(Controller::Storage.isMember("account") && Controller::Storage["account"].size() > 0)){
std::cout << "Please type in the username, a colon and a password in the following format; username:password" << std::endl << ": "; std::cout << "Please type in the username, a colon and a password in the following format; username:password" << std::endl << ": ";
std::cout.flush(); std::cout.flush();
std::getline(std::cin, usr_string); std::getline(std::cin, usr_string);
createAccount(usr_string); createAccount(usr_string);
}
}else if(yna(in_string) == 'a'){
//abort controller startup
return 0;
}
}
}
//check for protocols
if ( !Controller::Storage.isMember("config") || !Controller::Storage["config"].isMember("protocols") || Controller::Storage["config"]["protocols"].size() < 1){
std::string in_string = "";
while(yna(in_string) == 'x'){
std::cout << "Protocols not set, do you want to enable default protocols? (y)es, (n)o, (a)bort: ";
std::cout.flush();
std::getline(std::cin, in_string);
if (yna(in_string) == 'y'){
//create protocols
jsonForEach(Controller::capabilities["connectors"], it) {
if (!it->isMember("required")){
JSON::Value newProtocol;
newProtocol["connector"] = it.key();
Controller::Storage["config"]["protocols"].append(newProtocol);
} }
} }
}else if(yna(in_string) == 'a'){ break;
//abort controller startup case 'a': return 0; //abort bootup
return 0; case 't':
} createAccount("test:test");
break;
} }
} }
}else{//logfile is enabled }
//check for username //check for protocols
if ( !Controller::Storage.isMember("account") || Controller::Storage["account"].size() < 1){ if ( !Controller::Storage.isMember("config") || !Controller::Storage["config"].isMember("protocols") || Controller::Storage["config"]["protocols"].size() < 1){
std::cout << "No login configured. To create one, attempt to login through the web interface on port " << Controller::conf.getInteger("port") << " and follow the instructions." << std::endl; std::string in_string = "";
} while(yna(in_string) == 'x'){
//check for protocols std::cout << "Protocols not set, do you want to enable default protocols? (y)es, (n)o, (a)bort: ";
if ( !Controller::Storage.isMember("config") || !Controller::Storage["config"].isMember("protocols") || Controller::Storage["config"]["protocols"].size() < 1){ std::cout.flush();
std::cout << "No protocols enabled, remember to set them up through the web interface on port " << Controller::conf.getInteger("port") << " or API." << std::endl; std::getline(std::cin, in_string);
if (yna(in_string) == 'y'){
//create protocols
jsonForEach(Controller::capabilities["connectors"], it) {
if (!it->isMember("required")){
JSON::Value newProtocol;
newProtocol["connector"] = it.key();
Controller::Storage["config"]["protocols"].append(newProtocol);
}
}
}else if(yna(in_string) == 'a'){
//abort controller startup
return 0;
}
} }
} }
}
//Check if we have a usable server, if not, print messages with helpful hints
{
std::string web_port = JSON::Value((long long)Controller::conf.getInteger("port")).asString();
//check for username
if ( !Controller::Storage.isMember("account") || Controller::Storage["account"].size() < 1){
Controller::Log("CONF", "No login configured. To create one, attempt to login through the web interface on port "+web_port+" and follow the instructions.");
}
//check for protocols
if ( !Controller::Storage.isMember("config") || !Controller::Storage["config"].isMember("protocols") || Controller::Storage["config"]["protocols"].size() < 1){
Controller::Log("CONF", "No protocols enabled, remember to set them up through the web interface on port "+web_port+" or API.");
}
//check for streams - regardless of logfile setting //check for streams - regardless of logfile setting
if ( !Controller::Storage.isMember("streams") || Controller::Storage["streams"].size() < 1){ if ( !Controller::Storage.isMember("streams") || Controller::Storage["streams"].size() < 1){
std::cout << "No streams configured, remember to set up streams through the web interface on port " << Controller::conf.getInteger("port") << " or API." << std::endl; Controller::Log("CONF", "No streams configured, remember to set up streams through the web interface on port "+web_port+" or API.");
} }
}//connected to a terminal }
Controller::Log("CONF", "Controller started"); Controller::Log("CONF", "Controller started");
Controller::conf.activate();//activate early, so threads aren't killed. Controller::conf.activate();//activate early, so threads aren't killed.

View file

@ -20,12 +20,25 @@ namespace Controller{
unsigned long long logCounter = 0; unsigned long long logCounter = 0;
bool configChanged = false; bool configChanged = false;
bool restarting = false; bool restarting = false;
bool isTerminal = false;
bool isColorized = false;
///\brief Store and print a log message. ///\brief Store and print a log message.
///\param kind The type of message. ///\param kind The type of message.
///\param message The message to be logged. ///\param message The message to be logged.
void Log(std::string kind, std::string message){ void Log(std::string kind, std::string message){
tthread::lock_guard<tthread::mutex> guard(logMutex); tthread::lock_guard<tthread::mutex> guard(logMutex);
std::string color_time, color_msg, color_end;
if (Controller::isColorized){
color_end = "\033[0m";
color_time = "\033[2m";
color_msg = color_end;
if (kind == "CONF"){color_msg = "\033[0;1;37m";}
if (kind == "FAIL"){color_msg = "\033[0;1;31m";}
if (kind == "ERROR"){color_msg = "\033[0;31m";}
if (kind == "WARN"){color_msg = "\033[0;1;33m";}
if (kind == "INFO"){color_msg = "\033[0;36m";}
}
JSON::Value m; JSON::Value m;
m.append(Util::epoch()); m.append(Util::epoch());
m.append(kind); m.append(kind);
@ -38,7 +51,7 @@ namespace Controller{
time(&rawtime); time(&rawtime);
timeinfo = localtime(&rawtime); timeinfo = localtime(&rawtime);
strftime(buffer, 100, "%F %H:%M:%S", timeinfo); strftime(buffer, 100, "%F %H:%M:%S", timeinfo);
std::cout << "[" << buffer << "] " << kind << ": " << message << std::endl; std::cout << color_time << "[" << buffer << "] " << color_msg << kind << ": " << message << color_end << std::endl;
logCounter++; logCounter++;
} }

View file

@ -11,6 +11,8 @@ namespace Controller {
extern tthread::mutex configMutex;///< Mutex for server config access. extern tthread::mutex configMutex;///< Mutex for server config access.
extern bool configChanged; ///< Bool that indicates config must be written to SHM. extern bool configChanged; ///< Bool that indicates config must be written to SHM.
extern bool restarting;///< Signals if the controller is shutting down (false) or restarting (true). extern bool restarting;///< Signals if the controller is shutting down (false) or restarting (true).
extern bool isTerminal;///< True if connected to a terminal and not a log file.
extern bool isColorized;///< True if we colorize the output
extern unsigned long long logCounter; ///<Count of logged messages since boot extern unsigned long long logCounter; ///<Count of logged messages since boot
/// Store and print a log message. /// Store and print a log message.