Код:
// обработать запрос от провайдера IP-телефонии
async function VoipParseWebhookRequest(request: FetchRequest): Promise<VoipWebhookParseResult> {
try {
if (typeof request.body !== 'string') {
throw new Error('Expected request body to be string')
}
let event: VoipWebhookRequest | undefined;
let callRecord: VoipCallRecord | undefined;
let response: HttpResponse | undefined;
const reqAny : WebhookRequest = JSON.parse(request.body);
await System.cache.setItem("testapi", `VoipParseWebhookRequest ${request.body}`, 300000);
if (reqAny.endpoint === 'notify') {
const req = <WebhookRequest>JSON.parse(request.body);
const dstPhone = req.data.user ?? '';
await System.cache.setItem("testapi", `VoipParseWebhookRequest звонок отвечен notify ${JSON.stringify(req)}`, 300000);
event = {
event: VoipWebhookEvent.NotifyAnswer,
direction: VoipCallDirection.In,
dstPhone: dstPhone,
srcPhone: req.data.source,
disposition: VoipCallDisposition.Answered,
}
response = new HttpResponse()
.status(200)
.content(JSON.stringify({
code: 200,
reason: 'OK'
}))
return {
event: event,
callRecord: callRecord,
response: response,
};
}
else {
const req = <WebhookRequest>JSON.parse(request.body);
const dstPhone = req.data.user ?? '';
switch (req.method) {
// пришел входящий звонок (в это время у менеджера должен начать звонить телефон)
case "POST": {
await System.cache.setItem("testapi", `VoipParseWebhookRequest POST пришел звонок call ${JSON.stringify(req)}`, 300000);
event = {
event: VoipWebhookEvent.NotifyStart,
direction: VoipCallDirection.In,
dstPhone: dstPhone,
srcPhone: req.data.source,
disposition: VoipCallDisposition.Unknown,
}
response = new HttpResponse()
.status(200)
.content(JSON.stringify({
code: 200,
reason: 'OK'
}))
} break;
// уведомление о завершении вызова
case "PUT": {
if (req.data.callRecord) {
await System.cache.setItem("testapi", `завершен звонок call ${JSON.stringify(req)}`, 300000);
event = {
event: VoipWebhookEvent.NotifyEnd,
direction: VoipCallDirection.In,
dstPhone: dstPhone,
srcPhone: req.data.source,
disposition: VoipCallDisposition.Answered,
}
// после успешного звонка в CRM отправляется запрос с данными о звонке и ссылкой на запись разговора.
// команда может быть использована для сохранения в данных ваших клиентов истории и записей входящих и исходящих звонков.
const cmd = req.data;
callRecord = {
srcPhone: cmd.source,
dstPhone: dstPhone,
direction: VoipCallDirection.In,
duration: cmd.durationSeconds,
// данные из этого поля будут доступны в функции VoipGetCallLink
call: <RTUCallData>{
link: cmd.callRecord ? (cmd.callRecord).substring(0, (cmd.callRecord).indexOf("&")) : "",
id: cmd.protocolConfId,
},
disposition: VoipCallDisposition.Answered,
}
}
else {
await System.cache.setItem("testapi", `пропущен звонок call ${JSON.stringify(req)} ${dstPhone}`, 300000);
event = {
event: VoipWebhookEvent.NotifyEnd,
direction: VoipCallDirection.In,
dstPhone: dstPhone,
srcPhone: req.data.source,
disposition: VoipCallDisposition.Cancel,
}
// после успешного звонка в CRM отправляется запрос с данными о звонке и ссылкой на запись разговора.
// команда может быть использована для сохранения в данных ваших клиентов истории и записей входящих и исходящих звонков.
const cmd = req.data;
callRecord = {
srcPhone: cmd.source,
dstPhone: dstPhone,
direction: VoipCallDirection.In,
duration: cmd.durationSeconds,
// данные из этого поля будут доступны в функции VoipGetCallLink
call: <RTUCallData>{
link: "",
id: cmd.protocolConfId,
},
disposition: VoipCallDisposition.Cancel,
}
}
response = new HttpResponse()
.status(200)
.content(JSON.stringify({
code: 200,
reason: 'OK'
}))
} break;
default: throw new Error(`Unknown method type "${req.method}"`)
}
return {
event: event,
callRecord: callRecord,
response: response,
};
}
} catch (e) {
return {
response: new HttpResponse()
.status(400)
.content(JSON.stringify({
error: e.message ?? 'internal error',
}))
};
}
}
Таким образом, можно реализовать основные функции телефонии для взаимодействия с IP-телефонией