Browse Source

Version 1.0

zry 1 year ago
parent
commit
911db9679b

+ 1 - 1
.gitignore

@@ -23,4 +23,4 @@ _testmain.go
 *.exe
 *.test
 *.prof
-
+*.key

+ 8 - 0
.idea/go-zSshRpcServer.iml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/go-zSshRpcServer.iml" filepath="$PROJECT_DIR$/.idea/go-zSshRpcServer.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 97 - 0
easyophdl/EasyOpHdlRequest.go

@@ -0,0 +1,97 @@
+package easyophdl
+
+import (
+	"encoding/json"
+	"fmt"
+	"git.swzry.com/zry/go-zSshRpcServer/server"
+	"github.com/tidwall/gjson"
+	"golang.org/x/crypto/ssh"
+)
+
+type EasyOpHdlRequest struct {
+	RawRequest      zsshrpc_server.ZSshRpcOperationRequest
+	isGJsonProc     bool
+	gjsonResult     gjson.Result
+	isErrHappend    bool
+	isJsonProcError bool
+	errMsg          string
+	logger          zsshrpc_server.SvrLogFunc
+}
+
+func (this *EasyOpHdlRequest) GetMethodName() string {
+	return zsshrpc_server.GetOperationMethodName(this.RawRequest.Method)
+}
+
+func (this *EasyOpHdlRequest) GetUserName() string {
+	return this.RawRequest.ChannelContext.SessionCtx.ServerConn.User()
+}
+
+func (this *EasyOpHdlRequest) GetPermissions() *ssh.Permissions {
+	return this.RawRequest.ChannelContext.SessionCtx.ServerConn.Permissions
+}
+
+func (this *EasyOpHdlRequest) WriteLogInfo(msg string) {
+	this.writeLog(zsshrpc_server.SvrLogLevel_INFO, msg)
+}
+
+func (this *EasyOpHdlRequest) WriteLogDebug(msg string) {
+	this.writeLog(zsshrpc_server.SvrLogLevel_DEBUG, msg)
+}
+
+func (this *EasyOpHdlRequest) WriteErrLog(msg string, err error) {
+	this.writeLogWithError(zsshrpc_server.SvrLogLevel_WARNING, msg, err)
+}
+
+func (this *EasyOpHdlRequest) writeLog(level int, msg string) {
+	this.writeLogWithError(level, msg, nil)
+}
+
+func (this *EasyOpHdlRequest) writeLogWithError(level int, msg string, err error) {
+	this.logger(level, fmt.Sprint("Backend ", this.RawRequest.URI, " Handler Log: ", msg), err)
+}
+
+func (this *EasyOpHdlRequest) GetClientVersion() string {
+	return string(this.RawRequest.ChannelContext.SessionCtx.ServerConn.ClientVersion())
+}
+
+func (this *EasyOpHdlRequest) GetRemoteAddr() string {
+	return this.RawRequest.ChannelContext.SessionCtx.ServerConn.RemoteAddr().String()
+}
+
+func (this *EasyOpHdlRequest) ProcGJson() {
+	this.gjsonResult = gjson.Parse(this.RawRequest.JSON)
+	this.isGJsonProc = true
+}
+
+func (this *EasyOpHdlRequest) GJsonGet(path string) *gjson.Result {
+	if this.isGJsonProc {
+		gjo := this.gjsonResult.Get(path)
+		return &gjo
+	} else {
+		this.isErrHappend = true
+		this.errMsg = "Do GJson Getting Operation Before ProcGJson."
+		this.doErrLog()
+		return nil
+	}
+}
+
+func (this *EasyOpHdlRequest) ProcRegularJson(v interface{}) bool {
+	err := json.Unmarshal([]byte(this.RawRequest.JSON), v)
+	if err != nil {
+		this.isErrHappend = true
+		this.isJsonProcError = true
+		this.errMsg = fmt.Sprint("Failed ProcRegularJson: ", err)
+		this.doErrLog()
+		return false
+	}
+	return true
+}
+
+func (this *EasyOpHdlRequest) doErrLog() {
+	if this.isErrHappend {
+		this.logger(zsshrpc_server.SvrLogLevel_WARNING,
+			fmt.Sprint("Internal Error: ", this.errMsg),
+			nil,
+		)
+	}
+}

+ 70 - 0
easyophdl/EasyOpHdlResponse.go

@@ -0,0 +1,70 @@
+package easyophdl
+
+import (
+	"encoding/json"
+	"fmt"
+	"git.swzry.com/zry/go-zSshRpcServer/server"
+	"github.com/bitly/go-simplejson"
+)
+
+type EasyOpHdlResponse struct {
+	statusCode       int
+	responseJson     string
+	isErrHappend     bool
+	errMsg           string
+	isUseSimpleJson  bool
+	isUseRegularJson bool
+	logger           zsshrpc_server.SvrLogFunc
+	simpleJson       *simplejson.Json
+}
+
+func (this *EasyOpHdlResponse) UseSimpleJson() {
+	if this.isUseRegularJson {
+		this.isErrHappend = true
+		this.errMsg = "Only Can Use One of SimpleJson or RegularJson."
+		this.doErrLog()
+	} else {
+		this.isUseSimpleJson = true
+		this.simpleJson = simplejson.New()
+	}
+}
+
+func (this *EasyOpHdlResponse) SimplePut(key string, content interface{}) {
+	if this.isUseSimpleJson {
+		this.simpleJson.Set(key, content)
+	} else {
+		this.isErrHappend = true
+		this.errMsg = "Call SimplePut Before Declared UseSimpleJson."
+		this.doErrLog()
+	}
+}
+
+func (this *EasyOpHdlResponse) UseRegularJson(v interface{}) {
+	if this.isUseSimpleJson {
+		this.isErrHappend = true
+		this.errMsg = "Only Can Use One of SimpleJson or RegularJson."
+		this.doErrLog()
+	} else {
+		this.isUseRegularJson = true
+		jdata, err := json.Marshal(v)
+		if err != nil {
+			this.isErrHappend = true
+			this.errMsg = fmt.Sprint("Failed Encoding Json: ", err)
+			this.doErrLog()
+		}
+		this.responseJson = string(jdata)
+	}
+}
+
+func (this *EasyOpHdlResponse) SetStatusCode(code int) {
+	this.statusCode = code
+}
+
+func (this *EasyOpHdlResponse) doErrLog() {
+	if this.isErrHappend {
+		this.logger(zsshrpc_server.SvrLogLevel_WARNING,
+			fmt.Sprint("Internal Error: ", this.errMsg),
+			nil,
+		)
+	}
+}

+ 394 - 0
easyophdl/EasyOperationHandler.go

@@ -0,0 +1,394 @@
+package easyophdl
+
+import (
+	"fmt"
+	"git.swzry.com/zry/go-zSshRpcServer/server"
+	"github.com/bitly/go-simplejson"
+	"sync"
+)
+
+type EasyOperationHandleFunc func(request *EasyOpHdlRequest, response *EasyOpHdlResponse)
+
+type EasyOperationHandler struct {
+	IsDebug             bool
+	SuggestWhenNotFound bool
+	LogSuccessAccess    bool
+	LogFailedAccess     bool
+	logger              zsshrpc_server.SvrLogFunc
+	handlerMap          map[string]map[zsshrpc_server.ZSshRpcMethod]EasyOperationHandleFunc
+	m                   sync.RWMutex
+}
+
+func NewEasyOperationHandler() *EasyOperationHandler {
+	o := &EasyOperationHandler{
+		IsDebug:             false,
+		SuggestWhenNotFound: false,
+		LogSuccessAccess:    true,
+		LogFailedAccess:     true,
+		logger: func(level int, msg string, err error) {
+		},
+	}
+	o.handlerMap = make(map[string]map[zsshrpc_server.ZSshRpcMethod]EasyOperationHandleFunc)
+	return o
+}
+
+func (this *EasyOperationHandler) EnableDebug() {
+	this.IsDebug = true
+}
+
+func (this *EasyOperationHandler) DisableAccessSuccessLog() {
+	this.LogSuccessAccess = false
+}
+
+func (this *EasyOperationHandler) DisableAccessFailLog() {
+	this.LogFailedAccess = false
+}
+
+func (this *EasyOperationHandler) EnableUriSuggestWhenNotFound() {
+	this.SuggestWhenNotFound = true
+}
+
+func (this *EasyOperationHandler) UseLogger(logger zsshrpc_server.SvrLogFunc) {
+	this.logger = logger
+}
+
+func (this *EasyOperationHandler) HandleOperation(request zsshrpc_server.ZSshRpcOperationRequest) zsshrpc_server.ZSshRpcOperationResponse {
+	this.m.RLock()
+	uv, ok := this.handlerMap[request.URI]
+	this.m.RUnlock()
+	if ok {
+		this.m.RLock()
+		mv, ok := uv[request.Method]
+		this.m.RUnlock()
+		if ok {
+			ereq := &EasyOpHdlRequest{
+				RawRequest:      request,
+				isGJsonProc:     false,
+				isErrHappend:    false,
+				isJsonProcError: false,
+				logger:          this.logger,
+			}
+			eresp := &EasyOpHdlResponse{
+				isUseRegularJson: false,
+				isUseSimpleJson:  false,
+				isErrHappend:     false,
+				logger:           this.logger,
+				responseJson:     "{}",
+				statusCode:       zsshrpc_server.ResponseStatusCode_OK,
+			}
+			mv(ereq, eresp)
+			if ereq.isErrHappend {
+				if ereq.isJsonProcError {
+					if this.LogFailedAccess {
+						this.logger(zsshrpc_server.SvrLogLevel_INFO,
+							fmt.Sprintf("%s %s -> %s",
+								zsshrpc_server.GetOperationMethodName(request.Method),
+								request.URI,
+								zsshrpc_server.GetResponseStatusCodeString(601),
+							),
+							nil,
+						)
+					}
+					respj := simplejson.New()
+					errj := simplejson.New()
+					extmsgj := simplejson.New()
+					extmsgj.Set("description", "JSON Decode Failed.")
+					if this.IsDebug {
+						extmsgj.Set("detail", ereq.errMsg)
+					}
+					errj.Set("code", 601)
+					errj.Set("msg", zsshrpc_server.GetResponseStatusCodeString(601))
+					errj.Set("ext_err_msg", extmsgj)
+					respj.Set("err", errj)
+					jdata, err := respj.MarshalJSON()
+					if err != nil {
+						this.logger(zsshrpc_server.SvrLogLevel_WARNING,
+							fmt.Sprint("Internal Error: ", err.Error()),
+							nil,
+						)
+						if this.IsDebug {
+							return zsshrpc_server.ZSshRpcOperationResponse{
+								StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+								ResponseJSON: `{"internal_fatal_error":"` + err.Error() + `"}`,
+							}
+						} else {
+							return zsshrpc_server.ZSshRpcOperationResponse{
+								StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+								ResponseJSON: "{}",
+							}
+						}
+					}
+					return zsshrpc_server.ZSshRpcOperationResponse{
+						StatusCode:   zsshrpc_server.ResponseStatusCode_JSON_DECODE_ERROR,
+						ResponseJSON: string(jdata),
+					}
+				} else {
+					if this.LogFailedAccess {
+						this.logger(zsshrpc_server.SvrLogLevel_INFO,
+							fmt.Sprintf("%s %s -> %s",
+								zsshrpc_server.GetOperationMethodName(request.Method),
+								request.URI,
+								zsshrpc_server.GetResponseStatusCodeString(500),
+							),
+							nil,
+						)
+					}
+					respj := simplejson.New()
+					errj := simplejson.New()
+					extmsgj := simplejson.New()
+					extmsgj.Set("description", "Internal Error.")
+					if this.IsDebug {
+						extmsgj.Set("detail", ereq.errMsg)
+					}
+					errj.Set("code", 500)
+					errj.Set("msg", zsshrpc_server.GetResponseStatusCodeString(500))
+					errj.Set("ext_err_msg", extmsgj)
+					respj.Set("err", errj)
+					jdata, err := respj.MarshalJSON()
+					if err != nil {
+						this.logger(zsshrpc_server.SvrLogLevel_WARNING,
+							fmt.Sprint("Internal Error: ", err.Error()),
+							nil,
+						)
+						if this.IsDebug {
+							return zsshrpc_server.ZSshRpcOperationResponse{
+								StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+								ResponseJSON: `{"internal_fatal_error":"` + err.Error() + `"}`,
+							}
+						} else {
+							return zsshrpc_server.ZSshRpcOperationResponse{
+								StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+								ResponseJSON: "{}",
+							}
+						}
+					}
+					return zsshrpc_server.ZSshRpcOperationResponse{
+						StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+						ResponseJSON: string(jdata),
+					}
+				}
+			}
+			if eresp.isErrHappend {
+				if this.LogFailedAccess {
+					this.logger(zsshrpc_server.SvrLogLevel_INFO,
+						fmt.Sprintf("%s %s -> %s",
+							zsshrpc_server.GetOperationMethodName(request.Method),
+							request.URI,
+							zsshrpc_server.GetResponseStatusCodeString(500),
+						),
+						nil,
+					)
+				}
+				respj := simplejson.New()
+				errj := simplejson.New()
+				extmsgj := simplejson.New()
+				extmsgj.Set("description", "Internal Error.")
+				if this.IsDebug {
+					extmsgj.Set("detail", eresp.errMsg)
+				}
+				errj.Set("code", 500)
+				errj.Set("msg", zsshrpc_server.GetResponseStatusCodeString(500))
+				errj.Set("ext_err_msg", extmsgj)
+				respj.Set("err", errj)
+				jdata, err := respj.MarshalJSON()
+				if err != nil {
+					this.logger(zsshrpc_server.SvrLogLevel_WARNING,
+						fmt.Sprint("Internal Error: ", err.Error()),
+						nil,
+					)
+					if this.IsDebug {
+						return zsshrpc_server.ZSshRpcOperationResponse{
+							StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+							ResponseJSON: `{"internal_fatal_error":"` + err.Error() + `"}`,
+						}
+					} else {
+						return zsshrpc_server.ZSshRpcOperationResponse{
+							StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+							ResponseJSON: "{}",
+						}
+					}
+				}
+				return zsshrpc_server.ZSshRpcOperationResponse{
+					StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+					ResponseJSON: string(jdata),
+				}
+			} else {
+				if eresp.isUseSimpleJson {
+					ejd, err := eresp.simpleJson.MarshalJSON()
+					if err != nil {
+						if this.LogFailedAccess {
+							this.logger(zsshrpc_server.SvrLogLevel_INFO,
+								fmt.Sprintf("%s %s -> %s",
+									zsshrpc_server.GetOperationMethodName(request.Method),
+									request.URI,
+									zsshrpc_server.GetResponseStatusCodeString(500),
+								),
+								nil,
+							)
+						}
+						respj := simplejson.New()
+						errj := simplejson.New()
+						extmsgj := simplejson.New()
+						extmsgj.Set("description", "Internal Error.")
+						if this.IsDebug {
+							extmsgj.Set("detail", err)
+						}
+						errj.Set("code", 500)
+						errj.Set("msg", zsshrpc_server.GetResponseStatusCodeString(500))
+						errj.Set("ext_err_msg", extmsgj)
+						respj.Set("err", errj)
+						jdata, err := respj.MarshalJSON()
+						if err != nil {
+							this.logger(zsshrpc_server.SvrLogLevel_WARNING,
+								fmt.Sprint("Internal Error: ", err.Error()),
+								nil,
+							)
+							if this.IsDebug {
+								return zsshrpc_server.ZSshRpcOperationResponse{
+									StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+									ResponseJSON: `{"internal_fatal_error":"` + err.Error() + `"}`,
+								}
+							} else {
+								return zsshrpc_server.ZSshRpcOperationResponse{
+									StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+									ResponseJSON: "{}",
+								}
+							}
+						}
+						return zsshrpc_server.ZSshRpcOperationResponse{
+							StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+							ResponseJSON: string(jdata),
+						}
+					}
+					eresp.responseJson = string(ejd)
+				}
+			}
+			if this.LogSuccessAccess {
+				this.logger(zsshrpc_server.SvrLogLevel_INFO,
+					fmt.Sprintf("%s %s -> %s",
+						zsshrpc_server.GetOperationMethodName(request.Method),
+						request.URI,
+						zsshrpc_server.GetResponseStatusCodeString(eresp.statusCode),
+					),
+					nil,
+				)
+			}
+			return zsshrpc_server.ZSshRpcOperationResponse{
+				StatusCode:   eresp.statusCode,
+				ResponseJSON: eresp.responseJson,
+			}
+		} else {
+			if this.LogFailedAccess {
+				this.logger(zsshrpc_server.SvrLogLevel_INFO,
+					fmt.Sprintf("%s %s -> %s",
+						zsshrpc_server.GetOperationMethodName(request.Method),
+						request.URI,
+						zsshrpc_server.GetResponseStatusCodeString(405),
+					),
+					nil,
+				)
+			}
+			respj := simplejson.New()
+			errj := simplejson.New()
+			extmsgj := simplejson.New()
+			methodlist := make([]string, 0)
+			for key, _ := range uv {
+				methodlist = append(methodlist, zsshrpc_server.GetOperationMethodName(key))
+			}
+			extmsgj.Set("description",
+				"Method '"+zsshrpc_server.GetOperationMethodName(request.Method)+"' Not Allowed With URI '"+
+					request.URI+"'.",
+			)
+			extmsgj.Set("allowed_methods", methodlist)
+			errj.Set("code", 405)
+			errj.Set("msg", zsshrpc_server.GetResponseStatusCodeString(405))
+			errj.Set("ext_err_msg", extmsgj)
+			respj.Set("err", errj)
+			jdata, err := respj.MarshalJSON()
+			if err != nil {
+				this.logger(zsshrpc_server.SvrLogLevel_WARNING,
+					fmt.Sprint("Internal Error: ", err.Error()),
+					nil,
+				)
+				if this.IsDebug {
+					return zsshrpc_server.ZSshRpcOperationResponse{
+						StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+						ResponseJSON: `{"internal_fatal_error":"` + err.Error() + `"}`,
+					}
+				} else {
+					return zsshrpc_server.ZSshRpcOperationResponse{
+						StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+						ResponseJSON: "{}",
+					}
+				}
+			}
+			return zsshrpc_server.ZSshRpcOperationResponse{
+				StatusCode:   zsshrpc_server.ResponseStatusCode_METHOD_NOT_ALLOWED,
+				ResponseJSON: string(jdata),
+			}
+		}
+	} else {
+		if this.LogFailedAccess {
+			this.logger(zsshrpc_server.SvrLogLevel_INFO,
+				fmt.Sprintf("%s %s -> %s",
+					zsshrpc_server.GetOperationMethodName(request.Method),
+					request.URI,
+					zsshrpc_server.GetResponseStatusCodeString(404),
+				),
+				nil,
+			)
+		}
+		respj := simplejson.New()
+		errj := simplejson.New()
+		extmsgj := simplejson.New()
+		extmsgj.Set("description",
+			"URI '"+request.URI+"' Not Defined In RPC Server.",
+		)
+		if this.SuggestWhenNotFound {
+			urlsuggestlist := make([]string, 0)
+			for key, _ := range this.handlerMap {
+				urlsuggestlist = append(urlsuggestlist, key)
+			}
+			extmsgj.Set("suggest_uri", urlsuggestlist)
+		}
+		errj.Set("code", 404)
+		errj.Set("msg", zsshrpc_server.GetResponseStatusCodeString(404))
+		errj.Set("ext_err_msg", extmsgj)
+		respj.Set("err", errj)
+		jdata, err := respj.MarshalJSON()
+		if err != nil {
+			this.logger(zsshrpc_server.SvrLogLevel_WARNING,
+				fmt.Sprint("Internal Error: ", err.Error()),
+				nil,
+			)
+			if this.IsDebug {
+				return zsshrpc_server.ZSshRpcOperationResponse{
+					StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+					ResponseJSON: `{"internal_fatal_error":"` + err.Error() + `"}`,
+				}
+			} else {
+				return zsshrpc_server.ZSshRpcOperationResponse{
+					StatusCode:   zsshrpc_server.ResponseStatusCode_INTERNAL_ERROR,
+					ResponseJSON: "{}",
+				}
+			}
+		}
+		return zsshrpc_server.ZSshRpcOperationResponse{
+			StatusCode:   zsshrpc_server.ResponseStatusCode_NOT_FOUND,
+			ResponseJSON: string(jdata),
+		}
+	}
+}
+
+func (this *EasyOperationHandler) AddHandler(uri string, method zsshrpc_server.ZSshRpcMethod, handler EasyOperationHandleFunc) {
+	this.m.Lock()
+	defer this.m.Unlock()
+	uv, ok := this.handlerMap[uri]
+	if ok {
+		uv[method] = handler
+	} else {
+		nuv := make(map[zsshrpc_server.ZSshRpcMethod]EasyOperationHandleFunc)
+		nuv[method] = handler
+		this.handlerMap[uri] = nuv
+	}
+}

+ 83 - 0
server/ConstAndEnum.go

@@ -0,0 +1,83 @@
+package zsshrpc_server
+
+const (
+	SvrLogLevel_DEBUG   = 0
+	SvrLogLevel_INFO    = 1
+	SvrLogLevel_WARNING = 2
+	SvrLogLevel_ERROR   = 3
+)
+
+type ZSshRpcChState int8
+
+const (
+	ChannelState_IDLE           ZSshRpcChState = 0
+	ChannelState_WAIT_URI       ZSshRpcChState = 1
+	ChannelState_WAIT_JSON      ZSshRpcChState = 2
+	ChannelState_EXEC_HANDLER   ZSshRpcChState = 3
+	ChannelState_WAIT_JSON_READ ZSshRpcChState = 4
+)
+
+type ZSshRpcMethod int8
+
+const (
+	RpcMethod_CALL ZSshRpcMethod = 0
+	RpcMethod_ADD  ZSshRpcMethod = 1
+	RpcMethod_DEL  ZSshRpcMethod = 2
+	RpcMethod_GET  ZSshRpcMethod = 3
+	RpcMethod_SET  ZSshRpcMethod = 4
+)
+
+const (
+	ResponseStatusCode_OK                  = 200
+	ResponseStatusCode_NO_CONTENT          = 204
+	ResponseStatusCode_METHOD_NOT_ALLOWED  = 405
+	ResponseStatusCode_NOT_FOUND           = 404
+	ResponseStatusCode_FORBIDDEN           = 403
+	ResponseStatusCode_INVALID_REQUEST     = 400
+	ResponseStatusCode_INTERNAL_ERROR      = 500
+	ResponseStatusCode_VERSION_NOT_SUPPORT = 505
+	ResponseStatusCode_UNKNOWN             = 600
+	ResponseStatusCode_JSON_DECODE_ERROR   = 601
+)
+
+func GetResponseStatusCodeString(code int) string {
+	switch code {
+	case 200:
+		return "OK"
+	case 204:
+		return "NO_CONTENT"
+	case 405:
+		return "METHOD_NOT_ALLOWED"
+	case 404:
+		return "NOT_FOUND"
+	case 403:
+		return "FORBIDDEN"
+	case 400:
+		return "INVALID_REQUEST"
+	case 500:
+		return "INTERNAL_ERROR"
+	case 505:
+		return "VERSION_NOT_SUPPORT"
+	case 601:
+		return "JSON_DECODE_ERROR"
+	default:
+		return "UNKNOWN"
+	}
+}
+
+func GetOperationMethodName(method ZSshRpcMethod) string {
+	switch method {
+	case RpcMethod_CALL:
+		return "CALL"
+	case RpcMethod_ADD:
+		return "ADD"
+	case RpcMethod_DEL:
+		return "DEL"
+	case RpcMethod_GET:
+		return "GET"
+	case RpcMethod_SET:
+		return "SET"
+	default:
+		return "UNKNOWN"
+	}
+}

+ 17 - 0
server/HandlerInterface.go

@@ -0,0 +1,17 @@
+package zsshrpc_server
+
+type ZSshRpcOperationRequest struct {
+	ChannelContext *ZSshRpcChannelContext
+	Method         ZSshRpcMethod
+	URI            string
+	JSON           string
+}
+
+type ZSshRpcOperationResponse struct {
+	StatusCode   int
+	ResponseJSON string
+}
+
+type ZSshRpcOperationHandler interface {
+	HandleOperation(request ZSshRpcOperationRequest) ZSshRpcOperationResponse
+}

+ 36 - 0
server/MappedOperationHandler.go

@@ -0,0 +1,36 @@
+package zsshrpc_server
+
+import "sync"
+
+type OpHandlerFunc func(request ZSshRpcOperationRequest) ZSshRpcOperationResponse
+
+type MappedOperationHandler struct {
+	handlerMap map[string]OpHandlerFunc
+	m          sync.RWMutex
+}
+
+func NewMappedOperationHandler() *MappedOperationHandler {
+	o := &MappedOperationHandler{}
+	o.handlerMap = make(map[string]OpHandlerFunc)
+	return o
+}
+
+func (this *MappedOperationHandler) HandleOperation(request ZSshRpcOperationRequest) ZSshRpcOperationResponse {
+	this.m.RLock()
+	vf, ok := this.handlerMap[request.URI]
+	this.m.RUnlock()
+	if ok {
+		return vf(request)
+	} else {
+		return ZSshRpcOperationResponse{
+			StatusCode:   ResponseStatusCode_NOT_FOUND,
+			ResponseJSON: "{}",
+		}
+	}
+}
+
+func (this *MappedOperationHandler) AddHandler(uri string, handler OpHandlerFunc) {
+	this.m.Lock()
+	this.handlerMap[uri] = handler
+	this.m.Unlock()
+}

+ 11 - 0
server/MiscUtil.go

@@ -0,0 +1,11 @@
+package zsshrpc_server
+
+import "git.swzry.com/zry/pathutils"
+
+func IsFileExists(path string) bool {
+	b, err := pathutils.PathExists(path)
+	if err != nil {
+		return false
+	}
+	return b
+}

+ 78 - 0
server/Server.go

@@ -0,0 +1,78 @@
+package zsshrpc_server
+
+import (
+	"fmt"
+	"golang.org/x/crypto/ssh"
+	"net"
+	"strings"
+)
+
+type ZSshRpcServer struct {
+	sshcfg           *ssh.ServerConfig
+	stopchan         chan int
+	logger           SvrLogFunc
+	ioBlockSize      int
+	OperationHandelr ZSshRpcOperationHandler
+}
+
+func NewZSshRpcServer(conf *ZSshRpcServerCfg) *ZSshRpcServer {
+	o := &ZSshRpcServer{}
+	o.sshcfg = &ssh.ServerConfig{
+		ServerVersion:               "SSH-2.0-zSshRpcTest-1.0",
+		NoClientAuth:                conf.NoClientAuth,
+		MaxAuthTries:                conf.MaxAuthTries,
+		PasswordCallback:            conf.PasswordCallback,
+		PublicKeyCallback:           conf.PublicKeyCallback,
+		KeyboardInteractiveCallback: conf.KeyboardInteractiveCallback,
+		AuthLogCallback:             conf.AuthLogCallback,
+	}
+	ciphers := []string{
+		"aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "arcfour256", "arcfour128",
+	}
+	if conf.Support_AES128_CBC {
+		ciphers = append(ciphers, "aes128-cbc")
+	}
+	o.sshcfg.Ciphers = ciphers
+	o.sshcfg.AddHostKey(conf.HostKey)
+	o.logger = conf.ServerLogger
+	o.OperationHandelr = conf.OperationHandler
+	o.ioBlockSize = conf.IOBlockSize
+	return o
+}
+
+func (this *ZSshRpcServer) Stop() {
+	this.stopchan <- 1
+}
+
+func (this *ZSshRpcServer) StartWithListener(listener net.Listener) error {
+	this.stopchan = make(chan int)
+	go func() {
+		<-this.stopchan
+		listener.Close()
+	}()
+	go func() {
+		for {
+			nconn, err := listener.Accept()
+			if err == nil {
+				this.logger(SvrLogLevel_INFO, fmt.Sprintf("Client '%v' Come In.", nconn.RemoteAddr()), nil)
+				go HandleNewSession(nconn, this.sshcfg, this.logger, this.OperationHandelr, this.ioBlockSize)
+			} else {
+				if strings.Contains(err.Error(), "use of closed network connection") {
+					this.logger(SvrLogLevel_INFO, "Server Terminated By User.", err)
+				} else {
+					this.logger(SvrLogLevel_ERROR, fmt.Sprintf("Failed Handle Connection From Client '%v'", nconn.RemoteAddr()), err)
+				}
+			}
+		}
+	}()
+	return nil
+}
+
+func (this *ZSshRpcServer) ListenTCP(network string, addr *net.TCPAddr) error {
+	lis, err := net.ListenTCP(network, addr)
+	if err != nil {
+		return err
+	}
+	this.StartWithListener(lis)
+	return nil
+}

+ 143 - 0
server/ServerCfg.go

@@ -0,0 +1,143 @@
+package zsshrpc_server
+
+import (
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"golang.org/x/crypto/ssh"
+	"io/ioutil"
+	"os"
+)
+
+type PasswdCb func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error)
+type PubKeyCb func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error)
+type KeyIntCb func(conn ssh.ConnMetadata, cli ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error)
+type AuthLogCb func(conn ssh.ConnMetadata, method string, err error)
+type SvrLogFunc func(level int, msg string, err error)
+
+type ZSshRpcServerCfg struct {
+	HostKey                     ssh.Signer
+	NoClientAuth                bool
+	MaxAuthTries                int
+	PasswordCallback            PasswdCb
+	PublicKeyCallback           PubKeyCb
+	KeyboardInteractiveCallback KeyIntCb
+	AuthLogCallback             AuthLogCb
+	ServerLogger                SvrLogFunc
+	Support_AES128_CBC          bool
+	OperationHandler            ZSshRpcOperationHandler
+	IOBlockSize                 int
+}
+
+func NewDefaultZSshRpcServerCfg(host_key_store_path string) (*ZSshRpcServerCfg, error) {
+	hostkey, err := GetOrGenerateHostKey(host_key_store_path, 2028)
+	if err != nil {
+		return nil, err
+	}
+	return &ZSshRpcServerCfg{
+		HostKey:                     hostkey,
+		NoClientAuth:                false,
+		MaxAuthTries:                5,
+		PasswordCallback:            defaultPasswordCallback,
+		PublicKeyCallback:           defaultPubkeyCallback,
+		KeyboardInteractiveCallback: defaultKeyIntCallback,
+		AuthLogCallback:             defaultAuthLogCb,
+		ServerLogger:                defaultServerLoggerFunc,
+		Support_AES128_CBC:          true,
+		OperationHandler:            &defaultOperationHandler{},
+		IOBlockSize:                 1024,
+	}, nil
+}
+
+func defaultPasswordCallback(conn ssh.ConnMetadata, passwd []byte) (*ssh.Permissions, error) {
+	return nil, errors.New("method not support")
+}
+
+func defaultPubkeyCallback(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
+	return nil, errors.New("method not support")
+}
+
+func defaultKeyIntCallback(conn ssh.ConnMetadata, cli ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
+	return nil, errors.New("method not support")
+}
+
+func defaultAuthLogCb(conn ssh.ConnMetadata, method string, err error) {
+}
+
+type defaultOperationHandler struct {
+}
+
+func (this *defaultOperationHandler) HandleOperation(request ZSshRpcOperationRequest) ZSshRpcOperationResponse {
+	return ZSshRpcOperationResponse{
+		StatusCode:   ResponseStatusCode_NOT_FOUND,
+		ResponseJSON: "{}",
+	}
+}
+
+func defaultServerLoggerFunc(level int, msg string, err error) {
+}
+
+func (this *ZSshRpcServerCfg) UsePasswordAuth(callback PasswdCb) {
+	this.PasswordCallback = callback
+}
+
+func (this *ZSshRpcServerCfg) UsePublicKeyAuth(callback PubKeyCb) {
+	this.PublicKeyCallback = callback
+}
+func (this *ZSshRpcServerCfg) UseKeyboardInteractiveAuth(callback KeyIntCb) {
+	this.KeyboardInteractiveCallback = callback
+}
+func (this *ZSshRpcServerCfg) UseAuthLogger(callback AuthLogCb) {
+	this.AuthLogCallback = callback
+}
+
+func (this *ZSshRpcServerCfg) UseLogger(logfunc SvrLogFunc) {
+	this.ServerLogger = logfunc
+}
+
+func (this *ZSshRpcServerCfg) SetHandler(handler ZSshRpcOperationHandler) {
+	this.OperationHandler = handler
+}
+
+func GetOrGenerateHostKey(key_store_path string, key_length_to_gen int) (ssh.Signer, error) {
+	if IsFileExists(key_store_path) {
+		hostkeydata, err := ioutil.ReadFile(key_store_path)
+		if err != nil {
+			return generateHostKey(key_store_path, key_length_to_gen)
+		}
+		hostkey, err := ssh.ParsePrivateKey(hostkeydata)
+		if err != nil {
+			return generateHostKey(key_store_path, key_length_to_gen)
+		}
+		return hostkey, nil
+	} else {
+		return generateHostKey(key_store_path, key_length_to_gen)
+	}
+}
+
+func generateHostKey(keypath string, len int) (ssh.Signer, error) {
+	prikey, err := rsa.GenerateKey(rand.Reader, len)
+	if err != nil {
+		return nil, err
+	}
+	privateKeyFile, err := os.Create(keypath)
+	defer privateKeyFile.Close()
+	if err != nil {
+		return nil, err
+	}
+	privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(prikey)}
+	if err := pem.Encode(privateKeyFile, privateKeyPEM); err != nil {
+		return nil, err
+	}
+	hostkeydata, err := ioutil.ReadFile(keypath)
+	if err != nil {
+		return nil, err
+	}
+	hostkey, err := ssh.ParsePrivateKey(hostkeydata)
+	if err != nil {
+		return nil, err
+	}
+	return hostkey, nil
+}

+ 254 - 0
server/SessionHandler.go

@@ -0,0 +1,254 @@
+package zsshrpc_server
+
+import (
+	"fmt"
+	"golang.org/x/crypto/ssh"
+	"net"
+)
+
+type ZSshRpcSessionContext struct {
+	NetConn          net.Conn
+	ServerConn       *ssh.ServerConn
+	NewChannelChan   <-chan ssh.NewChannel
+	ReqChan          <-chan *ssh.Request
+	OperationHandler ZSshRpcOperationHandler
+	Logger           SvrLogFunc
+}
+
+type ZSshRpcChannelContext struct {
+	Channel      ssh.Channel
+	ReqChan      <-chan *ssh.Request
+	SessionCtx   *ZSshRpcSessionContext
+	Logger       SvrLogFunc
+	RxState      ZSshRpcChState
+	RxMethod     ZSshRpcMethod
+	RxBuf        ThreadSafeBuffer
+	UriStr       string
+	JsonStr      string
+	ResponseData ZSshRpcOperationResponse
+}
+
+func HandleNewSession(conn net.Conn, sshcfg *ssh.ServerConfig, logger SvrLogFunc, handler ZSshRpcOperationHandler, IOBlockSize int) {
+	sconn, schan, reqchan, err := ssh.NewServerConn(conn, sshcfg)
+	if err != nil {
+		logger(SvrLogLevel_WARNING, fmt.Sprintf("Failed Handling Session From Client '%v'", conn.RemoteAddr()), err)
+		return
+	}
+	rpcSessCtx := &ZSshRpcSessionContext{
+		NetConn:          conn,
+		ServerConn:       sconn,
+		NewChannelChan:   schan,
+		ReqChan:          reqchan,
+		OperationHandler: handler,
+		Logger:           logger,
+	}
+	go ssh.DiscardRequests(reqchan)
+	go handleChannels(rpcSessCtx, IOBlockSize)
+}
+
+func try(Logger SvrLogFunc) {
+	if err := recover(); err != nil {
+		var einf error
+		switch err.(type) {
+		case error:
+			einf = err.(error)
+			break
+		default:
+			einf = nil
+			break
+		}
+		Logger(SvrLogLevel_WARNING, "Internal Error Recovered", einf)
+	}
+}
+
+func handleChannels(ctx *ZSshRpcSessionContext, IOBlockSize int) {
+	defer try(ctx.Logger)
+	for newchan := range ctx.NewChannelChan {
+		go handleChannel(ctx, newchan, IOBlockSize)
+	}
+}
+
+func handleChannel(sessctx *ZSshRpcSessionContext, nch ssh.NewChannel, IOBlockSize int) {
+	defer try(sessctx.Logger)
+	if nch.ChannelType() == "zsshrpc" {
+		ch, req, err := nch.Accept()
+		if err != nil {
+			sessctx.Logger(SvrLogLevel_INFO, fmt.Sprintf("Failed Handler Channel From '%v'", sessctx.NetConn.RemoteAddr()), err)
+			sessctx.ServerConn.Close()
+		} else {
+			chctx := &ZSshRpcChannelContext{
+				SessionCtx: sessctx,
+				Channel:    ch,
+				ReqChan:    req,
+				Logger:     sessctx.Logger,
+				RxState:    ChannelState_IDLE,
+			}
+			go handleZSshRpcChannel(chctx, IOBlockSize)
+		}
+	} else {
+		sessctx.Logger(SvrLogLevel_INFO, fmt.Sprintf("Unsupported Channel Type '%s' From Client '%v'", nch.ChannelType(), sessctx.NetConn.RemoteAddr()), nil)
+		nch.Reject(ssh.UnknownChannelType, "Unsupported Channel Type.")
+		sessctx.ServerConn.Close()
+	}
+}
+
+func readChannelData(b []byte, recvBufLen int, chctx *ZSshRpcChannelContext) {
+	for {
+		rl, err := chctx.Channel.Read(b)
+		if err != nil || rl == 0 {
+			break
+		}
+		if rl < recvBufLen {
+			if rl != 0 {
+				if b[rl-1] == 0 {
+					chctx.RxBuf.Write(b[:rl-1])
+					break
+				} else {
+					chctx.RxBuf.Write(b[:rl])
+				}
+			}
+		} else {
+			if b[recvBufLen-1] == 0 {
+				chctx.RxBuf.Write(b[:recvBufLen-1])
+				break
+			} else {
+				chctx.RxBuf.Write(b)
+			}
+		}
+	}
+}
+
+func handleZSshRpcChannel(chctx *ZSshRpcChannelContext, IOBlockSize int) {
+	defer try(chctx.Logger)
+	ioblockbuf := make([]byte, IOBlockSize)
+	waitchan := make(chan int)
+	go func() {
+		defer try(chctx.Logger)
+		for {
+			readChannelData(ioblockbuf, IOBlockSize, chctx)
+			//chctx.Logger(SvrLogLevel_DEBUG, fmt.Sprintf("<RECV> [len=%d] %s",chctx.RxBuf.Len(), hex.EncodeToString([]byte(chctx.RxBuf.String()))), nil)
+			waitchan <- 1
+		}
+		//io.Copy(&chctx.RxBuf, chctx.Channel)
+	}()
+	for {
+		req := <-chctx.ReqChan
+		switch chctx.RxState {
+		case ChannelState_IDLE:
+			{
+				if req.Type == "ZSSHRPC-1.0" {
+					chctx.RxState = ChannelState_WAIT_URI
+					chctx.RxBuf.Reset()
+				}
+			}
+			break
+		case ChannelState_WAIT_URI:
+			{
+				//chctx.Logger(SvrLogLevel_DEBUG, fmt.Sprintf("[Before URL Clear]Length Of RxBuf: %d", chctx.RxBuf.Len()), nil)
+				switch req.Type {
+				case "CALL":
+					{
+						chctx.RxMethod = RpcMethod_CALL
+						chctx.RxState = ChannelState_WAIT_JSON
+						<-waitchan
+						chctx.UriStr = chctx.RxBuf.String()
+						chctx.RxBuf.Reset()
+					}
+					break
+				case "ADD":
+					{
+						chctx.RxMethod = RpcMethod_ADD
+						chctx.RxState = ChannelState_WAIT_JSON
+						<-waitchan
+						chctx.UriStr = chctx.RxBuf.String()
+						chctx.RxBuf.Reset()
+					}
+					break
+				case "DEL":
+					{
+						chctx.RxMethod = RpcMethod_DEL
+						chctx.RxState = ChannelState_WAIT_JSON
+						<-waitchan
+						chctx.UriStr = chctx.RxBuf.String()
+						chctx.RxBuf.Reset()
+					}
+					break
+				case "GET":
+					{
+						chctx.RxMethod = RpcMethod_GET
+						chctx.RxState = ChannelState_WAIT_JSON
+						<-waitchan
+						chctx.UriStr = chctx.RxBuf.String()
+						chctx.RxBuf.Reset()
+					}
+					break
+				case "SET":
+					{
+						chctx.RxMethod = RpcMethod_SET
+						chctx.RxState = ChannelState_WAIT_JSON
+						<-waitchan
+						chctx.UriStr = chctx.RxBuf.String()
+						chctx.RxBuf.Reset()
+					}
+					break
+				default:
+					{
+						chctx.RxState = ChannelState_IDLE
+						chctx.RxBuf.Reset()
+					}
+					break
+				}
+				chctx.Logger(SvrLogLevel_DEBUG, fmt.Sprint("Recv URI: ", chctx.UriStr), nil)
+				//chctx.Logger(SvrLogLevel_DEBUG, fmt.Sprintf("[After URI Clear]Length Of RxBuf: %d", chctx.RxBuf.Len()), nil)
+			}
+			break
+		case ChannelState_WAIT_JSON:
+			{
+				if req.Type == "ENDREQ" {
+					//chctx.Logger(SvrLogLevel_DEBUG, fmt.Sprintf("[Before JSON Clear]Length Of RxBuf: %d", chctx.RxBuf.Len()), nil)
+					<-waitchan
+					chctx.JsonStr = chctx.RxBuf.String()
+					//chctx.Logger(SvrLogLevel_DEBUG, fmt.Sprint("Recv JSON: ", chctx.JsonStr), nil)
+					chctx.RxBuf.Reset()
+					//chctx.Logger(SvrLogLevel_DEBUG, fmt.Sprintf("[After JSON Clear]Length Of RxBuf: %d", chctx.RxBuf.Len()), nil)
+					chctx.RxState = ChannelState_EXEC_HANDLER
+					req := ZSshRpcOperationRequest{
+						ChannelContext: chctx,
+						Method:         chctx.RxMethod,
+						URI:            chctx.UriStr,
+						JSON:           chctx.JsonStr,
+					}
+					chctx.ResponseData = chctx.SessionCtx.OperationHandler.HandleOperation(req)
+					rcstring := fmt.Sprintf(
+						"%d - %s",
+						chctx.ResponseData.StatusCode,
+						GetResponseStatusCodeString(chctx.ResponseData.StatusCode),
+					)
+					chctx.Channel.Write([]byte(rcstring))
+					chctx.Channel.Write([]byte{0})
+					chctx.RxState = ChannelState_WAIT_JSON_READ
+				} else {
+					chctx.RxState = ChannelState_IDLE
+					chctx.RxBuf.Reset()
+				}
+			}
+			break
+		case ChannelState_EXEC_HANDLER:
+			{
+				chctx.RxState = ChannelState_IDLE
+				chctx.RxBuf.Reset()
+			}
+			break
+		case ChannelState_WAIT_JSON_READ:
+			if req.Type == "GETJSON" {
+				chctx.Channel.Write([]byte(chctx.ResponseData.ResponseJSON))
+				chctx.Channel.Write([]byte{0})
+			}
+			chctx.RxState = ChannelState_IDLE
+			break
+		}
+		if req.WantReply {
+			req.Reply(true, nil)
+		}
+	}
+}

+ 47 - 0
server/SimplePasswordMgr.go

@@ -0,0 +1,47 @@
+package zsshrpc_server
+
+import (
+	"errors"
+	"golang.org/x/crypto/bcrypt"
+	"golang.org/x/crypto/ssh"
+)
+
+type SimplePasswordMgr struct {
+	authlist map[string][]byte
+}
+
+func NewSimplePasswordMgr() *SimplePasswordMgr {
+	o := &SimplePasswordMgr{
+		authlist: make(map[string][]byte),
+	}
+	return o
+}
+
+func (this *SimplePasswordMgr) AddUserWithBytesPassword(username string, password []byte) error {
+	p, err := bcrypt.GenerateFromPassword(password, 10)
+	if err != nil {
+		return err
+	}
+	this.authlist[username] = p
+	return nil
+}
+
+func (this *SimplePasswordMgr) AddUserWithStringPassword(username string, password string) error {
+	return this.AddUserWithBytesPassword(username, []byte(password))
+}
+
+func (this *SimplePasswordMgr) AddUserWithBcryptPassword(username string, password []byte) {
+	this.authlist[username] = password
+}
+
+func (this *SimplePasswordMgr) PasswordCheckCallback(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
+	v, ok := this.authlist[conn.User()]
+	if !ok {
+		return nil, errors.New("auth failed with incorrected password")
+	}
+	err := bcrypt.CompareHashAndPassword(v, password)
+	if err != nil {
+		return nil, errors.New("auth failed with incorrected password")
+	}
+	return nil, nil
+}

+ 39 - 0
server/ThreadSafeBuffer.go

@@ -0,0 +1,39 @@
+package zsshrpc_server
+
+import (
+	"bytes"
+	"sync"
+)
+
+type ThreadSafeBuffer struct {
+	b bytes.Buffer
+	m sync.RWMutex
+}
+
+func (b *ThreadSafeBuffer) Read(p []byte) (n int, err error) {
+	b.m.RLock()
+	defer b.m.RUnlock()
+	return b.b.Read(p)
+}
+func (b *ThreadSafeBuffer) Write(p []byte) (n int, err error) {
+	b.m.Lock()
+	defer b.m.Unlock()
+	return b.b.Write(p)
+}
+func (b *ThreadSafeBuffer) String() string {
+	b.m.RLock()
+	defer b.m.RUnlock()
+	return b.b.String()
+}
+
+func (b *ThreadSafeBuffer) Reset() {
+	b.m.Lock()
+	defer b.m.Unlock()
+	b.b.Reset()
+}
+
+func (b *ThreadSafeBuffer) Len() int {
+	b.m.RLock()
+	defer b.m.RUnlock()
+	return b.b.Len()
+}

+ 116 - 0
test/main.go

@@ -0,0 +1,116 @@
+package main
+
+import (
+	"fmt"
+	"git.swzry.com/zry/go-zSshRpcServer/easyophdl"
+	"git.swzry.com/zry/go-zSshRpcServer/server"
+	"github.com/bitly/go-simplejson"
+	"net"
+)
+
+func main() {
+	conf, err := zsshrpc_server.NewDefaultZSshRpcServerCfg("hostkey.key")
+	if err != nil {
+		fmt.Println("Error: ", err)
+		return
+	}
+	passwdMgr := zsshrpc_server.NewSimplePasswordMgr()
+	passwdMgr.AddUserWithStringPassword("admin", "114514")
+	conf.UsePasswordAuth(passwdMgr.PasswordCheckCallback)
+	conf.UseLogger(func(level int, msg string, err error) {
+		level_string := "[NIL]"
+		switch level {
+		case zsshrpc_server.SvrLogLevel_DEBUG:
+			level_string = "[DBG]"
+			break
+		case zsshrpc_server.SvrLogLevel_INFO:
+			level_string = "[INF]"
+			break
+		case zsshrpc_server.SvrLogLevel_WARNING:
+			level_string = "[WRN]"
+			break
+		case zsshrpc_server.SvrLogLevel_ERROR:
+			level_string = "[ERR]"
+			break
+		}
+		if err != nil {
+			fmt.Println("<FrontEnd>", level_string, msg, ":", err)
+		} else {
+			fmt.Println("<FrontEnd>", level_string, msg)
+		}
+	})
+	hdl := easyophdl.NewEasyOperationHandler()
+	hdl.EnableDebug()
+	hdl.EnableUriSuggestWhenNotFound()
+	hdl.UseLogger(func(level int, msg string, err error) {
+		level_string := "[NIL]"
+		switch level {
+		case zsshrpc_server.SvrLogLevel_DEBUG:
+			level_string = "[DBG]"
+			break
+		case zsshrpc_server.SvrLogLevel_INFO:
+			level_string = "[INF]"
+			break
+		case zsshrpc_server.SvrLogLevel_WARNING:
+			level_string = "[WRN]"
+			break
+		case zsshrpc_server.SvrLogLevel_ERROR:
+			level_string = "[ERR]"
+			break
+		}
+		if err != nil {
+			fmt.Println("<BackEnd>", level_string, msg, ":", err)
+		} else {
+			fmt.Println("<BackEnd>", level_string, msg)
+		}
+	})
+	conf.SetHandler(hdl)
+	server := zsshrpc_server.NewZSshRpcServer(conf)
+	bindaddr, err := net.ResolveTCPAddr("tcp4", "0.0.0.0:19180")
+	if err != nil {
+		fmt.Println("Failed Bind Address: ", err)
+		return
+	}
+	server.ListenTCP("tcp4", bindaddr)
+	fmt.Printf("Listening At %v\n", bindaddr.String())
+	hdl.AddHandler("/info", zsshrpc_server.RpcMethod_GET, func(request *easyophdl.EasyOpHdlRequest, response *easyophdl.EasyOpHdlResponse) {
+		response.UseSimpleJson()
+		response.SimplePut("hello", "gensokyo")
+		sj := simplejson.New()
+		sj.Set("client_ver", request.GetClientVersion())
+		sj.Set("username", request.GetUserName())
+		sj.Set("remote_addr", request.GetRemoteAddr())
+	})
+	reqinfo := func(request *easyophdl.EasyOpHdlRequest, response *easyophdl.EasyOpHdlResponse) {
+		request.ProcGJson()
+		response.UseSimpleJson()
+		response.SimplePut("uri", request.RawRequest.URI)
+		response.SimplePut("method", request.GetMethodName())
+		response.SimplePut("arg1", request.GJsonGet("arg1").Value())
+		response.SimplePut("arg2", request.GJsonGet("arg2").Value())
+		response.SimplePut("arg3", request.GJsonGet("arg3").Value())
+		response.SimplePut("arg4", request.GJsonGet("arg4").Value())
+	}
+	hdl.AddHandler("/reqinfo", zsshrpc_server.RpcMethod_CALL, reqinfo)
+	hdl.AddHandler("/reqinfo", zsshrpc_server.RpcMethod_ADD, reqinfo)
+	hdl.AddHandler("/reqinfo", zsshrpc_server.RpcMethod_DEL, reqinfo)
+	hdl.AddHandler("/reqinfo", zsshrpc_server.RpcMethod_GET, reqinfo)
+	hdl.AddHandler("/reqinfo", zsshrpc_server.RpcMethod_SET, reqinfo)
+	hdl.AddHandler("/test1", zsshrpc_server.RpcMethod_GET, reqinfo)
+	hdl.AddHandler("/test1", zsshrpc_server.RpcMethod_SET, reqinfo)
+	hdl.AddHandler("/rjtest1", zsshrpc_server.RpcMethod_SET, func(request *easyophdl.EasyOpHdlRequest, response *easyophdl.EasyOpHdlResponse) {
+		type testtype struct {
+			arg1 int    `json:"num"`
+			arg2 string `json:"val"`
+		}
+		var test testtype
+		if request.ProcRegularJson(test) {
+			var out testtype
+			out.arg1 = test.arg1 + 114
+			out.arg2 = test.arg2 + "514"
+			response.UseRegularJson(out)
+		}
+	})
+	wch := make(chan int)
+	<-wch
+}