diff --git a/CHANGELOG-zh-cn.md b/CHANGELOG-zh-cn.md
deleted file mode 100644
index c09ca401..00000000
--- a/CHANGELOG-zh-cn.md
+++ /dev/null
@@ -1,134 +0,0 @@
-## ZeroNet 0.5.1 (2016-11-18)
-### 新增
-- 多语言界面
-- 新插件:为站点 HTML 与 JS 文件提供的翻译助手
-- 每个站点独立的 favicon
-
-### 修复
-- 并行可选文件下载
-
-## ZeroNet 0.5.0 (2016-11-08)
-### 新增
-- 新插件:允许在 ZeroHello 列出/删除/固定/管理文件
-- 新的 API 命令来关注用户的可选文件,与可选文件的请求统计
-- 新的可选文件总大小限制
-- 新插件:保存节点到数据库并在重启时保持它们,使得更快的可选文件搜索以及在没有 Tracker 的情况下工作
-- 重写 UPnP 端口打开器 + 退出时关闭端口(感谢 sirMackk!)
-- 通过懒惰 PeerHashfield 创建来减少内存占用
-- 在 /Stats 页面加载 JSON 文件统计与数据库信息
-
-### 更改
-- 独立的锁定文件来获得更好的 Windows 兼容性
-- 当执行 start.py 时,即使 ZeroNet 已经运行也打开浏览器
-- 在重载时保持插件顺序来允许插件扩展另一个插件
-- 只在完整加载 sites.json 时保存来避免数据丢失
-- 将更多的 Tracker 更改为更可靠的 Tracker
-- 更少的 findhashid CPU 使用率
-- 合并下载大量可选文件
-- 更多对于可选文件的其他优化
-- 如果一个站点有 1000 个节点,更积极地清理
-- 为验证错误使用警告而不是错误
-- 首先推送更新到更新的客户端
-- 损坏文件重置改进
-
-### 修复
-- 修复启动时出现的站点删除错误
-- 延迟 WebSocket 消息直到连接上
-- 修复如果文件包含额外数据时的数据库导入
-- 修复大站点下载
-- 修复 diff 发送 bug (跟踪它好长时间了)
-- 修复当 JSON 文件包含 [] 字符时随机出现的发布错误
-- 修复 siteDelete 与 siteCreate bug
-- 修复文件写入确认对话框
-
-
-## ZeroNet 0.4.1 (2016-09-05)
-### 新增
-- 更快启动与更少内存使用的内核改变
-- 尝试连接丢失时重新连接 Tor
-- 侧边栏滑入
-- 尝试避免不完整的数据文件被覆盖
-- 更快地打开数据库
-- 在侧边栏显示用户文件大小
-- 依赖 --connection_limit 的并发 worker 数量
-
-
-### 更改
-- 在空闲 5 分钟后关闭数据库
-- 更好的站点大小计算
-- 允许在域名中使用“-”符号
-- 总是尝试为站点保持连接
-- 移除已合并站点的合并权限
-- 只扫描最后 3 天的新闻源来加快数据库请求
-- 更新 ZeroBundle-win 到 Python 2.7.12
-
-
-### 修复
-- 修复重要的安全问题:允许任意用户无需有效的来自 ID 提供者的证书发布新内容,感谢 Kaffie 指出
-- 修复在没有选择提供证书提供者时的侧边栏错误
-- 在数据库重建时跳过无效文件
-- 修复随机弹出的 WebSocket 连接错误
-- 修复新的 siteCreate 命令
-- 修复站点大小计算
-- 修复计算机唤醒后的端口打开检查
-- 修复 --size_limit 的命令行解析
-
-
-## ZeroNet 0.4.0 (2016-08-11)
-### 新增
-- 合并站点插件
-- Live source code reloading: Faster core development by allowing me to make changes in ZeroNet source code without restarting it.
-- 为合并站点设计的新 JSON 表
-- 从侧边栏重建数据库
-- 允许直接在 JSON 表中存储自定义数据:更简单与快速的 SQL 查询
-- 用户文件存档:允许站点拥有者存档不活跃的用户内容到单个文件(减少初始同步的时间/CPU/内存使用率)
-- 在文件删除时同时触发数据库 onUpdated/update
-- 从 ZeroFrame API 请求权限
-- 允许使用 fileWrite API 命令在 content.json 存储额外数据
-- 更快的可选文件下载
-- 使用替代源 (Gogs, Gitlab) 来下载更新
-- Track provided sites/connection and prefer to keep the ones with more sites to reduce connection number
-
-### 更改
-- 保持每个站点至少 5 个连接
-- 将目标站点连接从 10 更改到 15
-- ZeroHello 搜索功能稳定性/速度改进
-- 提升机械硬盘下的客户端性能
-
-### 修复
-- 修复 IE11 wrapper nonce 错误
-- 修复在移动设备上的侧边栏
-- 修复站点大小计算
-- 修复 IE10 兼容性
-- Windows XP ZeroBundle 兼容性(感谢中国人民)
-
-
-## ZeroNet 0.3.7 (2016-05-27)
-### 更改
-- 通过只传输补丁来减少带宽使用
-- 其他 CPU /内存优化
-
-
-## ZeroNet 0.3.6 (2016-05-27)
-### 新增
-- 新的 ZeroHello
-- Newsfeed 函数
-
-### 修复
-- 安全性修复
-
-
-## ZeroNet 0.3.5 (2016-02-02)
-### 新增
-- 带有 .onion 隐藏服务的完整 Tor 支持
-- 使用 ZeroNet 协议的 Bootstrap
-
-### 修复
-- 修复 Gevent 1.0.2 兼容性
-
-
-## ZeroNet 0.3.4 (2015-12-28)
-### 新增
-- AES, ECIES API 函数支持
-- PushState 与 ReplaceState URL 通过 API 的操作支持
-- 多用户 localstorage
diff --git a/plugins/Sidebar/media/Internals.coffee b/plugins/Sidebar/media/Internals.coffee
deleted file mode 100644
index 484ecdb7..00000000
--- a/plugins/Sidebar/media/Internals.coffee
+++ /dev/null
@@ -1,60 +0,0 @@
-class Internals extends Class
- constructor: (@sidebar) ->
- @tag = null
- @opened = false
- if window.top.location.hash == "#internals"
- setTimeout (=> @open()), 10
-
- createHtmltag: ->
- @when_loaded = $.Deferred()
- if not @container
- @container = $("""
-
-
- """)
- @container.appendTo(document.body)
- @tag = @container.find(".internals")
-
- open: =>
- @createHtmltag()
- @sidebar.fixbutton_targety = @sidebar.page_height
- @stopDragY()
-
- onOpened: =>
- @sidebar.onClosed()
- @log "onOpened"
-
- onClosed: =>
- $(document.body).removeClass("body-internals")
-
- stopDragY: =>
- # Animate sidebar and iframe
- if @sidebar.fixbutton_targety == @sidebar.fixbutton_inity
- # Closed
- targety = 0
- @opened = false
- else
- # Opened
- targety = @sidebar.fixbutton_targety - @sidebar.fixbutton_inity
- @onOpened()
- @opened = true
-
- # Revent sidebar transitions
- if @tag
- @tag.css("transition", "0.5s ease-out")
- @tag.css("transform", "translateY(#{targety}px)").one transitionEnd, =>
- @tag.css("transition", "")
- if not @opened
- @log "cleanup"
- # Revert body transformations
- @log "stopdrag", "opened:", @opened, targety
- if not @opened
- @onClosed()
-
-window.Internals = Internals
\ No newline at end of file
diff --git a/plugins/Sidebar/media/Internals.css b/plugins/Sidebar/media/Internals.css
deleted file mode 100644
index 36b2489e..00000000
--- a/plugins/Sidebar/media/Internals.css
+++ /dev/null
@@ -1,17 +0,0 @@
-.internals-container { width: 100%; z-index: 998; position: absolute; top: -100vh; }
-.internals { background-color: #EEE; height: 100vh; transform: translateY(0px); }
-.internals-middle {height: 0px; top: 50%; position: absolute; width: 100%; left: 50%; }
-
-.internals .mynode {
- border: 0.5px solid #aaa; width: 50px; height: 50px; transform: rotateZ(45deg); margin-top: -25px; margin-left: -25px;
- opacity: 1; display: inline-block; background-color: #EEE; z-index: 9; position: absolute; outline: 5px solid #EEE;
-}
-.internals .peers { width: 0px; height: 0px; position: absolute; left: -20px; top: -20px; text-align: center; }
-.internals .peer { left: 0px; top: 0px; position: absolute; }
-.internals .peer .icon { width: 20px; height: 20px; padding: 10px; display: inline-block; text-decoration: none; left: 200px; position: absolute; color: #666; }
-.internals .peer .icon:before { content: "\25BC"; position: absolute; margin-top: 3px; margin-left: -1px; opacity: 0; transition: all 0.3s }
-.internals .peer .icon:hover:before { opacity: 1; transition: none }
-.internals .peer .line {
- width: 187px; border-top: 1px solid #CCC; position: absolute; top: 20px; left: 20px;
- transform: rotateZ(334deg); transform-origin: bottom left;
-}
\ No newline at end of file
diff --git a/plugins/Stats/StatsPlugin.py b/plugins/Stats/StatsPlugin.py
index e0c410db..6fb182ae 100644
--- a/plugins/Stats/StatsPlugin.py
+++ b/plugins/Stats/StatsPlugin.py
@@ -373,6 +373,7 @@ class UiRequestPlugin(object):
gc.collect() # Implicit grabage collection
yield "Done in %.1f" % (time.time() - s)
+ @helper.encodeResponse
def actionDumpobj(self):
import gc
@@ -410,6 +411,7 @@ class UiRequestPlugin(object):
gc.collect() # Implicit grabage collection
+ @helper.encodeResponse
def actionListobj(self):
import gc
@@ -827,6 +829,7 @@ class UiRequestPlugin(object):
yield "
Done. Total: %.2fs" % (time.time() - t)
+ @helper.encodeResponse
def actionGcCollect(self):
import gc
self.sendHeader()
diff --git a/plugins/disabled-Bootstrapper/BootstrapperDb.py b/plugins/disabled-Bootstrapper/BootstrapperDb.py
index fcc428f7..3c47b76d 100644
--- a/plugins/disabled-Bootstrapper/BootstrapperDb.py
+++ b/plugins/disabled-Bootstrapper/BootstrapperDb.py
@@ -26,7 +26,7 @@ class BootstrapperDb(Db.Db):
def updateHashCache(self):
res = self.execute("SELECT * FROM hash")
- self.hash_ids = {str(row["hash"]): row["hash_id"] for row in res}
+ self.hash_ids = {row["hash"]: row["hash_id"] for row in res}
self.log.debug("Loaded %s hash_ids" % len(self.hash_ids))
def checkTables(self):
diff --git a/plugins/disabled-Bootstrapper/BootstrapperPlugin.py b/plugins/disabled-Bootstrapper/BootstrapperPlugin.py
index b6d9e178..474f79c1 100644
--- a/plugins/disabled-Bootstrapper/BootstrapperPlugin.py
+++ b/plugins/disabled-Bootstrapper/BootstrapperPlugin.py
@@ -130,6 +130,7 @@ class FileRequestPlugin(object):
@PluginManager.registerTo("UiRequest")
class UiRequestPlugin(object):
+ @helper.encodeResponse
def actionStatsBootstrapper(self):
self.sendHeader()
diff --git a/plugins/disabled-Bootstrapper/Test/TestBootstrapper.py b/plugins/disabled-Bootstrapper/Test/TestBootstrapper.py
index 983cb44c..69bdc54c 100644
--- a/plugins/disabled-Bootstrapper/Test/TestBootstrapper.py
+++ b/plugins/disabled-Bootstrapper/Test/TestBootstrapper.py
@@ -27,6 +27,28 @@ def bootstrapper_db(request):
@pytest.mark.usefixtures("resetSettings")
class TestBootstrapper:
+ def testHashCache(self, file_server, bootstrapper_db):
+ ip_type = helper.getIpType(file_server.ip)
+ peer = Peer(file_server.ip, 1544, connection_server=file_server)
+ hash1 = hashlib.sha256(b"site1").digest()
+ hash2 = hashlib.sha256(b"site2").digest()
+ hash3 = hashlib.sha256(b"site3").digest()
+
+ # Verify empty result
+ res = peer.request("announce", {
+ "hashes": [hash1, hash2],
+ "port": 15441, "need_types": [ip_type], "need_num": 10, "add": [ip_type]
+ })
+
+ assert len(res["peers"][0][ip_type]) == 0 # Empty result
+
+ hash_ids_before = bootstrapper_db.hash_ids.copy()
+
+ bootstrapper_db.updateHashCache()
+
+ assert hash_ids_before == bootstrapper_db.hash_ids
+
+
def testBootstrapperDb(self, file_server, bootstrapper_db):
ip_type = helper.getIpType(file_server.ip)
peer = Peer(file_server.ip, 1544, connection_server=file_server)
diff --git a/src/Config.py b/src/Config.py
index 13a8ec44..4613940b 100644
--- a/src/Config.py
+++ b/src/Config.py
@@ -13,7 +13,7 @@ class Config(object):
def __init__(self, argv):
self.version = "0.7.0"
- self.rev = 4122
+ self.rev = 4126
self.argv = argv
self.action = None
self.pending_changes = {}
@@ -409,7 +409,7 @@ class Config(object):
self.config_file = argv[argv.index("--config_file") + 1]
# Load config file
if os.path.isfile(self.config_file):
- config = configparser.ConfigParser(allow_no_value=True, strict=False)
+ config = configparser.RawConfigParser(allow_no_value=True, strict=False)
config.read(self.config_file)
for section in config.sections():
for key, val in config.items(section):
diff --git a/src/Debug/DebugReloader.py b/src/Debug/DebugReloader.py
index e6cdec06..29ca7029 100644
--- a/src/Debug/DebugReloader.py
+++ b/src/Debug/DebugReloader.py
@@ -44,6 +44,9 @@ class DebugReloader:
self.last_chaged = time.time()
time_modified = os.path.getmtime(path)
self.log.debug("File changed: %s reloading source code (modified %.3fs ago)" % (evt, time.time() - time_modified))
+ if time.time() - time_modified > 5: # Probably it's just an attribute change, ignore it
+ return False
+
time.sleep(0.1) # Wait for lock release
for callback in self.callbacks:
try:
diff --git a/zeronet.py b/zeronet.py
index 03c9865d..73339c3f 100755
--- a/zeronet.py
+++ b/zeronet.py
@@ -26,7 +26,12 @@ def main():
print("Failed to log error:", log_err)
traceback.print_exc()
from Config import config
- traceback.print_exc(file=open(config.log_dir + "/error.log", "a"))
+ error_log_path = config.log_dir + "/error.log"
+ traceback.print_exc(file=open(error_log_path, "w"))
+ print("---")
+ print("Please report it: https://github.com/HelloZeroNet/ZeroNet/issues/new?assignees=&labels=&template=bug-report.md")
+ if sys.platform.startswith("win"):
+ displayErrorMessage(err, error_log_path)
if main and (main.update_after_shutdown or main.restart_after_shutdown): # Updater
if main.update_after_shutdown:
@@ -37,6 +42,28 @@ def main():
print("Restarting...")
restart()
+def displayErrorMessage(err, error_log_path):
+ import ctypes
+ import urllib.parse
+ import subprocess
+
+ MB_YESNOCANCEL = 0x3
+ MB_ICONEXCLAIMATION = 0x30
+
+ ID_YES = 0x6
+ ID_NO = 0x7
+ ID_CANCEL = 0x2
+
+ err_message = "%s: %s" % (type(err).__name__, err)
+
+ res = ctypes.windll.user32.MessageBoxW(0, "Unhandled exception: %s\nReport error?" % err_message, "ZeroNet error", MB_YESNOCANCEL | MB_ICONEXCLAIMATION)
+ if res == ID_YES:
+ import webbrowser
+ report_url = "https://github.com/HelloZeroNet/ZeroNet/issues/new?assignees=&labels=&template=bug-report.md&title=%s"
+ webbrowser.open(report_url % urllib.parse.quote("Unhandled exception: %s" % err_message))
+ if res in [ID_YES, ID_NO]:
+ subprocess.Popen(['notepad.exe', error_log_path])
+
def restart():
if "main" in sys.modules: