2016年5月30日星期一

Swift中指针使用及操作

在Swift中指针用两个特殊的类型来描述,UnsafePointer和UnsafeMutablePointer,遵循Cocoa的原则,可以看出不可变可变的不同,当创建指针之后,可以通过指针的memory来操作指针。另外,Swift中UnsafeBufferPointer用来描述一组连续的数据指针,COpaquePointer用来描述非完整结构的不透明指针。
在函数中传递指针(指针作为函数参数进行传递)
在函数中传递指针有两种方式,一:使用inout关键字。二:使用Swift准备的指针类型。
使用inout关键字:
var num:Int = 10
func some(inout numb:Int){
    //如果使用inout关键字,在函数体内部不需要处理指针类型,可直接操作
    numb += 1
    print("numb --> \(numb)")
}
some(&num)
print("num ---> \(num)")
使用Swift准备的指针类型
var num:Int = 10
func some(numb:UnsafeMutablePointer<Int>){
    //如果使用Swift提供的类型,那么需要使用memory来进行操作
    numb.memory += 1
    print("numb --> \(numb.memory)")
}
some(&num)
print("num ---> \(num)")
需要注意的是,Swift中地址符&是不能直接使用的,只能是函数传递时才可用。
如何直接操作
虽然无法像OC或者C中那样直接通过地址符&来操作指针,但是Swift也提供了辅助的方法间接的来帮助我们来操作指针。
var i:Int = 10
i = withUnsafeMutablePointer(&i, {
   (p:UnsafeMutablePointer<Int>) -> Int in
       p.memory += 20
       return p.memory
})
print("i value ---> \(i)")
如何使用指向数组的指针
如果只是函数传递,不可变直接传递,可变使用&符即可,如果想直接操作,那么还是需要UnsafeBufferPointer来辅助完成。
var array:[Int] = [2,1,3,4]
var arrayPtr:UnsafeMutableBufferPointer<Int> = UnsafeMutableBufferPointer<Int>(start: &array, count: array.count)
var baseArrayPtr:UnsafeMutablePointer<Int> = arrayPtr.baseAddress as UnsafeMutablePointer<Int>
var nextPtr:UnsafeMutablePointer<Int> = baseArrayPtr.successor()
var threPtr:UnsafeMutablePointer<Int> = nextPtr.successor()

print("第一个元素  \(baseArrayPtr.memory)")
print("第二个元素 \(nextPtr.memory)")
print("第三个元素  \(threPtr.memory)")
如何通过指针强制转换类型
这个操作比较危险,除非你明确预期知道类型,不然编译器是无法知道的,也就造成了非常大的不确定性。
let arr:NSArray = NSArray(object: "icepy")
let str:NSString = unsafeBitCast(arr[0],NSString.self)

print("str --- > \(str.stringByAppendingPathComponent("app"))")
创建一个指针
//创建可变指针
var i:UnsafeMutablePointer<String> = UnsafeMutablePointer<String>.alloc(10)
i.initialize("icepy")
内存管理
还有一点要注意的是,如果是属于自己手动创建的指针,Swift是不负责管理内存的,需要手动的销毁与释放。
一个UnsafeMutablePointer内存一般有三个状态:
  • 内存没有被分配,null指针
  • 内存进行了分配,且值还未初始化
  • 内存进行了分配,且值已经初始化
var i:UnsafeMutablePointer<String> = UnsafeMutablePointer<String>.alloc(10)
i.initialize("icepy")        
print("i的内存地址 \(i)")
print("i的memory \(i.memory)")        
i.destroy() //销毁指针指向的对象
i.dealloc(10) //销毁指针申请的内存
i = nil

2016年5月8日星期日

Go Golang

        因为新版的Golang使用Go本身编译Golang,不再使用C编译器,所以需要先安装Go 1.4,否则在安装1.6版本时会报错ERROR: Cannot find /home/xxx/go1.4/bin/go。
         在.bash_profile文件中设置Go环境变量:
                  export GOROOT_BOOTSTRAP=$HOME/go1.4.3
                  export GOROOT=$HOME/go1.6.2
                  export GOPATH=$HOME/Go/Proj1:$HOME/Go/Proj2
                  export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
          Go compiler的package搜索顺序:首先在安装目录GOROOT查找,没有则继续GOPATH=PATH1:PATH2的PATH1/src/filename.go和PATH2/src/filename.go,如果均没有找到则提示错误。上述GOPATH中的PATH1和PATH2被称为workplace

          一般Go项目目录结构:
                                                  Proj1/
                                                           bin/
                                                           pkg/
                                                           src/
                                                                lib1/      
                                                                      lib1.go
                                                                lib2/     
                                                                      lib2.go
                                                                app/     
                                                                      main.go
                                                  Proj2/
                                                           bin/
                                                           pkg/
                                                           src/
                                                                lib1/      
                                                                      lib1.go
                                                                lib2/     
                                                                      lib2.go
                                                                app/     
                                                                      main.go                                                                    

2016年4月27日星期三

Use OpenSSL to generate RSA private key and public key

Generate RSA private key
1、openssl genrsa -out rsa_private_key.pem 1024

Convert RSA private key into PKCS8 format
2、openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -out PEM -nocrypt

Generate RSA public key
3、openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

Now the RSA key pair is available


2016年4月26日星期二

How to configure LetsEncrypt SSL cert on Nginx

Step 1、You need to compile Nginx from source code for support ssl:
              ./configure --with-http_ssl_module
Step 2、Get letsencrypt client: git clone https://github.com/letsencrypt/letsencrypt
Step 3、Run letsencrypt client to generate the cert(You need stop nginx service if you have already run a nginx server and specify the full root path of your website ):
              cd letsencrypt
              ./letsencrypt-auto certonly --standalone --email ***@email.com -d www.yourdomain.com --webroot=/www/web/
Step 4、Configure the nginx server
              listen    443 ssl;
              ssl_protocols TLSv1.2 TLSv1.1 TLSv1
              ssl_certificate /etc/letsencrypt/live/www.yourdomain.com/fullchain.pem;
              ssl_certificate_key /etc/letsencrypt/live/www.yourdomain.com/privkey.pem;

2016年2月3日星期三

iOS KeychainWrapper with Swift

//
//  KeychainWrapper.swift
//
//  Created by guangmean
//  Copyright © 2016 guangmean All rights reserved.
//

import Foundation

let SecMatchLimit: String! = kSecMatchLimit as String
let SecReturnData: String! = kSecReturnData as String
let SecValueData: String! = kSecValueData as String
let SecAttrAccessible: String! = kSecAttrAccessible as String
let SecClass: String! = kSecClass as String
let SecAttrService: String! = kSecAttrService as String
let SecAttrGeneric: String! = kSecAttrGeneric as String
let SecAttrAccount: String! = kSecAttrAccount as String
let SecAttrAccessGroup: String! = kSecAttrAccessGroup as String

/// KeychainWrapper is a class to help make Keychain access in Swift more straightforward. It is designed to make accessing the Keychain services more like using NSUserDefaults, which is much more familiar to people.
public class KeychainWrapper {
    // MARK: Private static Properties
    private struct internalVars {
        static var serviceName: String = ""
        static var accessGroup: String = ""
    }
    
    // MARK: Public Properties
    
    /// ServiceName is used for the kSecAttrService property to uniquely identify this keychain accessor. If no service name is specified, KeychainWrapper will default to using the bundleIdentifier.
    ///
    ///This is a static property and only needs to be set once
    public class var serviceName: String {
        get {
        if internalVars.serviceName.isEmpty {
        internalVars.serviceName = NSBundle.mainBundle().bundleIdentifier ?? "SwiftKeychainWrapper"
        }
        return internalVars.serviceName
        }
        set(newServiceName) {
            internalVars.serviceName = newServiceName
        }
    }
    
    /// AccessGroup is used for the kSecAttrAccessGroup property to identify which Keychain Access Group this entry belongs to. This allows you to use the KeychainWrapper with shared keychain access between different applications.
    ///
    /// Access Group defaults to an empty string and is not used until a valid value is set.
    ///
    /// This is a static property and only needs to be set once. To remove the access group property after one has been set, set this to an empty string.
    public class var accessGroup: String {
        get {
        return internalVars.accessGroup
        }
        set(newAccessGroup){
            internalVars.accessGroup = newAccessGroup
        }
    }
    
    // MARK: Public Methods
    
    /// Checks if keychain data exists for a specified key.
    ///
    /// - parameter keyName: The key to check for.
    /// - returns: True if a value exists for the key. False otherwise.
    public class func hasValueForKey(keyName: String) -> Bool {
        let keychainData: NSData? = self.dataForKey(keyName)
        if keychainData != nil {
            return true
        } else {
            return false
        }
    }
    
    /// Returns a string value for a specified key.
    ///
    /// - parameter keyName: The key to lookup data for.
    /// - returns: The String associated with the key if it exists. If no data exists, or the data found cannot be encoded as a string, returns nil.
    public class func stringForKey(keyName: String) -> String? {
        let keychainData: NSData? = self.dataForKey(keyName)
        var stringValue: String?
        if let data = keychainData {
            stringValue = NSString(data: data, encoding: NSUTF8StringEncoding) as String?
        }
        
        return stringValue
    }
    
    
    /// Returns an object that conforms to NSCoding for a specified key.
    ///
    /// - parameter keyName: The key to lookup data for.
    /// - returns: The decoded object associated with the key if it exists. If no data exists, or the data found cannot be decoded, returns nil.
    public class func objectForKey(keyName: String) -> NSCoding? {
        let dataValue: NSData? = self.dataForKey(keyName)
        
        var objectValue: NSCoding?
        
        if let data = dataValue {
            objectValue = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? NSCoding
        }
        
        return objectValue;
    }
    
    
    /// Returns a NSData object for a specified key.
    ///
    /// - parameter keyName: The key to lookup data for.
    /// - returns: The NSData object associated with the key if it exists. If no data exists, returns nil.
    public class func dataForKey(keyName: String) -> NSData? {
        var keychainQueryDictionary = self.setupKeychainQueryDictionaryForKey(keyName)
        var result: AnyObject?
        
        // Limit search results to one
        keychainQueryDictionary[SecMatchLimit] = kSecMatchLimitOne
        
        // Specify we want NSData/CFData returned
        keychainQueryDictionary[SecReturnData] = kCFBooleanTrue
        
        // Search
        let status = withUnsafeMutablePointer(&result) {
            SecItemCopyMatching(keychainQueryDictionary, UnsafeMutablePointer($0))
        }
        
        return status == noErr ? result as? NSData : nil
    }
    
    /// Save a String value to the keychain associated with a specified key. If a String value already exists for the given keyname, the string will be overwritten with the new value.
    ///
    /// - parameter value: The String value to save.
    /// - parameter forKey: The key to save the String under.
    /// - returns: True if the save was successful, false otherwise.
    public class func setString(value: String, forKey keyName: String) -> Bool {
        if let data = value.dataUsingEncoding(NSUTF8StringEncoding) {
            return self.setData(data, forKey: keyName)
        } else {
            return false
        }
    }
    
    /// Save an NSCoding compliant object to the keychain associated with a specified key. If an object already exists for the given keyname, the object will be overwritten with the new value.
    ///
    /// - parameter value: The NSCoding compliant object to save.
    /// - parameter forKey: The key to save the object under.
    /// - returns: True if the save was successful, false otherwise.
    public class func setObject(value: NSCoding, forKey keyName: String) -> Bool {
        let data = NSKeyedArchiver.archivedDataWithRootObject(value)
        
        return self.setData(data, forKey: keyName)
    }
    
    /// Save a NSData object to the keychain associated with a specified key. If data already exists for the given keyname, the data will be overwritten with the new value.
    ///
    /// - parameter value: The NSData object to save.
    /// - parameter forKey: The key to save the object under.
    /// - returns: True if the save was successful, false otherwise.
    public class func setData(value: NSData, forKey keyName: String) -> Bool {
        var keychainQueryDictionary: [String:AnyObject] = self.setupKeychainQueryDictionaryForKey(keyName)
        
        keychainQueryDictionary[SecValueData] = value
        
        // Protect the keychain entry so it's only valid when the device is unlocked
        keychainQueryDictionary[SecAttrAccessible] = kSecAttrAccessibleWhenUnlocked
        
        let status: OSStatus = SecItemAdd(keychainQueryDictionary, nil)
        
        if status == errSecSuccess {
            return true
        } else if status == errSecDuplicateItem {
            return self.updateData(value, forKey: keyName)
        } else {
            return false
        }
    }
    
    /// Remove an object associated with a specified key.
    ///
    /// - parameter keyName: The key value to remove data for.
    /// - returns: True if successful, false otherwise.
    public class func removeObjectForKey(keyName: String) -> Bool {
        let keychainQueryDictionary: [String:AnyObject] = self.setupKeychainQueryDictionaryForKey(keyName)
        
        // Delete
        let status: OSStatus =  SecItemDelete(keychainQueryDictionary);
        
        if status == errSecSuccess {
            return true
        } else {
            return false
        }
    }
    
    // MARK: Private Methods
    
    /// Update existing data associated with a specified key name. The existing data will be overwritten by the new data
    private class func updateData(value: NSData, forKey keyName: String) -> Bool {
        let keychainQueryDictionary: [String:AnyObject] = self.setupKeychainQueryDictionaryForKey(keyName)
        let updateDictionary = [SecValueData:value]
        
        // Update
        let status: OSStatus = SecItemUpdate(keychainQueryDictionary, updateDictionary)
        
        if status == errSecSuccess {
            return true
        } else {
            return false
        }
    }
    
    /// Setup the keychain query dictionary used to access the keychain on iOS for a specified key name. Takes into account the Service Name and Access Group if one is set.
    ///
    /// - parameter keyName: The key this query is for
    /// - returns: A dictionary with all the needed properties setup to access the keychain on iOS
    private class func setupKeychainQueryDictionaryForKey(keyName: String) -> [String:AnyObject] {
        // Setup dictionary to access keychain and specify we are using a generic password (rather than a certificate, internet password, etc)
        var keychainQueryDictionary: [String:AnyObject] = [SecClass:kSecClassGenericPassword]
        
        // Uniquely identify this keychain accessor
        keychainQueryDictionary[SecAttrService] = KeychainWrapper.serviceName
        
        // Set the keychain access group if defined
        if !KeychainWrapper.accessGroup.isEmpty {
            keychainQueryDictionary[SecAttrAccessGroup] = KeychainWrapper.accessGroup
        }
        
        // Uniquely identify the account who will be accessing the keychain
        let encodedIdentifier: NSData? = keyName.dataUsingEncoding(NSUTF8StringEncoding)
        
        keychainQueryDictionary[SecAttrGeneric] = encodedIdentifier
        
        keychainQueryDictionary[SecAttrAccount] = encodedIdentifier
        
        return keychainQueryDictionary
    }
}

2016年1月14日星期四

Offline Message Push Notification Module for Ejabberd, Test on ejabberd-15.11

Recently I need a offline push notification on ejabberd server for iOS and Android remote notification, after a sets of google and try I found the following solution, it works fine on jabberd-15.11, hope it helpful for somebody.

You should save the following code to a file and put it into ejabberd source code folder ejabberd-15.11/src/mod_offline_push.erl


%% name of module must match file name
-module(mod_offline_push).

-author("guangmean").

%% Every ejabberd module implements the gen_mod behavior
%% The gen_mod behavior requires two functions: start/2 and stop/1
-behaviour(gen_mod).

%% public methods for this module
-export([start/2, stop/1, message_push/3]).

%% included for writing to ejabberd log file
-include("ejabberd.hrl").
-include("logger.hrl"). 

%% ejabberd functions for JID manipulation called jlib.
-include("jlib.hrl").

start(Host, Opts) -> 
        ?INFO_MSG("Loading offline message push mode", []),
        ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, message_push, 3).   

stop(Host) -> 
        ?INFO_MSG("Stoping offline message push mode", []),
        ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, message_push, 3).

message_push(From, To, Packet) ->
        MessageType = xml:get_tag_attr_s(<<"type">>, Packet),
        MessageFrom = xml:get_tag_attr_s(<<"from">>, Packet),
        MessageTo = xml:get_tag_attr_s(<<"to">>, Packet),
        curl_request_push(MessageFrom, MessageTo),
    ok.

curl_request_push(From, To) ->
        ?INFO_MSG("Pushing notify From ~p To ~p~n",[From, To]),
    httpc:request(post, {"http://fullstacking.blogspot.com", [], "application/x-www-form-urlencoded", list_to_binary(["from=", From, "&to=", To])}, [], []).



Compile ejabberd:
./configure --prefix=/your/ejabberd/install/path/ejabberd-15.11
make
make install

MySQL存储Emoji表情

Problems with utf8 character set, should use utf8mb4

Apply to whole table:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin

Or apply to a column
ALTER TABLE table_name CHANGE column_name VARCHAR(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin