libs.dispatcher

libs/dispatcher.py

  1"""
  2libs/dispatcher.py
  3"""
  4
  5import logging
  6from typing import TYPE_CHECKING
  7
  8import libs.global_value as g
  9from integrations import factory
 10from libs.domain import modify
 11from libs.domain.score import GameResult
 12from libs.functions import lookup, message
 13from libs.types import MessageStatus, StyleOptions
 14from libs.utils import formatter, validator
 15
 16if TYPE_CHECKING:
 17    from integrations.protocols import MessageParserProtocol
 18
 19
 20def by_keyword(m: "MessageParserProtocol") -> None:
 21    """メイン処理"""
 22    g.params.default_reset()
 23    g.params.update_from_dict(
 24        {
 25            "database_file": g.cfg.setting.database_file,
 26            "logging_verbose": g.args.verbose,
 27        }
 28    )
 29
 30    logging.debug("keyword=%s, argument=%s, source=%s", m.keyword, m.argument, m.status.source)
 31    logging.debug(
 32        "status=%s, event_ts=%s, thread_ts=%s, in_thread=%s, is_command=%s, user_id=%s,",
 33        m.data.status.value,
 34        m.data.event_ts,
 35        m.data.thread_ts,
 36        m.in_thread,
 37        m.is_command,
 38        m.data.user_id,
 39    )
 40
 41    # 変更がないイベントは処理をスキップ
 42    if m.data.status == MessageStatus.DO_NOTHING:
 43        return
 44
 45    # 許可されていないユーザのコマンドは処理しない
 46    if m.ignore_user:
 47        logging.debug("event skip[ignore user]: %s", m.data.user_id)
 48        return
 49
 50    # メッセージが削除された場合
 51    if m.data.status == MessageStatus.DELETED:
 52        message_deleted(m)
 53        return
 54
 55    match m.keyword:
 56        # キーワード実行
 57        case word if word in g.keyword_dispatcher and not m.is_command:
 58            logging.debug("dispatch keyword")
 59            if m.data.status == MessageStatus.APPEND:
 60                g.keyword_dispatcher[word](m)
 61        # コマンド実行
 62        case word if word in g.command_dispatcher and m.is_command:
 63            logging.debug("dispatch command")
 64            if m.data.status == MessageStatus.APPEND:
 65                g.command_dispatcher[word](m)
 66        # リマインダ実行
 67        case "Reminder:":
 68            logging.debug("dispatch keyword for reminder")
 69            if m.data.text in g.keyword_dispatcher and m.is_bot:
 70                g.keyword_dispatcher[m.data.text](m)
 71        # その他(ディスパッチテーブルにない場合)
 72        case _ as word:
 73            logging.debug("dispatch other words")
 74            other_words(word, m)
 75
 76    g.adapter.api.post(m)
 77
 78
 79def other_words(word: str, m: "MessageParserProtocol") -> None:
 80    """
 81    コマンド以外のワードの処理
 82
 83    Args:
 84        word (str): 入力ワード
 85        m (MessageParserProtocol): メッセージデータ
 86
 87    """
 88    if word in g.cfg.rule.remarks_words and m.in_thread:  # 追加メモ
 89        if lookup.exsist_record(m.data.thread_ts).has_valid_data():
 90            modify.check_remarks(m)
 91    else:  # スコア登録
 92        if detection_dict := validator.check_score(m):  # 結果報告フォーマットに一致するポストの処理
 93            score = GameResult(**detection_dict)
 94            # 名前ブレ修正
 95            for k, p in score.to_dict().items():
 96                if k.endswith("_name"):
 97                    score.set(**{k: formatter.name_replace(str(p), not_replace=True)})
 98                    continue
 99
100            match m.data.status:
101                case MessageStatus.APPEND:
102                    message_append(score, m)
103                case MessageStatus.CHANGED:
104                    message_changed(score, m)
105                case _:
106                    pass
107        else:
108            record_data = lookup.exsist_record(m.data.event_ts)
109            if record_data and m.data.status == MessageStatus.CHANGED:
110                message_deleted(m)
111
112
113def message_append(detection: GameResult, m: "MessageParserProtocol") -> None:
114    """
115    メッセージの追加処理
116
117    Args:
118        detection (GameResult): スコアデータ
119        m (MessageParserProtocol): メッセージデータ
120
121    """
122    if _thread_check(m):
123        modify.db_insert(detection, m)
124    else:
125        m.post.ts = m.data.event_ts
126        m.set_message(message.random_reply(m, "inside_thread"), StyleOptions(key_title=False))
127        logging.debug("skip (inside thread). event_ts=%s, thread_ts=%s", m.data.event_ts, m.data.thread_ts)
128
129
130def message_changed(detection: GameResult, m: "MessageParserProtocol") -> None:
131    """
132    メッセージの変更処理
133
134    Args:
135        detection (GameResult): スコアデータ
136        m (MessageParserProtocol): メッセージデータ
137
138    """
139    record_data = lookup.exsist_record(m.data.event_ts)
140
141    # 変更がない場合は終了
142    if detection.to_dict() == record_data.to_dict():
143        return
144
145    # スレッド内チェック → 処理対象外なら終了
146    if not _thread_check(m):
147        m.post.ts = m.data.event_ts
148        m.set_message(message.random_reply(m, "inside_thread"), StyleOptions(key_title=False))
149        logging.debug("skip (inside thread). event_ts=%s, thread_ts=%s", m.data.event_ts, m.data.thread_ts)
150        return
151
152    # 既存データなし → 新規挿入
153    if not record_data.has_valid_data():
154        modify.db_insert(detection, m)
155        modify.reprocessing_remarks(m)
156        return
157
158    # 全条件クリア → 更新実行
159    modify.db_update(detection, m)
160
161
162def message_deleted(m: "MessageParserProtocol") -> None:
163    """
164    メッセージの削除処理
165
166    Args:
167        m (MessageParserProtocol): メッセージデータ
168
169    """
170    if m.keyword in g.cfg.rule.remarks_words:  # 追加メモ
171        modify.remarks_delete(m)
172    else:
173        modify.db_delete(m)
174
175
176def _thread_check(m: "MessageParserProtocol") -> bool:
177    """スレッド内判定関数"""
178    if isinstance(g.adapter, factory.slack_adapter):  # type: ignore[attr-defined]
179        if not m.in_thread or (m.in_thread == g.adapter.conf.thread_report):
180            return True
181        return False
182    return not m.in_thread
def by_keyword(m: integrations.protocols.MessageParserProtocol) -> None:
21def by_keyword(m: "MessageParserProtocol") -> None:
22    """メイン処理"""
23    g.params.default_reset()
24    g.params.update_from_dict(
25        {
26            "database_file": g.cfg.setting.database_file,
27            "logging_verbose": g.args.verbose,
28        }
29    )
30
31    logging.debug("keyword=%s, argument=%s, source=%s", m.keyword, m.argument, m.status.source)
32    logging.debug(
33        "status=%s, event_ts=%s, thread_ts=%s, in_thread=%s, is_command=%s, user_id=%s,",
34        m.data.status.value,
35        m.data.event_ts,
36        m.data.thread_ts,
37        m.in_thread,
38        m.is_command,
39        m.data.user_id,
40    )
41
42    # 変更がないイベントは処理をスキップ
43    if m.data.status == MessageStatus.DO_NOTHING:
44        return
45
46    # 許可されていないユーザのコマンドは処理しない
47    if m.ignore_user:
48        logging.debug("event skip[ignore user]: %s", m.data.user_id)
49        return
50
51    # メッセージが削除された場合
52    if m.data.status == MessageStatus.DELETED:
53        message_deleted(m)
54        return
55
56    match m.keyword:
57        # キーワード実行
58        case word if word in g.keyword_dispatcher and not m.is_command:
59            logging.debug("dispatch keyword")
60            if m.data.status == MessageStatus.APPEND:
61                g.keyword_dispatcher[word](m)
62        # コマンド実行
63        case word if word in g.command_dispatcher and m.is_command:
64            logging.debug("dispatch command")
65            if m.data.status == MessageStatus.APPEND:
66                g.command_dispatcher[word](m)
67        # リマインダ実行
68        case "Reminder:":
69            logging.debug("dispatch keyword for reminder")
70            if m.data.text in g.keyword_dispatcher and m.is_bot:
71                g.keyword_dispatcher[m.data.text](m)
72        # その他(ディスパッチテーブルにない場合)
73        case _ as word:
74            logging.debug("dispatch other words")
75            other_words(word, m)
76
77    g.adapter.api.post(m)

メイン処理

def other_words(word: str, m: integrations.protocols.MessageParserProtocol) -> None:
 80def other_words(word: str, m: "MessageParserProtocol") -> None:
 81    """
 82    コマンド以外のワードの処理
 83
 84    Args:
 85        word (str): 入力ワード
 86        m (MessageParserProtocol): メッセージデータ
 87
 88    """
 89    if word in g.cfg.rule.remarks_words and m.in_thread:  # 追加メモ
 90        if lookup.exsist_record(m.data.thread_ts).has_valid_data():
 91            modify.check_remarks(m)
 92    else:  # スコア登録
 93        if detection_dict := validator.check_score(m):  # 結果報告フォーマットに一致するポストの処理
 94            score = GameResult(**detection_dict)
 95            # 名前ブレ修正
 96            for k, p in score.to_dict().items():
 97                if k.endswith("_name"):
 98                    score.set(**{k: formatter.name_replace(str(p), not_replace=True)})
 99                    continue
100
101            match m.data.status:
102                case MessageStatus.APPEND:
103                    message_append(score, m)
104                case MessageStatus.CHANGED:
105                    message_changed(score, m)
106                case _:
107                    pass
108        else:
109            record_data = lookup.exsist_record(m.data.event_ts)
110            if record_data and m.data.status == MessageStatus.CHANGED:
111                message_deleted(m)

コマンド以外のワードの処理

Arguments:
  • word (str): 入力ワード
  • m (MessageParserProtocol): メッセージデータ
def message_append( detection: libs.domain.score.GameResult, m: integrations.protocols.MessageParserProtocol) -> None:
114def message_append(detection: GameResult, m: "MessageParserProtocol") -> None:
115    """
116    メッセージの追加処理
117
118    Args:
119        detection (GameResult): スコアデータ
120        m (MessageParserProtocol): メッセージデータ
121
122    """
123    if _thread_check(m):
124        modify.db_insert(detection, m)
125    else:
126        m.post.ts = m.data.event_ts
127        m.set_message(message.random_reply(m, "inside_thread"), StyleOptions(key_title=False))
128        logging.debug("skip (inside thread). event_ts=%s, thread_ts=%s", m.data.event_ts, m.data.thread_ts)

メッセージの追加処理

Arguments:
  • detection (GameResult): スコアデータ
  • m (MessageParserProtocol): メッセージデータ
def message_changed( detection: libs.domain.score.GameResult, m: integrations.protocols.MessageParserProtocol) -> None:
131def message_changed(detection: GameResult, m: "MessageParserProtocol") -> None:
132    """
133    メッセージの変更処理
134
135    Args:
136        detection (GameResult): スコアデータ
137        m (MessageParserProtocol): メッセージデータ
138
139    """
140    record_data = lookup.exsist_record(m.data.event_ts)
141
142    # 変更がない場合は終了
143    if detection.to_dict() == record_data.to_dict():
144        return
145
146    # スレッド内チェック → 処理対象外なら終了
147    if not _thread_check(m):
148        m.post.ts = m.data.event_ts
149        m.set_message(message.random_reply(m, "inside_thread"), StyleOptions(key_title=False))
150        logging.debug("skip (inside thread). event_ts=%s, thread_ts=%s", m.data.event_ts, m.data.thread_ts)
151        return
152
153    # 既存データなし → 新規挿入
154    if not record_data.has_valid_data():
155        modify.db_insert(detection, m)
156        modify.reprocessing_remarks(m)
157        return
158
159    # 全条件クリア → 更新実行
160    modify.db_update(detection, m)

メッセージの変更処理

Arguments:
  • detection (GameResult): スコアデータ
  • m (MessageParserProtocol): メッセージデータ
def message_deleted(m: integrations.protocols.MessageParserProtocol) -> None:
163def message_deleted(m: "MessageParserProtocol") -> None:
164    """
165    メッセージの削除処理
166
167    Args:
168        m (MessageParserProtocol): メッセージデータ
169
170    """
171    if m.keyword in g.cfg.rule.remarks_words:  # 追加メモ
172        modify.remarks_delete(m)
173    else:
174        modify.db_delete(m)

メッセージの削除処理

Arguments:
  • m (MessageParserProtocol): メッセージデータ