고양국제고

GGHS Time Table 5 개발 스토리 #2: 새로운 기능! 고양국제고 익명채팅

카루-R 2022. 2. 22. 09:56
반응형

환영합니다, Rolling Ress의 카루입니다.


아마 마지막 GTT가 될, GGHS Time Table 5. 출시를 임박해서 대규모 업데이트를 앞두고 있습니다. 아마 3학년들은 온라인 수업이 크게 줄어들기 때문에 ZOOM 링크 기능을 다 빼버리려고 계획중입니다. 그런데, 사라지는 게 있으면 생기는 게 있어야겠죠. 무슨 기능을 넣을까 하다가, 익명 단체채팅방을 고민하고 있습니다.

2-4반의 '무야호'라든가 2-8반의 '문학소년'처럼 모두가 섞여 서로를 모르는 상태에서 채팅을 한다. 뭐, 싫은 과목에 대해 불평할 수도 있고, 친구들끼리 도움을 얻을 수도 있고. 물론 욕설이나 기타 문제가 발생할 수도 있겠지만, 제가 항상 상주하면서 제지할 예정입니다. 뭐 100% 익명이니만큼 차단을 한다든가 할 수는 없어요. 그래도, 문제가 되는 발언을 찾아 서버에서 바로 삭제시키는 것 까진 가능합니다.

자, 대충 디자인을 끝냈어요. 정식 버전에선 조금 더 다듬을 수도 있고...중요한 건 일단 기능이죠. 기능부터 구현해봅시다.

SQL 서버를 호스팅받았습니다. 여기서 메시지를 차곡차곡 쌓을 거예요. 보낸 사람, 시각, 메시지가 들어갑니다. 잠깐, 보낸 사람이 왜 있냐고요? 아, 이건 저를 표시하기 위함입니다.

Karu (개발자: 카루)
Azure (레벨 A)
Bisque (레벨 B)

GGHS Time Table의 인증 레벨은 네 가지가 있어요. 개발자, Azure, Bisque, Coral. 전부 색상 이름이죠. Coral은 GGHS 10th에서 이름만 바꾼 겁니다. 기존 Insiders, 즉 개발을 도와줬던 사람들이 Azure과 Bisque로 각각 나뉘어 들어갔다고 생각하시면 됩니다. 둘 차이는 거의 없어요.

if (!Info.User.IsAuthorized)
{
    _ = await TimeTablePage.ActivateAsync("여기는 GTT 유저 대화방으로, Azure/Bisque 레벨만 이용할 수 있습니다.");
    if (!Info.User.IsAuthorized)
    {
        _ = ShowMessageAsync("You need to be Auzre/Bisque level to use this chatroom.", "Limited feature", Info.Settings.Theme);
        return;
    }
}

당연하지만, 인증이 안 된 상태로 (혹은 Coral 등급의 상태로) GGHS Anonymous에 접근하려고 하면 막힙니다. 전교생들에게 풀지...이건 생각을 좀 해보고요. 서버를 제가 부담하는 거라 조금... 어려울 수도 있어요. 양해해주시길 ^^,,,

private async Task ReloadChatsAsync()
{
    string connection = ConfigurationManager.ConnectionStrings["ChatDB"].ConnectionString;
    string connString = connection;
    string query = "SELECT * FROM chatmsg";

    while (true)
    {
        while (isSending)
            await Task.Delay(100);
        
        SqlConnection conn = new(connString);
        SqlCommand cmd = new(query, conn);
        conn.Open();

        SqlDataAdapter da = new(cmd);
        DataTable dataTable = new();
        da.Fill(dataTable);
        conn.Close();
        da.Dispose();

        StringBuilder sb = new();
        foreach (DataRow row in dataTable.Rows)
        {
            DateTime dt = DateTime.Parse(row["Time"].ToString());
            string sender = Convert(row["Sender"].ToString());
            string msg = row["Message"].ToString();
            sb.AppendLine($"({dt:MM/dd HH:mm}) {sender}: {msg}");
        }
        viewBox.Text = sb.ToString();
        // Chat Reload Delay
        await Task.Delay(800);
    }
}

그리고 이건 Async 메서드로 만들어서 그냥 흘렸습니다. await시키지 않고, 그냥 백그라운드 스레드로 방치해둔 거예요. 1초 (위 코드상에서는 0.8초)마다 서버에 있는 모든 데이터를 긁어와 화면에 표시해줍니다. 이건 나중에 동작 방식을 개선할 거예요. 없는 부분만 받아온다든지, 없는 부분만 새로 파싱해서 Append하든지. 매번 통으로 이러면 성능 저하가 일어나거든요.

private async Task SendMessageAsync(ActivationLevel userLevel)
{
    // Send Message
    isSending = true;
    textBox.IsEnabled = false;

    using SqlConnection sql = new();
    sql.ConnectionString = ConfigurationManager.ConnectionStrings["ChatDB"].ConnectionString;
    await sql.OpenAsync();

    SqlCommand cmd = new();
    cmd.Connection = sql;

    SqlParameter pSender = new("Sender", SqlDbType.TinyInt);
    pSender.Value = Convert(userLevel);

    SqlParameter pTime = new("Time", SqlDbType.DateTime);
    pTime.Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");

    SqlParameter pMsg = new("Message", SqlDbType.NVarChar, 80);
    pMsg.Value = textBox.Text;

    cmd.Parameters.Add(pSender);
    cmd.Parameters.Add(pTime);
    cmd.Parameters.Add(pMsg);

    cmd.CommandText = "INSERT INTO chatmsg(Sender, Time, Message) VALUES(@Sender, @Time, @Message)";
    await cmd.ExecuteNonQueryAsync();

    isSending = false;
    textBox.Text = String.Empty;
    textBox.IsEnabled = true;
}

엔터를 치면 그냥 메시지가 서버로 전송됩니다. SQL 쿼리를 이용해서 진행하는데, 뭐... 딱히 특별해보이는 건 없네요. 한 가지 재밌는 건, 이 채팅방에는 저만을 위한 스텔스 기능이 있다는 점입니다. 그 얘기는 GTT가 완전히 끝날 때 하죠.

대략 이런 느낌으로 봐주시면 될 겁니다. 아직 사용자가 없어서, 이건 그냥 제가 임의로 넣은 문장들입니다. 이제 서버를 초기화하고, 업데이트를 올려야겠네요. 참고로 지금 저장 기능이 먹통이 돼서, 인증이 풀립니다. 인증 문제부터 잡고 업데이트 마저 진행하도록 해야겠어요.

반응형