Skip to content

Commit

Permalink
ランタイム部分をトリム可能にする (2ch_NicoJK/9/949 より)
Browse files Browse the repository at this point in the history
再検証が必要になるのと実装例の少なさからSystem.Text.Json移行は保留
  • Loading branch information
xtne6f committed Aug 26, 2024
1 parent 4052775 commit d69f79e
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 36 deletions.
61 changes: 30 additions & 31 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -425,8 +424,8 @@ static async Task<string> 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>();
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/"))
Expand Down Expand Up @@ -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<WatchSessionPost>();
var jsWatchSessionResult = new DataContractJsonSerializerWrapper<WatchSessionResult>();
var jsWatchSessionResultForError = new DataContractJsonSerializerWrapper<WatchSessionResultForError>();
var jsWatchSessionResultForMessageServer = new DataContractJsonSerializerWrapper<WatchSessionResultForMessageServer>();
var jsWatchSessionResultForSeat = new DataContractJsonSerializerWrapper<WatchSessionResultForSeat>();
var jsWatchSessionResultForServerTime = new DataContractJsonSerializerWrapper<WatchSessionResultForServerTime>();

string nextAt = "now";
bool closed = false;
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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":
Expand All @@ -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));
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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<WatchSessionPost>();
var jsWatchSessionResult = new DataContractJsonSerializerWrapper<WatchSessionResult>();
var jsWatchSessionResultForError = new DataContractJsonSerializerWrapper<WatchSessionResultForError>();
var jsWatchSessionResultForRoom = new DataContractJsonSerializerWrapper<WatchSessionResultForRoom>();
var jsWatchSessionResultForSeat = new DataContractJsonSerializerWrapper<WatchSessionResultForSeat>();
var jsWatchSessionResultForServerTime = new DataContractJsonSerializerWrapper<WatchSessionResultForServerTime>();
var jsCommentSessionResult = new DataContractJsonSerializerWrapper<CommentSessionResult>();

bool closed = false;
while (!closed)
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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":
Expand All @@ -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));
Expand Down Expand Up @@ -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に変換
Expand All @@ -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<CommentSessionOpen>));
var js = new DataContractJsonSerializerWrapper<List<CommentSessionOpen>>();
var ms = new MemoryStream();
js.WriteObject(ms, new List<CommentSessionOpen>()
js.WriteValue(ms, new List<CommentSessionOpen>()
{
new CommentSessionOpen() { ping = new ContentContainer() { content = "rs: 0" } },
new CommentSessionOpen() { ping = new ContentContainer() { content = "ps: 0" } },
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions Readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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???<改行> (←???は実況の番号)
Expand Down
31 changes: 31 additions & 0 deletions SerializerClassDefinitions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

namespace jkcnsl
{
Expand Down Expand Up @@ -205,4 +207,33 @@ public class ContentContainer
{
public string content { get; set; }
}

/// <summary>
/// DataContractJsonSerializerのジェネリックなラッパー
/// トリミング(PublishTrimmed)する場合は型Tがトリム対象にならないよう注意
/// </summary>
class DataContractJsonSerializerWrapper<T>
{
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);
}
}
}
5 changes: 2 additions & 3 deletions Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Settings>().ReadValue(fs);
}
break;
}
Expand Down Expand Up @@ -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<Settings>().WriteValue(fs, settings);
}
break;
}
Expand Down
1 change: 1 addition & 0 deletions jkcnsl.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
<TrimMode>partial</TrimMode>
</PropertyGroup>

<ItemGroup>
Expand Down

0 comments on commit d69f79e

Please sign in to comment.