Python SDK for Dooray.com with Socket Mode support
Project description
Dooray SDK - Python
Python Dooray SDK의 주요 클래스, 데코레이터 및 사용법을 설명합니다.
설치
pip으로 설치
pip install dooray-sdk
aiohttp 포함 설치 (권장)
pip install dooray-sdk[aiohttp]
가상환경 사용 (권장)
# 가상환경 생성
python3 -m venv .venv
# 활성화 (Linux/macOS)
source .venv/bin/activate
# 활성화 (Windows)
.venv\Scripts\activate
# 설치
pip install dooray-sdk[aiohttp]
필수 의존성
| 패키지 | 버전 | 설명 |
|---|---|---|
aiohttp |
>= 3.8.0 | 비동기 HTTP/WebSocket 클라이언트 |
requests |
>= 2.28.0 | 동기 HTTP 클라이언트 |
환경변수
SDK는 다음 환경변수를 사용합니다:
| 환경변수 | 필수 | 설명 | 예시 |
|---|---|---|---|
DOORAY_AGENT_TOKEN |
예 | 에이전트 인증 토큰 | your_agent_token |
DOORAY_DOMAIN |
예 | Dooray 도메인 | company.dooray.com |
클래스
Agent
Dooray 에이전트를 만들기 위한 핵심 클래스입니다. 메시지 수신, 자동 응답, 이벤트 처리 등을 지원합니다.
class Agent:
def __init__(
self,
token: str = None,
domain: str = None,
services: List[str] = None,
**kwargs
)
생성자 매개변수
| 매개변수 | 타입 | 기본값 | 설명 |
|---|---|---|---|
token |
str | None |
None |
에이전트 토큰 (환경변수 DOORAY_AGENT_TOKEN 대체) |
domain |
str | None |
None |
Dooray 도메인 (환경변수 DOORAY_DOMAIN 대체) |
services |
List[str] | None |
["messenger"] |
연결할 서비스 목록 |
속성
| 속성 | 타입 | 설명 |
|---|---|---|
token |
str |
에이전트 인증 토큰 |
domain |
str |
Dooray 도메인 |
services |
List[str] |
연결된 서비스 목록 |
base_url |
str |
API 기본 URL |
is_connected |
bool |
연결 상태 |
메서드
| 메서드 | 설명 |
|---|---|
run() |
에이전트 실행 (블로킹) |
on(event_type, action, service) |
이벤트 핸들러 데코레이터 |
add_handler(event_type, handler, action, service) |
핸들러 등록 (비데코레이터) |
reply_to(trigger, response) |
단순 응답 매핑 |
send_message(channel, text) |
메시지 전송 |
예제 - 기본 사용
from dooray_sdk import Agent
agent = Agent()
@agent.messenger
def handle_message(req):
"""메신저 메시지 처리."""
if req.text:
req.reply(f"받은 메시지: {req.text}")
agent.run()
예제 - 멀티 서비스
from dooray_sdk import Agent
agent = Agent(services=["messenger", "task", "wiki"])
@agent.messenger
def handle_messenger(req):
req.reply("메신저 메시지입니다")
@agent.task
def handle_task(req):
print(f"업무 이벤트: {req.action}")
@agent.wiki
def handle_wiki(req):
print(f"위키 이벤트: {req.action}")
agent.run()
SocketModeRequest
WebSocket으로 수신된 요청을 나타내는 클래스입니다.
@dataclass
class SocketModeRequest:
envelope_id: str
type: str
payload: Dict[str, Any]
service: str = ""
action: str = ""
entity: EntityWrapper = None
actor: ActorWrapper = None
action_data: ActionWrapper = None
속성
| 속성 | 타입 | 설명 |
|---|---|---|
envelope_id |
str |
메시지 고유 ID |
type |
str |
이벤트 타입 (message, task, page 등) |
payload |
Dict[str, Any] |
원본 페이로드 데이터 |
service |
str |
서비스 이름 (messenger, task, wiki) |
action |
str |
액션 타입 (create, update, delete) |
entity |
EntityWrapper |
엔티티 정보 래퍼 |
actor |
ActorWrapper |
액터 정보 래퍼 |
action_data |
ActionWrapper |
액션 데이터 래퍼 |
편의 속성
| 속성 | 타입 | 설명 |
|---|---|---|
is_message |
bool |
메시지 타입 여부 |
text |
str | None |
메시지 텍스트 |
channel |
str | None |
채널 ID |
data |
Dict[str, Any] |
원본 데이터 (payload 별칭) |
메서드
| 메서드 | 설명 |
|---|---|
reply(text) |
동기/비동기 응답 전송 |
is_type(types) |
타입 확인 |
is_action(actions) |
액션 확인 |
is_service(services) |
서비스 확인 |
to_dict() |
딕셔너리 변환 |
from_dict(data, default_service) |
딕셔너리에서 생성 (클래스 메서드) |
예제 - 요청 처리
@agent.messenger
def handle(req):
# 메시지 타입 확인
if req.is_message:
print(f"텍스트: {req.text}")
print(f"채널: {req.channel}")
# 액션 확인
if req.is_action("create"):
print("새 메시지입니다")
# 서비스 확인
if req.is_service("messenger"):
req.reply("메신저에서 응답합니다")
WebClient
동기 REST API 클라이언트입니다.
class WebClient:
def __init__(
self,
token: str,
base_url: str = "https://api.dooray.com/",
timeout: int = 30
)
메서드
| 메서드 | 반환 타입 | 설명 |
|---|---|---|
send_message(channel, text, **kwargs) |
Dict |
메시지 전송 |
get_member(member_id) |
Dict |
조직 멤버 정보 조회 |
AsyncWebClient
비동기 REST API 클라이언트입니다.
class AsyncWebClient:
def __init__(
self,
token: str,
base_url: str = "https://api.dooray.com/"
)
메서드
| 메서드 | 반환 타입 | 설명 |
|---|---|---|
send_message(channel, text, **kwargs) |
Dict |
메시지 전송 |
get_member(member_id) |
Dict |
조직 멤버 정보 조회 |
데코레이터
서비스별 데코레이터
각 서비스에 대한 이벤트 핸들러를 등록합니다.
@agent.messenger # 메신저 서비스 전체 이벤트
@agent.task # 업무 서비스 전체 이벤트
@agent.wiki # 위키 서비스 전체 이벤트
@agent.on() 데코레이터
통합 이벤트 핸들러 데코레이터입니다.
def on(
event_type: Union[str, List[str]] = "all",
action: Union[str, List[str]] = None,
service: Union[str, List[str]] = None
) -> Callable
매개변수
| 매개변수 | 타입 | 기본값 | 설명 |
|---|---|---|---|
event_type |
str | List[str] |
"all" |
이벤트 타입 필터 |
action |
str | List[str] | None |
None |
액션 필터 |
service |
str | List[str] | None |
None |
서비스 필터 |
예제
# 메시지 이벤트만 처리
@agent.on("message")
def handle_message(req):
pass
# 특정 액션만 처리
@agent.on("message", action="create")
def handle_new_message(req):
pass
# 복수 타입 처리
@agent.on(["task", "page"])
def handle_task_or_page(req):
pass
# 서비스 + 액션 조합
@agent.on(service="wiki", action=["create", "update"])
def handle_wiki_changes(req):
pass
요청 데이터 구조
SDK는 딕셔너리 데이터를 점 표기법(dot notation)으로 접근할 수 있게 해주는 래퍼 타입을 제공합니다.
타입 구조 개요
SocketModeRequest
├── entity: EntityWrapper # 엔티티 정보 (task, page 등)
│ ├── type: str # 엔티티 타입
│ └── data: DataWrapper # 엔티티 데이터
├── actor: ActorWrapper # 액션 수행자 정보
│ ├── type: str # 액터 타입
│ └── data: DataWrapper # 액터 데이터
└── action_data: ActionWrapper # 액션 상세 정보
├── type: str # 액션 타입
└── data: DataWrapper # 액션 데이터
DataWrapper
모든 래퍼 타입의 기반이 되는 클래스입니다. 딕셔너리 데이터를 점 표기법으로 접근할 수 있게 합니다.
class DataWrapper:
def __getattr__(self, name: str) -> Any # 점 표기법 접근
def __getitem__(self, key: str) -> Any # 딕셔너리 접근
def get(self, key: str, default=None) # 안전한 접근
def to_dict(self) -> Dict[str, Any] # 원본 딕셔너리 반환
사용 예시:
# 점 표기법 접근
data.id
data.subject
data.nested.value
# 딕셔너리 접근
data["id"]
data.get("subject", "기본값")
# 원본 딕셔너리
data.to_dict()
EntityWrapper
엔티티(업무, 페이지 등) 정보를 래핑합니다.
| 속성 | 타입 | 설명 |
|---|---|---|
type |
str |
엔티티 타입 (예: "task", "page") |
data |
DataWrapper |
엔티티 상세 데이터 |
사용 예시:
@agent.on("task")
def handle_task(req):
print(req.entity.type) # "task"
print(req.entity.data.id) # 업무 ID
print(req.entity.data.subject) # 업무 제목
메시지 데이터
메신저 메시지의 경우 entity.type이 "message"입니다.
| 속성 | 타입 | 설명 |
|---|---|---|
id |
str |
메시지 ID |
channelId |
str |
채널 ID |
senderId |
str |
보낸 사람 멤버 ID |
text |
str |
메시지 텍스트 |
sentAt |
int |
보낸 시간 (timestamp ms) |
seq |
int |
메시지 시퀀스 번호 |
directMemberId |
str |
DM 상대방 멤버 ID |
parentChannelId |
str |
부모 채널 ID (스레드) |
@agent.messenger
def handle(req):
print(req.entity.message.text)
print(req.entity.message.channelId)
print(req.entity.message.senderId)
print(req.entity.message.sentAt)
ActorWrapper
액션을 수행한 사용자 정보를 래핑합니다.
| 속성 | 타입 | 설명 |
|---|---|---|
type |
str |
액터 타입 (예: "organizationMember") |
data |
DataWrapper |
액터 상세 데이터 |
organizationMember |
LazyMemberData | None |
조직 멤버 정보 (lazy loading 지원) |
사용 예시:
@agent.on("message")
def handle(req):
if req.actor:
print(req.actor.type) # "organizationMember"
# organizationMember로 접근 (권장)
member = req.actor.organizationMember
print(member.id) # 멤버 ID (로컬 데이터)
print(member.name) # 멤버 이름 (lazy loading)
organizationMember 필드
| 속성 | 타입 | 설명 |
|---|---|---|
id |
str |
멤버 ID |
name |
str |
멤버 이름 |
externalEmailAddress |
str |
이메일 주소 |
nickname |
str |
닉네임 |
englishName |
str |
영문 이름 |
nativeName |
str |
현지 이름 |
userCode |
str |
사용자 코드 |
locale |
str |
로케일 |
timezoneName |
str |
타임존 |
Lazy Loading
organizationMember는 WebSocket 메시지에 포함된 데이터는 즉시 반환하고, 없는 필드는 API를 호출하여 가져옵니다.
@agent.messenger
async def handle(req):
member = req.actor.organizationMember
# 로컬 데이터 (API 호출 없음)
member_id = member.id
# Async 접근 - 필요시 API 호출
name = await member.name
email = await member.externalEmailAddress
# Sync 접근 (print, 비교 등)
print(member.name)
if member.name == "홍길동":
await req.reply("안녕하세요!")
# 전체 데이터 조회
full_data = await member
ActionWrapper
액션의 상세 정보를 래핑합니다.
| 속성 | 타입 | 설명 |
|---|---|---|
type |
str |
액션 타입 (예: "create", "update") |
data |
DataWrapper |
액션 상세 데이터 |
사용 예시
에코 에이전트
from dooray_sdk import Agent
agent = Agent()
@agent.messenger
def echo(req):
if req.text:
req.reply(f"에코: {req.text}")
agent.run()
자동 응답 에이전트
from dooray_sdk import Agent
agent = Agent()
# 단순 매핑
agent.reply_to("ping", "pong")
agent.reply_to("hello", "안녕하세요!")
# 커스텀 핸들러
@agent.messenger
def handle(req):
text = req.text or ""
if text.startswith("help"):
req.reply("사용 가능한 명령: ping, hello, help")
agent.run()
멀티 서비스 에이전트
from dooray_sdk import Agent
agent = Agent(services=["messenger", "task", "wiki"])
@agent.messenger
def on_message(req):
print(f"[메신저] {req.text}")
req.reply("메시지 받음!")
@agent.task
def on_task(req):
print(f"[업무] {req.action}: {req.entity.data.subject}")
@agent.wiki
def on_wiki(req):
print(f"[위키] {req.action}: {req.entity.data.title}")
@agent.on("all")
def on_any(req):
print(f"[전체] {req.service}/{req.type}/{req.action}")
agent.run()
오류 처리
일반적인 예외
| 예외 | 원인 | 해결 방법 |
|---|---|---|
ValueError |
환경변수 미설정 | DOORAY_AGENT_TOKEN, DOORAY_DOMAIN 설정 |
ConnectionError |
WebSocket 연결 실패 | 네트워크 및 토큰 확인 |
RuntimeError |
에이전트 미실행 상태에서 reply 호출 | agent.run() 후 사용 |
예외 처리 예시
from dooray_sdk import Agent
try:
agent = Agent()
except ValueError as e:
print(f"설정 오류: {e}")
print("DOORAY_AGENT_TOKEN과 DOORAY_DOMAIN을 설정하세요")
exit(1)
@agent.messenger
def handle(req):
try:
# 비즈니스 로직
process_message(req)
except Exception as e:
# 에러 로깅 (사용자에게 에러 노출 방지)
logger.error(f"처리 오류: {e}")
agent.run()
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dooray_sdk-0.0.1a1.tar.gz.
File metadata
- Download URL: dooray_sdk-0.0.1a1.tar.gz
- Upload date:
- Size: 56.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
303b5b536681f6e91d19aa2efc311de3cc5b59a1dfa2462a7be60827d948571f
|
|
| MD5 |
40957b364920ab4df75255b5bcaf4d42
|
|
| BLAKE2b-256 |
2160ff3ebe448f4c80aa4b51825dd87548d916e064818fb29eb1bb3536642795
|
File details
Details for the file dooray_sdk-0.0.1a1-py3-none-any.whl.
File metadata
- Download URL: dooray_sdk-0.0.1a1-py3-none-any.whl
- Upload date:
- Size: 44.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e342edf3fd403587f46d6c49967e956cd61353fbfff9bea3f79e8b9845cb1ba9
|
|
| MD5 |
0528a632fa80cc6652a92ed9454a298b
|
|
| BLAKE2b-256 |
30f386ca3fb9c504bfe37c9f54791c346c56bfdb82dfd9600e219565e1a32fb3
|