在上一篇《基于Mozilla Thunderbird的扩展开发(五)---进程间通信之Socket篇(上)》中开发了一个简单的TCP服务器,本文将介绍其对应的客户端。
客户端代码:
const tBirdBiffClientUi
=
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
tBirdBiffClientOnLoad: function()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// remove to avoid duplicate initialization
removeEventListener("load", tBirdBiffClientUi.tBirdBiffClientOnLoad, true);
//初始化客户端
var client = Components.classes["@phinecos.cnblogs.com/TBbiff/client;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
client.initialize();
var windowCount = client.getWindowCollection().Count();
client.addWindow(window);
client = null;
tBirdBiffClientObserver.updateUi();//更新UI
// register for notifications
var service = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
service.addObserver(tBirdBiffClientObserver, "thunderbirdBiff.uiUpdate", false);//加入监控者
service = null;
},
![](/Images/OutliningIndicators/InBlock.gif)
tBirdBiffClientOnClose: function()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// remove to avoid duplicate initialization
removeEventListener("close", tBirdBiffClientUi.tBirdBiffClientOnClose, true);
var service = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
service.removeObserver(tBirdBiffClientObserver, "thunderbirdBiff.uiUpdate");//移除监控者
service = null;
![](/Images/OutliningIndicators/InBlock.gif)
var client = Components.classes["@phinecos.cnblogs.com/TBbiff/client;1"].getService(Components.interfaces.nsISupports).wrappedJSObject;
client.removeWindow(window);//移除窗口
client = null;
}
}
addEventListener(
"
load
"
, tBirdBiffClientUi.tBirdBiffClientOnLoad,
true
);
addEventListener(
"
close
"
, tBirdBiffClientUi.tBirdBiffClientOnClose,
true
);
客户类:
const CI
=
Components.interfaces, CC
=
Components.classes, CR
=
Components.results;
tBirdBiffClient.classID
=
Components.ID(
"
{5b0bccd0-83b9-11db-9fe1-0800200c9a66}
"
);
tBirdBiffClient.contractID
=
"
@phinecos.cnblogs.com/TBbiff/client;1
"
;
tBirdBiffClient.classDescription
=
"
Biff Client Service
"
;
![](/Images/OutliningIndicators/None.gif)
function
tBirdBiffClient()
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
this.timer = CC["@mozilla.org/timer;1"].getService(CI.nsITimer);//定时器
this.interval = null;//定时器时间间隔
this.socketTransport = null;
this.biffState = null;//邮箱状态
this.socket = null;//socket对象
this.input = null;//输入流
this.port = null;//服务器端口
this.hostname = null;//服务器主机名称
this.windowCollection = CC["@mozilla.org/supports-array;1"].createInstance(CI.nsICollection);//客户端窗口集合
this.initialized = false;//是否已经初始化
}
![](/Images/OutliningIndicators/None.gif)
tBirdBiffClient.prototype
=
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
getConnection: function()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.closeSocket();//关闭先前的连接
this.socket = this.socketTransport.createTransport(null, 0, this.hostname, this.port, null);//创建socket连接
if(!this.socket)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return;
}
var stream = this.socket.openInputStream(CI.nsITransport.OPEN_BLOCKING | CI.nsITransport.OPEN_UNBUFFERED, 0, 0);//打开输入流,类型为阻塞式,无缓冲
if(!stream)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.closeSocket();
return;
}
this.input = CC["@mozilla.org/scriptableinputstream;1"].createInstance(CI.nsIScriptableInputStream);
if(!this.input)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.closeSocket();
return;
}
this.input.init(stream);//初始化输入流
},
closeSocket: function()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//关闭socket连接
if(this.input)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.input.close(null);
this.input = null;
}
![](/Images/OutliningIndicators/InBlock.gif)
if(this.socket)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.socket.close(null);
this.socket = null;
}
},
currentEventQueue: function()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//当前事件队列
var EQS = CC["@mozilla.org/event-queue-service;1"].getService(CI.nsIEventQueueService);
return EQS.getSpecialEventQueue(EQS.CURRENT_THREAD_EVENT_QUEUE);
},
initialize: function()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//初始化客户端
if(this.initialized)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return;
}
![](/Images/OutliningIndicators/InBlock.gif)
this.getIntervalPref();//获取时间间隔
this.hostname = this.utility.getHostnamePref();//获取主机名称
this.port = this.utility.getPortPref();//获取端口
this.socketTransport = CC["@mozilla.org/network/socket-transport-service;1"].getService(CI.nsISocketTransportService);
this.getConnection();//创建socket连接
this.timer.initWithCallback(tBirdBiffCheckMailCallback, 1000, this.timer.TYPE_ONE_SHOT);//启动定时器监听来自服务器的响应
this.initialized = true;
},
updateUi: function(result)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//更新客户端UI
var state;
switch(result)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
case "":
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
state = "offline";
break;
}
case "0":
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
state = "noMail";
break;
}
case "1":
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
state = "newMail";
break;
}
case "-1":
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
state = "error";
break;
}
default:
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
state = "weirdness";
break;
}
}
this.biffState = state;
state = null;
var service = CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService);
service.notifyObservers(null, "thunderbirdBiff.uiUpdate", null);
service = null;
},
checkForMail: function()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//检查是否有数据到来
this.timer.initWithCallback(tBirdBiffReadFromServerCallback, 1000, this.timer.TYPE_ONE_SHOT);
},
![](/Images/OutliningIndicators/InBlock.gif)
readFromServer: function()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//从服务器读取数据
if(!this.input)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//还未初始化输入流
this.getConnection();
}
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
var result = this.input.read(1);//读取数据
if(result.length == 1)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.updateUi(result);//更新状态
}
result = null;
}
catch (e)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.getConnection();
this.updateUi("");
}
this.timer.initWithCallback(tBirdBiffCheckMailCallback, this.interval, this.timer.TYPE_ONE_SHOT);//设置定时器
},
}
客户端监听者,负责监视邮箱的状态变化和读取来自服务器端的数据:
const tBirdBiffReadFromServerCallback
=
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
notify: function(timer)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//从服务器读取数据
var client = CC[tBirdBiffClient.contractID].getService(CI.nsISupports).wrappedJSObject;
client.readFromServer();
client = null;
}
}
![](/Images/OutliningIndicators/None.gif)
const tBirdBiffCheckMailCallback
=
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
notify: function(timer)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{//检查邮箱状态
var client = CC[tBirdBiffClient.contractID].getService(CI.nsISupports).wrappedJSObject;
client.checkForMail();
client = null;
}
}
为了测试服务器和客户端,我们使用firefox作为客户端的载体,thunderbird作为服务器端载体,可以看到thunderbird的邮箱状态会定时传给firefox,从而使得后者能随之更新其状态。
Reference:
1, https://addons.mozilla.org/en-US/thunderbird/addon/3788