如何在ejabberd中实现模块?
How to implement modules in ejabberd?
我是 XMPP 服务器 ejabberd 的新手。我通过 link: https://docs.ejabberd.im/admin/installation/#install-on-linux 在 ubuntu 上安装了 ejabberd。我正在使用 ejabberd-20.07/conf 文件夹中的默认 ejabberd.yml 文件。这是我的 ejabberd.yml 文件:
hosts:
- "faiqkhan-VirtualBox"
loglevel: 4
log_rotate_size: 10485760
log_rotate_count: 1
certfiles:
- "/home/faiqkhan/ejabberd-20.07/conf/server.pem"
## - "/etc/letsencrypt/live/localhost/fullchain.pem"
## - "/etc/letsencrypt/live/localhost/privkey.pem"
ca_file: "/home/faiqkhan/ejabberd-20.07/conf/cacert.pem"
listen:
-
port: 5222
ip: "::"
module: ejabberd_c2s
max_stanza_size: 262144
shaper: c2s_shaper
access: c2s
starttls_required: false
-
port: 5269
ip: "::"
module: ejabberd_s2s_in
max_stanza_size: 524288
-
port: 5443
ip: "::"
module: ejabberd_http
tls: true
request_handlers:
"/admin": ejabberd_web_admin
"/api": mod_http_api
"/bosh": mod_bosh
"/captcha": ejabberd_captcha
"/upload": mod_http_upload
"/ws": ejabberd_http_ws
"/oauth": ejabberd_oauth
-
port: 5280
ip: "::"
module: ejabberd_http
request_handlers:
"/admin": ejabberd_web_admin
-
port: 1883
ip: "::"
module: mod_mqtt
backlog: 1000
s2s_use_starttls: optional
acl:
local:
user_regexp: ""
loopback:
ip:
- 127.0.0.0/8
- ::1/128
- ::FFFF:127.0.0.1/128
admin:
user:
- "admin@faiqkhan-VirtualBox"
access_rules:
local:
allow: local
c2s:
deny: blocked
allow: all
announce:
allow: admin
configure:
allow: admin
muc_create:
allow: local
pubsub_createnode:
allow: local
trusted_network:
allow: local
api_permissions:
"console commands":
from:
- ejabberd_ctl
who: all
what: "*"
"admin access":
who:
access:
allow:
acl: loopback
acl: admin
oauth:
scope: "ejabberd:admin"
access:
allow:
acl: loopback
acl: admin
what:
- "*"
- "!stop"
- "!start"
"public commands":
who:
ip: 127.0.0.1/8
what:
- status
- connected_users_number
shaper:
normal: 1000
fast: 50000
shaper_rules:
max_user_sessions: 10
max_user_offline_messages:
5000: admin
100: all
c2s_shaper:
none: admin
normal: all
s2s_shaper: fast
max_fsm_queue: 10000
acme:
contact: "mailto:admin@faiqkhan-VirtualBox"
ca_url: "https://acme-v02.api.letsencrypt.org/directory"
modules:
mod_adhoc: {}
mod_admin_extra: {}
mod_announce:
access: announce
mod_avatar: {}
mod_blocking: {}
mod_bosh: {}
mod_caps: {}
mod_carboncopy: {}
mod_client_state: {}
mod_configure: {}
mod_disco: {}
mod_fail2ban: {}
mod_http_api: {}
mod_http_upload:
put_url: https://@HOST@:5443/upload
mod_last: {}
mod_mam:
## Mnesia is limited to 2GB, better to use an SQL backend
## For small servers SQLite is a good fit and is very easy
## to configure. Uncomment this when you have SQL configured:
## db_type: sql
assume_mam_usage: true
default: never
mod_mqtt: {}
mod_muc:
access:
- allow
access_admin:
- allow: admin
access_create: muc_create
access_persistent: muc_create
access_mam:
- allow
default_room_options:
allow_subscription: true # enable MucSub
mam: false
mod_muc_admin: {}
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
mod_privacy: {}
mod_private: {}
mod_proxy65:
access: local
max_connections: 5
mod_pubsub:
access_createnode: pubsub_createnode
plugins:
- flat
- pep
force_node_config:
## Avoid buggy clients to make their bookmarks public
storage:bookmarks:
access_model: whitelist
mod_push: {}
mod_push_keepalive: {}
mod_register:
## Only accept registration requests from the "trusted"
## network (see access_rules section above).
## Think twice before enabling registration from any
## address. See the Jabber SPAM Manifesto for details:
## https://github.com/ge0rg/jabber-spam-fighting-manifesto
ip_access: all
mod_roster:
versioning: true
mod_s2s_dialback: {}
mod_shared_roster: {}
mod_stream_mgmt:
resend_on_timeout: if_offline
mod_vcard: {}
mod_vcard_xupdate: {}
mod_version:
show_os: false
mod_stanza_ack: {}
我尝试了 link 问题 Ejabberd return message to sender hook / message receipts 中的给定代码,并在上述代码最后一行的 ejabberd.yml 文件中添加了我的模块。我创建 mod_stanza_ack.erl 文件并使用命令
编译该文件
./erlc mod_stanza_ack.erl
并获取 mod_stanza_ack.beam 文件。我将 mod_stanza_ack.beam 文件复制到 ejabberd-20.07/lib/ejabberd-20.07/ebin 文件夹,其中存在所有模块文件.然后我使用
启动 ejabberd 服务器
./ejabberdctl live
查看日志的命令。模块适用于我,但在服务器端,它总是因错误而崩溃
**Hook user_send_packet crashed when running mod_stanza_ack:on_user_send_packet/1:
** exception error: undefined function mod_stanza_ack:on_user_send_packet/1
in function ejabberd_hooks:safe_apply/4 (src/ejabberd_hooks.erl, line 236)
in call from ejabberd_hooks:run_fold1/4 (src/ejabberd_hooks.erl, line 217)
in call from ejabberd_c2s:handle_authenticated_packet/2 (src/ejabberd_c2s.erl, line 484)
in call from xmpp_stream_in:process_authenticated_packet/2 (src/xmpp_stream_in.erl, line 714)
in call from xmpp_stream_in:handle_info/2 (src/xmpp_stream_in.erl, line 404)
in call from p1_server:handle_msg/8 (src/p1_server.erl, line 696)
in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 249)**.
我错过了什么吗?或者使用已弃用的功能?
好吧,那个示例源代码已有 6 年历史,ejabberd 开发 API 从那时起发生了变化。我已经更新了这个例子,这个编译并正确启动了 ejabberd 20.07:
-module(mod_stanza_ack).
-behaviour(gen_mod).
-include("xmpp.hrl").
-include("logger.hrl").
-include("translate.hrl").
-export([start/2, stop/1, mod_options/1, mod_doc/0, depends/2]).
-export([on_user_send_packet/1]).
start(Host, _Opts) ->
?INFO_MSG("mod_stanza_ack starting", []),
ejabberd_hooks:add(user_send_packet, Host, ?MODULE, on_user_send_packet, 0),
ok.
stop(Host) ->
?INFO_MSG("mod_stanza_ack stopping", []),
ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, on_user_send_packet, 0),
ok.
on_user_send_packet({#presence{to = To, from = From} = Packet, C2SState}) ->
?INFO_MSG("mod_stanza_ack a presence has been sent coming from: ~p", [From]),
?INFO_MSG("mod_stanza_ack a presence has been sent to: ~p", [To]),
?INFO_MSG("mod_stanza_ack a presence has been sent with the following packet:~n ~p", [Packet]),
{Packet, C2SState};
on_user_send_packet({#iq{to = To, from = From} = Packet, C2SState}) ->
?INFO_MSG("mod_stanza_ack a iq has been sent coming from: ~p", [From]),
?INFO_MSG("mod_stanza_ack a iq has been sent to: ~p", [To]),
?INFO_MSG("mod_stanza_ack a iq has been sent with the following packet:~n ~p", [Packet]),
{Packet, C2SState};
on_user_send_packet({#message{to = To, from = From} = Packet, C2SState}) ->
?INFO_MSG("mod_stanza_ack a message has been sent coming from: ~p", [From]),
?INFO_MSG("mod_stanza_ack a message has been sent to: ~p", [To]),
?INFO_MSG("mod_stanza_ack a message has been sent with the following packet:~n ~p", [Packet]),
{Packet, C2SState}.
depends(_Host, _Opts) ->
[].
mod_options(_Host) ->
[].
mod_doc() ->
#{desc =>
?T("This an example module.")}.
按照您详细的分步安装指南,我遇到了两个问题,我在这里描述了它们以及如何解决它们:
- 编译缺少头文件。
我复制mod_stanza_ack.erl到ejabberd-20.07/bin,然后运行这个命令:
$ ./erlc mod_stanza_ack.erl
mod_stanza_ack.erl:4: can't find include file "xmpp.hrl"
mod_stanza_ack.erl:5: can't find include file "logger.hrl"
mod_stanza_ack.erl:6: can't find include file "translate.hrl"
mod_stanza_ack.erl:12: undefined macro 'INFO_MSG/2'
mod_stanza_ack.erl:17: undefined macro 'INFO_MSG/2'
mod_stanza_ack.erl:22: undefined macro 'INFO_MSG/2'
mod_stanza_ack.erl:47: undefined macro 'T/1'
mod_stanza_ack.erl:8: function mod_doc/0 undefined
mod_stanza_ack.erl:8: function start/2 undefined
mod_stanza_ack.erl:8: function stop/1 undefined
mod_stanza_ack.erl:9: function on_user_send_packet/1 undefined
解决方法很简单:提供头文件的路径:
$ ./erlc -I ../lib/ejabberd-20.07/include/ -I ../lib/xmpp-1.4.9/include/ -I ../lib/fast_xml-1.1.43/include/ mod_stanza_ack.erl
这样文件编译正确。
- INFO_MSG 源代码中不会在 ejabberd 日志文件或“ejabberdctl live”控制台中生成日志消息。
这是因为我们没有告诉编译器使用 LAGER 库。解决方案非常简单:在模块编译中包含 -DLAGER。所以,这是完美的编译调用:
$ ./erlc -I ../lib/ejabberd-20.07/include/ -I ../lib/xmpp-1.4.9/include/ -I ../lib/fast_xml-1.1.43/include/ -DLAGER mod_stanza_ack.erl
现在,您将生成的 mod_stanza_ack.beam 与所有其他 ejabberd beam 文件一起复制,启用 ejabberd.yml 中的模块,然后重新启动 ejabberd,一切都会按预期工作
我是 XMPP 服务器 ejabberd 的新手。我通过 link: https://docs.ejabberd.im/admin/installation/#install-on-linux 在 ubuntu 上安装了 ejabberd。我正在使用 ejabberd-20.07/conf 文件夹中的默认 ejabberd.yml 文件。这是我的 ejabberd.yml 文件:
hosts:
- "faiqkhan-VirtualBox"
loglevel: 4
log_rotate_size: 10485760
log_rotate_count: 1
certfiles:
- "/home/faiqkhan/ejabberd-20.07/conf/server.pem"
## - "/etc/letsencrypt/live/localhost/fullchain.pem"
## - "/etc/letsencrypt/live/localhost/privkey.pem"
ca_file: "/home/faiqkhan/ejabberd-20.07/conf/cacert.pem"
listen:
-
port: 5222
ip: "::"
module: ejabberd_c2s
max_stanza_size: 262144
shaper: c2s_shaper
access: c2s
starttls_required: false
-
port: 5269
ip: "::"
module: ejabberd_s2s_in
max_stanza_size: 524288
-
port: 5443
ip: "::"
module: ejabberd_http
tls: true
request_handlers:
"/admin": ejabberd_web_admin
"/api": mod_http_api
"/bosh": mod_bosh
"/captcha": ejabberd_captcha
"/upload": mod_http_upload
"/ws": ejabberd_http_ws
"/oauth": ejabberd_oauth
-
port: 5280
ip: "::"
module: ejabberd_http
request_handlers:
"/admin": ejabberd_web_admin
-
port: 1883
ip: "::"
module: mod_mqtt
backlog: 1000
s2s_use_starttls: optional
acl:
local:
user_regexp: ""
loopback:
ip:
- 127.0.0.0/8
- ::1/128
- ::FFFF:127.0.0.1/128
admin:
user:
- "admin@faiqkhan-VirtualBox"
access_rules:
local:
allow: local
c2s:
deny: blocked
allow: all
announce:
allow: admin
configure:
allow: admin
muc_create:
allow: local
pubsub_createnode:
allow: local
trusted_network:
allow: local
api_permissions:
"console commands":
from:
- ejabberd_ctl
who: all
what: "*"
"admin access":
who:
access:
allow:
acl: loopback
acl: admin
oauth:
scope: "ejabberd:admin"
access:
allow:
acl: loopback
acl: admin
what:
- "*"
- "!stop"
- "!start"
"public commands":
who:
ip: 127.0.0.1/8
what:
- status
- connected_users_number
shaper:
normal: 1000
fast: 50000
shaper_rules:
max_user_sessions: 10
max_user_offline_messages:
5000: admin
100: all
c2s_shaper:
none: admin
normal: all
s2s_shaper: fast
max_fsm_queue: 10000
acme:
contact: "mailto:admin@faiqkhan-VirtualBox"
ca_url: "https://acme-v02.api.letsencrypt.org/directory"
modules:
mod_adhoc: {}
mod_admin_extra: {}
mod_announce:
access: announce
mod_avatar: {}
mod_blocking: {}
mod_bosh: {}
mod_caps: {}
mod_carboncopy: {}
mod_client_state: {}
mod_configure: {}
mod_disco: {}
mod_fail2ban: {}
mod_http_api: {}
mod_http_upload:
put_url: https://@HOST@:5443/upload
mod_last: {}
mod_mam:
## Mnesia is limited to 2GB, better to use an SQL backend
## For small servers SQLite is a good fit and is very easy
## to configure. Uncomment this when you have SQL configured:
## db_type: sql
assume_mam_usage: true
default: never
mod_mqtt: {}
mod_muc:
access:
- allow
access_admin:
- allow: admin
access_create: muc_create
access_persistent: muc_create
access_mam:
- allow
default_room_options:
allow_subscription: true # enable MucSub
mam: false
mod_muc_admin: {}
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
mod_privacy: {}
mod_private: {}
mod_proxy65:
access: local
max_connections: 5
mod_pubsub:
access_createnode: pubsub_createnode
plugins:
- flat
- pep
force_node_config:
## Avoid buggy clients to make their bookmarks public
storage:bookmarks:
access_model: whitelist
mod_push: {}
mod_push_keepalive: {}
mod_register:
## Only accept registration requests from the "trusted"
## network (see access_rules section above).
## Think twice before enabling registration from any
## address. See the Jabber SPAM Manifesto for details:
## https://github.com/ge0rg/jabber-spam-fighting-manifesto
ip_access: all
mod_roster:
versioning: true
mod_s2s_dialback: {}
mod_shared_roster: {}
mod_stream_mgmt:
resend_on_timeout: if_offline
mod_vcard: {}
mod_vcard_xupdate: {}
mod_version:
show_os: false
mod_stanza_ack: {}
我尝试了 link 问题 Ejabberd return message to sender hook / message receipts 中的给定代码,并在上述代码最后一行的 ejabberd.yml 文件中添加了我的模块。我创建 mod_stanza_ack.erl 文件并使用命令
编译该文件./erlc mod_stanza_ack.erl
并获取 mod_stanza_ack.beam 文件。我将 mod_stanza_ack.beam 文件复制到 ejabberd-20.07/lib/ejabberd-20.07/ebin 文件夹,其中存在所有模块文件.然后我使用
启动 ejabberd 服务器./ejabberdctl live
查看日志的命令。模块适用于我,但在服务器端,它总是因错误而崩溃
**Hook user_send_packet crashed when running mod_stanza_ack:on_user_send_packet/1:
** exception error: undefined function mod_stanza_ack:on_user_send_packet/1
in function ejabberd_hooks:safe_apply/4 (src/ejabberd_hooks.erl, line 236)
in call from ejabberd_hooks:run_fold1/4 (src/ejabberd_hooks.erl, line 217)
in call from ejabberd_c2s:handle_authenticated_packet/2 (src/ejabberd_c2s.erl, line 484)
in call from xmpp_stream_in:process_authenticated_packet/2 (src/xmpp_stream_in.erl, line 714)
in call from xmpp_stream_in:handle_info/2 (src/xmpp_stream_in.erl, line 404)
in call from p1_server:handle_msg/8 (src/p1_server.erl, line 696)
in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 249)**.
我错过了什么吗?或者使用已弃用的功能?
好吧,那个示例源代码已有 6 年历史,ejabberd 开发 API 从那时起发生了变化。我已经更新了这个例子,这个编译并正确启动了 ejabberd 20.07:
-module(mod_stanza_ack).
-behaviour(gen_mod).
-include("xmpp.hrl").
-include("logger.hrl").
-include("translate.hrl").
-export([start/2, stop/1, mod_options/1, mod_doc/0, depends/2]).
-export([on_user_send_packet/1]).
start(Host, _Opts) ->
?INFO_MSG("mod_stanza_ack starting", []),
ejabberd_hooks:add(user_send_packet, Host, ?MODULE, on_user_send_packet, 0),
ok.
stop(Host) ->
?INFO_MSG("mod_stanza_ack stopping", []),
ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, on_user_send_packet, 0),
ok.
on_user_send_packet({#presence{to = To, from = From} = Packet, C2SState}) ->
?INFO_MSG("mod_stanza_ack a presence has been sent coming from: ~p", [From]),
?INFO_MSG("mod_stanza_ack a presence has been sent to: ~p", [To]),
?INFO_MSG("mod_stanza_ack a presence has been sent with the following packet:~n ~p", [Packet]),
{Packet, C2SState};
on_user_send_packet({#iq{to = To, from = From} = Packet, C2SState}) ->
?INFO_MSG("mod_stanza_ack a iq has been sent coming from: ~p", [From]),
?INFO_MSG("mod_stanza_ack a iq has been sent to: ~p", [To]),
?INFO_MSG("mod_stanza_ack a iq has been sent with the following packet:~n ~p", [Packet]),
{Packet, C2SState};
on_user_send_packet({#message{to = To, from = From} = Packet, C2SState}) ->
?INFO_MSG("mod_stanza_ack a message has been sent coming from: ~p", [From]),
?INFO_MSG("mod_stanza_ack a message has been sent to: ~p", [To]),
?INFO_MSG("mod_stanza_ack a message has been sent with the following packet:~n ~p", [Packet]),
{Packet, C2SState}.
depends(_Host, _Opts) ->
[].
mod_options(_Host) ->
[].
mod_doc() ->
#{desc =>
?T("This an example module.")}.
按照您详细的分步安装指南,我遇到了两个问题,我在这里描述了它们以及如何解决它们:
- 编译缺少头文件。
我复制mod_stanza_ack.erl到ejabberd-20.07/bin,然后运行这个命令:
$ ./erlc mod_stanza_ack.erl
mod_stanza_ack.erl:4: can't find include file "xmpp.hrl"
mod_stanza_ack.erl:5: can't find include file "logger.hrl"
mod_stanza_ack.erl:6: can't find include file "translate.hrl"
mod_stanza_ack.erl:12: undefined macro 'INFO_MSG/2'
mod_stanza_ack.erl:17: undefined macro 'INFO_MSG/2'
mod_stanza_ack.erl:22: undefined macro 'INFO_MSG/2'
mod_stanza_ack.erl:47: undefined macro 'T/1'
mod_stanza_ack.erl:8: function mod_doc/0 undefined
mod_stanza_ack.erl:8: function start/2 undefined
mod_stanza_ack.erl:8: function stop/1 undefined
mod_stanza_ack.erl:9: function on_user_send_packet/1 undefined
解决方法很简单:提供头文件的路径:
$ ./erlc -I ../lib/ejabberd-20.07/include/ -I ../lib/xmpp-1.4.9/include/ -I ../lib/fast_xml-1.1.43/include/ mod_stanza_ack.erl
这样文件编译正确。
- INFO_MSG 源代码中不会在 ejabberd 日志文件或“ejabberdctl live”控制台中生成日志消息。
这是因为我们没有告诉编译器使用 LAGER 库。解决方案非常简单:在模块编译中包含 -DLAGER。所以,这是完美的编译调用:
$ ./erlc -I ../lib/ejabberd-20.07/include/ -I ../lib/xmpp-1.4.9/include/ -I ../lib/fast_xml-1.1.43/include/ -DLAGER mod_stanza_ack.erl
现在,您将生成的 mod_stanza_ack.beam 与所有其他 ejabberd beam 文件一起复制,启用 ejabberd.yml 中的模块,然后重新启动 ejabberd,一切都会按预期工作