File transfer WIP
This commit is contained in:
parent
ab83f7e5ca
commit
5f66d2eeb6
8
3rdparty/smallsha1/CMakeLists.txt
vendored
Normal file
8
3rdparty/smallsha1/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(smallsha1)
|
||||
set(SRCS
|
||||
smallsha1.cpp
|
||||
)
|
||||
add_library(smallsha1 STATIC ${SRCS})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x -g -O0 -Wall")
|
185
3rdparty/smallsha1/smallsha1.cpp
vendored
Normal file
185
3rdparty/smallsha1/smallsha1.cpp
vendored
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
Contributors:
|
||||
Gustav
|
||||
Several members in the gamedev.se forum.
|
||||
Gregory Petrosyan
|
||||
*/
|
||||
|
||||
#include "smallsha1.h"
|
||||
|
||||
namespace smallsha1
|
||||
{
|
||||
namespace // local
|
||||
{
|
||||
// Rotate an integer value to left.
|
||||
inline const unsigned int rol(const unsigned int value,
|
||||
const unsigned int steps)
|
||||
{
|
||||
return ((value << steps) | (value >> (32 - steps)));
|
||||
}
|
||||
|
||||
// Sets the first 16 integers in the buffert to zero.
|
||||
// Used for clearing the W buffert.
|
||||
inline void clearWBuffert(unsigned int* buffert)
|
||||
{
|
||||
for (int pos = 16; --pos >= 0;)
|
||||
{
|
||||
buffert[pos] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void innerHash(unsigned int* result, unsigned int* w)
|
||||
{
|
||||
unsigned int a = result[0];
|
||||
unsigned int b = result[1];
|
||||
unsigned int c = result[2];
|
||||
unsigned int d = result[3];
|
||||
unsigned int e = result[4];
|
||||
|
||||
int round = 0;
|
||||
|
||||
#define sha1macro(func,val) \
|
||||
{ \
|
||||
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
|
||||
e = d; \
|
||||
d = c; \
|
||||
c = rol(b, 30); \
|
||||
b = a; \
|
||||
a = t; \
|
||||
}
|
||||
|
||||
while (round < 16)
|
||||
{
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 20)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 40)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0x6ed9eba1)
|
||||
++round;
|
||||
}
|
||||
while (round < 60)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
|
||||
++round;
|
||||
}
|
||||
while (round < 80)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0xca62c1d6)
|
||||
++round;
|
||||
}
|
||||
|
||||
#undef sha1macro
|
||||
|
||||
result[0] += a;
|
||||
result[1] += b;
|
||||
result[2] += c;
|
||||
result[3] += d;
|
||||
result[4] += e;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash)
|
||||
{
|
||||
// Init the result array.
|
||||
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
|
||||
|
||||
// Cast the void src pointer to be the byte array we can work with.
|
||||
const unsigned char* sarray = (const unsigned char*) src;
|
||||
|
||||
// The reusable round buffer
|
||||
unsigned int w[80];
|
||||
|
||||
// Loop through all complete 64byte blocks.
|
||||
const int endOfFullBlocks = bytelength - 64;
|
||||
int endCurrentBlock;
|
||||
int currentBlock = 0;
|
||||
|
||||
while (currentBlock <= endOfFullBlocks)
|
||||
{
|
||||
endCurrentBlock = currentBlock + 64;
|
||||
|
||||
// Init the round buffer with the 64 byte block data.
|
||||
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
|
||||
{
|
||||
// This line will swap endian on big endian and keep endian on little endian.
|
||||
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
|
||||
| (((unsigned int) sarray[currentBlock + 2]) << 8)
|
||||
| (((unsigned int) sarray[currentBlock + 1]) << 16)
|
||||
| (((unsigned int) sarray[currentBlock]) << 24);
|
||||
}
|
||||
innerHash(result, w);
|
||||
}
|
||||
|
||||
// Handle the last and not full 64 byte block if existing.
|
||||
endCurrentBlock = bytelength - currentBlock;
|
||||
clearWBuffert(w);
|
||||
int lastBlockBytes = 0;
|
||||
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
|
||||
{
|
||||
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
}
|
||||
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
if (endCurrentBlock >= 56)
|
||||
{
|
||||
innerHash(result, w);
|
||||
clearWBuffert(w);
|
||||
}
|
||||
w[15] = bytelength << 3;
|
||||
innerHash(result, w);
|
||||
|
||||
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void toHexString(const unsigned char* hash, char* hexstring)
|
||||
{
|
||||
const char hexDigits[] = { "0123456789abcdef" };
|
||||
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
|
||||
hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
|
||||
}
|
||||
hexstring[40] = 0;
|
||||
}
|
||||
} // namespace sha1
|
49
3rdparty/smallsha1/smallsha1.h
vendored
Normal file
49
3rdparty/smallsha1/smallsha1.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Micael Hildenborg nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_DEFINED
|
||||
#define SHA1_DEFINED
|
||||
|
||||
namespace smallsha1
|
||||
{
|
||||
|
||||
/**
|
||||
@param src points to any kind of data to be hashed.
|
||||
@param bytelength the number of bytes to hash from the src pointer.
|
||||
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
|
||||
*/
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash);
|
||||
|
||||
/**
|
||||
@param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
|
||||
@param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
|
||||
*/
|
||||
void toHexString(const unsigned char* hash, char* hexstring);
|
||||
|
||||
} // namespace sha1
|
||||
|
||||
#endif // SHA1_DEFINED
|
@ -7,6 +7,12 @@ project(buildat)
|
||||
|
||||
add_subdirectory("3rdparty/cereal")
|
||||
add_subdirectory("3rdparty/c55lib")
|
||||
add_subdirectory("3rdparty/smallsha1")
|
||||
|
||||
include_directories("src")
|
||||
include_directories("3rdparty/cereal/include")
|
||||
include_directories("3rdparty/c55lib")
|
||||
include_directories("3rdparty/smallsha1")
|
||||
|
||||
#
|
||||
# Polycode
|
||||
@ -45,10 +51,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
# Security / crash protection
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-all")
|
||||
|
||||
include_directories("src")
|
||||
include_directories("3rdparty/c55lib")
|
||||
include_directories("3rdparty/cereal/include")
|
||||
|
||||
# Client
|
||||
set(CLIENT_EXE_NAME buildat_client)
|
||||
set(CLIENT_SRCS
|
||||
@ -57,11 +59,13 @@ set(CLIENT_SRCS
|
||||
src/client/app.cpp
|
||||
src/core/log.cpp
|
||||
src/impl/tcpsocket.cpp
|
||||
src/impl/sha1.cpp
|
||||
)
|
||||
add_executable(${CLIENT_EXE_NAME} ${CLIENT_SRCS})
|
||||
TARGET_LINK_LIBRARIES(${CLIENT_EXE_NAME}
|
||||
${POLYCODE_DEPENDENCY_LIBS}
|
||||
c55lib
|
||||
smallsha1
|
||||
)
|
||||
|
||||
# Server
|
||||
@ -76,10 +80,12 @@ set(SERVER_SRCS
|
||||
src/impl/tcpsocket.cpp
|
||||
src/impl/module.cpp
|
||||
src/impl/linux/file_watch.cpp
|
||||
src/impl/sha1.cpp
|
||||
)
|
||||
add_executable(${SERVER_EXE_NAME} ${SERVER_SRCS})
|
||||
TARGET_LINK_LIBRARIES(${SERVER_EXE_NAME}
|
||||
c55lib
|
||||
smallsha1
|
||||
dl
|
||||
)
|
||||
add_definitions()
|
||||
|
12
share/builtin/client_file/boot.lua
Normal file
12
share/builtin/client_file/boot.lua
Normal file
@ -0,0 +1,12 @@
|
||||
-- Buildat: client_lua/boot.lua
|
||||
local log = buildat:Logger("client_lua")
|
||||
log:info("boot.lua loaded")
|
||||
|
||||
-- Temporary test
|
||||
require "Polycode/Core"
|
||||
scene = Scene(Scene.SCENE_2D)
|
||||
scene:getActiveCamera():setOrthoSize(640, 480)
|
||||
label = SceneLabel("Hello from remote module!", 32)
|
||||
label:setPosition(0, -100, 0)
|
||||
scene:addChild(label)
|
||||
|
140
share/builtin/client_file/client_file.cpp
Normal file
140
share/builtin/client_file/client_file.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include "core/log.h"
|
||||
#include "interface/module.h"
|
||||
#include "interface/server.h"
|
||||
#include "interface/event.h"
|
||||
#include "interface/fs.h"
|
||||
#include "interface/sha1.h"
|
||||
#include "client_file/include/api.h"
|
||||
#include "network/include/api.h"
|
||||
#include <cereal/archives/binary.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
|
||||
using interface::Event;
|
||||
|
||||
struct FileInfo {
|
||||
ss_ name;
|
||||
ss_ content;
|
||||
ss_ hash;
|
||||
FileInfo(const ss_ &name, const ss_ &content, const ss_ &hash):
|
||||
name(name), content(content), hash(hash){}
|
||||
};
|
||||
|
||||
namespace client_file {
|
||||
|
||||
struct Module: public interface::Module, public client_file::Interface
|
||||
{
|
||||
interface::Server *m_server;
|
||||
sm_<ss_, sp_<FileInfo>> m_files;
|
||||
|
||||
Module(interface::Server *server):
|
||||
m_server(server),
|
||||
interface::Module("client_file")
|
||||
{
|
||||
log_v(MODULE, "client_file construct");
|
||||
}
|
||||
|
||||
~Module()
|
||||
{
|
||||
log_v(MODULE, "client_file destruct");
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
log_v(MODULE, "client_file init");
|
||||
m_server->sub_event(this, Event::t("core:start"));
|
||||
m_server->sub_event(this, Event::t("network:new_client"));
|
||||
}
|
||||
|
||||
void event(const Event::Type &type, const Event::Private *p)
|
||||
{
|
||||
EVENT_VOIDN("core:start", on_start)
|
||||
EVENT_TYPEN("network:new_client", on_new_client, network::NewClient)
|
||||
}
|
||||
|
||||
void on_start()
|
||||
{
|
||||
}
|
||||
|
||||
void on_new_client(const network::NewClient &new_client)
|
||||
{
|
||||
log_i(MODULE, "client_file::on_new_client: id=%zu", new_client.info.id);
|
||||
|
||||
// Tell file hashes to client
|
||||
for(auto &pair : m_files){
|
||||
const FileInfo &info = *pair.second.get();
|
||||
std::ostringstream os(std::ios::binary);
|
||||
{
|
||||
cereal::BinaryOutputArchive ar(os);
|
||||
ar(info.name);
|
||||
ar(info.hash);
|
||||
}
|
||||
network::access(m_server, [&](network::Interface * inetwork){
|
||||
inetwork->send(new_client.info.id, "core:announce_file", os.str());
|
||||
});
|
||||
}
|
||||
m_server->emit_event(ss_()+"client_file:files_sent",
|
||||
new FilesSent(new_client.info.id));
|
||||
|
||||
#if 0
|
||||
sv_<ss_> module_names = m_server->get_loaded_modules();
|
||||
|
||||
for(const ss_ &module_name : module_names){
|
||||
ss_ module_path = m_server->get_module_path(module_name);
|
||||
ss_ client_file_path = module_path+"/client_file";
|
||||
auto list = interface::getGlobalFilesystem()->list_directory(client_file_path);
|
||||
|
||||
sv_<ss_> log_list;
|
||||
for(const interface::Filesystem::Node &n : list){
|
||||
if(n.is_directory)
|
||||
continue;
|
||||
log_list.push_back(n.name);
|
||||
}
|
||||
log_i(MODULE, "client_file: %s: %s", cs(module_name), cs(dump(log_list)));
|
||||
|
||||
for(const interface::Filesystem::Node &n : list){
|
||||
if(n.is_directory)
|
||||
continue;
|
||||
std::ifstream f(client_file_path+"/"+n.name);
|
||||
std::string file_content((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
std::ostringstream os(std::ios::binary);
|
||||
{
|
||||
cereal::BinaryOutputArchive ar(os);
|
||||
ar(n.name);
|
||||
ar(file_content);
|
||||
}
|
||||
network::access(m_server, [&](network::Interface * inetwork){
|
||||
inetwork->send(new_client.info.id, "core:cache_file", os.str());
|
||||
});
|
||||
}
|
||||
m_server->emit_event(ss_()+"client_file:files_sent:"+module_name,
|
||||
new FilesSent(new_client.info.id));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
void add_file_content(const ss_ &name, const ss_ &content)
|
||||
{
|
||||
ss_ hash = interface::sha1::calculate(content);
|
||||
log_v(MODULE, "File: %s: %s", cs(name),
|
||||
cs(interface::sha1::hex(hash)));
|
||||
m_files[name] = up_<FileInfo>(new FileInfo(name, content, hash));
|
||||
}
|
||||
|
||||
void* get_interface()
|
||||
{
|
||||
return dynamic_cast<Interface*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
EXPORT void* createModule_client_file(interface::Server *server){
|
||||
return (void*)(new Module(server));
|
||||
}
|
||||
}
|
||||
}
|
26
share/builtin/client_file/include/api.h
Normal file
26
share/builtin/client_file/include/api.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "interface/event.h"
|
||||
#include "network/include/api.h"
|
||||
|
||||
namespace client_file
|
||||
{
|
||||
struct FilesSent: public interface::Event::Private
|
||||
{
|
||||
network::PeerInfo::Id recipient;
|
||||
|
||||
FilesSent(const network::PeerInfo::Id &recipient): recipient(recipient){}
|
||||
};
|
||||
|
||||
struct Interface
|
||||
{
|
||||
virtual void add_file_content(const ss_ &name, const ss_ &content) = 0;
|
||||
};
|
||||
|
||||
inline bool access(interface::Server *server,
|
||||
std::function<void(client_file::Interface*)> cb)
|
||||
{
|
||||
return server->access_module("client_file", [&](interface::Module * module){
|
||||
cb((client_file::Interface*)module->check_interface());
|
||||
});
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
#include "interface/server.h"
|
||||
#include "interface/event.h"
|
||||
#include "interface/fs.h"
|
||||
#include "client_file/include/api.h"
|
||||
#include "client_lua/include/api.h"
|
||||
#include "network/include/api.h"
|
||||
#include <cereal/archives/binary.hpp>
|
||||
@ -34,12 +35,18 @@ struct Module: public interface::Module
|
||||
{
|
||||
log_v(MODULE, "client_lua init");
|
||||
m_server->sub_event(this, Event::t("core:start"));
|
||||
m_server->sub_event(this, Event::t("core:module_loaded"));
|
||||
m_server->sub_event(this, Event::t("core:module_unloaded"));
|
||||
m_server->sub_event(this, Event::t("network:new_client"));
|
||||
}
|
||||
|
||||
void event(const Event::Type &type, const Event::Private *p)
|
||||
{
|
||||
EVENT_VOIDN("core:start", on_start)
|
||||
EVENT_TYPEN("core:module_loaded", on_module_loaded,
|
||||
interface::ModuleLoadedEvent)
|
||||
EVENT_TYPEN("core:module_unloaded", on_module_unloaded,
|
||||
interface::ModuleUnloadedEvent)
|
||||
EVENT_TYPEN("network:new_client", on_new_client, network::NewClient)
|
||||
}
|
||||
|
||||
@ -47,12 +54,51 @@ struct Module: public interface::Module
|
||||
{
|
||||
}
|
||||
|
||||
void on_module_loaded(const interface::ModuleLoadedEvent &event)
|
||||
{
|
||||
log_v(MODULE, "on_module_loaded(): %s", cs(event.name));
|
||||
ss_ module_name = event.name;
|
||||
ss_ module_path = m_server->get_module_path(module_name);
|
||||
ss_ client_lua_path = module_path+"/client_lua";
|
||||
auto list = interface::getGlobalFilesystem()
|
||||
->list_directory(client_lua_path);
|
||||
|
||||
sv_<ss_> log_list;
|
||||
for(const interface::Filesystem::Node &n : list){
|
||||
if(n.is_directory)
|
||||
continue;
|
||||
log_list.push_back(n.name);
|
||||
}
|
||||
log_i(MODULE, "client_lua: %s: %s", cs(module_name), cs(dump(log_list)));
|
||||
|
||||
for(const interface::Filesystem::Node &n : list){
|
||||
if(n.is_directory)
|
||||
continue;
|
||||
const ss_ &file_name = n.name;
|
||||
std::ifstream f(client_lua_path+"/"+file_name);
|
||||
std::string file_content((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
client_file::access(m_server, [&](client_file::Interface * i){
|
||||
i->add_file_content(file_name, file_content);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void on_module_unloaded(const interface::ModuleUnloadedEvent &event)
|
||||
{
|
||||
log_v(MODULE, "on_module_unloaded(): %s", cs(event.name));
|
||||
// TODO
|
||||
}
|
||||
|
||||
void on_new_client(const network::NewClient &new_client)
|
||||
{
|
||||
log_i(MODULE, "client_lua::on_new_client: id=%zu", new_client.info.id);
|
||||
|
||||
ss_ module_path = m_server->get_module_path(MODULE);
|
||||
|
||||
#if 0
|
||||
// Not sure what this is useful for
|
||||
std::ifstream f(module_path+"/boot.lua");
|
||||
std::string script_content((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
@ -60,13 +106,15 @@ struct Module: public interface::Module
|
||||
network::access(m_server, [&](network::Interface * inetwork){
|
||||
inetwork->send(new_client.info.id, "core:run_script", script_content);
|
||||
});
|
||||
|
||||
#endif
|
||||
#if 0
|
||||
sv_<ss_> module_names = m_server->get_loaded_modules();
|
||||
|
||||
for(const ss_ &module_name : module_names){
|
||||
ss_ module_path = m_server->get_module_path(module_name);
|
||||
ss_ client_lua_path = module_path+"/client_lua";
|
||||
auto list = interface::getGlobalFilesystem()->list_directory(client_lua_path);
|
||||
auto list = interface::getGlobalFilesystem()
|
||||
->list_directory(client_lua_path);
|
||||
|
||||
sv_<ss_> log_list;
|
||||
for(const interface::Filesystem::Node &n : list){
|
||||
@ -96,6 +144,7 @@ struct Module: public interface::Module
|
||||
m_server->emit_event(ss_()+"client_lua:files_sent:"+module_name,
|
||||
new FilesSent(new_client.info.id));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,15 +1,6 @@
|
||||
#pragma once
|
||||
#include "interface/event.h"
|
||||
#include "network/include/api.h"
|
||||
|
||||
namespace client_lua
|
||||
{
|
||||
struct FilesSent: public interface::Event::Private
|
||||
{
|
||||
network::PeerInfo::Id recipient;
|
||||
|
||||
FilesSent(const network::PeerInfo::Id &recipient): recipient(recipient){}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,11 +95,6 @@ struct Module: public interface::Module, public network::Interface
|
||||
EVENT_TYPEN("network:incoming_data", on_incoming_data, interface::SocketEvent)
|
||||
}
|
||||
|
||||
void* get_interface()
|
||||
{
|
||||
return dynamic_cast<Interface*>(this);
|
||||
}
|
||||
|
||||
void on_start()
|
||||
{
|
||||
ss_ address = "any4";
|
||||
@ -257,6 +252,11 @@ struct Module: public interface::Module, public network::Interface
|
||||
{
|
||||
send(recipient, m_packet_types.get(name), data);
|
||||
}
|
||||
|
||||
void* get_interface()
|
||||
{
|
||||
return dynamic_cast<Interface*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
@ -8,5 +8,6 @@ namespace client
|
||||
ss_ server_address;
|
||||
ss_ polycode_path = "/home/celeron55/softat/polycode/";
|
||||
ss_ share_path = "../share";
|
||||
ss_ cache_path = "../cache";
|
||||
};
|
||||
}
|
||||
|
@ -47,13 +47,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
client::Config &config = g_client_config;
|
||||
|
||||
const char opts[100] = "hs:p:P:";
|
||||
const char opts[100] = "hs:p:P:C:";
|
||||
const char usagefmt[1000] =
|
||||
"Usage: %s [OPTION]...\n"
|
||||
" -h Show this help\n"
|
||||
" -s [address] Specify server address\n"
|
||||
" -p [polycode_path] Specify polycode path\n"
|
||||
" -P [share_path] Specify share/ path\n"
|
||||
" -C [cache_path] Specify cache/ path\n"
|
||||
;
|
||||
|
||||
int c;
|
||||
@ -76,6 +77,10 @@ int main(int argc, char *argv[])
|
||||
fprintf(stderr, "INFO: config.share_path: %s\n", c55_optarg);
|
||||
config.share_path = c55_optarg;
|
||||
break;
|
||||
case 'C':
|
||||
fprintf(stderr, "INFO: config.cache_path: %s\n", c55_optarg);
|
||||
config.cache_path = c55_optarg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: Invalid command-line argument\n");
|
||||
fprintf(stderr, usagefmt, argv[0]);
|
||||
|
@ -1,14 +1,18 @@
|
||||
#include "core/log.h"
|
||||
#include "client/state.h"
|
||||
#include "client/app.h"
|
||||
#include "client/config.h"
|
||||
#include "interface/tcpsocket.h"
|
||||
//#include <cereal/archives/binary.hpp>
|
||||
//#include <cereal/types/string.hpp>
|
||||
#include <cereal/archives/binary.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
#include <sys/socket.h>
|
||||
#define MODULE "__state"
|
||||
|
||||
extern client::Config g_client_config;
|
||||
|
||||
namespace client {
|
||||
|
||||
struct ClientPacketTypeRegistry
|
||||
@ -79,10 +83,10 @@ struct CState: public State
|
||||
if(r == -1)
|
||||
throw Exception(ss_()+"Receive failed: "+strerror(errno));
|
||||
if(r == 0){
|
||||
log_i(MODULE, "Peer disconnected");
|
||||
log_w(MODULE, "Peer disconnected");
|
||||
return;
|
||||
}
|
||||
log_i(MODULE, "Received %zu bytes", r);
|
||||
log_d(MODULE, "Received %zu bytes", r);
|
||||
m_socket_buffer.insert(m_socket_buffer.end(), buf, buf + r);
|
||||
}
|
||||
|
||||
@ -99,10 +103,10 @@ struct CState: public State
|
||||
(m_socket_buffer[3] & 0xff)<<8 |
|
||||
(m_socket_buffer[4] & 0xff)<<16 |
|
||||
(m_socket_buffer[5] & 0xff)<<24;
|
||||
log_i(MODULE, "size=%zu", size);
|
||||
log_d(MODULE, "size=%zu", size);
|
||||
if(m_socket_buffer.size() < 6 + size)
|
||||
return;
|
||||
log_i(MODULE, "Received full packet; type=%zu, length=6+%zu",
|
||||
log_v(MODULE, "Received full packet; type=%zu, length=6+%zu",
|
||||
type, size);
|
||||
ss_ data(m_socket_buffer.begin() + 6, m_socket_buffer.begin() + 6 + size);
|
||||
m_socket_buffer.erase(m_socket_buffer.begin(),
|
||||
@ -145,6 +149,38 @@ struct CState: public State
|
||||
m_app->run_script(data);
|
||||
return;
|
||||
}
|
||||
if(packet_name == "core:announce_file"){
|
||||
ss_ file_name;
|
||||
ss_ file_hash;
|
||||
std::istringstream is(data, std::ios::binary);
|
||||
{
|
||||
cereal::BinaryInputArchive ar(is);
|
||||
ar(file_name);
|
||||
ar(file_hash);
|
||||
}
|
||||
// TODO: Check if we already have this file
|
||||
ss_ path = g_client_config.cache_path+"/remote/"+file_hash;
|
||||
std::ifstream is(path, std::ios::binary);
|
||||
if(is.good()){
|
||||
// We have it; no need to ask this file
|
||||
} else {
|
||||
// We don't have it; request this file
|
||||
}
|
||||
}
|
||||
if(packet_name == "core:transfer_file"){
|
||||
ss_ file_name;
|
||||
ss_ file_content;
|
||||
std::istringstream is(data, std::ios::binary);
|
||||
{
|
||||
cereal::BinaryInputArchive ar(is);
|
||||
ar(file_name);
|
||||
ar(file_content);
|
||||
}
|
||||
// TODO: Check filename for malicious characters "/.\"\\"
|
||||
ss_ path = g_client_config.cache_path+"/remote/"+file_name;
|
||||
std::ofstream of(path, std::ios::binary);
|
||||
of<<file_content;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
24
src/impl/sha1.cpp
Normal file
24
src/impl/sha1.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "core/types.h"
|
||||
#include <smallsha1.h>
|
||||
|
||||
namespace interface {
|
||||
namespace sha1 {
|
||||
|
||||
ss_ calculate(const ss_ &data)
|
||||
{
|
||||
unsigned char result[20];
|
||||
smallsha1::calc(data.c_str(), data.size(), result);
|
||||
return ss_((char*)result, 20);
|
||||
}
|
||||
|
||||
ss_ hex(const ss_ &raw)
|
||||
{
|
||||
if(raw.size() != 20)
|
||||
throw Exception("interface::sha1::hex() only accepts raw.size()=20");
|
||||
char result[41];
|
||||
smallsha1::toHexString((const unsigned char*)raw.c_str(), result);
|
||||
return ss_(result, 40);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -24,6 +24,16 @@ namespace interface
|
||||
name(name), path(path){}
|
||||
};
|
||||
|
||||
struct ModuleLoadedEvent: public interface::Event::Private {
|
||||
ss_ name;
|
||||
ModuleLoadedEvent(const ss_ &name): name(name){}
|
||||
};
|
||||
|
||||
struct ModuleUnloadedEvent: public interface::Event::Private {
|
||||
ss_ name;
|
||||
ModuleUnloadedEvent(const ss_ &name): name(name){}
|
||||
};
|
||||
|
||||
struct Server
|
||||
{
|
||||
virtual ~Server(){}
|
||||
|
11
src/interface/sha1.h
Normal file
11
src/interface/sha1.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "core/types.h"
|
||||
|
||||
namespace interface
|
||||
{
|
||||
namespace sha1
|
||||
{
|
||||
ss_ calculate(const ss_ &data);
|
||||
ss_ hex(const ss_ &raw);
|
||||
}
|
||||
}
|
@ -127,6 +127,9 @@ struct CState: public State, public interface::Server
|
||||
interface::MutexScope ms2(mc.mutex);
|
||||
mc.module->init();
|
||||
}
|
||||
|
||||
emit_event(Event("core:module_loaded",
|
||||
new interface::ModuleLoadedEvent(module_name)));
|
||||
}
|
||||
|
||||
void load_modules(const ss_ &path)
|
||||
@ -207,6 +210,9 @@ struct CState: public State, public interface::Server
|
||||
delete mc->module;
|
||||
m_modules.erase(module_name);
|
||||
m_compiler->unload(module_name);
|
||||
|
||||
emit_event(Event("core:module_unloaded",
|
||||
new interface::ModuleUnloadedEvent(module_name)));
|
||||
}
|
||||
|
||||
ss_ get_modules_path()
|
||||
|
@ -42,6 +42,7 @@ struct Module: public interface::Module
|
||||
{
|
||||
ss_ builtin = m_server->get_builtin_modules_path();
|
||||
m_server->load_module("network", builtin+"/network");
|
||||
m_server->load_module("client_file", builtin+"/client_file");
|
||||
m_server->load_module("client_lua", builtin+"/client_lua");
|
||||
|
||||
sv_<ss_> load_list = {
|
||||
|
@ -2,7 +2,8 @@
|
||||
#include "interface/server.h"
|
||||
#include "interface/event.h"
|
||||
#include "test1/include/api.h"
|
||||
#include "client_lua/include/api.h"
|
||||
//#include "client_lua/include/api.h"
|
||||
#include "client_file/include/api.h"
|
||||
#include "network/include/api.h"
|
||||
#include "core/log.h"
|
||||
|
||||
@ -35,7 +36,7 @@ struct Module: public interface::Module
|
||||
m_server->sub_event(this, Event::t("core:start"));
|
||||
m_server->sub_event(this, m_EventType_test1_thing);
|
||||
m_server->sub_event(this, Event::t("network:new_client"));
|
||||
m_server->sub_event(this, Event::t("client_lua:files_sent:test1"));
|
||||
m_server->sub_event(this, Event::t("client_file:files_sent"));
|
||||
m_server->sub_event(this, Event::t("network:packet_received"));
|
||||
}
|
||||
|
||||
@ -44,8 +45,8 @@ struct Module: public interface::Module
|
||||
EVENT_VOIDN("core:start", on_start)
|
||||
EVENT_TYPE(m_EventType_test1_thing, on_thing, Thing)
|
||||
EVENT_TYPEN("network:new_client", on_new_client, network::NewClient)
|
||||
EVENT_TYPEN("client_lua:files_sent:test1", on_lua_files_sent,
|
||||
client_lua::FilesSent)
|
||||
EVENT_TYPEN("client_file:files_sent", on_files_sent,
|
||||
client_file::FilesSent)
|
||||
EVENT_TYPEN("network:packet_received", on_packet_received, network::Packet)
|
||||
}
|
||||
|
||||
@ -76,8 +77,9 @@ struct Module: public interface::Module
|
||||
});
|
||||
}
|
||||
|
||||
void on_lua_files_sent(const client_lua::FilesSent &event)
|
||||
void on_files_sent(const client_file::FilesSent &event)
|
||||
{
|
||||
log_v(MODULE, "on_files_sent(): recipient=%zu", event.recipient);
|
||||
network::access(m_server, [&](network::Interface * inetwork){
|
||||
inetwork->send(event.recipient, "core:run_script",
|
||||
"print(\"TODO: Run init.lua\")");
|
||||
|
5
todo.txt
5
todo.txt
@ -9,3 +9,8 @@ Buildat TODO
|
||||
- Modules should be run in threads.
|
||||
- Network should leave socket fds in m_server when destructing, and pick them up
|
||||
on core:continue.
|
||||
- Move module/include/api.h to module/api.h
|
||||
|
||||
Buildat TODO later
|
||||
==================
|
||||
- Watch dependencies of module source and client_lua/*.lua in addition to main file
|
||||
|
Loading…
x
Reference in New Issue
Block a user