// // chat_client.cpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #include #include #include #include #include #include "StateMachineDim.h" #include "Configuration.h" #include "StateMachineConsole.h" #include "Shell.h" namespace ba = boost::asio; namespace bs = boost::system; namespace fs = boost::filesystem; namespace dummy = ba::placeholders; using boost::lexical_cast; using ba::deadline_timer; using ba::ip::tcp; using namespace std; #include "MessageDim.h" #include "Connection.h" #include "Time.h" #include "Event.h" #include "WindowLog.h" #include "tools.h" // CheckDim // ------------------------------------------------------------------------ template class LocalTemplate : public T { public: StateMachine *fImp; string fName; ostream &wout; LocalTemplate(const char *name, ostream &out) : T(name), fImp(0), fName(fs::path(name).filename()), wout(out) { } void SetCommands(StateMachineConsole &imp) { fImp = &imp; } char *Complete(const char *text, int state) { static vector::const_iterator pos; if (state==0) pos = fImp->GetListOfEvents().begin(); while (pos!=fImp->GetListOfEvents().end()) { char *rc = Readline::Compare((*(pos++))->GetName(), text); if (rc) return rc; } return 0; } //bool PrintGeneralHelp() //bool PrintKeyBindings() bool PrintCommands() { wout << endl << kBold << "List of commands:" << endl; fImp->PrintListOfEvents(wout); wout << endl; return true; } bool Process(const std::string &str) { if (T::Process(str)) return true; if (str=="test") { wout << "Test" << endl; return false; } Event evt(str); evt.SetInt(7); if (!fImp->ProcessCommand(evt)) { wout << kRed << "Unknown command '" << str << "' " << kReset << " (type l for a list of commands)." << endl; return true; } return false; } }; class LocalShell : public LocalTemplate { public: LocalShell(const char *name, bool = false) : LocalTemplate(name, win) { } string GetUpdatePrompt() const { int s = Shell::wout.GetSizeBacklog()/1000; char u = 'k'; if (s>999) { s/=1000; u = 'M'; } return Form("[%d:%d%c] %s:%s> ", GetLine(), s, u, fName.c_str(), fImp->GetStateName().c_str()); } void Run(const char * = 0) { win << kBlue << kBold << "You are on the " << fName << " terminal of the MCP -" << endl; win << kBlue << kBold << "the Master Control Program." << endl; win << endl; win << kBlue << kBold << "Hello Flynn..." << endl; win << endl; Shell::Run(); } }; class LocalConsole : public LocalTemplate { WindowLog fLog; bool fContinous; public: LocalConsole(const char *name, bool continous=false) : LocalTemplate(name, fLog), fContinous(continous) { fLog.SetNullOutput(); } string GetUpdatePrompt() const { if (fContinous) return Form("\n[%d] \033[34m%s\033[0m:\033[32m\033[1m%s\033[0m> ", GetLine(), fName.c_str(), fImp->GetStateName().c_str()); int s = fLog.GetSizeBacklog()/1000; char u = 'k'; if (s>999) { s/=1000; u = 'M'; } return Form("\n[%d:%d%c] \033[34m%s\033[0m:\033[32m\033[1m%s\033[0m> ", GetLine(), s, u, fName.c_str(), fImp->GetStateName().c_str()); } WindowLog &GetStreamOut() { return fLog; } WindowLog &GetStreamIn() { return fLog; } void EventHook() { if (fContinous) { if (fLog.GetSizeBacklog()>0) cout << "\r"; fLog.Display(true); } Readline::EventHook(); } void Shutdown(const char * =0) { fLog.Display(true); cout << endl; } void Run(const char * = 0) { cout << endl; cout << "\033[34mYou are on the " << fName << " terminal of the MCP -" << endl; cout << "the Master Control Program." << endl; cout << endl; cout << "Hello Flynn...\033[0m" << endl; cout << endl; Shutdown(); Readline::Run(); fLog.Display(); fLog.SetNullOutput(false); fLog.SetBacklog(false); } }; // ========================================================================= template class AutoScheduler : public T { bool fNextIsPreview; public: enum states_t { kSM_Scheduling=1, kSM_Comitting, }; int fSessionId; int Schedule() { stringstream str; str << "Scheduling started -> Preview (id=" << fSessionId << ")"; T::Message(str); usleep(3000000); T::Message("Scheduling done."); fSessionId = -1; bool error = false; return error ? T::kSM_Error : T::kSM_Ready; } int Commit() { stringstream str; str << "Comitting preview (id=" << fSessionId << ")"; T::Message(str); usleep(3000000); T::Message("Comitted."); fSessionId = -1; bool error = false; return error ? T::kSM_Error : T::kSM_Ready; } AutoScheduler(ostream &out=cout) : T(out, "SCHEDULER"), fNextIsPreview(true), fSessionId(-1) { AddStateName(kSM_Scheduling, "Scheduling"); AddStateName(kSM_Comitting, "Comitting"); AddTransition(kSM_Scheduling, "SCHEDULE", T::kSM_Ready); AddTransition(kSM_Comitting, "COMMIT", T::kSM_Ready); T::PrintListOfEvents(); } int Execute() { switch (T::GetCurrentState()) { case kSM_Scheduling: return Schedule(); case kSM_Comitting: return Commit(); } return T::GetCurrentState(); } int Transition(const Event &evt) { switch (evt.GetTargetState()) { case kSM_Scheduling: case kSM_Comitting: fSessionId = evt.GetInt(); break; } return evt.GetTargetState(); } int Configure(const Event &) { return T::GetCurrentState(); } }; // ------------------------------------------------------------------------ int RunDim(const char *prgname) { if (!CheckDim()) return -1; WindowLog wout; if (!wout.OpenLogFile(string(prgname)+".log")) wout << kRed << "ERROR - Couldn't open log-file: " << strerror(errno) << endl; // Start io_service.Run to use the StateMachineImp::Run() loop // Start io_service.run to only use the commandHandler command detaching AutoScheduler io_service(wout); io_service.Run(); return 0; } template int RunShell(const char *prgname, bool cont=false) { static T shell(prgname, cont); WindowLog &win = shell.GetStreamIn(); WindowLog &wout = shell.GetStreamOut(); if (!wout.OpenLogFile(string(prgname)+".log")) win << kRed << "ERROR - Couldn't open log-file: " << strerror(errno) << endl; AutoScheduler io_service(wout); shell.SetCommands(io_service); boost::thread t(boost::bind(&AutoScheduler::Run, &io_service)); shell.Run(); // Run the shell io_service.Stop(); // Signal Loop-thread to stop // io_service.Close(); // Obsolete, done by the destructor t.join(); return 0; } void SetupConfiguration(Configuration &conf) { po::options_description config("Configuration"); config.add_options() ("console,c", po_int(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)") ; conf.AddOptionsCommandline(config); } int main(int argc, char* argv[]) { Configuration conf(argv[0]); SetupConfiguration(conf); po::variables_map vm; try { vm = conf.Parse(argc, argv); } catch (std::exception &e) { po::multiple_occurrences *MO = dynamic_cast(&e); if (MO) cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl; else cout << "Error: " << e.what() << endl; cout << endl; return -1; } if (conf.HasHelp() || conf.HasPrint()) return -1; const bool dim = !conf.Has("console"); try { if (dim) return RunDim(argv[0]); else if (conf.GetInt("console")==0) return RunShell(argv[0]); else return RunShell(argv[0], conf.GetInt("console")!=1); // Now shutdown everything.... // io_service.Close(); // Is this needed at all? // io_service.Run(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } /* class FADctrlDim : public StateMachineFAD { public: FADctrlDim(const std::string &name="DATA_LOGGER", std::ostream &out=std::cout) : StateMachineFAD(out, name) { } }; class FADctrlLocalShell : public StateMachineFAD { public: ostream &win; FADctrlLocalShell(std::ostream &out, std::ostream &out2) : StateMachineFAD(out), win(out2) { } FADctrlLocalShell(std::ostream &out=std::cout) : StateMachineFAD(out), win(out) { } }; */