diff --git a/Program.cs b/Program.cs index eb8e099..4d76dd4 100644 --- a/Program.cs +++ b/Program.cs @@ -9,7 +9,6 @@ using System.Net; using System.Net.Http; using System.Net.WebSockets; -using System.Runtime.Serialization.Json; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -425,8 +424,8 @@ static async Task GetNicovideoStreamAsync(string lvId, string cookie, Bl match = Regex.Match(match.Groups[1].Value, " data-props=\"([^\"]*)\""); if (match.Success) { - var js = new DataContractJsonSerializer(typeof(WatchEmbedded)); - var embedded = (WatchEmbedded)js.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(HttpUtility.HtmlDecode(match.Groups[1].Value)))); + var js = new DataContractJsonSerializerWrapper(); + WatchEmbedded embedded = js.ReadValue(Encoding.UTF8.GetBytes(HttpUtility.HtmlDecode(match.Groups[1].Value))); // 一応ドメインを検査しておく(スクレイピングなので。また、cookieを送信するため) if (embedded.site != null && embedded.site.relive != null && Regex.IsMatch(embedded.site.relive.webSocketUrl ?? "", @"^wss://[0-9A-Za-z.-]+\.nicovideo\.jp/")) @@ -502,12 +501,12 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen bool wroteFirstChat = false; bool wroteLiveChat = false; - var jsWatchSessionPost = new DataContractJsonSerializer(typeof(WatchSessionPost)); - var jsWatchSessionResult = new DataContractJsonSerializer(typeof(WatchSessionResult)); - var jsWatchSessionResultForError = new DataContractJsonSerializer(typeof(WatchSessionResultForError)); - var jsWatchSessionResultForMessageServer = new DataContractJsonSerializer(typeof(WatchSessionResultForMessageServer)); - var jsWatchSessionResultForSeat = new DataContractJsonSerializer(typeof(WatchSessionResultForSeat)); - var jsWatchSessionResultForServerTime = new DataContractJsonSerializer(typeof(WatchSessionResultForServerTime)); + var jsWatchSessionPost = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResult = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResultForError = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResultForMessageServer = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResultForSeat = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResultForServerTime = new DataContractJsonSerializerWrapper(); string nextAt = "now"; bool closed = false; @@ -585,7 +584,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen // vposは10msec単位。内部時計のずれに影響されないようにサーバ時刻を基準に補正 int vpos = (int)(serverUnixTime - vposBaseUnixTime).TotalSeconds * 100 + (((Environment.TickCount & int.MaxValue) - serverUnixTimeTick) & int.MaxValue) / 10; var ms = new MemoryStream(); - jsWatchSessionPost.WriteObject(ms, new WatchSessionPost() + jsWatchSessionPost.WriteValue(ms, new WatchSessionPost() { data = new WatchSessionPostData() { @@ -747,7 +746,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen if (watchReceived) { - var message = (WatchSessionResult)jsWatchSessionResult.ReadObject(new MemoryStream(watchBuf, 0, watchCount)); + WatchSessionResult message = jsWatchSessionResult.ReadValue(watchBuf, 0, watchCount); switch (message.type) { case "disconnect": @@ -759,7 +758,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen case "error": Trace.WriteLine("error"); { - var error = ((WatchSessionResultForError)jsWatchSessionResultForError.ReadObject(new MemoryStream(watchBuf, 0, watchCount))).data; + WatchSessionResultError error = jsWatchSessionResultForError.ReadValue(watchBuf, 0, watchCount).data; if (error != null) { Trace.WriteLine(Encoding.UTF8.GetString(watchBuf, 0, watchCount)); @@ -778,7 +777,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen Trace.WriteLine("messageServer"); // メッセージサーバの接続先情報 { - var messageServer = ((WatchSessionResultForMessageServer)jsWatchSessionResultForMessageServer.ReadObject(new MemoryStream(watchBuf, 0, watchCount))).data; + WatchSessionResultMessageServer messageServer = jsWatchSessionResultForMessageServer.ReadValue(watchBuf, 0, watchCount).data; if (messageServer != null) { if (messageServer.vposBaseTime != null && vposBaseUnixTime <= TimeSpan.Zero) @@ -816,7 +815,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen case "seat": Trace.WriteLine("seat"); { - var seat = ((WatchSessionResultForSeat)jsWatchSessionResultForSeat.ReadObject(new MemoryStream(watchBuf, 0, watchCount))).data; + WatchSessionResultSeat seat = jsWatchSessionResultForSeat.ReadValue(watchBuf, 0, watchCount).data; if (seat != null) { keepSeatIntervalSec = Math.Min((int)seat.keepIntervalSec, 1000); @@ -827,7 +826,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen case "serverTime": Trace.WriteLine("serverTime"); { - var serverTime = ((WatchSessionResultForServerTime)jsWatchSessionResultForServerTime.ReadObject(new MemoryStream(watchBuf, 0, watchCount))).data; + WatchSessionResultServerTime serverTime = jsWatchSessionResultForServerTime.ReadValue(watchBuf, 0, watchCount).data; if (serverTime != null && serverTime.currentMs != null) { DateTime d; @@ -1006,13 +1005,13 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen bool wroteFirstChat = false; bool wroteLiveChat = false; - var jsWatchSessionPost = new DataContractJsonSerializer(typeof(WatchSessionPost)); - var jsWatchSessionResult = new DataContractJsonSerializer(typeof(WatchSessionResult)); - var jsWatchSessionResultForError = new DataContractJsonSerializer(typeof(WatchSessionResultForError)); - var jsWatchSessionResultForRoom = new DataContractJsonSerializer(typeof(WatchSessionResultForRoom)); - var jsWatchSessionResultForSeat = new DataContractJsonSerializer(typeof(WatchSessionResultForSeat)); - var jsWatchSessionResultForServerTime = new DataContractJsonSerializer(typeof(WatchSessionResultForServerTime)); - var jsCommentSessionResult = new DataContractJsonSerializer(typeof(CommentSessionResult)); + var jsWatchSessionPost = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResult = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResultForError = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResultForRoom = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResultForSeat = new DataContractJsonSerializerWrapper(); + var jsWatchSessionResultForServerTime = new DataContractJsonSerializerWrapper(); + var jsCommentSessionResult = new DataContractJsonSerializerWrapper(); bool closed = false; while (!closed) @@ -1084,7 +1083,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen // vposは10msec単位。内部時計のずれに影響されないようにサーバ時刻を基準に補正 int vpos = (int)(serverUnixTime - vposBaseUnixTime).TotalSeconds * 100 + (((Environment.TickCount & int.MaxValue) - serverUnixTimeTick) & int.MaxValue) / 10; var ms = new MemoryStream(); - jsWatchSessionPost.WriteObject(ms, new WatchSessionPost() + jsWatchSessionPost.WriteValue(ms, new WatchSessionPost() { data = new WatchSessionPostData() { @@ -1144,7 +1143,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen if (watchReceived) { - var message = (WatchSessionResult)jsWatchSessionResult.ReadObject(new MemoryStream(watchBuf, 0, watchCount)); + WatchSessionResult message = jsWatchSessionResult.ReadValue(watchBuf, 0, watchCount); switch (message.type) { case "disconnect": @@ -1156,7 +1155,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen case "error": Trace.WriteLine("error"); { - var error = ((WatchSessionResultForError)jsWatchSessionResultForError.ReadObject(new MemoryStream(watchBuf, 0, watchCount))).data; + WatchSessionResultError error = jsWatchSessionResultForError.ReadValue(watchBuf, 0, watchCount).data; if (error != null) { Trace.WriteLine(Encoding.UTF8.GetString(watchBuf, 0, watchCount)); @@ -1185,7 +1184,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen Trace.WriteLine("room"); if (!commentConnected) { - var room = ((WatchSessionResultForRoom)jsWatchSessionResultForRoom.ReadObject(new MemoryStream(watchBuf, 0, watchCount))).data; + WatchSessionResultRoom room = jsWatchSessionResultForRoom.ReadValue(watchBuf, 0, watchCount).data; if (room != null) { // 適当なタグをでっちあげてxmlに変換 @@ -1207,9 +1206,9 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen if (room.threadId != null && room.messageServer != null && room.messageServer.uri != null && room.messageServer.uri.StartsWith("wss://", StringComparison.Ordinal)) { - var js = new DataContractJsonSerializer(typeof(List)); + var js = new DataContractJsonSerializerWrapper>(); var ms = new MemoryStream(); - js.WriteObject(ms, new List() + js.WriteValue(ms, new List() { new CommentSessionOpen() { ping = new ContentContainer() { content = "rs: 0" } }, new CommentSessionOpen() { ping = new ContentContainer() { content = "ps: 0" } }, @@ -1235,7 +1234,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen case "seat": Trace.WriteLine("seat"); { - var seat = ((WatchSessionResultForSeat)jsWatchSessionResultForSeat.ReadObject(new MemoryStream(watchBuf, 0, watchCount))).data; + WatchSessionResultSeat seat = jsWatchSessionResultForSeat.ReadValue(watchBuf, 0, watchCount).data; if (seat != null) { keepSeatIntervalSec = Math.Min((int)seat.keepIntervalSec, 1000); @@ -1246,7 +1245,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen case "serverTime": Trace.WriteLine("serverTime"); { - var serverTime = ((WatchSessionResultForServerTime)jsWatchSessionResultForServerTime.ReadObject(new MemoryStream(watchBuf, 0, watchCount))).data; + WatchSessionResultServerTime serverTime = jsWatchSessionResultForServerTime.ReadValue(watchBuf, 0, watchCount).data; if (serverTime != null && serverTime.currentMs != null) { DateTime d; @@ -1267,7 +1266,7 @@ await DoWebSocketAction(async ct => await watchSession.SendAsync(new ArraySegmen if (commentReceived) { // jsonをxmlに変換(もっと賢い方法ありそうだが属性の順序など維持したいので…) - var message = (CommentSessionResult)jsCommentSessionResult.ReadObject(new MemoryStream(commentBuf, 0, commentCount)); + CommentSessionResult message = jsCommentSessionResult.ReadValue(commentBuf, 0, commentCount); if (message.chat != null && serverUnixTime > TimeSpan.Zero) { TimeSpan at = TimeSpan.FromSeconds((long)message.chat.date) + TimeSpan.FromMicroseconds((long)message.chat.date_usec); diff --git a/Readme.txt b/Readme.txt index 02c71d4..b91b326 100644 --- a/Readme.txt +++ b/Readme.txt @@ -8,8 +8,6 @@ > dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:PublishTrimmed=true などとしてください。 動作環境はWindowsではWindows10以降と思います。 -2024年7月時点の.NET 8では /p:PublishTrimmed=true をつけるとビルドはできるが正常 -動作しないバイナリができるので、その場合はこのオプションを取り除いてください。 jkcnslを起動して、 > Lch???<改行> (←???は実況の番号) diff --git a/SerializerClassDefinitions.cs b/SerializerClassDefinitions.cs index c853589..758f39f 100644 --- a/SerializerClassDefinitions.cs +++ b/SerializerClassDefinitions.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using System.IO; using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; namespace jkcnsl { @@ -205,4 +207,33 @@ public class ContentContainer { public string content { get; set; } } + + /// + /// DataContractJsonSerializerのジェネリックなラッパー + /// トリミング(PublishTrimmed)する場合は型Tがトリム対象にならないよう注意 + /// + class DataContractJsonSerializerWrapper + { + readonly DataContractJsonSerializer _js = new DataContractJsonSerializer(typeof(T)); + + public T ReadValue(Stream s) + { + return (T)_js.ReadObject(s); + } + + public T ReadValue(byte[] buf) + { + return ReadValue(new MemoryStream(buf)); + } + + public T ReadValue(byte[] buf, int index, int count) + { + return ReadValue(new MemoryStream(buf, index, count)); + } + + public void WriteValue(Stream s, T val) + { + _js.WriteObject(s, val); + } + } } diff --git a/Settings.cs b/Settings.cs index 0b7ad26..ee152c7 100644 --- a/Settings.cs +++ b/Settings.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.IO; using System.Runtime.Serialization; -using System.Runtime.Serialization.Json; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -44,7 +43,7 @@ public void Load() { using (var fs = new FileStream(Path.Join(AppContext.BaseDirectory, "jkcnsl.json"), FileMode.Open, FileAccess.Read)) { - settings = (Settings)new DataContractJsonSerializer(typeof(Settings)).ReadObject(fs); + settings = new DataContractJsonSerializerWrapper().ReadValue(fs); } break; } @@ -94,7 +93,7 @@ public void Save() { using (var fs = new FileStream(Path.Join(AppContext.BaseDirectory, "jkcnsl.json"), FileMode.Create, FileAccess.Write, FileShare.None)) { - new DataContractJsonSerializer(typeof(Settings)).WriteObject(fs, settings); + new DataContractJsonSerializerWrapper().WriteValue(fs, settings); } break; } diff --git a/jkcnsl.csproj b/jkcnsl.csproj index c574260..c33017e 100644 --- a/jkcnsl.csproj +++ b/jkcnsl.csproj @@ -9,6 +9,7 @@ none false + partial