博客

  • 创建一个node typescript项目

    创建一个node typescript项目

    最近开始学习typescript,首先要解决的就是创建一个项目,功能也不要求太多,必须要什么特别的功能,只是需要ts编译,文件变动监控,最好带一个tslint。

    一般的套路自然是用yeoman,找了一圈,很多generator要不就是几年不维护,要不就是功能太多,最后选择的是generator-node-typescript。生成带gulp的项目,结构如下:

    这个脚手架生成出来的项目自带了tslint,也有自动监控变动的编译,总的来说能够用。

    但是我还有两个需求,一个是能够自动运行生成出来的脚本,这个运行本身能够自动重启,第二个是能够在开发阶段跳过tslint,开发阶段代码比较随意,很多实验性的,tslint很难过,还要兼顾两头去修复。

    第一个自动运行的需求可以用nodemon 它一方面可以将程序的输出打在console里面,一方面可以自动监控择机重启。

    var nodemon = require('gulp-nodemon');
    
    gulp.task('run', ['watch'], function () {
      nodemon({
        script: 'lib/index.js',
        watch: 'lib/'
      })
    });

    第二个需求可以用gulp-mode,定义两种模式,一种是dev,一种是prod。而tslint只在prod环境运行。也就是gulp –prod

    var mode = require('gulp-mode')({
      modes: ["prod", "dev"],
      default: "dev",
      verbose: false
    });
    
    gulp.task('lint', 'Lints all TypeScript source files', function () {
      return gulp.src(tsFilesGlob)
        .pipe(tslint({
          tslint: tslintCustom,
          formatter: 'verbose'
        }))
        .pipe(mode.prod(tslint.report()));
    });

     

  • 在Travis中集成libGDX项目

    之前Github放了一个例子,版本很老,是0.9.8的,后面1.x时代有一天突发奇想又去升级了一下,升级到了1.5.6。

    今天突然有人又问到这个了,就顺手升级到1.9.5。测试了一下桌面环境是工作的,不过android环境不太想测试了,就寻思着集成一下Travis来测试一下,因为项目本身没有单元测试,所以测试的要求也不高,一是能编译通过,生成apk包,二是能够apk能够安装。

    Travis是自带了android支持的,不过还是beta版,说实话beta版果然坑多。

    首先来个简单的.travis.yml 文件

    language: android
    
    android:
      components:
        - build-tools-23.0.1
        - android-24

    然后报错说找不到android-24。马上检查了一下本地的android sdk,有这个版本号。

    然后网上找了一下方案,原来默认最高支持就到23,要支持高版本需要这样

    language: android
    
    android:
      components:
        - tools
        - tools
        - build-tools-23.0.1
        - android-24

    这个的tools必须重复两遍,一次拉取最新的xml,一次才是真正的安装。

    这样之后可以生成apk了,再来试试安装apk吧。

    思路很简单:创建一个模拟器,然后启动,最后安装即可。Travis自带了一个命令android-wait-for-emulator 来等待模拟器启动。

    在components里面声明– sys-img-armeabi-v7a-android-24 然后添加

    after_script:
        - echo no | android create avd --force -n test -t android-24 --abi armeabi-v7a
        - emulator -avd test -no-audio -no-window &
        - android-wait-for-emulator
        - adb shell input keyevent 82 &
        - adb devices
        - adb install -r android/build/apk/android-release-unsigned.apk

    然而调用Travis自带的等待命令的时候报错qemu-system-armel: -audio: invalid option 。

    只好换回老版本,22来启动模拟器

    after_script:
        - echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
        - emulator -avd test -no-audio -no-window &
        - android-wait-for-emulator
        - adb shell input keyevent 82 &
        - adb devices
        - adb install -r android/build/apk/android-release-unsigned.apk

    然后,它就卡着不动了。一直是等待启动中…

    仔细检查日志,还是版本问题,没有安装API 22,所以镜像没有安装成功,实在没法,还是放弃24,使用22编译即可。

    language: android
    
    android:
      components:
        - build-tools-23.0.1
        - android-22
        - sys-img-armeabi-v7a-android-22
    after_script:
        - echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
        - emulator -avd test -no-audio -no-window &
        - android-wait-for-emulator
        - adb shell input keyevent 82 &
        - adb devices
        - adb install -r android/build/apk/android-debug.apk

    PS:这个集成方法的思路没有问题的,不过这个项目改来改去apk的生成估计已经有问题了,又或者Travis的环境还是有什么其他问题,所以会报错Invalid APK file,不过本地安装有时候又会成功。

  • 全站开启https

    申请了一个StartSSL的证书把全站https开启了,刚刚弄好,突然看到一条新闻说StartSSL证书有问题,一些基金会要移除它的根证书。

    只有赶紧换一套证书,看了一下let’s encrypt比较简单,马上本地安装let’s encrypt客户端,十秒获得全套证书,当然还有续期的问题,不过这个可以后面处理。

    具体的配置直接使用Mozilla SSL Configuration Generator生成一个,然后ssllabs的分析器测试一下。

    ssl

     

  • HashiCorp Vault简介

    HashiCorp Vault简介

    HashiCorp Vault是一个私密信息管理工具。

    我其实很反感那种中英文交杂的文章,但是很多时候很难找到合适的中文词语。这里特别说明一下,Vault的英文定位是A tool for managing secrets,本文用私密信息指secrets。 (更多…)

  • Spring Boot配置文件乱码的问题

    Spring Boot配置文件乱码的问题

    Spring Boot对于配置文件的支持非常完善,在配置文件中的内容可以很方便的在程序中应用。在配置文件中可能会出现中文的情况,而这个也是一个可能出现乱码的地方。

    首先Spring Boot支持两大类配置文件,一类是java properties文件,即application.properties文件;一类是yaml文件,即application.yml文件。

    这两种配置文件分别使用PropertiesPropertySourceLoader 和YamlPropertySourceLoader加载。这两种加载器对于编码的处理是不同的。

    PropertiesPropertySourceLoader 会首先检查配置文件后缀,如果是xml文件,那么是可以支持UTF-8的,但是如果是非xml文件,那么它调用的实际上是java的Properties类的load方法,而这个方法默认配置文件的编码是ISO 8859-1的。参考下面的Java API文档:

    The load(Reader) / store(Writer, String) methods load and store properties from and to a character based stream in a simple line-oriented format specified below. The load(InputStream) / store(OutputStream, String) methods work the same way as the load(Reader)/store(Writer, String) pair, except the input/output stream is encoded in ISO 8859-1 character encoding. Characters that cannot be directly represented in this encoding can be written using Unicode escapes as defined in section 3.3 of The Java™ Language Specification; only a single ‘u’ character is allowed in an escape sequence. The native2ascii tool can be used to convert property files to and from other character encodings.

    可以看到这里提供了一个选项,如果不是ISO 8859-1编码的,那么就需要使用Unicode escapes。

    YamlPropertySourceLoader 专门针对yaml格式,调用的是org.yaml.snakeyaml.Yaml实现,默认是支持utf-8的。

    所以综上所述,如果遇到Spring Boot配置文件中文乱码的有两个选项:

    1. 使用Unicode escapes
    2. 使用yaml格式或者xml格式
  • Severless简介和服务提供商对比

    Severless简介和服务提供商对比

    什么是Serverless

    Serverless最初是用于描述依赖第三方服务实现对逻辑和状态进行管理的应用。典型的包括“厚客户端”(例如单页Web应用、移动应用),他们一般都使用基于云端的数据库(例如Parse、Firebase),认证服务(Auth0、AWS congnito)等。这类服务以前被称为”(Mobile) backend as a Service ”,又称BASS。

    Serverless也可以指这样的应用,一部分服务逻辑由应用实现,但是跟传统架构不同在于,他们运行于无状态的容器中,可以由事件触发,短暂的,完全被第三方管理。这种思路是’Functions as a Service/FaaS’,AWS Lambda是目前唯一大规模商用的Serverless提供商。

    Serverless不是什么

    Serverless不代表完全去除服务器,而是代表去除有关对服务器运行状态的关心和担心,它们是否在工作,应用是否跑起来正常运行等等。Serverless代表的是你不要关心运营维护问题。

    Serverless不代表某个具体技术,虽然有框架或者工具名字叫Serverless;Serverless其实去除维护的担心,如果你了解某个具体服务器技术当然有帮助,但不是必须的。

    Serverless中的服务或功能代表的只是微功能或微服务,Serverless是思维方式的转变,从过去构建一个框架运行在一台服务器上,对多个事件进行响应变为构建或使用一个微服务或微功能来响应一个事件。Serverless并不任何语言绑定,虽然不同厂商对于语言的支持各有不同,但是也有一些基于Docker的Serverless平台,原理上是跨语言的,比如IBM openwhisk和UCloud UGC。

    Serverless服务提供商

    很明显,Serverless是厂商绑定的,因为并没有公认的标准,所以不同厂商提供的服务各有不同。这里是简单整理的一个表格,仅供参考。

    不过不得不说虽然有不同的提供商,但是真的能够进入实际使用的恐怕只有AWS Lambda一家。

    serverless-funciton-providers

  • Apache Spark

    Apache Spark

    spark-logo-trademark

    Apache Spark是一个围绕速度、易用性和复杂分析构建的大数据处理框架。最初在2009年由加州大学伯克利分校的AMPLab开发,并于2010年成为Apache的开源项目之一。

    Spark推出时的一个特点是快,对比的对象自然是Hadoop。

    Hadoop这项大数据处理技术大概已有十年历史,而且被看做是首选的大数据集合处理的解决方案。MapReduce是一路计算的优秀解决方案,不过对于需要多路计算和算法的用例来说,并非十分高效。数据处理流程中的每一步都需要一个Map阶段和一个Reduce阶段,而且如果要利用这一解决方案,需要将所有用例都转换成MapReduce模式。

    而Spark则允许程序开发者使用有向无环图开发复杂的多步数据管道。而且还支持跨有向无环图的内存数据共享,以便不同的作业可以共同处理同一个数据。

    Spark的目的并不是代替Hadoop,相反Spark是可以运行于Hadoop之上的,包括了使用Hadoop文件系统,Yarn调度器等等。

    Spark之上还有四个模块,分别对应了SQL,Streaming,ML还有Graph。spark-stack

    Spark近期的发力方向主要在于Machine Learning的Pipeline模式之上。

    这种设计理念将机器学习统一抽象为由DataFrame,Transformer,Estimator和Parameter组成的Pipeline,并提供了大量可以重用的组件。ml-pipeline

    Spark提供了多种语言的API,你可以使用Scala,Java,Python或者R来开发你自己的应用。

  • 停止词和StopWordsRemover

    停止词简单来说是指在一种语言中广泛使用的词。在各种需要处理文本的地方,我们对这些停止词做出一些特殊处理,以方便我们更关注在更重要的一些词上。

    对于不同类型的需求而言,对停止词的处理是不同的。

    1. 有监督的机器学习 – 将停止词从特征空间剔除
    2. 聚类– 降低停止词的权重
    3. 信息检索– 不对停止词做索引
    4. 自动摘要- 计分时不处理停止词

    对于不同语言,停止词的类型都可能有出入,但是一般而言有这简单的三类

    1. 限定词
    2. 并列连词
    3. 介词

    停止词的词表一般不需要自己制作,有很多可选项可以自己下载选用。

    Spark中提供了StopWordsRemover类处理停止词,它可以用作Machine learning Pipeline的一部分。

    StopWordsRemover的功能是直接移除,所有从inputCol输入的量都会被它检查,然后再outputCol中,这些停止词都会去掉了。

    默认的话会加载/org/apache/spark/ml/feature/stopwords/english.txt

    这是一个简单的停止词表,包含153个词。

    默认还提供了其他几种语言的停止词,遗憾的是没有中文默认停止词表,所以对于中文停止词需要自己提供。

  • AWS Lambda和持续交付pipeline

    为了让更多的事情自动化,并且能够持续的交付和发布新的功能,一个顺手的Pipeline是必要的。

    如果是自己维护的持续交付pipeline,那么大部分都是Jenkins。如果是不自己维护的,那选择就太多了,从Travis CI, Circle CI 到Snap CI选择丰富,而且很多也提供了收费服务。

    我们以一个Spring Boot的Web项目为例,一般情况下这个pipeline需要以下几个必要的步骤:

    pipeline

    其中发布到各种环境的操作大体为以下几个步骤:

    1. 停止运行原有jar文件
    2. 拷贝新的jar文件和必要的其他文件到运行环境
    3. 重新运行jar文件
    4. 测试是否正常启动

    如果同样一个项目采用无服务器架构,即serverless模式,那么多半使用的使用AWS Lambda。

    对于这种情况再对比我们的pipeline,其实很明显,需要改变的只有最后两个步骤lambda-pipeline

    发布步骤如下:

    1. 准备必要的zip包(这一步可以再编译项目环境就完成)
    2. 上传zip包到aws lambda
    3. 执行lambda并测试结果

    所以我们的问题叫变成了

    1. 如果在pipeline中更新AWS Lambda function的代码
    2. 如何调用lambda并测试结果

    更新AWS Lambda function代码

    由于AWS Lambda function并不能直接触发,而是需要一个触发器来执行,这里的触发器是API Gateway,通过API Gateway将所有Lambda function暴露出去。

    那么更新代码就涉及到一个问题,如果添加一个新的Endpoint(假定我们要实现一个新的功能,这个功能之前没有),那么API Gateway中就需要新增一个对应的配置,这个配置是手动的,还是自动的。

    只更新代码不涉及触发器

    如果是手动的,那么我们就可以假定所有发布实质上只是代码包的更新,这种情况下我们可以直接简单的调用AWS API即可,没有必要使用第三方的库或者工具了。

    PUT /2015-03-31/functions/FunctionName/code HTTP/1.1
    Content-type: application/json
    
    {
       "Publish": boolean,
       "S3Bucket": "string",
       "S3Key": "string",
       "S3ObjectVersion": "string",
       "ZipFile": blob
    }

    这个API调用只能针对已经存在的function,当然也有创建新的function的API

    POST /2015-03-31/functions HTTP/1.1
    Content-type: application/json
    
    {
       "Code": { 
          "S3Bucket": "string",
          "S3Key": "string",
          "S3ObjectVersion": "string",
          "ZipFile": blob
       },
       "Description": "string",
       "Environment": { 
          "Variables": { 
             "string" : "string" 
          }
       },
       "FunctionName": "string",
       "Handler": "string",
       "KMSKeyArn": "string",
       "MemorySize": number,
       "Publish": boolean,
       "Role": "string",
       "Runtime": "string",
       "Timeout": number,
       "VpcConfig": { 
          "SecurityGroupIds": [ "string" ],
          "SubnetIds": [ "string" ]
       }
    }

    Jenkins中可以找一个AWS Lambda的插件,它可以更新代码,当function不存在的时候也会自动创建。

    aws-jenkins-plugin

     

    更新代码且需要维护触发器

    这种情况稍微麻烦一些,但是也是我觉得最理想的情况。手动维护触发器很繁琐,出错与否先不论,如果不能自动化,还需要在不同的测试环境之间同步配置,实在闹心。

    对于这种情况,AWS API当然能够做到,而且还有aws cli工具呢。

    aws apigateway put-method --rest-api-id 1234123412 --resource-id a1b2c3 --http-method PUT --authorization-type "NONE" --no-api-key-required --request-parameters "method.request.header.custom-header=false" --region us-west-2

    这里推荐使用Serverless framework (https://serverless.com/)

    serverless

    它有专门的机制管理了event的维护,这是一个实例配置,它的触发器是api gateway

    # 'functions' in serverless.yml
    functions:
      createUser: # Function name
        handler: handler.createUser # Reference to file handler.js & exported function 'createUser'
        events: # All events associated with this function
          - http:
              path: users/create
              method: post

    当然还有多个event的情况,它也支持

    # 'functions' in serverless.yml
    functions:
      createUser: # Function name
        handler: handler.users # Reference to file handler.js & exported function 'users'
        events: # All events associated with this function
          - http:
              path: users/create
              method: post
          - http:
              path: users/update
              method: put
          - http:
              path: users/delete
              method: delete

    这样的好处在于触发器的配置可以包含在代码库中,而相关的维护由工具完成。

    执行lambda并测试结果

    这里指定lambda的原因和之前的原因可能不大意义。

    因为pipeline有一个build number的概念,合理的时候可以帮助我们判断当前测试环境的代码版本便于管理和回滚。而AWS Lambda中对于版本的管理是采用Versioning的方式,我们默认更新的是$LATEST版本,所以执行lambda的作用更多的是在于判断是否能够成功触发。

    还有一个好处是AWS Lambda虽然是无状态的,会随时销毁的,但是依然有重用机制,执行一次之后会有一个容器方便下次使用,可以带来一定的性能提升。

    具体的执行办法就比较多了,上面提到的Jenkins AWS Lambda Plugin和Serverless framework都可以实现。

    当然因为这里的例子是一个Web项目,直接请求API Gateway也是可以的。、

    结论

    所以对于运行于AWS Lambda的项目而言,其Pipeline并不会有太多变化,主要集中在发布上,而发布这个问题上AWS自身提供了完整功能的API,所以即便没有任何工具和插件,也是可以使用简单脚本实现的。

  • 加密游戏数据与反内存编辑器

    内存编辑器如字面意义是可以修改内存的工具。可以很简单的使用于游戏破解。

    比如游戏中有金币这个概念,那么用户是可以看到金币数的,那么在内存编辑器中搜索这个数值,然后在游戏中做出一些操作使金币数量发生变化,然后再搜索新的值,直到搜索出来的结果数量只有一个或者几个,然后使用内存编辑器修改这个数值,回到游戏中金币数就会变成修改过后的值。 (更多…)