Laravel로 만드는 Slack Bot (2) - 슬랙 봇 구현
- 초기설정을 마친 후, ComponentObjectModel 방식으로 슬랙봇을 구현한다.
- https://min-nine.tistory.com/186
Component Object Model이란?
- 마이크로소프트에서 개발한, 다양한 언어로 만들어진 소프트웨어 컴포넌트들이 자신의 기능을 다른 소프트웨어와 공유하고 통합될 수 있도록 하는 이진 코드 레벨에서의 표준과 서비스를 총칭합니다.
- 쉽게 말하자면 컴포넌트 '자동차' 1개의 컴포넌트로 구성되어 있는 것이 아닌 엔진,타이어,변속기 등이 각각 컴포넌트로 분리되어 있는 것을 의미합니다.
- 프로그래밍 언어 독립성과 하위 호환성을 가능하게 하는 기술로써 객체 내부는 노출하지 않되, 응용프로그램이 호출 할 수 있는 메서드 단위로 구성된 객체지향 모델링 방법중 하나입니다.
- Model이기 때문에 본인은 App\Models\ 에 만들어 사용하였습니다.
SettingComponentObjectModel 생성하기
<?php
namespace App\Models;
class SettingComponentObjectModel
{
// Settings 테이블 조회
public static function get($key, $default = null)
{
if (!$row = Setting::where('key', $key)->first()) {
return $default;
}
return json_decode($row->value, true);
}
// Settings 테이블 삽입
public static function set($key, $value = null)
{
if (is_array($key) && $value === null) {
$rows = $key;
foreach ($rows as $key => $value) {
self::set($key, $value);
}
} else {
$row = Setting::where('key', $key)->first() ?: new Setting;
$row->key = $key;
$row->value = json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
$row->save();
}
}
}
SlackCompoentObjectModel 생성하기
<?php
namespace App\Models;
use GuzzleHttp\Client;
use Illuminate\Support\Arr;
use App\Models\SettingComponentObjectModel;
class SlackComponentObjectModel
{
const CHANNEL1 = 'channel1';
const CHANNEL2 = 'channel2';
const CHANNEL3 = 'channel3';
private static $last_channel_category = null;
public static function setLastSlackCategory($slack_category)
{
self::$last_channel_category = $slack_category;
}
public static function getLastSlackCategory($default = null)
{
return self::$last_channel_category ?: $default;
}
public static function getSlackCategoryWithChannelToken($channel_token)
{
$slack = SettingComponentObjectModel::get('slack', null);
foreach (Arr::get($slack, "channels") as $news_category => $channel) {
if ($channel['token'] === $channel_token) {
return $news_category;
}
}
return null;
}
public static function getTokensWithSlackCategory($slack_category)
{
$tokens = [];
$slack = SettingComponentObjectModel::get('slack', null);
$channel_key = Arr::get($slack, "channels.$slack_category", [$slack_category]);
$channel_bot = Arr::get($channel_key, 'bot');
$channel_token = Arr::get($channel_key, 'token');
if ($bot =Arr::get($slack, "bots.$channel_bot")) {
$bot_token = Arr::get($bot, 'token');
$tokens[] = ['bot_token' => $bot_token, 'channel_token' => $channel_token];
}
return $tokens;
}
public static function async($slack_category, $msg, $data = [])
{
$slack_call_idx = SettingComponentObjectModel::get('slack_call_idx', 0);
$slack_call_idx++;
SettingComponentObjectModel::set('slack_call_idx', $slack_call_idx);
$data = array_merge($data, ['slack_call_idx' => $slack_call_idx]);
$tokens = self::getTokensWithSlackCategory($slack_category);
foreach ($tokens as $token) {
\App\Jobs\SendSlackJob::dispatch(
Arr::get($token, 'bot_token'),
Arr::get($token, 'channel_token'),
$msg,
$data
);
}
}
public static function send($bot_token, $channel_token, $msg, $data = [])
{
$json = [
"channel" => $channel_token,
"text" => $msg,
];
if ($data) {
$json = array_merge($json, $data);
}
$client = new Client(['base_uri' => 'https://slack.com/api/']);
$client->request('POST', 'chat.postMessage', [
'headers' => ['Authorization' => 'Bearer ' . $bot_token],
'json' => $json,
]);
self::setLastSlackCategory(null);
}
}
SendSlackJob 생성하기
- make:job 명령어로 위 SlackCom에서 사용할 SendSlackJob 생성
$ php artisan make:job SendSlackJob
<?php
namespace App\Jobs;
use App\Models\SlackComponentObjectModel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SendSlackJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $bot_token;
protected $channel_token;
protected $msg;
protected $data;
public $tries = 2;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($bot_token, $channel_token, $msg, $data)
{
$this->bot_token = $bot_token;
$this->channel_token = $channel_token;
$this->msg = $msg;
$this->data = $data;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// 슬랙은 전송 실패시 30초 뒤에 한번더 시도한다
// 이떄도 실패했을때 failed queue 에 등록됨
try {
SlackComponentObjectModel::send($this->bot_token, $this->channel_token, $this->msg, $this->data);
} catch (\Throwable $exception) {
if ($this->attempts() > 1) {
throw $exception;
}
$this->release(30);
return;
}
}
}
artisan tinker로 테스트하기
- COM 방식으로 만들었기 때문에, 호출에 의해 작동하여 테스트또한 tinker로 호출합니다.
$ php artisan tinker
Psy Shell v0.11.2 (PHP 8.0.16 — cli) by Justin Hileman
>>> App\Models\SlackComponentObjectModel::async(SlackComponentObjectModel::CHANNEL3, 'MyNameIsMingyu!!!!! ');
=> null
>>> App\Models\SlackComponentObjectModel::async(SlackComponentObjectModel::CHANNEL3, 'this is channel 3@@@!@#!@#!#');
=> null
마무리
- 챗봇은 채널 가입이 안 되어있기 때문에 에러가 났었습니다.
- 때문에 스코프에서 chat:write.public을 추가하여 채널 가입이 안된 멤버에게도 메세지 전송을 허락해 줬습니다.
'Laravel' 카테고리의 다른 글
데이터 대량 Insert Or Update 방법에 관한 고찰 - Migration And Seeder 사용하기 (0) | 2022.03.17 |
---|---|
How can change css in laravel nova??? (0) | 2022.03.10 |
Laravel로 만드는 Slack Bot (1) - slack app 만들기 및 초기설정 (0) | 2022.03.02 |
Laravel RestAPI 구현하기 (3) - 상품조회,주문,주문조회 구현 (0) | 2022.03.02 |
Laravel RestAPI 구현하기 (2) - 회원가입,로그인,로그아웃 구현 (1) | 2022.03.02 |