1212from derisk ._private .pydantic import BaseModel , ConfigDict , Field
1313
1414
15+ class ChannelConnectionState (str , Enum ):
16+ """Channel connection state enumeration."""
17+
18+ DISCONNECTED = "disconnected"
19+ CONNECTING = "connecting"
20+ CONNECTED = "connected"
21+ ERROR = "error"
22+ RECONNECTING = "reconnecting"
23+
24+
25+ class SendMessageResult (BaseModel ):
26+ """Result of sending a message through a channel."""
27+
28+ model_config = ConfigDict (title = "SendMessageResult" )
29+
30+ success : bool = Field (
31+ ...,
32+ description = "Whether the message was sent successfully" ,
33+ )
34+ message_id : Optional [str ] = Field (
35+ default = None ,
36+ description = "Message ID returned by the channel platform" ,
37+ )
38+ error : Optional [str ] = Field (
39+ default = None ,
40+ description = "Error message if sending failed" ,
41+ )
42+ timestamp : Optional [datetime ] = Field (
43+ default = None ,
44+ description = "Timestamp when the message was sent" ,
45+ )
46+
47+
1548class ChannelType (str , Enum ):
1649 """Channel type enumeration."""
1750
@@ -83,7 +116,7 @@ class ChannelCapabilities(BaseModel):
83116class ChannelConfig (BaseModel ):
84117 """Base channel configuration."""
85118
86- model_config = ConfigDict (title = "ChannelConfig" )
119+ model_config = ConfigDict (title = "ChannelConfig" , extra = "allow" )
87120
88121 enabled : bool = Field (
89122 default = True ,
@@ -97,6 +130,10 @@ class ChannelConfig(BaseModel):
97130 default = None ,
98131 description = "Channel description" ,
99132 )
133+ platform_config : Optional [Dict [str , Any ]] = Field (
134+ default = None ,
135+ description = "Platform-specific configuration (FeishuConfig, DingTalkConfig, etc.)" ,
136+ )
100137
101138
102139class ChannelMessage (BaseModel ):
@@ -161,6 +198,88 @@ class ChannelHandler(ABC):
161198 They handle message processing, signature validation, and capability reporting.
162199 """
163200
201+ def __init__ (self , channel_id : str , config : "ChannelConfig" ):
202+ """Initialize the channel handler.
203+
204+ Args:
205+ channel_id: The unique identifier for this channel.
206+ config: The channel configuration.
207+ """
208+ self ._channel_id = channel_id
209+ self ._config = config
210+ self ._connection_state : ChannelConnectionState = (
211+ ChannelConnectionState .DISCONNECTED
212+ )
213+
214+ @classmethod
215+ def get_default_capabilities (cls ) -> ChannelCapabilities :
216+ """Get default capabilities for this channel type.
217+
218+ This class method can be called without instantiating the handler.
219+ Subclasses should override this to return their specific capabilities.
220+
221+ Returns:
222+ ChannelCapabilities instance with default values.
223+ """
224+ return ChannelCapabilities ()
225+
226+ @property
227+ def channel_id (self ) -> str :
228+ """Get the channel ID."""
229+ return self ._channel_id
230+
231+ @property
232+ def connection_state (self ) -> ChannelConnectionState :
233+ """Get the current connection state."""
234+ return self ._connection_state
235+
236+ @abstractmethod
237+ async def start (self ) -> None :
238+ """Start the channel handler.
239+
240+ This should establish the connection to the platform (WebSocket, Stream, etc.)
241+ and start listening for incoming messages.
242+ """
243+ pass
244+
245+ @abstractmethod
246+ async def stop (self ) -> None :
247+ """Stop the channel handler.
248+
249+ This should close all connections and stop listening for messages.
250+ """
251+ pass
252+
253+ @abstractmethod
254+ async def send_message (
255+ self ,
256+ receiver_id : str ,
257+ content : str ,
258+ content_type : str = "text" ,
259+ ** kwargs ,
260+ ) -> SendMessageResult :
261+ """Send a message to a receiver through this channel.
262+
263+ Args:
264+ receiver_id: The ID of the receiver (user or group).
265+ content: The message content.
266+ content_type: The content type (text, markdown, etc.).
267+ **kwargs: Additional parameters (reply_to, mentions, etc.).
268+
269+ Returns:
270+ SendMessageResult indicating success or failure.
271+ """
272+ pass
273+
274+ @abstractmethod
275+ def get_connection_url (self ) -> Optional [str ]:
276+ """Get the webhook URL for setting up the channel integration.
277+
278+ Returns:
279+ The webhook URL if applicable, None if using WebSocket/Stream mode.
280+ """
281+ pass
282+
164283 @abstractmethod
165284 async def process_message (
166285 self ,
@@ -220,4 +339,4 @@ async def test_connection(self, channel_id: str) -> bool:
220339 Returns:
221340 True if the connection is successful, False otherwise.
222341 """
223- pass
342+ pass
0 commit comments