ãã®è¨äºã¯ Perl Advent Calendar 2022 14æ¥ç®ã®è¨äºã§ãã
æåã«3è¡ã§ã¾ã¨ã
- Slackã®
rtm.start
APIãå»æ¢ããã - AnySan+AnyEvent::SlackRTMãæ£å¸¸ã«åä½ããªããªã£ã
- ããã解決ããproxyãGoã§æ¸ããã
ãããã¯ãã®éçºã»éç¨ã®ãä¾ã« Slack botãããã¨æãã¾ããã¨ããä¼ç¤¾ã§7ã8å¹´åã«ä½ãããPerlã«ããWebãµã¼ãã¹(ã²ã¼ã ãµã¼ãã¼ã2ã¿ã¤ãã«)ã§ããå¤åã«æ¼ãããSlackã§åä½ãã¦ããbotã大å¤éç¨ããã¦ãã¾ãã
ç¹ã«ãã©ã³ããã¨ã®éçºç°å¢ã®ç«ã¡ä¸ããçµäºããã¹ã¿ã¼ãã¼ã¿ã®æä½ãªã©ã¯Slackã§ã®botã¸ã®ã³ãã³ãã§æä½ããã®ããã£ã±ãã«ãªã£ã¦ãã¦ããããã§ããªãã¨éçºãéç¨ãã»ã¼æ¢ã¾ã£ã¦ãã¾ããããªç¶æ ã§ãã
ãããã®ããã¸ã§ã¯ãã§ã¯Perlã§éåæã«åä½ããbotãæ¸ãããã«ãAnySan 㨠AnySan::Provider::Slackã使ããã¦ãããæ´ã«ãããã AnyEvent::SlackRTM ãå®éã®Slackã«å¯¾ããéä¿¡ãè¡ã£ã¦ããä½ãã«ãªã£ã¦ãã¾ããã
Slackã®rtm.start
APIå»æ¢
ã¨ããã2022å¹´9æãAnyEvent::SlackRTM (v1.1ã¾ã§)ã使ã£ã¦ããAPIã§ãã rtm.start
ãå»æ¢ããããã¨ã«ãªãã¾ããã
ãã®APIã¯æåæãããã£ãé¢ä¿ããWebSocketæ¥ç¶ã®æåã«ãã®workspaceã«ããã¡ã³ãã¼å ¨å¡(!!)ã®æ å ±ã¨ãWebSocketã®æ¥ç¶ã¨ã³ããã¤ã³ããè¿ããã¨ãã豪æ°ãªä½ãã«ãªã£ã¦ãããworkspaceã«äººãããããããã¨ã¬ã¹ãã³ã¹ã極ãã¦é ãã¨ããç¹å¾´ãããã¾ãã (ãªã®ã§å»æ¢ããããã§ããã)ã
å®éã«ããã§APIãã¿ã¤ã ã¢ã¦ããã¦botãèµ·åã§ããªããã¨ããããHTTPã¯ã©ã¤ã¢ã³ãã®ã¿ã¤ã ã¢ã¦ãã伸ã°ãPRãååãéã£ã¦åãã§ããããã¾ããã
代æ¿ã¨ãã¦ã¯ rtm.connect
ã¨ããAPIã使ããã¨ãã§ãã¾ãããã®APIã¯ãåç´ã«WebSocketã®æ¥ç¶ã¨ã³ããã¤ã³ããè¿ããã®ã§é«éã§ããAnyEvent::SlackRTM ã«ãããã«åãæ¿ããPRãéããã¦ããã®ã§ãããä½è
ãããPerlããã¾ã使ã£ã¦ããªããããããã°ããåå¿ãããã¾ããã§ããã
ä½åº¦ãã³ã¡ã³ãããçµæãåãè¾¼ãã§ãªãªã¼ã¹ãã¦ããããã®ã§ãããä½è æ°ã
I'm not doing a lot of Perl these days, and I am not writing any bots at all, unfortunately.
ã¨ã®ãã¨ã§ãä»å¾ã®ã¡ã³ããã³ã¹ã¯ã¡ãã£ã¨æå¾ ãã¥ããæãã§ãã
rtm.start
ãå»æ¢ããã¦ã©ããªã£ãã
ãã¦ãrtm.connect
ã使ãã°ããã§åé¡ãªããã¨ããã¨ãå®éã«ããã«åãæ¿ããå ´åã«ããã¤ãåé¡ãçºçããã®ã§ããã
- AnySan::Provider::Slack ã¯
rtm.start
ã§ã¡ã³ãã¼ãªã¹ããè¿ãããã®ãã¡ã¢ãªä¸ã«hashã§æã¤- ãã®æ å ±ã使ã£ã¦ã¡ãã»ã¼ã¸ã®éä¿¡è (IDãå«ã¾ãã¦ãã)ããnicknameã解決ãã¦ãã
- AnySanã®APIã§ã¯ãIDã§ã¯ãªãnicknameãåãåãããã«ãªã£ã¦ãã (ãã¨ãã¨IRCç¨ã ã£ãã®ã§æ¦å¿µãnicknameãã¼ã¹)
- ã¡ã³ãã¼ãªã¹ãããªãã¨ã¡ãã»ã¼ã¸ã®éä¿¡è ãåããªããããããã«ä¾åããå¦çãã§ããªããªã£ã
rtm.start
å»æ¢å¾ãé »ç¹ã«botããå身ãããããã«ãªã£ã- ããã¯ä»¥åã¯ãªãã£ãæåãªã®ã§ãããã©ãããbotä¸ã§æ°ç§ç¨åº¦ããããã³ã°ããå¦çããã¦ãã¾ãã¨WebSocketãåæãããæã®ãããªæåã示ãããã§ã
- å ãã¦AnyEvent::WebSocket::Client ãããã®åæ¥ç¶ã®æåãåå ãªã®ããåæ¥ç¶ãèµ·ããã¨å é¨çã«2åãããªãbotãéè¤ãããããªæåãããããã«ãªãã¾ããâå身
å¾è ã¯ããªãæ·±å»ã§ãä¸æã«botãå é¨çã«1â2â4â8ã¨å身ãã¦ãããããã¡ãã»ã¼ã¸ã«åå¿ããããã1ã¤è©±ããããã¨è¤æ°ã®botãä¸æã«è¿äºããã (ã ããªãã¾ã ãããéçºç°å¢ãéè¤ãã¦èµ·åãããCIãéè¤ãã¦å®è¡ããããã) ããã«ãªã£ã¦ãã¾ãã¾ããã
ã¨ããããããã»ã¹ãåèµ·åããã°ãªã»ããããã¦å¾©æ´»ããã®ã§ãå®æçã«åèµ·åãã¦åãã¨ããã¯ã¼ã¯ã¢ã©ã¦ã³ãã§åãã§ããã®ã§ãããä¸æã«å身ãããã³ã«æåã§åèµ·åããã®ã¯ãã¾ãã«ãã²ã©ãéç¨ã§ããã
è§£æ±ºæ³ proxy ãæ¸ã
å身ã¾ããã®æåã¯AnyEvent::WebSocket::Client (ãæ´ã«ããã§ä½¿ã£ã¦ããã¢ã¸ã¥ã¼ã«)ãé å¼µã£ã¦è¿½ãã°ãç´ããããããã¾ããããããbotã®è¡åã«ã¯çºè¨è ãã¡ã³ãã¼ãªã¹ãã§è§£æ±ºãã¦ããã®çºè¨è ã®æ å ±ãå ã«ãªã«ãããã³ã¼ãããã£ããããããããªãã¨ããã¦è§£æ±ºããªãã¨botã®æ¹ä¿®ãå¿ è¦ã«ãªã£ã¦ãã¾ãã¾ãã
ãããä»ããAnySanãé å¼µã£ã¦ç´ãã¦ããããããã¢ã¸ã¥ã¼ã«ã®ã¡ã³ããã使ã£ã¦ããªãããã ãâ¦
ã¨æ©ãã çµæããSlackã®rtm.start
ã®ããªãããProxyãæ¸ãæ¹ãæ©ãããããªãã(Goã§)ãã¨æãç«ã¡ã1æ¥é å¼µã£ã¦æ¸ãããåããã®ã§æå
¥ãã¾ãããããã£ãã§ããã
sock2rtm
Goã§æ¸ããããSlack Socket Modeã§ã¡ãã»ã¼ã¸ãåä¿¡ãã¦Slack RTMã®ããã«æ¯ãèãproxyãã§ãã
使ããã人ããããã¯åããã¾ããããREADMEã¯æ¥æ¬èªã§æ¸ãã¦ããã®ã§ä½¿ãå ´åã¯èªãã§ã¿ã¦ãã ããã
/start/{ãã£ã³ãã«ID è¤æ°æå®ããå ´å㯠, åºåã}
ã«æ¥ç¶ããã¨ããã®ãã£ã³ãã«ã«ããã¡ã³ãã¼ãåå¾ãã¦rtm.start
ã¨åæ§ã®ã¬ã¹ãã³ã¹ãè¿ãã¾ããWebSocket APIãæä¾ãã¦ãããããã¬ã¹ãã³ã¹ã®ä¸ã®WebSocket URLã«æ¥ç¶ããã¨ãbotãjoinãã¦ãããã£ã³ãã«ã®ã¡ãã»ã¼ã¸ã(Slack RTMåæ§ã®å½¢å¼ã§)éã£ã¦ãã¾ãã
ã¤ã¾ãAnyEvent::SlackRTM ã使ç¨ããå ´åã¯ã$AnyEvent::SlackRTM::START_URL
ããã®APIã®URLã«æ¸ãæããã°OKãªã®ã§ãï¼
Socket Modeå´ã®åæ¥ç¶ã¯Goã®Slackã¯ã©ã¤ã¢ã³ãããããªã«ãã¦ãããã®ã§ãããWebSocketå´ã§åæ¥ç¶ãçºçããã¨ç¸å¤ãããå身ãããã¨ãããã¾ãã
ãããã調ã¹ãçµæãAnyEvent::WebSocket::Connection::close
ãå¼ã°ãããããã§èªæ»ãã(ããã¦supervisorã«åèµ·åãã¦ããã)ã®ãæã£åãæ©ãã£ãããã以ä¸ã®ãããªã³ã¼ããbotã®æåã«å
¥ãã¦è§£æ±ºãã¾ããã
BEGIN { if ($ENV{SLACK_START_URL} ne '') { # sock2rtmã®ã¨ã³ããã¤ã³ãã«å·®ãæ¿ãã # https://metacpan.org/dist/AnyEvent-SlackRTM/source/lib/AnyEvent/SlackRTM.pm#L14 warn "Set SLACK_START_URL to $ENV{SLACK_START_URL}"; $AnyEvent::SlackRTM::START_URL = $ENV{SLACK_START_URL}; # åæ¥ç¶æã«è¤æ°ã®websocketæ¥ç¶ãçºçãã¦å身ããç¾è±¡ããã # close()ãä¸æ¸ããããã¨ã§ãwebsocketåææã«ããã»ã¹ãæ»ã¬ããã«ãªã # start_serverããèµ·åãããã¨ã§ãããã»ã¹ãåèµ·åããããã¨ãæå¾ ãã sub AnyEvent::WebSocket::Connection::close { die "websocket connection closed"; } } };
ãªããããã§ããªãããç¨ã«å身ãã¦ãã¾ããã¨ãããã¾ããsock2rmã«ã¯/metrics
ã¨ããã¨ã³ããã¤ã³ãããããJSONå½¢å¼ã§ã¡ããªã¯ã¹ãåå¾ã§ãã¾ããwebsocket.current_connections
ãsock2rtmã«æ¥ç¶ãã¦ããã¯ã©ã¤ã¢ã³ãã®ã³ãã¯ã·ã§ã³æ°(ã¤ã¾ãbotã®å身æ°)ãªã®ã§ããããã¢ãã¿ãªã³ã°ãã¦åèµ·åãèµ°ãããããªã©ãã§ãã¾ããããããå°ç©ã§ãã£ã¦ãå¯è¦³æ¸¬æ§ã¯å¤§äºã§ããã
{ "slack": { "hello": 1, "connecting": 1, "connected": 1, "disconnect": 0 }, "websocket": { "total_connections": 9, "current_connections": 1 }, "messages": { "received_from_slack": 0, "delivered_to_websocket": 0, "unsupported_from_slack": 0, "write_errored_to_websocket": 0 } }
ãããã«
æè¿ã¯æ°è¦ã§Perlã使ã£ãéçºããããã¨ã¯å°ãªããªãã¾ããããéç¨ä¸ã®ãããã¯ãã¯å¼ãç¶ãéç¨ãã¦ãããªããã°ããã¾ãããåé¡ãèµ·ããå ´åããã¡ããPerlã®ä¸ã§è§£æ±ºãããã¨ãä¸çªããã®ã§ãããæè¿ã®è¶¨å¢ã ã¨ãªããªãã¢ã¯ãã£ããªã¡ã³ããã³ã¹ãæå¾ ãã¥ãããã¨ãããã¾ãããã®å ´åã¯ãå¤å´ã§ä¸å±¤å ãã§ããã¦è§£æ±ºãããã¨ãã§ããããããªãããã¨ããã話ã§ããã