Merge pull request #5477 from heliclei/console-upload-file

CCConsole:support file upload via telnet console
This commit is contained in:
James Chen 2014-02-27 21:53:57 +08:00
commit b363751b1a
4 changed files with 269 additions and 58 deletions

View File

@ -105,6 +105,7 @@ static bool isFloat( std::string myString ) {
// Check the entire string was consumed and if either failbit or badbit is set
return iss.eof() && !iss.fail();
}
// helper free functions
// dprintf() is not defined in Android
@ -281,7 +282,7 @@ Console::Console()
{ "texture", "Flush or print the TextureCache info. Args: [flush | ] ", std::bind(&Console::commandTextures, this, std::placeholders::_1, std::placeholders::_2) },
{ "director", "director commands, type -h or [director help] to list supported directives", std::bind(&Console::commandDirector, this, std::placeholders::_1, std::placeholders::_2) },
{ "touch", "simulate touch event via console, type -h or [touch help] to list supported directives", std::bind(&Console::commandTouch, this, std::placeholders::_1, std::placeholders::_2) },
{ "upload", "upload file. Args: [filename filesize]", std::bind(&Console::commandUpload, this, std::placeholders::_1, std::placeholders::_2) },
};
;
@ -753,6 +754,22 @@ void Console::commandTouch(int fd, const std::string& args)
}
}
void Console::commandUpload(int fd, const std::string& args)
{
auto argv = split(args,' ');
if(argv.size() == 2)
{
_upload_file_name = argv[0];
_upload_file_size = std::atoi(argv[1].c_str());
_file_uploading = true;
}
else
{
const char msg[] = "upload: invalid arguments.\n";
send(fd, msg, sizeof(msg) - 1, 0);
}
}
bool Console::parseCommand(int fd)
{
char buf[512];
@ -832,6 +849,48 @@ ssize_t Console::readline(int fd, char* ptr, int maxlen)
return n;
}
ssize_t Console::readfile(int fd, std::string& file_name, int file_size)
{
ssize_t n, rc;
char c;
auto sharedFileUtils = FileUtils::getInstance();
std::string writablePath = sharedFileUtils->getWritablePath();
std::string fileName = writablePath+file_name;
FILE* fp = fopen(fileName.c_str(), "wb");
if(!fp)
{
const char err[] = "can't create file!\n";
send(fd, err, sizeof(err),0);
return 0;
}
// if (fp)
// {
// size_t ret = fwrite(szBuf, 1, strl6en(szBuf), fp);
// CCASSERT(ret != 0, "fwrite function returned zero value");
// fclose(fp);
// if (ret != 0)
// log("Writing file to writable path succeed.");
// }
for( n=0; n<file_size; n++ ) {
if( (rc = recv(fd, &c, 1, 0)) ==1 ) {
fwrite(&c, 1, 1, fp);
} else if( rc == 0 ) {
return 0;
} else if( errno == EINTR ) {
continue;
} else {
return -1;
}
}
fclose(fp);
return n;
}
void Console::addClient()
{
struct sockaddr client;
@ -910,10 +969,21 @@ void Console::loop()
/* data from client */
std::vector<int> to_remove;
for(const auto &fd: _fds) {
if(FD_ISSET(fd,&copy_set)) {
if( ! parseCommand(fd) ) {
if(FD_ISSET(fd,&copy_set))
{
if(!_file_uploading)
{
if( ! parseCommand(fd) )
{
to_remove.push_back(fd);
}
}
else
{
readfile(fd, _upload_file_name, _upload_file_size);
_file_uploading = false;
}
if(--nready <= 0)
break;
}

View File

@ -100,6 +100,7 @@ public:
protected:
void loop();
ssize_t readline(int fd, char *buf, int maxlen);
ssize_t readfile(int fd, std::string &file_name, int file_size);
bool parseCommand(int fd);
void addClient();
@ -115,6 +116,7 @@ protected:
void commandProjection(int fd, const std::string &args);
void commandDirector(int fd, const std::string &args);
void commandTouch(int fd, const std::string &args);
void commandUpload(int fd, const std::string &args);
// file descriptor: socket, console, etc.
int _listenfd;
int _maxfd;
@ -126,6 +128,10 @@ protected:
bool _running;
bool _endThread;
bool _file_uploading;
ssize_t _upload_file_size;
std::string _upload_file_name;
std::map<std::string, Command> _commands;
// strings generated by cocos2d sent to the remote console

View File

@ -24,17 +24,21 @@
#include "ConsoleTest.h"
#include "../testResource.h"
#include <stdio.h>
#include <stdlib.h>
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#else
#include <io.h>
#include <WS2tcpip.h>
#endif
//------------------------------------------------------------------
//
// EaseSpriteDemo
// ConsoleTest
//
//------------------------------------------------------------------
@ -42,8 +46,8 @@ static int sceneIdx = -1;
static std::function<Layer*()> createFunctions[] =
{
CL(ConsoleTCP),
CL(ConsoleCustomCommand),
CL(ConsoleUploadFile),
};
#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0]))
@ -126,37 +130,6 @@ void ConsoleTestScene::runThisTest()
Director::getInstance()->replaceScene(this);
}
//------------------------------------------------------------------
//
// ConsoleTCP
//
//------------------------------------------------------------------
ConsoleTCP::ConsoleTCP()
{
_console = Director::getInstance()->getConsole();
}
ConsoleTCP::~ConsoleTCP()
{
}
void ConsoleTCP::onEnter()
{
BaseTestConsole::onEnter();
_console->listenOnTCP(5678);
}
std::string ConsoleTCP::title() const
{
return "Console TCP";
}
std::string ConsoleTCP::subtitle() const
{
return "telnet localhost 5678";
}
//------------------------------------------------------------------
//
@ -166,6 +139,7 @@ std::string ConsoleTCP::subtitle() const
ConsoleCustomCommand::ConsoleCustomCommand()
{
_console = Director::getInstance()->getConsole();
static struct Console::Command commands[] = {
{"hello", "This is just a user generated command", [](int fd, const std::string& args) {
const char msg[] = "how are you?\nArguments passed: ";
@ -184,7 +158,6 @@ ConsoleCustomCommand::~ConsoleCustomCommand()
void ConsoleCustomCommand::onEnter()
{
BaseTestConsole::onEnter();
_console->listenOnTCP(5678);
}
std::string ConsoleCustomCommand::title() const
@ -196,3 +169,162 @@ std::string ConsoleCustomCommand::subtitle() const
{
return "telnet localhost 5678";
}
//------------------------------------------------------------------
//
// ConsoleUploadFile
//
//------------------------------------------------------------------
ConsoleUploadFile::ConsoleUploadFile()
{
srand (time(NULL));
int _id = rand()%100000;
char buf[32];
sprintf(buf, "%d", _id);
_target_file_name = std::string("grossini") + buf;
_src_file_path = FileUtils::getInstance()->fullPathForFilename(s_pathGrossini);
_thread = std::thread( &ConsoleUploadFile::uploadFile, this);
}
void ConsoleUploadFile::onEnter()
{
BaseTestConsole::onEnter();
}
ConsoleUploadFile::~ConsoleUploadFile()
{
_thread.join();
}
void ConsoleUploadFile::uploadFile()
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s, j;
/* Obtain address(es) matching host/port */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* stream socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2),&wsaData);
#endif
s = getaddrinfo("localhost", "5678", &hints, &result);
if (s != 0)
{
CCLOG("ConsoleUploadFile: getaddrinfo error");
return;
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
closesocket(sfd);
#else
close(sfd);
#endif
}
if (rp == NULL) { /* No address succeeded */
CCLOG("ConsoleUploadFile: could not connect!");
return;
}
freeaddrinfo(result); /* No longer needed */
FILE* fp = fopen(_src_file_path.c_str(), "rb");
if(!fp)
{
CCLOG("ConsoleUploadFile: could not open file %s", _src_file_path.c_str());
return;
}
//read file size
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fseek(fp, 0, SEEK_SET);
char sb[32];
sprintf(sb, "%d", size);
std::string tmp = "upload";
tmp += " ";
tmp += _target_file_name;
tmp += " ";
tmp += sb;
tmp += "\n";
char cmd[512];
strcpy(cmd, tmp.c_str());
send(sfd,cmd,strlen(cmd),0);
// allocate memory to contain the whole file:
char* buffer = (char*) malloc (sizeof(char)*size);
if (buffer == NULL)
{
CCLOG("ConsoleUploadFile: memory allocate error!");
return;
}
// copy the file into the buffer:
int ret = fread(buffer, 1, size, fp);
if (ret != size)
{
CCLOG("ConsoleUploadFile: read file: %s error!",_src_file_path.c_str());
return;
}
//send to console socket
for(int i = 0; i < size; i++)
{
send(sfd, &buffer[i], 1, 0);
}
// terminate
fclose (fp);
free (buffer);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
closesocket(sfd);
WSACleanup();
#else
close(sfd);
#endif
return;
}
std::string ConsoleUploadFile::title() const
{
return "Console UploadFile";
}
std::string ConsoleUploadFile::subtitle() const
{
auto sharedFileUtils = FileUtils::getInstance();
std::string writablePath = sharedFileUtils->getWritablePath();
return "file uploaded to:" + writablePath + _target_file_name;
}

View File

@ -45,31 +45,13 @@ public:
void backCallback(Ref* sender) override;
};
class ConsoleTCP : public BaseTestConsole
{
public:
CREATE_FUNC(ConsoleTCP);
void onEnter() override;
virtual std::string title() const override;
virtual std::string subtitle() const override;
protected:
ConsoleTCP();
virtual ~ConsoleTCP();
cocos2d::Console *_console;
private:
CC_DISALLOW_COPY_AND_ASSIGN(ConsoleTCP);
};
class ConsoleCustomCommand : public BaseTestConsole
{
public:
CREATE_FUNC(ConsoleCustomCommand);
void onEnter() override;
virtual void onEnter() override;
virtual std::string title() const override;
virtual std::string subtitle() const override;
@ -82,6 +64,27 @@ private:
CC_DISALLOW_COPY_AND_ASSIGN(ConsoleCustomCommand);
};
class ConsoleUploadFile : public BaseTestConsole
{
public:
CREATE_FUNC(ConsoleUploadFile);
virtual void onEnter() override;
virtual std::string title() const override;
virtual std::string subtitle() const override;
protected:
ConsoleUploadFile();
virtual ~ConsoleUploadFile();
void uploadFile();
std::string _src_file_path;
std::string _target_file_name;
std::thread _thread;
private:
CC_DISALLOW_COPY_AND_ASSIGN(ConsoleUploadFile);
};
class ConsoleTestScene : public TestScene
{
public: