// ------------------------------------------------------------------------------------ // エラーがあった場合、例外で返される。このとき dst_wrt_WS_buf には、エラーの発生コードと、ID.End が書き込まれる。 // file_path は、"md_root/..." の形のもの public static void LexFile(Write_WS_Buffer dst_wrt_WS_buf, string file_path) { ReadFile_to_MD_buf(file_path); // この時点で、MD_buf の最後は \n\0 で終わっている。 // --------------------------------------------------------- // 字句解析用のフラグを初期化 msb_next_is_Div = true; // ファイル先頭は、必ず Div ブロックとなる msb_Dtct_CodeBlk_Mark = false; msb_is_in_CodeBlk = false; msb_is_in_QuoteBlk = false; // まず、Lexed_MD をエラー状態で書き込んでおく(エラーがあったときは、例外で外に飛んでいくため) ms_write_WS_buf = dst_wrt_WS_buf; ms_write_WS_buf.Wrt_ID_param(ID.Lexed_MD, Param.EN_Failed); ms_write_WS_buf.Clear_Txt_flags(); // --------------------------------------------------------- // 1行ごとに字句解析を実行する fixed(byte *pstr_MD_top = ms_MD_buf) { ushort *psrc = (ushort *)(pstr_MD_top + 2); // +2 は、utf-16le の BOM while (true) { // Consume_Line() は、次の行頭を返してくる psrc = Consume_Line(psrc); // 行頭が \0 であるとき、ファイル読み取りが終了したと判断する // エラーの場合は、例外処理で返される if (*psrc == 0) { break; } } } MainForm.StdOut($"変換後のサイズ : {ms_write_WS_buf.Get_idx_byte_cur().ToString("N0")}\r\n"); // Write_WS_Buffer で THROW_ERR() がコールされた場合、ID_End が既に書き込まれている // ここに来た場合、Lexing に成功している ms_write_WS_buf.Wrt_ID_param_At(0, ID.Lexed_MD, Param.EN_Succeeded); ms_write_WS_buf.Wrt_ID_End(); }
// ------------------------------------------------------------------------------------ // m_files_in_dir のみが Update される(m_dirs_in_dir はチェックされないため注意) public void Update_and_DirFileList(Write_WS_Buffer send_WS_buf, bool bNeed_DirNames) { m_SEC_Updated = (int)((DateTime.Now.Ticks - ms_base_tick) / 10_000_000); send_WS_buf.Wrt_Num_int(m_SEC_Updated); // --------------------------------------------------------- // ディレクトリ名の設定 if (bNeed_DirNames == true) { send_WS_buf.Wrt_ID_param(ID.Directory_Names, (byte)m_dirs_in_dir.Count); foreach (string dname in m_dirs_in_dir) { send_WS_buf.Wrt_PStr(dname); } } // --------------------------------------------------------- // ファイル名の設定 { // ID.File_Names は、ディレクトリの個数が分かってから書き込む int idx_byte_AtFName = send_WS_buf.Get_idx_byte_cur(); send_WS_buf.Skip_Wrt_ID(); var files = Directory.EnumerateFiles(mc_str_path_dir); int cnt = 0; m_exist_check_cnt++; // 存在確認用のカウンタを1つ進める foreach (string fpath in files) { // md ファイル以外であれば処理しない if (IsMdFile(fpath) == false) { continue; } string fname = Get_FName(fpath, true); if (m_files_in_dir.ContainsKey(fname) == true) { m_files_in_dir[fname] = m_exist_check_cnt; } else { m_files_in_dir.Add(fname, m_exist_check_cnt); #if DBG_LOG_FileLister MainForm.DBG_StdOut($"【DBG_LOG_FileLister】Update() でファイル追加 -> {fname}\r\n"); #endif } send_WS_buf.Wrt_PStr(fname); cnt++; } if (cnt > 255) { throw new Exception("ファイルの個数が 255 個を超えています。"); } // cnt == 0 であっても、ファイルの削除処理が必要である場合もあるため注意 send_WS_buf.Wrt_ID_param_At(idx_byte_AtFName, ID.File_Names, (byte)cnt); // 存在しなくなったファイル名を削除する if (m_files_in_dir.Count == 0) { return; } // m_files_in_dir が空であるときは、何もしなくて良い var it = m_files_in_dir.GetEnumerator(); int idx_of_files = 0; int rem_remove_idx_ary = ms_remove_idx_ary_pcs; int idx_next_on_rmv_idx_ary = 0; // イテレータを利用している間はコンテナの削除等ができないため、削除対象の idx のみを記録していく while (it.MoveNext()) { if (it.Current.Value != m_exist_check_cnt) { if (rem_remove_idx_ary == 0) { ms_remove_idx_ary_pcs += 10; Array.Resize(ref msa_remove_idx_ary, ms_remove_idx_ary_pcs); rem_remove_idx_ary = 10; } msa_remove_idx_ary[idx_next_on_rmv_idx_ary++] = idx_of_files; rem_remove_idx_ary--; // リムーブ対象に登録した時点で、リムーブされることを通知する // もし、Lexed されたデータが残っていたら削除すること ms_INtfy_DeleteFile.Ntfy_DeleteFile(mc_str_path_dir + it.Current.Key); } idx_of_files++; } // リムーブを実行する // RemoveAt は後ろ側から実行する必要がある(前の方を削除すると、インデックス値が変わるため) for (int idx_on_rmv_idx_ary = idx_next_on_rmv_idx_ary; idx_on_rmv_idx_ary > 0;) { int idx_of_files_to_rmv = msa_remove_idx_ary[--idx_on_rmv_idx_ary]; m_files_in_dir.RemoveAt(idx_of_files_to_rmv); } } }
// ------------------------------------------------------------------------------------ public async Task Spawn_Context(HttpListenerContext context, uint idx_context) { // AcceptWebSocketAsync() は、キャンセルトークンをサポートしていない // 引数: サポートされている WebSocket サブプロトコル HttpListenerWebSocketContext wsc = await context.AcceptWebSocketAsync(null); MainForm.StdOut("--- WebSocket 接続完了\r\n"); using (m_WS = wsc.WebSocket) using (WS_Buf_Pool.MemBlock mem_blk = WS_Buf_Pool.Lease_MemBlock()) { m_read_WS_buf = new Read_WS_Buf(mem_blk.m_ary_buf); m_write_WS_buf = new Write_WS_Buffer(mem_blk.m_ary_buf); try { // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #if CREATE_TEST_LEXED_CODE // Test Lexed Code を送信する Write_WS_Buffer write_ws_buf = MainForm.ms_DBG_write_WS_buf; await m_WS.SendAsync( new ArraySegment <byte>(write_ws_buf.Get_buf(), 0, write_ws_buf.Get_idx_byte_cur()) , WebSocketMessageType.Binary, true, ms_cts_shutdown.Token); #else // まずはルートフォルダのファイル情報を送信しておく FileLister.Set_DirFileNames(m_write_WS_buf, "./"); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); #endif while (true) { WebSocketReceiveResult rslt = await m_WS.ReceiveAsync( new ArraySegment <byte>(mem_blk.m_ary_buf), ms_cts_shutdown.Token); if (rslt.EndOfMessage == false) { MainForm.StdOut("--- 不正な大きさのデータを受信しました。クライアントを切断します\r\n"); break; } if (m_WS.State == WebSocketState.CloseReceived) { MainForm.StdOut("--- クライアントが接続を Close しました\r\n"); break; } m_read_WS_buf.Renew(rslt.Count); switch (m_read_WS_buf.Read_ID()) { case ID.DirFileList: { ID id = m_read_WS_buf.Read_ID(); if (id != ID.Text) { throw new Exception($"不正なパラメータを受信 DirFileList / id -> {((byte)id).ToString()}"); } FileLister.Set_DirFileNames(m_write_WS_buf, m_read_WS_buf.Get_text_cur()); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; case ID.Files_inDir: { ID id = m_read_WS_buf.Read_ID(); if (id != ID.Text) { throw new Exception($"不正なパラメータを受信 Files_inDir / id -> {((byte)id).ToString()}"); } string str_path_dir = m_read_WS_buf.Get_text_cur(); id = m_read_WS_buf.Read_ID(); if (id != ID.Num_int) { throw new Exception($"不正なパラメータを受信 Files_inDir / id -> {((byte)id).ToString()}"); } int SEC_Updated_recv = m_read_WS_buf.Get_Num_int(); FileLister.OnFiles_inDir(m_write_WS_buf, str_path_dir, SEC_Updated_recv); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; case ID.MD_file: { var(path_md_file, SEC_Updated, idx_byte_SEC_updated) = m_read_WS_buf.Read_Req_MD(); MainForm.StdOut($"path_md_file : {path_md_file} / SEC_Updated : {SEC_Updated.ToString()}\r\n"); // ID.MD_file -> ID_Text (path_dir) -> ID_Text (file name) は Receive時の値を流用 m_write_WS_buf.Set_idx_byte(idx_byte_SEC_updated); m_write_WS_buf.Wrt_Num_int(1000); // 1000 は試験値 Lexer.LexFile(m_write_WS_buf, path_md_file); MainForm.StdOut("--- Lexing 処理完了\r\n"); m_write_WS_buf.Simplify_Buf(); MainForm.StdOut("--- Simplify_Buf 処理完了\r\n"); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; } MainForm.StdOut($"--- ReceiveAsync() : 受信バイト数 -> {rslt.Count}\r\n"); MainForm.HexDump(mem_blk.m_ary_buf, 0, 20); DBG_WS_Buffer.Show_WS_buf(MainForm.ms_RBox_stdout, mem_blk.m_ary_buf, rslt.Count); // 今は、index.md のみを解析するようにしている // string ret_str = Lexer.LexFile(m_write_WS_buf, "md_root/index.md"); // string str_recv = ms_utf16_encoding.GetString(mem_blk.m_ary_buf, 0, rslt.Count); // MainForm.StdOut(str_recv); } await m_WS.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "接続を終了します", ms_cts_shutdown.Token); } catch (OperationCanceledException) { MainForm.StdOut("--- サーバーシャットダウンのシグナルを受信しました\r\n"); } catch (WebSocketException ex) { MainForm.StdOut($"!!! 例外発を補足しました WebSoketErrorCode : {ex.WebSocketErrorCode.ToString()}\r\n"); MainForm.StdOut($" {ex.ToString()}\r\n"); } catch (Exception ex) { MainForm.StdOut($"!!! 例外を補足しました : {ex.ToString()}\r\n"); } } MdSvr.Remove_task_context(idx_context); MainForm.StdOut("--- WebSocket 切断完了\r\n"); }