跳至内容

現代フォーラムの選択肢、およびDiscuzフォーラムからnodebbへの移行

Discuzの更新停止後、代替となるフォーラムの選択が必要となりました。いくつか試してみたので、簡単に感想と移行方法を述べます。

以下、Githubのランキング順に記載します。

discourse

これは一位のフォーラムですが、rorベースです。rorの性能はかなり劣り、メモリ使用量も大きいため、直接見送りました。

例を挙げると、以前のログインシステムはrorで作られていました。クローラーが当社のdiscuzフォーラムをクロールする際、各投稿の下にログインリンクがあり、fromパラメータが異なるため、一部の低品質なクローラーはそれらすべてをクロールしてしまい、そのページは単にログインボックスを表示するだけなのに、rorのログインシステムをダウンさせてしまいました。一方、同じくクロールされていたdiscuzは全く影響を受けませんでした。discuzの速度と経済性に慣れている方は、この点を耐えられるかどうか、覚悟しておいてください。

flarum

このインターフェースは非常に優れています。php+mysqlベースなので、性能上の問題はないはずですが、フォーラムのSQLクエリが最適化されておらず、空のフォーラムで初期投稿にアクセスすると100回のSQLクエリが発生し、読み込み速度は100msから始まります。低スペックのクラウドデータベースを使用している場合、200msも普通です。この速度に他の読み込み内容を加えると、ほぼ1秒の待ち時間になります。

nodebb

これはnosql+nodejsで作られており、性能が高く、CPU使用率も低いです。さらにwebsocketの長い接続を基盤としているため、応答速度が非常に速いです。メモリ使用量は初期1GBですが、増加は緩やかです。プラグインとAPIが充実しているため、これを選択しました。

apache / answer

これも非常に優れており、知乎やstackoverflowに似ています。しかし、質問や採用といった機能を削除する方法を探しましたが見つかりませんでした。もし削除できれば、記事(長文の主投稿)を中心としたフォーラムとなり、多くの交流機能を必要とせず、攻略向けのフォーラムに適しています。

flaskbb / flaskbb

Pythonのフォーラムで、性能は非常に優れていますが、長い間更新されていません。

rafalp / Misago

一目で二次元フォーラムとわかるもので、これもPythonベースです。作者は開発を始めて数年ですが、非常に熱心です。彼がPythonのSocialAuthライブラリを使用しているのを見ましたが、QQ、Weixin、Googleなどのさまざまなログイン方法を統合でき、自社サイトとの統合も容易です。

また、中国人による2つのフォーラムも良さそうに見えました。一つはCasbinでv2exを高精度に模倣しており、もう一つはbbs-goとsymphonyでcsdnのブログに似ていますが、これらは試していません。

Discuz から nodebb への移行

自社のウェブサイトをお持ちの場合、nodebbのパスポート移行には、nodebb-plugin-session-sharingまたはnodebb-plugin-sso-oauth2-multipleの2つの公式プラグインが使用できます。

discuzのインポートについては、自分でコードを書くしかありません。AIにPythonでフレームワークを書いてもらい、残りは自分で修正します。

投稿のみをインポートする必要がある場合、discuzのpostsテーブルをループ処理し、各行が一つの投稿です。first=1が主題投稿です。

主題投稿の場合、nodebbのapi/v3/topics/インターフェースを呼び出し、返信の場合はapi/v3/topics/{tid}インターフェースを呼び出します。ユーザーについては、ユーザー作成インターフェースを使用できます。私はsession-sharingを使用しているため、api/session-sharing/userインターフェースを使用し、ユーザーの検索にはapi/session-sharing/lookup?id={passport_id}を使用しています。

APIの処理速度は1秒あたり5回なので、ゆっくりと移行する準備をしてください。

呼び出し例:

async def create_topic(title, body, timestamp, category, tags, uid):
    # 主題作成 POST
    data = {
        "cid": category,  # カテゴリ番号
        "title": title,
        "content": body,
        "timestamp": int(timestamp),  # ミリ秒単位の時間
        "tags": tags,
        "_uid": uid   # 投稿者
    }
    # api管理者キー
    headers = {"Authorization": f"Bearer 1239383-3323-2323-2323-asd123123123"}
    # 呼び出し
    async with aiohttp.ClientSession() as session:
        async with session.post(
                'https://xxx.com/api/v3/topics/',
                headers=headers,
                json=data
        ) as response:
            if response.status != 200:
                # 「投稿内容を追加してください。1文字以上必要です」というエラーの場合、contentがエスケープされていません
                response_text = await response.text()
                raise Exception(f"Error creating topic {title}: {response_text}")
            result = await response.json()
            topic_object = result['response']
            return topic_object['tid']

注意点として、APIによる投稿とユーザーによる投稿は同じロジックであり、フォーラムのすべての文字数制限の対象となります。同様に、timestampもこれにより無効になり、最新の時間で投稿されてしまいます。解決策は、src/api/helpers.js の16行目のタイムスタンプを修正し、data.timestamp = Date.now(); の行を直接コメントアウトすることです。移行後は元に戻すことを忘れないでください。そうしないと、ユーザーも時間を変更できるようになってしまいます。

この修正後、返信のAPIインターフェース api/v3/topics/{tid} も、timestamp を指定して時間を渡すことができるようになります。