슬랙봇 개발기 ① - 소켓 모드란 무엇일까?
슬랙봇을 개발할 경우에는 HTTP통신을 기반으로 하거나 웹소켓 통신을 기반으로 하는 두가지 방법이 있다. 먼저 HTTP 통신을 기반으로 하는 방법은 public으로 열어놓은 REST API를 기반으로 하는 방
bboglebbogle.tistory.com
이전 글에서 소켓모드를 사용해서 웹소켓 기반의 슬랙봇을 구축해야 하는 이유에 대해서 살펴보았다.
Socket Mode Client — Python Slack SDK
Socket Mode is a method of connecting your app to Slack’s APIs using WebSockets instead of HTTP. You can use slack_sdk.socket_mode.SocketModeClient for managing Socket Mode connections and performing interactions with Slack. SocketModeClient First off, l
slack.dev
슬랙에서는 웹소켓 구축을 조금 더 쉽게할 수 있도록 만들어진 라이브러리를 제공한다.
바로 Python Slack SDK의 SocketModeClient 기능인 데, 나는 이것을 사용해서 구축하기로 결정했다.
Slack bolt를 사용할 수도 있지만, 조금 더 로우 레벨이면서 커스텀하기에 편하다고 생각하여 결정했다.
웹소켓 통신을 사용하면서 flask 서버도 사용하는 이유는 간단한 데,
- 쿠버네티스 헬스 체크를 위하여 api/ping url을 열어줘야 하기도 하고,
- 나중에 Oauth를 할 때 redirect uri가 필요하기도 하므로
결론적으로는 웹소켓 통신 + http 통신을 둘 다 사용할 것 같다.
pip3 명령어를 사용하여 slack-sdk와 flask를 설치한다.
from flask import Flask
from slack_sdk.socket_mode import SocketModeClient
from slack_sdk import WebClient
app = Flask(__name__)
@app.route('/api/ping')
def ping():
return "pong"
clinet = WebClient(
token=SLACK_BOT_TOKEN,
proxy=PROXY_URL
)
socket = SocketModeClient(
app_token=APP_TOKEN,
web_client=client,
on_close_listeners=[error_listner],
on_message_listeners=[message_listener],
)
socket.connect()
socket.connect()를 사용하면 flask app context를 block하지 않기 때문에,
flask와 web socket 통신을 둘 다 사용할 수 있다.
만약 ssl 관련 오류가 발생한다면,
import ssl
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
client = WebClient(token='yourtoken',
ssl=ssl_context)
와 같은 ssl verify하지 않는 ssl_context를 넣을 수 있다.
def error_listener(app, ex: Exception):
logging.error(e)
if isinstance(ex, WebSocketConnectionClosedException):
socket.close()
socket.conenct_to_new_endpoint(True)
Error listener는 에러가 발생할 때마다 호출되는 함수라고 볼 수 있다.
나는 여러번의 시도 끝에, 어플리케이션을 장시간 켜놓을 경우, 웹 소켓이 간헐적으로 끊어지는 에러가 발생하는 것을 알게 되었고,
이를 해결 하기 위해 웹소켓 연결이 끊어지는 WebSocketConnectionClosedException이 발생할 경우,
새로운 endpoint로 강제로 연결을 갱신해주는 함수를 호출하는 것으로 이 문제를 해결했다.
이처럼 에러가 발생할 경우 할 코드들을 이 곳에 적어주면 된다.
def message_listener(req: str):
req = json.loads(req)
if req.get("type") == "slash_commands" and req.get("payload").get("command") == "/test":
//do something
그리고 message_listener는 웹소켓을 통한 메시지가 올때마다 호출되는 함수이다.
연결이 될 때, disconnect될 때, 커맨드를 호출할 때, 슬랙봇을 멘션할 때 등등,
모든 이벤트가 발생할 때마다 message_listener를 통해 메시지가 전달된다.
따라서 먼저 json.loads를 통해서 메시지를 dictionary 형태로 변형한 후에,
해당 메시지의 타입에 따라서 할 동작들을 수행하도록 구조를 잡았다.
'프로젝트 > 개인 플젝' 카테고리의 다른 글
슬랙봇 개발기 ③ - 슬랙봇에게 말을 걸면 답장 보내기 (socket mode) (0) | 2022.12.15 |
---|---|
슬랙봇 개발기 ① - 소켓 모드란 무엇일까? (0) | 2022.12.11 |
스프링부트 & JUnit5 - 단위 테스트 작성 기본 (0) | 2021.08.11 |
[프로젝트] 1일 1커밋 실천할 수 있는 웹사이트 - 연속 커밋 횟수 보여주는 곳 (0) | 2021.07.18 |