update
This commit is contained in:
		
							
								
								
									
										25
									
								
								server/src/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								server/src/app.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
import { App } from '@kevisual/router'
 | 
			
		||||
 | 
			
		||||
import { sendDefaultSipMessage } from './lib.ts';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const app = new App();
 | 
			
		||||
 | 
			
		||||
//  http://localhost:3001/api/router?path=floor
 | 
			
		||||
app.route({
 | 
			
		||||
  path: 'floor'
 | 
			
		||||
}).define(async (ctx) => {
 | 
			
		||||
  await sendDefaultSipMessage();
 | 
			
		||||
  ctx.body = 'SIP消息已发送';
 | 
			
		||||
}).addTo(app)
 | 
			
		||||
 | 
			
		||||
app.route({
 | 
			
		||||
  path: 'test'
 | 
			
		||||
}).define(async (ctx) => {
 | 
			
		||||
  ctx.body = 'SIP消息已发送';
 | 
			
		||||
}).addTo(app)
 | 
			
		||||
 | 
			
		||||
app.listen(3001, "::", () => {
 | 
			
		||||
  console.log('Server is running on http://localhost:3001');
 | 
			
		||||
})
 | 
			
		||||
// curl http://localhost:3001/api/router?path=test
 | 
			
		||||
							
								
								
									
										1
									
								
								server/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								server/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
import './app.ts'
 | 
			
		||||
							
								
								
									
										113
									
								
								server/src/lib.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								server/src/lib.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
interface SipMessageConfig {
 | 
			
		||||
  targetIp?: string;
 | 
			
		||||
  targetPort?: number;
 | 
			
		||||
  macLocalIp?: string;
 | 
			
		||||
  senderSip?: string;
 | 
			
		||||
  senderIp?: string;
 | 
			
		||||
  receiverSip?: string;
 | 
			
		||||
  receiverIp?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function sendSipMessage(config: SipMessageConfig = {}): Promise<void> {
 | 
			
		||||
  // 配置参数(使用默认值或传入的配置)
 | 
			
		||||
  const targetIp = config.targetIp || "192.168.3.3";    // 设备eth1的IP(转发入口)
 | 
			
		||||
  const targetPort = config.targetPort || 5060;           // 转发端口
 | 
			
		||||
  const macLocalIp = config.macLocalIp || "192.168.3.33"; // Mac的本地IP(与Via头部一致)
 | 
			
		||||
  const senderSip = config.senderSip || "3011302";       // 发送方SIP用户
 | 
			
		||||
  const senderIp = config.senderIp || "192.168.9.57";   // 设备eth0的IP(转发后源IP)
 | 
			
		||||
  const receiverSip = config.receiverSip || "3019901";   // 接收方SIP用户
 | 
			
		||||
  const receiverIp = config.receiverIp || "192.168.9.4"; // 目标IP
 | 
			
		||||
 | 
			
		||||
  // 生成唯一标识
 | 
			
		||||
  const callId = `${Math.floor(Date.now() / 1000)}`;  // 基于时间戳的Call-ID
 | 
			
		||||
  const tag = `${Math.floor(Date.now() % 1000000)}`;  // 随机tag
 | 
			
		||||
  const branch = `z9hG4bK${Math.floor(Date.now() / 1000)}`; // Via分支标识
 | 
			
		||||
 | 
			
		||||
  // XML消息体(业务数据)
 | 
			
		||||
  const xmlBody = `<?xml version="1.0" encoding="UTF-8" ?>
 | 
			
		||||
<params>
 | 
			
		||||
	<to>sip:${receiverSip}@${receiverIp}:5060</to>
 | 
			
		||||
	<elev>1</elev>
 | 
			
		||||
	<direct>2</direct>
 | 
			
		||||
	<floor>13</floor>
 | 
			
		||||
	<family>2</family>
 | 
			
		||||
	<app>elev</app>
 | 
			
		||||
	<event>appoint</event>
 | 
			
		||||
	<event_url>/elev/appoint</event_url>
 | 
			
		||||
</params>`;
 | 
			
		||||
 | 
			
		||||
  // 计算消息体长度(使用字符串长度 + utf8编码估算)
 | 
			
		||||
  const contentLength = new TextEncoder().encode(xmlBody).length;
 | 
			
		||||
 | 
			
		||||
  // 构造SIP MESSAGE请求(严格使用\r\n换行)
 | 
			
		||||
  const sipMessage = `MESSAGE sip:${receiverSip}@${receiverIp}:5060 SIP/2.0\r\n` +
 | 
			
		||||
    `Via: SIP/2.0/UDP ${macLocalIp}:5060;rport;branch=${branch}\r\n` +
 | 
			
		||||
    `From: <sip:${senderSip}@${senderIp}:5060>;tag=${tag}\r\n` +
 | 
			
		||||
    `To: <sip:${receiverSip}@${receiverIp}:5060>\r\n` +
 | 
			
		||||
    `Call-ID: ${callId}@${macLocalIp}\r\n` +
 | 
			
		||||
    `CSeq: 20 MESSAGE\r\n` +
 | 
			
		||||
    `Content-Type: text/plain\r\n` +
 | 
			
		||||
    `Max-Forwards: 70\r\n` +
 | 
			
		||||
    `User-Agent: DnakeVoip v1.0\r\n` +
 | 
			
		||||
    `Content-Length: ${contentLength}\r\n\r\n` +
 | 
			
		||||
    `${xmlBody}`;
 | 
			
		||||
 | 
			
		||||
  return new Promise((resolve, reject) => {
 | 
			
		||||
    try {
 | 
			
		||||
      console.log(`准备发送SIP消息到 ${targetIp}:${targetPort}`);
 | 
			
		||||
      console.log('\n发送的消息内容:');
 | 
			
		||||
      console.log(sipMessage);
 | 
			
		||||
      resolve();
 | 
			
		||||
    } catch (error: any) {
 | 
			
		||||
      console.log(`处理失败:${error.message}`);
 | 
			
		||||
      reject(error);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 使用默认配置的便捷函数
 | 
			
		||||
export function sendDefaultSipMessage(): Promise<void> {
 | 
			
		||||
  return sendSipMessage();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 使用Node.js原生dgram模块的实现(需要@types/node)
 | 
			
		||||
export function getSipMessageWithDgram(config: SipMessageConfig = {}): string {
 | 
			
		||||
  const targetIp = config.targetIp || "192.168.3.3";
 | 
			
		||||
  const macLocalIp = config.macLocalIp || "192.168.3.33";
 | 
			
		||||
  const senderSip = config.senderSip || "3011302";
 | 
			
		||||
  const senderIp = config.senderIp || "192.168.9.57";
 | 
			
		||||
  const receiverSip = config.receiverSip || "3019901";
 | 
			
		||||
  const receiverIp = config.receiverIp || "192.168.9.4";
 | 
			
		||||
 | 
			
		||||
  const callId = `${Math.floor(Date.now() / 1000)}`;
 | 
			
		||||
  const tag = `${Math.floor(Date.now() % 1000000)}`;
 | 
			
		||||
  const branch = `z9hG4bK${Math.floor(Date.now() / 1000)}`;
 | 
			
		||||
 | 
			
		||||
  const xmlBody = `<?xml version="1.0" encoding="UTF-8" ?>
 | 
			
		||||
<params>
 | 
			
		||||
	<to>sip:${receiverSip}@${receiverIp}:5060</to>
 | 
			
		||||
	<elev>1</elev>
 | 
			
		||||
	<direct>2</direct>
 | 
			
		||||
	<floor>13</floor>
 | 
			
		||||
	<family>2</family>
 | 
			
		||||
	<app>elev</app>
 | 
			
		||||
	<event>appoint</event>
 | 
			
		||||
	<event_url>/elev/appoint</event_url>
 | 
			
		||||
</params>`;
 | 
			
		||||
 | 
			
		||||
  const contentLength = new TextEncoder().encode(xmlBody).length;
 | 
			
		||||
 | 
			
		||||
  return `MESSAGE sip:${receiverSip}@${receiverIp}:5060 SIP/2.0\r\n` +
 | 
			
		||||
    `Via: SIP/2.0/UDP ${macLocalIp}:5060;rport;branch=${branch}\r\n` +
 | 
			
		||||
    `From: <sip:${senderSip}@${senderIp}:5060>;tag=${tag}\r\n` +
 | 
			
		||||
    `To: <sip:${receiverSip}@${receiverIp}:5060>\r\n` +
 | 
			
		||||
    `Call-ID: ${callId}@${macLocalIp}\r\n` +
 | 
			
		||||
    `CSeq: 20 MESSAGE\r\n` +
 | 
			
		||||
    `Content-Type: text/plain\r\n` +
 | 
			
		||||
    `Max-Forwards: 70\r\n` +
 | 
			
		||||
    `User-Agent: DnakeVoip v1.0\r\n` +
 | 
			
		||||
    `Content-Length: ${contentLength}\r\n\r\n` +
 | 
			
		||||
    `${xmlBody}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sendDefaultSipMessage().catch(console.error);
 | 
			
		||||
		Reference in New Issue
	
	Block a user