Apply .gitignore rules
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
// ************************************
|
||||
// @package: websocketServer
|
||||
// @description:
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-16 18:13:45
|
||||
// ************************************
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
webServer "Framework/webServer"
|
||||
logUtil "goutil/logUtil"
|
||||
)
|
||||
|
||||
// 事件回调函数
|
||||
type EventCallbackFuncs struct {
|
||||
// websocket连接事件
|
||||
OnConnFunc func(ctx *Context)
|
||||
|
||||
// websocket关闭事件
|
||||
OnCloseFunc func(ctx *Context)
|
||||
|
||||
// websocket接收事件
|
||||
OnMsgFunc func(ctx *Context, msgType int, msgData []byte)
|
||||
}
|
||||
|
||||
// 用户自定义数据结构
|
||||
type userDatas struct {
|
||||
// WsServer 或 WssServer 指针
|
||||
server interface{}
|
||||
|
||||
// 事件回调函数
|
||||
eventCallback *EventCallbackFuncs
|
||||
}
|
||||
|
||||
// iServerMgr
|
||||
// @description: WsServer/WssServer内部管理接口,以便hookHandler中统一访问
|
||||
type iServerMgr interface {
|
||||
// 升级为websocket
|
||||
upgrade(ctx *Context) (conn *websocket.Conn, err error)
|
||||
|
||||
// 将连接从连接池删除
|
||||
delConn(conn *websocket.Conn)
|
||||
|
||||
// 获取接收到Ping消息时,是否自动回复Pong信息
|
||||
GetAutoPong() bool
|
||||
}
|
||||
|
||||
// 回调勾子,将http/https升级为websocket
|
||||
func hookHandler(webServerCtx *webServer.Context) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logUtil.LogUnknownError(r)
|
||||
}
|
||||
}()
|
||||
|
||||
userDataI := webServerCtx.GetUserData()
|
||||
if userDataI == nil {
|
||||
return
|
||||
}
|
||||
|
||||
userData, ok := userDataI.(*userDatas)
|
||||
if !ok {
|
||||
logUtil.ErrorLog("userData type error")
|
||||
return
|
||||
}
|
||||
|
||||
// 通信结束信号
|
||||
cls := make(chan struct{})
|
||||
ctx := &Context{
|
||||
webServerCtx: webServerCtx, // web_server环境
|
||||
cls: cls, // 关闭连接信号
|
||||
}
|
||||
|
||||
var serverMgr iServerMgr
|
||||
var conn *websocket.Conn
|
||||
var err error
|
||||
|
||||
// 转为iServerMgr
|
||||
switch userData.server.(type) {
|
||||
case *WsServer:
|
||||
if svr, ok := userData.server.(*WsServer); ok {
|
||||
serverMgr = svr
|
||||
} else {
|
||||
logUtil.ErrorLog("server type not WsServer")
|
||||
return
|
||||
}
|
||||
case *WssServer:
|
||||
if svr, ok := userData.server.(*WssServer); ok {
|
||||
serverMgr = svr
|
||||
} else {
|
||||
logUtil.ErrorLog("server type not WssServer")
|
||||
return
|
||||
}
|
||||
default:
|
||||
logUtil.ErrorLog("server type not WsServer or WssServer")
|
||||
return
|
||||
}
|
||||
|
||||
// 升级为websocket
|
||||
conn, err = serverMgr.upgrade(ctx)
|
||||
if err != nil {
|
||||
if err.Error() == "connManager(disableNewConn)" {
|
||||
// 禁用新连接。正常功能,直接返回
|
||||
return
|
||||
}
|
||||
|
||||
logUtil.ErrorLog("websocket Upgrade failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 将连接从连接池删除
|
||||
defer serverMgr.delConn(conn)
|
||||
|
||||
// 关闭连接
|
||||
defer conn.Close()
|
||||
|
||||
// 默认情况下,ReadMessage不会读取到ping/pong/close消息(内部有专门的处理函数)
|
||||
// 设置心跳包处理函数
|
||||
conn.SetPingHandler(func(msg string) error {
|
||||
// 只要收到消息,都需要更新最近一次收到心跳包的时间
|
||||
ctx.heartbeat = time.Now()
|
||||
|
||||
if serverMgr.GetAutoPong() {
|
||||
// 自动回应一个Pong心跳
|
||||
go ctx.SendMessage(websocket.PongMessage, []byte(msg))
|
||||
}
|
||||
|
||||
// 接收消息回调
|
||||
if userData.eventCallback.OnMsgFunc != nil {
|
||||
userData.eventCallback.OnMsgFunc(ctx, websocket.PingMessage, []byte(msg))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
// 设置关闭包处理函数
|
||||
conn.SetCloseHandler(func(code int, text string) error {
|
||||
// 所有向cls写入,都使用select超时结构,以保证这儿不会一直阻塞,确保此协程能退出
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case cls <- struct{}{}:
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// 设置最近一次收到心跳包的时间
|
||||
ctx.heartbeat = time.Now()
|
||||
|
||||
// 新连接回调
|
||||
if userData.eventCallback.OnConnFunc != nil {
|
||||
userData.eventCallback.OnConnFunc(ctx)
|
||||
}
|
||||
|
||||
// 开启读协程
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logUtil.LogUnknownError(r)
|
||||
|
||||
// 有异常出现(可能是用户回调中出现异常);执行到这儿,需要关闭连接
|
||||
// 所有向cls写入,都使用select超时结构,以保证这儿不会一直阻塞,确保此协程能退出
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case cls <- struct{}{}:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
// 注意:ReadMessage不会读取到心跳包和关闭包数据;心跳包/关闭包需要设置专门的处理函数
|
||||
// 但内部对心跳包/关闭包的处理,也是由ReadMessage函数触发的(也就是不调用ReadMessage函数,可能也不会触发对心跳包/关闭包的处理);
|
||||
// 经测试和内部代码确认:调用心跳包/关闭包处理函数时,ReadMessage不会返回;心跳包/关闭包处理函数调用完毕后ReadMessage才可能返回
|
||||
mt, msg, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
// 所有向cls写入,都使用select超时结构,以保证这儿不会一直阻塞,确保此协程能退出
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 10):
|
||||
case cls <- struct{}{}:
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// 只要收到消息,都需要更新最近一次收到心跳包的时间
|
||||
ctx.heartbeat = time.Now()
|
||||
|
||||
// 接收消息回调
|
||||
if userData.eventCallback.OnMsgFunc != nil {
|
||||
userData.eventCallback.OnMsgFunc(ctx, mt, msg)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 等待退出
|
||||
<-cls
|
||||
|
||||
// 设置已关闭标志
|
||||
ctx.isClosed = true
|
||||
|
||||
// 关闭回调
|
||||
if userData.eventCallback.OnCloseFunc != nil {
|
||||
userData.eventCallback.OnCloseFunc(ctx)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
请求结构简介
|
||||
最近更新时间:2019-08-01 19:14:44
|
||||
|
||||
编辑 查看pdf
|
||||
在这篇文章中:
|
||||
服务地址
|
||||
通信协议
|
||||
请求方法
|
||||
请求参数
|
||||
字符编码
|
||||
对腾讯云的 API 接口的调用是通过向腾讯云 API 的服务端地址发送请求,并按照接口说明在请求中加入相应的请求参数来完成的。腾讯云 API 的请求结构由:服务地址、通信协议、请求方法、请求参数和字符编码组成。具体描述如下:
|
||||
|
||||
服务地址
|
||||
腾讯云 API 的服务接入地址与具体模块相关,详细请参见各接口相关描述。
|
||||
|
||||
通信协议
|
||||
腾讯云 API 的大部分接口都通过 HTTPS 进行通信,为您提供高安全性的通信通道。
|
||||
|
||||
请求方法
|
||||
腾讯云 API 同时支持 POST 和 GET 请求。
|
||||
|
||||
注意:
|
||||
|
||||
POST 和 GET 请求不能混合使用,若使用 GET 方式,则参数均从 Querystring 取得;
|
||||
若使用 POST 方式,则参数均从 Request Body 中取得,而 Querystring 中的参数将忽略。
|
||||
两种请求方式的参数格式规则相同,一般情况下使用 GET 请求,当参数字符串过长时推荐使用 POST。
|
||||
如果用户的请求方法是 GET,则对所有请求参数值均需要做 URL 编码,若为 POST,则无需对参数编码。
|
||||
GET 请求的最大长度根据不同的浏览器和服务器设置有所不同,例如,传统 IE 浏览器限制为 2K,Firefox 限制为 8K;对于一些参数较多、长度较长的 API 请求,建议您使用 POST 方法以免在请求过程中会由于字符串超过最大长度而导致请求失败。
|
||||
对于 POST 请求,您需要使用 x-www-form-urlencoded 的形式传参,因为云 API 侧是从 $_POST 中取出请求参数的。
|
||||
请求参数
|
||||
腾讯云 API 的每个请求都需要指定两类参数:公共请求参数以及接口请求参数。其中公共请求参数是每个接口都要用到的请求参数,具体可参见 公共请求参数,而接口请求参数是各个接口所特有的,具体见各个接口的“请求参数”描述。
|
||||
|
||||
字符编码
|
||||
腾讯云 API 的请求及返回结果均使用 UTF-8 字符集进行编码。
|
||||
*/
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"goutil/mathUtil"
|
||||
)
|
||||
|
||||
// CommonRequest 公共请求参数对象
|
||||
type CommonRequest struct {
|
||||
// Action 指令接口名称(必须)
|
||||
Action string
|
||||
|
||||
// 地域参数(必须)
|
||||
Region string
|
||||
|
||||
// Timestamp 当前UNIX时间戳(必须)
|
||||
Timestamp uint64
|
||||
|
||||
// Nonce 随机正整数(必须)
|
||||
Nonce uint32
|
||||
|
||||
// SecretId 在云API密钥上申请的标识身份的SecretId(必须)
|
||||
SecretId string
|
||||
|
||||
// 请求签名,用来验证此次请求的合法性,需要用户根据实际的输入参数计算得出。
|
||||
Signature string
|
||||
|
||||
// 签名方式,目前支持 HmacSHA256 和 HmacSHA1。只有指定此参数为 HmacSHA256 时,才使用 HmacSHA256 算法验证签名,其他情况均使用 HmacSHA1 验证签名。
|
||||
SignatureMethod string
|
||||
|
||||
// 队列名称(此属性虽然不是API文档中的公共属性,但是在队列模型中确实事实上的公共属性,所以将其转移到此处)
|
||||
queueName string
|
||||
}
|
||||
|
||||
// AssembleParamMap 组装请求参数字典
|
||||
// 返回值
|
||||
// map[string]interface{}:请求参数字
|
||||
func (this *CommonRequest) AssembleParamMap() map[string]string {
|
||||
result := make(map[string]string)
|
||||
|
||||
// 组装参数
|
||||
result["Action"] = this.Action
|
||||
result["Region"] = this.Region
|
||||
result["Timestamp"] = fmt.Sprintf("%d", this.Timestamp)
|
||||
result["Nonce"] = fmt.Sprintf("%d", this.Nonce)
|
||||
result["SecretId"] = this.SecretId
|
||||
result["SignatureMethod"] = this.SignatureMethod
|
||||
result["queueName"] = this.queueName
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// NewCommonRequest 新建公共请求参数对象
|
||||
// 参数
|
||||
// action:指令接口名称
|
||||
// region:地域
|
||||
// secretId:在云API密钥上申请的标识身份的SecretId
|
||||
// queueName:队列名称
|
||||
// 返回值
|
||||
// *CommonRequest:公共请求参数对象
|
||||
func NewCommonRequest(action, region, secretId, queueName string) *CommonRequest {
|
||||
return &CommonRequest{
|
||||
Action: action,
|
||||
Region: region,
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
Nonce: mathUtil.GetRand().Uint32(),
|
||||
SecretId: secretId,
|
||||
SignatureMethod: "HmacSHA256",
|
||||
queueName: queueName,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package configYaml
|
||||
|
||||
import (
|
||||
"framework/configMgr"
|
||||
"gopkg.in/yaml.v3"
|
||||
"goutil/logUtil"
|
||||
"goutil/yamlUtil"
|
||||
"log"
|
||||
)
|
||||
|
||||
var (
|
||||
// 配置对象
|
||||
|
||||
configManager = configMgr.NewConfigManager()
|
||||
)
|
||||
|
||||
// init
|
||||
//
|
||||
// @description: init
|
||||
//
|
||||
// parameter:
|
||||
// return:
|
||||
func init() {
|
||||
// 设置日志文件的存储目录
|
||||
logUtil.SetLogPath("LOG")
|
||||
|
||||
if err := reloadConfig(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//加载配置
|
||||
initBaseConfig()
|
||||
initDbConfig()
|
||||
initFunctionConfig()
|
||||
initLogMgrConfig()
|
||||
}
|
||||
|
||||
// reloadConfig
|
||||
//
|
||||
// @description: reloadConfig
|
||||
//
|
||||
// parameter:
|
||||
// return:
|
||||
//
|
||||
// @error: 错误信息
|
||||
func reloadConfig() error {
|
||||
|
||||
yamlFile, err := yamlUtil.LoadFromFile("config.yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析 YAML 文件
|
||||
err = yaml.Unmarshal(yamlFile, &ConfigYaml)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unmarshalling config file: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package webUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
client := NewClient(nil)
|
||||
|
||||
result, err := client.Get("https://www.baidu.com", nil)
|
||||
if err != nil {
|
||||
t.Errorf("测试错误,返回的结果为:%s", err)
|
||||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
t.Errorf("返回的数据为空,期望不为空")
|
||||
}
|
||||
|
||||
//t.Log(string(result))
|
||||
}
|
||||
|
||||
func TestGetTimeout(t *testing.T) {
|
||||
transportOPT := &TransportOPT{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
opt := make(map[string]interface{})
|
||||
opt["Timeout"] = 3 * time.Second
|
||||
|
||||
client := NewClient(transportOPT)
|
||||
_, err := client.Get("https://www.google.com", nil)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Errorf("测试异常")
|
||||
}
|
||||
|
||||
func TestPostWithMap(t *testing.T) {
|
||||
client := NewClient(nil)
|
||||
|
||||
data := make(map[string]string)
|
||||
data["test1"] = "value1"
|
||||
data["test2"] = "value2"
|
||||
result, err := client.PostWithMap("http://www.baidu.com", data, nil)
|
||||
if err != nil {
|
||||
t.Errorf("测试错误,返回的结果为:%s", err)
|
||||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
t.Errorf("返回的数据为空,期望不为空")
|
||||
}
|
||||
|
||||
//t.Log(string(result))
|
||||
}
|
||||
|
||||
func TestPostWithByte(t *testing.T) {
|
||||
client := NewClient(nil)
|
||||
|
||||
result, err := client.PostWithByte("http://www.baidu.com", []byte("test=abc"), nil)
|
||||
if err != nil {
|
||||
t.Errorf("测试错误,返回的结果为:%s", err)
|
||||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
t.Errorf("返回的数据为空,期望不为空")
|
||||
}
|
||||
|
||||
//t.Log(string(result))
|
||||
}
|
||||
Reference in New Issue
Block a user