先发图:
前几日刚刚公布了Joymsg的源码,许多朋友进行了回复,原文地址:http://www.cnblogs.com/loning/archive/2008/06/12/1218381.html
有些朋友说看不懂,也许扩展的确无从下手,没有任何文档,也没多少注释...昨天晚上正好有时间,匆匆写了一个MSN的数据源,使用Dotmsn.
首先,创建一个类库的项目.Loning.Joymsg.DotmsnDataSource,
然后引用项目Loning.Joymsg.Interface.删除程序自动创建的class1.cs,建立DotmsnDataSource.cs.
由于该类为一数据源,因此继承接口IDataSource.
因为整个解决方案我都是用的log4net作日志,引用了Log4net.dll.
关于Dotmsn的东西就不详细说了,网上有许多的例子.
下面具体说一下接口IDataSource.
using System.Collections.Generic;
using System.Text;
namespace Loning.Joymsg.Interface
{
public interface IDataSource
{
/**//// <summary>
/// 发送消息
/// </summary>
/// <param name="requester">接受者</param>
/// <param name="message">消息内容</param>
void SendMessage(object requester, string message);
/**//// <summary>
/// 数据源开始工作
/// </summary>
void Work();
/**//// <summary>
/// 数据源停止工作
/// </summary>
void Stop();
/**//// <summary>
/// 消息接收时该事件被触发
/// </summary>
event EventHandler<MessageEventArgs> MessageReceived;
/**//// <summary>
/// 用户状态改变时该事件被触发
/// </summary>
event EventHandler<FriendStatusChangedEventArgs> FriendStatusChanged;
}
}
下面是MessageEventArgs的代码
using System.Collections.Generic;
using System.Text;
namespace Loning.Joymsg.Interface
{
public class MessageEventArgs:EventArgs
{
/**//// <summary>
/// 请求者信息
/// </summary>
public object Requester { get; private set; }
/**//// <summary>
/// 请求者发送的消息
/// </summary>
public string Message { get; private set; }
/**//// <summary>
///
/// </summary>
/// <param name="requester">请求者信息</param>
/// <param name="message">请求者发送的消息</param>
public MessageEventArgs(object requester,string message)
{
Requester = requester;
Message = message;
}
}
}
在DotmsnDataSource中,Work()方法主要实现MSN的登录,而Stop()就是MSN的注销.这些都很容易理解.
我们先抛开好友状态改变的事件.(因为我在实现这个事件的时候遇到点问题,现在也没有解决)
机器人一般是受到消息后进行回复.Dotmsn与LumaQQ.net有所不同,Dotmsn为每一个对话建立了一个Conversation.而普通的聊天(PC上的MSN对MSN),接受消息需要订阅Conversation.Switchboard.TextMessageReceived这个事件,回复时的代码如下:
{
log.DebugFormat("收到{0}的消息:{1}", e.Sender.Name, e.Message.Text);
SBMessageHandler handler = (SBMessageHandler)sender;
handler.SendTextMessage(new TextMessage("something"));
}
因为MessageEventArgs中定义的Requester只是单纯的传递给Processor,然后再由Processor返回给DataSource,因此定义为Object的Requester属性可以传入任意的对象.于是在这个数据源中,干脆直接传入SBMessageHandler这个对象,然后在SendMessage中转型后直接调用其SendTextMessage方法就可以了.
具体代码实现如下:
{
SBMessageHandler handler = (SBMessageHandler)requester;
SendMessage(handler, message);
}
private void SendMessage(SBMessageHandler handler, string message)
{
string[] s = message.Split(new string[]{"\r\n"},StringSplitOptions.None);
StringBuilder sb = new StringBuilder();
int i=0;
while (i<=s.Length-1)
{
while (sb.Length < 400 && i <= s.Length - 1)
{
sb.AppendLine(s[i++]);
}
handler.SendTextMessage(new TextMessage(sb.ToString()));
sb.Remove(0, sb.Length);
}
if(sb.Length>0)
handler.SendTextMessage(new TextMessage(sb.ToString()));
}
void Switchboard_TextMessageReceived( object sender, TextMessageEventArgs e)
{
log.DebugFormat("收到{0}的消息:{1}", e.Sender.Name, e.Message.Text);
OnMessageReceived(new MessageEventArgs(sender, e.Message.Text));
}
这个方法是为了将Message分条发送出去,因为MSN貌似不支持长消息.
整个流程很简单,就是Dotmsn收到消息触发了事件,然后再由DotmsnDataSource触发它的MessageReceived事件,ProcessorManager订阅了这个事件,接受到把具体信息传给特定的Processor,Processor处理完毕后返回信息,ProcessorManager再将处理后的信息返回给Processor(没学过UML...只会看不怎么会画...)然后我们的机器人就说话了:)
然而我没有实现好友状态改变的事件,因为我订阅了Dotmsn的messenger.Nameserver.ContactStatusChanged += new ContactStatusChangedEventHandler(Nameserver_ContactStatusChanged);事件,但是没触发过,无论我怎么改变状态.知道的朋友请告诉我一下问题出在哪里.
该项目的源码
/Files/loning/Loning.Joymsg.DotmsnDataSource.rar
使用的时候请把生成的DLL COPY到Test项目的输出目录,然后修改Test项目的配置文件
配置文件示例
< configuration >
< configSections >
< section name ="log4net" type ="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
< section name ="Joymsg" type ="Loning.Joymsg.Configuration.JoymsgSection,Loning.Joymsg" />
< section name ="RssProcessor" type ="Loning.Joymsg.RssProcessor.Configuration.RssProcessorSectionHandler, Loning.Joymsg.RssProcessor" />
</ configSections >
< log4net >
< root >
< level value ="ALL" />
< appender-ref ref ="rollingFile" />
< appender-ref ref ="coloredConsoleAppender" />
</ root >
< appender name ="rollingFile" type ="log4net.Appender.RollingFileAppender,log4net" >
< lockingModel type ="log4net.Appender.FileAppender+MinimalLock" />
< param name ="File" value ="log" />
< param name ="AppendToFile" value ="true" />
< param name ="RollingStyle" value ="Date" />
< param name ="DatePattern" value ="yyyy.MM.dd" />
< param name ="StaticLogFileName" value ="false" />
< layout type ="log4net.Layout.PatternLayout,log4net" >
< param name ="ConversionPattern" value ="%d [%t] %-5p %c - %m%n" />
< param name ="Header" value =" ----------------------header-------------------------- " />
< param name ="Footer" value =" ----------------------footer-------------------------- " />
</ layout >
</ appender >
< appender name ="coloredConsoleAppender" type ="log4net.Appender.ColoredConsoleAppender" >
< mapping >
< level value ="ERROR" />
< foreColor value ="White" />
< backColor value ="Red, HighIntensity" />
</ mapping >
< mapping >
< level value ="DEBUG" />
< backColor value ="Green" />
</ mapping >
< mapping >
< level value ="INFO" />
< foreColor value ="White" />
</ mapping >
< layout type ="log4net.Layout.PatternLayout" >
< conversionPattern value ="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</ layout >
</ appender >
</ log4net >
< Joymsg processMessage ="收到消息{0}处理中,请稍候,您可以使用"?"查询命令" >
< DataSources >
< add name ="lumaQQ" type ="Loning.Joymsg.LumaQQDataSource.LumaQQDataSource, Loning.Joymsg.LumaQQDataSource, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
< add name ="dotmsn" type ="Loning.Joymsg.DotmsnDataSource.DotmsnDataSource, Loning.Joymsg.DotmsnDataSource, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ DataSources >
< Processors >
< add name ="default" type ="Loning.Joymsg.DefaultProcessor.DefaultProcessor, Loning.Joymsg.DefaultProcessor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
< add name ="online" type ="Loning.Joymsg.DefaultProcessor.DefaultProcessor, Loning.Joymsg.DefaultProcessor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
< add name ="fy" type ="Loning.Joymsg.TranslationProcessor.TranslationProcessor, Loning.Joymsg.TranslationProcessor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
< add name ="rss" type ="Loning.Joymsg.RssProcessor.RssProcessor, Loning.Joymsg.RssProcessor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</ Processors >
</ Joymsg >
< RssProcessor >
< RssChannels >
< add name ="cnblogs" url ="http://www.cnblogs.com/rss" />
< add name ="news" url ="http://news.cnblogs.com/rss" />
< add name ="cnbeta" url ="http://www.cnbeta.com/backend.php" />
< add name ="kc" url ="http://www.adjie.com/club/rss.php?fid=38&auth=0" />
< add name ="163" url ="http://news.163.com/special/00011K6L/rss_newstop.xml" />
< add name ="sina" url ="http://rss.sina.com.cn/news/marquee/ddt.xml" />
< add name ="nba" url ="http://rss.sina.com.cn/sports/basketball/nba.xml" />
< add name ="game" url ="http://rss.sina.com.cn/games/eqxw.xml" />
</ RssChannels >
</ RssProcessor >
< appSettings >
< add key ="luma:qq" value ="971125573" />
< add key ="luma:password" value ="" />
< add key ="luma:clusterReply" value ="true" />
< add key ="luma:addFriendAuthMessage" value ="我是QQ机器人,请让我加你为好友" />
< add key ="dotmsn:account" value ="loningrobot@hotmail.com" />
< add key ="dotmsn:password" value ="" />
</ appSettings >
</ configuration >