自然醒来发现昨夜一场洪雨唤起了我二十年前第一次仙剑入苗时的点滴
Linux Centos7 ThinkPad X1C无线网卡问题解决记录
折腾了两天,总结下问题
不知是2015款才有的问题还是前面几代内置无线网卡型号不同而不同
话说刚装Centos7系统时
安装向导顺利适配无线网卡并顺畅连接无线网络完成整个安装过程
然而在正常启动登录后,网卡是不适配的,当然除此之外其它驱动都完美适配
初步判断是安装向导自带很多无线驱动
但这些不是全都默认安装的,不过好歹知道是肯定支持的就放心了
查阅大量相关社区讨论及文档阅读后
最终发现这款型号Intel Wireless-N 7265 BN的驱动官方yum源就有:
1 |
iwl7265-firmware.noarch : Firmware for Intel(R) Dual Band Wireless-AC 7265: Series Adapters |
由于无网络连有线口都没,只好先去台式机用yum只下载不安装
1 |
sudo yum install --downloadonly --downloaddir=/home/srj/Downloads iwl7265-firmware |
得到iwl7265-firmware-22.0.7.0-36.el7.noarch.rpm安装包后通过U盘拷贝到小C本地安装
1 |
sudo yum localinstall iwl7265-firmware-22.0.7.0-36.el7.noarch.rpm |
重启后无线网络的小图标久别重逢了
但是好景不长就发现网络虽能连接但及其不稳定
掉包效超高,断线率也不少,经常动不动就全没了
回想安装向导时那驱动还是很稳定服务的,只能怀疑驱动版本问题了,毕竟小C内置的不是双频AC网卡,当然这要在Windows下肯定是一个大驱动全包了
接着又搜寻了许久,最终在
https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
找到了传说中Intel全系列Linux Wireless Driver下载集中地
然后根据Centos7 Kernel 3.10旧内核版本比较其实都不匹配
最终比对了下之前yum源安装的驱动
1 2 3 4 5 |
[srj@x1c firmware]$ pwd /usr/lib/firmware [srj@x1c firmware]$ ll|grep 7265 -rw-r--r--. 1 root root 690452 8月 9 23:40 iwlwifi-7265-8.ucode -rw-r--r--. 1 root root 697828 8月 9 23:47 iwlwifi-7265-9.ucode |
发现刚好就是iwlwifi-7265-ucode-22.24.8.0.tgz和iwlwifi-7265-ucode-25.228.9.0.tgz里的两同名文件
那要么先升级内核要么病马当活马医
立即下载解压覆盖重启解决所有问题
稳定顺畅的网络总算在新设备新系统的折腾上划了一个圆满的句号
开始白转黑行走江湖拥抱开源世界
ThinkPad X1 Carbon 2015款
硬件完美取代MacBook Air 13最佳选择
大小相似屏幕大一寸,轻薄相似碳纤维无静电
最关键的是支持Linux很好
可惜了自带的Win7,开箱验完货就被全格成CentOS7
Linux下的炉石传说
感谢过去一年的基础积累
Linux环境炉石传说折腾成功
提前告别迟早要决裂的盗版时代
努力拥抱开源世界
百闻不如一见华西村
tornado http basic and digest auth handler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
from tornado.web import RequestHandler from tornado.escape import utf8 from hashlib import md5 class BasicAuthHandler(RequestHandler): def get(self): realm = 'renjie' username = 'foo' password = 'bar' # Authorization: Basic base64("user:passwd") auth_header = self.request.headers.get('Authorization', None) if auth_header is not None: # Basic Zm9vOmJhcg== auth_mode, auth_base64 = auth_header.split(' ', 1) assert auth_mode == 'Basic' # 'Zm9vOmJhcg==' == base64("foo:bar") auth_username, auth_password = auth_base64.decode('base64').split(':', 1) if auth_username == username or auth_password == password: self.write('ok') else: self.write('fail') else: ''' HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="renjie" ''' self.set_status(401) self.set_header('WWW-Authenticate', 'Basic realm="%s"' % realm) class DigestAuthHandler(RequestHandler): def get(self): realm = 'test' opaque = 'asdf' # Real implementations would use a random nonce. nonce = "1234" username = 'foo' password = 'bar' ''' Authorization: Digest username="foo", realm="test", nonce="1234", uri="/auth/digest", response="e839337ef079c93238a4bf4f1ae712b3", opaque="asdf" ''' auth_header = self.request.headers.get('Authorization', None) if auth_header is not None: auth_mode, params = auth_header.split(' ', 1) assert auth_mode == 'Digest' param_dict = {} for pair in params.split(','): k, v = pair.strip().split('=', 1) if v[0] == '"' and v[-1] == '"': v = v[1:-1] param_dict[k] = v assert param_dict['realm'] == realm assert param_dict['opaque'] == opaque assert param_dict['nonce'] == nonce assert param_dict['username'] == username assert param_dict['uri'] == self.request.path h1 = md5(utf8('%s:%s:%s' % (username, realm, password))).hexdigest() h2 = md5(utf8('%s:%s' % (self.request.method, self.request.path))).hexdigest() digest = md5(utf8('%s:%s:%s' % (h1, nonce, h2))).hexdigest() if digest == param_dict['response']: self.write('ok') else: self.write('fail') else: self.set_status(401) # WWW-Authenticate: Digest realm="test", nonce="1234", opaque="asdf" self.set_header('WWW-Authenticate', 'Digest realm="%s", nonce="%s", opaque="%s"' % (realm, nonce, opaque)) |
python tornado微信公众号开发者认证示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import tornado.web import hashlib class WechatHandler(tornado.web.RequestHandler): def check(self): #微信公众平台设置 token = "renjie" #微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 signature = self.get_argument("signature", None) #时间戳 timestamp = self.get_argument("timestamp", None) #随机数 nonce = self.get_argument("nonce", None) #随机字符串 echostr = self.get_argument("echostr", None) if signature and timestamp and nonce: #将token、timestamp、nonce三个参数进行字典序排序 param = [token, timestamp, nonce] param.sort() #将三个参数字符串拼接成一个字符串进行sha1加密 sha = hashlib.sha1("%s%s%s" % tuple(param)).hexdigest() #开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 if sha == signature: if echostr: #请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。 return echostr else: return True return False def get(self): self.write(str(self.check())) |
svn: E200015 error proxy servers config
SVN E200015错误代理服务器配置文件位置
WIN:%APPDATA%Subversionservers
其它:~/.subversion/servers
1 2 3 4 5 6 7 8 9 10 |
#例外不走代理 http-proxy-exceptions = *.exception.com, www.internal-site.org #代理服务器 http-proxy-host = defaultproxy.whatever.com #代理端口号 http-proxy-port = 7000 #代理用户名 http-proxy-username = defaultusername #代理密码 http-proxy-password = defaultpassword |
如果是用TortoiseSVN,还有更直观的GUI设置
urllib2 vs tornado.httpclient and proxy vs auth
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import urllib2 # set up authentication info authinfo = urllib2.HTTPBasicAuthHandler() authinfo.add_password(realm='PDQ Application', uri='https://mahler:8092/site-updates.py', user='klem', passwd='geheim$parole') proxy_support = urllib2.ProxyHandler({"http" : "http://ahad-haam:3128"}) # build a new opener that adds authentication and caching FTP handlers opener = urllib2.build_opener(proxy_support, authinfo, urllib2.CacheFTPHandler) # install it urllib2.install_opener(opener) f = urllib2.urlopen('http://www.python.org/') |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import tornado.httpclient param = { "url" : "http://www.renjie.me/example", "proxy_host" : "proxy.renjie.me", "proxy_port" : 8080, "proxy_username" : "test", "proxy_password" : "welcome", "auth_mode" : "basic", "auth_username" : "renjie", "auth_password" : "CASwW8iJ" } http_request = tornado.httpclient.HTTPRequest(**param) http_client = tornado.httpclient.HTTPClient() try: response = http_client.fetch(http_request) print response.body except tornado.httpclient.HTTPError as e: print "Error:", e http_client.close() |
SPA3102基础上的OBi110准新手入门到熟悉心得分享
只不过它将Dial Plan分成了DigitMap与OutboundCallRoute两大类,而这两大类又包含了embedded-digit-map
也就是说,任何SPA的Dial Plan都可以根据原则分成DigitMap部分与OutboundCallRoute部分,反之也可
就像OBi110的DisconnectTonePattern与SPA3102的Disconnect Tone一样,本质是相同的,但是需要格式转换
这样的好处是解决了原有Dial Plan承载了太多太多东西的负担,什么都在里面,之前一个复杂些的DP复制出来都要分好几行,而且维护成本很高,一不小心一个语法格式错误就挂了
于是OBi将Dial Plan的非线路网关(包括默认Line1、gw0-4及其它自定义DP网关)部分单独划分出来称之为DigitMap,这个就非常类似很多编程语言里的Regular Expressions,中文叫正则表达式,只用于匹配、转换或限制,我先称之为预处理,或者一级处理
DigitMap又继续优化为可以单独成为一种embedded-digit-map,包括系统的(Msp1、Msp2、Mpp、Mli等,详细AdminGuide P118有介绍)与User Defined Digit Maps,并且可以互相嵌套(谨慎使用防止递归),每个(Mlabel)单独维护并做专一的事情,提高了可易阅读性,最终还使得主DigitMap变得很小且容易维护
比如我的PHONE Port DigitMap经过合理优化,最终就只有(#[012] | (MStar) | (Mpli))这些了,而Auto Attendant DigitMap也就(<0 : $1> | (MStar) | (Mpli))那样,非常容易维护,每次新增规则只需要改一个孙子级的DigitMap即可
经过DigitMap的划分,原来Dial Plan剩下的线路网关部分就自然成为了OutboundCallRoute,这个初看貌似很复杂的东西,如果你要知道其实这只是原来很熟悉Dial Plan的一部分那就很有信心去征服它了
我也将这个工作称之为后处理,或者二级处理,因为需要结合预处理才能组合成一个完整的Dial Plan,于是其也包含了embedded-digit-map,用于衔接两者的纽带,否则就只能靠一个个预先确定好的callee number号码来前呼后应了
当然关于这个,我觉得褒贬不一,还很有争论,因为细分带来的好处我例子中已经显而易见,但同时也增加了不少冗余,我就拿系统默认的也是大家最熟悉的**9来说吧,DigitMap需要有**9(Mpp)规则用于预处理OBiTalk号码的合法性,而OutboundCallRoute也需要有{(<**9:>(Mpp)):pp}规则,而其中都包含相同的DigitMap这就是冗余,而且预处理匹配了**9前缀,后处理用于消除**9前缀,本来简单一步的事情要分两步做,增加了设置的负担,与理解的难度
比如系统默认的OBiTALK Service DigitMap为(<ob>xxxxxxxxx|obxxxxxxxxx),一开始我始终不能理解后一个规则的作用,直到后来因为上述的一二级处理机制我才慢慢明白,后个规则是给后处理用的,因为预处理已经将9位数字提前增加的前缀,这个时候如果没有后一个规则允许的话,二级处理那里是不允许通过的,这些就是所谓有很小很小弊端的地方,但总体可以用前紧后松或前松后紧的原则来避免,总之这个划分我认为是利远远大于弊的
正因为有了OutboundCallRoute,于是对应出了InboundCallRoute,这与SPA3102如何对应呢,很简单,那就是SPA PSTN Line的两个Gateway功能分别对应OBi110 SP2 Service InboundCallRoute与LINE Port InboundCallRoute的部分功能,其他两个InboundCallRoute则是独一无二无法对应的,这和SPA Line1线很单纯有关,而且OBiTALK也是横空出世的
注意对应过来的功能在OBi110这里其实是雕虫小技了,因为SPA PSTN Line线在现在看来其实就只有可怜的VoIP-To-PSTN与PSTN-To-VoIP两个小功能,这在OBi时代就不过是很简单的SP2 InboundCallRoute{li(To-PSTN-Number)}与LINE InboundCallRoute{sp2(To-VoIP-Number)}基础上的扩展,其大部分的参数细节控制都可以一一对应过来,但肯定也有一些是还不行的,比如VoIP Access List这个,用于限制安全IP地址范围的,但目前的InboundCallRoute体系里似乎就没有考虑到这点,毕竟VOIP里的号码欺骗是非常容易的,仅凭匿名或指定号码来做匹配是很不安全的
当然退一步从更高一层次的角度来看,这个也不是问题,因为同级的还有Auto Attendant,而且可以UsePIN做最后保障,可松可紧,控制方便
最后总结,OBi110按照模块划分为7个基础部分,其中
四条独立的线路,即SP1 Service、SP2 Service、OBiTALK Service、LINE Port,其基本特征是拥有InboundCallRoute而没有OutboundCallRoute
两个独立的终端,分别是PHONE Port与Auto Attendant,前者是有形的,后则是无形的,其基本特征与线路相反,拥有OutboundCallRoute而没有InboundCallRoute
一个特殊的终端,即Auto Attendant2或AA2,官方称之为local device configuration IVR,其比AA更无形,什么都没有就是它的基本特征
前面六个部分都有自己的DigitMap,特别是这么多的地方可以设置DigitMap这让初学者很畏惧,其实最关键的是终端的DigitMap,特别是有形的那个我们最常用,只要控制好了终端的DigitMap,线路的DigitMap其实是浮云
从某种角度看也可以将一紧一松的思想适用于这里,就是终端紧就线路松,反之亦然,因为一个正常的主叫通话肯定是先由终端DigitMap拨号,之后在由线路DigitMap拨出,任何一级做精确控制都是可以的
线路特有的InboundCallRoute其实就是控制将线路的来电转移到指定终端上,包括但不限于那两个基本终端,因为对于线路拨打出去的号码所对应的其实也可以理解成是一个远程终端。比如ph与li(另外一个电话的号码),就分别为本地与远程终端,只不过前者直接连接,后者用网关桥接
终端特有的OutboundCallRoute其实就是将终端DigitMap一级处理过的拨号,再经过OutboundCallRoute二级匹配后通过线路拨打出去给其他终端,包括但不限于那四条基本线路,其实这里隐含了第五条本地线路,用于AA拨打PH或PH拨打AA,甚至特殊的AA2终端也是依靠这条本地线访问
总之,OBi110是站在SPA3000的基础上深化改良并与时俱进的,如果您还在SPA时代,请不要畏惧进入OBi时代,其实这非常简单,完全可以做到除了对您本人这个Admin外的其他使用者的透明转换,包括使用习惯,当然也许目前还有一些不足,但至少持续不断的Firmware更新让我们看到了希望,在这点上是停滞许久不前的SPA3000系列所无法比拟的