public TelnetStreamWatcherBase(TelnetStreamWatcherOptions options)
    {
        this.Options = options;

        Listener = TcpIp.CreateTcpListener(new TcpListenParam(async(listener, sock) =>
        {
            try
            {
                Con.WriteDebug($"TelnetStreamWatcher({this.ToString()}: Connected: {sock.EndPointInfo._GetObjectDump()}");

                await using (var destStream = sock.GetStream())
                {
                    if (sock.Info.Ip.RemoteIPAddress == null || Options.IPAccessFilter(sock.Info.Ip.RemoteIPAddress) == false)
                    {
                        Con.WriteDebug($"TelnetStreamWatcher({this.ToString()}: Access denied: {sock.EndPointInfo._GetObjectDump()}");

                        await destStream.WriteAsync("You are not allowed to access to this service.\r\n\r\n"._GetBytes_Ascii());

                        await Task.Delay(100);

                        return;
                    }

                    using (var pipePoint = await SubscribeImplAsync())
                    {
                        // ソケットから Enter キー入力を待機する
                        Task keyInputTask = TaskUtil.StartAsyncTaskAsync(async() =>
                        {
                            using StreamReader lineReader = new StreamReader(destStream);

                            while (true)
                            {
                                string?line = await lineReader.ReadLineAsync();

                                if (line == null)
                                {
                                    break;
                                }

                                line = line.Trim();

                                if (line._IsSamei("s"))
                                {
                                    // Socket リストの表示
                                    var list = LocalNet.GetSockList().OrderBy(x => x.Connected);

                                    StringWriter w = new StringWriter();

                                    w.WriteLine();

                                    foreach (var sock in list)
                                    {
                                        string tmp = sock._GetObjectDump();
                                        w.WriteLine(tmp);
                                    }

                                    w.WriteLine();

                                    w.WriteLine($"Total sockets: {list.Count()}");

                                    w.WriteLine();

                                    byte[] data = w.ToString()._GetBytes_Ascii();

                                    var pipe = pipePoint;
                                    if (pipe.CounterPart != null)
                                    {
                                        lock (pipe.CounterPart.StreamWriter.LockObj)
                                        {
                                            if (pipe.CounterPart.StreamWriter.NonStopWriteWithLock(data, false, FastStreamNonStopWriteMode.DiscardExistingData) != 0)
                                            {
                                                // To avoid deadlock, CompleteWrite() must be called from other thread.
                                                // (CompleteWrite() ==> Disconnect ==> Socket Log will recorded ==> ReceiveLog() ==> this function will be called!)
                                                TaskUtil.StartSyncTaskAsync(() => pipe.CounterPart.StreamWriter.CompleteWrite(false), false, false)._LaissezFaire(true);
                                            }
                                        }
                                    }
                                }
                                else if (line._IsSamei("0"))
                                {
                                    // GC
                                    Dbg.WriteLine($"Manual GC0 is called by the administrator.");

                                    long start = Time.HighResTick64;
                                    GC.Collect(0, GCCollectionMode.Forced, true, true);
                                    long end = Time.HighResTick64;

                                    long spentTime = end - start;

                                    Dbg.WriteLine($"Manual GC0 Took Time: {spentTime} msecs.");
                                }
                                else if (line._IsSamei("1"))
                                {
                                    // GC
                                    Dbg.WriteLine($"Manual GC1 is called by the administrator.");

                                    long start = Time.HighResTick64;
                                    GC.Collect(1, GCCollectionMode.Forced, true, true);
                                    long end = Time.HighResTick64;

                                    long spentTime = end - start;

                                    Dbg.WriteLine($"Manual GC1 Took Time: {spentTime} msecs.");
                                }
                                else
                                {
                                    // GC
                                    Dbg.WriteLine($"Manual GC is called by the administrator.");

                                    long start = Time.HighResTick64;
                                    Dbg.GcCollect();
                                    long end = Time.HighResTick64;

                                    long spentTime = end - start;

                                    Dbg.WriteLine($"Manual GC Took Time: {spentTime} msecs.");
                                }
                            }
                        });

                        try
                        {
                            // ソケットに対して、pipePoint のストリームをそのまま非同期で流し込む
                            await using (var pipeStub = pipePoint.GetNetAppProtocolStub())
                                await using (var srcStream = pipeStub.GetStream())
                                {
                                    await srcStream.CopyToAsync(destStream, sock.GrandCancel);
                                }
                        }
                        finally
                        {
                            await UnsubscribeImplAsync(pipePoint);

                            await pipePoint.CleanupAsync(new DisconnectedException());

                            await keyInputTask._TryAwait(noDebugMessage: true);
                        }
                    }
                }
            }
            finally
            {
                Con.WriteDebug($"TelnetStreamWatcher({this.ToString()}: Disconnected: {sock.EndPointInfo._GetObjectDump()}");
            }
        },
                                                              "TelnetStreamWatcher",
                                                              this.Options.EndPoints.ToArray()));

        this.AddIndirectDisposeLink(this.Listener);
    }
 public TelnetLocalLogWatcher(TelnetStreamWatcherOptions options) : base(options)
 {
 }