firefly辅助工具相关的文件都存放在utils文件内,也就是工具模块中
utils模块的文件结构
- utils
- __init__.py
- interface.py # 接口类
- service.py # 服务类
- singleton.py # 单例模式
工具类在firefly中也非常重要,尤其是工具类中的服务器类(service.py)
该类几乎贯穿整个分布式布局,而分布式布局又是firefly的重中之重
- 第一步我们首先就来看看服务类究竟都做了些什么
#coding:utf8
"""
Created on 2011-1-3
服务类
@author: sean_lan
"""
import threading
from twisted.internet import defer, threads
from twisted.python import log
class Service(object):
"""A remoting service
attributes:
============
* name - string, service name.
* runstyle
"""
# 在这里,我想作者应该是提供了两种运行模式(我对这部分的理解,如有错误,请帮忙指出)
# 单线程模式 这种模式下运行的服务应该是一个 deffered 对象,也就是延迟服务,不能运行同步的耗时任务,因为会堵塞整个服务线程,甚至导致软件奔溃
# 多线程模式 在这种模式下,服务是以twisted的多线程迟滞回调模式运行的,要求软件返回的必须是一个同步对象,如果返回异步对象,则同样会导致软件异常,甚至崩溃
# 所以在这里,你必须拥有足够的twisted使用知识,如果没有,请查阅相关文档
SINGLE_STYLE = 1 # 单线程运行
PARALLEL_STYLE = 2 # 多线程运行
def __init__(self, name, runstyle = SINGLE_STYLE):
self._name = name # 服务名称
self._runstyle = runstyle #运行模式
self.unDisplay = set() # 类似黑名单
self._lock = threading.RLock() # 线程锁
self._targets = {} #目标服务字典
# Keeps track of targets internally
def __iter__(self):
return self._targets.itervalues() # 返回所有服务
def addUnDisplayTarget(self,command):
"""Add a target unDisplay when client call it."""
self.unDisplay.add(command) # 将某个服务拉入黑名单
def mapTarget(self, target): # 注册服务
"""Add a target to the service."""
self._lock.acquire()
try:
key = target.__name__
if key in self._targets:
exist_target = self._targets.get(key)
raise "target [%d] Already exists,\
Conflict between the %s and %s"%(key,exist_target.__name__,target.__name__)
self._targets[key] = target
finally:
self._lock.release()
def unMapTarget(self, target): # 注销服务
"""Remove a target from the service."""
self._lock.acquire()
try:
key = target.__name__
if key in self._targets:
del self._targets[key]
finally:
self._lock.release()
def unMapTargetByKey(self,targetKey): # 根据服务名称注销服务
"""Remove a target from the service."""
self._lock.acquire()
try:
del self._targets[targetKey]
finally:
self._lock.release()
def getTarget(self, targetKey): #获取服务
"""Get a target from the service by name."""
self._lock.acquire()
try:
target = self._targets.get(targetKey, None)
finally:
self._lock.release()
return target
def callTarget(self, targetKey,*args,**kw): # 调用服务
"""call Target
@param conn: client connection
@param targetKey: target ID
@param data: client data
"""
if self._runstyle == self.SINGLE_STYLE:
result = self.callTargetSingle(targetKey,*args,**kw)
else:
result = self.callTargetParallel(targetKey,*args,**kw)
return result
def callTargetSingle(self,targetKey,*args,**kw): # 用单线程方式调用服务
"""call Target by Single
@param conn: client connection
@param targetKey: target ID
@param data: client data
"""
target = self.getTarget(targetKey)
self._lock.acquire()
try:
if not target:
log.err('the command '+str(targetKey)+' not Found on service')
return None
if targetKey not in self.unDisplay:
log.msg("call method %s on service[single]"%target.__name__)
defer_data = target(*args,**kw)
if not defer_data:
return None
if isinstance(defer_data,defer.Deferred):
return defer_data
d = defer.Deferred()
d.callback(defer_data)
finally:
self._lock.release()
return d
def callTargetParallel(self,targetKey,*args,**kw): # 用多线程方式调用服务
"""call Target by Single
@param conn: client connection
@param targetKey: target ID
@param data: client data
"""
self._lock.acquire()
try:
target = self.getTarget(targetKey)
if not target:
log.err('the command '+str(targetKey)+' not Found on service')
return None
log.msg("call method %s on service[parallel]"%target.__name__)
d = threads.deferToThread(target,*args,**kw)
finally:
self._lock.release()
return d
class CommandService(Service):
"""A remoting service
继承于服务类,主要用于指令服务(当客户端数据被解析成指令后可以直接根据指令内容调用服务)
这里要求客户讲注册到本服务对象的服务名称写成 name_commandId
比如:getUser_01,当我调用1号指令时,会自动解析成这个函数名称。
"""
def mapTarget(self, target):
"""Add a target to the service."""
self._lock.acquire()
try:
key = int((target.__name__).split('_')[-1]) #分割函数么,并取第二段
if key in self._targets: # 注册分割出来的函数ID
exist_target = self._targets.get(key)
raise "target [%d] Already exists,\
Conflict between the %s and %s"%(key,exist_target.__name__,target.__name__)
self._targets[key] = target
finally:
self._lock.release()
def unMapTarget(self, target):
"""Remove a target from the service."""
self._lock.acquire()
try:
key = int((target.__name__).split('_')[-1])
if key in self._targets:
del self._targets[key]
finally:
self._lock.release()
- 第二步,我们看一下单例模式(singleton.py)
# 这个文件提供了python单例模式的元类
# 至于什么是单例模式,什么是元类,笔者就不做详细描述了
# 基本原则是,单例模式一般用于配置文件
# 单例模式的特点是在一个进程中,无论被实例化几次,都不会重新创建对象,而始终是第一个对象,这样既能保证配置文件在一个程序中的唯一性,类似于全局变量
# 这一块,如果无法理解也没有关系,可以直接跳过,你可以吧单例模式产生的类实例化的对象当成一个全局类,里面的变量当成全局变量。
class Singleton(type):
"""Singleton Metaclass"""
def __init__(self, name, bases, dic):
super(Singleton, self).__init__(name, bases, dic)
self.instance = None
def __call__(self, *args, **kwargs):
if self.instance is None:
self.instance = super(Singleton, self).__call__(*args, **kwargs)
return self.instance
class test(metaclass=Singleton): # 指定创建Foo的type为SingletonType
def __init__(self):
self.json_config = None
- 最后,我们再来看看interface.py文件
# 这个作为一个接口类,以该类为接口的类必须要完成该类所提供的方法,否则会报错
'''
Created on 2013-10-17
@author: lan (www.9miao.com)
'''
from __future__ import division, absolute_import
from zope.interface import Interface
class IDataPackProtoc(Interface):
def getHeadlength():
"""获取数据包的长度
"""
pass
def unpack():
'''解包
'''
def pack():
'''打包数据包
'''