forked from Mirrorlandia_minetest/minetest
new auto masterserver
This commit is contained in:
parent
ef6b8bee07
commit
ee07c3f7cf
2
.gitignore
vendored
2
.gitignore
vendored
@ -40,6 +40,8 @@ src/cguittfont/CMakeFiles/
|
|||||||
src/cguittfont/libcguittfont.a
|
src/cguittfont/libcguittfont.a
|
||||||
src/cguittfont/cmake_install.cmake
|
src/cguittfont/cmake_install.cmake
|
||||||
src/cguittfont/Makefile
|
src/cguittfont/Makefile
|
||||||
|
src/json/CMakeFiles/
|
||||||
|
src/json/libjson.a
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
CPackConfig.cmake
|
CPackConfig.cmake
|
||||||
CPackSourceConfig.cmake
|
CPackSourceConfig.cmake
|
||||||
|
18
cmake/Modules/FindJson.cmake
Normal file
18
cmake/Modules/FindJson.cmake
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Look for json, use our own if not found
|
||||||
|
|
||||||
|
#FIND_PATH(JSON_INCLUDE_DIR json.h)
|
||||||
|
|
||||||
|
#FIND_LIBRARY(JSON_LIBRARY NAMES json)
|
||||||
|
|
||||||
|
#IF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
|
||||||
|
# SET( JSON_FOUND TRUE )
|
||||||
|
#ENDIF(JSON_LIBRARY AND JSON_INCLUDE_DIR)
|
||||||
|
|
||||||
|
#IF(JSON_FOUND)
|
||||||
|
# MESSAGE(STATUS "Found system json header file in ${JSON_INCLUDE_DIR}")
|
||||||
|
# MESSAGE(STATUS "Found system json library ${JSON_LIBRARY}")
|
||||||
|
#ELSE(JSON_FOUND)
|
||||||
|
SET(JSON_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/json)
|
||||||
|
SET(JSON_LIBRARY json)
|
||||||
|
MESSAGE(STATUS "Using project json library")
|
||||||
|
#ENDIF(JSON_FOUND)
|
@ -159,7 +159,7 @@
|
|||||||
#media_fetch_threads = 8
|
#media_fetch_threads = 8
|
||||||
|
|
||||||
# Url to the server list displayed in the Multiplayer Tab
|
# Url to the server list displayed in the Multiplayer Tab
|
||||||
#serverlist_url = servers.minetest.ru/server.list
|
#serverlist_url = servers.minetest.net
|
||||||
# File in client/serverlist/ that contains your favorite servers displayed in the Multiplayer Tab
|
# File in client/serverlist/ that contains your favorite servers displayed in the Multiplayer Tab
|
||||||
#serverlist_file = favoriteservers.txt
|
#serverlist_file = favoriteservers.txt
|
||||||
|
|
||||||
@ -172,6 +172,16 @@
|
|||||||
# Server stuff
|
# Server stuff
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Name of server
|
||||||
|
#server_name = Minetest server
|
||||||
|
# Description of server
|
||||||
|
#server_description = mine here
|
||||||
|
# Domain name of server
|
||||||
|
#server_address = game.minetest.net
|
||||||
|
# Homepage of server
|
||||||
|
#server_url = http://minetest.net
|
||||||
|
# Automaticaly report to masterserver
|
||||||
|
#server_announce = 0
|
||||||
# Default game (default when creating a new world)
|
# Default game (default when creating a new world)
|
||||||
#default_game = minetest
|
#default_game = minetest
|
||||||
# World directory (everything in the world is stored here)
|
# World directory (everything in the world is stored here)
|
||||||
|
@ -5,6 +5,7 @@ cmake_minimum_required( VERSION 2.6 )
|
|||||||
mark_as_advanced(EXECUTABLE_OUTPUT_PATH LIBRARY_OUTPUT_PATH)
|
mark_as_advanced(EXECUTABLE_OUTPUT_PATH LIBRARY_OUTPUT_PATH)
|
||||||
mark_as_advanced(JTHREAD_INCLUDE_DIR JTHREAD_LIBRARY)
|
mark_as_advanced(JTHREAD_INCLUDE_DIR JTHREAD_LIBRARY)
|
||||||
mark_as_advanced(SQLITE3_INCLUDE_DIR SQLITE3_LIBRARY)
|
mark_as_advanced(SQLITE3_INCLUDE_DIR SQLITE3_LIBRARY)
|
||||||
|
mark_as_advanced(JSON_INCLUDE_DIR JSON_LIBRARY)
|
||||||
|
|
||||||
option(ENABLE_CURL "Enable cURL support for fetching media" 1)
|
option(ENABLE_CURL "Enable cURL support for fetching media" 1)
|
||||||
|
|
||||||
@ -170,6 +171,7 @@ endif()
|
|||||||
|
|
||||||
find_package(Jthread REQUIRED)
|
find_package(Jthread REQUIRED)
|
||||||
find_package(Sqlite3 REQUIRED)
|
find_package(Sqlite3 REQUIRED)
|
||||||
|
find_package(Json REQUIRED)
|
||||||
|
|
||||||
if(USE_FREETYPE)
|
if(USE_FREETYPE)
|
||||||
find_package(Freetype REQUIRED)
|
find_package(Freetype REQUIRED)
|
||||||
@ -242,6 +244,7 @@ set(common_SRCS
|
|||||||
biome.cpp
|
biome.cpp
|
||||||
clientserver.cpp
|
clientserver.cpp
|
||||||
staticobject.cpp
|
staticobject.cpp
|
||||||
|
serverlist.cpp
|
||||||
util/serialize.cpp
|
util/serialize.cpp
|
||||||
util/directiontables.cpp
|
util/directiontables.cpp
|
||||||
util/numeric.cpp
|
util/numeric.cpp
|
||||||
@ -303,7 +306,6 @@ set(minetest_SRCS
|
|||||||
filecache.cpp
|
filecache.cpp
|
||||||
tile.cpp
|
tile.cpp
|
||||||
shader.cpp
|
shader.cpp
|
||||||
serverlist.cpp
|
|
||||||
game.cpp
|
game.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
@ -332,6 +334,7 @@ include_directories(
|
|||||||
${JTHREAD_INCLUDE_DIR}
|
${JTHREAD_INCLUDE_DIR}
|
||||||
${SQLITE3_INCLUDE_DIR}
|
${SQLITE3_INCLUDE_DIR}
|
||||||
${LUA_INCLUDE_DIR}
|
${LUA_INCLUDE_DIR}
|
||||||
|
${JSON_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(USE_FREETYPE)
|
if(USE_FREETYPE)
|
||||||
@ -341,6 +344,12 @@ if(USE_FREETYPE)
|
|||||||
)
|
)
|
||||||
endif(USE_FREETYPE)
|
endif(USE_FREETYPE)
|
||||||
|
|
||||||
|
if(USE_CURL)
|
||||||
|
include_directories(
|
||||||
|
${CURL_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
endif(USE_CURL)
|
||||||
|
|
||||||
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin")
|
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin")
|
||||||
|
|
||||||
if(BUILD_CLIENT)
|
if(BUILD_CLIENT)
|
||||||
@ -359,18 +368,15 @@ if(BUILD_CLIENT)
|
|||||||
${JTHREAD_LIBRARY}
|
${JTHREAD_LIBRARY}
|
||||||
${SQLITE3_LIBRARY}
|
${SQLITE3_LIBRARY}
|
||||||
${LUA_LIBRARY}
|
${LUA_LIBRARY}
|
||||||
|
${JSON_LIBRARY}
|
||||||
${PLATFORM_LIBS}
|
${PLATFORM_LIBS}
|
||||||
${CLIENT_PLATFORM_LIBS}
|
${CLIENT_PLATFORM_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(USE_CURL)
|
if(USE_CURL)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
${PROJECT_NAME}
|
${PROJECT_NAME}
|
||||||
${CURL_LIBRARY}
|
${CURL_LIBRARY}
|
||||||
)
|
)
|
||||||
include_directories(
|
|
||||||
${CURL_INCLUDE_DIR}
|
|
||||||
)
|
|
||||||
endif(USE_CURL)
|
endif(USE_CURL)
|
||||||
if(USE_FREETYPE)
|
if(USE_FREETYPE)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
@ -388,12 +394,20 @@ if(BUILD_SERVER)
|
|||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
${JTHREAD_LIBRARY}
|
${JTHREAD_LIBRARY}
|
||||||
${SQLITE3_LIBRARY}
|
${SQLITE3_LIBRARY}
|
||||||
|
${JSON_LIBRARY}
|
||||||
${GETTEXT_LIBRARY}
|
${GETTEXT_LIBRARY}
|
||||||
${LUA_LIBRARY}
|
${LUA_LIBRARY}
|
||||||
${PLATFORM_LIBS}
|
${PLATFORM_LIBS}
|
||||||
)
|
)
|
||||||
|
if(USE_CURL)
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}server
|
||||||
|
${CURL_LIBRARY}
|
||||||
|
)
|
||||||
|
endif(USE_CURL)
|
||||||
endif(BUILD_SERVER)
|
endif(BUILD_SERVER)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Set some optimizations and tweaks
|
# Set some optimizations and tweaks
|
||||||
#
|
#
|
||||||
@ -569,4 +583,9 @@ else (LUA_FOUND)
|
|||||||
add_subdirectory(lua)
|
add_subdirectory(lua)
|
||||||
endif (LUA_FOUND)
|
endif (LUA_FOUND)
|
||||||
|
|
||||||
|
if (JSON_FOUND)
|
||||||
|
else (JSON_FOUND)
|
||||||
|
add_subdirectory(json)
|
||||||
|
endif (JSON_FOUND)
|
||||||
|
|
||||||
#end
|
#end
|
||||||
|
@ -130,8 +130,13 @@ void set_default_settings(Settings *settings)
|
|||||||
|
|
||||||
settings->setDefault("media_fetch_threads", "8");
|
settings->setDefault("media_fetch_threads", "8");
|
||||||
|
|
||||||
settings->setDefault("serverlist_url", "servers.minetest.ru/server.list");
|
settings->setDefault("serverlist_url", "servers.minetest.net");
|
||||||
settings->setDefault("serverlist_file", "favoriteservers.txt");
|
settings->setDefault("serverlist_file", "favoriteservers.txt");
|
||||||
|
settings->setDefault("server_announce", "false");
|
||||||
|
settings->setDefault("server_url", "");
|
||||||
|
settings->setDefault("server_address", "");
|
||||||
|
settings->setDefault("server_name", "");
|
||||||
|
settings->setDefault("server_description", "");
|
||||||
|
|
||||||
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "liberationsans.ttf"));
|
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "liberationsans.ttf"));
|
||||||
settings->setDefault("font_size", "13");
|
settings->setDefault("font_size", "13");
|
||||||
|
@ -108,6 +108,7 @@ enum
|
|||||||
GUI_ID_ENABLE_PARTICLES_CB,
|
GUI_ID_ENABLE_PARTICLES_CB,
|
||||||
GUI_ID_DAMAGE_CB,
|
GUI_ID_DAMAGE_CB,
|
||||||
GUI_ID_CREATIVE_CB,
|
GUI_ID_CREATIVE_CB,
|
||||||
|
GUI_ID_PUBLIC_CB,
|
||||||
GUI_ID_JOIN_GAME_BUTTON,
|
GUI_ID_JOIN_GAME_BUTTON,
|
||||||
GUI_ID_CHANGE_KEYS_BUTTON,
|
GUI_ID_CHANGE_KEYS_BUTTON,
|
||||||
GUI_ID_DELETE_WORLD_BUTTON,
|
GUI_ID_DELETE_WORLD_BUTTON,
|
||||||
@ -562,6 +563,14 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
|
|||||||
Environment->addCheckBox(m_data->enable_damage, rect, this, GUI_ID_DAMAGE_CB,
|
Environment->addCheckBox(m_data->enable_damage, rect, this, GUI_ID_DAMAGE_CB,
|
||||||
wgettext("Enable Damage"));
|
wgettext("Enable Damage"));
|
||||||
}
|
}
|
||||||
|
#if USE_CURL
|
||||||
|
{
|
||||||
|
core::rect<s32> rect(0, 0, 250, 30);
|
||||||
|
rect += m_topleft_server + v2s32(30+20+250+20, 60);
|
||||||
|
Environment->addCheckBox(m_data->enable_public, rect, this, GUI_ID_PUBLIC_CB,
|
||||||
|
wgettext("Public"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Delete world button
|
// Delete world button
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 130, 30);
|
core::rect<s32> rect(0, 0, 130, 30);
|
||||||
@ -841,6 +850,11 @@ void GUIMainMenu::readInput(MainMenuData *dst)
|
|||||||
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||||
dst->enable_damage = ((gui::IGUICheckBox*)e)->isChecked();
|
dst->enable_damage = ((gui::IGUICheckBox*)e)->isChecked();
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
gui::IGUIElement *e = getElementFromId(GUI_ID_PUBLIC_CB);
|
||||||
|
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||||
|
dst->enable_public = ((gui::IGUICheckBox*)e)->isChecked();
|
||||||
|
}
|
||||||
{
|
{
|
||||||
gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB);
|
gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB);
|
||||||
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
|
||||||
@ -912,8 +926,8 @@ void GUIMainMenu::readInput(MainMenuData *dst)
|
|||||||
{
|
{
|
||||||
ServerListSpec server =
|
ServerListSpec server =
|
||||||
getServerListSpec(wide_to_narrow(dst->address), wide_to_narrow(dst->port));
|
getServerListSpec(wide_to_narrow(dst->address), wide_to_narrow(dst->port));
|
||||||
dst->servername = server.name;
|
dst->servername = server["name"].asString();
|
||||||
dst->serverdescription = server.description;
|
dst->serverdescription = server["description"].asString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1174,12 +1188,30 @@ void GUIMainMenu::updateGuiServerList()
|
|||||||
i != m_data->servers.end(); i++)
|
i != m_data->servers.end(); i++)
|
||||||
{
|
{
|
||||||
std::string text;
|
std::string text;
|
||||||
if (i->name != "" && i->description != "")
|
|
||||||
text = i->name + " (" + i->description + ")";
|
if ((*i)["clients"].asString().size())
|
||||||
else if (i->name !="")
|
text += (*i)["clients"].asString();
|
||||||
text = i->name;
|
if ((*i)["clients_max"].asString().size())
|
||||||
|
text += "/" + (*i)["clients_max"].asString();
|
||||||
|
text += " ";
|
||||||
|
if ((*i)["version"].asString().size())
|
||||||
|
text += (*i)["version"].asString() + " ";
|
||||||
|
if ((*i)["password"].asString().size())
|
||||||
|
text += "*";
|
||||||
|
if ((*i)["creative"].asString().size())
|
||||||
|
text += "C";
|
||||||
|
if ((*i)["damage"].asString().size())
|
||||||
|
text += "D";
|
||||||
|
if ((*i)["pvp"].asString().size())
|
||||||
|
text += "P";
|
||||||
|
text += " ";
|
||||||
|
|
||||||
|
if ((*i)["name"] != "" && (*i)["description"] != "")
|
||||||
|
text += (*i)["name"].asString() + " (" + (*i)["description"].asString() + ")";
|
||||||
|
else if ((*i)["name"] !="")
|
||||||
|
text += (*i)["name"].asString();
|
||||||
else
|
else
|
||||||
text = i->address + ":" + i->port;
|
text += (*i)["address"].asString() + ":" + (*i)["port"].asString();
|
||||||
|
|
||||||
serverlist->addItem(narrow_to_wide(text).c_str());
|
serverlist->addItem(narrow_to_wide(text).c_str());
|
||||||
}
|
}
|
||||||
@ -1191,26 +1223,26 @@ void GUIMainMenu::serverListOnSelected()
|
|||||||
{
|
{
|
||||||
gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
|
gui::IGUIListBox *serverlist = (gui::IGUIListBox*)getElementFromId(GUI_ID_SERVERLIST);
|
||||||
u16 id = serverlist->getSelected();
|
u16 id = serverlist->getSelected();
|
||||||
if (id < 0) return;
|
//if (id < 0) return; // u16>0!
|
||||||
((gui::IGUIEditBox*)getElementFromId(GUI_ID_ADDRESS_INPUT))
|
((gui::IGUIEditBox*)getElementFromId(GUI_ID_ADDRESS_INPUT))
|
||||||
->setText(narrow_to_wide(m_data->servers[id].address).c_str());
|
->setText(narrow_to_wide(m_data->servers[id]["address"].asString()).c_str());
|
||||||
((gui::IGUIEditBox*)getElementFromId(GUI_ID_PORT_INPUT))
|
((gui::IGUIEditBox*)getElementFromId(GUI_ID_PORT_INPUT))
|
||||||
->setText(narrow_to_wide(m_data->servers[id].port).c_str());
|
->setText(narrow_to_wide(m_data->servers[id]["port"].asString()).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerListSpec GUIMainMenu::getServerListSpec(std::string address, std::string port)
|
ServerListSpec GUIMainMenu::getServerListSpec(std::string address, std::string port)
|
||||||
{
|
{
|
||||||
ServerListSpec server;
|
ServerListSpec server;
|
||||||
server.address = address;
|
server["address"] = address;
|
||||||
server.port = port;
|
server["port"] = port;
|
||||||
for(std::vector<ServerListSpec>::iterator i = m_data->servers.begin();
|
for(std::vector<ServerListSpec>::iterator i = m_data->servers.begin();
|
||||||
i != m_data->servers.end(); i++)
|
i != m_data->servers.end(); i++)
|
||||||
{
|
{
|
||||||
if (i->address == address && i->port == port)
|
if ((*i)["address"] == address && (*i)["port"] == port)
|
||||||
{
|
{
|
||||||
server.description = i->description;
|
server["description"] = (*i)["description"];
|
||||||
server.name = i->name;
|
server["name"] = (*i)["name"];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ struct MainMenuData
|
|||||||
// Server options
|
// Server options
|
||||||
bool creative_mode;
|
bool creative_mode;
|
||||||
bool enable_damage;
|
bool enable_damage;
|
||||||
|
bool enable_public;
|
||||||
int selected_world;
|
int selected_world;
|
||||||
bool simple_singleplayer_mode;
|
bool simple_singleplayer_mode;
|
||||||
// Actions
|
// Actions
|
||||||
@ -77,6 +78,7 @@ struct MainMenuData
|
|||||||
// Server opts
|
// Server opts
|
||||||
creative_mode(false),
|
creative_mode(false),
|
||||||
enable_damage(false),
|
enable_damage(false),
|
||||||
|
enable_public(false),
|
||||||
selected_world(0),
|
selected_world(0),
|
||||||
simple_singleplayer_mode(false),
|
simple_singleplayer_mode(false),
|
||||||
// Actions
|
// Actions
|
||||||
|
14
src/json/CMakeLists.txt
Normal file
14
src/json/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
if( UNIX )
|
||||||
|
set(json_SRCS jsoncpp.cpp)
|
||||||
|
set(json_platform_LIBS "")
|
||||||
|
else( UNIX )
|
||||||
|
set(json_SRCS jsoncpp.cpp)
|
||||||
|
set(json_platform_LIBS "")
|
||||||
|
endif( UNIX )
|
||||||
|
|
||||||
|
add_library(json ${json_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
json
|
||||||
|
${json_platform_LIBS}
|
||||||
|
)
|
16
src/json/UPDATING
Normal file
16
src/json/UPDATING
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cd ..
|
||||||
|
svn co https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/jsoncpp jsoncpp
|
||||||
|
svn up jsoncpp
|
||||||
|
cd jsoncpp
|
||||||
|
python amalgamate.py
|
||||||
|
cp -R dist/json ..
|
||||||
|
cp dist/jsoncpp.cpp ../json
|
||||||
|
|
||||||
|
# maybe you need to patch:
|
||||||
|
# src/json/jsoncpp.cpp:
|
||||||
|
# -#include <json/json.h>
|
||||||
|
# +#include "json/json.h"
|
||||||
|
|
||||||
|
#svn export --force https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/jsoncpp/src/lib_json json
|
||||||
|
#svn export --force https://jsoncpp.svn.sourceforge.net/svnroot/jsoncpp/trunk/jsoncpp/include/json json
|
1914
src/json/json.h
Normal file
1914
src/json/json.h
Normal file
File diff suppressed because it is too large
Load Diff
4367
src/json/jsoncpp.cpp
Normal file
4367
src/json/jsoncpp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
10
src/main.cpp
10
src/main.cpp
@ -1095,6 +1095,7 @@ int main(int argc, char *argv[])
|
|||||||
#else
|
#else
|
||||||
bool run_dedicated_server = cmd_args.getFlag("server");
|
bool run_dedicated_server = cmd_args.getFlag("server");
|
||||||
#endif
|
#endif
|
||||||
|
g_settings->set("server_dedicated", run_dedicated_server ? "true" : "false");
|
||||||
if(run_dedicated_server)
|
if(run_dedicated_server)
|
||||||
{
|
{
|
||||||
DSTACK("Dedicated server branch");
|
DSTACK("Dedicated server branch");
|
||||||
@ -1593,6 +1594,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
g_settings->set("creative_mode", itos(menudata.creative_mode));
|
g_settings->set("creative_mode", itos(menudata.creative_mode));
|
||||||
g_settings->set("enable_damage", itos(menudata.enable_damage));
|
g_settings->set("enable_damage", itos(menudata.enable_damage));
|
||||||
|
g_settings->set("server_announce", itos(menudata.enable_public));
|
||||||
g_settings->set("name", playername);
|
g_settings->set("name", playername);
|
||||||
g_settings->set("address", address);
|
g_settings->set("address", address);
|
||||||
g_settings->set("port", itos(port));
|
g_settings->set("port", itos(port));
|
||||||
@ -1619,10 +1621,10 @@ int main(int argc, char *argv[])
|
|||||||
else if (address != "")
|
else if (address != "")
|
||||||
{
|
{
|
||||||
ServerListSpec server;
|
ServerListSpec server;
|
||||||
server.name = menudata.servername;
|
server["name"] = menudata.servername;
|
||||||
server.address = wide_to_narrow(menudata.address);
|
server["address"] = wide_to_narrow(menudata.address);
|
||||||
server.port = wide_to_narrow(menudata.port);
|
server["port"] = wide_to_narrow(menudata.port);
|
||||||
server.description = menudata.serverdescription;
|
server["description"] = menudata.serverdescription;
|
||||||
ServerList::insert(server);
|
ServerList::insert(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "sound.h" // dummySoundManager
|
#include "sound.h" // dummySoundManager
|
||||||
#include "event_manager.h"
|
#include "event_manager.h"
|
||||||
#include "hex.h"
|
#include "hex.h"
|
||||||
|
#include "serverlist.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "util/pointedthing.h"
|
#include "util/pointedthing.h"
|
||||||
#include "util/mathconstants.h"
|
#include "util/mathconstants.h"
|
||||||
@ -961,9 +962,11 @@ Server::Server(
|
|||||||
{
|
{
|
||||||
m_liquid_transform_timer = 0.0;
|
m_liquid_transform_timer = 0.0;
|
||||||
m_print_info_timer = 0.0;
|
m_print_info_timer = 0.0;
|
||||||
|
m_masterserver_timer = 0.0;
|
||||||
m_objectdata_timer = 0.0;
|
m_objectdata_timer = 0.0;
|
||||||
m_emergethread_trigger_timer = 0.0;
|
m_emergethread_trigger_timer = 0.0;
|
||||||
m_savemap_timer = 0.0;
|
m_savemap_timer = 0.0;
|
||||||
|
m_clients_number = 0;
|
||||||
|
|
||||||
m_env_mutex.Init();
|
m_env_mutex.Init();
|
||||||
m_con_mutex.Init();
|
m_con_mutex.Init();
|
||||||
@ -1505,7 +1508,7 @@ void Server::AsyncRunStep()
|
|||||||
counter = 0.0;
|
counter = 0.0;
|
||||||
|
|
||||||
JMutexAutoLock lock2(m_con_mutex);
|
JMutexAutoLock lock2(m_con_mutex);
|
||||||
|
m_clients_number = 0;
|
||||||
if(m_clients.size() != 0)
|
if(m_clients.size() != 0)
|
||||||
infostream<<"Players:"<<std::endl;
|
infostream<<"Players:"<<std::endl;
|
||||||
for(core::map<u16, RemoteClient*>::Iterator
|
for(core::map<u16, RemoteClient*>::Iterator
|
||||||
@ -1519,10 +1522,25 @@ void Server::AsyncRunStep()
|
|||||||
continue;
|
continue;
|
||||||
infostream<<"* "<<player->getName()<<"\t";
|
infostream<<"* "<<player->getName()<<"\t";
|
||||||
client->PrintInfo(infostream);
|
client->PrintInfo(infostream);
|
||||||
|
++m_clients_number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if USE_CURL
|
||||||
|
// send masterserver announce
|
||||||
|
{
|
||||||
|
float &counter = m_masterserver_timer;
|
||||||
|
if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
|
||||||
|
{
|
||||||
|
ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
|
||||||
|
counter = 0.01;
|
||||||
|
}
|
||||||
|
counter += dtime;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//if(g_settings->getBool("enable_experimental"))
|
//if(g_settings->getBool("enable_experimental"))
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -5186,6 +5204,10 @@ void dedicated_server_loop(Server &server, bool &kill)
|
|||||||
if(server.getShutdownRequested() || kill)
|
if(server.getShutdownRequested() || kill)
|
||||||
{
|
{
|
||||||
infostream<<"Dedicated server quitting"<<std::endl;
|
infostream<<"Dedicated server quitting"<<std::endl;
|
||||||
|
#if USE_CURL
|
||||||
|
if(g_settings->getBool("server_announce") == true)
|
||||||
|
ServerList::sendAnnounce("delete");
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,6 +720,7 @@ private:
|
|||||||
// Some timers
|
// Some timers
|
||||||
float m_liquid_transform_timer;
|
float m_liquid_transform_timer;
|
||||||
float m_print_info_timer;
|
float m_print_info_timer;
|
||||||
|
float m_masterserver_timer;
|
||||||
float m_objectdata_timer;
|
float m_objectdata_timer;
|
||||||
float m_emergethread_trigger_timer;
|
float m_emergethread_trigger_timer;
|
||||||
float m_savemap_timer;
|
float m_savemap_timer;
|
||||||
@ -737,6 +738,7 @@ private:
|
|||||||
JMutex m_con_mutex;
|
JMutex m_con_mutex;
|
||||||
// Connected clients (behind the con mutex)
|
// Connected clients (behind the con mutex)
|
||||||
core::map<u16, RemoteClient*> m_clients;
|
core::map<u16, RemoteClient*> m_clients;
|
||||||
|
u16 m_clients_number; //for announcing masterserver
|
||||||
|
|
||||||
// Bann checking
|
// Bann checking
|
||||||
BanManager m_banmanager;
|
BanManager m_banmanager;
|
||||||
|
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "json/json.h"
|
||||||
#if USE_CURL
|
#if USE_CURL
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#endif
|
#endif
|
||||||
@ -83,7 +84,7 @@ std::vector<ServerListSpec> getOnline()
|
|||||||
{
|
{
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, g_settings->get("serverlist_url").c_str());
|
curl_easy_setopt(curl, CURLOPT_URL, (g_settings->get("serverlist_url")+"/list").c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ServerList::WriteCallback);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ServerList::WriteCallback);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &liststring);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &liststring);
|
||||||
|
|
||||||
@ -92,8 +93,7 @@ std::vector<ServerListSpec> getOnline()
|
|||||||
errorstream<<"Serverlist at url "<<g_settings->get("serverlist_url")<<" not found (internet connection?)"<<std::endl;
|
errorstream<<"Serverlist at url "<<g_settings->get("serverlist_url")<<" not found (internet connection?)"<<std::endl;
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
}
|
}
|
||||||
|
return ServerList::deSerializeJson(liststring);
|
||||||
return ServerList::deSerialize(liststring);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -106,8 +106,8 @@ bool deleteEntry (ServerListSpec server)
|
|||||||
std::vector<ServerListSpec> serverlist = ServerList::getLocal();
|
std::vector<ServerListSpec> serverlist = ServerList::getLocal();
|
||||||
for(unsigned i = 0; i < serverlist.size(); i++)
|
for(unsigned i = 0; i < serverlist.size(); i++)
|
||||||
{
|
{
|
||||||
if (serverlist[i].address == server.address
|
if (serverlist[i]["address"] == server["address"]
|
||||||
&& serverlist[i].port == server.port)
|
&& serverlist[i]["port"] == server["port"])
|
||||||
{
|
{
|
||||||
serverlist.erase(serverlist.begin() + i);
|
serverlist.erase(serverlist.begin() + i);
|
||||||
}
|
}
|
||||||
@ -150,17 +150,21 @@ std::vector<ServerListSpec> deSerialize(std::string liststring)
|
|||||||
{
|
{
|
||||||
std::vector<ServerListSpec> serverlist;
|
std::vector<ServerListSpec> serverlist;
|
||||||
std::istringstream stream(liststring);
|
std::istringstream stream(liststring);
|
||||||
std::string line;
|
std::string line, tmp;
|
||||||
while (std::getline(stream, line))
|
while (std::getline(stream, line))
|
||||||
{
|
{
|
||||||
std::transform(line.begin(), line.end(),line.begin(), ::toupper);
|
std::transform(line.begin(), line.end(),line.begin(), ::toupper);
|
||||||
if (line == "[SERVER]")
|
if (line == "[SERVER]")
|
||||||
{
|
{
|
||||||
ServerListSpec thisserver;
|
ServerListSpec thisserver;
|
||||||
std::getline(stream, thisserver.name);
|
std::getline(stream, tmp);
|
||||||
std::getline(stream, thisserver.address);
|
thisserver["name"] = tmp;
|
||||||
std::getline(stream, thisserver.port);
|
std::getline(stream, tmp);
|
||||||
std::getline(stream, thisserver.description);
|
thisserver["address"] = tmp;
|
||||||
|
std::getline(stream, tmp);
|
||||||
|
thisserver["port"] = tmp;
|
||||||
|
std::getline(stream, tmp);
|
||||||
|
thisserver["description"] = tmp;
|
||||||
serverlist.push_back(thisserver);
|
serverlist.push_back(thisserver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,13 +177,100 @@ std::string serialize(std::vector<ServerListSpec> serverlist)
|
|||||||
for(std::vector<ServerListSpec>::iterator i = serverlist.begin(); i != serverlist.end(); i++)
|
for(std::vector<ServerListSpec>::iterator i = serverlist.begin(); i != serverlist.end(); i++)
|
||||||
{
|
{
|
||||||
liststring += "[server]\n";
|
liststring += "[server]\n";
|
||||||
liststring += i->name + "\n";
|
liststring += (*i)["name"].asString() + "\n";
|
||||||
liststring += i->address + "\n";
|
liststring += (*i)["address"].asString() + "\n";
|
||||||
liststring += i->port + "\n";
|
liststring += (*i)["port"].asString() + "\n";
|
||||||
liststring += i->description + "\n";
|
liststring += (*i)["description"].asString() + "\n";
|
||||||
liststring += "\n";
|
liststring += "\n";
|
||||||
}
|
}
|
||||||
return liststring;
|
return liststring;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ServerListSpec> deSerializeJson(std::string liststring)
|
||||||
|
{
|
||||||
|
std::vector<ServerListSpec> serverlist;
|
||||||
|
Json::Value root;
|
||||||
|
Json::Reader reader;
|
||||||
|
std::istringstream stream(liststring);
|
||||||
|
if (!liststring.size()) {
|
||||||
|
return serverlist;
|
||||||
|
}
|
||||||
|
if (!reader.parse( stream, root ) )
|
||||||
|
{
|
||||||
|
errorstream << "Failed to parse server list " << reader.getFormattedErrorMessages();
|
||||||
|
return serverlist;
|
||||||
|
}
|
||||||
|
if (root["list"].isArray())
|
||||||
|
for (unsigned int i = 0; i < root["list"].size(); i++)
|
||||||
|
{
|
||||||
|
if (root["list"][i].isObject()) {
|
||||||
|
serverlist.push_back(root["list"][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serverlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string serializeJson(std::vector<ServerListSpec> serverlist)
|
||||||
|
{
|
||||||
|
Json::Value root;
|
||||||
|
Json::Value list(Json::arrayValue);
|
||||||
|
for(std::vector<ServerListSpec>::iterator i = serverlist.begin(); i != serverlist.end(); i++)
|
||||||
|
{
|
||||||
|
list.append(*i);
|
||||||
|
}
|
||||||
|
root["list"] = list;
|
||||||
|
Json::StyledWriter writer;
|
||||||
|
return writer.write( root );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if USE_CURL
|
||||||
|
static size_t ServerAnnounceCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
//((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||||
|
//return size * nmemb;
|
||||||
|
}
|
||||||
|
void sendAnnounce(std::string action, u16 clients) {
|
||||||
|
Json::Value server;
|
||||||
|
if (action.size())
|
||||||
|
server["action"] = action;
|
||||||
|
server["port"] = g_settings->get("port");
|
||||||
|
if (action != "del") {
|
||||||
|
server["name"] = g_settings->get("server_name");
|
||||||
|
server["description"] = g_settings->get("server_description");
|
||||||
|
server["address"] = g_settings->get("server_address");
|
||||||
|
server["version"] = VERSION_STRING;
|
||||||
|
server["url"] = g_settings->get("server_url");
|
||||||
|
server["creative"] = g_settings->get("creative_mode");
|
||||||
|
server["damage"] = g_settings->get("enable_damage");
|
||||||
|
server["dedicated"] = g_settings->get("server_dedicated");
|
||||||
|
server["password"] = g_settings->getBool("disallow_empty_password");
|
||||||
|
server["pvp"] = g_settings->getBool("enable_pvp");
|
||||||
|
server["clients"] = clients;
|
||||||
|
server["clients_max"] = g_settings->get("max_users");
|
||||||
|
}
|
||||||
|
if(server["action"] == "start")
|
||||||
|
actionstream << "announcing to " << g_settings->get("serverlist_url") << std::endl;
|
||||||
|
Json::StyledWriter writer;
|
||||||
|
CURL *curl;
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if (curl)
|
||||||
|
{
|
||||||
|
CURLcode res;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, (g_settings->get("serverlist_url")+std::string("/announce?json=")+curl_easy_escape(curl, writer.write( server ).c_str(), 0)).c_str());
|
||||||
|
//curl_easy_setopt(curl, CURLOPT_USERAGENT, "minetest");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ServerList::ServerAnnounceCallback);
|
||||||
|
//curl_easy_setopt(curl, CURLOPT_WRITEDATA, &liststring);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1);
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
//if (res != CURLE_OK)
|
||||||
|
// errorstream<<"Serverlist at url "<<g_settings->get("serverlist_url")<<" not found (internet connection?)"<<std::endl;
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} //namespace ServerList
|
} //namespace ServerList
|
||||||
|
@ -19,17 +19,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "json/json.h"
|
||||||
|
|
||||||
#ifndef SERVERLIST_HEADER
|
#ifndef SERVERLIST_HEADER
|
||||||
#define SERVERLIST_HEADER
|
#define SERVERLIST_HEADER
|
||||||
|
|
||||||
struct ServerListSpec
|
typedef Json::Value ServerListSpec;
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::string address;
|
|
||||||
std::string port;
|
|
||||||
std::string description;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ServerList
|
namespace ServerList
|
||||||
{
|
{
|
||||||
@ -41,6 +36,11 @@ namespace ServerList
|
|||||||
bool insert(ServerListSpec server);
|
bool insert(ServerListSpec server);
|
||||||
std::vector<ServerListSpec> deSerialize(std::string liststring);
|
std::vector<ServerListSpec> deSerialize(std::string liststring);
|
||||||
std::string serialize(std::vector<ServerListSpec>);
|
std::string serialize(std::vector<ServerListSpec>);
|
||||||
|
std::vector<ServerListSpec> deSerializeJson(std::string liststring);
|
||||||
|
std::string serializeJson(std::vector<ServerListSpec>);
|
||||||
|
#if USE_CURL
|
||||||
|
void sendAnnounce(std::string action = "", u16 clients = 0);
|
||||||
|
#endif
|
||||||
} //ServerList namespace
|
} //ServerList namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
11
util/master/index.html
Normal file
11
util/master/index.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Minetest server list</title>
|
||||||
|
<link rel="stylesheet" href="style.css"/>
|
||||||
|
</head>
|
||||||
|
<body><div id="table"></div></body>
|
||||||
|
</html>
|
||||||
|
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||||
|
<script src="list.js"></script>
|
72
util/master/list.js
Normal file
72
util/master/list.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
function e(s) {
|
||||||
|
if (typeof s === "undefined") s = '';
|
||||||
|
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); //mc"
|
||||||
|
}
|
||||||
|
function human_time(t) {
|
||||||
|
var n = 's';
|
||||||
|
if (!t || t < 0) t = 0;
|
||||||
|
var f = 0;
|
||||||
|
var s = parseInt((new Date().getTime() / 1000 - (t || 0)));
|
||||||
|
if (!s || s <= 0) s = 0;
|
||||||
|
if (s == 0) return 'now';
|
||||||
|
if (s >= 60) {
|
||||||
|
s /= 60;
|
||||||
|
n = 'm';
|
||||||
|
if (s >= 60) {
|
||||||
|
s /= 60;
|
||||||
|
n = 'h';
|
||||||
|
f = 1;
|
||||||
|
if (s >= 24) {
|
||||||
|
s /= 24;
|
||||||
|
n = 'd';
|
||||||
|
f = 1;
|
||||||
|
if (s >= 30) {
|
||||||
|
s /= 30;
|
||||||
|
n = 'M';
|
||||||
|
f = 1;
|
||||||
|
if (s >= 12) {
|
||||||
|
s /= 12;
|
||||||
|
n = 'y';
|
||||||
|
f = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ((f ? parseFloat(s).toFixed(1) : parseInt(s)) + n);
|
||||||
|
}
|
||||||
|
function success(r) {
|
||||||
|
if (!r || !r.list) return;
|
||||||
|
var h = '<table><tr><th>ip:port</th><th>clients, max</th><th>version</th><th>name</th><th>desc</th><th>flags</th><th>updated/started</th><th>ping</th></tr>';
|
||||||
|
for (var i = 0; i < r.list.length; ++i) {
|
||||||
|
var s = r.list[i];
|
||||||
|
if (!s) continue;
|
||||||
|
h += '<tr>';
|
||||||
|
h += '<td>' + e(s.address) + ':' + e(s.port) + '</td>';
|
||||||
|
h += '<td>' + e(s.clients) + (s.clients_max ? '/' + e(s.clients_max) : '') + (s.clients_top ? ', ' + s.clients_top : '') + '</td>';
|
||||||
|
h += '<td>' + e(s.version) + '</td>';
|
||||||
|
h += '<td>';
|
||||||
|
if (s.url) h += '<a href="' + e(s.url) + '">';
|
||||||
|
h += e(s.name || s.url);
|
||||||
|
if (s.url) h += '</a>';
|
||||||
|
h += '</td>';
|
||||||
|
h += '<td>' + e(s.description) + '</td>';
|
||||||
|
h += '<td>' + e(s.password ? 'Pwd ' : '') + (s.creative ? 'Cre ' : '') + (s.damage ? 'Dmg ' : '') + (s.pvp ? 'Pvp ' : '') + (s.dedicated ? 'Ded ' : '') + '</td>';
|
||||||
|
if (!s.time || s.time < 0) s.time = 0;
|
||||||
|
if (!s.start || s.start < 0) s.start = 0;
|
||||||
|
h += '<td>' + human_time(s.time) + (s.start ? '/' + human_time(s.start) : '') + '</td>';
|
||||||
|
h += '<td>' + (s.ping ? parseFloat(s.ping).toFixed(3)*1000 : '') + '</td>';
|
||||||
|
h += '</tr>';
|
||||||
|
}
|
||||||
|
h += '</table>'
|
||||||
|
jQuery('#table').html(h);
|
||||||
|
}
|
||||||
|
function get() {
|
||||||
|
jQuery.ajax({
|
||||||
|
url: 'list',
|
||||||
|
dataType: 'json',
|
||||||
|
success: success
|
||||||
|
});
|
||||||
|
setTimeout(get, 60000);
|
||||||
|
}
|
||||||
|
get();
|
257
util/master/master.cgi
Executable file
257
util/master/master.cgi
Executable file
@ -0,0 +1,257 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
=info
|
||||||
|
install:
|
||||||
|
cpan JSON JSON::XS
|
||||||
|
touch list_full list
|
||||||
|
chmod a+rw list_full list
|
||||||
|
|
||||||
|
freebsd:
|
||||||
|
www/fcgiwrap www/nginx
|
||||||
|
|
||||||
|
rc.conf.local:
|
||||||
|
nginx_enable="YES"
|
||||||
|
fcgiwrap_enable="YES"
|
||||||
|
fcgiwrap_user="www"
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
|
||||||
|
location / {
|
||||||
|
index index.html;
|
||||||
|
}
|
||||||
|
location /announce {
|
||||||
|
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root/master.cgi;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
apache .htaccess:
|
||||||
|
AddHandler cgi-script .cgi
|
||||||
|
DirectoryIndex index.html
|
||||||
|
Options +ExecCGI +FollowSymLinks
|
||||||
|
Order allow,deny
|
||||||
|
<FilesMatch (\.(html?|cgi|fcgi|css|js|gif|png|jpe?g|ico)|(^)|\w+)$>
|
||||||
|
Allow from all
|
||||||
|
</FilesMatch>
|
||||||
|
Deny from all
|
||||||
|
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
no strict qw(refs);
|
||||||
|
use warnings "NONFATAL" => "all";
|
||||||
|
no warnings qw(uninitialized);
|
||||||
|
use utf8;
|
||||||
|
use Socket;
|
||||||
|
use Time::HiRes qw(time sleep);
|
||||||
|
use IO::Socket::INET;
|
||||||
|
use JSON;
|
||||||
|
use Net::Ping;
|
||||||
|
our $root_path;
|
||||||
|
($ENV{'SCRIPT_FILENAME'} || $0) =~ m|^(.+)[/\\].+?$|; #v0w
|
||||||
|
$root_path = $1 . '/' if $1;
|
||||||
|
$root_path =~ s|\\|/|g;
|
||||||
|
|
||||||
|
our %config = (
|
||||||
|
#debug => 1,
|
||||||
|
list_full => $root_path . 'list_full',
|
||||||
|
list_pub => $root_path . 'list',
|
||||||
|
time_purge => 86400 * 30,
|
||||||
|
time_alive => 650,
|
||||||
|
source_check => 1,
|
||||||
|
ping_timeout => 3,
|
||||||
|
ping => 1,
|
||||||
|
mineping => 1,
|
||||||
|
pingable => 1,
|
||||||
|
trusted => [qw( 176.9.122.10 )], #masterserver self ip - if server on same ip with masterserver doesnt announced
|
||||||
|
#blacklist => [], # [qw(2.3.4.5 4.5.6.7 8.9.0.1), '1.2.3.4', qr/^10\.20\.30\./, ], # list, or quoted, ips, or regex
|
||||||
|
);
|
||||||
|
do($root_path . 'config.pl');
|
||||||
|
our $ping = Net::Ping->new("udp", $config{ping_timeout});
|
||||||
|
$ping->hires();
|
||||||
|
|
||||||
|
sub get_params_one(@) {
|
||||||
|
local %_ = %{ref $_[0] eq 'HASH' ? shift : {}};
|
||||||
|
for (@_) {
|
||||||
|
tr/+/ /, s/%([a-f\d]{2})/pack 'H*', $1/gei for my ($k, $v) = /^([^=]+=?)=(.+)$/ ? ($1, $2) : (/^([^=]*)=?$/, /^-/);
|
||||||
|
$_{$k} = $v;
|
||||||
|
}
|
||||||
|
wantarray ? %_ : \%_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_params(;$$) { #v7
|
||||||
|
my ($string, $delim) = @_;
|
||||||
|
$delim ||= '&';
|
||||||
|
read(STDIN, local $_ = '', $ENV{'CONTENT_LENGTH'}) if !$string and $ENV{'CONTENT_LENGTH'};
|
||||||
|
local %_ =
|
||||||
|
$string
|
||||||
|
? get_params_one split $delim, $string
|
||||||
|
: (get_params_one(@ARGV), map { get_params_one split $delim, $_ } split(/;\s*/, $ENV{'HTTP_COOKIE'}), $ENV{'QUERY_STRING'}, $_);
|
||||||
|
wantarray ? %_ : \%_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_params_utf8(;$$) {
|
||||||
|
local $_ = &get_params;
|
||||||
|
utf8::decode $_ for %$_;
|
||||||
|
wantarray ? %$_ : $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub file_rewrite(;$@) {
|
||||||
|
local $_ = shift;
|
||||||
|
return unless open my $fh, '>', $_;
|
||||||
|
print $fh @_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub file_read ($) {
|
||||||
|
open my $f, '<', $_[0] or return;
|
||||||
|
local $/ = undef;
|
||||||
|
my $ret = <$f>;
|
||||||
|
close $f;
|
||||||
|
return \$ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub read_json {
|
||||||
|
my $ret = {};
|
||||||
|
eval { $ret = JSON->new->utf8->relaxed(1)->decode(${ref $_[0] ? $_[0] : file_read($_[0]) or \''} || '{}'); }; #'mc
|
||||||
|
warn "json error [$@] on [", ${ref $_[0] ? $_[0] : \$_[0]}, "]" if $@;
|
||||||
|
$ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub printu (@) {
|
||||||
|
for (@_) {
|
||||||
|
print($_), next unless utf8::is_utf8($_);
|
||||||
|
my $s = $_;
|
||||||
|
utf8::encode($s);
|
||||||
|
print($s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub name_to_ip_noc($) {
|
||||||
|
my ($name) = @_;
|
||||||
|
unless ($name =~ /^\d+\.\d+\.\d+\.\d+$/) {
|
||||||
|
local $_ = (gethostbyname($name))[4];
|
||||||
|
return ($name, 1) unless length($_) == 4;
|
||||||
|
$name = inet_ntoa($_);
|
||||||
|
}
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub float {
|
||||||
|
return ($_[0] < 8 and $_[0] - int($_[0]))
|
||||||
|
? sprintf('%.' . ($_[0] < 1 ? 3 : ($_[0] < 3 ? 2 : 1)) . 'f', $_[0])
|
||||||
|
: int($_[0]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub mineping ($$) {
|
||||||
|
my ($addr, $port) = @_;
|
||||||
|
warn "mineping($addr, $port)" if $config{debug};
|
||||||
|
my $data;
|
||||||
|
my $time = time;
|
||||||
|
eval {
|
||||||
|
my $socket = IO::Socket::INET->new(
|
||||||
|
'PeerAddr' => $addr,
|
||||||
|
'PeerPort' => $port,
|
||||||
|
'Proto' => 'udp',
|
||||||
|
'Timeout' => $config{ping_timeout},
|
||||||
|
);
|
||||||
|
$socket->send("\x4f\x45\x74\x03\x00\x00\x00\x01");
|
||||||
|
local $SIG{ALRM} = sub { die "alarm time out"; };
|
||||||
|
alarm $config{ping_timeout};
|
||||||
|
$socket->recv($data, POSIX::BUFSIZ) or die "recv: $!";
|
||||||
|
alarm 0;
|
||||||
|
1; # return value from eval on normalcy
|
||||||
|
} or return 0;
|
||||||
|
return 0 unless length $data;
|
||||||
|
$time = float(time - $time);
|
||||||
|
warn "recvd: ", length $data, " [$time]" if $config{debug};
|
||||||
|
return $time;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub request (;$) {
|
||||||
|
my ($r) = @_;
|
||||||
|
$r ||= \%ENV;
|
||||||
|
my $param = get_params_utf8;
|
||||||
|
my $after = sub {
|
||||||
|
if ($param->{json}) {
|
||||||
|
my $j = {};
|
||||||
|
eval { $j = JSON->new->decode($param->{json}) || {} };
|
||||||
|
$param->{$_} = $j->{$_} for keys %$j;
|
||||||
|
delete $param->{json};
|
||||||
|
}
|
||||||
|
if (%$param) {
|
||||||
|
s/^false$// for values %$param;
|
||||||
|
$param->{ip} = $r->{REMOTE_ADDR};
|
||||||
|
for (@{$config{blacklist}}) {
|
||||||
|
return if $param->{ip} ~~ $_;
|
||||||
|
}
|
||||||
|
$param->{address} ||= $param->{ip};
|
||||||
|
if ($config{source_check} and name_to_ip_noc($param->{address}) ne $param->{ip} and !($param->{ip} ~~ $config{trusted})) {
|
||||||
|
warn("bad address [$param->{address}] ne [$param->{ip}]") if $config{debug};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$param->{port} ||= 30000;
|
||||||
|
$param->{key} = "$param->{ip}:$param->{port}";
|
||||||
|
$param->{off} = time if $param->{action} ~~ 'delete';
|
||||||
|
|
||||||
|
if ($config{ping} and $param->{action} ne 'delete') {
|
||||||
|
if ($config{mineping}) {
|
||||||
|
$param->{ping} = mineping($param->{ip}, $param->{port});
|
||||||
|
} else {
|
||||||
|
$ping->port_number($param->{port});
|
||||||
|
$ping->service_check(0);
|
||||||
|
my ($pingret, $duration, $ip) = $ping->ping($param->{address});
|
||||||
|
if ($ip ne $param->{ip} and !($param->{ip} ~~ $config{trusted})) {
|
||||||
|
warn "strange ping ip [$ip] != [$param->{ip}]" if $config{debug};
|
||||||
|
return if $config{source_check} and !($param->{ip} ~~ $config{trusted});
|
||||||
|
}
|
||||||
|
$param->{ping} = $duration if $pingret;
|
||||||
|
warn " PING t=$config{ping_timeout}, $param->{address}:$param->{port} = ( $pingret, $duration, $ip )" if $config{debug};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $list = read_json($config{list_full}) || {};
|
||||||
|
warn "readed[$config{list_full}] list size=", scalar @{$list->{list}};
|
||||||
|
my $listk = {map { $_->{key} => $_ } @{$list->{list}}};
|
||||||
|
my $old = $listk->{$param->{key}};
|
||||||
|
$param->{time} = $old->{time} if $param->{off};
|
||||||
|
$param->{time} ||= int time;
|
||||||
|
$param->{start} = $param->{action} ~~ 'start' ? $param->{time} : $old->{start} || $param->{time};
|
||||||
|
delete $param->{start} if $param->{off};
|
||||||
|
$param->{first} ||= $old->{first} || $old->{time} || $param->{time};
|
||||||
|
$param->{clients_top} = $old->{clients_top} if $old->{clients_top} > $param->{clients};
|
||||||
|
$param->{clients_top} ||= $param->{clients} || 0;
|
||||||
|
delete $param->{action};
|
||||||
|
$listk->{$param->{key}} = $param;
|
||||||
|
$list->{list} = [grep { $_->{time} > time - $config{time_purge} } values %$listk];
|
||||||
|
file_rewrite($config{list_full}, JSON->new->encode($list));
|
||||||
|
warn "writed[$config{list_full}] list size=", scalar @{$list->{list}};
|
||||||
|
$list->{list} = [
|
||||||
|
sort { $b->{clients} <=> $a->{clients} || $a->{start} <=> $b->{start} }
|
||||||
|
grep { $_->{time} > time - $config{time_alive} and !$_->{off} and (!$config{ping} or !$config{pingable} or $_->{ping}) }
|
||||||
|
@{$list->{list}}
|
||||||
|
];
|
||||||
|
file_rewrite($config{list_pub}, JSON->new->encode($list));
|
||||||
|
warn "writed[$config{list_pub}] list size=", scalar @{$list->{list}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return [200, ["Content-type", "application/json"], [JSON->new->encode({})]], $after;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub request_cgi {
|
||||||
|
my ($p, $after) = request(@_);
|
||||||
|
shift @$p;
|
||||||
|
printu join "\n", map { join ': ', @$_ } shift @$p;
|
||||||
|
printu "\n\n";
|
||||||
|
printu join '', map { join '', @$_ } @$p;
|
||||||
|
if (fork) {
|
||||||
|
unless ($config{debug}) {
|
||||||
|
close STDOUT;
|
||||||
|
close STDERR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$after->() if ref $after ~~ 'CODE';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request_cgi() unless caller;
|
14
util/master/style.css
Normal file
14
util/master/style.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
table {
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
border: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#table table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user