Commit 9af9db2f authored by alexstocks's avatar alexstocks

add echo examples

parent 3d5349a9
This diff is collapsed.
/******************************************************
# DESC : getty utility
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-08-22 17:44
# FILE : utils.go
******************************************************/
package getty
import (
"bytes"
"encoding/binary"
"net"
"strconv"
"time"
)
func HostAddress(host string, port int) string {
return net.JoinHostPort(host, strconv.Itoa(port))
}
func dial(addr string) (net.Conn, error) {
return net.Dial("tcp", addr)
}
func dialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("tcp", addr, timeout)
}
////////////////////////////////////////
// enc/dec
////////////////////////////////////////
func Int2Bytes(x int32) []byte {
var buf = bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, x)
return buf.Bytes()
}
func Bytes2Int(b []byte) int32 {
var (
x int32
buf *bytes.Buffer
)
buf = bytes.NewBuffer(b)
binary.Read(buf, binary.BigEndian, &x)
return x
}
type GettyHeader struct {
Magic int32
Len int32 // body length
LogId int32 // log id
ServiceId int32 // service id
Code int32 // error code
Extra int32 // reserved
}
func (this *GettyHeader) Bytes() []byte {
var buf = bytes.NewBuffer(make([]byte, 24))
binary.Write(buf, binary.BigEndian, this.Magic)
binary.Write(buf, binary.BigEndian, this.Len)
binary.Write(buf, binary.BigEndian, this.LogId)
binary.Write(buf, binary.BigEndian, this.ServiceId)
binary.Write(buf, binary.BigEndian, this.Code)
binary.Write(buf, binary.BigEndian, this.Extra)
return buf.Bytes()
}
type WrappedPackage struct {
H GettyHeader
Payload []byte
}
func (this *WrappedPackage) PackMessage() []byte {
return append(this.H.Bytes(), this.Payload...)
}
/******************************************************
# DESC : echo client
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-06 17:24
# FILE : client.go
******************************************************/
package main
import (
"math/rand"
"sync"
"sync/atomic"
"time"
)
import (
"github.com/AlexStocks/getty"
log "github.com/AlexStocks/log4go"
)
var (
reqID uint32
src = rand.NewSource(time.Now().UnixNano())
)
func init() {
rand.Seed(time.Now().UnixNano())
}
////////////////////////////////////////////////////////////////////
// echo client
////////////////////////////////////////////////////////////////////
type EchoClient struct {
lock sync.RWMutex
sessions []*clientEchoSession
gettyClient *getty.Client
}
func (this *EchoClient) isAvailable() bool {
if this.selectSession() == nil {
return false
}
return true
}
func (this *EchoClient) close() {
client.lock.Lock()
if client.gettyClient != nil {
for _, s := range this.sessions {
log.Info("close client session{%s, last active:%s, request number:%d}",
s.session.Stat(), s.active.String(), s.reqNum)
s.session.Close()
}
client.gettyClient.Close()
client.gettyClient = nil
client.sessions = client.sessions[:0]
}
client.lock.Unlock()
}
func (this *EchoClient) selectSession() *getty.Session {
// get route server session
this.lock.RLock()
defer this.lock.RUnlock()
count := len(this.sessions)
if count == 0 {
log.Info("client session arrray is nil...")
return nil
}
return this.sessions[rand.Int31n(int32(count))].session
}
func (this *EchoClient) addSession(session *getty.Session) {
log.Debug("add session{%s}", session.Stat())
if session == nil {
return
}
this.lock.Lock()
this.sessions = append(this.sessions, &clientEchoSession{session: session, active: time.Now()})
this.lock.Unlock()
}
func (this *EchoClient) removeSession(session *getty.Session) {
if session == nil {
return
}
this.lock.Lock()
for i, s := range this.sessions {
if s.session == session {
this.sessions = append(this.sessions[:i], this.sessions[i+1:]...)
log.Debug("delete session{%s}, its index{%d}", session.Stat(), i)
break
}
}
log.Info("after remove session{%s}, left session number:%d", session.Stat(), len(this.sessions))
this.lock.Unlock()
}
func (this *EchoClient) updateSession(session *getty.Session) {
if session == nil {
return
}
this.lock.Lock()
for i, s := range this.sessions {
if s.session == session {
this.sessions[i].active = time.Now()
this.sessions[i].reqNum++
break
}
}
this.lock.Unlock()
}
func (this *EchoClient) getClientEchoSession(session *getty.Session) (clientEchoSession, error) {
var (
err error
echoSession clientEchoSession
)
this.lock.Lock()
err = errSessionNotExist
for _, s := range this.sessions {
if s.session == session {
echoSession = *s
err = nil
break
}
}
this.lock.Unlock()
return echoSession, err
}
func (this *EchoClient) heartbeat(session *getty.Session) {
var pkg EchoPackage
pkg.H.Magic = echoPkgMagic
pkg.H.LogID = (uint32)(src.Int63())
pkg.H.Sequence = atomic.AddUint32(&reqID, 1)
// pkg.H.ServiceID = 0
pkg.H.Command = heartbeatCmd
pkg.B = echoHeartbeatRequestString
pkg.H.Len = (uint16)(len(pkg.B))
if err := session.WritePkg(pkg); err != nil {
log.Warn("session.WritePkg(session{%s}, pkg{%s}) = error{%v}", session.Stat(), pkg, err)
session.Close()
}
}
/******************************************************
# DESC : env var & configure
# MAINTAINER : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-06 16:53
# FILE : config.go
******************************************************/
package main
import (
"fmt"
"os"
"path"
"time"
)
import (
"github.com/AlexStocks/gocolor"
log "github.com/AlexStocks/log4go"
config "github.com/koding/multiconfig"
)
const (
APP_CONF_FILE string = "APP_CONF_FILE"
APP_LOG_CONF_FILE string = "APP_LOG_CONF_FILE"
)
var (
conf *Config
)
type (
// Config holds supported types by the multiconfig package
Config struct {
LocalHost string `default:"127.0.0.1"`
ServerHost string `default:"127.0.0.1"`
ServerPort int `default:"10000"`
ProfilePort int `default:"10086"`
ConnectionNum int `default:"16"`
ConnectInterval string `default:"5s"`
connectInterval time.Duration
HeartbeatPeriod string `default:"15s"`
heartbeatPeriod time.Duration
SessionTimeout string `default:"60s"`
sessionTimeout time.Duration
EchoTimes int `default:"10"`
}
)
func initConf() {
var (
err error
confFile string
)
// configure
confFile = os.Getenv(APP_CONF_FILE)
if confFile == "" {
panic(fmt.Sprintf("application configure file name is nil"))
return // I know it is of no usage. Just Err Protection.
}
if path.Ext(confFile) != ".toml" {
panic(fmt.Sprintf("application configure file name{%v} suffix must be .toml", confFile))
return
}
conf = new(Config)
config.MustLoadWithPath(confFile, conf)
conf.connectInterval, err = time.ParseDuration(conf.ConnectInterval)
if err != nil {
panic(fmt.Sprintf("time.ParseDuration(ConnectionInterval{%#v}) = error{%v}", conf.ConnectInterval, err))
return
}
conf.heartbeatPeriod, err = time.ParseDuration(conf.HeartbeatPeriod)
if err != nil {
panic(fmt.Sprintf("time.ParseDuration(HeartbeatPeroid{%#v}) = error{%v}", conf.HeartbeatPeriod, err))
return
}
conf.sessionTimeout, err = time.ParseDuration(conf.SessionTimeout)
if err != nil {
panic(fmt.Sprintf("time.ParseDuration(SessionTimeout{%#v}) = error{%v}", conf.SessionTimeout, err))
return
}
gocolor.Info("config{%#v}\n", conf)
// log
confFile = os.Getenv(APP_LOG_CONF_FILE)
if confFile == "" {
panic(fmt.Sprintf("log configure file name is nil"))
return
}
if path.Ext(confFile) != ".xml" {
panic(fmt.Sprintf("log configure file name{%v} suffix must be .xml", confFile))
return
}
log.LoadConfiguration(confFile)
return
}
/******************************************************
# DESC : echo package handler
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-04 13:08
# FILE : handler.go
******************************************************/
package main
import (
"errors"
"time"
)
import (
"github.com/AlexStocks/getty"
log "github.com/AlexStocks/log4go"
)
var (
errSessionNotExist = errors.New("session not exist!")
)
////////////////////////////////////////////
// EchoMessageHandler
////////////////////////////////////////////
type clientEchoSession struct {
session *getty.Session
active time.Time
reqNum int32
}
type EchoMessageHandler struct {
}
func newEchoMessageHandler() *EchoMessageHandler {
return &EchoMessageHandler{}
}
func (this *EchoMessageHandler) OnOpen(session *getty.Session) error {
client.addSession(session)
return nil
}
func (this *EchoMessageHandler) OnError(session *getty.Session, err error) {
log.Info("session{%s} got error{%v}, will be closed.", session.Stat(), err)
client.removeSession(session)
}
func (this *EchoMessageHandler) OnClose(session *getty.Session) {
log.Info("session{%s} is closing......", session.Stat())
client.removeSession(session)
}
func (this *EchoMessageHandler) OnMessage(session *getty.Session, pkg interface{}) {
p, ok := pkg.(*EchoPackage)
if !ok {
log.Error("illegal packge{%#v}", pkg)
return
}
log.Debug("get echo package{%s}", p)
client.updateSession(session)
}
func (this *EchoMessageHandler) OnCron(session *getty.Session) {
clientEchoSession, err := client.getClientEchoSession(session)
if err != nil {
log.Error("client.getClientSession(session{%s}) = error{%#v}", session.Stat(), err)
return
}
if conf.sessionTimeout.Nanoseconds() < time.Since(clientEchoSession.active).Nanoseconds() {
log.Warn("session{%s} timeout{%s}, reqNum{%d}",
session.Stat(), time.Since(clientEchoSession.active).String(), clientEchoSession.reqNum)
client.removeSession(session)
return
}
client.heartbeat(session)
}
/******************************************************
# DESC : echo client app
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-06 17:24
# FILE : main.go
******************************************************/
package main
import (
// "flag"
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
// "strings"
"sync/atomic"
"syscall"
"time"
)
import (
"github.com/AlexStocks/getty"
log "github.com/AlexStocks/log4go"
)
const (
tcpRBufSize = 256 * 1024
tcpWBufSize = 64 * 1024
pkgRQSize = 1024
pkgWQSize = 64
tcpReadTimeout = 1e9
tcpWriteTimeout = 5e9
waitTimeout = 5e9 // 5s
echoSessionTimeout = 5e9
maxSessionNum = 100
sessionName = "echo-client"
)
const (
survivalTimeout = 3e9
pprofPath = "/debug/pprof/"
)
var (
client EchoClient
)
////////////////////////////////////////////////////////////////////
// main
////////////////////////////////////////////////////////////////////
func main() {
initConf()
initProfiling()
initClient()
go test()
initSignal()
}
func initProfiling() {
var (
addr string
)
addr = getty.HostAddress(conf.LocalHost, conf.ProfilePort)
log.Info("App Profiling startup on address{%v}", addr+pprofPath)
go func() {
log.Info(http.ListenAndServe(addr, nil))
}()
}
func newSession(session *getty.Session) error {
var (
ok bool
tcpConn *net.TCPConn
)
if tcpConn, ok = session.Conn().(*net.TCPConn); !ok {
panic(fmt.Sprintf("%s, session.conn{%#v} is not tcp connection\n", session.Stat(), session.Conn()))
}
tcpConn.SetNoDelay(true)
tcpConn.SetReadBuffer(tcpRBufSize)
tcpConn.SetWriteBuffer(tcpWBufSize)
tcpConn.SetKeepAlive(true)
session.SetName(sessionName)
session.SetPkgHandler(NewEchoPackageHandler())
session.SetEventListener(newEchoMessageHandler())
session.SetRQLen(pkgRQSize)
session.SetWQLen(pkgWQSize)
session.SetReadDeadline(tcpReadTimeout)
session.SetWriteDeadline(tcpWriteTimeout)
session.SetCronPeriod((int)(conf.heartbeatPeriod.Nanoseconds() / 1e6))
session.SetWaitTime(waitTimeout)
log.Debug("client new session:%s\n", session.Stat())
return nil
}
func initClient() {
client.gettyClient = getty.NewClient(
(int)(conf.ConnectionNum),
conf.connectInterval,
getty.HostAddress(conf.ServerHost, conf.ServerPort),
)
client.gettyClient.RunEventLoop(newSession)
}
func uninitClient() {
client.close()
}
func initSignal() {
signals := make(chan os.Signal, 1)
// It is not possible to block SIGKILL or syscall.SIGSTOP
signal.Notify(signals, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
sig := <-signals
log.Info("get signal %s", sig.String())
switch sig {
case syscall.SIGHUP:
// reload()
default:
go time.AfterFunc(survivalTimeout, func() {
log.Warn("app exit now by force...")
os.Exit(1)
})
// 要么survialTimeout时间内执行完毕下面的逻辑然后程序退出,要么执行上面的超时函数程序强行退出
uninitClient()
fmt.Println("app exit now...")
return
}
}
}
func echo() {
var pkg EchoPackage
pkg.H.Magic = echoPkgMagic
pkg.H.LogID = (uint32)(src.Int63())
pkg.H.Sequence = atomic.AddUint32(&reqID, 1)
// pkg.H.ServiceID = 0
pkg.H.Command = echoCmd
pkg.B = echoMessage
pkg.H.Len = (uint16)(len(pkg.B))
if session := client.selectSession(); session != nil {
err := session.WritePkg(&pkg)
if err != nil {
log.Warn("session.WritePkg(session{%s}, pkg{%s}) = error{%v}", session.Stat(), pkg, err)
session.Close()
}
}
}
func test() {
for {
if client.isAvailable() {
break
}
time.Sleep(1e9)
}
for i := 0; i < conf.EchoTimes; i++ {
echo()
}
}
/******************************************************
# DESC : echo stream parser
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-04 13:08
# FILE : readwriter.go
******************************************************/
package main
import (
"bytes"
"errors"
"time"
)
import (
"github.com/AlexStocks/getty"
log "github.com/AlexStocks/log4go"
)
type EchoPackageHandler struct {
}
func NewEchoPackageHandler() *EchoPackageHandler {
return &EchoPackageHandler{}
}
func (this *EchoPackageHandler) Read(ss *getty.Session, data []byte) (interface{}, int, error) {
var (
err error
len int
pkg EchoPackage
buf *bytes.Buffer
)
buf = bytes.NewBuffer(data)
len, err = pkg.Unmarshal(buf)
if err != nil {
if err == ErrNotEnoughSteam {
return nil, 0, nil
}
return nil, 0, err
}
return &pkg, len, nil
}
func (this *EchoPackageHandler) Write(ss *getty.Session, pkg interface{}) error {
var (
ok bool
err error
startTime time.Time
echoPkg *EchoPackage
buf *bytes.Buffer
)
startTime = time.Now()
if echoPkg, ok = pkg.(*EchoPackage); !ok {
log.Error("illegal pkg:%+v\n", pkg)
return errors.New("invalid echo package!")
}
buf, err = echoPkg.Marshal()
if err != nil {
log.Warn("binary.Write(echoPkg{%#v}) = err{%#v}", echoPkg, err)
return err
}
err = ss.WriteBytes(buf.Bytes())
log.Info("WriteEchoPkgTimeMs = %s", time.Since(startTime).String())
return err
}
/******************************************************
# DESC : getty utility
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-08-22 17:44
# FILE : utils.go
******************************************************/
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"unsafe"
)
////////////////////////////////////////////
// echo command
////////////////////////////////////////////
type echoCommand uint32
const (
heartbeatCmd = iota
echoCmd
)
var echoCommandStrings = [...]string{
"heartbeat",
"echo",
}
func (c echoCommand) String() string {
return echoCommandStrings[c]
}
////////////////////////////////////////////
// EchoPkgHandler
////////////////////////////////////////////
const (
echoPkgMagic = 0x20160905
maxEchoStringLen = 0xff
echoHeartbeatRequestString = "ping"
echoHeartbeatResponseString = "pong"
echoMessage = "Hello, getty!"
)
var (
ErrNotEnoughSteam = errors.New("packet stream is not enough")
ErrTooLargePackage = errors.New("package length is exceed the echo package's legal maximum length.")
ErrIllegalMagic = errors.New("package magic is not right.")
)
var (
echoPkgHeaderLen int
)
func init() {
echoPkgHeaderLen = (int)((uint)(unsafe.Sizeof(EchoPkgHeader{})))
}
type EchoPkgHeader struct {
Magic uint32
LogID uint32 // log id
Sequence uint32 // request/response sequence
ServiceID uint32 // service id
Command uint32 // operation command code
Code int32 // error code
Len uint16 // body length
_ uint16
_ int32 // reserved, maybe used as package md5 checksum
}
type EchoPackage struct {
H EchoPkgHeader
B string
}
func (this EchoPackage) String() string {
return fmt.Sprintf("log id:%d, sequence:%d, command:%s, echo string:%s",
this.H.LogID, this.H.Sequence, (echoCommand(this.H.Command)).String(), this.B)
}
func (this EchoPackage) Marshal() (*bytes.Buffer, error) {
var (
err error
buf *bytes.Buffer
)
buf = &bytes.Buffer{}
err = binary.Write(buf, binary.LittleEndian, this.H)
if err != nil {
return nil, err
}
buf.WriteByte((byte)(len(this.B)))
buf.WriteString(this.B)
return buf, nil
}
func (this *EchoPackage) Unmarshal(buf *bytes.Buffer) (int, error) {
var (
err error
len byte
)
if buf.Len() < echoPkgHeaderLen {
return 0, ErrNotEnoughSteam
}
// header
err = binary.Read(buf, binary.LittleEndian, &(this.H))
if err != nil {
return 0, err
}
if this.H.Magic != echoPkgMagic {
return 0, ErrIllegalMagic
}
if buf.Len() < (int)(this.H.Len) {
return 0, ErrNotEnoughSteam
}
if maxEchoStringLen < this.H.Len {
return 0, ErrTooLargePackage
}
len, err = buf.ReadByte()
if err != nil {
return 0, nil
}
this.B = (string)(buf.Next((int)(len)))
return (int)(this.H.Len) + echoPkgHeaderLen, nil
}
/******************************************************
# DESC : echo client version
# MAINTAINER : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-06 11:23
# FILE : version.go
******************************************************/
package main
var (
Version = "0.3.04"
)
#!/usr/bin/env bash
# ******************************************************
# DESC : getty app devops script
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : LGPL V3
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-05-13 02:01
# FILE : load.sh
# ******************************************************
APP_NAME="APPLICATION_NAME"
APP_ARGS=""
PROJECT_HOME=""
OS_NAME=`uname`
if [[ ${OS_NAME} == "Linux" ]]; then
PROJECT_HOME=`pwd`
PROJECT_HOME=${PROJECT_HOME}"/"
fi
export APP_CONF_FILE=${PROJECT_HOME}"TARGET_CONF_FILE"
export APP_LOG_CONF_FILE=${PROJECT_HOME}"TARGET_LOG_CONF_FILE"
usage() {
echo "Usage: $0 start"
echo " $0 stop"
echo " $0 term"
echo " $0 restart"
echo " $0 list"
exit
}
start() {
APP_LOG_PATH="${PROJECT_HOME}logs/"
mkdir -p ${APP_LOG_PATH}
APP_BIN=${PROJECT_HOME}sbin/${APP_NAME}
chmod u+x ${APP_BIN}
# CMD="nohup ${APP_BIN} ${APP_ARGS} >>${APP_NAME}.nohup.out 2>&1 &"
CMD="${APP_BIN}"
eval ${CMD}
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $2}'`
if [[ ${OS_NAME} != "Linux" ]]; then
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $1}'`
fi
if [ "${PID}" != "" ];
then
for p in ${PID}
do
echo "start ${APP_NAME} ( pid =" ${p} ")"
done
fi
}
stop() {
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $2}'`
if [[ ${OS_NAME} != "Linux" ]]; then
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $1}'`
fi
if [ "${PID}" != "" ];
then
for ps in ${PID}
do
echo "kill -SIGINT ${APP_NAME} ( pid =" ${ps} ")"
kill -2 ${ps}
done
fi
}
term() {
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $2}'`
if [[ ${OS_NAME} != "Linux" ]]; then
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $1}'`
fi
if [ "${PID}" != "" ];
then
for ps in ${PID}
do
echo "kill -9 ${APP_NAME} ( pid =" ${ps} ")"
kill -9 ${ps}
done
fi
}
list() {
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{printf("%s,%s,%s,%s\n", $1, $2, $9, $10)}'`
if [[ ${OS_NAME} != "Linux" ]]; then
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{printf("%s,%s,%s,%s,%s\n", $1, $4, $6, $7, $8)}'`
fi
if [ "${PID}" != "" ];
then
echo "list ${APP_NAME}"
if [[ ${OS_NAME} == "Linux" ]]; then
echo "index: user, pid, start, duration"
else
echo "index: PID, WINPID, UID, STIME, COMMAND"
fi
idx=0
for ps in ${PID}
do
echo "${idx}: ${ps}"
((idx ++))
done
fi
}
opt=$1
case C"$opt" in
Cstart)
start
;;
Cstop)
stop
;;
Cterm)
term
;;
Crestart)
term
start
;;
Clist)
list
;;
C*)
usage
;;
esac
# dubbogo application configure script
# ******************************************************
# DESC : application environment variable
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:29
# FILE : app.properties
# ******************************************************
TARGET_EXEC_NAME="echo_client"
BUILD_PACKAGE="app"
TARGET_CONF_FILE="conf/config.toml"
TARGET_LOG_CONF_FILE="conf/log.xml"
#!/usr/bin/env bash
# ******************************************************
# DESC : build script
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:28
# FILE : build.sh
# ******************************************************
rm -rf target/
PROJECT_HOME=`pwd`
TARGET_FOLDER=${PROJECT_HOME}/target/${GOOS}
TARGET_SBIN_NAME=${TARGET_EXEC_NAME}
version=`cat app/version.go | grep Version | awk -F '=' '{print $2}' | awk -F '"' '{print $2}'`
if [[ ${GOOS} == "windows" ]]; then
TARGET_SBIN_NAME=${TARGET_SBIN_NAME}.exe
fi
TARGET_NAME=${TARGET_FOLDER}/${TARGET_SBIN_NAME}
if [[ $PROFILE = "test" ]]; then
# GFLAGS=-gcflags "-N -l" -race -x -v # -x会把go build的详细过程输出
# GFLAGS=-gcflags "-N -l" -race -v
# GFLAGS="-gcflags \"-N -l\" -v"
cd ${BUILD_PACKAGE} && go build -gcflags "-N -l" -x -v -i -o ${TARGET_NAME} && cd -
else
# -s去掉符号表(然后panic时候的stack trace就没有任何文件名/行号信息了,这个等价于普通C/C++程序被strip的效果),
# -w去掉DWARF调试信息,得到的程序就不能用gdb调试了。-s和-w也可以分开使用,一般来说如果不打算用gdb调试,
# -w基本没啥损失。-s的损失就有点大了。
cd ${BUILD_PACKAGE} && go build -ldflags "-w" -x -v -i -o ${TARGET_NAME} && cd -
fi
TAR_NAME=${TARGET_EXEC_NAME}-${version}-`date "+%Y%m%d-%H%M"`-${PROFILE}
mkdir -p ${TARGET_FOLDER}/${TAR_NAME}
SBIN_DIR=${TARGET_FOLDER}/${TAR_NAME}/sbin
BIN_DIR=${TARGET_FOLDER}/${TAR_NAME}
CONF_DIR=${TARGET_FOLDER}/${TAR_NAME}/conf
mkdir -p ${SBIN_DIR}
mkdir -p ${CONF_DIR}
mv ${TARGET_NAME} ${SBIN_DIR}
cp -r assembly/bin ${BIN_DIR}
# modify APPLICATION_NAME
sed -i "s~APPLICATION_NAME~${TARGET_EXEC_NAME}~g" ${BIN_DIR}/bin/*
# modify TARGET_CONF_FILE
sed -i "s~TARGET_CONF_FILE~${TARGET_CONF_FILE}~g" ${BIN_DIR}/bin/*
# modify TARGET_LOG_CONF_FILE
sed -i "s~TARGET_LOG_CONF_FILE~${TARGET_LOG_CONF_FILE}~g" ${BIN_DIR}/bin/*
cp -r profiles/${PROFILE}/* ${CONF_DIR}
cd ${TARGET_FOLDER}
tar czf ${TAR_NAME}.tar.gz ${TAR_NAME}/*
#!/usr/bin/env bash
# ******************************************************
# DESC : build script for release env
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : LGPL V3
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:25
# FILE : release.sh
# ******************************************************
set -e
export GOOS=linux
export GOARCH=amd64
PROFILE=release
PROJECT_HOME=`pwd`
if [ -f "${PROJECT_HOME}/assembly/common/app.properties" ]; then
. ${PROJECT_HOME}/assembly/common/app.properties
fi
if [ -f "${PROJECT_HOME}/assembly/common/build.sh" ]; then
. ${PROJECT_HOME}/assembly/common/build.sh
fi
#!/usr/bin/env bash
# ******************************************************
# DESC : build script for test env
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : LGPL V3
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:34
# FILE : test.sh
# ******************************************************
set -e
export GOOS=linux
export GOARCH=amd64
PROFILE=test
PROJECT_HOME=`pwd`
if [ -f "${PROJECT_HOME}/assembly/common/app.properties" ]; then
. ${PROJECT_HOME}/assembly/common/app.properties
fi
if [ -f "${PROJECT_HOME}/assembly/common/build.sh" ]; then
. ${PROJECT_HOME}/assembly/common/build.sh
fi
#!/usr/bin/env bash
# ******************************************************
# DESC : build script for release env
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : LGPL V3
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:25
# FILE : release.sh
# ******************************************************
set -e
export GOOS=windows
export GOARCH=amd64
PROFILE=release
PROJECT_HOME=`pwd`
if [ -f "${PROJECT_HOME}/assembly/common/app.properties" ]; then
. ${PROJECT_HOME}/assembly/common/app.properties
fi
if [ -f "${PROJECT_HOME}/assembly/common/build.sh" ]; then
. ${PROJECT_HOME}/assembly/common/build.sh
fi
#!/usr/bin/env bash
# ******************************************************
# DESC : build script for test env
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : LGPL V3
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:34
# FILE : test.sh
# ******************************************************
set -e
export GOOS=windows
export GOARCH=amd64
PROFILE=test
PROJECT_HOME=`pwd`
if [ -f "${PROJECT_HOME}/assembly/common/app.properties" ]; then
. ${PROJECT_HOME}/assembly/common/app.properties
fi
if [ -f "${PROJECT_HOME}/assembly/common/build.sh" ]; then
. ${PROJECT_HOME}/assembly/common/build.sh
fi
# toml configure file
LocalHost = "127.0.0.1"
# ServerHost = "192.168.35.3"
ServerHost = "192.168.35.1"
ServerPort = 10000
ProfilePort = 10080
# 连接池连接数目
ConnectionNum = 2
# 当连接失败或者连接断开时,连接池中重连的间隔时间
ConnectInterval = "5s"
# client与server之间连接的心跳周期
HeartbeatPeriod = "10s"
# client与server之间连接的超时时间
SessionTimeout = "20s"
# 发送echo请求次数
EchoTimes = 100
/******************************************************
# DESC : env var & configure
# MAINTAINER : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-06 16:53
# FILE : config.go
******************************************************/
package main
import (
"fmt"
"os"
"path"
"time"
)
import (
"github.com/AlexStocks/gocolor"
log "github.com/AlexStocks/log4go"
config "github.com/koding/multiconfig"
)
const (
APP_CONF_FILE string = "APP_CONF_FILE"
APP_LOG_CONF_FILE string = "APP_LOG_CONF_FILE"
)
var (
conf *Config
)
type (
// Config holds supported types by the multiconfig package
Config struct {
Host string `default:"127.0.0.1"`
Ports []string `default:["10000"]`
ProfilePort int `default:"10086"`
SessionTimeout string `default:"60s"`
sessionTimeout time.Duration
}
)
func initConf() {
var (
err error
confFile string
)
// configure
confFile = os.Getenv(APP_CONF_FILE)
if confFile == "" {
panic(fmt.Sprintf("application configure file name is nil"))
return // I know it is of no usage. Just Err Protection.
}
if path.Ext(confFile) != ".toml" {
panic(fmt.Sprintf("application configure file name{%v} suffix must be .toml", confFile))
return
}
conf = new(Config)
config.MustLoadWithPath(confFile, conf)
conf.sessionTimeout, err = time.ParseDuration(conf.SessionTimeout)
if err != nil {
panic(fmt.Sprintf("time.ParseDuration(SessionTimeout{%#v}) = error{%v}", conf.SessionTimeout, err))
return
}
gocolor.Info("config{%#v}\n", conf)
// log
confFile = os.Getenv(APP_LOG_CONF_FILE)
if confFile == "" {
panic(fmt.Sprintf("log configure file name is nil"))
return
}
if path.Ext(confFile) != ".xml" {
panic(fmt.Sprintf("log configure file name{%v} suffix must be .xml", confFile))
return
}
log.LoadConfiguration(confFile)
return
}
/******************************************************
# DESC : echo package handler
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-04 13:08
# FILE : handler.go
******************************************************/
package main
import (
"errors"
"sync"
"time"
)
import (
"github.com/AlexStocks/getty"
log "github.com/AlexStocks/log4go"
)
var (
errTooManySessions = errors.New("Too many echo sessions!")
)
type PackageHandler interface {
Handle(*getty.Session, *EchoPackage)
}
////////////////////////////////////////////
// heartbeat handler
////////////////////////////////////////////
type HeartbeatHandler struct{}
func (this *HeartbeatHandler) Handle(session *getty.Session, pkg *EchoPackage) {
log.Debug("get echo heartbeat package{%s}", pkg)
var rspPkg EchoPackage
rspPkg.H = pkg.H
rspPkg.B = echoHeartbeatResponseString
rspPkg.H.Len = uint16(len(rspPkg.B))
session.WritePkg(&rspPkg)
}
////////////////////////////////////////////
// message handler
////////////////////////////////////////////
type MessageHandler struct{}
func (this *MessageHandler) Handle(session *getty.Session, pkg *EchoPackage) {
log.Debug("get echo package{%s}", pkg)
session.WritePkg(pkg)
}
////////////////////////////////////////////
// EchoMessageHandler
////////////////////////////////////////////
type clientEchoSession struct {
session *getty.Session
active time.Time
reqNum int32
}
type EchoMessageHandler struct {
handlers map[uint32]PackageHandler
rwlock sync.RWMutex
sessionMap map[*getty.Session]*clientEchoSession
}
func newEchoMessageHandler() *EchoMessageHandler {
handlers := make(map[uint32]PackageHandler)
handlers[heartbeatCmd] = &HeartbeatHandler{}
handlers[echoCmd] = &MessageHandler{}
return &EchoMessageHandler{sessionMap: make(map[*getty.Session]*clientEchoSession), handlers: handlers}
}
func (this *EchoMessageHandler) OnOpen(session *getty.Session) error {
var (
err error
)
this.rwlock.RLock()
if maxSessionNum < len(this.sessionMap) {
err = errTooManySessions
}
this.rwlock.RUnlock()
if err != nil {
return err
}
log.Info("got session:%s", session.Stat())
this.rwlock.Lock()
this.sessionMap[session] = &clientEchoSession{session: session, active: time.Now()}
this.rwlock.Unlock()
return nil
}
func (this *EchoMessageHandler) OnError(session *getty.Session, err error) {
log.Info("session{%s} got error{%v}, will be closed.", session.Stat(), err)
this.rwlock.Lock()
delete(this.sessionMap, session)
this.rwlock.Unlock()
}
func (this *EchoMessageHandler) OnClose(session *getty.Session) {
log.Info("session{%s} is closing......", session.Stat())
this.rwlock.Lock()
delete(this.sessionMap, session)
this.rwlock.Unlock()
}
func (this *EchoMessageHandler) OnMessage(session *getty.Session, pkg interface{}) {
p, ok := pkg.(*EchoPackage)
if !ok {
log.Error("illegal packge{%#v}", pkg)
return
}
handler, ok := this.handlers[p.H.Command]
if !ok {
log.Error("illegal command{%d}", p.H.Command)
return
}
handler.Handle(session, p)
this.rwlock.Lock()
if _, ok := this.sessionMap[session]; ok {
this.sessionMap[session].active = time.Now()
this.sessionMap[session].reqNum++
}
this.rwlock.Unlock()
}
func (this *EchoMessageHandler) OnCron(session *getty.Session) {
var flag bool
this.rwlock.RLock()
if _, ok := this.sessionMap[session]; ok {
if conf.sessionTimeout.Nanoseconds() < time.Since(this.sessionMap[session].active).Nanoseconds() {
flag = true
log.Warn("session{%s} timeout{%s}, reqNum{%d}",
session.Stat(), time.Since(this.sessionMap[session].active).String(), this.sessionMap[session].reqNum)
}
}
this.rwlock.RUnlock()
if flag {
this.rwlock.Lock()
delete(this.sessionMap, session)
this.rwlock.Unlock()
session.Close()
}
}
/******************************************************
# DESC : echo stream parser
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-04 13:08
# FILE : readwriter.go
******************************************************/
package main
import (
"bytes"
"errors"
"time"
)
import (
"github.com/AlexStocks/getty"
log "github.com/AlexStocks/log4go"
)
type EchoPackageHandler struct {
}
func NewEchoPackageHandler() *EchoPackageHandler {
return &EchoPackageHandler{}
}
func (this *EchoPackageHandler) Read(ss *getty.Session, data []byte) (interface{}, int, error) {
var (
err error
len int
pkg EchoPackage
buf *bytes.Buffer
)
buf = bytes.NewBuffer(data)
len, err = pkg.Unmarshal(buf)
if err != nil {
if err == ErrNotEnoughSteam {
return nil, 0, nil
}
return nil, 0, err
}
return &pkg, len, nil
}
func (this *EchoPackageHandler) Write(ss *getty.Session, pkg interface{}) error {
var (
ok bool
err error
startTime time.Time
echoPkg *EchoPackage
buf *bytes.Buffer
)
startTime = time.Now()
if echoPkg, ok = pkg.(*EchoPackage); !ok {
log.Error("illegal pkg:%+v\n", pkg)
return errors.New("invalid echo package!")
}
buf, err = echoPkg.Marshal()
if err != nil {
log.Warn("binary.Write(echoPkg{%#v}) = err{%#v}", echoPkg, err)
return err
}
err = ss.WriteBytes(buf.Bytes())
log.Info("WriteEchoPkgTimeMs = %s", time.Since(startTime).String())
return err
}
/******************************************************
# DESC : echo server
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-04 15:49
# FILE : server.go
******************************************************/
package main
import (
// "flag"
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
// "strings"
"syscall"
"time"
)
import (
"github.com/AlexStocks/getty"
log "github.com/AlexStocks/log4go"
)
const (
tcpRBufSize = 256 * 1024
tcpWBufSize = 64 * 1024
pkgRQSize = 1024
pkgWQSize = 64
tcpReadTimeout = 1e9
tcpWriteTimeout = 5e9
waitTimeout = 5e9 // 5s
echoSessionTimeout = 5e9
maxSessionNum = 100
sessionName = "echo-server"
)
const (
survivalTimeout = 3e9
pprofPath = "/debug/pprof/"
)
var (
// host = flag.String("host", "127.0.0.1", "local host address that server app will use")
// ports = flag.String("ports", "12345,12346,12347", "local host port list that the server app will bind")
)
var (
serverList []*getty.Server
)
func main() {
// flag.Parse()
// if *host == "" || *ports == "" {
// panic(fmt.Sprintf("Please intput local host ip or port lists"))
// }
initConf()
initProfiling()
initServer()
initSignal()
}
func initProfiling() {
var (
addr string
)
// addr = *host + ":" + "10000"
addr = getty.HostAddress(conf.Host, conf.ProfilePort)
log.Info("App Profiling startup on address{%v}", addr+pprofPath)
go func() {
log.Info(http.ListenAndServe(addr, nil))
}()
}
func newSession(session *getty.Session) error {
var (
ok bool
tcpConn *net.TCPConn
)
if tcpConn, ok = session.Conn().(*net.TCPConn); !ok {
panic(fmt.Sprintf("%s, session.conn{%#v} is not tcp connection\n", session.Stat(), session.Conn()))
}
tcpConn.SetNoDelay(true)
tcpConn.SetReadBuffer(tcpRBufSize)
tcpConn.SetWriteBuffer(tcpWBufSize)
tcpConn.SetKeepAlive(true)
session.SetName(sessionName)
session.SetPkgHandler(NewEchoPackageHandler())
session.SetEventListener(newEchoMessageHandler())
session.SetRQLen(pkgRQSize)
session.SetWQLen(pkgWQSize)
session.SetReadDeadline(tcpReadTimeout)
session.SetWriteDeadline(tcpWriteTimeout)
session.SetWaitTime(waitTimeout)
log.Debug("app accepts new session:%s\n", session.Stat())
return nil
}
func initServer() {
var (
err error
addr string
portList []string
server *getty.Server
)
// if *host == "" {
// panic("host can not be nil")
// }
// if *ports == "" {
// panic("ports can not be nil")
// }
// portList = strings.Split(*ports, ",")
portList = conf.Ports
if len(portList) == 0 {
panic("portList is nil")
}
for _, port := range portList {
server = getty.NewServer()
// addr = *host + ":" + port
addr = conf.Host + ":" + port
err = server.Listen("tcp", addr)
if err != nil {
panic(fmt.Sprintf("server.Listen(tcp, addr:%s) = error{%#v}", addr, err))
}
// run server
server.RunEventloop(newSession)
log.Debug("server bind addr{%s} ok!", addr)
serverList = append(serverList, server)
}
}
func uninitServer() {
for _, server := range serverList {
server.Close()
}
}
func initSignal() {
signals := make(chan os.Signal, 1)
// It is not possible to block SIGKILL or syscall.SIGSTOP
signal.Notify(signals, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
sig := <-signals
log.Info("get signal %s", sig.String())
switch sig {
case syscall.SIGHUP:
// reload()
default:
go time.AfterFunc(survivalTimeout, func() {
log.Warn("app exit now by force...")
os.Exit(1)
})
// 要么survialTimeout时间内执行完毕下面的逻辑然后程序退出,要么执行上面的超时函数程序强行退出
uninitServer()
fmt.Println("app exit now...")
return
}
}
}
/******************************************************
# DESC : getty utility
# AUTHOR : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-08-22 17:44
# FILE : utils.go
******************************************************/
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"unsafe"
)
import (
log "github.com/AlexStocks/log4go"
)
////////////////////////////////////////////
// echo command
////////////////////////////////////////////
type echoCommand uint32
const (
heartbeatCmd = iota
echoCmd
)
var echoCommandStrings = [...]string{
"heartbeat",
"echo",
}
func (c echoCommand) String() string {
return echoCommandStrings[c]
}
////////////////////////////////////////////
// EchoPkgHandler
////////////////////////////////////////////
const (
echoPkgMagic = 0x20160905
maxEchoStringLen = 0xff
echoHeartbeatRequestString = "ping"
echoHeartbeatResponseString = "pong"
echoMessage = "Hello, getty!"
)
var (
ErrNotEnoughSteam = errors.New("packet stream is not enough")
ErrTooLargePackage = errors.New("package length is exceed the echo package's legal maximum length.")
ErrIllegalMagic = errors.New("package magic is not right.")
)
var (
echoPkgHeaderLen int
)
func init() {
echoPkgHeaderLen = (int)((uint)(unsafe.Sizeof(EchoPkgHeader{})))
}
type EchoPkgHeader struct {
Magic uint32
LogID uint32 // log id
Sequence uint32 // request/response sequence
ServiceID uint32 // service id
Command uint32 // operation command code
Code int32 // error code
Len uint16 // body length
_ uint16
_ int32 // reserved, maybe used as package md5 checksum
}
type EchoPackage struct {
H EchoPkgHeader
B string
}
func (this EchoPackage) String() string {
return fmt.Sprintf("log id:%d, sequence:%d, command:%s, echo string:%s",
this.H.LogID, this.H.Sequence, (echoCommand(this.H.Command)).String(), this.B)
}
func (this EchoPackage) Marshal() (*bytes.Buffer, error) {
var (
err error
buf *bytes.Buffer
)
buf = &bytes.Buffer{}
err = binary.Write(buf, binary.LittleEndian, this.H)
if err != nil {
return nil, err
}
buf.WriteByte((byte)(len(this.B)))
buf.WriteString(this.B)
return buf, nil
}
func (this *EchoPackage) Unmarshal(buf *bytes.Buffer) (int, error) {
var (
err error
len byte
)
if buf.Len() < echoPkgHeaderLen {
return 0, ErrNotEnoughSteam
}
// header
err = binary.Read(buf, binary.LittleEndian, &(this.H))
if err != nil {
return 0, err
}
if this.H.Magic != echoPkgMagic {
log.Error("@this.H.Magic{%x}, right magic{%x}", this.H.Magic, echoPkgMagic)
return 0, ErrIllegalMagic
}
if buf.Len() < (int)(this.H.Len) {
return 0, ErrNotEnoughSteam
}
if maxEchoStringLen < this.H.Len {
return 0, ErrTooLargePackage
}
len, err = buf.ReadByte()
if err != nil {
return 0, nil
}
this.B = (string)(buf.Next((int)(len)))
return (int)(this.H.Len) + echoPkgHeaderLen, nil
}
/******************************************************
# DESC : echo server version
# MAINTAINER : Alex Stocks
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-09-06 11:23
# FILE : version.go
******************************************************/
package main
var (
Version = "0.3.04"
)
#!/usr/bin/env bash
# ******************************************************
# DESC : getty app devops script
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : LGPL V3
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-05-13 02:01
# FILE : load.sh
# ******************************************************
APP_NAME="APPLICATION_NAME"
APP_ARGS=""
PROJECT_HOME=""
OS_NAME=`uname`
if [[ ${OS_NAME} == "Linux" ]]; then
PROJECT_HOME=`pwd`
PROJECT_HOME=${PROJECT_HOME}"/"
fi
export APP_CONF_FILE=${PROJECT_HOME}"TARGET_CONF_FILE"
export APP_LOG_CONF_FILE=${PROJECT_HOME}"TARGET_LOG_CONF_FILE"
usage() {
echo "Usage: $0 start"
echo " $0 stop"
echo " $0 term"
echo " $0 restart"
echo " $0 list"
exit
}
start() {
APP_LOG_PATH=${PROJECT_HOME}"logs/"
mkdir -p ${APP_LOG_PATH}
APP_BIN=${PROJECT_HOME}sbin/${APP_NAME}
chmod u+x ${APP_BIN}
# CMD="nohup ${APP_BIN} ${APP_ARGS} >>${APP_NAME}.nohup.out 2>&1 &"
CMD="${APP_BIN}"
eval ${CMD}
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $2}'`
if [[ ${OS_NAME} != "Linux" ]]; then
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $1}'`
fi
if [ "${PID}" != "" ];
then
for p in ${PID}
do
echo "start ${APP_NAME} ( pid =" ${p} ")"
done
fi
}
stop() {
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $2}'`
if [[ ${OS_NAME} != "Linux" ]]; then
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $1}'`
fi
if [ "${PID}" != "" ];
then
for ps in ${PID}
do
echo "kill -SIGINT ${APP_NAME} ( pid =" ${ps} ")"
kill -2 ${ps}
done
fi
}
term() {
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $2}'`
if [[ ${OS_NAME} != "Linux" ]]; then
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{print $1}'`
fi
if [ "${PID}" != "" ];
then
for ps in ${PID}
do
echo "kill -9 ${APP_NAME} ( pid =" ${ps} ")"
kill -9 ${ps}
done
fi
}
list() {
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{printf("%s,%s,%s,%s\n", $1, $2, $9, $10)}'`
if [[ ${OS_NAME} != "Linux" ]]; then
PID=`ps aux | grep -w ${APP_NAME} | grep -v grep | awk '{printf("%s,%s,%s,%s,%s\n", $1, $4, $6, $7, $8)}'`
fi
if [ "${PID}" != "" ];
then
echo "list ${APP_NAME}"
if [[ ${OS_NAME} == "Linux" ]]; then
echo "index: user, pid, start, duration"
else
echo "index: PID, WINPID, UID, STIME, COMMAND"
fi
idx=0
for ps in ${PID}
do
echo "${idx}: ${ps}"
((idx ++))
done
fi
}
opt=$1
case C"$opt" in
Cstart)
start
;;
Cstop)
stop
;;
Cterm)
term
;;
Crestart)
term
start
;;
Clist)
list
;;
C*)
usage
;;
esac
# dubbogo application configure script
# ******************************************************
# DESC : application environment variable
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:29
# FILE : app.properties
# ******************************************************
TARGET_EXEC_NAME="echo_server"
BUILD_PACKAGE="app"
TARGET_CONF_FILE="conf/config.toml"
TARGET_LOG_CONF_FILE="conf/log.xml"
#!/usr/bin/env bash
# ******************************************************
# DESC : build script
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:28
# FILE : build.sh
# ******************************************************
rm -rf target/
PROJECT_HOME=`pwd`
TARGET_FOLDER=${PROJECT_HOME}/target/${GOOS}
TARGET_SBIN_NAME=${TARGET_EXEC_NAME}
version=`cat app/version.go | grep Version | awk -F '=' '{print $2}' | awk -F '"' '{print $2}'`
if [[ ${GOOS} == "windows" ]]; then
TARGET_SBIN_NAME=${TARGET_SBIN_NAME}.exe
fi
TARGET_NAME=${TARGET_FOLDER}/${TARGET_SBIN_NAME}
if [[ $PROFILE = "test" ]]; then
# GFLAGS=-gcflags "-N -l" -race -x -v # -x会把go build的详细过程输出
# GFLAGS=-gcflags "-N -l" -race -v
# GFLAGS="-gcflags \"-N -l\" -v"
cd ${BUILD_PACKAGE} && go build -gcflags "-N -l" -x -v -i -o ${TARGET_NAME} && cd -
else
# -s去掉符号表(然后panic时候的stack trace就没有任何文件名/行号信息了,这个等价于普通C/C++程序被strip的效果),
# -w去掉DWARF调试信息,得到的程序就不能用gdb调试了。-s和-w也可以分开使用,一般来说如果不打算用gdb调试,
# -w基本没啥损失。-s的损失就有点大了。
cd ${BUILD_PACKAGE} && go build -ldflags "-w" -x -v -i -o ${TARGET_NAME} && cd -
fi
TAR_NAME=${TARGET_EXEC_NAME}-${version}-`date "+%Y%m%d-%H%M"`-${PROFILE}
mkdir -p ${TARGET_FOLDER}/${TAR_NAME}
SBIN_DIR=${TARGET_FOLDER}/${TAR_NAME}/sbin
BIN_DIR=${TARGET_FOLDER}/${TAR_NAME}
CONF_DIR=${TARGET_FOLDER}/${TAR_NAME}/conf
mkdir -p ${SBIN_DIR}
mkdir -p ${CONF_DIR}
mv ${TARGET_NAME} ${SBIN_DIR}
cp -r assembly/bin ${BIN_DIR}
# modify APPLICATION_NAME
sed -i "s~APPLICATION_NAME~${TARGET_EXEC_NAME}~g" ${BIN_DIR}/bin/*
# modify TARGET_CONF_FILE
sed -i "s~TARGET_CONF_FILE~${TARGET_CONF_FILE}~g" ${BIN_DIR}/bin/*
# modify TARGET_LOG_CONF_FILE
sed -i "s~TARGET_LOG_CONF_FILE~${TARGET_LOG_CONF_FILE}~g" ${BIN_DIR}/bin/*
cp -r profiles/${PROFILE}/* ${CONF_DIR}
cd ${TARGET_FOLDER}
tar czf ${TAR_NAME}.tar.gz ${TAR_NAME}/*
#!/usr/bin/env bash
# ******************************************************
# DESC : build script for test env
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : LGPL V3
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:34
# FILE : test.sh
# ******************************************************
set -e
export GOOS=linux
export GOARCH=amd64
PROFILE=test
PROJECT_HOME=`pwd`
if [ -f "${PROJECT_HOME}/assembly/common/app.properties" ]; then
. ${PROJECT_HOME}/assembly/common/app.properties
fi
if [ -f "${PROJECT_HOME}/assembly/common/build.sh" ]; then
. ${PROJECT_HOME}/assembly/common/build.sh
fi
#!/usr/bin/env bash
# ******************************************************
# DESC : build script for test env
# AUTHOR : Alex Stocks
# VERSION : 1.0
# LICENCE : Apache License 2.0
# EMAIL : alexstocks@foxmail.com
# MOD : 2016-07-12 16:34
# FILE : test.sh
# ******************************************************
set -e
export GOOS=windows
export GOARCH=amd64
PROFILE=test
PROJECT_HOME=`pwd`
if [ -f "${PROJECT_HOME}/assembly/common/app.properties" ]; then
. ${PROJECT_HOME}/assembly/common/app.properties
fi
if [ -f "${PROJECT_HOME}/assembly/common/build.sh" ]; then
. ${PROJECT_HOME}/assembly/common/build.sh
fi
# toml configure file
# Host = "127.0.0.1"
Host = "192.168.35.1"
Ports = ["10000", "20000"]
ProfilePort = 10086
# client与server之间连接的超时时间
SessionTimeout = "20s"
# getty #
---
*a netty like asynchronous network I/O library*
## license ##
---
Apache License 2.0
## getty examples ##
---
*getty examples是基于getty的实现的代码示例*
> dubbogo-examples借鉴java的编译思路,提供了区别于一般的go程序的而类似于java的独特的编译脚本系统。
### dubogo example1: echo ###
---
*这个程序是为了给出代码示例以及执行压力测试*
> 1 部署zookeeper服务;
>
> 2 请部署 https://github.com/QianmiOpen/dubbo-rpc-jsonrpc 服务端,如果你不想编译,可以使用我编译好的 dubbogo-examples/user-info/java-server/dubbo_jsonrpc_example.bz2,注意修改zk地址;
>
> 3 修改dubbogo-examples/user-info/client/profiles/test/client.toml:line 33,写入正确的zk地址;
>
> 4 dubbogo-examples/user-info/client/下执行 sh assembly/windows/test.sh命令(linux下请执行sh assembly/linux/test.sh),然后target/windows下即放置好了编译好的程序以及打包结果,在dubbogo-examples\user-info\client\target\windows\user_info_client-0.1.0-20160818-1346-test下执行sh bin/load.sh start命令即可客户端程序;
>
> 5 修改dubbogo-examples/user-info/server/profiles/test/server.toml:line 21,写入正确的zk地址;
>
> 6 dubbogo-examples/user-info/server/下执行 sh assembly/windows/test.sh命令(linux下请执行sh assembly/linux/test.sh),然后target/windows下即放置好了编译好的程序以及打包结果,在dubbogo-examples\user-info\server\target\windows\user_info_server-0.1.0-xxxx下执行sh bin/load.sh start命令即可服务端程序;
>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment