网络寻租

Programmer, Gamer, Hacker

手机远程收听电脑声音

| Comments

我现在笔记本的声音都通过耳机输出,耳机有几个不好的地方,就是每次我离开电脑去上厕所或者干什么事情的时候,都要把耳机拔出来,非常不方便, 我想如果能够把声音换到手机上面,这样挺不错的。我的电脑是rMBP,手机是google galaxy手机。

我搜索到了一些解决方案:

我测试了Airfoil和iPlay的方案,都可以用,Airfoil如果要获取系统声音,需要重新启动电脑比较麻烦。并且价格也比较贵,iPlay的方案看起来比较适合我。 不过如果你是其他操作系统或者希望更多特性的话,Airfoil比较好。 不过最后我一个方案都没有用成,因为声音同步需要带宽100KB的上下行,我的无线路由器撑不住了。。

关于独立游戏

| Comments

我是一个游戏爱好者。从初中起我就在玩电脑游戏,一直持续到现在。初中到大学阶段我一直是以PC游戏为主,最近几年我渐渐转移到了独立游戏上面。

为什么我喜欢独立游戏

  • 我喜欢去接触各种新的领域,厌烦没有新意的东西。在独立游戏领域,会有更多人尝试新的游戏性,设计性的东西出来。
  • 独立游戏一般不会是大制作,游戏占用的硬盘空间不会很大,容易下载容易保存。
  • 独立游戏价格一般不会很高,我能够承受得起,并且能够购买相当数量的游戏。

我玩的一些独立游戏

Mosh介绍

| Comments

image

这年头做技术没有人不用ssh的吧,然后ssh使用起来还是很不爽的, 远程服务器慢的时候反应慢,ssh有的时候断掉要重新连。。。

mosh是ssh的替代方案,用来解决慢速网络和移动网络的问题,具体上来说:

  • 连上一台服务器后,不管你切换什么网络,或者网络断掉,或者机器休眠又醒过来,连接都能够一直保持。
  • 缓存输入输出,当连接慢的时候,屏幕上面显示的响应还是很快。

强烈建议大家都去用它。

原理

mosh它实现了一套自有的状态同步协议SSP:

  • 底层采用UDP,client和网络解耦合,
  • 内部client和server都维护到屏幕和输入的状态,根据状态发送diff/patch。
  • 再在上层加上一个预测模块,根据用户输入先在本地显示预期的输出结果,收到远程服务器返回的屏幕数据,再更新。

作者同时也提出,现在的应用往往没有针对移动作优化,如果一个用户切换了网络(比如正在移动中), 那么tcp连接断掉会出现各种问题,在这种场景下,SSP这种解决方案会很有用处。

建议大家可以看看mosh首页的视频,作者介绍得很充分。

使用

大家去看首页的介绍就好。这里整理一些我觉得需要提到的:

mosh首先通过ssh连进去,然后开启一个mosh server,端口随机在60000:61000,如果你开了防火墙需要允许这个范围。

指定ssh参数,比如你的ssh端口不是22:

1
mosh $server --ssh='ssh -p 2222'

当你在网络断开的时候,关掉了mosh的进程,远程服务器上面对应的server进程会一直存在, 这个时候重新连上去的时候,就会提示你。这个时候你需要手动kill掉这个进程, 具体见issue报告

Squeel介绍

| Comments

squeel是Rails下面一个处理复杂sql查询的框架, 具体用法可以点击前面的链接查看,这里整理一下我对这个东西的评估。

为什么要用它?

平时我们在rails里面,需要写复杂查询的时候,一般都是直接写sql,比如:

1
2
3
4
Person.where(
  '(name LIKE ? AND salary < ?) OR (name LIKE ? AND salary > ?)',
  'Ernie%', 50000, 'Joe%', 100000
)

这样的写法不是很好,因为:

  • 里面的sql是只针对一个数据库的,不能做到数据库的切换。
  • 里面的sql在ruby里面是字符串,一个是可读性差,一个是不能进行语法上面的检查,只能通过单元测试来保证。
  • 写这样语句的时候,需要切换成sql的思路,写完之后再切换回来。
  • 遇到复杂sql的时候,不容易拆分问题,只能通过大段长度的sql来处理。

采用squeel,就可以变成这些的写法:

1
Person.where{(name =~ 'Ernie%') & (salary < 50000) | (name =~ 'Joe%') & (salary > 100000)}

原理

squeel使用的方法是传一个block给where,然后这个block会被修改作用域,在这个作用域里面, 各种操作符和变量都会被转义,变成Node对象,然后形成一个抽象语法树,最后通过底层的arel变成真正执行的sql。

具体代码比较重要的是dsl.rb里面的evalmethod_missingstub.rbvisitor.rb

我思考了一下,这种方法应该是最简洁和干净的,语法是采用ruby的方式,魔法的部分都被包裹在block里面,和现有的功能无缝衔接。

使用心得

如果明白原理,使用它没有什么太多的问题,需要注意的是, 一定要看一遍log里面生成的sql,确认是自己期望的结构。

还有就是,squeel和原有系统切割得比较好,只有一点需要注意: 针对User.where(name: :aaa)里面把symbol当做value的状况,squeel会转变成:

1
select * from users where users.name == users.aaa

这是一个特性,如果你不期望这样的话,需要改成where(name: :aaa.to_s)。也可以关闭,具体看squeel的文档。

在我用的过程中,遇到几个问题:

  • 我直接用orand,结果发现按照文档应该是用|&,使用任何东西之前还是需要认真看一遍文档。
  • 复杂查询条件下面,如果用到了|&,为了保证是按照自己期望的优先级分割,需要用括号来明确界定,比如where{(name == 'aaa' | name == 'bbb') & (level == 1)}
  • 上面提到的symbol当做value的bug。
  • 因为使用了作用域切换,对象属性等就不能访问了,比如where{name == @user.name},需要改成where{name == my{@user.name}}

结论

考虑一下是否需要采用squeel:它的学习成本应该只需要一个小时,性能问题可以通过cache来解决,可以无缝衔接,收益是更清晰,更一致,更好用的代码。

试用gitlab

| Comments

image

今天我试着安装了一下gitlab,它是一个开源的类似github的系统, 利用它可以本地搭建一个github网站出来。可以解决一些需要客制化代码库,或者私有化管理的需求。

安装过程

按照文档进行,我中间走了一些弯路:

  • 安装ruby的时候,我是采用rvm,而不是教程里面的采用系统ruby,后来发现不对,必须安装成系统的版本,不然服务起不起来。
  • postgres用户gitlab不能登陆,后来搜索了一下,发现需要修改权限

其他过程比较顺利,基本按照教程来就可以了。

架构

其实整体系统还是比较简单的,安装了一个系统服务,后面主要是把gitlab当做一个rails应用来跑,后台启动了一个sidekiq。

针对git的部分,分离出来了git-shell,其实就是在系统里面安装了一个shell,用户用git连过来的时候,就用这个shell来进行版本库的操作,它是调用rails网站服务器的API来做权限管控之类的事情。

试用感觉

因为我只是试用一下,没有用于生产,只是稍微浏览了一下功能。 github有的功能它都有,还加上了用户管理,群组管理,查看系统日志等功能。 功能上面感觉还是够用的。

关于这个项目的架构思路,我觉得还是挺好的。 网站的部分归网站,git的部分归git,中间通过API来通讯。 git-shell的方式减少另外跑一个服务的成本,对于小用户群的环境来说可以, 但是不是很适应用户数量过多的状况,但是场景不多,问题不大。 不过需要安装系统的ruby环境倒是挺麻烦的,希望他们以后针对这个问题提出改进方案。

Pow介绍

| Comments

image

Pow是一个神奇的东西,原先你需要跑一个服务器应用,你可能需要在命令行下面执行一个命令,以及你自己需要时刻监控到这个程序的运行。但是有了POW,你需要做的事情只是做一个ln软链接就可以了。对了,它只能在OSX下面使用。

安装:

1
curl get.pow.cx | sh

删除:

1
curl get.pow.cx/uninstall.sh | sh

如果你需要设置一个基于Rack的应用,你需要做的是:

1
2
cd ~/.pow
ln -s /path/to/myapp

就是这么简单。

原理

  • Pow把目录当做Rack应用来执行,目录主要含有config.ru配置文件和public静态文件目录。
  • 在访问到目录的时候,它自动创建一个worker,最多每个应用2个worker,15分钟没有请求后自动回收。

一些特性整理

  • 链接到~/.pow里面的目录比如myapp会映射到http://myapp.dev/
  • www.myapp.dev这种子域名都会映射到myapp.dev,除非你重新创建一个www.myapp目录。
  • ~/pow多个软链接到同一个目录,只会生成一个worker。
  • 如果没有myapp,访问myapp.dev会给出提示。
  • Pow支持端口转发功能,只要echo 8080 > ~/.pow/proxiedapp,访问proxiedapp.dev就是访问本地端口8080。
  • Pow支持只含有public目录,直接serve静态文件。
  • 重新启动服务:touch tmp/restart.txt,或者直接杀掉进程就好了。会重新加载环境。
  • 每次访问都重启服务:生成这个文件:tmp/always_restart.txt。但是它不会重新加载环境。
  • log放在~/Library/Logs/Pow里面。
  • 重启Pow:touch ~/.pow/restart.txt

设置

Pow启动前会去执行目录下.powrc.powenv这2个脚本。

如何设定ruby版本?

  • rbenvrbenv local 1.9.3-p194
  • 用rvm,添加.rvmrc:rvm 1.8.7 因为rvm需要加载环境变量,你需要修改上面的2个脚本之一: sh if [ -f "$rvm_path/scripts/rvm" ] && [ -f ".rvmrc" ]; then source "$rvm_path/scripts/rvm" source ".rvmrc" fi
  • 或者直接设置PATH就好了。

FAQ

手动设置软链接太烦了,有什么方便的方法?

有的。 gem install powder,cd到你应用的目录,然后执行:

powder link

文档在这里

如何让局域网的其他人访问到这个服务?

xip.io,它是一个把网络地址转换到具体IP的服务,方便进行一些调试。 比如你的ip是10.0.0.2,用Pow跑的服务是app,那么同一个局域网的人就可以用app.10.0.0.2.xip.io来访问你的服务。

如何让外网的其他人访问到这个服务?

forward

资料

给Rails加上https支持

| Comments

https是针对http的加密协议,它可以保证用户访问网站的过程中,通讯的数据是加密的,这样可以防止第三方监听,保护用户隐私。这里总结一下如何给Rails加上https的支持。

首先,假设你的rails已经跑起来了,在http://yourserver.com,服务器是ubuntu,本地的访问方式是127.0.0.1:8787,那么你需要利用nginx来提供https的服务。

首先安装nginxopenssl

sudo apt-get install nginx openssl

生成服务器的秘钥公钥:

openssl req -new -nodes -keyout server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

生成的几个文件解释:

  • server.key 服务器的私钥。
  • server.csr (certificate signing request) https证书签名请求。
  • server.crt 生成的服务器证书。

然后有这些文件,我们可以配置nginx服务了。

生成nginx的配置文件:

sudo touch /etc/nginx/sites-available/yourserver
sudo ln -s /etc/nginx/sites-available/yourserver /etc/nginx/sites-enabled
sudo vi /etc/nginx/sites-available/yourserver

里面的内容:

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
upstream unicorn {
  server 127.0.0.1:8787 fail_timeout=0;
}
server {
  listen       443;
  server_name  yourserver.com;
    
  ssl                  on;
  ssl_certificate      yourpath/server.crt;
  ssl_certificate_key  yourpath/server.key;
    
  ssl_session_timeout  5m;
    
  ssl_protocols  SSLv2 SSLv3 TLSv1;
  ssl_ciphers  HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers   on;
    
  location / {
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto https;
      proxy_redirect off;
      proxy_pass http://localserver;
  }
}

需要修改里面的server_name,yourpath

然后重新启动nginx:

sudo service nginx restart

如果没有报错,那么你就可以通过https://yourserver.com来访问你的网站了。

不过,浏览器会阻止你继续访问,或者需要你的确认。 浏览器会保存一份可信网站的列表,你的服务器加密是自己生成的,不在里面。 如果你的网站是商用的,最好去注册一下。这里有一个指引。

引用资料:

Install ruby2.0 by Using Rvm

| Comments

According to the NEWS, ruby 2.0.0-p0 is released in February. With the performance improvement, lower memory usage, feature enhancement, and back support to 1.9.3, Everyone is encouraged to upgrade to ruby2.0.

And here is the method about how to upgrade ruby under rvm:

rvm get head
rvm install 2.0.0
rvm use 2.0.0

Happy hacking, and keep fun~

Display Image After It Is Downloaded

| Comments

It is very annoying when you see a image is loading in a webpage:

Lots of website support this kind of effect to get rid of this. when the image is loading, it is displaying a “loading” effect, like this:

So how can we implement it to our website? The method is simple:

  1. Display a loading gif, and hide the image.
  2. After image loaded, hide gif, and display image.

We can use JQuery load method here to add a callback to do the things in step 2 above. Use this html:

1
2
3
4
5
<img class="loading_image" data-src="/images/demo.png">
...
<div class="resources">
  <img class="image_loader" src="loader.gif">
</div>

add run init_loading_image javascript list below. It is written in coffeescript:

1
2
3
4
5
6
7
8
9
10
window.init_loading_image = ()->
    $('.loading_image').each ->
        self = $(this)
        loader = $('.resources .image_loader').clone()
        loader.insertBefore(self)
        self.load ->
            self.prev().hide()
            self.addClass('show')
        self.attr('src', self.data('src'))
$(init_loading_image)

For each .loading_image, place a loader gif in front of it. I set the image to opacity 0.0, so the image is downloading, and user will not see this image. after image loaded, hide the gif, and show the image.

The css is list below. I’m using sass + compass for clearer css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.resources
  display: none
.loading_image
  +opacity(0.0)
  &.show
    +opacity(1.0)
    +transition-property(opacity)
    +transition-duration(0.3s)
.image_loader
  position: absolute
  top: 50%
  left: 50%
  margin-top: -6px
  margin-left: -22px
  width: 43px
  height: 11px

Very simple process, you can see the demo here.

Rails里面拆分大的model

| Comments

有的时候,rails里面一个model的工作太多,在一个文件里面都放不下了,于是我需要拆分出不同的模块。我的拆分方法是这样的:

user.rb里面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class User < ActiveRecord::Base

  def self.has_module name
    eval "
    define_method :#{name} do
      @#{name} ||= User#{name.to_s.camelize}.new(self)
    end
    "
  end

  has_module :account
  has_module :displayer
  has_module :privacy
  has_module :message

end

然后对应的职责模块:

1
2
3
4
5
6
7
8
9
10
11
class UserDisplayer

  def initialize user
    @user = user
  end

  def address
    "#{@user.city}#{', ' unless @user.city.blank? or @user.country.blank?}#{@user.country}"
  end

end

然后调用的方式:

1
2
user = User.find 5
user.displayer.address

当用到对应模块的时候,才会加载该模块。

原先我考虑过采用concerns,但是看起来只是把代码移动到另外的地方去, 当需要调试的时候很不方便,不知道代码放到哪里了。所以不觉得好用。

大家有什么看法?