提交 c64c6842 authored 作者: Jonas Gauffin's avatar Jonas Gauffin

Completed EventWatcher, added ToString to most of the events (now showing…

Completed EventWatcher, added ToString to most of the events (now showing relevant info). Recoded EventParser to be thread safe. EventParser/EventSocket now queues up all incoming data and parses it as soon as possible (true async handling)

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk/scripts/contrib@8817 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 cd7b29e3
namespace EventWatcher
{
partial class ChannelWatcher
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.tv = new System.Windows.Forms.TreeView();
this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel();
this.tb = new System.Windows.Forms.RichTextBox();
this.toolStrip1.SuspendLayout();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.SuspendLayout();
//
// toolStrip1
//
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripLabel1});
this.toolStrip1.Location = new System.Drawing.Point(0, 0);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(961, 25);
this.toolStrip1.TabIndex = 3;
this.toolStrip1.Text = "toolStrip1";
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.Location = new System.Drawing.Point(0, 25);
this.splitContainer1.Name = "splitContainer1";
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.tb);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.tv);
this.splitContainer1.Size = new System.Drawing.Size(961, 622);
this.splitContainer1.SplitterDistance = 307;
this.splitContainer1.TabIndex = 4;
//
// tv
//
this.tv.Dock = System.Windows.Forms.DockStyle.Fill;
this.tv.FullRowSelect = true;
this.tv.Location = new System.Drawing.Point(0, 0);
this.tv.Name = "tv";
this.tv.ShowLines = false;
this.tv.ShowPlusMinus = false;
this.tv.ShowRootLines = false;
this.tv.Size = new System.Drawing.Size(961, 311);
this.tv.TabIndex = 2;
//
// toolStripLabel1
//
this.toolStripLabel1.Name = "toolStripLabel1";
this.toolStripLabel1.Size = new System.Drawing.Size(37, 22);
this.toolStripLabel1.Text = "Rensa";
this.toolStripLabel1.Click += new System.EventHandler(this.toolStripLabel1_Click);
//
// tb
//
this.tb.Dock = System.Windows.Forms.DockStyle.Fill;
this.tb.Location = new System.Drawing.Point(0, 0);
this.tb.Name = "tb";
this.tb.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.ForcedBoth;
this.tb.Size = new System.Drawing.Size(961, 307);
this.tb.TabIndex = 0;
this.tb.Text = "";
this.tb.WordWrap = false;
//
// ChannelWatcher
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(961, 647);
this.Controls.Add(this.splitContainer1);
this.Controls.Add(this.toolStrip1);
this.Name = "ChannelWatcher";
this.Text = "ChannelWatcher";
this.Load += new System.EventHandler(this.ChannelWatcher_Load);
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripLabel toolStripLabel1;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.TreeView tv;
private System.Windows.Forms.RichTextBox tb;
}
}
\ No newline at end of file
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using FreeSwitch.EventSocket;
namespace EventWatcher
{
public partial class ChannelWatcher : Form
{
private EventManager _mgr = new EventManager();
private Color _currentColor = 0;
StringBuilder sb = new StringBuilder();
public ChannelWatcher()
{
InitializeComponent();
}
private void ChannelWatcher_Load(object sender, EventArgs e)
{
_mgr.Start("localhost");
_mgr.Subscribe(Event.All);
_mgr.EventReceived += OnPreSwitchEvent;
ClearTb();
// AddText("bajs");
}
private void OnPreSwitchEvent(EventBase theEvent)
{
if (tv.InvokeRequired)
BeginInvoke((MethodInvoker)delegate { OnSwitchEvent(theEvent); });
else
OnSwitchEvent(theEvent);
}
private void ClearTb()
{
/*
{\rtf1\ansi\ansicpg1252\deff0\deflang1053
{\colortbl ;\red128\green0\blue0;\red0\green128\blue0;\red0\green0\blue255;\red0\green0\blue255;}
{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}
\viewkind4\uc1\pard\f0\fs17 Hello\cf1\b <\cf3\b0 (Wor"ld")\cf1\b >\cf0\b0 \par
}
*/
sb.Length = 0;
sb.Append(
@"{\rtf1\ansi\ansicpg1252\deff0\deflang1053"
+ @"{\colortbl ;\red0\green0\blue0;\red128\green0\blue0;\red0\green128\blue0;\red0\green0\blue255;\red0\green0\blue255;}"
+ @"{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}"
+ @"\viewkind4\uc1\pard\f0\fs20\par \par}");
tb.Rtf = sb.ToString();
}
public enum Color
{
None,
Black,
Red,
Green,
Blue
}
[DllImport("user32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWndLock);
private void AddText(string text)
{
text = text.Replace("\\", "\\\\").Replace("{", "\\{").Replace("}", "\\}");
string colored = string.Empty;
bool inQ = false;
bool bold = false;
foreach (char ch in text)
{
Color color = Color.None;
if (inQ)
{
if (ch == '"')
{
inQ = false;
color = Color.Black;
}
}
else if (char.IsLetter(ch))
color = Color.Black;
else if (Char.IsDigit(ch))
color = Color.Blue;
else if (ch == '"')
{
inQ = true;
color = Color.Green;
}
else
{
bold = true;
color = Color.Red;
}
if (color != Color.None)
SetColor(ref colored, color, bold);
if (ch == ')')
colored += ' ';
colored += ch;
if (ch == ')')
colored += ' ';
}
sb.Length = sb.Length - 5;
sb.AppendLine(colored);
sb.Append("\\par\\par}");
LockWindowUpdate(tb.Handle);
tb.Rtf = sb.ToString();
tb.SelectionStart = tb.Text.Length;
tb.ScrollToCaret();
LockWindowUpdate(IntPtr.Zero);
//ScrollToEnd(tb);
}
private void SetColor(ref string text, Color color, bool bold)
{
if (color != _currentColor)
{
text += "\\cf" + (int) color;
//if (bold)
// text += "\\b";
text += " ";
_currentColor = color;
}
}
private void OnSwitchEvent(EventBase theEvent)
{
AddText(theEvent.ToString());
ChannelEvent evt = theEvent as ChannelEvent;
if (evt == null)
return;
TreeNode node = tv.Nodes[evt.UniqueId];
if (node == null)
{
tv.Nodes.Add(evt.UniqueId, evt.ToString());
node = tv.Nodes[evt.UniqueId];
node.Tag = evt;
node.ToolTipText = evt.ToString().Replace(".", "\r\n");
}
node.Nodes.Add(new TreeNode(evt.ToString()));
}
private void toolStripLabel1_Click(object sender, EventArgs e)
{
tv.Nodes.Clear();
ClearTb();
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>
\ No newline at end of file
......@@ -40,6 +40,12 @@
<Compile Include="Call.cs" />
<Compile Include="CallManager.cs" />
<Compile Include="CallStateEvent.cs" />
<Compile Include="ChannelWatcher.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ChannelWatcher.Designer.cs">
<DependentUpon>ChannelWatcher.cs</DependentUpon>
</Compile>
<Compile Include="Extension.cs" />
<Compile Include="Form1.cs">
<SubType>Form</SubType>
......@@ -52,6 +58,10 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="ChannelWatcher.resx">
<SubType>Designer</SubType>
<DependentUpon>ChannelWatcher.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Form1.resx">
<SubType>Designer</SubType>
<DependentUpon>Form1.cs</DependentUpon>
......
......@@ -14,7 +14,7 @@ namespace EventWatcher
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Application.Run(new ChannelWatcher());
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
namespace FreeSwitch.EventSocket.Test
{
......@@ -10,18 +9,70 @@ namespace FreeSwitch.EventSocket.Test
{
static void Main(string[] args)
{
EventManager mgr = new EventManager();
/*EventManager mgr = new EventManager();
mgr.Subscribe(Events.GetChannelEvents());
mgr.Start("localhost");
Console.ReadLine();
*/
Program p = new Program();
p.Test();
string buffer = File.ReadAllText("..\\..\\..\\watcherRaw.log");
int bufLen = buffer.Length;
}
private int _counter;
private EventParser _parser;
Random _rand = new Random((int)DateTime.Now.Ticks);
public void Test()
{
_parser = new EventParser();
string text = File.ReadAllText("C:\\mymsgs.txt");
Thread[] threads = new Thread[5];
for (int i = 0; i < 5; ++i)
threads[i] = new Thread(FeedStream);
while (StreamFeeder(ref text)) ;
//Parse(text);
/*
Parse(File.ReadAllText("C:\\events1.txt"));
Parse(File.ReadAllText("C:\\events2.txt"));
Parse(File.ReadAllText("C:\\events3.txt"));
*/
}
public void FeedStream()
{
}
public bool StreamFeeder(ref string text)
{
int length;
if (text.Length < 5)
length = text.Length;
else
length = _rand.Next(text.Length / 2);
string myText = text.Substring(0, length);
Parse(myText);
text = text.Remove(0, length);
return text.Length > 0;
}
public void Parse(string text)
{
_parser.Append(text);
PlainEventMsg msg = _parser.ParseOne();
while (msg != null)
{
++_counter;
NameValueCollection pars = msg.ParseBody(true);
Console.WriteLine(pars["event-name"]);
msg = _parser.ParseOne();
}
EventParser ep = new EventParser(buffer);
//int cnt = 0;
EventSocket es = new EventSocket();
es.Setup();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class ChannelEvent : EventBase
......@@ -62,5 +58,12 @@ namespace FreeSwitch.EventSocket
return true;
}
public override string ToString()
{
return
"ChannelEvent(" + _uniqueId + " [" + _callDirection + "] " + _answerState +
", channelInfo{" + _channelInfo + "})";
}
}
}
......@@ -2,5 +2,9 @@ namespace FreeSwitch.EventSocket
{
public class EventChannelAnswer : EventChannelState
{
public override string ToString()
{
return "ChannelAnswer." + base.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventChannelApplication : EventChannelState
{
public override string ToString()
{
return "ChannelApplication." + base.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventChannelBridge : EventChannelState
{
public override string ToString()
{
return "ChannelBridge." + base.ToString();
}
}
}
......@@ -2,5 +2,9 @@ namespace FreeSwitch.EventSocket
{
public class EventChannelCreate : ChannelEvent
{
public override string ToString()
{
return "ChannelCreate." + base.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventChannelDestroy : EventChannelState
{
public override string ToString()
{
return "ChannelDestroy." + base.ToString();
}
}
}
......@@ -28,5 +28,10 @@ namespace FreeSwitch.EventSocket
return true;
}
public override string ToString()
{
return "EventChannelExecute(" + _appName + ", '" + _arguments + "')." + base.ToString();
}
}
}
......@@ -28,6 +28,11 @@ namespace FreeSwitch.EventSocket
return true;
}
public override string ToString()
{
return "ExecuteComplete(" + _appName + ", '" + _arguments + "')." + base.ToString();
}
}
}
......@@ -33,6 +33,10 @@ namespace FreeSwitch.EventSocket
return true;
}
public override string ToString()
{
return "ChannelHangup(" + _hangupCause + ")." + base.ToString();
}
}
public enum HangupCause
......
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventChannelOriginate : ChannelEvent
{
public override string ToString()
{
return "ChannelOriginate." + base.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventChannelOutgoing : EventChannelState
{
public override string ToString()
{
return "ChannelOutgoing." + base.ToString();
}
}
}
namespace FreeSwitch.EventSocket
{
public class EventChannelPark : EventChannelState
{
public override string ToString()
{
return "ChannelPark." + base.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventChannelProgress : EventChannelState
{
public override string ToString()
{
return "ChannelProgress" + base.ToString();
}
}
}
......@@ -2,8 +2,15 @@ namespace FreeSwitch.EventSocket
{
public class EventChannelState : ChannelEvent
{
private PartyInfo _caller = new PartyInfo();
private PartyInfo _originator = new PartyInfo();
private const string Yes = "yes";
private const string CallerTag = "caller-";
private const string OriginatorTag = "originator-";
private const string OriginateeTag = "originatee-";
private const string OtherLegTag = "other-leg-";
private const string ScreenBitTag = "screen-bit";
private PartyInfo _caller = PartyInfo.Empty;
private PartyInfo _originator = PartyInfo.Empty;
private PartyInfo _otherLeg = PartyInfo.Empty;
private bool _screenBit = false;
/// <summary>
......@@ -34,30 +41,58 @@ namespace FreeSwitch.EventSocket
set { _screenBit = value; }
}
/// <summary>
/// Other leg of call.
/// </summary>
public PartyInfo OtherLeg
{
get { return _otherLeg; }
set { _otherLeg = value; }
}
public override bool ParseCommand(string name, string value)
{
if (name == "screen-bit")
if (name == ScreenBitTag)
{
ScreenBit = value == "yes";
ScreenBit = value == Yes;
return true;
}
else if (name.Length > 11 && name.Substring(0, 11) == "originator-"
|| name.Length > 11 && name.Substring(0, 11) == "originatee-")
else if (name.Length > 11 && name.Substring(0, 11) == OriginatorTag
|| name.Length > 11 && name.Substring(0, 11) == OriginateeTag)
{
if (_originator == null)
if (_originator == PartyInfo.Empty)
_originator = new PartyInfo();
return _originator.Parse(name.Substring(11), value);
}
else if (name.Length > 7 && name.Substring(0, 7) == "caller-")
else if (name.Length > 7 && name.Substring(0, 7) == CallerTag)
{
if (_caller == null)
if (_caller == PartyInfo.Empty)
_caller = new PartyInfo();
return _caller.Parse(name.Substring(7), value);
}
else if (name.Length > 10 && name.Substring(0, 10) == OtherLegTag)
{
if (_otherLeg == PartyInfo.Empty)
_otherLeg = new PartyInfo();
return _otherLeg.Parse(name.Substring(10), value);
}
else
return base.ParseCommand(name, value);
}
public override string ToString()
{
string temp = "ChannelState(";
if (Caller != PartyInfo.Empty)
temp += " Caller{" + Caller + "}";
if (Originator != PartyInfo.Empty)
temp += " Originator{" + Originator + "}";
if (OtherLeg != PartyInfo.Empty)
temp += " OtherLeg{" + OtherLeg + "}";
return temp + ")." + base.ToString();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventChannelUnbridge : EventChannelState
{
public override string ToString()
{
return "ChannelUnbridge." + base.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventChannelUnpark : EventChannelState
{
public override string ToString()
{
return "ChannelUnpark." + base.ToString();
}
}
}
......@@ -2,5 +2,9 @@ namespace FreeSwitch.EventSocket
{
public class EventCodec : EventChannelState
{
public override string ToString()
{
return "Codec." + base.ToString();
}
}
}
......@@ -31,5 +31,10 @@ namespace FreeSwitch.EventSocket
return base.ParseCommand(name, value);
}
public override string ToString()
{
return "Dtmf(" + _digit + ")." + base.ToString();
}
}
}
......@@ -27,5 +27,10 @@ namespace FreeSwitch.EventSocket
return base.ParseCommand(name, value);
}
public override string ToString()
{
return "DtmfStatus." + base.ToString();
}
}
}
namespace FreeSwitch.EventSocket.ChannelEvents
{
public class EventSessionCrash : ChannelEvent
{
public override string ToString()
{
return "SessionCrash." + base.ToString();
}
}
}
......@@ -9,8 +9,10 @@ namespace FreeSwitch.EventSocket
SoftExecute, // Channel is in a passive transmit state
Execute, // Channel is executing it's dialplan
ExchangeMedia, // Channel is exchanging media
Park,
ConsumeMedia, // Channel is consuming media
Hibernate, // Channel is in a sleep state
Reset,
Hangup, // Channel is flagged for hangup and ready to end
Done, // Channel is ready to be destroyed and out of the state machine
Unknown
......@@ -21,9 +23,9 @@ namespace FreeSwitch.EventSocket
{
private ChannelState _state;
private int _stateNumber;
private string _profile;
private string _address;
private string _hostName;
private string _profile = string.Empty;
private string _address = string.Empty;
private string _hostName = string.Empty;
private string _protocol = string.Empty;
private string _readCodecName;
private int _readCodecRate;
......@@ -209,10 +211,12 @@ namespace FreeSwitch.EventSocket
case "CS_SOFT_EXECUTE": return ChannelState.SoftExecute;
case "CS_EXECUTE": return ChannelState.Execute;
case "CS_EXCHANGE_MEDIA": return ChannelState.ExchangeMedia;
case "CS_PARK": return ChannelState.Park;
case "CS_CONSUME_MEDIA": return ChannelState.ConsumeMedia;
case "CS_HIBERNATE": return ChannelState.Hibernate;
case "CS_HANGUP": return ChannelState.Hangup;
case "CS_DONE": return ChannelState.Done;
case "CS_RESET": return ChannelState.Reset;
default: return ChannelState.Unknown;
}
}
......@@ -221,5 +225,10 @@ namespace FreeSwitch.EventSocket
{
return "Unknown";
}
public override string ToString()
{
return _address + "@" + _hostName + ": " + _state;
}
}
}
......@@ -25,6 +25,7 @@ namespace FreeSwitch.EventSocket.Commands
private readonly IList<ChannelVariable> _variables = new List<ChannelVariable>();
private string _callerIdName = null;
private string _callerIdNumber = null;
private bool _varsAdded = false;
public Originate()
{}
......@@ -73,9 +74,13 @@ namespace FreeSwitch.EventSocket.Commands
{
get
{
_variables.Add(new ChannelVariable("origination_caller_id_name", CallerIdName ?? _caller.Extension));
if (!string.IsNullOrEmpty(_callerIdNumber))
_variables.Add(new ChannelVariable("origination_caller_id_number", _callerIdNumber));
if (!_varsAdded)
{
_variables.Add(new ChannelVariable("origination_caller_id_name", CallerIdName ?? _caller.Extension));
if (!string.IsNullOrEmpty(_callerIdNumber))
_variables.Add(new ChannelVariable("origination_caller_id_number", _callerIdNumber));
_varsAdded = true;
}
string variables = string.Empty;
foreach (ChannelVariable var in _variables)
......
......@@ -13,8 +13,8 @@ namespace FreeSwitch.EventSocket
{
private readonly EventSocket _socket = new EventSocket();
public event EventHandler EventReceived;
private EventsWriter _writer;
private TextWriter _myWriter;
private readonly EventsWriter _writer;
private readonly TextWriter _rawLog;
public string Password
{
set { _socket.Password = value; }
......@@ -22,13 +22,14 @@ namespace FreeSwitch.EventSocket
public EventManager()
{
_writer = MyWriter;
_myWriter = new StreamWriter(new FileStream("C:\\temp\\WatcherRow.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite));
_writer = RawWriter;
_rawLog = new StreamWriter(new FileStream("C:\\temp\\WatcherRaw.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite));
}
private void MyWriter(string text)
private void RawWriter(string text)
{
_myWriter.Write(text);
_rawLog.Write(text);
_rawLog.Flush();
}
......@@ -68,7 +69,7 @@ namespace FreeSwitch.EventSocket
protected void OnMessage(PlainEventMsg msg)
{
NameValueCollection parameters = msg.BodyToNameValue(true);
NameValueCollection parameters = msg.ParseBody(true);
string eventName = parameters["event-name"];
if (eventName == null)
return;
......
using EventSocketParser;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class EventParser
{
private PlainEventMsg _msg;
private readonly StringParser _parser;
private static readonly char[] BugWorkaround = {'C', 'o', 'n', 't', 'e', 'n', 't', '-'};
private readonly StringBuilder _text = new StringBuilder();
private readonly Queue<string> _piecesToAppend = new Queue<string>();
public EventParser(string text)
public string Text
{
_parser = new StringParser(text);
get { return _text.ToString(); }
}
public PlainEventMsg ParseMessage()
internal static void ParseHeaders(PlainEventMsg msg, string header)
{
_parser.ClearSavedPositions();
_msg = new PlainEventMsg();
// Save pos if we cant parse the whole message
_parser.SavePos();
ReadHeader();
if (!_msg.ValidateHeader())
{
_parser.RestorePos();
return null;
}
// skip empty line between body and header
_parser.ReadLine(true);
// we got no body.
if (_msg.ContentLength == -1)
return _msg;
// Unfortunately, \n\n doesnt appear after all content.
if (_msg.ContentLength != 0)
_msg.Body = _parser.Read(_msg.ContentLength);
else
_msg.Body = _parser.ReadToEmptyLine();
// assume that we have not got a complete packet yet.
if (!_msg.Validate())
{
_parser.RestorePos();
return null;
}
return _msg;
}
public bool ReadHeader()
{
// skip empty lines
while (!_parser.EOF && _parser.PeekWord(true, true) == string.Empty)
_parser.ReadLine(false);
if (_parser.EOF)
return false;
string name = _parser.Read(':', true);
StringParser parser = new StringParser(header);
string name = parser.Read(':', true);
while (name != string.Empty)
{
switch (name)
{
case "Content-Length":
_msg.ContentLength = int.Parse(_parser.ReadLine(true));
msg.ContentLength = int.Parse(parser.ReadLine(true));
break;
case "Content-Type":
_msg.ContentType = _parser.ReadLine(true);
msg.ContentType = parser.ReadLine(true);
break;
case "Reply-Text":
_msg.Body = _parser.ReadLine();
msg.Body = parser.ReadLine(true);
break;
}
// empty line == end of header
if (_parser.EOL)
if (parser.EOL)
break;
name = _parser.Read(':', true);
name = parser.Read(':', true);
}
}
/*
private int IsLineBreaks(int pos)
{
if (pos > 0 && Text[pos] == '\n' && Text[pos - 1] == '\n')
return 1;
if (pos > 3 && Text[pos] == '\n' && Text[pos - 1] == '\r'
&& Text[pos - 2] == '\n' && Text[pos - 3] == '\r')
return 3;
return 0;
}
*/
public void Clear()
{
lock (Text)
_text.Length = 0;
}
return _msg.ContentType != string.Empty;
private void IgnoreLineBreaks(ref int i)
{
while (i < Text.Length && (Text[i] == '\n' || Text[i] == '\r'))
++i;
}
public void Append(string value)
/// <summary>
///
/// </summary>
/// <returns></returns>
/// <exception cref="InvalidDataException">If parsing failed due to invalid format.</exception>
public PlainEventMsg ParseOne()
{
_parser.RemoveUsedContent();
_parser.Append(value);
// Move queue to text
lock (_piecesToAppend)
{
while (_piecesToAppend.Count > 0)
_text.Append(_piecesToAppend.Dequeue());
}
PlainEventMsg plainEvent;
lock (Text)
{
int i = 0;
// find complete header
bool found = false;
for (; i < Text.Length - 1; ++i)
{
if (Text[i] == '\n' && Text[i+1] == '\n')
{
found = true;
break;
}
}
if (!found)
return null;
// extract header
char[] chars = new char[i];
Text.CopyTo(0, chars, 0, i);
string headers = new string(chars);
#if DEBUG
Console.WriteLine("====================================");
Console.WriteLine("Headers: ");
Console.WriteLine(headers);
#endif
IgnoreLineBreaks(ref i);
plainEvent = new PlainEventMsg();
ParseHeaders(plainEvent, headers);
// we got a body?
if (plainEvent.ContentLength > 0)
{
// Start of Empty header bugfix
// FS seems to send a header with content-length without sending an actual body
// this will eat that kind of header.
if (Text.Length >= BugWorkaround.Length + i)
{
found = true;
for (int index = 0; index < BugWorkaround.Length; ++index)
{
if (Text[index + i] != BugWorkaround[index])
{
found = false;
break;
}
}
if (found)
{
Text.Remove(0, i);
Console.WriteLine("Removing empty content header.");
return null;
}
}
// end of bugfix.
// not enough data for body.
if (plainEvent.ContentLength + i > Text.Length)
return null;
// extract body
chars = new char[plainEvent.ContentLength];
Text.CopyTo(i, chars, 0, plainEvent.ContentLength);
plainEvent.Body = new string(chars);
// check for errors.
int pos = plainEvent.Body.IndexOf("\n\n");
if (pos < plainEvent.Body.Length - 2)
{
Console.WriteLine("Fucked up event");
Console.WriteLine("Header");
Console.WriteLine(headers);
Console.WriteLine("Body");
Console.WriteLine(plainEvent.Body);
Console.WriteLine("=========================== EVERYTHING in _text ==============================");
Console.WriteLine(Text);
throw new InvalidDataException("Fucked up event: " + Text);
}
#if DEBUG
Console.WriteLine("Body:");
Console.WriteLine(plainEvent.Body);
#endif
if (plainEvent.Body.Length < plainEvent.ContentLength)
throw new InvalidDataException("Body contents are too small!");
// Move forward to next header
i += plainEvent.ContentLength;
IgnoreLineBreaks(ref i);
}
// remove header( + body) from buffer
Text.Remove(0, i);
}
return plainEvent;
}
public void Clear()
public void Append(string text)
{
_parser.Clear();
lock (_piecesToAppend)
_piecesToAppend.Enqueue(text);
}
}
}
\ No newline at end of file
......@@ -24,18 +24,30 @@ namespace FreeSwitch.EventSocket
private bool _autoConnect = true;
private Events _events;
private string _hostName;
private readonly EventParser _parser = new EventParser(string.Empty);
private readonly EventParser _parser = new EventParser();
public event DataHandler DataReceived;
private string _password = "ClueCon";
private int _port = 8021;
private object _lockobj = new object();
private readonly object _lockobj = new object();
private readonly byte[] _readBuffer = new byte[8192];
private string _temp = string.Empty;
private Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private Socket _socket;
private NetworkStream _stream;
private Timer _timer;
private bool _authed = false;
const int RetryTimeout = 5000;
private bool _parsing = false;
public EventSocket()
{
CreateSocket();
}
private void CreateSocket()
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.NoDelay = true;
_socket.ReceiveBufferSize = 65535;
}
public string Password
{
......@@ -112,15 +124,18 @@ namespace FreeSwitch.EventSocket
private void OnReadCompleted(IAsyncResult ar)
{
int bytesRead;
string inbuffer;
try
{
bytesRead = _stream.EndRead(ar);
int bytesRead = _stream.EndRead(ar);
if (bytesRead == 0)
{
HandleDisconnect();
return;
}
inbuffer = Encoding.ASCII.GetString(_readBuffer, 0, bytesRead);
_parser.Append(inbuffer);
BeginRead();
}
catch (IOException)
{
......@@ -129,14 +144,22 @@ namespace FreeSwitch.EventSocket
return;
}
string text = Encoding.ASCII.GetString(_readBuffer, 0, bytesRead);
if (DataReceived != null)
DataReceived(text);
_temp += text;
_parser.Append(text);
ParseMessages();
DataReceived(inbuffer);
_stream.BeginRead(_readBuffer, 0, _readBuffer.Length, OnReadCompleted, null);
try
{
ParseMessages();
}
catch (InvalidDataException)
{
HandleDisconnect();
}
catch (ArgumentException)
{
Console.WriteLine(_parser.Text);
HandleDisconnect();
}
}
/// <summary>
......@@ -176,39 +199,56 @@ namespace FreeSwitch.EventSocket
_stream.Write(bytes, 0, bytes.Length);
}
static readonly object locker = new object();
private void ParseMessages()
{
PlainEventMsg msg = _parser.ParseMessage();
while (msg != null)
lock (locker)
{
if (msg.ContentType == "auth/request")
{
AuthCommand cmd = new AuthCommand(_password);
cmd.ReplyReceived += OnAuthed;
_commands.Enqueue(cmd);
Write(cmd + "\n\n");
}
else if (msg.ContentType == "command/reply"
|| msg.ContentType == "api/response")
if (_parsing)
return;
_parsing = true;
}
try
{
PlainEventMsg msg = _parser.ParseOne();
while (msg != null)
{
if (_commands.Count > 0)
if (msg.ContentType == "auth/request")
{
CmdBase cmd = _commands.Dequeue();
cmd.HandleReply(cmd.CreateReply(msg.Body));
AuthCommand cmd = new AuthCommand(_password);
cmd.ReplyReceived += OnAuthed;
_commands.Enqueue(cmd);
Write(cmd + "\n\n");
}
else if (msg.ContentType == "command/reply"
|| msg.ContentType == "api/response")
{
if (_commands.Count > 0)
{
CmdBase cmd = _commands.Dequeue();
cmd.HandleReply(cmd.CreateReply(msg.Body.Trim()));
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Got command reply or api response, but no actual command/api: " + msg.Body);
Console.ForegroundColor = ConsoleColor.Gray;
}
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Got command reply or api response, but no actual command/api: " + msg.Body);
Console.ForegroundColor = ConsoleColor.Gray;
if (MessageReceived != null)
MessageReceived(msg);
}
}
else
{
if (MessageReceived != null)
MessageReceived(msg);
}
msg = _parser.ParseMessage();
msg = _parser.ParseOne();
}
}
finally
{
lock (locker)
_parsing = false;
}
}
......@@ -223,7 +263,7 @@ namespace FreeSwitch.EventSocket
_parser.Clear();
_authed = false;
_socket.Close();
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
CreateSocket();
if (_stream != null)
{
_stream.Dispose();
......
......@@ -155,5 +155,10 @@ namespace FreeSwitch.EventSocket
}
return true;
}
public override string ToString()
{
return "Base(" + m_name + ")";
}
}
}
\ No newline at end of file
......@@ -43,10 +43,12 @@
<Compile Include="ChannelEvents\EventChannelBridge.cs" />
<Compile Include="ChannelEvents\ChannelEvent.cs" />
<Compile Include="ChannelEvents\EventChannelAnswer.cs" />
<Compile Include="ChannelEvents\EventChannelPark.cs" />
<Compile Include="ChannelEvents\EventChannelProgress.cs" />
<Compile Include="ChannelEvents\EventChannelUnbridge.cs" />
<Compile Include="ChannelEvents\EventChannelUnpark.cs" />
<Compile Include="ChannelEvents\EventCodec.cs" />
<Compile Include="ChannelEvents\EventSessionCrash.cs" />
<Compile Include="ChannelInfo.cs" />
<Compile Include="Commands\AnyCommand.cs">
</Compile>
......
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
public class PartyInfo
{
private string m_userName = string.Empty;
public static PartyInfo Empty = new PartyInfo();
private string _userName = string.Empty;
private string m_dialplan = string.Empty;
private string m_callerIdName = string.Empty;
private string m_callerIdNumber = string.Empty;
......@@ -14,14 +11,14 @@ namespace FreeSwitch.EventSocket
private string m_uniqueId = string.Empty;
private string m_source = string.Empty;
private string m_context = string.Empty;
private string m_channelName = string.Empty;
private string _channelName = string.Empty;
private bool m_screenBit;
private bool m_privacyHideName;
private bool m_privacyHideNumber;
public PartyInfo()
{
m_userName = string.Empty;
_userName = string.Empty;
m_dialplan = string.Empty;
m_callerIdName = string.Empty;
}
......@@ -70,8 +67,8 @@ namespace FreeSwitch.EventSocket
public string ChannelName
{
get { return m_channelName; }
set { m_channelName = value; }
get { return _channelName; }
set { _channelName = value; }
}
public bool ScreenBit
......@@ -94,8 +91,8 @@ namespace FreeSwitch.EventSocket
public string UserName
{
get { return m_userName; }
set { m_userName = value; }
get { return _userName; }
set { _userName = value; }
}
public bool Parse(string name, string value)
......@@ -103,7 +100,7 @@ namespace FreeSwitch.EventSocket
switch (name)
{
case "username":
m_userName = value;
_userName = value;
break;
case "dialplan":
Dialplan = value;
......@@ -146,5 +143,11 @@ namespace FreeSwitch.EventSocket
}
public override string ToString()
{
return _channelName + "(" + CallerIdName + "/" + CallerIdNumber + ") id: "+UniqueId+", destination: " + DestinationNumber;
}
}
}
using System;
using System.Collections.Specialized;
using EventSocketParser;
namespace FreeSwitch.EventSocket
{
......@@ -50,7 +49,7 @@ namespace FreeSwitch.EventSocket
}
public NameValueCollection BodyToNameValue(bool urlDecodeValues)
public NameValueCollection ParseBody(bool urlDecodeValues)
{
NameValueCollection items = new NameValueCollection();
StringParser parser = new StringParser(_body);
......@@ -64,7 +63,7 @@ namespace FreeSwitch.EventSocket
{
items.Add(name.ToLower(), Uri.UnescapeDataString(value));
}
catch (UriFormatException)
catch (UriFormatException)
{
// add the value unformatted
items.Add(name.ToLower(), value);
......@@ -77,4 +76,4 @@ namespace FreeSwitch.EventSocket
return items;
}
}
}
}
\ No newline at end of file
......@@ -10,7 +10,7 @@ namespace FreeSwitch.EventSocket
//private string _expires; //not "presencein/register", "presenceout/register"
private string _eventType = string.Empty;
private string _login = string.Empty;
private EventChannelState _channelState;
private EventChannelState _channelState = new EventChannelState();
public string Login
{
......@@ -71,6 +71,7 @@ namespace FreeSwitch.EventSocket
* */
public override bool ParseCommand(string name, string value)
{
bool res = _channelState.ParseCommand(name, value);
switch (name)
{
case "status":
......@@ -87,6 +88,7 @@ namespace FreeSwitch.EventSocket
break;
default:
if (name.Length > 7 && name.Substring(0, 7) == "caller-")
{
if (Caller == null)
......@@ -98,15 +100,16 @@ namespace FreeSwitch.EventSocket
if (base.ParseCommand(name, value))
return true;
else
{
if (_channelState == null)
_channelState = new EventChannelState();
return _channelState.ParseCommand(name, value);
}
return res;
}
}
return true;
}
public override string ToString()
{
return "Presence(" + _login + ", " + _status + ")." + _channelState + "." + base.ToString();
}
}
}
\ No newline at end of file
......@@ -2,5 +2,9 @@ namespace FreeSwitch.EventSocket
{
public class EventPresenceIn : EventPresence
{
public override string ToString()
{
return "PresenceIn." + base.ToString();
}
}
}
......@@ -2,7 +2,11 @@ namespace FreeSwitch.EventSocket
{
public class EventPresenceOut : EventPresence
{
public override string ToString()
{
return "PresenceOut." + base.ToString();
}
}
}
......@@ -6,5 +6,11 @@ namespace FreeSwitch.EventSocket.SipEvents
{
class EventPresenceProbe : EventPresence
{
public override string ToString()
{
return "PresenceProbe." + base.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSwitch.EventSocket
{
class EventRoster : SipEvent
......
......@@ -59,5 +59,10 @@ namespace FreeSwitch.EventSocket
return true;
}
public override string ToString()
{
return "SofiaExpire(" + _userName + "@" + _domain + ")." + base.ToString();
}
}
}
......@@ -88,5 +88,12 @@ contact: %22Jonas%20Gauffin%22%20%3Csip%3Ajonas%40192.168.1.101%3A5060%3E
}
return true;
}
public override string ToString()
{
return "SofiaRegister(" + _user + "@" + _domain + ", " + _expires + ")." + base.ToString();
}
}
}
\ No newline at end of file
......@@ -35,5 +35,10 @@ namespace FreeSwitch.EventSocket
}
return true;
}
public override string ToString()
{
return "Sip(" + _from + ")." + base.ToString();
}
}
}
\ No newline at end of file
using System.Collections.Generic;
namespace EventSocketParser
namespace FreeSwitch.EventSocket
{
internal class StringParser
{
......@@ -44,12 +44,8 @@ namespace EventSocketParser
public void RestorePos()
{
_pos = _savedPositions.Pop();
}
public void RemoveSavedPos()
{
_savedPositions.Pop();
if (_savedPositions.Count > 0)
_pos = _savedPositions.Pop();
}
public void ClearSavedPositions()
......@@ -59,17 +55,19 @@ namespace EventSocketParser
private bool IsEOF(int pos)
{
return pos >= _text.Length - 1;
return pos >= _text.Length;
}
public bool IsEmptyLine(bool skipWhitespaces)
{
if (EOF)
return false;
else if (_pos == _text.Length - 1)
else if (_pos < _text.Length - 1)
return _text[_pos] == '\n';
else
else if (_pos < _text.Length - 2)
return _text[_pos] == '\r' && _text[_pos + 1] == '\n';
return false;
}
public string PeekWord(bool skipWS, bool stopAtEOL)
......@@ -126,10 +124,10 @@ namespace EventSocketParser
int endpos = _pos;
_pos = pos;
// Move to after new line chars
if (_text[_pos] == '\r')
_pos += 2;
else
// Move to after new line chars
if (!EOF && _text[_pos] == '\r')
++_pos;
if (!EOF && _text[_pos] == '\n')
++_pos;
// .. and the result is line without whitespaces at the end and without new line chars.
......@@ -196,6 +194,9 @@ namespace EventSocketParser
private int TrimEnd()
{
if (EOF)
return _pos;
int pos = _pos;
while (IsWS(_text[pos]))
--pos;
......@@ -216,7 +217,9 @@ namespace EventSocketParser
private bool IsEOL()
{
if (_text[_pos] == '\r' && _text[_pos + 1] == '\n')
if (EOF)
return true;
if (_text[_pos] == '\r')
return true;
else if (_text[_pos] == '\n')
return true;
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论