shadowsocks / shadowsocks-windows

A C# port of shadowsocks
Other
58.41k stars 16.4k forks source link

gfwlist.txt 修改后 user-rule.txt 会随机失效,user-rule.txt 中随便添加几个空格又会随机生效 #1332

Closed osdu closed 6 years ago

osdu commented 7 years ago

gfwlist.txt 修改后 user-rule.txt 会随机失效,user-rule.txt 中随便添加几个空格又会随机生效

gfwlist.txt 大批量删除规则重新保存后会出现这个问题

修改后的 gfwlist.txt

W0F1dG9Qcm94eSAwLjIuOV0KISBDaGVja3N1bTogMzAyM2t1NEV1Y1ZpZFJMQUZLb3ZDdwohIEV4
cGlyZXM6IDZoCiEgVGl0bGU6IEdGV0xpc3Q0TEwKISBHRldMaXN0IHdpdGggRVZFUllUSElORyBp
bmNsdWRlZAohIExhc3QgTW9kaWZpZWQ6IFNhdCwgMTkgQXVnIDIwMTcgMDI6MjQ6MjQgLTA0MDAK
IQohIEhvbWVQYWdlOiBodHRwczovL2dpdGh1Yi5jb20vZ2Z3bGlzdC9nZndsaXN0CiEgTGljZW5z
ZTogaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2dmd2xpc3QvZ2Z3bGlzdC9tYXN0
ZXIvQ09QWUlORy50eHQKIQohIEdGV0xpc3QgaXMgdW5saWtlbHkgdG8gZnVsbHkgY29tcHJpc2Ug
dGhlIHJlYWwKISBydWxlcyBiZWluZyBkZXBsb3llZCBpbnNpZGUgR0ZXIHN5c3RlbS4gV2UgdHJ5
CiEgb3VyIGJlc3QgdG8ga2VlcCB0aGUgbGlzdCB1cCB0byBkYXRlLiBQbGVhc2UKISBjb250YWN0
IHVzIHJlZ2FyZGluZyBVUkwgc3VibWlzc2lvbiAvIHJlbW92YWwsCiEgb3Igc3VnZ2VzdGlvbiAv
IGVuaGFuY2VtZW50IGF0IGlzc3VlIHRyYWNrZXI6CiEgaHR0cHM6Ly9naXRodWIuY29tL2dmd2xp
c3QvZ2Z3bGlzdC9pc3N1ZXMvLgoKIS0tLS0tLS0tLTQwMy80NTEvNTIwICYgVVJMIFJlZGlyZWN0
cy0tLS0tLS0tLQp8fDJkYm9vay5jb20KfHw0dGVybi5jb20KCiEtLS0tLS0tLS0tLS0tLS0tLS0t
LS1FT0YtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQo=

local 会出现随机为空的情况

string local = FileManager.NonExclusiveReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8);

qq 20170820174818

qq 20170820175650

qq 20170820175748

chenshaoju commented 7 years ago

@celeron533

wongsyrone commented 7 years ago

user-rule.ini??

osdu commented 7 years ago

@wongsyrone 我自己修改扩展名了,txt 不能语法高亮。 我试过官方版本都有同样的问题

第一张图是官方版本的,后两张是我自己修改后编译的版本,都有同样的问题。

这是我的修改记录 https://github.com/osdu/shadowsocks-windows-for-anmpserver/commits/master

celeron533 commented 7 years ago

以前为了能实时按照user-rule更新PAC,使用了FileSystemWatcher b2c2d05c940cf7249c3597274cd5a3281b93749b 怀疑

            UserRuleFileWatcher = new FileSystemWatcher(Directory.GetCurrentDirectory());
            UserRuleFileWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
            UserRuleFileWatcher.Filter = USER_RULE_FILE;
            UserRuleFileWatcher.Changed += UserRuleFileWatcher_Changed;
            UserRuleFileWatcher.Created += UserRuleFileWatcher_Changed;
            UserRuleFileWatcher.Deleted += UserRuleFileWatcher_Changed;
            UserRuleFileWatcher.Renamed += UserRuleFileWatcher_Changed;
            UserRuleFileWatcher.EnableRaisingEvents = true;

在处理的时候发生了意外

现存代码还有段dirty hack ...

osdu commented 7 years ago

@celeron533 这个好像会受到 gfwlist.txt 和 user-rule.txt 所含内容或者是文件大小的影响,具体原因不明。 我没学过 .Net 没能力深入排查,还望大神给解决下。

因为平时做PHP开发,需要翻墙的网站不多,就想重新定制一份精简的 gfwlist.txt,在精简gfwlist.txt过程中发现这个问题。

celeron533 commented 7 years ago

@osdu 如果仅限于浏览器的话,chrome系的可以用switchyomega自定义代理切换规则 https://github.com/FelisCatus/SwitchyOmega/releases

有详细的重现过程吗? 主要是user-rule的文件大小还是gfwlist的文件大小? 如果使用经典notepad.exe是否会有这样的问题?记得notepad++不是使用独占模式打开的文件

另外notepad++在打开文件后,可以手动指定语法高亮的语言的

osdu commented 7 years ago

@celeron533

使用我修改后的 gfwlist.txt 替换 ss_win_temp 目录下的 gfwlist.txt, 然后编辑 user-rule.txt,打开自动生成的pac文件可以看到gfwlist.txt里边的规则解析出来了,但是 user-rule.txt 里边的自定义规则却没生效。

gfwlist.txt 内如如下

W0F1dG9Qcm94eSAwLjIuOV0KISBDaGVja3N1bTogMzAyM2t1NEV1Y1ZpZFJMQUZLb3ZDdwohIEV4
cGlyZXM6IDZoCiEgVGl0bGU6IEdGV0xpc3Q0TEwKISBHRldMaXN0IHdpdGggRVZFUllUSElORyBp
bmNsdWRlZAohIExhc3QgTW9kaWZpZWQ6IFNhdCwgMTkgQXVnIDIwMTcgMDI6MjQ6MjQgLTA0MDAK
IQohIEhvbWVQYWdlOiBodHRwczovL2dpdGh1Yi5jb20vZ2Z3bGlzdC9nZndsaXN0CiEgTGljZW5z
ZTogaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2dmd2xpc3QvZ2Z3bGlzdC9tYXN0
ZXIvQ09QWUlORy50eHQKIQohIEdGV0xpc3QgaXMgdW5saWtlbHkgdG8gZnVsbHkgY29tcHJpc2Ug
dGhlIHJlYWwKISBydWxlcyBiZWluZyBkZXBsb3llZCBpbnNpZGUgR0ZXIHN5c3RlbS4gV2UgdHJ5
CiEgb3VyIGJlc3QgdG8ga2VlcCB0aGUgbGlzdCB1cCB0byBkYXRlLiBQbGVhc2UKISBjb250YWN0
IHVzIHJlZ2FyZGluZyBVUkwgc3VibWlzc2lvbiAvIHJlbW92YWwsCiEgb3Igc3VnZ2VzdGlvbiAv
IGVuaGFuY2VtZW50IGF0IGlzc3VlIHRyYWNrZXI6CiEgaHR0cHM6Ly9naXRodWIuY29tL2dmd2xp
c3QvZ2Z3bGlzdC9pc3N1ZXMvLgoKIS0tLS0tLS0tLTQwMy80NTEvNTIwICYgVVJMIFJlZGlyZWN0
cy0tLS0tLS0tLQp8fDJkYm9vay5jb20KfHw0dGVybi5jb20KCiEtLS0tLS0tLS0tLS0tLS0tLS0t
LS1FT0YtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQo=

复现视频链接 https://www.youtube.com/watch?v=tMVFOW-CsnQ

只在 user-rule.ini 增删空格,在视频50-55 秒之间可看到 pac.txt 体积在 22KB61KB 之间变化

gfwlist.txt 规则始终是生效的,user-rule.ini 是否生效毫无规律可言

celeron533 commented 7 years ago

用vscode编辑user-rule.txt,发现依旧存在两次保存的现象,第一次清空了文件,第二次把新内容存了进去。 目前的PAC生成逻辑在某些情况下仅被第一次保存行为激发,而忽略第二次

https://stackoverflow.com/a/1765094/2075611

Notepad writes to the disk in batches that create the content of the file and then the file attributes. Other applications may perform in the same manner.

osdu commented 7 years ago

@celeron533 做个延时处理能否解决这个问题? 就是检测到改后做500ms延时,保证编辑器顺利写入user-rule.txt文件后再重写读入user-rule.txt内容


刚测试过管用,至于有没有其他副作用就不清楚了 https://github.com/osdu/shadowsocks-windows-for-anmpserver/commit/4ead4113ff2e0da14f3d204fc01564d7e32cc3c0

celeron533 commented 7 years ago

https://ci.appveyor.com/project/celeron533/shadowsocks-windows-3j4p4/build/4.0.5.8/job/ir2wenqvgdqx3b8v/artifacts

请试用一下 https://github.com/celeron533/shadowsocks-windows/commit/71f87955dcfefee55d83318920a3e4892af9fa5a

osdu commented 7 years ago

@celeron533 貌似可以了,只是看不明白 currentLastWriteTime string 改成 DateTime 就可以了?

感觉 shadowsocks-csharp/Data/proxy.pac.txt.gz 暂时没必要更新,改完就和 abp.js.gz 功能重复了

celeron533 commented 7 years ago

proxy.pac.txt.gz 不应该更新的。没关系,是我自己的repo,过会儿force push掉。 currentLastWriteTime.ToString() 的时候会掉精度,所以后面的判断语句在某些情况下会认为两次FileChange都是同一时刻,而忽略第二次的event。可惜在有些文本编辑器上是先清空文件再重写内容,此时重写的内容就被忽略。 但如果保持精度的话,那个关于时间的IF判断就变得没用了,因为几乎不可能相同

wongsyrone commented 7 years ago

另一个方案

        // DateTime only has millisecond resolution
        // these two DateTimes are used as long as the program is running
        private static DateTime _pacLastWriteDateTime = DateTime.MinValue;
        private static DateTime _userRuleLastWriteDateTime = DateTime.MinValue;
        // make the timespan sane for checking in case we catch events multiple times
        private static readonly TimeSpan LastWriteCheckSpan = TimeSpan.FromSeconds(1);

        private void PACFileWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            var path = e.FullPath;
            DateTime lastWriteTime = File.GetLastWriteTime(path);
            if (lastWriteTime - _pacLastWriteDateTime > LastWriteCheckSpan)
            {
                if (PACFileChanged != null)
                {
                    Logging.Info($"Detected: PAC file {e.Name} {e.ChangeType}.");
                    PACFileChanged(this, new EventArgs());
                }
                _pacLastWriteDateTime = lastWriteTime;
            }

        }

        private void UserRuleFileWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            var path = e.FullPath;
            DateTime lastWriteTime = File.GetLastWriteTime(path);
            if (lastWriteTime - _userRuleLastWriteDateTime > LastWriteCheckSpan)
            {
                if (UserRuleFileChanged != null)
                {
                    Logging.Info($"Detected: User Rule file {e.Name} {e.ChangeType}.");
                    UserRuleFileChanged(this, new EventArgs());
                }
                _userRuleLastWriteDateTime = lastWriteTime;
            }
        }
celeron533 commented 7 years ago

@wongsyrone 这个写法可能还是有逻辑问题,假设_userRuleLastWriteDateTime为2分钟前最后一次读写,你开了文本编辑器再次保存文件(触发2次change),按照目前逻辑第一次change的时差为2分钟,第二次change时差和前次只有几毫秒,不会走进if语句吧。所以第二次保存依旧被miss掉。 每次保存的时候将文件相关对象保存到一个变量(多次change这个文件仅保留最后一次记录)并启动唯一计时器,特定延时后保存

wongsyrone commented 7 years ago

事实上两次change的原因是第一次保存文件,第二次修改文件属性,比如修改lastwrite等。第一次已经足够了,不用区分两次触发。

celeron533 commented 7 years ago

使用vscode编辑文件:

  1. 什么都不做的话,直接点击保存,触发一次change事件,读到的文件内容不变,仅修改文件属性。
  2. 更改内容后保存,触发两次change事件。第一次读到的是空文件,第二次读到的是修改后的新内容。

各种文本编辑器有各种不同的行为,头痛。

wongsyrone commented 7 years ago

我这有一些有趣的log

[2017-08-28 09:49:43] Detected: PAC file pac.txt Created 736568.09:49:43.1066383. [2017-08-28 09:49:49] Detected: User Rule file user-rule.txt Created 736568.09:49:49.7043727. [2017-08-28 09:50:02] Detected: User Rule file user-rule.txt Changed 00:00:12.4706746. [2017-08-28 09:50:02] Detected: PAC file pac.txt Changed 00:00:19.0864094. [2017-08-28 09:50:02] Detected: PAC file pac.txt Changed 00:00:00.0010021. [2017-08-28 09:50:35] Detected: User Rule file user-rule.txt Changed 00:00:32.8794936. [2017-08-28 09:50:35] Detected: PAC file pac.txt Changed 00:00:32.8674470. [2017-08-28 09:50:35] Detected: PAC file pac.txt Changed 00:00:00.0010008. [2017-08-28 09:50:40] Detected: User Rule file user-rule.txt Deleted -152180.01:50:35.0545409. [2017-08-28 09:51:17] Detected: PAC file pac.txt Deleted -152180.01:50:35.0624976. [2017-08-28 09:59:25] Detected: PAC file pac.txt Created 2017/8/28 9:59:25. [2017-08-28 09:59:46] Detected: User Rule file user-rule.txt Created 2017/8/28 9:59:46. [2017-08-28 09:59:54] Detected: User Rule file user-rule.txt Changed 2017/8/28 9:59:54. [2017-08-28 09:59:54] Detected: PAC file pac.txt Changed 2017/8/28 9:59:54. [2017-08-28 09:59:58] Detected: User Rule file user-rule.txt Changed 2017/8/28 9:59:58. [2017-08-28 09:59:58] Detected: PAC file pac.txt Changed 2017/8/28 9:59:58. [2017-08-28 09:59:58] Detected: PAC file pac.txt Changed 2017/8/28 9:59:58. [2017-08-28 10:00:04] Detected: User Rule file user-rule.txt Deleted 1601/1/1 8:00:00. [2017-08-28 10:00:05] Detected: PAC file pac.txt Deleted 1601/1/1 8:00:00. [2017-08-28 10:07:48] Detected: PAC file pac.txt Created. [2017-08-28 10:07:48] Detected: PAC file pac.txt Changed 2017/8/28 10:07:48. [2017-08-28 10:08:14] Detected: User Rule file user-rule.txt Created. [2017-08-28 10:08:14] Detected: User Rule file user-rule.txt Changed 2017/8/28 10:08:14. [2017-08-28 10:08:58] Detected: User Rule file user-rule.txt Changed 2017/8/28 10:08:58. [2017-08-28 10:08:58] Detected: PAC file pac.txt Changed 2017/8/28 10:08:58. [2017-08-28 10:09:01] Detected: User Rule file user-rule.txt Changed 2017/8/28 10:09:01. [2017-08-28 10:09:01] Detected: PAC file pac.txt Changed 2017/8/28 10:09:01. [2017-08-28 10:09:05] Detected: User Rule file user-rule.txt Deleted. [2017-08-28 10:09:06] Detected: PAC file pac.txt Deleted. [2017-08-28 10:10:54] Detected: PAC file pac.txt Created. [2017-08-28 10:11:04] Detected: User Rule file user-rule.txt Created. [2017-08-28 10:11:25] Detected: User Rule file user-rule.txt Changed 2017/8/28 10:11:25. [2017-08-28 10:11:25] Detected: PAC file pac.txt Changed 2017/8/28 10:11:25. [2017-08-28 10:11:29] Detected: User Rule file user-rule.txt Changed 2017/8/28 10:11:29. [2017-08-28 10:11:29] Detected: PAC file pac.txt Changed 2017/8/28 10:11:29. [2017-08-28 10:11:31] Detected: User Rule file user-rule.txt Deleted. [2017-08-28 10:11:32] Detected: PAC file pac.txt Deleted.

改过的代码

        // DateTime only has millisecond resolution
        // these two DateTimes are used as long as the program is running
        private static DateTime _pacLastWriteDateTime = DateTime.MinValue;
        private static DateTime _userRuleLastWriteDateTime = DateTime.MinValue;
        // make the timespan sane for checking in case we catch Changed events multiple times
        private static readonly TimeSpan LastWriteCheckSpan = TimeSpan.FromMilliseconds(2);

        private void PACFileWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            if (e.ChangeType == WatcherChangeTypes.Created ||
                e.ChangeType == WatcherChangeTypes.Deleted ||
                e.ChangeType == WatcherChangeTypes.Renamed)
            {
                _pacLastWriteDateTime = DateTime.Now;
                if (PACFileChanged != null)
                {
                    Logging.Info($"Detected: PAC file {e.Name} {e.ChangeType}.");
                    PACFileChanged(this, new EventArgs());
                }
                return;
            }
            var path = e.FullPath;
            DateTime lastWriteTime = File.GetLastWriteTime(path);
            var timeDiff = lastWriteTime - _pacLastWriteDateTime;
            if (timeDiff > LastWriteCheckSpan)
            {
                _pacLastWriteDateTime = lastWriteTime;
                if (PACFileChanged != null)
                {
                    Logging.Info($"Detected: PAC file {e.Name} {e.ChangeType}.");
                    PACFileChanged(this, new EventArgs());
                }
            }

        }

        private void UserRuleFileWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            if (e.ChangeType == WatcherChangeTypes.Created ||
                e.ChangeType == WatcherChangeTypes.Deleted ||
                e.ChangeType == WatcherChangeTypes.Renamed)
            {
                _userRuleLastWriteDateTime = DateTime.Now;
                if (UserRuleFileChanged != null)
                {
                    Logging.Info($"Detected: User Rule file {e.Name} {e.ChangeType}.");
                    UserRuleFileChanged(this, new EventArgs());
                }
                return;
            }
            var path = e.FullPath;
            DateTime lastWriteTime = File.GetLastWriteTime(path);
            var timeDiff = lastWriteTime - _userRuleLastWriteDateTime;
            if (timeDiff > LastWriteCheckSpan)
            {
                _userRuleLastWriteDateTime = lastWriteTime;
                if (UserRuleFileChanged != null)
                {
                    Logging.Info($"Detected: User Rule file {e.Name} {e.ChangeType}.");
                    UserRuleFileChanged(this, new EventArgs());
                }
            }
        }
osdu commented 7 years ago

@celeron533

做了下延时处理,使用一天,貌似一切正常

Thread.Sleep(250);

https://github.com/osdu/shadowsocks-windows-for-anmpserver/commit/4ead4113ff2e0da14f3d204fc01564d7e32cc3c0

celeron533 commented 6 years ago

做了下延时处理,使用一天,貌似一切正常

以后再看看有没有更“优雅”的方法

celeron533 commented 6 years ago

目前官方关于FileSystemWatcher两次执行的讨论 https://github.com/dotnet/corefx/issues/25117