月度归档:2013年08月

吃自己的狗粮,用Dropbox Go SDK

获取appKey和设置回调地址

到这个页面https://www.dropbox.com/developers/apps 创建一个应用,应用的类型选择Dropbox API app,在这个页面还可以选择应用能访问的数据范围。

很重要的一点就是:应该只赋予应用最小权限,也就是只访问它自己创建的文件。

应用创建好后就可以在详细页面查看它的的App key,也就是下面要用的。

在应用的详细页面,还要设置授权后的回调地址,也就是“ OAuth redirect URIs ”的输入框,这个地址必须是合法的URL,哪怕是不存在的,也就是,可以设置成“https://127.0.0.1/oauth2/authorized”。

获取授权码

将上面得到的appKey和回调地址拼接成下面这样:
https://www.dropbox.com/1/oauth2/authorize?response_type=token&client_id=abc1234569XYZ&redirect_uri=https://127.0.0.1/oauth2/authorized

里面的client_id的值填appKey,redirect_uri填回调地址,把这个地址拷贝到浏览器打开,如果你还没有登录Dropbox,会提醒你登录,登录后大概是这样的界面:
vpsBak4coderbee

点击“允许”授权成功后,浏览器会调整,地址栏里的地址会变,拷出来大概是这样的:
https://127.0.0.1/oauth2/authorized#access_token=O_xxkdkdkdw2yeidikcppdfdoiffjj&token_type=bearer&uid=158130000

上面的access_token: O_xxkdkdkdw2yeidikcppdfdoiffjj就是代码要用的。

调用Go SDK

首先要把sdk clone回来: git clone https://github.com/wen866595/godropbox.git , 这条命令会把sdk拷贝到当前的godropbox目录下。


package main

import (
        "./dropbox"
        "fmt"
        "os"
        "flag"
)

var (
        tokens = map[string]string{
                "access_token": "you oauth2 access token",
                "token_type":   "bearer",
        }
)

func main() {
        flag.Parse()

        args := flag.Args()
        if len(args) < 2 {
                fmt.Printf("Usage: godropbox path/to/locale/file  /path/at/dropbox\n")
                return
        }

        oauth2 := &dropbox.OAuth2{AccessToken: tokens["access_token"], TokenType: tokens["token_type"]}

        dropboxApi := &dropbox.DropboxApi{Signer: oauth2, Root: "sandbox", Locale: "CN"}

        localePath, remotePath := flag.Arg(0), flag.Arg(1)
        _, err := dropboxApi.UploadByChunked(localePath, remotePath, 10485760, 8)   //  10485760表示一次上传的块大小为1M,对于大文件,这个值设得大点可以减少上传的次数。
        if err != nil {
                fmt.Printf("error msg: %s\n", err)
                os.Exit(1)
        } else {
                os.Exit(0)
        }
}

把上面的代码保存在main.go文件里面,放到godropbox目录下,到godropbox目录用 go build命令构建成一个可执行文件。在我的VPS上使用: ./godropbox path/to/locale/file /path/at/dropbox,效果还行。

以前用Java SDK写过一个上传的功能,文件上传完了还要很久才退出。

很佩服那些搞安全的人

今晚看了下博客的4xx访问日志,发现了这么几条有趣的记录:
scriptboy-scan

里面的路径:/testcopy-moved.txt, /testcopy.txt, /abctest/testcopy.txt, /\x22 + cnzz_protocol + \x22s22.cnzz.com/z_stat.php%3Fid%3D1000033072,这些路径都不是我的博客里的常规地址,怎么突然有人会去扫描这些路径呢?以前发现的一般都是扫描phpAdmin的。

再想想,记起来了,前面三个路径是我在前一篇博客里介绍我写的Dropbox Go SDK里的例子里有提到,而cnzz那个估计是人家发现我的站点使用cnzz的统计服务。

哈哈,真心佩服搞安全的人的耐心与细心!虽然前三个路径是Dropbox里的虚拟路径。

之前写博客搭建笔记和博客维护脚本时,贴了一些脚本,但没有把没有把所有细节贴出来,本来是想贴的,觉得太麻烦,也算是侥幸了。服务器的具体配置、细节还真不能乱透露,特别要小心无意中泄漏了。

最后,如果哪个大神已经拿下或准备拿下这个VPS时,我只能说:此地真无银三百两!

Dropbox Go SDK

把最近用Go写的 Dropbox SDK 发布到了 gihub上,有兴趣的可以参与、反馈。

地址: https://github.com/wen866595/godropbox

大多数接口都已实现,除了获取delta数据的,因为这个接口返回的JSON结构数据没法映射到Go的数据结构上。

一些示例:

 oauth2 := &oauth2.OAuth2{AccessToken: "you ouath2 access_token"}

 dropboxApi := &dropbox.DropboxApi{Signer: oauth2, Root: "dropbox", Locale: "CN"}

 accountInfo, err := dropboxApi.GetAccountInfo()
 if err != nil {
     fmt.Printf("error msg: %s\n", err)
 } else {
     fmt.Printf("account info: %v\n", accountInfo)
 }

 metadata, err := dropboxApi.GetFileMetadata("/")
 if err != nil {
     fmt.Printf("error msg: %s\n", err)
 } else {
     fmt.Printf("metadata: %v\n", metadata)
 }

 put, err := dropboxApi.PutFileByName("main.go", "dropbox", "/main.go")
 if err != nil {
     fmt.Printf("error msg: %s\n", err)
 } else {
     fmt.Printf("put: %v\n", put)
 }

 copyRef, err := dropboxApi.CopyRef("/main.go")
 if err != nil {
     fmt.Printf("error msg: %s\n", err)
 } else {
     fmt.Printf("copyRef : %v\n", copyRef)
 }

 revisions, err := dropboxApi.Revisions("/main.go")
 if err != nil {
     fmt.Printf("error msg: %s\n", err)
 } else {
     fmt.Printf("revisions : %v\n", revisions)
 }

 shares, err := dropboxApi.Shares("/main.go")
 if err != nil {
     fmt.Printf("error msg: %s\n", err)
 } else {
     fmt.Printf("shares : %v\n", shares)
 }

  media, err := dropboxApi.Media("/main.go")
  if err != nil {
      fmt.Printf("error msg: %s\n", err)
  } else {
      fmt.Printf("media : %v\n", media)
  }

  thumbnails, err := dropboxApi.Thumbnails("/IMG_20130613_121901.jpg")
  if err != nil {
      fmt.Printf("get thumbnails error msg: %s\n", err)
  } else {
      ioerr := ioutil.WriteFile("IMG_20130613_121901.jpg", thumbnails.DataByte, 666)
      if ioerr == nil {
          fmt.Printf("write image ok .\n")
      } else {
          fmt.Printf("write image error : %v\n", ioerr)
      }
  }

  copym, err := dropboxApi.Copy("/testcopy.txt", "/abctest/testcopy.txt")
  if err != nil {
      fmt.Printf("error msg: %s\n", err)
  } else {
      fmt.Printf("copym : %v\n", copym)
  }

  copym, err := dropboxApi.Copy("/testcopy.txt", "/abctest/testcopy.txt")
  if err != nil {
      fmt.Printf("error msg: %s\n", err)
  } else {
      fmt.Printf("copym : %v\n", copym)
  }

  move, err := dropboxApi.Move("/abctest/testcopy.txt", "/testcopy-moved.txt")
  if err != nil {
      fmt.Printf("error msg: %s\n", err)
  } else {
      fmt.Printf("move : %v\n", move)
  }

  createFolder, err := dropboxApi.CreateFolder("createFolder")
  if err != nil {
      fmt.Printf("error msg: %s\n", err)
  } else {
      fmt.Printf("createFolder: %v\n", createFolder)
  }

  deleted, err := dropboxApi.Delete("createFolder")
  if err != nil {
      fmt.Printf("error msg: %s\n", err)
  } else {
      fmt.Printf("deleted: %v\n", deleted)
  }

路由跟踪

traceroute

打印用于跟踪到网络主机的路由包。利用了IP协议的存活时间(time to live, TTL)字段和尝试引起到目的主机路径的每个网关的 ICMP TIME_EXCEEDED 响应。

Traceroute的工作原理(来自:http://www.cnblogs.com/peida/archive/2013/03/07/2947326.html

Traceroute最简单的基本用法是:traceroute hostname
Traceroute 程序的设计是利用ICMP及IP header的TTL(Time To Live)栏位(field)。首先,traceroute送出一个TTL是1 的IP datagram(其实,每次送出的为3个40字节的包,包括源地址,目的地址和包发出的时间标签)到目的地,当路径上的第一个路由器 (router)收到这个datagram时,它将TTL减1。此时,TTL变为0了,所以该路由器会将此datagram丢掉,并送回一个 「ICMP time exceeded」消息(包括发IP包的源地址,IP包的所有内容及路由器的IP地址),traceroute 收到这个消息后, 便知道这个路由器存在于这个路径上,接着traceroute 再送出另一个TTL是2 的datagram,发现第2 个路由 器...... traceroute 每次将送出的datagram的TTL 加1来发现另一个路由器,这个重复的动作一直持续到某个 datagram 抵达目的地。当datagram到达目的地后,该主机并不会送回ICMP time exceeded消息,因为它已是目的地了,那么 traceroute如何得知目的地到达了呢?
Traceroute 在送出UDP datagrams到目的地时,它所选择送达的port number 是一个一般应用程序都不会用的号码(30000 以上),所以当此 UDP datagram 到达目的地后该主机会送回一个「ICMP port unreachable」的消息,而当traceroute 收到这个消 息时,便知道目的地已经到达了。所以traceroute 在Server端也是没有所谓的Daemon 程式。
Traceroute提取发 ICMP TTL到期消息设备的IP地址并作域名解析。每次 ,Traceroute都打印出一系列数据,包括所经过的路由设备的域名及 IP地址,三个包每次来回所花时间。
     

继续阅读

门后的秘密-卓越管理的故事 笔记

第1周 了解部门成员和工作

卓越的管理所包含的工作内容是:领导和培养员工并管理工作任务。

当你进入一个新的组织或开始新的工作时,首先要知道三件事:

  • 这些人是谁,他们的优点和兴趣是什么,他们正在从事什么工作;
  • 团队的既定任务以及该团队如何产生价值;
  • 你的团队是如何与整个组织机构相契合的。

一对一会面

管理,因人而异。

一对一会面是辅导工作、听取回馈、进行职业培训和工作进度汇报的重要渠道。

  • 为每周的会面确定固定时间;
  • 会面礼仪,免谈时不做与会面无关的事情;
  • 真诚地会面;
  • 保持会谈的惯有形式;
  • 变通。根据不同的人变通管理方式,公正地对待各种情况。

会面时间不要过长。

与人打交道就是管理工作。

如果做不到,就不要主动提供帮助。
继续阅读

Disruptor 源码阅读笔记

一、Disruptor 是什么?

Disruptor 是一个高性能异步处理框架,也可以认为是一个消息框架,它实现了观察者模式。

Disruptor 比传统的基于锁的消息框架的优势在于:它是无锁的、CPU友好;它不会清除缓存中的数据,只会覆盖,降低了垃圾回收机制启动的频率。

这个解读是在最新版 3.1.1 的源码上进行。

关于Disruptor的更多介绍可见: http://ifeve.com/disruptor/

二、Disruptor 为什么快

  • 不使用锁。通过内存屏障和原子性的CAS操作替换锁。
  • 缓存基于数组而不是链表,用位运算替代求模。缓存的长度总是2的n次方,这样可以用位运算 i & (length - 1) 替代 i % length

  • 去除伪共享。CPU的缓存一般是以缓存行为最小单位的,对应主存的一块相应大小的单元;当前的缓存行大小一般是64字节,每个缓存行一次只能被一个CPU核访问,如果一个缓存行被多个CPU核访问,就会造成竞争,导致某个核必须等其他核处理完了才能继续处理,响应性能。去除伪共享就是确保CPU核访问某个缓存行时不会出现争用。

  • 预分配缓存对象,通过更新缓存里对象的属性而不是删除对象来减少垃圾回收。

继续阅读

tcpdump

tcpdump是Linux内置的一个抓包工具,用于对网络上的数据包进行截获、分析的工具。

完整命令格式

       tcpdump [ -AbdDefhHIJKlLnNOpqRStuUvxX ] [ -B buffer_size ] [ -c count ]
               [ -C file_size ] [ -G rotate_seconds ] [ -F file ]
               [ -i interface ] [ -j tstamp_type ] [ -m module ] [ -M secret ]
               [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]
               [ -W filecount ]
               [ -E spi@ipaddr algo:secret,...  ]
               [ -y datalinktype ] [ -z postrotate-command ] [ -Z user ]
               [ expression ]

继续阅读

Nginx与Apache 之间的 HTTP 400错误

魅影危机

有同事今天碰到的一个问题:用户访问公网的Nginx服务器,Nginx再把用户请求转发到内网的Tomcat服务器的80端口,现在内网Tomcat服务器的应用想拆分,不同应用用不同的Tomcat来运行,这样就在内网配置了一台Apache(不方便改Nginx的转发规则,那个Nginx是别人弄的),根据应用的url转发到对应的Tomcat。出现的问题是:从公网访问Nginx出现HTTP 400错误,从Apache访问日志可以看到,请求是过来了,但没转发给后端的Tomcat,Apache直接返回400;如果Nginx直接转发到Tomcat也是可以的,从内网通过Apache访问Tomcat也是可以的。

所以问题应该是Nginx到Apache的请求有问题。这个同事知道我以前配置过Nginx,所以找我要Nginx转发到Tomcat的配置。

在本地测试机上,Nginx的转发配置都没问题,从 Nginx --> Tomcat 或者 Nginx --> Apache --> Tomcat 都没问题。

没辙,我只好回自己工位去google。
继续阅读

动态规划 笔记

一、引题

在一个N行M列的二维数组vec,每个元素位置放置一定数量的苹果,从底部开始往顶部走,每一步只能按 正前方、正前方左45度(如果左边还有位置)、正前方右45度(如果右边还有位置) 三种方式前进,起点可以是底部的任意一个位置,终点也可以是顶部的任意一个位置,求一条路径,使得按这条路径走过时能收集到最多的苹果。

分析

结果是要找出一条路径,使得按这条路径走时能收集到最多的苹果,这是找最优结果的问题。这样的路径当然没法一眼就看出来,可以随便画一条路径,但没法证明这条路径能得出最优结果。

那么能不能假设一个点vec[i][j],这个点是最优路径上的一个点。尽管现在还不能证明vec[i][j]肯定处于最优路径上,但我们就是假设它是(这是动态规划的分析的一个特点)!

cc[i][j]表示达到点vec[i][j]时能收集到的最多苹果数。按照题目的要求,如果vec[i][j]不是处于最底行,那么到达vec[i][j]最多有三种走法:

  1. 如果左上方还有位置,从vec[i-1][j-1]向右前方前进一步。
  2. 从vec[i-1][j]按正前方前进一步。
  3. 如果右上方还有位置,从vec[i-1][j+1]向左前方前进一步。

图示:
dynamic-programming-apple-select

要在vec[i][j]收集到最多苹果,当然是从它的三个来源中选一个能收集到最多苹果的节点作为vec[i][j]在最优路径上的前一个节点。那么在vec[i][j]上收集到的苹果数为:
cc[i][j] = vec[i][j] + max{ cc[i-1][j-1] if j-1>=0, cc[i-1][j], cc[i-1][j+1] if j+1 < M } if i-1 >= 0

继续阅读