C#으로 Slack Bot 만들기

Slack은 '디지털 전선’이라 불리기도 하며 전세계적으로 아주 많은 기업이 사용하는 서비스 입니다.

2년 전에 글로벌 회사인 세일즈 포스에서 Slack을 역대급 인수 합병하여 이슈가 되기도 했었습니다.

물론 1론 머스크가 트위터를 인수해서 바로 역대급이 아니게 되었습니다.

아무튼 이 Slack은 많은 사람들이, 많은 장소에서, 많은 업무에서 사용합니다.
그래서 단순 업무 채팅이 아닌 여러 기능이 붙어있으면 도움이 많이 될 것이고, 그 중 하나가 Bot 서비스 입니다.

이 문서에서는 .NET 7 C#으로 Slack Bot을 만드는 방법을 설명합니다.

Slack Bot을 사실 C#말고 JavaScript, Java, Python 으로 만든다면 Bolt라는 매우 편리한 라이브러리가 있어서 Slack만 잘 이용하고 있는 개발자라면 1시간 이내에도 Bot을 만들 수 있습니다.

하지만 .NET은 이런 라이브러리가 없기 때문에 직접 구현해야 합니다.

  1. Slack API 에 접속합니다.

  2. Bot 역할을 할 Slack App을 만듭니다. Slack App은 Plugin 형태로 제공됩니다.

  1. From scratch 를 클릭합니다.

  1. 어떤 WorkSpace에서 사용할지, Bot APP의 이름은 뭘로 할 것인지 작성합니다.

  1. Event Subscriptions 로 이동하여 Enable Events 를 활성화 하고, Subscribe to events on behalf of users 에 message.channels 권한을 추가합니다.

  1. 추후 Bot Server에서 받은 요청을 채팅창으로 전송할 수 있게 Webhook도 허용합니다.

  1. App Home에서 메세지 보내기 허용을 체크합니다.

  1. Install App을 통해 WorkSpace에 배포하고 설치합니다.

  1. 여기까지하면 Slack 설정은 끝났습니다. 이제 C#으로 코딩할 차례입니다.
    C#으로 Bot을 만드는 행위는 물론 Github에 예제들이 있긴하지만 prototyping 수준으로 우리가 이해하기에는 너무 구조화가 되어있어서 비지니스를 이해하기 어렵습니다.
    아래 문서를 참고해서 개발해봅시다.
    참고로 Event API가 최신 API고 RTM(Real Time Message)은 레거시 입니다.
    Intro to Socket Mode | Slack
    Socket Mode implementation | Slack
    Using the Slack Events API | Slack
    Events API types | Slack
using System.Net.WebSockets;
using System.Buffers;
using System.Text;
using System.Net.Http.Headers;
using Newtonsoft.Json;

const string slackUrlList = "https://slack.com/api/apps.connections.open";
const string slack_app_level_token = "앱토큰~";

HttpClient httpClient = new();

// WebSocket Bot 주소 가져오기
HttpRequestMessage reqSlackbotUrl = new()
{
    Method = HttpMethod.Post,
    RequestUri = new Uri(slackUrlList),
};
reqSlackbotUrl.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
reqSlackbotUrl.Headers.Add("Authorization", $"Bearer {slack_app_level_token}");
HttpResponseMessage resSlackbotUrl = await httpClient.SendAsync(reqSlackbotUrl);

if (!resSlackbotUrl.IsSuccessStatusCode)
{
    string failReason = await resSlackbotUrl.Content.ReadAsStringAsync();
    System.Console.WriteLine(failReason);

    return;
}

string successGetSlackbotUrl = await resSlackbotUrl.Content.ReadAsStringAsync();
dynamic rawStr = JsonConvert.DeserializeObject(successGetSlackbotUrl);
string slackUrl = rawStr.url.ToString();

slackUrl += "&debug_reconnects=true";

using ClientWebSocket ws = new();
Uri uri = new(slackUrl);

try
{
    using StreamWriter sw = new("temp.txt");

    await ws.ConnectAsync(uri, CancellationToken.None);

    while (ws.State == WebSocketState.Open)
    {
        byte[] receiveBuf = ArrayPool<byte>.Shared.Rent(10240);
        ArraySegment<byte> bytesToReceived = new(receiveBuf);
        WebSocketReceiveResult result = await ws.ReceiveAsync(bytesToReceived, CancellationToken.None);
        string jsonStr = Encoding.UTF8.GetString(bytesToReceived.Array, 0, result.Count);
        dynamic jsonObj = JsonConvert.DeserializeObject(jsonStr);
        string jsonStrSerialized = JsonConvert.SerializeObject(jsonObj, Formatting.Indented);

        Console.WriteLine(jsonStrSerialized);
        await sw.WriteAsync(jsonStrSerialized);
    }
}
catch (WebSocketException ex)
{

}
catch (System.Exception ex)
{
    
    throw;
}

Console.ReadLine();

위가 소스코드의 전부입니다. 60줄 밖에 안됩니다.
Top Level Programming으로 Program.cs 한 파일에 작성된 코드입니다.

Flow는 간단합니다.
https://slack.com/api/apps.connections.open 에 App_Token을 넣고 HTTP Post Request하면, 자신이 속한 WorkSpace에서 호출할 수 있는 App의 목록들이 출력됩니다.
AppToken은 아래 사진에서 확인할 수 있습니다.

빨간색으로 마킹된 것이 링크인데 누르면 AppToken이 출력됩니다.

지금 같은 경우 WebSocket App 하나만 만들었기 때문에 호출하면 wss 프로토콜의 URI 1개가 리턴됩니다.

그 다음, 리턴된 주소에 WebSocket으로 연결하고 메세지를 주고 받으면 됩니다.


위의 설명이 전부입니다.

메세지를 보내는 것은 Slack Webhook으로 하시면 되는데 검색하시면 많은 레퍼런스가 나옵니다.

위 Bot을 개발할 때 유념해야할 것은, Bot이 Slack 내의 Private Channel까지 구독이 됩니다.
또한 아까 권한 설정할 때 message.channel 을 추가했는데, 여기에 message.im 을 추가하면 DM 까지 모두 모니터링이 가능해져서, Slack bot 개발자가 빅브라더가 될 수 있으므로, 메세지에 대한 권한 설정과 필터링을 잘 해서 bot 이용에 사용자들이 불편함이 없도록 해야합니다.

물론 위에 언급된 bolt 라이브러리들을 사용하면 알아서 필터링이 되기는 합니다.
어쩌면 제가 권한을 덜 설정해서 그런 것일 수도 있는데, C#으로 된 Slack Bot 예제가 너무 없어서 튜토리얼 차원에서 공유합니다.
나머지는 여러분들께서 같이 공유해주시고 발전시켜주시면 감사드리겠습니다.

읽어주셔서 감사합니다!

10개의 좋아요

아… @Vincent 님께서 방법을 찾아주시기 전까진 방법을 찾는데 오래 걸릴지도 모른다고 판단하고, Bolt 라이브러리를 써야 해서 이미 TypeScript로 개발해버렸네요. :sob:

개발 인력이라는 비용이 들다보니, Bolt 같은 백업 라이브러리가 없으면 C#으로 개발하자고 정하기가 어렵네요.

3개의 좋아요