G-root ruby elixir go 生活不易 多才多艺

Tcl 超快速入门

概述

Tcl 跟 ruby 一样 是个脚本语言,在最新的 8.6 提供了对象系统,还提供了 coroutine, 跟 ruby 的 fiber 一样。也提供了内建的的 event loop 编程模型,像 eventmachine. 比较特别的是提供了一个自带的 UI 页面,叫 tk,可以快速搭建UI 界面,感觉有点像 visual basic,不过是跨平台,我在 mac 上试了下对 Retina 支持的不是很好。不过有解决方案。

mac 上有安装包,可以安装最新的。如果用 brew 的话 brew install tcl-tk 得到的是8.5的版本。

语法

字符串

Tcl 认为除了关键字就是字符串,所以这里 hello 其实被认为是字符串,或者可以当作 symbol 来理解,如果需要空格的的话就用花括号阔起来,不然会被认为是两个参数。双引号和花括号一样, 但是变量会被替换。单引号没有特别的意义跟其他字符一样的,这跟其他语言的词法解析还是很不同的。

puts hello
# => hello

puts hello''world
# => hello''world

puts {hello \n world}
# => hello \n world

puts "hello \n world"
# => hello 
#    world

变量赋值

这跟上面说的有关系了,因为一切都是字符串如果是, “puts abc” 的话解释器会以为你只是想输出字符串 abc,要是要输出 abc 的值的话就得加一个 $

set abc hello
puts $abc
# => hello

函数

proc hello {arg} {
  puts "hello $arg"
}
hello world
# => hello world

分支语句

if {1 == 1 } {
  puts "wow, right!"
} else {
  puts "impossible"
}

regexp

regexp {\d} 10 -> foo
puts $foo
# => 1

运算

下面两个是等价的, 都是给变量啊加1,expr 表示运算可以加减乘除,不知道为什么没有像 lisp 一样把操作符前置,而是引入了新的关键字 expr,后面跟了一个表达式

set a 1
set a [expr $a + 1]
incr a 1

list 数据结构和遍历器

set cars {Toyota Mazda}
lappend cars Honda
puts $cars
# => Toyota Mazda Honda
foreach car $cars {
  puts $car
}
# => Toyota
#    Mazda
#    Honda

Associative Arrays 和 Dictionary

功能类似 ruby 的 hash。但是 dictionary 更加强大一点,跟 array 比

  • 可以直接传递给函数
  • 值可以是任何类型

下面的方括号表示对方法的呼叫,相当于 ruby 里的小括号, 因为一切都是字符串,解析器需要明确定信息告诉它是字符串 foo,还是变量 $foo,还是表达式 [foo]

array set dic {}
array set dic(foo) bar
puts $dic(foo)
# => bar

dict set clients  name Joe
puts [dict get $clients name]
# -> Joe

作用域

不像 javascript 或者 ruby 的 block,可以看到函数调用时候 context 时候里面的变量,Tcl 需要显示的声明某个变量我要引用外部的变量,可以用 global 声明他全局变量,或者用 upvar 声明要向上几个调用栈来找这个变量, 这个时候其实传递的就是引用了,在函数外面改变这个值的话,外面的值也会发生变化

set item 1
proc test {} {
  puts $item
}
test
# => can't read "item": no such variable

proc test_global {} {
  global item
  puts $item
}
test_global
# => 1

proc test_upvar {} {
  upvar 1 item hah_my_var
  puts $hah_my_var
  set hah_my_var 2
}
test_upvar
puts item
# => 1
#    2

coroutine

用 yield 交出控制权,进入挂起的状态,恢复的手段是在别的 coroutine 中或者事先埋好的 callback 中显始式的调用它的名字, coroutine name func,name 就是这个corouting 的标示

vwait 就是表示就如 event loop,等待时间发生 vwait var 表示一直等到 var 这个变量被赋值了,那么就继续运行,不然就等着,另外一个是 vwait forever,就顾名思义了。

package require http

proc get url {
     http::geturl $url -command httpCallback
     #事先埋好 callback
     yield
     #交出控制权
}

proc httpCallback {token} {
  # 唤醒
  query $token
  global sig
  set sig done
}

proc main {} {
     set t [get http://wiki.tcl.tk/4]
     puts [::http::data $t]
     http::cleanup $t
}
coroutine query main
vwait sig

八卦

看到一篇文章,作者以前应该是 Tcl 死忠,总结了一下为啥 Tcl 没火起来。其实看 Tcl 的文档话感觉作者还挺傲娇的,说 ruby 除了日本基本没啥人用,给鄙视的不行了,也说了现在 node 跟 phtyon 的异步编程老子早就玩的不待完了,感觉有点酸溜溜的,哈哈哈。 作者主要总结就是

  • Tcl 社区太屌,没有赶上开源运动的热潮,核心开发人员也不是很想参加社区活动
  • 虽然 tk 是大杀器,但是 UI 不行,old school,被 Gnome 和 KDE 抄了老家
  • 社区对语言的定义有分歧,有的想 keep small, 也有人想搞成全功能的,这其实挺尴尬的,大家不一心的话确实比较难搞,就跟公司也一样。嵌入式干不过 lua,功能全的就太多了
  • 迟迟不引入官方的 OO 实现,开发者无所适从,这个 8.6 已经有了
  • 没有 rails 这样的杀手级应用,web 开发又没赶上趟
  • Tcl 的一切都是字符串给垃圾回收带来一些问题

总的来说还是有些小惊讶,哦原来可以这么搞啊,刚开始 abc $abc 傻傻分不清楚。总体感觉惊喜不大,不过开发个工作用的桌面应用啥的应该还挺实用的。

看来要给 ruby 贡献点什么才行呀,不然说不定就成了下个 Tcl,当然真成了 Tcl 也没啥不好的。

参考

tcl tutorial

where tcl and tk went wrong

堆排序

问题描述

想要实现一个优先队列,我可以使劲往里丢东西(insert),也可以把最大的弹出来(delMax)

解法

概述

我就不假情假意的介绍一番用有序的数组或者链表来实现的方法了,不是丢东西慢,就是弹东西慢,最后还是用树的思想来解,树为啥这么牛逼呢。

先引入一个概念,”堆有序”, 就是说一个二叉树(最多只有两个叉叉的树),如果对于任何一个节点,都满足该节点不小于他的两个子节点的任意一个,那这个二叉树就是堆有序的,如果我们把值大成为屌的话,就是越往上越掉的感觉,类似你老板坐最上面,下面是左右护法,再下面是你。

然后从上往下一个个塞到数组里面,这个数组就是”二叉堆”,是堆有序的二叉树的一种表现形式,具体来说对于 index 是 k 的那个家伙,他的爸爸就是 k / 2(整数除法,舍弃小数),他的两个小弟就是 2k 和 2k + 1

术语

上浮(swim)

书上是叫 swim,为啥不叫 swim up 呢?

就是一个节点,如果发现他的父节点比他还小,那么就和他的父节点交换位置,一直到他合适的位置,那这个过程就是 上浮,重新构建了堆有序

下沉(sink)

就是一个节点,如果发现他的子节点有比他还小,那么就和他子节点最小那个交换位置,一直到他合适的位置,那这个过程就是 下沉,重新构建了堆有序,上浮的是跟父节点比,下沉是跟子节点比

我们来正式吃肉咯。

插入

怎插入呢(咳~咳~),就是把一个节点新增到最下面的一层,然后把他上浮到合适的位置,那插入就完成了,跟没插入的时候一样样的,都是堆有序,多么完美

选出最大

选最大值呢,就是把最高那个拿走,把最低的放到这个位置,然后先下沉到合适的位置,撤退之后依然是堆有序

构建堆

堆排序分两步,第一步是构建堆。一种暴力的方法是我们从前到后一个一个的节点上浮到合适的位置,遍历完节点就完成了树的构建,另外一种更好的做法是最后一层不管,从倒数第二层开始,每一个节点做下沉,这样用的次数就少很多

排序

第二步是排序,就是依次取出最大元素就好了, 思想跟选择排序一样,实现起来就快多了。

归并排序

问题描述

对一个数组进行排序

解法

背景知识是,如果让我们两个单调不递减的数组合并起来,然后保证合并后的数据是单调不递减的,这是一件比较容易的事情,可以想象成两个队比身高,身高低的算输(打我呀), 然后两个队都是从低到高派出选手,低的那个出局,站在旁边,我们称之为失败序列,这个时候输的那一队会派出第二个, 输掉的就去失败序列, 依次类推,当一方队伍耗尽的时候,另外一方也依序进入失败队列,最后失败队列就是一个单调不递减的序列,我们就完成了排序, 这个方法我称之为 merge

所以我们就想,如果可以构造两个有序队列就好了。

于是把一个数组分成两两半, 然后分别对他们排序,怎么排序呢,再把他分成两半,一直到就剩下两个元素,直接比较就可了,然后在一层一层的 merge 回来,最后就是结果了

SMTC(show me the code)

def merge_sort(arr)
  return arr if arr.length <= 1
  if arr.length == 2
    if arr[0] > arr[1]
      [arr[1], arr[0]]
    else arr
    end
  else
    midlle = arr.length / 2
    merge merge_sort(arr[0..midlle]), merge_sort(arr[(midlle + 1)..(arr.length)])
  end
end

def merge(first, second)
  result = []
  a, b = first, second
  while true
    if a.length == 0 and b.length == 0
      break
    elsif a.length == 0
      result.push(b.shift())
    elsif b.length == 0
      result.push(a.shift())
    elsif a[0] > b[0]
      result.push(b.shift())
    else
      result.push(a.shift())
    end
  end
  result
end

动态连通性

前言

主要内容出自算法第四版,这里记录一些我的理解

问题描述

连通性就是判断两个事物是不是一伙的,是不是连在一起,就好像一个连在一起的铃铛,可不可以一次把全部都提留起来。 构建数据的过程就是把一个一个对象连起来,如果已经连起来了,就不用连了, 最后形成一幅无环连通图

应用

  • 网络,判断是不是可达的,需不需要架设新的线路
  • 变量相等
  • 集合分类

解法

1. quick-find

顾名思义,就是 find 起来很快,union 很慢. 实现的方式用输入构建一个哈希表(key-value) table, 对于j 和 k两个如果 table[j] == table[k], 就认为 j 和 k 是联通的

# 以下代码均为实例代码
def find(key)
  table[key]
end

def union(first_key, second_key)
  first_value = find(first_key)
  second_value = find(second_key)
  if first_value != second_value
    table.each do |k, v|
      if v == first_value
        table[k] = second_value
      end
    end
  end
end

2. quick-union

利用链表,把所有的在一起的连起来。如果 对 p 和 q 做 union 的做作,就是把 p 所在树的根节点指向 q 所在树的根节点, 数据结构上也是用一个Hash Table, 根节点的 key value 是相等的,其他节点的 key 代表这个数据本身,value 代表他指向的节点

def find(key)
  # 相当于找到这棵树的根节点来代表他, 相当于他们这个团体(set)的名字
  compare_value = key
  while compare_value != table[key]
    compare_value = table[key]
  end
  compare_value
end

def union(first_key, second_key)
  first_key_root = find(first_key)
  second_key_root = find(second_key)
  if first_key_root != second_key_root
    table[first_key] = second_key_root
  end
end

3. weighted quick-union (加权quick-union)

quick-union 明显的缺点是找的时候,如果树太高的话,找的这个点又是在树底下,要挨个找到根,非常浪费时间. 所以说怎么把书的高度降低就是关键了。这个时候就是刚才连树的时候,可以 a 往 b 连,也可以 b 往 a 连,那怎么选择呢,我们这次不按照传值传进来的顺序连,而是智能一点,总是把短的树往长的树连,这样子就是 weighted quick-union 啦,简单又好用 perfect!

class WeightedQuickUnion
  # capacity 的读音是[ ke 'pan si ti] 注意重音位置
  def initialize(capacity)
    @set_count = capacity #不同的集团有几个,也就是所谓的连通分量

    # 保存 x 在他所在集团成员数量
    @single_set_count_table = (1..capacity).to_a.map {|x| [x, 1]}.to_h

    #一开始大家全部都指向自己
    @relation_table = (1..capacity).to_a.map {|x| [x, x]}.to_h
  end

  def addNode(first_node, second_node)
    first_key_root = find(first_key)
    second_key_root = find(second_key)
    return if (first_key_root == second_key_root)

    if @single_set_count_table[first_node] >  @single_set_count_table[second_node]
      @relation_table[second_node] = find(first_node)
      @single_set_count_table[first_node] += single_set_count_table[second_node]
    else
      @relation_table[first_node] = find(sencond_node)
      @single_set_count_table[second_node] += single_set_count_table[second_node]
    end
    @set_count--
  end

  def find(key)
    # 跟 quick-union 是一样的
    compare_value = key
    while compare_value != table[key]
      compare_value = table[key]
    end
    compare_value
  end
end

锁和数据库事务

数据的原子性和和隔离性比较好理解,持久性也是。关于”一致性”引用几处别人的理解:

@Wonder: 数据库一致性,是数据库中的数据开始是正确的,随着状态转移,总是保持正确的状态。用户在任意时刻的任何请求返回的都是正确的结果。数据库以一定的模式存储数据,本质是对真实世界建模,因此这里的正确是指,数据满足真实世界各种约束(例如:完整性约束)。

ACID里的AID都是数据库的特征,也就是依赖数据库的具体实现.而唯独这个C,实际上它依赖于应用层,也就是依赖于开发者.这里的一致性是指系统从一个正确的状态,迁移到另一个正确的状态.什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态.而事务具备ACID里C的特性是说通过事务的AID来保证我们的一致性.

一步一步用 elixir 搭建一个 obd 的 socket server

应用场景

obd 设备要通过 socket 把数据发送到服务器, 然后把数据存储到数据库,要求服务器可以通过 socket 下发 指令。

ruby 虽然有一个基于 actor 的框架 celluloid(三六劳艾的), 但是用下来发现性能还是不够,尤其是遭遇移动运行商出现网络问题或者重启服务,导致设备集体重连的时候,会带来比较大的冲击,所以后来决定干脆采用 elixir 本尊来尝试一下

待续…

ruby重构经常用到的方法

《重构》Ruby 版的笔记

6.9 使用方法对象替换方法

当一个方法要调用到其他很多方法的时候,参数往往要传来传去,这个时候,加一个类,把这些参数当作实例变量,就可以不用考虑传递参数, 相当于变成了实例上的全局变量

6.12 利用 block 来传递条件

重构前

def number_of_living_descendants
  children.inject(0) do |count, child|
    count +=1 if child.alive?
    count + child.number_of_living_descendatns
  end
end

def number_of_desendants_named(name)
  children.inject(0) do |count, child|
    count +=1 if child.name == name
    count + child.number_of_desendants_named(name)
  end
end

重构后

def count_desendants_matching(&block)
  children.inject(0) do |count, child|
    count +=1 if yield child
    count + child.count_desendants_matching(&block)
  end
end

def number_of_descendants_named(name)
  count_descendants_matching {|descendant| desendant.name == name}
end

def number_of_living_descendants
    count_descendants_matching {|descendant| desendant.alive?}
end

git 的操作

撤销一次merge

git reset --merge ORIG_HEAD

mongoid 查找附近的记录

model 的写法

class Meal
  include Mongoid::Document

  field :location, type: Array
end

这里要注意的是,location 的类型必须是 Float 组成的 Array,而不是字符串

query 的写法

Meal.where(:location => {'$near' => [50,50],'$maxDistance' => 5}).count
end

为mysql 添加emoji支持

Mysql 从5.5.3 开始支持 utf8mb4 编码,用 4 个 byte 作为一个字符,utf8 编码是3个 bype 的,存emoji就溢出了.

  1. 更新mysql(以centos 为例)
wget file:///Users/neal/Downloads/mysql-community-release-el6-5.noarch.rpm
sudo yum localinstall mysql-community-release-el6-5.noarch.rpm
sudo yum update mysql-server
  1. 重启 mysql 服务

  2. 添加编码到 /usr/share/mysql/charsets/Index.xml

<charset name="utf8mb4">
  <family>Unicode</family>
  <description>UTF-8 Unicode</description>
  <alias>utf-8</alias>
  <collation name="utf8mb4_unicode_ci"  id="99">
   <flag>primary</flag>
   <flag>compiled</flag>
  </collation>
  <collation name="utf8_bin"            id="100">
    <flag>binary</flag>
    <flag>compiled</flag>
  </collation>
</charset>
  1. 修改 Rails 的数据库配置
  adapter: mysql2
  encoding: utf8mb4
  reconnect: false
  database: feixiang_production
  pool: 5
  username: user
  password: password

用 swift 上传文件到 Rails 服务器

###1. 用Base64 编码,在 Rails 解码

var imageData = UIImageJPEGRepresentation(image, 0.9)
var base64String = imageData.base64EncodedStringWithOptions(.allZeros)

然后按照普通字符串传到rails 服务器就行了,但是在服务器端可能要加上表示这是一个图像的头文件, 类似"data:image/jpg;base64," + Base64string

###2. 用二进制数据

var imageData = UIImageJPEGRepresentation(image, 1.0);
//var request = createRequest(userid: "ss", password: "ss", email: "ss", data: imageData)
let boundary = generateBoundaryString()
let url = NSURL(string: "http://localhost/api/test")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let body = NSMutableData()
let filename = "abc"
let mimetype = "multipart/form-data; boundary=\(boundary)"
body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("Content-Disposition: form-data; name=image; filename=abc.jpg\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("Content-Type: \(mimetype)\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(imageData)
body.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData("--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
request.HTTPBody = body
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.currentQueue()) { (reponse, data, error) -> Void in
    //NSLog(reponse.description)

}

从百度地图抓去大学的边界

最近一个项目需要大学的地理位置信息,在网上并没有发现相关的库,刚好在百度地图上看到搜一个大学可以有一个范围的蓝线表示出来,就萌生了从百度地图抓去数据的想法

知乎上有个文章给我极大信心和方向上的指导,《如何获得全国大学的区域边界数据》

  1. 获取大学的uid 这个时候大学就是一个兴趣点
require "cgi"
result = JSON.parse RestClient.get("http://api.map.baidu.com/place/v2/search?ak=483bcc031ef80a1384950a998908e494&output=json&query=#{CGI.escape "北京大学"}&page_size=10&page_num=0&scope=1&region=#{CGI.escape "全国"}")
@uid = result["results"][0]["uid"]
  1. 获取边界 根据上一步拿到的兴趣点去获取边界信息
pr = JSON.parse RestClient.get("http://map.baidu.com/?newmap=1&reqflag=pcmap&biz=1&pcevaname=pc2&da_par=direct&from=webmap&qt=ext&uid=#{@uid}&c=131&ext_ver=new&tn=B_NORMAL_MAP&nn=0&ie=utf-8&l=15&b=(12945800.61,4838078.8495000005;12951968.61,4839350.8495000005)&t=1427876027620")
@geo = pr["content"]["geo"]
  1. 解析数据 上一步的 @geo 是一个字符串,用函数解析一下就可以拿到点了
var string = "<%= @geo %>"

arr = parseGeo(string).points.split(";")
points = []
for (var i = 0; i < arr.length; i++) {
  var p = arr[i].split(",")
  points.push(projection.pointToLngLat({x: p[0], y: p[1]}));
}
console.log(points)

页面内播放以及播放器闪动的解决方案

在iPhone 版微信的内置浏览器里面,是可以实现在页面内播放视频的,方法又两种,一种是通过 iframe,另外一种直接的方式是通过设置 video tag 的webkit-playsinline 属性

<iframe frameborder=0 src="http://v.qq.com/iframe/player.html?vid=c0015wqcp3v&tiny=0&auto=0" allowfullscreen></iframe>

或者

<video src="http://mvvideo2.meitudata.com/55123c0eb1af82919.mp4" width="480" height="480" loop="loop" x-webkit-airplay="" webkit-playsinline="" style="position: static; display: block; opacity: 1; left: 0px; top: 0px; height: 320px; width: 320px;"></video>

之后需要点击视频停止,可能会发现画面会闪动,在开始或者停止的时候,在美拍的app 里面找了大半天,发现是这个css 属性其作用的

body {
    -webkit-tap-highlight-color: rgba(0,0,0,0);
}

Strope 加入 MUC

引入两个js strophe.js strophe.muc.js

connection.muc.join("abc@conference.sand.chinacloudapp.cn",
    "15002",
    room_message,
    on_presence,
    on_roster, "000000");

发送消息

connection.muc.join("abc@conference.sand.chinacloudapp.cn", "15002", room_message, on_presence, on_roster, "000000");

openfire 的配置

nginx 反向代理配置


        location /http-bind {

            proxy_pass http://127.0.0.1:7070/http-bind/;

            proxy_buffering off;

            proxy_redirect off;

            proxy_read_timeout 120;

            proxy_connect_timeout 120;
       }

mongoDB 地理索引学习

t.location = {type: “Polygon”, coordinates: [ [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ] ] }

Polygon 类型的地理坐标是由两条线组成的,第一个数是外面的圈,第二个数组是在这个环里挖的洞洞,所以才嵌套2个数组的 coordinates: [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0],这样写是不行的会报错的”Can’t extract geo keys”

用ab测试的时候怎样使用 post 请求

ab -n 20 -c 5 -p post_data -v 4 -T 'application/x-www-form-urlencoded' http://hroch486.icpf.cas.cz/cgi-bin/echo.pl

其中 post_date 文件里面是你的 post 的内容,举个栗子,name=neal&age=18

Go 笔记

  1. 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private )。

  2. go get -u github.com/astaxie/beedb -u 参数自动安装依赖包

elixir 学习笔记

ex 是要编译的,exs 呢就不用,比如

elixir math.exs

在 module 里面

emac 学习记录

  • 选择目录 M-x ffap 直接打开,有点叼
  • M-x ido-mode 进入懒人模式
  • C-x k 杀掉 buffer
  • C-x-s 保存buffer
  • C-x-w 另存为

ansible

ansible 第一步是指定服务器 hosts

ansible -i hosts all -u yuntuo -a 'ls'

hosts 的内容

sample.cn

或者用 playbook ansible-playbook -i hosts test.yml palybook 内容

- hosts: all
  remote_user: yuntuo
  tasks:
    - command:  rvmsudo ruby /home/yuntuo/auto_install_wowza/wowza.rb

Wowza Plugin 获取 query string

public void onPublish(IMediaStream stream, String streamName,
    boolean isRecord, boolean isAppend) {
  postStreamStart(stream.getName());
  //String uri = stream.getQueryStr();
  //getLogger().info("***********" + uri);
  //IClient client = stream.getClient();
}

用日志文件恢复 mysql 的误操作

参见这篇文章

数据库操作真是危险,有备无患啊!!!

mysql 的数据文件默认在 /var/lib/mysql, 里面有类似 mysql-bin.00000X 的文件就是 mysql的日志了,先把日志文件转成 sql,然后导入就大功告成

mysqlbinlog --start-date="2013-10-01 00:00:00" --stop-date="2013-12-12 12:00:00" mysql-bin.000067 > da_nan_bu_si_bi_you_hou_fu.sql

Rails 测试入门

  1. 准备测试数据库

rake db:test:prepare

  1. 遇到的坑 以前的版本的 rspec 的 expect 的写法是 expect 不跟参数的,跟一个 block,新的是可以跟参数的

在 Rails 和 Node 之间共享 session

主要参考这篇文章

Rails 本身对 session 做了 Marshal.dump 和 Marshal.load,nodejs 做这部分就比较困难,所以就采用一个变通的方法在用户登录的时候给他的 cookie 里面设一个值,然后再用这个值做为一个 hash 的 key 和用户的信息一起放到 redis 里面,用户登出的时候再把这个值删掉就可以了

# app/controllers/application_controller.rb
def after_sign_in_path_for(resource_or_scope)
  #store session to redis
  if current_user
    # an unique MD5 key
    cookies["_validation_token_key"] = Digest::MD5.hexdigest("#{session[:session_id]}:#{current_user.id}")
    # store session data or any authentication data you want here, generate to JSON data
    stored_session = JSON.generate({"user_id"=> current_user.id, "username"=>current_user.screen_name, ... ...})
    $redis.hset(
      "mySessionStore",
      cookies["_validation_token_key"],
      stored_session,
     )
   end
end
 
def after_sign_out_path_for(resource_or_scope)
  #expire session in redis
  if cookies["_validation_token_key"].present?
    $redis.hdel("mySessionStore", cookies["_validation_token_key"])
  end
end

Rails 配置 mysql的远程链接

记录第一次配置 mysql 远程链接的问题,主要参考这篇文章

###1. 更改 mysql 配置

vi /etc/my.cnf

把文件里面的 skip-networking 去掉,这个是把监听端口禁止,当你根本不允许外部链接的时候可以用这个。

然后加入

bind-address=202.54.10.20

server-ip 要填的就是 mysql sever 所在的那台机器的 ip

###2. 重启 msyql

###3. 用 root 用户登录设置远程访问权限

 mysql -u root -p mysql
 mysql> CREATE DATABASE foo;
 mysql> GRANT ALL ON *.* TO bar@'10.5.1.3' IDENTIFIED BY 'PASSWORD';

这里需要说的是 10.5.1.3 是这你最终用来在远端登录 mysql client 的那台机器的 ip

###4. 配置防火墙规则 在这一步的时候要可以先把防火情停掉,

sudo /etc/init.d/iptables top

然后看看从远程的机器上的 mysql 客户端能不能连上来,

mysql --host=202.54.10.20 --user=mysql --port=3306 -p

不行的话返回头检查,可以的话在继续下面:

/sbin/iptables -A INPUT -i eth0 -s 10.5.1.3 -p tcp --destination-port 3306 -j ACCEPT

这句话是说接受 eth0 这个网卡上来自 10.5.1.3 的 对于 3306 这个端口的访问,如果加了 iptables 就连不上的话,就是 iptables 的规则有问题了,还是问题 google 吧

Wowza 的分布

现在应用情况是一个流发不出去,要大量的用户观看,这样的话就需要用到 liverepeater 把流分布出去。按照 liverepeater 的配置基本就可以了。需要注意的几点:

  • 如果要用 iphone 观看的话,在 liveorigin 的 LiveStreamPacketizers 要配置成
  
    cupertinostreamingpacketizer, smoothstreamingpacketizer, sanjosestreamingpacketizer
  

夏日乐悠悠

戴不戴?

不戴可以吗?戴了不舒服哎

不戴出了事我可不负责哦

戴了你就负责么?

ok

用 rspec 写测试

准备资料库 rake:test:prepare

Azure 的使用经验

  1. 上传文件到 blob 的根目录

在播放媒体的时候需要在根目录下放一个 crossdomain.xml 文件,访问地址类似 http://portalohdsvt7pcctrrrfv3.blob.core.chinacloudapi.cn/crossdomain.xml,这样的话要先在存储账户里面建立一个叫 ‘$root’ 的 container,然后上传文件到这个 contrainer 就可以了。

  1. Azure 单个虚拟机的出口带宽

azure是8个虚拟机在一个物理机上,公用一块千兆网卡,所以根据虚拟机的 (核心数 * 1000 / 8) 就是单个虚拟机的出口带宽

  1. Azure 增删endpoint 导致其他tcp链接中断一次

现在也没解决,所以有持续链接的应用可能收到影响