Pull to refresh

Comments 9

Первый — регистрация статуса пира держится какое то время после обрыва, и вполне возможна ситуация, когда пир кратковременно зарегистрируется и отвалится, а система «отправит» в течение минуты ему сообщение, и будет считать его доставленным. Выкрутится можно, использовав не Application в call-файле, а передачу данных в контекст с проверкой статуса переменной ${MESSAGE_SEND_STATUS}. Наверное, возможно будет использовать имеющийся контекст, задав переменные через Set в call-файле.

Наверное будет как-то так.

${MESSAGE_SEND_STATUS} подтверждает только отправку. https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+Application_MessageSend

Получаем статус пира и uri (Status и RegContact):
Action: SIPshowpeer
Peer: 3030

Response: Success
Channeltype: SIP
ObjectName: 3030
ChanObjectType: peer
Codecs: (ulaw|alaw|gsm|h263)
Status: OK (19 ms)
SIP-Useragent: Yealink SIP-T27P 45.80.0.60
Reg-Contact: sip:3030@192.168.100.101:5060
QualifyFreq: 60000 ms
SIP-Use-Reason-Header: N
Description: 

Можно перед этим отправить qualify запрос. Чтобы быть уверенным в статусе.

Отправляем сообщение.
action: messagesend
to: sip:3030@192.168.100.101:5060
from: sip:3030@192.168.100.101:5060
body: abra cadabra

Response: Success
Message: Message successfully sent


https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+ManagerAction_MessageSend

Статус доставки не отдается. Проверяется только отправка. Как собственно и приложение MessageSend, которое вы используете в плане набора. Либо делайте проверку статуса девайса в диалплане.
Использовать mysql_connect в 2017, как-то не актуально. Почему не PDO?
Привычка, лет 15 пишу так. Даст ли pdo прирост в скорости и насколько примерно, если да?

Дело не в скорости. Эта функция рано или поздно перестанет работать при обновлении или переносе кода на новые серера. Она обьявлена как deprecated 5.5.0 и убрана в php 7.0.0

я понял, займусь вопросом, спасибо!
Спасибо, поразбираюсь.
${MESSAGE_SEND_STATUS} достаточен, чтобы быть уверенным, что пакет попал на нужный адрес и пришло подтверждение, по моим тестам.
Если резко потерять клиента и тут же попытаться отправить сообщение, статус будет неудачный, хотя в пирах он ещё висит как ОК.
${MESSAGE_SEND_STATUS} достаточен, чтобы быть уверенным, что пакет попал на нужный адрес и пришло подтверждение, по моим тестам.

Я не пробовал из плана набора. Но попробуйте отправить на несуществующий пир. По исходникам я не вижу откуда взятся разнице в работе AMI action (action_messagesend) и приложения (ast_msg_send).
Возможно, что в моих тестах я не так указывал uri, но не думаю…

main/message.c
static int action_messagesend(struct mansession *s, const struct message *m)
{
	const char *to = ast_strdupa(astman_get_header(m, "To"));
	const char *from = astman_get_header(m, "From");
	const char *body = astman_get_header(m, "Body");
	const char *base64body = astman_get_header(m, "Base64Body");
	char base64decoded[1301] = { 0, };
	char *tech_name = NULL;
	struct ast_variable *vars = NULL;
	struct ast_variable *data = NULL;
	const struct ast_msg_tech *msg_tech;
	struct ast_msg *msg;
	int res = -1;

	if (ast_strlen_zero(to)) {
		astman_send_error(s, m, "No 'To' address specified.");
		return 0;
	}

	if (!ast_strlen_zero(base64body)) {
		ast_base64decode((unsigned char *) base64decoded, base64body, sizeof(base64decoded) - 1);
		body = base64decoded;
	}

	tech_name = ast_strdupa(to);
	tech_name = strsep(&tech_name, ":");

	ast_rwlock_rdlock(&msg_techs_lock);
	msg_tech = msg_find_by_tech_name(tech_name);
	if (!msg_tech) {
		ast_rwlock_unlock(&msg_techs_lock);
		astman_send_error(s, m, "Message technology not found.");
		return 0;
	}

	if (!(msg = ast_msg_alloc())) {
		ast_rwlock_unlock(&msg_techs_lock);
		astman_send_error(s, m, "Internal failure\n");
		return 0;
	}

	data = astman_get_variables_order(m, ORDER_NATURAL);
	for (vars = data; vars; vars = vars->next) {
		ast_msg_set_var_outbound(msg, vars->name, vars->value);
	}

	ast_msg_set_body(msg, "%s", body);

	res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));

	ast_rwlock_unlock(&msg_techs_lock);

	ast_variables_destroy(vars);
	ao2_ref(msg, -1);

	if (res) {
		astman_send_error(s, m, "Message failed to send.");
	} else {
		astman_send_ack(s, m, "Message successfully sent");
	}
	return 0;
}

int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
{
	char *tech_name = NULL;
	const struct ast_msg_tech *msg_tech;
	int res = -1;

	if (ast_strlen_zero(to)) {
		ao2_ref(msg, -1);
		return -1;
	}

	tech_name = ast_strdupa(to);
	tech_name = strsep(&tech_name, ":");

	ast_rwlock_rdlock(&msg_techs_lock);
	msg_tech = msg_find_by_tech_name(tech_name);

	if (!msg_tech) {
		ast_log(LOG_ERROR, "Unknown message tech: %s\n", tech_name);
		ast_rwlock_unlock(&msg_techs_lock);
		return -1;
	}

	res = msg_tech->msg_send(msg, S_OR(to, ""), S_OR(from, ""));

	ast_rwlock_unlock(&msg_techs_lock);

	ao2_ref(msg, -1);

	return res;
}



Если резко потерять клиента и тут же попытаться отправить сообщение, статус будет неудачный, хотя в пирах он ещё висит как ОК.

Отошлите qualify запрос. Если пир отвалился, то после запроса статус обновится. Но поскольку запрос асинхронный нужно будет сделать задержку.
https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+ManagerAction_SIPqualifypeer
Будет время — попробую, конечно. Надо бы уже довести до ума решение.
Код приложения.
MessageSend
/*!
 * \internal
 * \brief MessageSend() application
 */
static int msg_send_exec(struct ast_channel *chan, const char *data)
{
	struct ast_datastore *ds;
	struct ast_msg *msg;
	char *tech_name;
	const struct ast_msg_tech *msg_tech;
	char *parse;
	int res = -1;
	AST_DECLARE_APP_ARGS(args,
		AST_APP_ARG(to);
		AST_APP_ARG(from);
	);

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "An argument is required to MessageSend()\n");
		pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
		return 0;
	}

	parse = ast_strdupa(data);
	AST_STANDARD_APP_ARGS(args, parse);

	if (ast_strlen_zero(args.to)) {
		ast_log(LOG_WARNING, "A 'to' URI is required for MessageSend()\n");
		pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_URI");
		return 0;
	}

	ast_channel_lock(chan);

	if (!(ds = ast_channel_datastore_find(chan, &msg_datastore, NULL))) {
		ast_channel_unlock(chan);
		ast_log(LOG_WARNING, "No message data found on channel to send.\n");
		pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "FAILURE");
		return 0;
	}

	msg = ds->data;
	ao2_ref(msg, +1);
	ast_channel_unlock(chan);

	tech_name = ast_strdupa(args.to);
	tech_name = strsep(&tech_name, ":");

	ast_rwlock_rdlock(&msg_techs_lock);
	msg_tech = msg_find_by_tech_name(tech_name);

	if (!msg_tech) {
		ast_log(LOG_WARNING, "No message technology '%s' found.\n", tech_name);
		pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", "INVALID_PROTOCOL");
		goto exit_cleanup;
	}

	/*
	 * The message lock is held here to safely allow the technology
	 * implementation to access the message fields without worrying
	 * that they could change.
	 */
	ao2_lock(msg);
	res = msg_tech->msg_send(msg, S_OR(args.to, ""), S_OR(args.from, ""));
	ao2_unlock(msg);

	pbx_builtin_setvar_helper(chan, "MESSAGE_SEND_STATUS", res ? "FAILURE" : "SUCCESS");

exit_cleanup:
	ast_rwlock_unlock(&msg_techs_lock);
	ao2_ref(msg, -1);

	return 0;
}

Sign up to leave a comment.

Articles