ShellSession.cpp 5.36 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * MIT License
xzl committed
3
 *
xiongziliang committed
4
 * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
xiongziliang committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
xzl committed
25 26 27
 */

#include "ShellSession.h"
28
#include "Util/CMD.h"
xzl committed
29
#include "Util/onceToken.h"
30
#include "Util/NoticeCenter.h"
31 32
#include "Common/config.h"
#include "ShellCMD.h"
xiongziliang committed
33
using namespace toolkit;
xzl committed
34

xiongziliang committed
35
namespace mediakit {
xzl committed
36

37 38 39
static onceToken s_token([]() {
    REGIST_CMD(media);
}, nullptr);
40

xiongziliang committed
41
ShellSession::ShellSession(const Socket::Ptr &_sock) : TcpSession(_sock) {
xiongziliang committed
42
    DebugP(this);
43
    pleaseInputUser();
xzl committed
44 45 46
}

ShellSession::~ShellSession() {
xiongziliang committed
47
    DebugP(this);
xzl committed
48 49
}

50
void ShellSession::onRecv(const Buffer::Ptr&buf) {
xzl committed
51
	//DebugL << hexdump(buf->data(), buf->size());
52
    GET_CONFIG(uint32_t,maxReqSize,Shell::kMaxReqSize);
53
    if (_strRecvBuf.size() + buf->size() >= maxReqSize) {
xiongziliang committed
54
		shutdown(SockException(Err_other,"recv buffer overflow"));
xzl committed
55 56
		return;
	}
57 58 59
	_beatTicker.resetTime();
	_strRecvBuf.append(buf->data(), buf->size());
	if (_strRecvBuf.find("\xff\xf4\xff\0xfd\x06") != std::string::npos) {
xzl committed
60
		send("\033[0m\r\n	Bye bye!\r\n");
xiongziliang committed
61
		shutdown(SockException(Err_other,"received Ctrl+C"));
xzl committed
62 63 64 65
		return;
	}
	size_t index;
	string line;
66 67 68
	while ((index = _strRecvBuf.find("\r\n")) != std::string::npos) {
		line = _strRecvBuf.substr(0, index);
		_strRecvBuf.erase(0, index + 2);
69
		if (!onCommandLine(line)) {
xiongziliang committed
70
			shutdown(SockException(Err_other,"exit cmd"));
xzl committed
71 72 73 74 75
			return;
		}
	}
}

xiongziliang committed
76 77 78 79
void ShellSession::onError(const SockException &err){
    WarnP(this) << err.what();
}

xzl committed
80
void ShellSession::onManager() {
81
	if (_beatTicker.elapsedTime() > 1000 * 60 * 5) {
xzl committed
82
		//5 miniutes for alive
xiongziliang committed
83
        shutdown(SockException(Err_timeout,"session timeout"));
xzl committed
84 85 86 87
		return;
	}
}

88
inline bool ShellSession::onCommandLine(const string& line) {
89
    auto loginInterceptor = _loginInterceptor;
90 91
    if (loginInterceptor) {
		bool ret = loginInterceptor(line);
xzl committed
92 93
		return ret;
	}
94 95 96 97 98 99 100 101 102 103 104 105
    try {
        std::shared_ptr<stringstream> ss(new stringstream);
        CMDRegister::Instance()(line,ss);
        send(ss->str());
    }catch(ExitException &ex){
        return false;
    }catch(std::exception &ex){
        send(ex.what());
        send("\r\n");
    }
    printShellPrefix();
	return true;
xzl committed
106 107
}

108
inline void ShellSession::pleaseInputUser() {
xzl committed
109
	send("\033[0m");
110
	send(StrPrinter << SERVER_NAME << " login: " << endl);
111 112
	_loginInterceptor = [this](const string &user_name) {
		_strUserName=user_name;
113
        pleaseInputPasswd();
xzl committed
114 115 116
		return true;
	};
}
117
inline void ShellSession::pleaseInputPasswd() {
xzl committed
118
	send("Password: \033[8m");
119
	_loginInterceptor = [this](const string &passwd) {
120 121 122 123 124 125 126
        auto onAuth = [this](const string &errMessage){
            if(!errMessage.empty()){
                //鉴权失败
                send(StrPrinter
                     <<"\033[0mAuth failed("
                     << errMessage
                     <<"), please try again.\r\n"
127
                     <<_strUserName<<"@"<<SERVER_NAME
128 129 130 131 132 133 134 135 136
                     <<"'s password: \033[8m"
                     <<endl);
                return;
            }
            send("\033[0m");
            send("-----------------------------------------\r\n");
            send(StrPrinter<<"欢迎来到"<<SERVER_NAME<<", 你可输入\"help\"查看帮助.\r\n"<<endl);
            send("-----------------------------------------\r\n");
            printShellPrefix();
137
            _loginInterceptor=nullptr;
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
        };

        weak_ptr<ShellSession> weakSelf = dynamic_pointer_cast<ShellSession>(shared_from_this());
        Broadcast::AuthInvoker invoker = [weakSelf,onAuth](const string &errMessage){
            auto strongSelf =  weakSelf.lock();
            if(!strongSelf){
                return;
            }
            strongSelf->async([errMessage,weakSelf,onAuth](){
                auto strongSelf =  weakSelf.lock();
                if(!strongSelf){
                    return;
                }
                onAuth(errMessage);
            });
        };

155
        auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastShellLogin,_strUserName,passwd,invoker,*this);
156 157 158 159
        if(!flag){
            //如果无人监听shell登录事件,那么默认shell无法登录
            onAuth("please listen kBroadcastShellLogin event");
        }
xzl committed
160 161 162 163
		return true;
	};
}

164
inline void ShellSession::printShellPrefix() {
165
	send(StrPrinter << _strUserName << "@" << SERVER_NAME << "# " << endl);
xzl committed
166 167
}

xiongziliang committed
168
}/* namespace mediakit */