npm -v
node -v
asterisk -rvvvv
node.js 로 프로그램을 만들 디렉토리가 필요하다. 당장 만들자 !!
> mkdir helloAgi
그 다음, npm 초기화를 진행한다. 대부분의 node.js 모듈은 npm 초기화로 시작한다.
> cd helloAgi
> npm init -y
npm 명령어는 따로 정리해야 한다. 생각보다 기능과 명령어가 많다. npm을 간단히 기억하려면, 다른 똑똑한 사람들이 만든 node.js 모듈을 가져다 쓰기 쉽게 도와주는 의존성 관리 툴 정도로 생각하면 된다. 마음에 드는 모듈 쇼핑이 가능하다!!!
init 옵션은 package.json파일을 자동으로 생성해주며 그 파일에 프로퍼티 값을 추가하는데, -y 옵션은 전부 Yes로 묻지도 따지지도 않고 넣어준다는 뜻이다.
이제 VSCode 에서 해당 폴더를 open 해보자. 아래의 그림처럼 되어 있을 것이다.
npm 명령어로 ding-dong 모듈을 가지고 오려면 아래와 같이 명령어를 수행하면 된다.
> npm install ding-dong
VSCode 를 이용한다면, 터미널에서 명령어를 날려도 된다.
ding-dong 모듈이 설치 되었고, package.json 파일의 dependencies 에 ding-dong 0.1.7 이 추가 되었다.
VSCode의 왼쪽에서 새로운 파일을 추가하고, 그 파일 이름을 index.js 라고 한다.
아래의 소스를 작성 한다. 물론 npm ding-dong 에 가면 sample 소스는 존재 한다.
npm ding-dong 바로가기
const AGIServer = require('ding-dong');
const handler = (context) => {
context.onEvent('variables')
.then((vars) => {
return context.streamFile('hello-world');
})
.then((result) => {
return context.setVariable('RECOGNITION_RESULT', 'I\'m your father, Luc');
})
.then((result) => {
return context.end();
})
.catch((error) => {
context.end();
});
};
const agi = new AGIServer(handler, { debug: true });
agi.start(5000);
[dialplan]
exten => s,1,NoOp(dialplan start====>) ; log
same => n,Answer() ; answer
same => n,AGI(agi://127.0.0.1:5000) ; AGI 호출
same => n,Hangup() ; 전화 종료
npm ding-dong 예제 소스와 약간 다르지만 비슷한 기능을 수행한다. ES6 스타일을 따르도록 노력했다.
정말 짧은 소스지만 온전히 이해하기까지 수많은 삽질이 필요했다.
자, 여기까지 소스코드를 작성했다면 index.js 모듈을 실행하자.
> node index.js
콘솔에 아무것도 나타나지 않는다. 응????
자 그럼 5000번 port를 확인해 보자
netstat -an | grep 5000
좋다 !!! 5000번 port에 뭔가가 떠 있다. 성공이다.
Asterisk서버의 extentions.conf 파일에 위 dialplan을 추가한다.
Asterisk서버로 전화를 걸어 본다. 현재는 테스트를 위해 소프트폰으로 Zoiper5 를 사용하고 있다. 무료로 사용 가능하지만, 유료로도 사용하고 싶을 정도로 정말 조이퍼~~
전화를 걸면 "hello world" 라는 음성이 들리고 전화가 종료될 것이다.
위 AGI 흐름을 순서대로 표시하면 아래와 같다.
- 발신자가 전화를 건다. 착신번호는 1111.
- Asterisk는 dialplan 에 정의된 1111 이라는 exten을 찾아 아무일도 하지 않고 "dialplan start====>" 이라는 log를 남긴다.(NoOp() 실행)
- Answer() 를 수행한다. 즉, Asterisk 가 전화를 받았다.
- agi를 호출하여, dialplan에서 AGI서버로 제어를 넘기고 기다린다.
- AGI에서 "hello-world" 멘트 play를 Asterisk에게 요청한다.
- Asterisk는 발신자에게 "hello-world" 멘트를 play 한다.
- AGI에서 "RECOGNITION_RESULT"에 특정 값을 넣어 달라고 Asterisk에게 요청한다.
- AGI에서 end()를 요청한다. 제어는 다시 dialplan으로 돌아 왔다.
- dialplan에서 Hangup() 으로 전화를 종료한다.
만약 시나리오 DB 또는 API 서버가 별도로 있다면 아래와 같은 그림으로 서버 구성이 가능하다. 물론 Asterisk 로컬 서버에 AGI를 연결 하는 것도 가능하다.
-------> {"command":"STREAM FILE \"hello-world\"\"#\""}
<------- {"err":null,"result":{"code":200,"result":"0 endpos=11234"}}
<vars.....>
{
agi_network: 'yes',
agi_request: 'agi',
agi_channel: 'SIP/6003-00000004',
agi_language: 'en',
agi_type: 'SIP',
agi_uniqueid: '1593015578.8',
agi_version: '16.4.1',
agi_callerid: '2222',
agi_calleridname: 'handphone',
agi_callingpres: '0',
agi_callingani2: '0',
agi_callington: '0',
agi_callingtns: '0',
agi_dnid: '1111',
agi_rdnis: 'unknown',
agi_context: 'dialplan',
agi_extension: 's',
agi_priority: '3',
agi_enhanced: '0.0',
agi_accountcode: '',
agi_threadid: '140333349705472',
}
물론, 가능하다. 아래에 ding-dong에서 사용가능한 API 목록 링크를 추가 한다.
ding-dong API
다음 글에서는 좀 더 다양한 AGI 기능들을 ding-dong으로 구현해 보면서 이야기해볼 생각이다.