add initialize
diff --git a/supwisdom/__init__.py b/supwisdom/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/supwisdom/__init__.py
diff --git a/supwisdom/protocol/__init__.py b/supwisdom/protocol/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/supwisdom/protocol/__init__.py
diff --git a/supwisdom/protocol/nettrans.py b/supwisdom/protocol/nettrans.py
new file mode 100644
index 0000000..98099f7
--- /dev/null
+++ b/supwisdom/protocol/nettrans.py
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+""" 一卡通后台通讯协议包封装
+所有数据都是 unicode utf-8 编码
+"""
+import traceback
+import simplejson as json
+
+
+def _unicode_str(value):
+ if isinstance(value, str):
+ return value.decode('utf-8')
+ elif isinstance(value, unicode):
+ return value
+ else:
+ return unicode(value)
+
+
+class message_writer:
+ """ 后台消息写接口
+ """
+ def __init__(self):
+ self.clear()
+
+ def clear(self):
+ self._attr = {}
+ self._row_data = []
+ self._col_names = []
+ self._row = {}
+ self._frozen = False
+
+ def attr(self, name, value):
+ if name in self._attr:
+ raise ValueError('Attribute [%s] already exists' % name)
+ self._attr[name] = _unicode_str(value)
+ return self
+
+ def row(self, name, value):
+ if not (name in self._col_names):
+ self._col_names.append(name)
+ self._row[name] = _unicode_str(value)
+
+ def add_row(self):
+ if not self._row:
+ raise ValueError('Row has no values')
+ self._row_data.append(self._row)
+ self._row = {}
+ return len(self._row_data)
+
+ def append_row(self, row):
+ if not self._col_names:
+ for k, v in row.iteritems():
+ self._col_names.append(k)
+ self._row_data.append(row)
+ else:
+ new_row = dict([(v, row.get(v, None)) for v in self._col_names])
+ self._row_data.append(new_row)
+
+ def _normalize(self):
+ colcnt = len(self._col_names)
+ rowcnt = len(self._row_data)
+ self._attr["colcnt"] = colcnt
+ self._attr["rowcnt"] = rowcnt
+ if colcnt > 0:
+ self._attr["colname"] = self._col_names
+ self._attr["coldesc"] = self._col_names
+
+ if rowcnt > 0 and colcnt <= 0:
+ raise ValueError(u'数据没有列值')
+
+ if rowcnt > 0:
+ self._attr["rowdata"] = [[row.get(colname, u"") for colname in self._col_names]
+ for row in self._row_data]
+ self._frozen = True
+
+ def serialize(self):
+ """ 返回 unicode utf-8编码
+ """
+ if not self._frozen:
+ self._normalize()
+ seri = json.dumps(self._attr, ensure_ascii=False, encoding='utf-8')
+ return seri
+
+ def root(self):
+ if not self._frozen:
+ self._normalize()
+ return self._attr
+
+
+class message_reader:
+ """ 后台消息读接口
+ """
+ def __init__(self):
+ self.clear()
+
+ def clear(self):
+ """ 清空数据
+ """
+ self._attr = {}
+ self._row_data = None
+ self._col_names = []
+ self._col_desc = []
+ self._row_no = -1
+ self._frozen = False
+
+ def unserialize(self, message):
+ """ 解析报文
+ """
+ self.clear()
+ try:
+ message = _unicode_str(message)
+ obj = json.loads(message)
+ #obj = json.loads(msg.replace('\\',"\\\\"))
+ except Exception, ex:
+ traceback.print_exc()
+ raise ValueError(u'解析报文错误,' + ex.message)
+
+ if u"colname" in obj:
+ colname = obj[u"colname"]
+ colcnt = obj[u"colcnt"]
+ rowcnt = obj[u"rowcnt"]
+
+ if colcnt != len(colname):
+ raise ValueError(u'记录列数定义不符')
+
+ rowdata = obj[u"rowdata"]
+ if rowcnt != len(rowdata):
+ raise ValueError(u'记录行数定义不符')
+
+ self._row_data = [dict(zip(colname, row)) for row in rowdata]
+ self._col_names = colname
+ self._col_desc = obj["coldesc"]
+ else:
+ pass
+
+ for n, v in obj.iteritems():
+ if n in (u"colname", u"colcnt", u"rowcnt", u"coldesc", u"rowdata"):
+ continue
+ self._attr[n] = v
+ self._frozen = True
+ #print self._attr
+
+ def attr(self, name):
+ """ 获取属性值,如果没有改属性返回空字符串
+ """
+ assert self._frozen == True
+ if name not in self._attr:
+ return ""
+ return self._attr[name]
+
+ def has_more_row(self):
+ """ 判断是否有后续行
+ """
+ assert self._frozen == True
+ if not self._row_data:
+ return False
+ if self._row_no < len(self._row_data):
+ return True
+ return False
+
+ def next_row(self):
+ """ 将读取指针移到下一行
+ """
+ assert self._frozen == True
+ assert self.has_more_row()
+ self._row_no += 1
+
+ _ARG_DEFAULT = []
+
+ def col(self, name, default=[], strip=True):
+ """ 获取当前行的字段值
+ """
+ assert self._row_no >= 0
+ arg = self._row_data[self._row_no].get(name, None)
+ if not arg:
+ if strip and default == message_reader._ARG_DEFAULT:
+ raise IndexError(u'no such column %s' % name)
+ return default
+ return arg
+
+ def is_eof(self):
+ """判断是否到记录尾
+ """
+ if self._row_no >= len(self._row_data):
+ return True
+ return False
+
+ def fetch_rows(self):
+ """ 读取所有行记录
+ """
+ if not self.has_more_row():
+ return
+ self._row_no = 0
+ for row in self._row_data:
+ self._row_no += 1
+ yield row
diff --git a/supwisdom/protocol/webservice.py b/supwisdom/protocol/webservice.py
new file mode 100644
index 0000000..48062b3
--- /dev/null
+++ b/supwisdom/protocol/webservice.py
@@ -0,0 +1,204 @@
+# -*- coding: utf-8
+"""
+一卡通webservice 请求 session 封装
+"""
+import urllib
+from datetime import datetime
+from tornado.httpclient import HTTPClient, HTTPRequest, HTTPError
+import json
+import traceback
+
+
+class SWWebserviceError(BaseException):
+ def __init__(self, code, msg):
+ self.code = code
+ self.msg = msg
+
+ def __str__(self):
+ try:
+ msg = self.msg.encode('utf-8', 'ignore')
+ except:
+ msg = self.msg.encode('gbk', 'ignore')
+ return "%d : %s" % (self.code, msg)
+
+ def __unicode__(self):
+ return u"%d: %s" % (self.code, self.msg)
+
+
+class SWWebserviceSession(object):
+ """
+ webservice session object
+ example
+
+ session = SWWebserviceSession('http://localhost:8080/yktapi/services',
+ '123213','3334df334223',1)
+
+ try:
+ if not session.auth():
+ print u"签到失败"
+ except SWWebserviceError, ex:
+ print "Error : %d , %s" % (ex.code, ex.msg)
+
+ """
+ def __init__(self, service_url, appid, appsecret, termid):
+ self.service_url = service_url
+ self.appid = appid
+ self.appsecret = appsecret
+ if isinstance(termid, int):
+ self.termid = str(termid)
+ elif isinstance(termid, float):
+ self.termid = str(termid)
+ else:
+ self.termid = termid
+ self.access_token = None
+ self.session_key = None
+ self.error_msg = None
+ self.status_code = None
+
+ def auth(self, timeout=10):
+ """
+ 签到
+ """
+ if not self._get_access_token(timeout):
+ return False
+ if not self._get_session_key(timeout):
+ return False
+ return True
+
+ def logoff(self):
+ """
+ 签退
+ """
+ self.access_token = None
+ self.session_key = None
+
+ def is_logon(self):
+ """
+ 是否签到成功
+ """
+ return self.session_key != None
+
+ def _get_access_token(self, timeout):
+ url = ''.join((self.service_url, '/authservice/getauth/',
+ self.appid, '/getaccesstoken?term_id=', self.termid))
+ http_client = HTTPClient()
+ try:
+ response = http_client.fetch(url, connect_timeout=timeout,
+ request_timeout=timeout)
+ try:
+ result = json.loads(response.body)
+ self.access_token = result.get('access_token', None)
+ if not self.access_token:
+ raise SWWebserviceError(501, u"系统返回值正确")
+ return True
+ except:
+ raise SWWebserviceError(500, u"无法解析返回值")
+ except HTTPError, ex:
+ if not ex.response:
+ self.error_msg = u"检查与服务器的连接"
+ return False
+ self.status_code = ex.response.code
+ self.error_msg = ex.response.body
+ return False
+
+ def _sign_data(self, key, data):
+ import hmac
+ import hashlib
+ h = hmac.new(key, digestmod=hashlib.sha1)
+ h.update(data)
+ return (h.hexdigest(), 'HMAC')
+
+ def _get_session_key(self, timeout):
+ timestamp = self.nonce()
+ sign, sign_meth = self._sign_data(self.appsecret,
+ self.access_token + timestamp)
+ r = (self.service_url, '/authservice/getauth/', self.appid,
+ '?access_token=', self.access_token, '&term_id=', self.termid,
+ "&sign_method=", sign_meth, "&sign=", sign, "×tamp=",
+ timestamp, "&v=1")
+ url = ''.join(r)
+
+ http_client = HTTPClient()
+ try:
+ response = http_client.fetch(url, connect_timeout=timeout,
+ request_timeout=timeout)
+ try:
+ result = json.loads(response.body)
+ self.session_key = result.get('session_key', None)
+ if not self.session_key:
+ raise SWWebserviceError(501, u"系统返回值正确")
+ return True
+ except:
+ raise SWWebserviceError(500, u"无法解析返回值")
+ except HTTPError, ex:
+ self.status_code = ex.response.code
+ self.error_msg = ex.response.body
+ return False
+
+ def nonce(self):
+ return datetime.now().strftime('%Y%m%d%H%M%S')
+
+ def gen_request_token(self):
+ """
+ 生成请求 token
+ """
+ timestamp = self.nonce()
+ token = ''.join((self.appid, self.termid,
+ self.session_key, timestamp))
+ sign, sign_meth = self._sign_data(self.appsecret, token)
+ # params = urllib.urlencode(dict(app_id=appinfo.get('appid'),
+ # term_id=appinfo.get('termid'),
+ # sign_method="HMAC",
+ # timestamp=timestamp,
+ # sign=sign))
+ return dict(timestamp=timestamp, sign=sign,
+ app_id=self.appid, term_id=self.termid,
+ sign_method=sign_meth)
+
+ def request_token_urlencode(self, token):
+ """
+ 将 gen_request_token 返回的数据编码成请求url
+ """
+ return urllib.urlencode(token)
+
+
+class SWRequest(object):
+ def __init__(self, session):
+ self.session = session
+ self.service_url = self.session.service_url + '/ecardservice/ecardapi'
+ self.error_msg = None
+
+ def request(self, request, response, timeout=10.0):
+ if not self.session.is_logon():
+ raise SWWebserviceError(u"session无效")
+ client = HTTPClient()
+ try:
+ http_request = HTTPRequest(url=self.service_url, method='POST',
+ headers={'Content-Type': 'application/json'},
+ connect_timeout=timeout,
+ body=self._pack_body(request))
+ http_resp = client.fetch(http_request)
+ except HTTPError, ex:
+ http_resp = ex.response
+ except:
+ traceback.print_exc()
+ return False
+
+ if not http_resp:
+ return False
+ self.status_code = http_resp.code
+ if http_resp.code != 200:
+ self.error_msg = '%d : %s' % (self.status_code, http_resp.body)
+ self.error_msg = self.error_msg.decode('utf-8', 'ignore')
+ else:
+ try:
+ response.unserialize(http_resp.body)
+ return True
+ except:
+ return False
+
+ def _pack_body(self, request):
+ funcdata = request.serialize()
+ request_token = self.session.gen_request_token()
+ request_token['funcdata'] = funcdata.decode('utf-8', 'ignore')
+ return json.dumps(request_token, ensure_ascii=False)