diff --git a/.idea/goProject.iml b/.idea/goProject.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/goProject.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..3c2fb49 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..b1c9cc9 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + true + + \ No newline at end of file diff --git a/.svn/entries b/.svn/entries new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/.svn/entries @@ -0,0 +1 @@ +12 diff --git a/.svn/format b/.svn/format new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/.svn/format @@ -0,0 +1 @@ +12 diff --git a/.svn/pristine/00/001ae31cf129372b636ccad5355eca7cd5992f37.svn-base b/.svn/pristine/00/001ae31cf129372b636ccad5355eca7cd5992f37.svn-base new file mode 100644 index 0000000..0d781a3 --- /dev/null +++ b/.svn/pristine/00/001ae31cf129372b636ccad5355eca7cd5992f37.svn-base @@ -0,0 +1,34 @@ +package webServer + +import ( + "reflect" +) + +// methodAndInOutTypes +// @description: 反射的方法和输入、输出参数类型组合类型 +type methodAndInOutTypes struct { + // 反射出来的对应方法对象 + Method reflect.Value + + // 反射出来的方法的输入参数的类型集合 + InTypes []reflect.Type + + // 反射出来的方法的输出参数的类型集合 + OutTypes []reflect.Type +} + +// newmethodAndInOutTypes +// @description: newmethodAndInOutTypes +// parameter: +// @_method: _method +// @_inTypes: _inTypes +// @_outTypes: _outTypes +// return: +// @*methodAndInOutTypes: methodAndInOutTypes +func newmethodAndInOutTypes(_method reflect.Value, _inTypes []reflect.Type, _outTypes []reflect.Type) *methodAndInOutTypes { + return &methodAndInOutTypes{ + Method: _method, + InTypes: _inTypes, + OutTypes: _outTypes, + } +} diff --git a/.svn/pristine/00/00274e716eefcbc7222fcf148fae2d4a027038d1.svn-base b/.svn/pristine/00/00274e716eefcbc7222fcf148fae2d4a027038d1.svn-base new file mode 100644 index 0000000..59af09c --- /dev/null +++ b/.svn/pristine/00/00274e716eefcbc7222fcf148fae2d4a027038d1.svn-base @@ -0,0 +1,110 @@ +gxpath +==== +gxpath is XPath packages for the Go, that lets you extract data from the custom documents using XPath expression. + +**[XQuery](https://github.com/antchfx/xquery)** : gxpath implemented, lets you extract data from HTML/XML documents using XPath. + +### Features + +#### The basic XPath patterns. + +> The basic XPath patterns cover 90% of the cases that most stylesheets will need. + +- `node` : Selects all child elements with nodeName of node. + +- `*` : Selects all child elements. + +- `@attr` : Selects the attribute attr. + +- `@*` : Selects all attributes. + +- `node()` : Matches an org.w3c.dom.Node. + +- `text()` : Matches a org.w3c.dom.Text node. + +- `comment()` : Matches a comment. + +- `.` : Selects the current node. + +- `..` : Selects the parent of current node. + +- `/` : Selects the document node. + +- `a[expr]` : Select only those nodes matching a which also satisfy the expression expr. + +- `a[n]` : Selects the nth matching node matching a When a filter's expression is a number, XPath selects based on position. + +- `a/b` : For each node matching a, add the nodes matching b to the result. + +- `a//b` : For each node matching a, add the descendant nodes matching b to the result. + +- `//b` : Returns elements in the entire document matching b. + +- `a|b` : All nodes matching a or b. + +#### Node Axes + +- `child::*` : The child axis selects children of the current node. + +- `descendant::*` : The descendant axis selects descendants of the current node. It is equivalent to '//'. + +- `descendant-or-self::*` : Selects descendants including the current node. + +- `attribute::*` : Selects attributes of the current element. It is equivalent to @* + +- `following-sibling::*` : Selects nodes after the current node. + +- `preceding-sibling::*` : Selects nodes before the current node. + +- `following::*` : Selects the first matching node following in document order, excluding descendants. + +- `preceding::*` : Selects the first matching node preceding in document order, excluding ancestors. + +- `parent::*` : Selects the parent if it matches. The '..' pattern from the core is equivalent to 'parent::node()'. + +- `ancestor::*` : Selects matching ancestors. + +- `ancestor-or-self::*` : Selects ancestors including the current node. + +- `self::*` : Selects the current node. '.' is equivalent to 'self::node()'. + +#### Expressions + + The gxpath supported three types: number, boolean, string. + +- `path` : Selects nodes based on the path. + +- `a = b` : Standard comparisons. + + * a = b True if a equals b. + * a != b True if a is not equal to b. + * a < b True if a is less than b. + * a <= b True if a is less than or equal to b. + * a > b True if a is greater than b. + * a >= b True if a is greater than or equal to b. + +- `a + b` : Arithmetic expressions. + + * `- a` Unary minus + * a + b Add + * a - b Substract + * a * b Multiply + * a div b Divide + * a mod b Floating point mod, like Java. + +- `(expr)` : Parenthesized expressions. + +- `fun(arg1, ..., argn)` : Function calls. + + * position() + * last() + * count(node-set) + * name() + * starts-with(string,string) + * normalize-space(string) + * substring(string,start[,length]) + * come more + +- `a or b` : Boolean or. + +- `a and b` : Boolean and. diff --git a/.svn/pristine/00/0096b6776a09918ae8e11a6ea4ea0baebb972248.svn-base b/.svn/pristine/00/0096b6776a09918ae8e11a6ea4ea0baebb972248.svn-base new file mode 100644 index 0000000..b5425d1 --- /dev/null +++ b/.svn/pristine/00/0096b6776a09918ae8e11a6ea4ea0baebb972248.svn-base @@ -0,0 +1,29 @@ +package ensureSendUtil + +/* +ensureSendUtil 用于推送数据 +支持TCP和HTTP两种形式,在发送失败时会缓存数据,并在一定时间间隔后重试 + +通过NewTCPSender和NewHTTPSender两个接口分别创建TCP和HTTP模式的EnsureSender + +type EnsureSender interface { + // 用于发送数据 + Write(string) error + + // 用于停止发送,此时会自动保存未发送数据 + Close() error +} + +// 创建一个tcp数据发送器 +// 参数: +// _dataFolder 数据存放目录 +// _address 连接地址 +func NewTCPSender(_dataFolder, _address string) (EnsureSender, error) { + + +// 创建一个http数据发送器 +// 参数: +// _dataFolder 数据存放目录 +// _url 发送地址 +func NewHTTPSender(_dataFolder, _url string) (EnsureSender, error) { +*/ diff --git a/.svn/pristine/01/01089319b44c6f1155fa6d3b8d81d7557fdea2a1.svn-base b/.svn/pristine/01/01089319b44c6f1155fa6d3b8d81d7557fdea2a1.svn-base new file mode 100644 index 0000000..e274a21 --- /dev/null +++ b/.svn/pristine/01/01089319b44c6f1155fa6d3b8d81d7557fdea2a1.svn-base @@ -0,0 +1,129 @@ +/* +url的格式如下:https://cmq-{$type}-{$region}.api.{$network}.com +其最终内容受到以下因素的影响:地域、网络、消息队列模型 + +地域 +gz(广州)、sh(上海)、bj(北京)、shjr(上海金融)、szjr(深圳金融)、hk(中国香港)、cd(成都)、ca(北美)、usw(美西)、use(美东)、in(印度)、th(泰国)、sg(新加坡) + +网络 +外网接口请求域名后缀:api.qcloud.com +内网接口请求域名后缀:api.tencentyun.com + +队列模型 +请参照下面说明将域名中的 {$region} 替换成相应地域: +外网接口请求域名:https://cmq-queue-{$region}.api.qcloud.com +内网接口请求域名:http://cmq-queue-{$region}.api.tencentyun.com + +主题模型 +请参照下面说明将域名中的 {$region} 替换成相应地域: +外网接口请求域名:https://cmq-topic-{$region}.api.qcloud.com +内网接口请求域名:http://cmq-topic-{$region}.api.tencentyun.com +*/ +package mqMgr + +import ( + "fmt" + "strings" + + "goutil/securityUtil" + "goutil/stringUtil" + "goutil/webUtil" +) + +func getPrefix(network string) string { + if network == MQ_NETWORK_INTERNAL { + return "http://" + } + + return "https://" +} + +// // 获取请求url +// // region:地域 +// // network:网络类型:内网、外网 +// // _type:消息队列类型:消息队列、消息主题 +// // 返回: +// // 请求url +// func getHost(region, network, _type string) string { +// url := "cmq-{$type}-{$region}.api.{$network}.com" +// url = strings.Replace(url, "{$region}", region, 1) +// url = strings.Replace(url, "{$network}", network, 1) +// url = strings.Replace(url, "{$type}", _type, 1) + +// return url +// } + +// 获取请求url todo:切换成tdmq之后需要用这个方法 +// region:地域 +// network:网络类型:内网、外网 +// _type:消息队列类型:消息队列、消息主题 +// 返回: +// 请求url +func getHost(region, network, _type string) string { + var url string = "" + if network == MQ_NETWORK_INTERNAL { + url = "{$region}.mqadapter.cmq.{$network}.com" + } else { + url = "cmq-{$region}.public.{$network}.com" + } + + url = strings.Replace(url, "{$region}", region, 1) + url = strings.Replace(url, "{$network}", network, 1) + + return url +} + +func getPath() string { + return "/v2/index.php" +} + +func getMethod() string { + return "POST" +} + +// AssembleUrl 组装请求url +// 参数 +// region:地域 +// network:网络类型:内网、外网 +// _type:消息队列类型:消息队列、消息主题 +// secretKey:密钥的key +// paramMap:参数字典 +// 返回值 +// string:组装好的请求url +// string:签名 +// error:错误 +func AssembleUrl(region, network, _type, secretKey string, paramMap map[string]string) (url, signature string, err error) { + // 1. 申请安全凭证(已经得到) + + // 2. 生成签名串 + // 2.1、对参数排序 + // 2.2、拼接请求字符串 + // 注意: + // “参数值”为原始值而非 url 编码后的值。 + // 若输入参数中包含下划线,则需要将其转换为“.”。(指的是参数的名称,不是参数的值) + paramStr := webUtil.AssembleRequestParamSort(paramMap, true) + + // 2.3、拼接签名原文字符串 + host := getHost(region, network, _type) + path := getPath() + signatureSource := fmt.Sprintf("%s%s%s?%s", getMethod(), host, path, paramStr) + + // 2.4、生成签名串 + data, err := securityUtil.HmacSha256(signatureSource, secretKey) + if err != nil { + return + } + signature = string(stringUtil.Base64Encode2(data)) + + // 3. 签名串编码 + // 注意: + // 生成的签名串并不能直接作为请求参数,需要对其进行 URL 编码。 + // 如果用户的请求方法是 GET,则对所有请求参数值均需要做 URL 编码。 + // 如果是POST,则不用进行URL编码 + // signature = url.QueryEscape(signature) + + // 将签名添加到参数集合中 + url = fmt.Sprintf("%s%s%s", getPrefix(network), host, path) + + return +} diff --git a/.svn/pristine/01/010cd221ec8c3741fb44e0c141d45af65b1dcf19.svn-base b/.svn/pristine/01/010cd221ec8c3741fb44e0c141d45af65b1dcf19.svn-base new file mode 100644 index 0000000..bf69716 --- /dev/null +++ b/.svn/pristine/01/010cd221ec8c3741fb44e0c141d45af65b1dcf19.svn-base @@ -0,0 +1,36 @@ +package timeUtil + +import ( + "testing" + "time" +) + +func TestGetTime(t *testing.T) { + timeVal := time.Date(2018, 4, 25, 9, 36, 1, 0, time.Local) + timeStr1 := ToDateTimeString2(timeVal) + + utcTime := GetUTCTime(timeVal) + timeStr2 := ToDateTimeString2(utcTime) + + if timeStr1 != timeStr2 { + t.Errorf("获取UTC时间出错,两个时间不对等") + } + + utcTime2 := GetUTCTime(utcTime) + timeStr3 := ToDateTimeString2(utcTime2) + if timeStr1 != timeStr3 { + t.Errorf("两次的UTC时间不对等") + } + + utcTime4 := GetLocalTime(utcTime) + timeStr4 := ToDateTimeString2(utcTime4) + if timeStr4 != timeStr1 { + t.Errorf("local变更了时间 time1:%v time4:%v", timeStr1, timeStr4) + } + + utcTime5 := GetLocalTime(utcTime) + timeStr5 := ToDateTimeString2(utcTime5) + if timeStr4 != timeStr5 { + t.Errorf("两次的local时间不对等") + } +} diff --git a/.svn/pristine/01/013419d9030f7fb4c2de649a85be0862d57334ba.svn-base b/.svn/pristine/01/013419d9030f7fb4c2de649a85be0862d57334ba.svn-base new file mode 100644 index 0000000..29de99f --- /dev/null +++ b/.svn/pristine/01/013419d9030f7fb4c2de649a85be0862d57334ba.svn-base @@ -0,0 +1,658 @@ +package query + +import ( + "reflect" + + "goutil/xmlUtil/gxpath/xpath" +) + +// An XPath query interface. +type Query interface { + // Select traversing Iterator returns a query matched node xpath.NodeNavigator. + Select(Iterator) xpath.NodeNavigator + + // Evaluate evaluates query and returns values of the current query. + Evaluate(Iterator) interface{} + + // Test checks a specified xpath.NodeNavigator can passed by the current query. + //Test(xpath.NodeNavigator) bool +} + +// ContextQuery is returns current node on the Iterator object query. +type ContextQuery struct { + count int + Root bool // Moving to root-level node in the current context Iterator. +} + +func (c *ContextQuery) Select(t Iterator) (n xpath.NodeNavigator) { + if c.count == 0 { + c.count++ + n = t.Current().Copy() + if c.Root { + n.MoveToRoot() + } + } + return n +} + +func (c *ContextQuery) Evaluate(Iterator) interface{} { + c.count = 0 + return c +} + +// AncestorQuery is an XPath ancestor node query.(ancestor::*|ancestor-self::*) +type AncestorQuery struct { + iterator func() xpath.NodeNavigator + + Self bool + Input Query + Predicate func(xpath.NodeNavigator) bool +} + +func (a *AncestorQuery) Select(t Iterator) xpath.NodeNavigator { + for { + if a.iterator == nil { + node := a.Input.Select(t) + if node == nil { + return nil + } + first := true + a.iterator = func() xpath.NodeNavigator { + if first && a.Self { + first = false + if a.Predicate(node) { + return node + } + } + for node.MoveToParent() { + if !a.Predicate(node) { + break + } + return node + } + return nil + } + } + + if node := a.iterator(); node != nil { + return node + } + a.iterator = nil + } +} + +func (a *AncestorQuery) Evaluate(t Iterator) interface{} { + a.Input.Evaluate(t) + return a +} + +func (a *AncestorQuery) Test(n xpath.NodeNavigator) bool { + return a.Predicate(n) +} + +// AttributeQuery is an XPath attribute node query.(@*) +type AttributeQuery struct { + iterator func() xpath.NodeNavigator + + Input Query + Predicate func(xpath.NodeNavigator) bool +} + +func (a *AttributeQuery) Select(t Iterator) xpath.NodeNavigator { + for { + if a.iterator == nil { + node := a.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + a.iterator = func() xpath.NodeNavigator { + for { + onAttr := node.MoveToNextAttribute() + if !onAttr { + return nil + } + if a.Predicate(node) { + return node + } + } + } + } + + if node := a.iterator(); node != nil { + return node + } + a.iterator = nil + } +} + +func (a *AttributeQuery) Evaluate(t Iterator) interface{} { + a.Input.Evaluate(t) + a.iterator = nil + return a +} + +func (a *AttributeQuery) Test(n xpath.NodeNavigator) bool { + return a.Predicate(n) +} + +// ChildQuery is an XPath child node query.(child::*) +type ChildQuery struct { + posit int + iterator func() xpath.NodeNavigator + + Input Query + Predicate func(xpath.NodeNavigator) bool +} + +func (c *ChildQuery) Select(t Iterator) xpath.NodeNavigator { + for { + if c.iterator == nil { + c.posit = 0 + node := c.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + first := true + c.iterator = func() xpath.NodeNavigator { + for { + if (first && !node.MoveToChild()) || (!first && !node.MoveToNext()) { + return nil + } + first = false + if c.Predicate(node) { + return node + } + } + } + } + + if node := c.iterator(); node != nil { + c.posit++ + return node + } + c.iterator = nil + } +} + +func (c *ChildQuery) Evaluate(t Iterator) interface{} { + c.Input.Evaluate(t) + c.iterator = nil + return c +} + +func (c *ChildQuery) Test(n xpath.NodeNavigator) bool { + return c.Predicate(n) +} + +// position returns a position of current xpath.NodeNavigator. +func (c *ChildQuery) position() int { + return c.posit +} + +// DescendantQuery is an XPath descendant node query.(descendant::* | descendant-or-self::*) +type DescendantQuery struct { + iterator func() xpath.NodeNavigator + + Self bool + Input Query + Predicate func(xpath.NodeNavigator) bool +} + +func (d *DescendantQuery) Select(t Iterator) xpath.NodeNavigator { + for { + if d.iterator == nil { + node := d.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + level := 0 + first := true + d.iterator = func() xpath.NodeNavigator { + if first && d.Self { + first = false + if d.Predicate(node) { + return node + } + } + + for { + if node.MoveToChild() { + level++ + } else { + for { + if level == 0 { + return nil + } + if node.MoveToNext() { + break + } + node.MoveToParent() + level-- + } + } + if d.Predicate(node) { + return node + } + } + } + } + + if node := d.iterator(); node != nil { + return node + } + d.iterator = nil + } +} + +func (d *DescendantQuery) Evaluate(t Iterator) interface{} { + d.Input.Evaluate(t) + d.iterator = nil + return d +} + +func (d *DescendantQuery) Test(n xpath.NodeNavigator) bool { + return d.Predicate(n) +} + +// FollowingQuery is an XPath following node query.(following::*|following-sibling::*) +type FollowingQuery struct { + iterator func() xpath.NodeNavigator + + Input Query + Sibling bool // The matching sibling node of current node. + Predicate func(xpath.NodeNavigator) bool +} + +func (f *FollowingQuery) Select(t Iterator) xpath.NodeNavigator { + for { + if f.iterator == nil { + node := f.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + if f.Sibling { + f.iterator = func() xpath.NodeNavigator { + for { + if !node.MoveToNext() { + return nil + } + if f.Predicate(node) { + return node + } + } + } + } else { + var q Query // descendant query + f.iterator = func() xpath.NodeNavigator { + for { + if q == nil { + for !node.MoveToNext() { + if !node.MoveToParent() { + return nil + } + } + q = &DescendantQuery{ + Self: true, + Input: &ContextQuery{}, + Predicate: f.Predicate, + } + t.Current().MoveTo(node) + } + if node := q.Select(t); node != nil { + return node + } + q = nil + } + } + } + } + + if node := f.iterator(); node != nil { + return node + } + f.iterator = nil + } +} + +func (f *FollowingQuery) Evaluate(t Iterator) interface{} { + f.Input.Evaluate(t) + return f +} + +func (f *FollowingQuery) Test(n xpath.NodeNavigator) bool { + return f.Predicate(n) +} + +// PrecedingQuery is an XPath preceding node query.(preceding::*) +type PrecedingQuery struct { + iterator func() xpath.NodeNavigator + Input Query + Sibling bool // The matching sibling node of current node. + Predicate func(xpath.NodeNavigator) bool +} + +func (p *PrecedingQuery) Select(t Iterator) xpath.NodeNavigator { + for { + if p.iterator == nil { + node := p.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + if p.Sibling { + p.iterator = func() xpath.NodeNavigator { + for { + for !node.MoveToPrevious() { + return nil + } + if p.Predicate(node) { + return node + } + } + } + } else { + var q Query + p.iterator = func() xpath.NodeNavigator { + for { + if q == nil { + for !node.MoveToPrevious() { + if !node.MoveToParent() { + return nil + } + } + q = &DescendantQuery{ + Self: true, + Input: &ContextQuery{}, + Predicate: p.Predicate, + } + t.Current().MoveTo(node) + } + if node := q.Select(t); node != nil { + return node + } + q = nil + } + } + } + } + if node := p.iterator(); node != nil { + return node + } + p.iterator = nil + } +} + +func (p *PrecedingQuery) Evaluate(t Iterator) interface{} { + p.Input.Evaluate(t) + return p +} + +func (p *PrecedingQuery) Test(n xpath.NodeNavigator) bool { + return p.Predicate(n) +} + +// ParentQuery is an XPath parent node query.(parent::*) +type ParentQuery struct { + Input Query + Predicate func(xpath.NodeNavigator) bool +} + +func (p *ParentQuery) Select(t Iterator) xpath.NodeNavigator { + for { + node := p.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + if node.MoveToParent() && p.Predicate(node) { + return node + } + } +} + +func (p *ParentQuery) Evaluate(t Iterator) interface{} { + p.Input.Evaluate(t) + return p +} + +func (p *ParentQuery) Test(n xpath.NodeNavigator) bool { + return p.Predicate(n) +} + +// SelfQuery is an Self node query.(self::*) +type SelfQuery struct { + Input Query + Predicate func(xpath.NodeNavigator) bool +} + +func (s *SelfQuery) Select(t Iterator) xpath.NodeNavigator { + for { + node := s.Input.Select(t) + if node == nil { + return nil + } + + if s.Predicate(node) { + return node + } + } +} + +func (s *SelfQuery) Evaluate(t Iterator) interface{} { + s.Input.Evaluate(t) + return s +} + +func (s *SelfQuery) Test(n xpath.NodeNavigator) bool { + return s.Predicate(n) +} + +// FilterQuery is an XPath query for predicate filter. +type FilterQuery struct { + Input Query + Predicate Query +} + +func (f *FilterQuery) do(t Iterator) bool { + val := reflect.ValueOf(f.Predicate.Evaluate(t)) + switch val.Kind() { + case reflect.Bool: + return val.Bool() + case reflect.String: + return len(val.String()) > 0 + case reflect.Float64: + pt := float64(getNodePosition(f.Input)) + return int(val.Float()) == int(pt) + default: + if q, ok := f.Predicate.(Query); ok { + return q.Select(t) != nil + } + } + return false +} + +func (f *FilterQuery) Select(t Iterator) xpath.NodeNavigator { + for { + node := f.Input.Select(t) + if node == nil { + return node + } + node = node.Copy() + //fmt.Println(node.LocalName()) + + t.Current().MoveTo(node) + if f.do(t) { + return node + } + } +} + +func (f *FilterQuery) Evaluate(t Iterator) interface{} { + f.Input.Evaluate(t) + return f +} + +// FunctionQuery is an XPath function that call a function to returns +// value of current xpath.NodeNavigator node. +type XPathFunction struct { + Input Query // Node Set + Func func(Query, Iterator) interface{} // The xpath function. +} + +func (f *XPathFunction) Select(t Iterator) xpath.NodeNavigator { + return nil +} + +// Evaluate call a specified function that will returns the +// following value type: number,string,boolean. +func (f *XPathFunction) Evaluate(t Iterator) interface{} { + return f.Func(f.Input, t) +} + +// XPathConstant is an XPath constant operand. +type XPathConstant struct { + Val interface{} +} + +func (c *XPathConstant) Select(t Iterator) xpath.NodeNavigator { + return nil +} + +func (c *XPathConstant) Evaluate(t Iterator) interface{} { + return c.Val +} + +// LogicalExpr is an XPath logical expression. +type LogicalExpr struct { + Left, Right Query + + Do func(Iterator, interface{}, interface{}) interface{} +} + +func (l *LogicalExpr) Select(t Iterator) xpath.NodeNavigator { + // When a XPath expr is logical expression. + node := t.Current().Copy() + val := l.Evaluate(t) + switch val.(type) { + case bool: + if val.(bool) == true { + return node + } + } + return nil +} + +func (l *LogicalExpr) Evaluate(t Iterator) interface{} { + m := l.Left.Evaluate(t) + n := l.Right.Evaluate(t) + return l.Do(t, m, n) +} + +// NumericExpr is an XPath numeric operator expression. +type NumericExpr struct { + Left, Right Query + + Do func(interface{}, interface{}) interface{} +} + +func (n *NumericExpr) Select(t Iterator) xpath.NodeNavigator { + return nil +} + +func (n *NumericExpr) Evaluate(t Iterator) interface{} { + m := n.Left.Evaluate(t) + k := n.Right.Evaluate(t) + return n.Do(m, k) +} + +type BooleanExpr struct { + IsOr bool + Left, Right Query + iterator func() xpath.NodeNavigator +} + +func (b *BooleanExpr) Select(t Iterator) xpath.NodeNavigator { + if b.iterator == nil { + var list []xpath.NodeNavigator + i := 0 + root := t.Current().Copy() + if b.IsOr { + for { + node := b.Left.Select(t) + if node == nil { + break + } + node = node.Copy() + list = append(list, node) + } + t.Current().MoveTo(root) + for { + node := b.Right.Select(t) + if node == nil { + break + } + node = node.Copy() + list = append(list, node) + } + } else { + var m []xpath.NodeNavigator + var n []xpath.NodeNavigator + for { + node := b.Left.Select(t) + if node == nil { + break + } + node = node.Copy() + list = append(m, node) + } + t.Current().MoveTo(root) + for { + node := b.Right.Select(t) + if node == nil { + break + } + node = node.Copy() + list = append(n, node) + } + for _, k := range m { + for _, j := range n { + if k == j { + list = append(list, k) + } + } + } + } + + b.iterator = func() xpath.NodeNavigator { + if i >= len(list) { + return nil + } + node := list[i] + i++ + return node + } + } + return b.iterator() +} + +func (b *BooleanExpr) Evaluate(t Iterator) interface{} { + m := b.Left.Evaluate(t) + if m.(bool) == b.IsOr { + return m + } + return b.Right.Evaluate(t) +} + +func getNodePosition(q Query) int { + type Position interface { + position() int + } + if count, ok := q.(Position); ok { + return count.position() + } + return 1 +} diff --git a/.svn/pristine/01/01fbd56a6bc1d05c1f484952a04efc5e992d3c89.svn-base b/.svn/pristine/01/01fbd56a6bc1d05c1f484952a04efc5e992d3c89.svn-base new file mode 100644 index 0000000..aa66436 --- /dev/null +++ b/.svn/pristine/01/01fbd56a6bc1d05c1f484952a04efc5e992d3c89.svn-base @@ -0,0 +1,73 @@ +package fileUtil + +import ( + "fmt" + "strings" + "testing" +) + +func TestTar(t *testing.T) { + path := GetCurrentPath() + fmt.Printf("CurrPath:%s\n", path) + + fileName1 := fmt.Sprintf("%s/%s", path, "test1.txt") + fileName2 := fmt.Sprintf("%s/%s", path, "test2.txt") + + if err := WriteFile(path, "test1.txt", true, "first line"); err != nil { + t.Errorf("there should be no error, but now it is:%s", err) + } + if err := WriteFile(path, "test2.txt", true, "first line"); err != nil { + t.Errorf("there should be no error, but now it is:%s", err) + } + + sourceList := make([]string, 0, 2) + sourceList = append(sourceList, fileName1) + sourceList = append(sourceList, fileName2) + target := fmt.Sprintf("%s/%s", path, "test.tar") + if err := Tar(sourceList, target); err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } + + if fileList, err := GetFileList(path); err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } else { + for _, item := range fileList { + fmt.Printf("item:%s\n", item) + } + } + + DeleteFile(fileName1) + DeleteFile(fileName2) +} + +func TestUntar(t *testing.T) { + path := GetCurrentPath() + fmt.Printf("CurrPath:%s\n", path) + + source := fmt.Sprintf("%s/%s", path, "test.tar") + // target := path + target := "" + if err := Untar(source, target); err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } + + if fileList, err := GetFileList(path); err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } else { + for _, item := range fileList { + fmt.Printf("item:%s\n", item) + + if strings.HasSuffix(item, "txt") { + if content, err := ReadFileContent(item); err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } else { + fmt.Printf("content:%s\n", content) + } + + DeleteFile(item) + } + } + + DeleteFile(source) + } +} diff --git a/.svn/pristine/02/0299147d74eace2e9a84bcbe81bc0966d9a44600.svn-base b/.svn/pristine/02/0299147d74eace2e9a84bcbe81bc0966d9a44600.svn-base new file mode 100644 index 0000000..5586a8f --- /dev/null +++ b/.svn/pristine/02/0299147d74eace2e9a84bcbe81bc0966d9a44600.svn-base @@ -0,0 +1,35 @@ +package logUtilPlus + +import ( + "testing" + "time" +) + +func TestWrite(t *testing.T) { + Start("http://10.254.0.242:9200", "20008_gs_log", 20008) + + InfoLog("日志测试") + WarnLog("日志测试") + DebugLog("日志测试") + ErrorLog("日志测试") + FatalLog("日志测试") + + time.Sleep(1 * time.Second) + Stop() +} + +func BenchmarkWrite(b *testing.B) { + Start("http://10.254.0.242:9200", "20008_gs_log", 20008) + b.ResetTimer() + for i := 0; i < b.N; i++ { + InfoLog("日志测试%d", i) + WarnLog("日志测试%d", i) + DebugLog("日志测试%d", i) + ErrorLog("日志测试%d", i) + FatalLog("日志测试%d", i) + } + b.StopTimer() + + time.Sleep(1 * time.Second) + Stop() +} diff --git a/.svn/pristine/02/02bcd00feee3f43be99fed3c1fd0412e261ae3a5.svn-base b/.svn/pristine/02/02bcd00feee3f43be99fed3c1fd0412e261ae3a5.svn-base new file mode 100644 index 0000000..ca200f1 --- /dev/null +++ b/.svn/pristine/02/02bcd00feee3f43be99fed3c1fd0412e261ae3a5.svn-base @@ -0,0 +1,88 @@ +package ini_config + +import ( + "fmt" + "os" + "path" + "testing" +) + +func Test_File(t *testing.T) { + foder, _ := os.Getwd() + filePath := path.Join(foder, "ini.conf") + + kvmap, err := ParseFile(filePath) + if err != nil { + t.Error(err) + return + } + + if len(kvmap) != 12 { + t.Error("读取的内容数量不正确") + return + } + + if v, exists := kvmap["log.es.enable"]; exists == false || v != "false" { + t.Error("log.es.enable读取的值不正确") + } + + if v, exists := kvmap["log.es.url"]; exists == false || v != "" { + t.Error("log.es.url读取的值不正确") + } +} + +func Test_String(t *testing.T) { + k, v, err := Parse("log.es.enable") + if err == nil { + t.Error(fmt.Errorf("解析格式错误")) + return + } + + k, v, err = Parse("log.es.enable=false #(false,默认值,关闭es日志记录,后续配置可不填写; true 打开日志记录)") + if err != nil { + t.Error(err) + return + } + if k != "log.es.enable" || v != "false" { + t.Error("解析的值不正确") + } + + k, v, err = Parse("dbconnection=root:moqikaka3309!#@tcp(10.252.0.62:3309)/liangjian2_groupserver_auto_master?charset=utf8&parseTime=true&loc=Local&timeout=30s#数据库连接") + if err != nil { + t.Error(err) + return + } + if k != "dbconnection" || v != "root:moqikaka3309!#@tcp(10.252.0.62:3309)/liangjian2_groupserver_auto_master?charset=utf8&parseTime=true&loc=Local&timeout=30s" { + t.Error("解析的值不正确") + } + +} + +func Test_Content(t *testing.T) { + content := "#配置项说明\nlog.es.enable #(false,默认值,关闭es日志记录,后续配置可不填写; true 打开日志记录)\nlog.es.url= #(es服务地址)\nlog.es.indexName=1 #(es服务中Index名)\nlog.es.level=info #(debug|info|warn|error|fatal等级,等于或高于配置项则记录)\n\nlog.file.enable=false #(默认false)\nlog.file.path=log #(运行目录下log目录,默认logs)\nlog.file.pre=log #(文件名前缀,默认log)\nlog.file.enableHour=true #(文件以小时划分,格式:yyyyMMddHH,默认true,false 一天一个文件,格式:yyyyMMdd)\nlog.file.level=info\n\nlog.console.enable=false #(默认false)\nlog.console.level=info" + kvmap, err := ParseMultipleLines(content) + if err == nil { + t.Error(fmt.Errorf("配置格式不正确")) + return + } + + content = "#配置项说明\nlog.es.enable=false #(false,默认值,关闭es日志记录,后续配置可不填写; true 打开日志记录)\nlog.es.url= #(es服务地址)\nlog.es.indexName=1 #(es服务中Index名)\nlog.es.level=info #(debug|info|warn|error|fatal等级,等于或高于配置项则记录)\n\nlog.file.enable=false #(默认false)\nlog.file.path=log #(运行目录下log目录,默认logs)\nlog.file.pre=log #(文件名前缀,默认log)\nlog.file.enableHour=true #(文件以小时划分,格式:yyyyMMddHH,默认true,false 一天一个文件,格式:yyyyMMdd)\nlog.file.level=info\n\nlog.console.enable=false #(默认false)\nlog.console.level=info" + kvmap, err = ParseMultipleLines(content) + if err != nil { + t.Error(err) + return + } + + if len(kvmap) != 11 { + t.Error("读取的内容数量不正确") + return + } + + if v, exists := kvmap["log.es.enable"]; exists == false || v != "false" { + t.Error("log.es.enable读取的值不正确") + } + + if v, exists := kvmap["log.es.url"]; exists == false || v != "" { + t.Error("log.es.url读取的值不正确") + } +} diff --git a/.svn/pristine/03/033f93a5ed351569e457445896fd1913ce46d45b.svn-base b/.svn/pristine/03/033f93a5ed351569e457445896fd1913ce46d45b.svn-base new file mode 100644 index 0000000..3ec77dc --- /dev/null +++ b/.svn/pristine/03/033f93a5ed351569e457445896fd1913ce46d45b.svn-base @@ -0,0 +1,98 @@ +package ipMgr + +import ( + "fmt" + "testing" +) + +func TestQuery(t *testing.T) { + IP_SERVICE_URL = "http://ipip.7qule.com/query" + + appId := "unittest" + appId_wrong := "wrong" + appSecret := "c5746980-5d52-4ba9-834f-13d0066ad1d0" + appSecret_wrong := "wrong" + ip := "117.139.247.210" + ip_wrong := "wrong" + isDomestic := true + continent := "" + country := "中国" + region := "四川" + city := "成都" + timeout := 3 + + // Test with wrong AppId + ipInfoObj, err := Query(appId_wrong, appSecret, ip, isDomestic, timeout) + if err == nil { + t.Errorf("There should be an error, but now there is no error") + return + } + + // Test with wrong AppSecret + ipInfoObj, err = Query(appId, appSecret_wrong, ip, isDomestic, timeout) + if err == nil { + t.Errorf("There should be an error, but now there is no error") + return + } + + // Test with wrong IP + ipInfoObj, err = Query(appId, appSecret, ip_wrong, isDomestic, timeout) + if err == nil { + t.Errorf("There should be an error, but now there is no error") + return + } + + // Test with correct information and domestic ip + ipInfoObj, err = Query(appId, appSecret, ip, isDomestic, timeout) + if err != nil { + t.Errorf("There should be no error, but now there is one:%s", err) + return + } + fmt.Printf("ipInfoObj:%v\n", ipInfoObj) + + if ipInfoObj.Continent != continent { + t.Errorf("Expected continent %s, but got %s", continent, ipInfoObj.Continent) + } + + if ipInfoObj.Country != country { + t.Errorf("Expected country %s, but got %s", country, ipInfoObj.Country) + } + + if ipInfoObj.Region != region { + t.Errorf("Expected region %s, but got %s", region, ipInfoObj.Region) + } + + if ipInfoObj.City != city { + t.Errorf("Expected city %s, but got %s", city, ipInfoObj.City) + } + + // Test with correct information and foreign ip + isDomestic = false + continent = "亚洲" + country = "中国" + region = "四川省" + city = "成都" + + ipInfoObj, err = Query(appId, appSecret, ip, isDomestic, timeout) + if err != nil { + t.Errorf("There should be no error, but now there is one:%s", err) + return + } + fmt.Printf("ipInfoObj:%v\n", ipInfoObj) + + if ipInfoObj.Continent != continent { + t.Errorf("Expected continent %s, but got %s", continent, ipInfoObj.Continent) + } + + if ipInfoObj.Country != country { + t.Errorf("Expected country %s, but got %s", country, ipInfoObj.Country) + } + + if ipInfoObj.Region != region { + t.Errorf("Expected region %s, but got %s", region, ipInfoObj.Region) + } + + if ipInfoObj.City != city { + t.Errorf("Expected city %s, but got %s", city, ipInfoObj.City) + } +} diff --git a/.svn/pristine/03/03df81ec69165cb7077f9e740559446368aca1f2.svn-base b/.svn/pristine/03/03df81ec69165cb7077f9e740559446368aca1f2.svn-base new file mode 100644 index 0000000..3cb94b4 --- /dev/null +++ b/.svn/pristine/03/03df81ec69165cb7077f9e740559446368aca1f2.svn-base @@ -0,0 +1,78 @@ +package fileUtil + +import ( + "compress/gzip" + "fmt" + "io" + "os" + "path/filepath" +) + +// 对文件进行gzip压缩 +// source:源文件完整路径 +// target:目标文件文件夹(如果传空字符串,则为当前文件夹) +// 返回值 +// 错误对象 +func Gzip(source, target string) error { + reader, err := os.Open(source) + if err != nil { + return err + } + defer reader.Close() + + // 给目标文件夹赋值,如果传空,则默认为当前文件夹 + if target == "" { + target = filepath.Dir(source) + } + fileName := filepath.Base(source) + + targetFilePath := filepath.Join(target, fmt.Sprintf("%s.gz", fileName)) + writer, err := os.Create(targetFilePath) + if err != nil { + return err + } + defer writer.Close() + + archiver := gzip.NewWriter(writer) + archiver.Name = fileName + defer archiver.Close() + + _, err = io.Copy(archiver, reader) + + return err +} + +// 对文件进行gzip解压缩 +// source:源文件完整路径 +// target:目标文件文件夹(解压缩文件的名字是内部自动赋值) +// 返回值 +// 错误对象 +func UnGzip(source, target string) error { + reader, err := os.Open(source) + if err != nil { + return err + } + defer reader.Close() + + archive, err := gzip.NewReader(reader) + if err != nil { + return err + } + defer archive.Close() + + // 给目标文件夹赋值,如果传空,则默认为当前文件夹 + if target == "" { + target = filepath.Dir(source) + } + + targetFilePath := filepath.Join(target, archive.Name) + writer, err := os.Create(targetFilePath) + if err != nil { + return err + } + defer writer.Close() + + _, err = io.Copy(writer, archive) + + return err +} diff --git a/.svn/pristine/04/0418a758fbce45201919045075139dc8513be286.svn-base b/.svn/pristine/04/0418a758fbce45201919045075139dc8513be286.svn-base new file mode 100644 index 0000000..c35cf5e --- /dev/null +++ b/.svn/pristine/04/0418a758fbce45201919045075139dc8513be286.svn-base @@ -0,0 +1,67 @@ +package logUtil + +import ( + "os" + "os/exec" + "path/filepath" + "testing" + "time" + + impl_console "goutil/logUtil/impl-console" + impl_es "goutil/logUtil/impl-es" + impl_localfile "goutil/logUtil/impl-localfile" +) + +func TestAllLog(t *testing.T) { + file, _ := exec.LookPath(os.Args[0]) + path, _ := filepath.Abs(file) + logPath := filepath.Dir(path) + + GetLocalFileLog().SetLogPath(logPath) + + //添加控制台日志 + consoleLog := impl_console.NewLogger() + + //添加es日志 + urls := []string{"http://10.1.0.71:9101/"} + eslog, err := impl_es.NewLogger(urls, "", "", "es_log_test", "les_log_test_innerid", nil) + if err != nil { + t.Error("esLog 创建失败") + } + SettingLogs([]ILog{consoleLog, eslog, impl_localfile.NewLogger()}) + + for i := 1; i < 10; i++ { + InfoLog("Info记录") + InfoLog("Info记录2:%v %v", i, time.Now()) + + DebugLog("Debug记录") + DebugLog("Debug记录2:%v %v", i, time.Now()) + + WarnLog("Warn记录") + WarnLog("Warn记录2:%v %v", i, time.Now()) + + ErrorLog("Error记录") + ErrorLog("ErrorLog记录2:%v %v", i, time.Now()) + + FatalLog("Fatal记录") + FatalLog("Fatal记录2:%v %v", i, time.Now()) + } + + time.Sleep(time.Second * 5) + + Close(true) +} + +func BenchmarkInfoLog(b *testing.B) { + file, _ := exec.LookPath(os.Args[0]) + path, _ := filepath.Abs(file) + logPath := filepath.Dir(path) + + GetLocalFileLog().SetLogPath(logPath) + + for i := 0; i < b.N; i++ { + DebugLog("Debug 记录") + InfoLog("info记录 :%v", time.Now()) + } + Close(true) +} diff --git a/.svn/pristine/04/044e3ac017ca5d27710d505ac314376753225cfc.svn-base b/.svn/pristine/04/044e3ac017ca5d27710d505ac314376753225cfc.svn-base new file mode 100644 index 0000000..0e8bf38 --- /dev/null +++ b/.svn/pristine/04/044e3ac017ca5d27710d505ac314376753225cfc.svn-base @@ -0,0 +1,25 @@ +package managecenterMgr + +// ManageCenter数据获取开关(每一类数据一个开关) +type ManageCenterDataSwitch struct { + // 获取所有数据开关(只要这个开关值为true,则不论各类数据的开关是否打开,都获取数据) + AllDataSwitch bool + + // 获取合作商数据开关 + PartnerDataSwitch bool + + // 获取服务器数据开关 + ServerDataSwitch bool + + // 获取服务器组数开关 + ServerGroupDataSwitch bool + + // 获取资源包版本数据开关 + ResourceVersionDataSwitch bool + + // 获取白名单数据开关 + WhiteListDataSwitch bool + + // 获取大区数据开关 + AreaDataSwitch bool +} diff --git a/.svn/pristine/04/04cc1937beadc6d8dace22ef80979ab50388eeea.svn-base b/.svn/pristine/04/04cc1937beadc6d8dace22ef80979ab50388eeea.svn-base new file mode 100644 index 0000000..0cbb230 --- /dev/null +++ b/.svn/pristine/04/04cc1937beadc6d8dace22ef80979ab50388eeea.svn-base @@ -0,0 +1,38 @@ +module admincenter + +go 1.22.2 + +replace ( + common => ../common + framework => ../../framework + goutil => ../../goutil +) + +require ( + common v0.0.0-00010101000000-000000000000 + goutil v0.0.0-20230425160006-b2d0b0a0b0b0 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + framework v0.0.0-20230425160006-b2d0b0a0b0b0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/gomodule/redigo v1.8.9 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/jinzhu/gorm v1.9.12 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + gorm.io/driver/mysql v1.5.7 // indirect + gorm.io/gorm v1.25.12 // indirect +) diff --git a/.svn/pristine/04/04ff71b4d0991e86509f1059a6f59d487d6eadbf.svn-base b/.svn/pristine/04/04ff71b4d0991e86509f1059a6f59d487d6eadbf.svn-base new file mode 100644 index 0000000..cb6a69c --- /dev/null +++ b/.svn/pristine/04/04ff71b4d0991e86509f1059a6f59d487d6eadbf.svn-base @@ -0,0 +1,259 @@ +package timeUtil + +import ( + "fmt" + "strconv" + "strings" + "time" + + "goutil/stringUtil" +) + +// format time like java, such as: yyyy-MM-dd HH:mm:ss +// t:时间 +// format:格式化字符串 +// 返回值: +// 格式化后的字符串 +func Format(t time.Time, format string) string { + //year + if strings.ContainsAny(format, "y") { + year := strconv.Itoa(t.Year()) + + if strings.Count(format, "yy") == 1 && strings.Count(format, "y") == 2 { + format = strings.Replace(format, "yy", year[2:], 1) + } else if strings.Count(format, "yyyy") == 1 && strings.Count(format, "y") == 4 { + format = strings.Replace(format, "yyyy", year, 1) + } else { + panic("format year error! please 'yyyy' or 'yy'") + } + } + + //month + if strings.ContainsAny(format, "M") { + var month string + + if int(t.Month()) < 10 { + month = "0" + strconv.Itoa(int(t.Month())) + } else { + month = strconv.Itoa(int(t.Month())) + } + + if strings.Count(format, "MM") == 1 && strings.Count(format, "M") == 2 { + format = strings.Replace(format, "MM", month, 1) + } else { + panic("format month error! please 'MM'") + } + } + + //day + if strings.ContainsAny(format, "d") { + var day string + + if t.Day() < 10 { + day = "0" + strconv.Itoa(t.Day()) + } else { + day = strconv.Itoa(t.Day()) + } + + if strings.Count(format, "dd") == 1 && strings.Count(format, "d") == 2 { + format = strings.Replace(format, "dd", day, 1) + } else { + panic("format day error! please 'dd'") + } + } + + //hour + if strings.ContainsAny(format, "H") { + var hour string + + if t.Hour() < 10 { + hour = "0" + strconv.Itoa(t.Hour()) + } else { + hour = strconv.Itoa(t.Hour()) + } + + if strings.Count(format, "HH") == 1 && strings.Count(format, "H") == 2 { + format = strings.Replace(format, "HH", hour, 1) + } else { + panic("format hour error! please 'HH'") + } + } + + //minute + if strings.ContainsAny(format, "m") { + var minute string + + if t.Minute() < 10 { + minute = "0" + strconv.Itoa(t.Minute()) + } else { + minute = strconv.Itoa(t.Minute()) + } + if strings.Count(format, "mm") == 1 && strings.Count(format, "m") == 2 { + format = strings.Replace(format, "mm", minute, 1) + } else { + panic("format minute error! please 'mm'") + } + } + + //second + if strings.ContainsAny(format, "s") { + var second string + + if t.Second() < 10 { + second = "0" + strconv.Itoa(t.Second()) + } else { + second = strconv.Itoa(t.Second()) + } + + if strings.Count(format, "ss") == 1 && strings.Count(format, "s") == 2 { + format = strings.Replace(format, "ss", second, 1) + } else { + panic("format second error! please 'ss'") + } + } + + return format +} + +// 转换成日期字符串 +// timeVal:待转换的时间 +// 返回值: +// string:格式形如:2016-10-10 +/* +前面是含义,后面是 go 的表示值,多种表示,逗号","分割 +月份 1,01,Jan,January +日  2,02,_2 +时  3,03,15,PM,pm,AM,am +分  4,04 +秒  5,05 +年  06,2006 +时区 -07,-0700,Z0700,Z07:00,-07:00,MST +周几 Mon,Monday +*/ +func ToDateString(timeVal time.Time) string { + return timeVal.Local().Format("2006-01-02") +} + +// 忽略时区,转换成日期字符串 +// timeVal:待转换的时间 +// 返回值: +// string:格式形如:2016-10-10 +/* +前面是含义,后面是 go 的表示值,多种表示,逗号","分割 +月份 1,01,Jan,January +日  2,02,_2 +时  3,03,15,PM,pm,AM,am +分  4,04 +秒  5,05 +年  06,2006 +时区 -07,-0700,Z0700,Z07:00,-07:00,MST +周几 Mon,Monday +*/ +func ToDateString2(timeVal time.Time) string { + return timeVal.Format("2006-01-02") +} + +// 以本地时区为准,转换成时间字符串 +// timeVal:待转换的时间 +// 返回值: +// string:格式形如:2016-10-10 10:10:10 +/* +前面是含义,后面是 go 的表示值,多种表示,逗号","分割 +月份 1,01,Jan,January +日  2,02,_2 +时  3,03,15,PM,pm,AM,am +分  4,04 +秒  5,05 +年  06,2006 +时区 -07,-0700,Z0700,Z07:00,-07:00,MST +周几 Mon,Monday +*/ +func ToDateTimeString(timeVal time.Time) string { + return ToDateTimeStringEx(timeVal, false) +} + +func ToDateTimeStringEx(timeVal time.Time, flagT bool) string { + if flagT { + val := timeVal.Local().Format("2006-01-02 15:04:05") + return strings.Replace(val, " ", "T", -1) + } + + return timeVal.Local().Format("2006-01-02 15:04:05") +} + +// 忽略时区,转换成时间字符串 +// timeVal:待转换的时间 +// 返回值: +// string:格式形如:2016-10-10 10:10:10 +/* +前面是含义,后面是 go 的表示值,多种表示,逗号","分割 +月份 1,01,Jan,January +日  2,02,_2 +时  3,03,15,PM,pm,AM,am +分  4,04 +秒  5,05 +年  06,2006 +时区 -07,-0700,Z0700,Z07:00,-07:00,MST +周几 Mon,Monday +*/ +func ToDateTimeString2(timeVal time.Time) string { + return ToDateTimeStringEx2(timeVal, false) +} + +// 日期和时间中间带T方式 +func ToDateTimeStringEx2(timeVal time.Time, flagT bool) string { + if flagT { + val := timeVal.Format("2006-01-02 15:04:05") + return strings.Replace(val, " ", "T", -1) + } + + return timeVal.Format("2006-01-02 15:04:05") +} + +// 转换成日期格式 +func ToDateTime(timeVal string) (time.Time, error) { + if stringUtil.IsEmpty(timeVal) { + return time.Time{}, fmt.Errorf("timeval is empty") + } + + return time.ParseInLocation("2006-01-02 15:04:05", timeVal, time.Local) +} + +// 以指定时区,转换成日期格式 +func ToDateTime2(timeVal string, location *time.Location) (time.Time, error) { + if stringUtil.IsEmpty(timeVal) { + return time.Time{}, fmt.Errorf("timeval is empty") + } + + return time.ParseInLocation("2006-01-02 15:04:05", timeVal, location) +} + +// 转换成时间格式 +func ToDate(timeVal string) (time.Time, error) { + if stringUtil.IsEmpty(timeVal) { + return time.Time{}, fmt.Errorf("timeval is empty") + } + + return time.ParseInLocation("2006-01-02", timeVal, time.Local) +} + +// 转换成时间格式 +func ToDate2(timeVal string, location *time.Location) (time.Time, error) { + if stringUtil.IsEmpty(timeVal) { + return time.Time{}, fmt.Errorf("timeval is empty") + } + + return time.ParseInLocation("2006-01-02", timeVal, location) +} + +// 转换成yyyyMMddHHmmssms的格式 +func ToInt64(timeVal time.Time) int64 { + year := timeVal.Year() + month := int(timeVal.Month()) + day := timeVal.Day() + hour := timeVal.Hour() + minute := timeVal.Minute() + second := timeVal.Second() + + return int64(int64(year)*1e10) + int64(month*1e8) + int64(day*1e6) + int64(hour*1e4) + int64(minute*1e2) + int64(second) +} diff --git a/.svn/pristine/05/051936fe62906601a10b242b5729b54e02e6890c.svn-base b/.svn/pristine/05/051936fe62906601a10b242b5729b54e02e6890c.svn-base new file mode 100644 index 0000000..541a306 --- /dev/null +++ b/.svn/pristine/05/051936fe62906601a10b242b5729b54e02e6890c.svn-base @@ -0,0 +1,19 @@ +package game + +import "common/connection" + +func init() { + //注册数据库 + connection.RegisterDBModel(&Game{}) +} + +type Game struct { + GameID int64 `gorm:"column:game_id;primary_key;comment:用户id;autoIncrementIncrement" json:"gameid"` + + //账号 + Account string `gorm:"column:account;comment:账号" json:"account"` +} + +func (Game) TableName() string { + return "user" +} diff --git a/.svn/pristine/06/067c32d6d970c791745423200210d5c8eced9132.svn-base b/.svn/pristine/06/067c32d6d970c791745423200210d5c8eced9132.svn-base new file mode 100644 index 0000000..1c8739a --- /dev/null +++ b/.svn/pristine/06/067c32d6d970c791745423200210d5c8eced9132.svn-base @@ -0,0 +1,80 @@ +package gameLogMgr + +import ( + "fmt" + + "github.com/Shopify/sarama" + "goutil/debugUtil" + "goutil/logUtilPlus" +) + +var ( + producer sarama.AsyncProducer +) + +// 启动生产者 +// 参数: +// brokerList:Broker地址 +// userId:用户名(可默认为空字符串) +// passWard:密码(可默认为空字符串) +// 返回值: +// 无 +func Start(brokerList []string, userId string, passWard string) { + /* + 设置 acks = all。acks 是 Producer 的一个参数,代表了你对“已提交”消息的定义。如果设置成 all,则表明所有副本 Broker 都要接收到消息,该消息才算是“已提交”。这是最高等级的“已提交”定义。 + 对于游戏日志,设置为WaitForLocal即可;如果是游戏数据,则应设置为WaitForAll + 设置 retries 为一个较大的值。这里的 retries 同样是 Producer 的参数,对应前面提到的 Producer 自动重试。当出现网络的瞬时抖动时,消息发送可能会失败,此时配置了 retries > 0 的 Producer 能够自动重试消息发送,避免消息丢失。 + */ + var err error + config := sarama.NewConfig() + + config.Net.SASL.User = userId + config.Net.SASL.Password = passWard + config.Producer.Return.Successes = false + config.Producer.Return.Errors = true + config.Producer.Retry.Max = 10 + config.Producer.RequiredAcks = sarama.WaitForLocal + producer, err = sarama.NewAsyncProducer(brokerList, config) + if err != nil { + panic(fmt.Errorf("Kafka Start failed. Error: %v\n", err)) + } + + go func() { + for err := range producer.Errors() { + debugUtil.Printf("Send message to kafka failed. Error: %v\n", err.Err) + logUtilPlus.ErrorLog("Send message to kafka failed. Error: %v\n", err.Err) + } + }() +} + +func Stop() { + if producer != nil { + err := producer.Close() + if err != nil { + debugUtil.Printf("Stop kafka failed. Error: %v\n", err) + logUtilPlus.ErrorLog("Stop kafka failed. Error: %v\n", err) + } + } +} + +// 写入游戏日志 +// 参数: +// serverGroupId: 游戏服务器组Id +// key: 标识 +// message: 日志 +// 返回值: 无 +func Write(topic string, serverGroupId int32, message string) { + if producer == nil { + debugUtil.Printf("Send message to kafka failed. producer is nil") + logUtilPlus.ErrorLog("Send message to kafka failed. producer is nil") + return + } + + msg := &sarama.ProducerMessage{} + msg.Topic = topic + msg.Key = sarama.StringEncoder(fmt.Sprintf("%d", serverGroupId)) + msg.Value = sarama.ByteEncoder(message) + + // Send to kafka + producer.Input() <- msg +} diff --git a/.svn/pristine/07/0782015460cfe541898e77c9fb5904023dcd9457.svn-base b/.svn/pristine/07/0782015460cfe541898e77c9fb5904023dcd9457.svn-base new file mode 100644 index 0000000..cbbbf18 --- /dev/null +++ b/.svn/pristine/07/0782015460cfe541898e77c9fb5904023dcd9457.svn-base @@ -0,0 +1,14 @@ +package gameLogMgr + +// 游戏日志对象 +type GameLog struct { + ServerGroupId int32 // 服务器组Id + LogSql string // 日志Sql +} + +func newGameLog(serverGroupId int32, logSql string) *GameLog { + return &GameLog{ + ServerGroupId: serverGroupId, + LogSql: logSql, + } +} diff --git a/.svn/pristine/07/07ce17462368c2b1dc512b9b3abd7951d62168e5.svn-base b/.svn/pristine/07/07ce17462368c2b1dc512b9b3abd7951d62168e5.svn-base new file mode 100644 index 0000000..af97244 --- /dev/null +++ b/.svn/pristine/07/07ce17462368c2b1dc512b9b3abd7951d62168e5.svn-base @@ -0,0 +1,13 @@ +package mysqlSync + +/* +提供数据同步到mysql的方法。基本逻辑如下: +1、对外接收数据,以追加的方式保存到大文件中。数据的格式为:header(4bytes)+content。 +2、启动独立的goroutine来从大文件中读取数据,并保存到数据库中。 +3、使用syncInfo.txt文件保存当前已经处理的文件的路径,以及下一次将要读取的文件的Offset。为了降低向syncInfo.txt文件中写入失败, +导致需要从头开始同步数据,所以采用了在指定数目的范围内以追加形式来写入数据的方式;只有达到了指定数量才会将整个文件清空。 + +对于错误的处理方式,分为以下两种: +1、文件错误:由于文件系统是本系统的核心,所以如果出现文件的读写出错,则需要终止整个进程,所以需要抛出panic。 +2、数据库错误:当数据库不可访问时,为了不影响整个外部进程的运行,故而不抛出panic,而只是通过monitorNewMgr.Report的方式来报告故障。 +*/ diff --git a/.svn/pristine/08/08ab382d97d7dc9708f61a91bdf317d06b7b7d83.svn-base b/.svn/pristine/08/08ab382d97d7dc9708f61a91bdf317d06b7b7d83.svn-base new file mode 100644 index 0000000..a634f51 --- /dev/null +++ b/.svn/pristine/08/08ab382d97d7dc9708f61a91bdf317d06b7b7d83.svn-base @@ -0,0 +1,18 @@ +package mqMgr + +// 地域 +const ( + MQ_REGION_GUANGZHOU = "gz" + MQ_REGION_SAHNGHAI = "sh" + MQ_REGION_BEIJING = "bj" + MQ_REGION_SHANGHAIJINRONG = "shjr" + MQ_REGION_SHENZHENJINRONG = "szjr" + MQ_REGION_HONGKONG = "hk" + MQ_REGION_CHENGDU = "cd" + MQ_REGION_CANADA = "ca" + MQ_REGION_UNITED_STATES_EAST = "use" + MQ_REGION_UNITED_STATES_WEST = "usw" + MQ_REGION_INDIA = "in" + MQ_REGION_THILAND = "th" + MQ_REGION_SINGAPORE = "sg" +) diff --git a/.svn/pristine/09/0973b54e789e52c6207035406c7a797712e93165.svn-base b/.svn/pristine/09/0973b54e789e52c6207035406c7a797712e93165.svn-base new file mode 100644 index 0000000..c56ec77 --- /dev/null +++ b/.svn/pristine/09/0973b54e789e52c6207035406c7a797712e93165.svn-base @@ -0,0 +1,265 @@ +package typeUtil + +import ( + "fmt" + "time" +) + +// KeyValue数据集合 +type MapData map[string]interface{} + +// 创建新的MapData +// mapData:原有的map数据 +// 返回 +// 新的Map对象 +func NewMapData(mapData map[string]interface{}) MapData { + return MapData(mapData) +} + +// 类型转换为byte +// 返回值: +// byte:结果 +// error:错误数据 +func (this MapData) Byte(key string) (value byte, err error) { + return this.Uint8(key) +} + +// 类型转换为int +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Int(key string) (value int, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Int(val) + return +} + +// 类型转换为int8 +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Int8(key string) (value int8, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Int8(val) + return +} + +// 类型转换为int16 +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Int16(key string) (value int16, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Int16(val) + return +} + +// 类型转换为int32 +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Int32(key string) (value int32, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Int32(val) + return +} + +// 类型转换为int64 +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Int64(key string) (value int64, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Int64(val) + return +} + +// 类型转换为uint +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Uint(key string) (value uint, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Uint(val) + return +} + +// 类型转换为uint8 +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Uint8(key string) (value uint8, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Uint8(val) + return +} + +// 类型转换为uint16 +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Uint16(key string) (value uint16, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Uint16(val) + return +} + +// 类型转换为uint32 +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Uint32(key string) (value uint32, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Uint32(val) + return +} + +// 类型转换为uint64 +// 返回值: +// int:结果 +// error:错误数据 +func (this MapData) Uint64(key string) (value uint64, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Uint64(val) + return +} + +// 类型转换为float32 +// 返回值: +// float64:结果 +// error:错误数据 +func (this MapData) Float32(key string) (value float32, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Float32(val) + return +} + +// 类型转换为float64 +// 返回值: +// float64:结果 +// error:错误数据 +func (this MapData) Float64(key string) (value float64, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Float64(val) + return +} + +// 类型转换为bool +// 返回值: +// bool:结果 +// error:错误信息 +func (this MapData) Bool(key string) (value bool, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = Bool(val) + return +} + +// 类型转换为字符串 +// 返回值: +// string:结果 +// error:错误信息 +func (this MapData) String(key string) (value string, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = String(val) + return +} + +// 转换为时间格式,如果是字符串,则要求内容格式形如:2017-02-14 05:20:00 +// 返回值: +// bool:结果 +// error:错误信息 +func (this MapData) DateTime(key string) (value time.Time, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value, err = DateTime(val) + return +} + +// 获取指定的值 +// 返回值: +// interface{}:结果 +// error:错误信息 +func (this MapData) Interface(key string) (value interface{}, err error) { + val, exist := this[key] + if exist == false || val == nil { + err = fmt.Errorf("Target key: [%s] doesn't exist", key) + return + } + + value = val + return +} diff --git a/.svn/pristine/09/09b7f50515939483a29f46f368d7bd7db0165b49.svn-base b/.svn/pristine/09/09b7f50515939483a29f46f368d7bd7db0165b49.svn-base new file mode 100644 index 0000000..a6b18ae --- /dev/null +++ b/.svn/pristine/09/09b7f50515939483a29f46f368d7bd7db0165b49.svn-base @@ -0,0 +1,73 @@ +package shortUrlMgr + +import ( + "encoding/json" + "fmt" + "time" + + "goutil/securityUtil" + "goutil/stringUtil" + "goutil/webUtil" +) + +var ( + ShortUrl_SERVICE_URL = "http://a.app366.com/get" +) + +// 服务器的响应对象 +type QueryResponse struct { + // 响应结果的状态值 + ResultStatus string + + // 响应结果的数据 + Data string +} + +// 获取短链 +// appId: 为应用分配的唯一标识 +// appSecret: 为应用分配的密钥 +// fullUrl: 完整的Url +// timeout:超时时间(单位:秒) +// 返回值: +// ipInfoObj: IP地址信息对象 +// err: 错误对象 +func GetShortUrl(appId, appSecret, fullUrl string, timeout int) (shortUrl string, err error) { + timeStamp := fmt.Sprintf("%d", time.Now().Unix()) + fullUrl = stringUtil.Base64Encode(fullUrl) + rawString := fmt.Sprintf("AppId=%s&FullUrl=%s&Timestamp=%s&AppSecret=%s", appId, fullUrl, timeStamp, appSecret) + sign := securityUtil.Md5String(rawString, true) + + postData := make(map[string]string, 5) + postData["AppId"] = appId + postData["FullUrl"] = fullUrl + postData["Timestamp"] = timeStamp + postData["Sign"] = sign + + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, timeout) + statusCode, result, err := webUtil.PostMapData(ShortUrl_SERVICE_URL, postData, header, transport) + if err != nil { + return + } + if statusCode != 200 { + err = fmt.Errorf("StatusCode:%d is wrong.", statusCode) + return + } + + var queryResponseObj *QueryResponse + err = json.Unmarshal(result, &queryResponseObj) + if err != nil { + return + } + + if queryResponseObj.ResultStatus != "" { + err = fmt.Errorf("Query result:%s", queryResponseObj.ResultStatus) + return + } + + shortUrl = queryResponseObj.Data + + return +} diff --git a/.svn/pristine/0a/0a32a7aadf4e5244aa44094b27c6e4e39d8a1f2d.svn-base b/.svn/pristine/0a/0a32a7aadf4e5244aa44094b27c6e4e39d8a1f2d.svn-base new file mode 100644 index 0000000..0c2a186 --- /dev/null +++ b/.svn/pristine/0a/0a32a7aadf4e5244aa44094b27c6e4e39d8a1f2d.svn-base @@ -0,0 +1,39 @@ +package reloadMgr + +import ( + "fmt" + + "goutil/logUtil" +) + +var ( + reloadFuncMap = make(map[string]func() error) +) + +// RegisterReloadFunc ...注册Reload方法 +// funcName:方法名称 +// reloadFunc:reload方法 +func RegisterReloadFunc(funcName string, reloadFunc func() error) { + if _, exists := reloadFuncMap[funcName]; exists { + panic(fmt.Sprintf("%s已经存在,请重新取名", funcName)) + } + + reloadFuncMap[funcName] = reloadFunc + logUtil.InfoLog(fmt.Sprintf("RegisterReloadFunc funcName:%s,当前共有%d个注册", funcName, len(reloadFuncMap))) +} + +// Reload ...重新加载 +// 返回值: +// 错误列表 +func Reload() (errList []error) { + for funcName, reloadFunc := range reloadFuncMap { + if err := reloadFunc(); err == nil { + logUtil.InfoLog(fmt.Sprintf("Call ReloadFunc:%s Success.", funcName)) + } else { + logUtil.ErrorLog(fmt.Sprintf("Call ReloadFunc:%s Fail, Error:%s", funcName, err)) + errList = append(errList, err) + } + } + + return +} diff --git a/.svn/pristine/0a/0a359deb9b9471a4ea96b66c1cc364911ab54b99.svn-base b/.svn/pristine/0a/0a359deb9b9471a4ea96b66c1cc364911ab54b99.svn-base new file mode 100644 index 0000000..08b6989 --- /dev/null +++ b/.svn/pristine/0a/0a359deb9b9471a4ea96b66c1cc364911ab54b99.svn-base @@ -0,0 +1,55 @@ +package stringUtil + +import ( + "encoding/base64" +) + +const ( + base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +// const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +// const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" +) + +var coder = base64.NewEncoding(base64Table) + +// 对字符串进行Base64编码 +func Base64Encode(src string) string { + if src == "" { + return src + } + + return base64.StdEncoding.EncodeToString([]byte(src)) +} + +// 对字符串进行Base64解码 +func Base64Encode2(src []byte) []byte { + if len(src) == 0 { + return src + } + + return []byte(base64.StdEncoding.EncodeToString(src)) +} + +// 对字符数组进行Base64编码 +func Base64Decode(src string) (string, error) { + if src == "" { + return src, nil + } + + bytes, err := coder.DecodeString(src) + if err != nil { + return "", err + } + + return string(bytes), nil +} + +// 对字符数组进行Base64解码 +func Base64Decode2(src []byte) ([]byte, error) { + if len(src) == 0 { + return src, nil + } + + return coder.DecodeString(string(src)) +} diff --git a/.svn/pristine/0a/0a5860746a4b445d18be34fff4f29b1e4b180b35.svn-base b/.svn/pristine/0a/0a5860746a4b445d18be34fff4f29b1e4b180b35.svn-base new file mode 100644 index 0000000..1644bfe --- /dev/null +++ b/.svn/pristine/0a/0a5860746a4b445d18be34fff4f29b1e4b180b35.svn-base @@ -0,0 +1,41 @@ +// ************************************ +// @package: handleMgr +// @description: 反射类-反射的方法和输入、输出参数类型组合类型 +// @author: +// @revision history: +// @create date: 2022-02-23 16:33:43 +// ************************************ + +package handleMgr + +import ( + "reflect" +) + +// ReflectMethod 反射的方法和输入、输出参数类型组合类型 +type ReflectMethod struct { + // 反射出来的对应方法对象 + Method reflect.Value + + // 反射出来的方法的输入参数的类型集合 + InTypes []reflect.Type + + // 反射出来的方法的输出参数的类型集合 + OutTypes []reflect.Type +} + +// NewReflectMethod +// @description:创建反射的方法和输入、输出参数类型组合类型 +// parameter: +// @_method:反射出来的对应方法对象 +// @_inTypes:反射出来的方法的输入参数的类型集合 +// @_outTypes:反射出来的方法的输出参数的类型集合 +// return: +// @*ReflectMethod: +func NewReflectMethod(_method reflect.Value, _inTypes []reflect.Type, _outTypes []reflect.Type) *ReflectMethod { + return &ReflectMethod{ + Method: _method, + InTypes: _inTypes, + OutTypes: _outTypes, + } +} diff --git a/.svn/pristine/0a/0aad8def9322e065863083d01d249ef44cf69dc5.svn-base b/.svn/pristine/0a/0aad8def9322e065863083d01d249ef44cf69dc5.svn-base new file mode 100644 index 0000000..5a3794f --- /dev/null +++ b/.svn/pristine/0a/0aad8def9322e065863083d01d249ef44cf69dc5.svn-base @@ -0,0 +1,4 @@ +/* +提供时间相关的一些助手方法 +*/ +package timeUtil diff --git a/.svn/pristine/0b/0b64d992d48171632e253b32b808a1222c5e7681.svn-base b/.svn/pristine/0b/0b64d992d48171632e253b32b808a1222c5e7681.svn-base new file mode 100644 index 0000000..f5bcaeb --- /dev/null +++ b/.svn/pristine/0b/0b64d992d48171632e253b32b808a1222c5e7681.svn-base @@ -0,0 +1,33 @@ +package exitMgr + +import ( + "fmt" + + "goutil/logUtil" +) + +var ( + exitFuncMap = make(map[string]func()) +) + +// RegisterExitFunc ...注册Exit方法 +// funcName:方法名称 +// exitFunc:exit方法 +func RegisterExitFunc(funcName string, exitFunc func()) { + if _, exists := exitFuncMap[funcName]; exists { + panic(fmt.Sprintf("%s已经存在,请重新取名", funcName)) + } + + exitFuncMap[funcName] = exitFunc + logUtil.InfoLog("RegisterExitFunc funcName:%s,当前共有%d个注册", funcName, len(exitFuncMap)) +} + +// Exit ...退出程序 +// 返回值: +// 无 +func Exit() { + for funcName, exitFunc := range exitFuncMap { + exitFunc() + logUtil.InfoLog("Call ExitFunc:%s Finish.", funcName) + } +} diff --git a/.svn/pristine/0b/0b6d198d02242d905fb9068a5756c87c3a5aa2fe.svn-base b/.svn/pristine/0b/0b6d198d02242d905fb9068a5756c87c3a5aa2fe.svn-base new file mode 100644 index 0000000..7c518a7 --- /dev/null +++ b/.svn/pristine/0b/0b6d198d02242d905fb9068a5756c87c3a5aa2fe.svn-base @@ -0,0 +1,7 @@ +package mqMgr + +// 消息队列类型:消息队列、消息主题 +const ( + MQ_TYPE_QUEUE = "queue" + MQ_TYPE_TOPIC = "topic" +) diff --git a/.svn/pristine/0c/0c649c8389b0629d492c0cc4dab91d9b280686d2.svn-base b/.svn/pristine/0c/0c649c8389b0629d492c0cc4dab91d9b280686d2.svn-base new file mode 100644 index 0000000..f505d70 --- /dev/null +++ b/.svn/pristine/0c/0c649c8389b0629d492c0cc4dab91d9b280686d2.svn-base @@ -0,0 +1,44 @@ +package intUtil + +import ( + "fmt" + "math/rand" + "time" +) + +// ShuffleIntDigits 打乱整数的各个数字位置并返回新的整数 +func ShuffleIntDigits(num int64) (int64, error) { + if num < 0 { + return 0, fmt.Errorf("number must be non-negative") + } + + var digits []int64 + for num > 0 { + digits = append(digits, num%10) + num /= 10 + } + + // 如果原始数字是0,直接返回 + if len(digits) == 0 { + return 0, nil + } + + // 反转切片以保持原来的数字顺序 + for i, j := 0, len(digits)-1; i < j; i, j = i+1, j-1 { + digits[i], digits[j] = digits[j], digits[i] + } + + // 打乱数字切片 + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(digits), func(i, j int) { + digits[i], digits[j] = digits[j], digits[i] + }) + + // 重新组合为新的整数 + result := int64(0) + for _, digit := range digits { + result = result*10 + digit + } + + return result, nil +} diff --git a/.svn/pristine/0c/0cc6a8594a211ca755865be522ee4fc139d7b3f1.svn-base b/.svn/pristine/0c/0cc6a8594a211ca755865be522ee4fc139d7b3f1.svn-base new file mode 100644 index 0000000..ca819e2 --- /dev/null +++ b/.svn/pristine/0c/0cc6a8594a211ca755865be522ee4fc139d7b3f1.svn-base @@ -0,0 +1,19 @@ +package qcloud + +// 发送模板短信字段 +type tmplSmsField struct { + // 签名 (前缀) + Sign string `json:"sign,omitempty"` + // 模板id + Tpl_id int `json:"tpl_id,omitempty"` + // 模板参数 + Params []string `json:"params,omitempty"` +} + +func newTmplSmsField(sign string, id int, params []string) *tmplSmsField { + return &tmplSmsField{ + Sign: sign, + Tpl_id: id, + Params: params, + } +} diff --git a/.svn/pristine/0c/0ce1ecad1add98c087081650bab4b1dc4ba8424b.svn-base b/.svn/pristine/0c/0ce1ecad1add98c087081650bab4b1dc4ba8424b.svn-base new file mode 100644 index 0000000..7df1797 --- /dev/null +++ b/.svn/pristine/0c/0ce1ecad1add98c087081650bab4b1dc4ba8424b.svn-base @@ -0,0 +1,41 @@ +package monitorNewMgr + +// 监控信息传输对象 +type MonitorModel struct { + //状态码 0 是心跳,非零为错误信息 + Code int `json:"Code"` + + //组Id + GroupId string `json:"GroupId"` + + //组密钥 + ProjectId string `json:"ProjectId"` + + //项目Id + ServerIp string `json:"ServerIp"` + + // 监控使用的服务器IP + ServerName string `json:"ServerName"` + + // 监控使用的服务器名称 + Content string `json:"Content"` + + // 消息产生时的时间戳 + Timestamp int64 `json:"Timestamp"` + + // 签名 + Sign string `json:"Sign"` +} + +func newMonitorModel(code int, groupId, projectId, serverIp, serverName, content string, timestamp int64, sign string) *MonitorModel { + return &MonitorModel{ + Code: code, + GroupId: groupId, + ProjectId: projectId, + ServerIp: serverIp, + ServerName: serverName, + Content: content, + Timestamp: timestamp, + Sign: sign, + } +} diff --git a/.svn/pristine/0c/0cf6873b2c63205e8f54bb6bb60b43880f54c4a8.svn-base b/.svn/pristine/0c/0cf6873b2c63205e8f54bb6bb60b43880f54c4a8.svn-base new file mode 100644 index 0000000..be896d2 --- /dev/null +++ b/.svn/pristine/0c/0cf6873b2c63205e8f54bb6bb60b43880f54c4a8.svn-base @@ -0,0 +1,43 @@ +package main + +import ( + "common/connection" + "sync" + + _ "common/resultStatus" + "common/webServer" + _ "logincenter/internal/user" +) + +var ( + wg sync.WaitGroup +) + +func init() { + // 设置WaitGroup需要等待的数量,只要有一个服务器出现错误都停止服务器 + wg.Add(1) +} + +func main() { + + //加载配置 + loadConfig() + + // 启动webserver + go webServer.Start(&wg) + + // 阻塞等待,以免main线程退出 + wg.Wait() +} + +// loadConfig 用于加载配置信息。 +// 该函数会读取配置文件或环境变量中的设置,并根据这些设置初始化程序所需的配置。 +// 目前函数的实现为空,需要根据实际的配置加载逻辑进行填充。 +func loadConfig() { + + //设置数据类型 + connection.SetModelDB(connection.GetUserDB()) + + //构建数据库 + connection.BuildDB() +} diff --git a/.svn/pristine/0d/0d81a7654b3ab7b1fa88a882ac9120820be781d1.svn-base b/.svn/pristine/0d/0d81a7654b3ab7b1fa88a882ac9120820be781d1.svn-base new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.svn/pristine/0d/0d81a7654b3ab7b1fa88a882ac9120820be781d1.svn-base @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.svn/pristine/0d/0de3f1598f1552816faf3d86834fb1b66bf8bf50.svn-base b/.svn/pristine/0d/0de3f1598f1552816faf3d86834fb1b66bf8bf50.svn-base new file mode 100644 index 0000000..3796ce7 --- /dev/null +++ b/.svn/pristine/0d/0de3f1598f1552816faf3d86834fb1b66bf8bf50.svn-base @@ -0,0 +1,155 @@ +package gameServerMgr + +import ( + "crypto/tls" + "encoding/json" + "fmt" + "strconv" + + . "Framework/managecenterModel" + "goutil/webUtil" + "goutil/zlibUtil" +) + +// 区服激活地址后缀 +const ActivateServer_URL_SUFFIX string = "/API/ServerActivate.ashx" + +var ( + mManageCenterServerAPIUrl string + mIsInit bool = true +) + +// 解析从ManagecenterServer中获取的服务器相关数据 +func ParseInfoFromManageCenterServer(serverGroupId int32, data string) { + var deserializedData map[string]interface{} + err := json.Unmarshal([]byte(data), &deserializedData) + if err != nil { + return + } + + //解析服务器组 + var serverGroup *ServerGroup + err = json.Unmarshal([]byte(deserializedData["ServerGroupInfo"].(string)), &serverGroup) + if err != nil { + return + } + + //解析合作商 + var partnerList []*Partner + err = json.Unmarshal([]byte(deserializedData["PartnerList"].(string)), &partnerList) + if err != nil { + return + } + + //解析服务器列表 + var serverList []*Server + err = json.Unmarshal([]byte(deserializedData["ServerList"].(string)), &serverList) + if err != nil { + return + } + + //解析资源包 + var resourceList []*ResourceVersion + err = json.Unmarshal([]byte(deserializedData["ResourceVersionList"].(string)), &resourceList) + if err != nil { + return + } + + //解析大区 + var areaList []*Area + err = json.Unmarshal([]byte(deserializedData["AreaList"].(string)), &areaList) + if err != nil { + return + } + + //判断是否需要更新数据(如果ServerGroupId不匹配,则不解析数据) + if serverGroupId != serverGroup.Id { + return + } + + //缓存服务器组 + ParseServerGroupInfo(serverGroup) + + //缓存合作商 + ParsePartnerInfo(partnerList) + + //缓存合作商对应的充值配置 + ParseChargeConfigInfo(partnerList) + + //缓存服务器 + ParseServerInfo(serverList) + + //缓存资源包 + ParseResourceVersionInfo(resourceList) + + //缓存大区 + ParseAreaInfo(areaList) +} + +// 激活服务器 +func ActiveServer(manageCenterServerAPIUrl string, serverGroupId int32) error { + if len(manageCenterServerAPIUrl) == 0 { + return fmt.Errorf("ManageCenterServerAPI地址不能为空") + } + mManageCenterServerAPIUrl = manageCenterServerAPIUrl + + //定义参数 + requestParamMap := make(map[string]string, 0) + requestParamMap["ServerGroupID"] = strconv.Itoa(int(serverGroupId)) + + //构造请求url + url := fmt.Sprintf("%s/%s", mManageCenterServerAPIUrl, ActivateServer_URL_SUFFIX) + + //请求url,请求头 + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, //关闭证书校验 + } + transport = webUtil.GetTimeoutTransport(transport, 30) + + statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, transport) + //statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, nil) + if err != nil { + return err + } + if statusCode != 200 { + return fmt.Errorf("StatusCode:%d", statusCode) + } + + //解压缩 + retBytes, err1 := zlibUtil.Decompress(returnBytes) + if err1 != nil { + return err1 + } + // 解析返回值 + returnObj := new(ReturnObject) + if err = json.Unmarshal(retBytes, &returnObj); err != nil { + return err + } + + // 判断返回状态是否为成功 + if returnObj.Code != 0 { + return fmt.Errorf("code:%d,Message:%s", returnObj.Code, returnObj.Message) + } + + //解析得到的数据 + ParseInfoFromManageCenterServer(serverGroupId, returnObj.Data.(string)) + + //获取白名单 + GetWhiteListFromManageCenterServer() + + //如果是初始化,则开启白名单刷新线程。避免游戏客户端刷新数据的时候重复开启线程 + if mIsInit { + //启动白名单数据刷新线程 + StartRefreshWhiteListTread() + + //启动刷新MC系统配置 + StartRefreshSysConfigTread() + //初始化修改为fasle + mIsInit = false + } + + return nil +} diff --git a/.svn/pristine/0e/0e6c90a79a2d82d7163bf69aa24a408f279cd51a.svn-base b/.svn/pristine/0e/0e6c90a79a2d82d7163bf69aa24a408f279cd51a.svn-base new file mode 100644 index 0000000..66a6829 --- /dev/null +++ b/.svn/pristine/0e/0e6c90a79a2d82d7163bf69aa24a408f279cd51a.svn-base @@ -0,0 +1,64 @@ +package main + +import ( + "sync" +) + +type player struct { + // 玩家id + Id string `gorm:"column:Id;primary_key"` + + // 玩家名称 + Name string `gorm:"column:Name"` +} + +func (this *player) resetName(name string) { + this.Name = name +} + +func (this *player) tableName() string { + return "player" +} + +func newPlayer(id, name string) *player { + return &player{ + Id: id, + Name: name, + } +} + +type playerMgr struct { + playerMap map[string]*player + + mutex sync.Mutex +} + +func (this *playerMgr) insert(obj *player) { + this.mutex.Lock() + defer this.mutex.Unlock() + + this.playerMap[obj.Id] = obj +} + +func (this *playerMgr) delete(obj *player) { + this.mutex.Lock() + defer this.mutex.Unlock() + + delete(this.playerMap, obj.Id) +} + +func (this *playerMgr) randomSelect() *player { + this.mutex.Lock() + defer this.mutex.Unlock() + + for _, obj := range this.playerMap { + return obj + } + return nil +} + +func newPlayerMgr() *playerMgr { + return &playerMgr{ + playerMap: make(map[string]*player), + } +} diff --git a/.svn/pristine/0e/0ee1b8980db1cb87c67f3c144daf44fb3b086161.svn-base b/.svn/pristine/0e/0ee1b8980db1cb87c67f3c144daf44fb3b086161.svn-base new file mode 100644 index 0000000..8a257ea --- /dev/null +++ b/.svn/pristine/0e/0ee1b8980db1cb87c67f3c144daf44fb3b086161.svn-base @@ -0,0 +1,86 @@ +package bytesSendUtil + +import ( + "fmt" + "io/ioutil" + "net/http" + "testing" + "time" + + "goutil/debugUtil" +) + +// 保存接收的数据用于校验 +var http_recv_msg = make([]byte, 0) + +func init() { + debugUtil.SetDebug(true) +} + +type httpHandler struct { + cnt int +} + +func (ctx *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + + defer r.Body.Close() + result, _ := ioutil.ReadAll(r.Body) + + if string(result) == "http-msg-failed" { + http.NotFound(w, r) + } else { + ctx.cnt++ + // 模拟一次失败 + if ctx.cnt == 2 { + http.NotFound(w, r) + } else { + http_recv_msg = append(http_recv_msg, result...) + } + } + +} + +func Test_http(t *testing.T) { + http.Handle("/test", new(httpHandler)) + go http.ListenAndServe("127.0.0.1:9560", nil) + + httpSender, err := NewHTTPSender("./test_http", "http://127.0.0.1:9560/test") + if err != nil { + t.Error(err) + } + + time.Sleep(time.Millisecond * 50) + + // 第一次应该成功 + httpSender.Write([]byte("http-msg-1")) + + time.Sleep(time.Millisecond) + + // 发送消息,此数据会多次失败,被丢弃到giveup目录 + httpSender.Write([]byte("http-msg-failed")) + + time.Sleep(time.Second * 4) + + // 第二次应该失败 + httpSender.Write([]byte("http-msg-2")) + + time.Sleep(time.Millisecond) + + // 保存数据 + httpSender.Close() + + // 重启之后应该会重发数据 + httpSender, err = NewHTTPSender("./test_http", "http://127.0.0.1:9560/test") + if err != nil { + t.Error(err) + } + time.Sleep(time.Second * 2) + + httpSender.Close() + + if string(http_recv_msg) != "http-msg-1http-msg-2" { + t.Error("message error. got " + string(http_recv_msg)) + } else { + fmt.Println("HTTP OK") + } +} diff --git a/.svn/pristine/0f/0f30963356a1fb59be2104ee2e958491fa209bf6.svn-base b/.svn/pristine/0f/0f30963356a1fb59be2104ee2e958491fa209bf6.svn-base new file mode 100644 index 0000000..8036f5b --- /dev/null +++ b/.svn/pristine/0f/0f30963356a1fb59be2104ee2e958491fa209bf6.svn-base @@ -0,0 +1,17 @@ +v1.0版本,支持以下功能: +1、项目中的各种基础功能; +2、其中的managecenterMgr兼容旧版本的ManageCenter(2019-12-01之前)。 +3、新增日志记录功能(LogMgr 2020-03-09) +4、新增监控功能(MonitorNewMgr 2020-03-09) +5、新增短链功能(ShortUrlMgr 2020-03-09) + +v2.0版本,支持以下功能: +1、新的ManageCenter版本(2019-12-01之后) + +v2.0.0.1 +LogMgr里面Log日志消息先进行base64编码之后再发送到mq,因为原消息有特殊符号, +直接发送消息会导致消息返送之后,在腾讯mq收到消息之后数据会丢失,导致验签失败 + +v2.0.1.1 +新增屏蔽字处理forbidWordsMgr +新增gameServerMgr diff --git a/.svn/pristine/0f/0fe95ca68a7edc2b57740acf0aacde3feac27ecc.svn-base b/.svn/pristine/0f/0fe95ca68a7edc2b57740acf0aacde3feac27ecc.svn-base new file mode 100644 index 0000000..869b391 --- /dev/null +++ b/.svn/pristine/0f/0fe95ca68a7edc2b57740acf0aacde3feac27ecc.svn-base @@ -0,0 +1,114 @@ +package coroutine_timer + +import ( + "sync" + "testing" + "time" + + "goutil/mathUtil" + "goutil/stringUtil" +) + +func init() { +} + +func Test_Method1(t *testing.T) { + imap := make(map[int]struct{}) + var lockObj sync.Mutex + + cb := func(obj interface{}) { + i := obj.(int) + + lockObj.Lock() + defer lockObj.Unlock() + + if _, exist := imap[i]; exist == false { + t.Error(i, "应该删除,不应该回调 Test_Method1") + } + + delete(imap, i) + } + + for i := 0; i < 20000; i++ { + tick := i % 20 + isdel := false + if tick > 1 { + isdel = mathUtil.GetRand().GetRandInt(100) < 50 + } + if isdel == false { + lockObj.Lock() + imap[i] = struct{}{} + lockObj.Unlock() + } + id := AddTimer(tick, cb, i) + if isdel { + DeleteTimer(id) + } + } + + newN := 10000000 + newId := stringUtil.GetNewUUID() + + lockObj.Lock() + imap[newN] = struct{}{} + lockObj.Unlock() + + err := AddTimer4(newId, 3, cb, newN) + if err != nil { + t.Error(err) + } + + err = AddTimer4(newId, 3, cb, newN) + if err == nil { + t.Error("未检测到重复id") + } + + for { + if len(imap) == 0 { + break + } + + t.Log("剩余回调次数:", len(imap)) + time.Sleep(time.Second) + } +} + +func Test_Method2(t *testing.T) { + imap := make(map[int64]struct{}) + var lockObj sync.Mutex + + cb := func(obj interface{}) { + i := obj.(int64) + n := time.Now().Unix() + x := n - i + // 此处因为启动有暂停5s,所以启动后最近的执行偏差在5s内 + if x > 6 || x < -6 { + t.Errorf("错误的时间执行了回调函数 tick:%v now:%v", i, n) + } + + lockObj.Lock() + defer lockObj.Unlock() + + if _, exist := imap[i]; exist == false { + t.Error(i, "应该删除,不应该回调 Test_Method2") + } + + delete(imap, i) + } + + for i := 0; i < 20; i++ { + tick := time.Now().Unix() + int64(i) + imap[tick] = struct{}{} + AddTimer3(tick, cb, tick) + } + + for { + if len(imap) == 0 { + break + } + + t.Log("剩余回调次数:", len(imap)) + time.Sleep(time.Second) + } + +} diff --git a/.svn/pristine/10/107fc1aabad97f3332dd60150062cf10fd36945d.svn-base b/.svn/pristine/10/107fc1aabad97f3332dd60150062cf10fd36945d.svn-base new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.svn/pristine/10/107fc1aabad97f3332dd60150062cf10fd36945d.svn-base @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.svn/pristine/10/108dff723727057f2372bcb30ec7552664b06138.svn-base b/.svn/pristine/10/108dff723727057f2372bcb30ec7552664b06138.svn-base new file mode 100644 index 0000000..195fd01 --- /dev/null +++ b/.svn/pristine/10/108dff723727057f2372bcb30ec7552664b06138.svn-base @@ -0,0 +1,141 @@ +package appChargeUtil + +import ( + "encoding/json" + "fmt" + + "goutil/typeUtil" +) + +// APP Store充值收据对象 +type Receipt struct { + // Bvrs + Bvrs string + + // BundleIdentifier + BundleIdentifier string + + // 产品Id + ProductId string + + // 交易Id + TransactionId string + + // 数量 + Quantity int + + // 状态 + Status int +} + +// BundleIdentifier是否有效 +// bundleIdentifierList:配置的BundleIdentifier列表 +// 返回值: +// 是否有效 +func (this *Receipt) IsBundleIdentifierValid(bundleIdentifierList []string) bool { + for _, item := range bundleIdentifierList { + if this.BundleIdentifier == item { + return true + } + } + + return false +} + +// ProductId是否有效 +// productId:输入的ProductId +// 返回值: +// 是否有效 +func (this *Receipt) IsProductIdValid(productId string) bool { + return this.ProductId == productId +} + +// 转换为字符串 +// 返回值: +// 字符串 +func (this *Receipt) String() string { + return fmt.Sprintf("{Bvrs=%s,BundleIdentifier=%s,ProductId=%s,TransactionId=%s,Quantity=%d,Status=%d}", this.Bvrs, this.BundleIdentifier, this.ProductId, this.TransactionId, this.Quantity, this.Status) +} + +// 创建新的收据对象 +// receiptInfo:收据信息 +// 返回值: +// 收据对象 +// 错误对象 +/* + { + "receipt": + { + "original_purchase_date_pst":"2015-06-22 20:56:34 America/Los_Angeles", //购买时间,太平洋标准时间 + "purchase_date_ms":"1435031794826", //购买时间毫秒 + "unique_identifier":"5bcc5503dbcc886d10d09bef079dc9ab08ac11bb",//唯一标识符 + "original_transaction_id":"1000000160390314", //原始交易ID + "bvrs":"1.0",//iPhone程序的版本号 + "transaction_id":"1000000160390314", //交易的标识 + "quantity":"1", //购买商品的数量 + "unique_vendor_identifier":"AEEC55C0-FA41-426A-B9FC-324128342652", //开发商交易ID + "item_id":"1008526677",//App Store用来标识程序的字符串 + "product_id":"cosmosbox.strikehero.gems60",//商品的标识 + "purchase_date":"2015-06-23 03:56:34 Etc/GMT",//购买时间 + "original_purchase_date":"2015-06-23 03:56:34 Etc/GMT", //原始购买时间 + "purchase_date_pst":"2015-06-22 20:56:34 America/Los_Angeles",//太平洋标准时间 + "bid":"com.cosmosbox.StrikeHero",//iPhone程序的bundle标识 + "original_purchase_date_ms":"1435031794826"//毫秒 + }, + "status":0 //状态码,0为成功 + } +*/ +func newReceipt(receiptInfo string) (receiptObj *Receipt, err error) { + // 创建空对象 + receiptObj = &Receipt{} + + // 将接收的数据转化为map类型的对象 + receiptDataMap := make(map[string]interface{}) + err = json.Unmarshal([]byte(receiptInfo), &receiptDataMap) + if err != nil { + return + } + mapData := typeUtil.NewMapData(receiptDataMap) + + // 定义、并判断返回状态 + receiptObj.Status, err = mapData.Int("status") + if err != nil { + return + } + if receiptObj.Status != 0 { + err = fmt.Errorf("状态:%d不正确", receiptObj.Status) + return + } + + // Receipt is actually a child + receiptDataMap, ok := mapData["receipt"].(map[string]interface{}) + if !ok { + err = fmt.Errorf("receipt错误") + return + } + mapData = typeUtil.NewMapData(receiptDataMap) + + // 用返回值对本对象的属性进行赋值 + receiptObj.Bvrs, err = mapData.String("bvrs") + if err != nil { + return + } + receiptObj.BundleIdentifier, err = mapData.String("bid") + if err != nil { + return + } + receiptObj.ProductId, err = mapData.String("product_id") + if err != nil { + return + } + receiptObj.TransactionId, err = mapData.String("transaction_id") + if err != nil { + return + } + receiptObj.Quantity, err = mapData.Int("quantity") + if err != nil { + return + } + + return +} diff --git a/.svn/pristine/10/10a0f5439f7d2565fa8e1274fd45c809c65da569.svn-base b/.svn/pristine/10/10a0f5439f7d2565fa8e1274fd45c809c65da569.svn-base new file mode 100644 index 0000000..9f5ec23 --- /dev/null +++ b/.svn/pristine/10/10a0f5439f7d2565fa8e1274fd45c809c65da569.svn-base @@ -0,0 +1,330 @@ +package stringUtil + +import ( + "fmt" + "strconv" + "strings" + + "goutil/mathUtil" +) + +// 使用多分隔符来进行分割(默认分隔符为:",", ";", ":", "|", "||") +// eg:1,2;3|4||5,6;7|8||9 +// 返回值: +// []string +func Split(s string, seps []string) []string { + retList := make([]string, 0, 32) + + // 如果seps为nil,则使用默认值 + if seps == nil { + seps = []string{",", ";", ":", "|", "||"} + } + + // 根据所有的分隔符来一点一点地切割字符串,直到不可切割为止 + for { + startIndex := len(s) - 1 + endIndex := 0 + exists := false + + // 遍历,找到第一个分割的位置 + for _, sep := range seps { + index := strings.Index(s, sep) + + // 如果找到有匹配项,则寻找最小的pos,如果有多个相同的pos,则使用长度最长的分隔符 + if index > -1 { + exists = true + + // 说明有多个有效的分隔符,如|和|| + if index < startIndex { + startIndex = index + endIndex = startIndex + len(sep) - 1 + } else if index == startIndex { + if startIndex+len(sep)-1 > endIndex { + endIndex = startIndex + len(sep) - 1 + } + } + } + } + + // 如果没有找到匹配的pos,则分割过程结束 + if !exists { + retList = append(retList, s) + break + } + + // 切割字符串 + sub := s[:startIndex] + if sub != "" { + retList = append(retList, sub) + } + s = s[endIndex+1:] + } + + return retList +} + +// 将字符串切割为[]int +// str:输入字符串 +// 返回值: +// []int +// error +func SplitToIntSlice(s, sep string) ([]int, error) { + // 先按照分隔符进行切割 + strSlice := strings.Split(s, sep) + + // 定义int slice + intSlice := make([]int, 0, len(strSlice)) + for _, value := range strSlice { + // 去除空格 + if value = strings.TrimSpace(value); value == "" { + continue + } + + if value_int, err := strconv.Atoi(value); err != nil { + return nil, err + } else { + intSlice = append(intSlice, value_int) + } + } + + return intSlice, nil +} + +// 将字符串切割为[]int32 +// s:输入字符串 +// 返回值: +// []int +// error +func SplitToInt32Slice(s, sep string) ([]int32, error) { + // 先获得int slice + count := 0 + intSlice, err := SplitToIntSlice(s, sep) + if err != nil { + return nil, err + } else { + count = len(intSlice) + } + + // 定义int32 slice + int32Slice := make([]int32, 0, count) + for _, item := range intSlice { + int32Slice = append(int32Slice, int32(item)) + } + + return int32Slice, nil +} + +// 将字符串切割为[]int64 +// s:输入字符串 +// 返回值: +// []int64 +// error +func SplitToInt64Slice(s, sep string) ([]int64, error) { + // 先获得int slice + count := 0 + intSlice, err := SplitToIntSlice(s, sep) + if err != nil { + return nil, err + } else { + count = len(intSlice) + } + + // 定义int32 slice + int64Slice := make([]int64, 0, count) + for _, item := range intSlice { + int64Slice = append(int64Slice, int64(item)) + } + + return int64Slice, nil +} + +// 将字符串切割为[]float64 +// s:输入字符串 +// 返回值: +// []float64 +// error +func SplitToFloat64Slice(s, sep string) ([]float64, error) { + // 先按照分隔符进行切割 + strSlice := strings.Split(s, sep) + + // 定义float64 slice + floatSlice := make([]float64, 0, len(strSlice)) + for _, value := range strSlice { + // 去除空格 + if value = strings.TrimSpace(value); value == "" { + continue + } + + if value_float, err := strconv.ParseFloat(value, 64); err != nil { + return nil, err + } else { + floatSlice = append(floatSlice, value_float) + } + } + + return floatSlice, nil +} + +// 将字符串切割为map[int32]int32 +// s:输入字符串 +// 返回值: +// map[int32]float32 +// error +func SplitToDict_KintVint(s, outerSep, innerSep string) (map[int32]int32, error) { + // 先按照分隔符进行切割 + outerSlice := strings.Split(s, outerSep) + + // 定义map[int32]float32 + floatMap := make(map[int32]int32, len(outerSlice)) + for _, itemStr := range outerSlice { + innerSlice := strings.Split(strings.TrimSpace(itemStr), innerSep) + key := strings.TrimSpace(innerSlice[0]) + value := strings.TrimSpace(innerSlice[1]) + + key_int, err := strconv.Atoi(key) + if err != nil { + return nil, err + } + + value_int, err := strconv.Atoi(value) + if err != nil { + return nil, err + } + floatMap[int32(key_int)] = int32(value_int) + } + return floatMap, nil +} + +// 将字符串切割为map[int32]string +// s:输入字符串 +// 返回值: +// map[int32]string +// error +func SplitToDict_KintVstring(s, outerSep, innerSep string) (map[int32]string, error) { + // 先按照分隔符进行切割 + outerSlice := strings.Split(s, outerSep) + + // 定义map[int32]string + resultMap := make(map[int32]string, len(outerSlice)) + for _, itemStr := range outerSlice { + innerSlice := strings.Split(strings.TrimSpace(itemStr), innerSep) + key := strings.TrimSpace(innerSlice[0]) + value := strings.TrimSpace(innerSlice[1]) + + key_int, err := strconv.Atoi(key) + if err != nil { + return nil, err + } + + resultMap[int32(key_int)] = value + } + return resultMap, nil +} + +// 将字符串切割为map[int32]float32 +// s:输入字符串 +// 返回值: +// map[int32]float32 +// error +func SplitToDict_KintVfloat(s, outerSep, innerSep string) (map[int32]float32, error) { + // 先按照分隔符进行切割 + outerSlice := strings.Split(s, outerSep) + + // 定义map[int32]float32 + floatMap := make(map[int32]float32, len(outerSlice)) + for _, itemStr := range outerSlice { + innerSlice := strings.Split(strings.TrimSpace(itemStr), innerSep) + key := strings.TrimSpace(innerSlice[0]) + value := strings.TrimSpace(innerSlice[1]) + + key_int, err := strconv.Atoi(key) + if err != nil { + return nil, err + } + + value_float, err := strconv.ParseFloat(value, 64) + if err != nil { + return nil, err + } + floatMap[int32(key_int)] = float32(value_float) + } + return floatMap, nil +} + +// 将字符串切割为map[int32]float32 +// s:输入字符串 +// 返回值: +// map[int32]float32 +// error +func SplitToDict_KintVfloat64(s, outerSep, innerSep string) (map[int32]float64, error) { + // 先按照分隔符进行切割 + outerSlice := strings.Split(s, outerSep) + + // 定义map[int32]float32 + floatMap := make(map[int32]float64, len(outerSlice)) + for _, itemStr := range outerSlice { + innerSlice := strings.Split(strings.TrimSpace(itemStr), innerSep) + key := strings.TrimSpace(innerSlice[0]) + value := strings.TrimSpace(innerSlice[1]) + + key_int, err := strconv.Atoi(key) + if err != nil { + return nil, err + } + + value_float, err := strconv.ParseFloat(value, 64) + if err != nil { + return nil, err + } + floatMap[int32(key_int)] = float64(value_float) + } + return floatMap, nil +} + +// 将字符串切割为IntRegion列表 +// s:输入字符串,形如:1-200,201-400,401-1000 +// outerSep:外部分隔符 +// innerSep:内部分隔符 +// 返回值: +// IntRegion列表 +// 错误对象 +func SplitToIntRegion(s, outerSep, innerSep string) (intRegionList []*mathUtil.IntRegion, err error) { + if s == "" { + err = fmt.Errorf("Input is empty") + return + } + + outerRegionList := make([]string, 0, 4) + outerRegionList = strings.Split(s, outerSep) + if len(outerRegionList) == 0 { + err = fmt.Errorf("%s:Format invalid. Such as:1-100,101-200", s) + return + } + + for _, item := range outerRegionList { + innerRegionList := make([]string, 0, 2) + innerRegionList = strings.Split(item, innerSep) + if len(innerRegionList) != 2 { + err = fmt.Errorf("%s:Format invalid. Such as:1-100", item) + return + } + + var lower, upper int + lower, err = strconv.Atoi(innerRegionList[0]) + if err != nil { + return + } + upper, err = strconv.Atoi(innerRegionList[1]) + if err != nil { + return + } + if lower > upper { + err = fmt.Errorf("lower:%d should less than upper:%d", lower, upper) + return + } + + intRegionList = append(intRegionList, mathUtil.NewIntRegion(lower, upper)) + } + + return +} diff --git a/.svn/pristine/11/116309fe30c7ac55d6efe3eaf1f188a4151a7571.svn-base b/.svn/pristine/11/116309fe30c7ac55d6efe3eaf1f188a4151a7571.svn-base new file mode 100644 index 0000000..899fa1c --- /dev/null +++ b/.svn/pristine/11/116309fe30c7ac55d6efe3eaf1f188a4151a7571.svn-base @@ -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) + } +} diff --git a/.svn/pristine/11/11dd611238f6e4771bc74430cc3f2bee6b274238.svn-base b/.svn/pristine/11/11dd611238f6e4771bc74430cc3f2bee6b274238.svn-base new file mode 100644 index 0000000..e8434bb --- /dev/null +++ b/.svn/pristine/11/11dd611238f6e4771bc74430cc3f2bee6b274238.svn-base @@ -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, + } +} diff --git a/.svn/pristine/11/11ea234943ccae37879b6dbde2815a17b6504038.svn-base b/.svn/pristine/11/11ea234943ccae37879b6dbde2815a17b6504038.svn-base new file mode 100644 index 0000000..d7b4053 --- /dev/null +++ b/.svn/pristine/11/11ea234943ccae37879b6dbde2815a17b6504038.svn-base @@ -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 +} diff --git a/.svn/pristine/11/11f624645ee771a7b2811130a3b416d486e6e892.svn-base b/.svn/pristine/11/11f624645ee771a7b2811130a3b416d486e6e892.svn-base new file mode 100644 index 0000000..422b34c --- /dev/null +++ b/.svn/pristine/11/11f624645ee771a7b2811130a3b416d486e6e892.svn-base @@ -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)) +} diff --git a/.svn/pristine/12/12d698470913bfc03a551aa87944abac426b9072.svn-base b/.svn/pristine/12/12d698470913bfc03a551aa87944abac426b9072.svn-base new file mode 100644 index 0000000..f5c8059 --- /dev/null +++ b/.svn/pristine/12/12d698470913bfc03a551aa87944abac426b9072.svn-base @@ -0,0 +1,13 @@ +package qcloud + +type telField struct { + Nationcode string `json:"nationcode"` + Mobile string `json:"mobile"` +} + +func newTelField(nation, mobile string) *telField { + return &telField{ + Nationcode: nation, + Mobile: mobile, + } +} diff --git a/.svn/pristine/12/12f5e440c04874ab483587453f0e175feeb4c956.svn-base b/.svn/pristine/12/12f5e440c04874ab483587453f0e175feeb4c956.svn-base new file mode 100644 index 0000000..d7d8f9b --- /dev/null +++ b/.svn/pristine/12/12f5e440c04874ab483587453f0e175feeb4c956.svn-base @@ -0,0 +1,105 @@ +package gameServerMgr + +import ( + "encoding/json" + "errors" + "fmt" + "time" + + "Framework/goroutineMgr" + . "Framework/managecenterModel" + "goutil/logUtil" + "goutil/webUtil" +) + +const SYSCONF_URL_SUFFIX string = "/API/SysConfig.ashx" + +var ( + mSysConfig *SysConfig +) + +// 获取MC系统配置 +func GetSysConfigFromManageCenterServer() error { + //定义参数 + requestParamMap := make(map[string]string, 0) + requestParamMap["IsResultCompressed"] = "false" + + //构造url + url := fmt.Sprintf("%s/%s", mManageCenterServerAPIUrl, SYSCONF_URL_SUFFIX) + + //请求url,请求头 + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, 30) + + statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, transport) + //statusCode, returnBytes, err := webUtil.PostMapData(url, requestParamMap, header, nil) + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取MC系统配置出错,url:%s,错误信息为:%s", url, err)) + return err + } + if statusCode != 200 { + logUtil.ErrorLog(fmt.Sprintf("获取MC系统配置出错,url:%s,错误码为:%d", url, statusCode)) + return err + } + // 解析返回值 + returnObj := new(ReturnObject) + if err = json.Unmarshal(returnBytes, &returnObj); err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取MC系统配置出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes))) + return err + } + + // 判断返回状态是否为成功 + if returnObj.Code != 0 { + // 数据没有变化,所以没有获取到新的数据,不能算错误。 + if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" { + return nil + } else { + msg := fmt.Sprintf("获取MC系统配置出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message) + logUtil.ErrorLog(msg) + return errors.New(msg) + } + } + + // 解析Data + var tmpSysConfig *SysConfig + if data, ok := returnObj.Data.(string); !ok { + msg := "获取MC系统配置出错,返回的数据不是string类型" + logUtil.ErrorLog(msg) + return errors.New(msg) + } else { + if err = json.Unmarshal([]byte(data), &tmpSysConfig); err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取MC系统配置出错出错,反序列化数据出错,错误信息为:%s", err)) + return err + } + } + + // 赋值给最终的sysconfig + mSysConfig = tmpSysConfig + + return nil +} + +// 定时刷新MC系统配置 +func StartRefreshSysConfigTread() { + // 定时刷新数据 + go func() { + goroutineName := "gameServerMgr.StartRefreshSysConfigTread" + goroutineMgr.Monitor(goroutineName) + defer goroutineMgr.ReleaseMonitor(goroutineName) + + for { + // 每30秒刷新一次 + time.Sleep(30 * time.Second) + + // MC系统配置 + GetSysConfigFromManageCenterServer() + } + }() +} + +// 获取系统配置 +func GetSysConfig() *SysConfig { + return mSysConfig +} diff --git a/.svn/pristine/12/12f75adbec35d99e08a5f0ff52f0c36225adff02.svn-base b/.svn/pristine/12/12f75adbec35d99e08a5f0ff52f0c36225adff02.svn-base new file mode 100644 index 0000000..12de232 --- /dev/null +++ b/.svn/pristine/12/12f75adbec35d99e08a5f0ff52f0c36225adff02.svn-base @@ -0,0 +1,54 @@ +package initMgr + +import ( + "fmt" + "testing" +) + +func TestRegister(t *testing.T) { + Register("first", 1, first) + Register("second", 2, second) + Register("third", 3, third) + Register("fourth", 4, fourth) +} + +func TestCallOne(t *testing.T) { + name := "first" + if err := CallOne(name); err != nil { + t.Errorf("there should be no error, but now it has:%s", err) + } +} + +func TestCallAny(t *testing.T) { + errList := CallAny("second", "third") + if len(errList) != 1 { + t.Errorf("there should be 1 error, but now:%d", len(errList)) + } +} + +func TestCallAll(t *testing.T) { + errList := CallAll() + if len(errList) != 2 { + t.Errorf("there should be 1 error, but now:%d", len(errList)) + } +} + +func first() error { + fmt.Println("first") + return nil +} + +func second() error { + fmt.Println("second") + return fmt.Errorf("the second error") +} + +func third() error { + fmt.Println("third") + return nil +} + +func fourth() error { + fmt.Println("fourth") + return fmt.Errorf("the fourth error") +} diff --git a/.svn/pristine/12/12fec7f3f1013e25716d622f56b3972e13598eea.svn-base b/.svn/pristine/12/12fec7f3f1013e25716d622f56b3972e13598eea.svn-base new file mode 100644 index 0000000..0e03193 --- /dev/null +++ b/.svn/pristine/12/12fec7f3f1013e25716d622f56b3972e13598eea.svn-base @@ -0,0 +1,89 @@ +package user + +import ( + "common/cache" + "common/connection" + "goutil/logUtilPlus" + "sync" +) + +// 用户缓存对象 +var userMap = make(map[int64]*User) +var rwmu sync.RWMutex + +// GetUserByID 根据用户id获取用户信息 +func GetUserByID(UserID int64) (*User, error) { + + //判断缓存是否存在 + var user *User + + func() *User { + rwmu.RLock() + defer rwmu.RUnlock() + ok := true + if user, ok = userMap[UserID]; ok { + return user + } + return nil + }() + + if user != nil { + return user, nil + } + + result := connection.GetUserDB().First(&user, UserID) + if result.Error != nil { + return nil, result.Error + } + + //添加缓存 + func() { + rwmu.Lock() + defer rwmu.Unlock() + user.Cache = cache.NewCache() + userMap[user.ID] = user + }() + + return user, nil +} + +// AddUserCache 添加用户缓存 +func AddUserCache(user *User) { + rwmu.Lock() + defer rwmu.Unlock() + user.Cache = cache.NewCache() + userMap[user.ID] = user +} + +// AddUser 添加用户 +// AddUser 添加新的用户到数据库中。 +// 参数 User: 包含用户信息的对象。 +// 返回值: 插入操作影响的行数和可能发生的错误。 +func AddUser(User *User) (int64, error) { + + //处理一些验证 + + //写入缓存 + AddUserCache(User) + + // 写入到数据库 + result := connection.GetUserDB().Create(&User) // 通过数据的指针来创建 + + if result.Error != nil { + logUtilPlus.ErrorLog("添加用户失败 错误信息:", result.Error.Error()) + } + return User.ID, nil +} + +// Login 用户登录 +func Login(account string, password string) (*User, error) { + + //这里优先验证缓存数据 + + var User User + result := connection.GetUserDB().Where("account = ? AND password = ?", account, password).First(&User) + if result.Error != nil { + return nil, result.Error + } + return &User, nil +} diff --git a/.svn/pristine/13/133b571edb1ebc33483b575fba2f0df647af9e8a.svn-base b/.svn/pristine/13/133b571edb1ebc33483b575fba2f0df647af9e8a.svn-base new file mode 100644 index 0000000..6012895 --- /dev/null +++ b/.svn/pristine/13/133b571edb1ebc33483b575fba2f0df647af9e8a.svn-base @@ -0,0 +1,20 @@ + + + <!-- 阿斯大三大四的 --> + 这里有中文哦 + + + +

This is a H1

+ +

+ Hello,This is an example for gxpath. +

+ + + \ No newline at end of file diff --git a/.svn/pristine/13/13a7a5172d7c0e0fdc2fe718e7d1e71f371e8ac6.svn-base b/.svn/pristine/13/13a7a5172d7c0e0fdc2fe718e7d1e71f371e8ac6.svn-base new file mode 100644 index 0000000..8583cf6 --- /dev/null +++ b/.svn/pristine/13/13a7a5172d7c0e0fdc2fe718e7d1e71f371e8ac6.svn-base @@ -0,0 +1,76 @@ +package monitorNewMgr + +import ( + "time" +) + +//服务器节点信息 +type ServerNodeMessage struct { + //通用信息 + CommInfo CommInfoModel + + // indexMap 指标对象 + IndexSlice []Index +} + +type Index struct { + // IndexName 指标名字(eg:可以为cpu,mem,numGoroutine,proxy) + IndexName string + + // moduleName 模块名字 + ModuleName string + + // methodName 方法名字 + MethodName string + + // value 指标值(eg:indexName为cpu时,value 为cpu使用率,indexName为内存时,value为内存使用率) + Value float64 +} + +//服务监控中心信息 +type MonitorCenterMessage struct { + //通用信息 + CommInfo CommInfoModel + + // Cpu 核数 + Cpu int32 + + // Mem 内存大小 + Mem int32 + + // Status + Status int32 +} + +// 通用信息 +type CommInfoModel struct { + // 项目组ID + GroupId string + + // projectId 项目Id (eg:迪士尼) + ProjectId string + + // clusterId 集群Id(一个集群相当于一个大区) + ClusterId string + + // 组密钥 + ProjectSecret string + + // 服务器IP + IP string + + // Port 服务端口 + Port int32 + + // 服务名(eg:玩家服务player,城市服务:city,代理服务:proxy) + ServiceName string + + // instanceId 服务实例Id + InstanceId string + + // tll 时间戳 + Tll time.Duration + + // 签名 + Sign string +} diff --git a/.svn/pristine/14/14de84ff1959026fcd250504d7000e59f58e3b41.svn-base b/.svn/pristine/14/14de84ff1959026fcd250504d7000e59f58e3b41.svn-base new file mode 100644 index 0000000..b77992c --- /dev/null +++ b/.svn/pristine/14/14de84ff1959026fcd250504d7000e59f58e3b41.svn-base @@ -0,0 +1,53 @@ +package configUtil + +import ( + "testing" +) + +var ( + config map[string]interface{} + err error +) + +func TestReadJsonConfig(t *testing.T) { + config, err = ReadJsonConfig("testdata/jsonConfig.ini") + if err != nil { + t.Errorf("读取JSON配置失败,错误信息为:%s", err) + } +} + +func TestReadIntJsonValue(t *testing.T) { + actualValue, err := ReadIntJsonValue(config, "ServerGroupId") + if err != nil { + t.Errorf("读取JSON配置失败,错误信息为:%s", err) + } + + expectedValue := 1 + if actualValue != expectedValue { + t.Errorf("期望的值为%d,实际的值为%d", expectedValue, actualValue) + } +} + +func TestReadStringJsonValue(t *testing.T) { + actualValue, err := ReadStringJsonValue(config, "ChatDBConnection") + if err != nil { + t.Errorf("读取JSON配置失败,错误信息为:%s", err) + } + + expectedValue := "root:moqikaka@tcp(192.168.1.226:3306)/chatserver?charset=utf8&parseTime=true&loc=Local&timeout=30s" + if actualValue != expectedValue { + t.Errorf("期望的值为%s,实际的值为%s", expectedValue, actualValue) + } +} + +func TestReadBoolJsonValue(t *testing.T) { + actualValue, err := ReadBoolJsonValue(config, "IfRecordMessage") + if err != nil { + t.Errorf("读取JSON配置失败,错误信息为:%s", err) + } + + expectedValue := true + if actualValue != expectedValue { + t.Errorf("期望的值为%v,实际的值为%v", expectedValue, actualValue) + } +} diff --git a/.svn/pristine/14/14f1b3374c1cb8cdd4b7ad9f7efe545734fe2675.svn-base b/.svn/pristine/14/14f1b3374c1cb8cdd4b7ad9f7efe545734fe2675.svn-base new file mode 100644 index 0000000..92f898c --- /dev/null +++ b/.svn/pristine/14/14f1b3374c1cb8cdd4b7ad9f7efe545734fe2675.svn-base @@ -0,0 +1,127 @@ +package logUtil + +import ( + "fmt" + "runtime" + "strings" +) + +const ( + con_MIN_SKIP = 1 + con_MAX_SKIP = 10 +) + +// InfoLog 信息日志记录 +// format:日志格式 +// args:参数列表 +func InfoLog(format string, args ...interface{}) { + for _, log := range logs { + log.InfoLog(format, args...) + } +} + +// WarnLog 警告日志记录 +// format:日志格式 +// args:参数列表 +func WarnLog(format string, args ...interface{}) { + for _, log := range logs { + log.WarnLog(format, args...) + } +} + +// DebugLog 调试日志记录 +// format:日志格式 +// args:参数列表 +func DebugLog(format string, args ...interface{}) { + for _, log := range logs { + log.DebugLog(format, args...) + } +} + +// ErrorLog 错误日志记录 +// format:日志格式 +// args:参数列表 +func ErrorLog(format string, args ...interface{}) { + for _, log := range logs { + log.ErrorLog(format, args...) + } +} + +// FatalLog 致命错误日志记录 +// format:日志格式 +// args:参数列表 +func FatalLog(format string, args ...interface{}) { + for _, log := range logs { + log.FatalLog(format, args...) + } +} + +// Close +// @description: 关闭日志 +// parameter: +// @waitFinish:是否等待关闭完成 +// return: +func Close(waitFinish bool) { + for _, log := range logs { + log.CloseLog(waitFinish) + } +} + +//--------------------------Deprecated methods start---------------------------- + +// Log 日志记录 +// Deprecated: use XXXLog api instead +func Log(logInfo string, lv LogType, ifIncludeHour bool) { + switch lv { + case Info: + InfoLog(logInfo) + case Warn: + WarnLog(logInfo) + case Debug: + DebugLog(logInfo) + case Error: + ErrorLog(logInfo) + case Fatal: + FatalLog(logInfo) + } +} + +// NormalLog 日志记录 +// Deprecated: use XXXLog api instead +func NormalLog(logInfo string, level LogType) { + Log(logInfo, level, true) +} + +// LogAndPrint 日志记录 +// Deprecated: use XXXLog api instead +func LogAndPrint(logInfo string, level LogType) { + NormalLog(logInfo, level) + fmt.Println(logInfo) +} + +// LogUnknownError 日志记录 +func LogUnknownError(r interface{}, args ...string) { + buf := strings.Builder{} + buf.WriteString(fmt.Sprintf("通过recover捕捉到的未处理异常:%v \n", r)) + + // 获取附加信息 + if len(args) > 0 { + buf.WriteString("附加信息:") + buf.WriteString(strings.Join(args, "-")) + buf.WriteString("\n") + } + + // 获取堆栈信息 + for skip := con_MIN_SKIP; skip <= con_MAX_SKIP; skip++ { + _, file, line, ok := runtime.Caller(skip) + if !ok { + break + } + buf.WriteString(fmt.Sprintf("skip = %d, file = %s, line = %d \n", skip, file, line)) + buf.WriteString("\n") + } + + ErrorLog(buf.String()) +} + +//--------------------------Deprecated methods end---------------------------- diff --git a/.svn/pristine/15/15c0d6e3d729f98b5b8564f2033328f4aee93dc0.svn-base b/.svn/pristine/15/15c0d6e3d729f98b5b8564f2033328f4aee93dc0.svn-base new file mode 100644 index 0000000..941f258 --- /dev/null +++ b/.svn/pristine/15/15c0d6e3d729f98b5b8564f2033328f4aee93dc0.svn-base @@ -0,0 +1,76 @@ +// ************************************ +// @package: websocketServer +// @description: WsServer/WssServer接口,以便统一调用 +// @author: +// @revision history: +// @create date: 2022-02-22 16:07:27 +// ************************************ +package websocketServer + +import ( + "github.com/gorilla/websocket" + webServer "Framework/webServer" + "sync" + "time" +) + +// IServer +// @description: WsServer/WssServer接口,以便统一调用 +type IServer interface { + //------------------------------------- + // HttpServer方法 + + // HttpServer接口 + webServer.IWebServer + + // 设置地址 + SetAddr(addr string) + + // 启动HttpServer + Start(wg *sync.WaitGroup) + + //------------------------------------- + // websocket方法 + + // 注册websocket回调 + RegisterWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) + + // 注册正则websocket回调 + RegisterRegexWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) + + // 设置websocket参数结构 + SetUpgrader(upgrader *websocket.Upgrader) + + // 获取websocket参数结构 + GetUpgrader() *websocket.Upgrader + + // 设置接收到Ping消息时,是否自动回复Pong信息 + SetAutoPong(autuPong bool) + + // 获取接收到Ping消息时,是否自动回复Pong信息 + GetAutoPong() bool + + // 设置心跳检测信息 + SetHeartbeatDetectInfo(heartbeatCloseCount int, heartbeatCycle time.Duration) + + // 获取心跳检测信息 + GetHeartbeatDetectInfo() (heartbeatCloseCount int, heartbeatCycle time.Duration) + + // 设置广播并发数 + SetBroadcastConcurrent(n int) + + // 允许新连接 + EnableNewConn() + + // 禁用新连接 + DisableNewConn() + + // 多播消息(给指定多用户发送消息) + MulticastMessage(ctxs []*Context, messageType int, data []byte) (err error) + + // 消息广播 + BroadcastMessage(messageType int, data []byte) (err error) + + // 关闭所有连接 + CloseAll() +} diff --git a/.svn/pristine/16/1651822b5dae47034a6e1eca1f65ebcdd985ab61.svn-base b/.svn/pristine/16/1651822b5dae47034a6e1eca1f65ebcdd985ab61.svn-base new file mode 100644 index 0000000..3a4043c --- /dev/null +++ b/.svn/pristine/16/1651822b5dae47034a6e1eca1f65ebcdd985ab61.svn-base @@ -0,0 +1,80 @@ + + + + go websocket + + + + +

WebSocket Test

+ + + +
+ + + \ No newline at end of file diff --git a/.svn/pristine/17/175c67ad8c4ec0d0b345954e5fcd054c655fcda7.svn-base b/.svn/pristine/17/175c67ad8c4ec0d0b345954e5fcd054c655fcda7.svn-base new file mode 100644 index 0000000..e7496b7 --- /dev/null +++ b/.svn/pristine/17/175c67ad8c4ec0d0b345954e5fcd054c655fcda7.svn-base @@ -0,0 +1,15 @@ +package dfaExUtil + +import "testing" + +func TestHandleWord(t *testing.T) { + strs := []string{"ABC", "1234", "测试", "测试代码", "测试一下"} + + dfaEx1 := NewDFAEx(strs) + str := dfaEx1.HandleWord("abc按了数字12345来测试代码是否正常,结果测试出了bug", '*') + t.Log(str) + + dfaEx2 := NewDFAEx(strs, true) + str = dfaEx2.HandleWord("abc按了数字12345来测试代码是否正常,结果测试出了bug", '*') + t.Log(str) +} diff --git a/.svn/pristine/17/17893865ee184352bf16c2e23e049560a9b6ba80.svn-base b/.svn/pristine/17/17893865ee184352bf16c2e23e049560a9b6ba80.svn-base new file mode 100644 index 0000000..c8ecf86 --- /dev/null +++ b/.svn/pristine/17/17893865ee184352bf16c2e23e049560a9b6ba80.svn-base @@ -0,0 +1,93 @@ +/* +提供统一的ip验证的逻辑;包括两部分: +1、ManageCenter中配置到ServerGroup中的IP;系统内部自动处理,外部无需关注(暂时不用); +2、各个应用程序中配置的ip;通过调用Init或InitString方法进行初始化; +*/ +package ipMgr + +import ( + "sync" + + "goutil/stringUtil" +) + +var ( + ipMap = make(map[string]struct{}, 32) // 本地ip集合 + ipCheckFuncList = make([]func(string) bool, 0, 16) // ip检查函数列表 + mutex sync.RWMutex +) + +// 初始化IP列表 +func Init(ipList []string) { + mutex.Lock() + defer mutex.Unlock() + + // 先清空再初始化 + ipMap = make(map[string]struct{}, 32) + for _, item := range ipList { + ipMap[item] = struct{}{} + } +} + +// 初始化ip字符串(以分隔符分割的,分隔符为:",", ";", ":", "|", "||") +func InitString(ipStr string) { + mutex.Lock() + defer mutex.Unlock() + + // 先清空再初始化 + ipMap = make(map[string]struct{}, 32) + for _, item := range stringUtil.Split(ipStr, nil) { + ipMap[item] = struct{}{} + } +} + +func AddString(ipStr string) { + mutex.Lock() + defer mutex.Unlock() + + // 先清空再初始化 + if ipMap == nil { + ipMap = make(map[string]struct{}, 32) + } + + for _, item := range stringUtil.Split(ipStr, nil) { + ipMap[item] = struct{}{} + } +} + +// RegisterIpCheckFunc 注册Ip检查函数 +func RegisterIpCheckFunc(funcName string, funcItem func(string) bool) { + mutex.Lock() + defer mutex.Unlock() + + ipCheckFuncList = append(ipCheckFuncList, funcItem) +} + +func isLocalValid(ip string) bool { + mutex.RLock() + defer mutex.RUnlock() + + _, exist := ipMap[ip] + return exist +} + +func isCheckFuncValid(ip string) bool { + mutex.RLock() + defer mutex.RUnlock() + + for _, funcItem := range ipCheckFuncList { + if funcItem(ip) { + return true + } + } + + return false +} + +// 判断传入的Ip是否有效 +// ip:ip +// 返回值: +// 是否有效 +func IsIpValid(ip string) bool { + return isLocalValid(ip) || isCheckFuncValid(ip) +} diff --git a/.svn/pristine/18/18086fba2a253139cdd05cf26644b4f525c60e99.svn-base b/.svn/pristine/18/18086fba2a253139cdd05cf26644b4f525c60e99.svn-base new file mode 100644 index 0000000..444c3b4 --- /dev/null +++ b/.svn/pristine/18/18086fba2a253139cdd05cf26644b4f525c60e99.svn-base @@ -0,0 +1,210 @@ +package managecenterModel + +import ( + "fmt" + "sort" + "strconv" + "strings" + "time" + + "goutil/stringUtil" + "goutil/typeUtil" +) + +// 游戏版本 +type ResourceVersion struct { + // 资源版本唯一标识 + Id int32 `json:"ResourceVersionID"` + + // 资源版本名称 + Name string `json:"ResourceVersionName"` + + // 资源版本的url地址 + Url string `json:"ResourceVersionUrl"` + + // 资源大小 + Size int32 `json:"Size"` + + // 资源文件MD5加密的结果 + MD5 string `json:"MD5"` + + //大区Id + AreaID int32 `json:"AreaID"` + + // 资源生效时间 + StartTime string `json:"StartTime"` + StartTimeTick int64 `json:"StartTimeTick"` + + // 资源失效时间 + EndTime string `json:"EndTime"` + EndTimeTick int64 `json:"EndTimeTick"` + + // 添加时间 + Crdate string `json:"Crdate"` + CrdateTick int64 `json:"CrdateTick"` + + // 更新时间 + UpdateTime string `json:"UpdateTime"` + UpdateTimeTick int64 `json:"UpdateTimeTick"` + + // 是否重启客户端 + IfRestart int32 `json:"IfRestart"` + + // 是否禁用 + IfDelete int32 `json:"IfDelete"` + + // 是否审核服下载 + IfAuditServiceDownload int32 `json:"IfAuditServiceDownload"` + + // 资源所属的合作商ID集合 + PartnerIds string `json:"PartnerIDs"` + + // 资源所属的游戏版本ID集合 + GameVersionIds string `json:"GameVersionIDs"` +} + +// 判断资源是否包含指定合作商 +// partnerId:合作商Id +// 返回值 +// 是否包含 +func (this *ResourceVersion) ContainsPartner(partnerId int32) bool { + partnerIdList, _ := stringUtil.SplitToInt32Slice(this.PartnerIds, ",") + for _, item := range partnerIdList { + if item == partnerId { + return true + } + } + + return false +} + +// 判断资源是否包含指定游戏版本 +// gameVersionId:游戏版本Id +// 返回值 +// 是否包含 +func (this *ResourceVersion) ContainsGameVersion(gameVersionId int32) bool { + gameVersionIdList, _ := stringUtil.SplitToInt32Slice(this.GameVersionIds, ",") + for _, item := range gameVersionIdList { + if item == gameVersionId { + return true + } + } + + return false +} + +// 获取有效资源包 +func GetAvailableResource(resourceVersionList []*ResourceVersion, partnerId, gameVersionId int32, resourceVersionName string, offTest OfficialOrTest) (availableResourceVersion map[string]interface{}) { + + if len(resourceVersionList) == 0 { + return + } + + //判断资源是否有效 + _, hashCode, isVaild := IsResourceVersionNameValid(resourceVersionName) + if !isVaild { + return + } + + //根据合作商Id和游戏版本Id和开始时间来过滤 + var targetResourceVersionList []*ResourceVersion + for _, resourceVersion := range resourceVersionList { + startime, err := typeUtil.DateTime(resourceVersion.StartTimeTick) + if resourceVersion.ContainsPartner(partnerId) && resourceVersion.ContainsGameVersion(gameVersionId) && err == nil && startime.Before(time.Now()) { + targetResourceVersionList = append(targetResourceVersionList, resourceVersion) + } + } + + if len(targetResourceVersionList) == 0 { + return + } + + //组装数据 + + //按照资源Id进行降序排列 + sort.Slice(targetResourceVersionList, func(i, j int) bool { + return targetResourceVersionList[i].SortByIdDesc(targetResourceVersionList[j]) + }) + + //取出资源号最大的资源,如果与传入的资源名称相等,则表示没有新资源 + availableResourceVersion = make(map[string]interface{}, 0) + newResource := targetResourceVersionList[0] + availableResourceVersion["ResourceVersionName"] = newResource.Name + availableResourceVersion["Url"] = strings.Replace(newResource.Url, ".zip", "", -1) + + if newResource.Name == resourceVersionName { + + //是否有新资源,如果为fasle,也需要返回project.manifest.temp.zip 用于子包验证 + availableResourceVersion["IsNewResource"] = false + + return + } + + //判断资源号中的HashCode是否相等,如果相等,则表示没有新资源;如果传入的timeTick>最新的timeTick说明服务器没有被刷新,表示没有新资源 + _, newHashCode, newIsVaild := IsResourceVersionNameValid(newResource.Name) + if !newIsVaild { + return + } + + if compareRes := strings.Compare(hashCode, newHashCode); compareRes == 0 { + //是否有新资源,如果为fasle,也需要返回project.manifest.temp.zip 用于子包验证 + availableResourceVersion["IsNewResource"] = false + + return + } + + if offTest == Con_Test && newResource.IfAuditServiceDownload == 0 { + return nil + } + + availableResourceVersion["IsNewResource"] = true + + return +} + +// 按照Id进行升序排序 +// target:另一个资源对象 +// 是否是小于 +func (this *ResourceVersion) SortByIdAsc(target *ResourceVersion) bool { + return this.Id < target.Id +} + +// 按照Id进行降序排序 +// target:另一个资源对象 +// 是否是大于 +func (this *ResourceVersion) SortByIdDesc(target *ResourceVersion) bool { + return this.Id > target.Id +} + +//判断资源版本是否有效 +func IsResourceVersionNameValid(resourceVersionName string) (timeTick int64, hashCode string, isValid bool) { + if len(resourceVersionName) == 0 { + isValid = false + + return + } + + if index := strings.Index(resourceVersionName, "_"); index == -1 { + resourceVersionName = fmt.Sprintf("0_%s", resourceVersionName) + } + + resourceList := stringUtil.Split(resourceVersionName, []string{"_"}) + if len(resourceList) != 2 { + isValid = false + + return + } + + //解析timeTick + timeTick, err := strconv.ParseInt(resourceList[0], 10, 64) + if err != nil { + isValid = false + + return + } + + hashCode = resourceList[1] + isValid = true + + return +} diff --git a/.svn/pristine/18/1838ff95fb3a29c19e78e2e5e1e308e4bc2551c4.svn-base b/.svn/pristine/18/1838ff95fb3a29c19e78e2e5e1e308e4bc2551c4.svn-base new file mode 100644 index 0000000..1e2afb3 --- /dev/null +++ b/.svn/pristine/18/1838ff95fb3a29c19e78e2e5e1e308e4bc2551c4.svn-base @@ -0,0 +1,73 @@ +package redisUtil + +import ( + "github.com/gomodule/redigo/redis" +) + +func (this *RedisPool) Int(reply interface{}) (int, error) { + return redis.Int(reply, nil) +} + +func (this *RedisPool) Int64(reply interface{}) (int64, error) { + return redis.Int64(reply, nil) +} + +func (this *RedisPool) Uint64(reply interface{}) (uint64, error) { + return redis.Uint64(reply, nil) +} + +func (this *RedisPool) Float64(reply interface{}) (float64, error) { + return redis.Float64(reply, nil) +} + +func (this *RedisPool) String(reply interface{}) (string, error) { + return redis.String(reply, nil) +} + +func (this *RedisPool) Bytes(reply interface{}) ([]byte, error) { + return redis.Bytes(reply, nil) +} + +func (this *RedisPool) Bool(reply interface{}) (bool, error) { + return redis.Bool(reply, nil) +} + +func (this *RedisPool) Values(reply interface{}) ([]interface{}, error) { + return redis.Values(reply, nil) +} + +func (this *RedisPool) Ints(reply interface{}) ([]int, error) { + return redis.Ints(reply, nil) +} + +func (this *RedisPool) Int64s(reply interface{}) ([]int64, error) { + return redis.Int64s(reply, nil) +} + +func (this *RedisPool) Float64s(reply interface{}) ([]float64, error) { + return redis.Float64s(reply, nil) +} + +func (this *RedisPool) Strings(reply interface{}) ([]string, error) { + return redis.Strings(reply, nil) +} + +func (this *RedisPool) ByteSlices(reply interface{}) ([][]byte, error) { + return redis.ByteSlices(reply, nil) +} + +func (this *RedisPool) IntMap(reply interface{}) (map[string]int, error) { + return redis.IntMap(reply, nil) +} + +func (this *RedisPool) Int64Map(reply interface{}) (map[string]int64, error) { + return redis.Int64Map(reply, nil) +} + +func (this *RedisPool) StringMap(reply interface{}) (map[string]string, error) { + return redis.StringMap(reply, nil) +} + +func (this *RedisPool) Positions(reply interface{}) ([]*[2]float64, error) { + return redis.Positions(reply, nil) +} diff --git a/.svn/pristine/18/1849d81e98b05475fc80c58a3255322d410a1a84.svn-base b/.svn/pristine/18/1849d81e98b05475fc80c58a3255322d410a1a84.svn-base new file mode 100644 index 0000000..4e5137f --- /dev/null +++ b/.svn/pristine/18/1849d81e98b05475fc80c58a3255322d410a1a84.svn-base @@ -0,0 +1,68 @@ +package intAndBytesUtil + +import ( + "encoding/binary" + "testing" +) + +func TestInt16ToBytes(t *testing.T) { + var expectedBigEndian []byte = []byte{1, 0} + var expectedLittleEndian []byte = []byte{0, 1} + var givenInt int16 = 256 + + result := Int16ToBytes(givenInt, binary.BigEndian) + if equal(result, expectedBigEndian) == false { + t.Errorf("IntToBytes(%v) failed.Got %v, expected %v", givenInt, result, expectedBigEndian) + } + + result = Int16ToBytes(givenInt, binary.LittleEndian) + if equal(result, expectedLittleEndian) == false { + t.Errorf("IntToBytes(%v) failed.Got %v, expected %v", givenInt, result, expectedLittleEndian) + } +} + +func TestInt32ToBytes(t *testing.T) { + var expectedBigEndian []byte = []byte{0, 0, 1, 0} + var expectedLittleEndian []byte = []byte{0, 1, 0, 0} + var givenInt int32 = 256 + + result := Int32ToBytes(givenInt, binary.BigEndian) + if equal(result, expectedBigEndian) == false { + t.Errorf("IntToBytes(%v) failed.Got %v, expected %v", givenInt, result, expectedBigEndian) + } + + result = Int32ToBytes(givenInt, binary.LittleEndian) + if equal(result, expectedLittleEndian) == false { + t.Errorf("IntToBytes(%v) failed.Got %v, expected %v", givenInt, result, expectedLittleEndian) + } +} + +func TestInt64ToBytes(t *testing.T) { + var expectedBigEndian []byte = []byte{0, 0, 0, 0, 0, 0, 1, 0} + var expectedLittleEndian []byte = []byte{0, 1, 0, 0, 0, 0, 0, 0} + var givenInt int64 = 256 + + result := Int64ToBytes(givenInt, binary.BigEndian) + if equal(result, expectedBigEndian) == false { + t.Errorf("IntToBytes(%v) failed.Got %v, expected %v", givenInt, result, expectedBigEndian) + } + + result = Int64ToBytes(givenInt, binary.LittleEndian) + if equal(result, expectedLittleEndian) == false { + t.Errorf("IntToBytes(%v) failed.Got %v, expected %v", givenInt, result, expectedLittleEndian) + } +} + +func equal(b1, b2 []byte) bool { + if len(b1) != len(b2) { + return false + } + + for i := 0; i < len(b1); i++ { + if b1[i] != b2[i] { + return false + } + } + + return true +} diff --git a/.svn/pristine/18/18e8f4fcc246b38d375d7d7cf3d46f677afc9de1.svn-base b/.svn/pristine/18/18e8f4fcc246b38d375d7d7cf3d46f677afc9de1.svn-base new file mode 100644 index 0000000..1a1566e --- /dev/null +++ b/.svn/pristine/18/18e8f4fcc246b38d375d7d7cf3d46f677afc9de1.svn-base @@ -0,0 +1,2 @@ +Log/* +logs/* \ No newline at end of file diff --git a/.svn/pristine/19/19cd06f67349e079d14ba9d6e284cd8a2cbd2ca4.svn-base b/.svn/pristine/19/19cd06f67349e079d14ba9d6e284cd8a2cbd2ca4.svn-base new file mode 100644 index 0000000..0139d3d --- /dev/null +++ b/.svn/pristine/19/19cd06f67349e079d14ba9d6e284cd8a2cbd2ca4.svn-base @@ -0,0 +1,1501 @@ +package redisUtil + +import ( + "fmt" + "testing" + "time" + + "github.com/gomodule/redigo/redis" +) + +var ( + redisPoolObj_hash *RedisPool +) + +func init() { + redisPoolObj_hash = NewRedisPool("testPool", "10.1.0.21:6379", "redis_pwd", 5, 500, 200, 10*time.Second, 5*time.Second) +} + +func TestHSet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 设置一个新域: + + redis> HSET website google "www.g.cn" + (integer) 1 + */ + key := "website" + field := "google" + value := "www.g.cn" + expected := 1 + got, err := redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> HGET website google + "www.g.cn" + */ + expected2 := "www.g.cn" + got2, exist, err := redisPoolObj_hash.HGet(key, field) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s and field:%s should exist, but now it doesn't", key, field) + return + } + got2_str, err := redis.String(got2, err) + if err != nil { + t.Fail() + } + if got2_str != expected2 { + t.Errorf("Expected to get %s, but got %s", expected2, got2_str) + return + } + + /* + 对一个已存在的域进行更新: + redis> HSET website google "www.google.com" + (integer) 0 + + */ + field = "google" + value = "www.google.com" + expected = 0 + got, err = redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + + /* + redis> HGET website google + "www.google.com" + */ + expected3 := "www.google.com" + got3, exist, err := redisPoolObj_hash.HGet(key, field) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s and field:%s should exist, but now it doesn't", key, field) + return + } + got3_str, err := redis.String(got3, nil) + if err != nil { + t.Fail() + } + if got3_str != expected3 { + t.Errorf("Expected to get %s, but got %s", expected3, got3_str) + return + } + + /* + 对一个已存在的域进行更新: + redis> HSET website google 1 + (integer) 0 + + */ + field = "google" + value4 := 1 + expected = 0 + got, err = redisPoolObj_hash.HSet(key, field, value4) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + + /* + redis> HGET website google + "www.google.com" + */ + expected4 := 1 + got4, exist, err := redisPoolObj_hash.HGet(key, field) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s and field:%s should exist, but now it doesn't", key, field) + return + } + got4_int, err := redis.Int(got4, nil) + if err != nil { + t.Fail() + } + if got4_int != expected4 { + t.Errorf("Expected to get %d, but got %d", expected4, got4_int) + return + } +} + +func TestHSetNX(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 域尚未存在, 设置成功: + + redis> HSETNX database key-value-store Redis + (integer) 1 + */ + key := "database" + field := "key-value-store" + value := "Redis" + successful, err := redisPoolObj_hash.HSetNX(key, field, value) + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("HSetNX key:%s, field:%s should be successful, but now it's not.", key, field) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> HGET database key-value-store + "Redis" + */ + expected := "Redis" + gottmp, exist, err := redisPoolObj_hash.HGet(key, field) + got, err := redis.String(gottmp, err) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("Key:%s, field:%s should exist, but now it doesn't.", key, field) + return + } + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + /* + 域已经存在, 设置未成功, 域原有的值未被改变: + + redis> HSETNX database key-value-store Riak + (integer) 0 + */ + value = "Riak" + successful, err = redisPoolObj_hash.HSetNX(key, field, value) + if err != nil { + t.Fail() + } + if successful { + t.Errorf("HSetNX key:%s, field:%s should be not successful, but now it is.", key, field) + return + } + + /* + redis> HGET database key-value-store + "Redis" + */ + expected = "Redis" + gottmp, exist, err = redisPoolObj_hash.HGet(key, field) + got, err = redis.String(gottmp, err) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("Key:%s, field:%s should exist, but now it doesn't.", key, field) + return + } + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } +} + +func TestHGet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 域存在的情况: + + redis> HSET homepage redis redis.com + (integer) 1 + */ + key := "homepage" + field := "redis" + value := "redis.com" + expected := 1 + got, err := redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> HGET homepage redis + "redis.com" + */ + expected2 := "redis.com" + got2, exist, err := redisPoolObj_hash.HGet(key, field) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s and field:%s should exist, but now it doesn't", key, field) + return + } + got2_str, err := redis.String(got2, err) + if err != nil { + t.Fail() + } + if got2_str != expected2 { + t.Errorf("Expected to get %s, but got %s", expected2, got2_str) + return + } + + /* + 域不存在的情况: + + redis> HGET site mysql + (nil) + */ + key = "site" + field = "mysql" + _, exist, err = redisPoolObj_hash.HGet(key, field) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s and field:%s should not exist, but now it does", key, field) + return + } +} + +func TestHExists(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 给定域不存在: + + redis> HEXISTS phone myphone + (integer) 0 + 给定域存在: + */ + key := "phone" + field := "myphone" + expected := false + got, err := redisPoolObj_hash.HExists(key, field) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + /* + redis> HSET phone myphone nokia-1110 + (integer) 1 + */ + value := "nokia-1110" + expected2 := 1 + got2, err := redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d", expected2, got2) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> HEXISTS phone myphone + (integer) 1 + */ + expected3 := true + got3, err := redisPoolObj_hash.HExists(key, field) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %t, but now got %t", expected3, got3) + return + } +} + +func TestHDel(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 测试数据 + */ + key := "abbr" + redisPoolObj_hash.HSet(key, "a", "apple") + redisPoolObj_hash.HSet(key, "b", "banana") + redisPoolObj_hash.HSet(key, "c", "cat") + redisPoolObj_hash.HSet(key, "d", "dog") + deleteKeys = append(deleteKeys, key) + + /* + # 删除单个域 + + redis> HDEL abbr a + (integer) 1 + */ + field := "a" + expected := 1 + got, err := redisPoolObj_hash.HDel(key, field) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + # 删除不存在的域 + + redis> HDEL abbr not-exists-field + (integer) 0 + */ + field = "not-exists-field" + expected = 0 + got, err = redisPoolObj_hash.HDel(key, field) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + # 删除多个域 + + redis> HDEL abbr b c + (integer) 2 + */ + fields := []string{"b", "c"} + expected = 2 + got, err = redisPoolObj_hash.HDel(key, fields...) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> HGETALL abbr + 1) "d" + 2) "dog" + */ +} + +func TestHLen(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> HSET db redis redis.com + (integer) 1 + */ + key := "db" + field := "redis" + value := "redis.com" + expected := 1 + got, err := redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> HSET db mysql mysql.com + (integer) 1 + */ + field = "mysql" + value = "mysql.com" + expected = 1 + got, err = redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> HLEN db + (integer) 2 + */ + expected = 2 + got, err = redisPoolObj_hash.HLen(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> HSET db mongodb mongodb.org + (integer) 1 + */ + field = "mongodb" + value = "mongodb.org" + expected = 1 + got, err = redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> HLEN db + (integer) 3 + */ + expected = 3 + got, err = redisPoolObj_hash.HLen(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } +} + +func TestHStrlen(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> HMSET myhash f1 "HelloWorld" f2 "99" f3 "-256" + OK + */ + key := "myhash" + redisPoolObj_hash.HSet(key, "f1", "HelloWorld") + redisPoolObj_hash.HSet(key, "f2", "99") + redisPoolObj_hash.HSet(key, "f3", "-256") + deleteKeys = append(deleteKeys, key) + + /* + redis> HSTRLEN myhash f1 + (integer) 10 + */ + expected := 10 + field := "f1" + got, err := redisPoolObj_hash.HStrlen(key, field) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> HSTRLEN myhash f2 + (integer) 2 + */ + expected = 2 + field = "f2" + got, err = redisPoolObj_hash.HStrlen(key, field) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> HSTRLEN myhash f3 + (integer) 4 + */ + expected = 4 + field = "f3" + got, err = redisPoolObj_hash.HStrlen(key, field) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } +} + +func TestHIncrBy(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # increment 为正数 + + redis> HEXISTS counter page_view # 对空域进行设置 + (integer) 0 + */ + key := "counter" + field := "page_view" + exist, err := redisPoolObj_hash.HExists(key, field) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s, field:%s should not exist, but now it does.", key, field) + return + } + + /* + redis> HINCRBY counter page_view 200 + (integer) 200 + */ + increment := int64(200) + expected := int64(200) + got, err := redisPoolObj_hash.HIncrBy(key, field, increment) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> HGET counter page_view + "200" + */ + expected = 200 + got2, exist, err := redisPoolObj_hash.HGet(key, field) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field) + return + } + got2_int64, err := redis.Int64(got2, err) + if err != nil { + t.Fail() + } + if got2_int64 != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got2_int64) + return + } + + /* + # increment 为负数 + + redis> HGET counter page_view + "200" + */ + /* + redis> HINCRBY counter page_view -50 + (integer) 150 + */ + increment = -50 + expected = 150 + got, err = redisPoolObj_hash.HIncrBy(key, field, increment) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> HGET counter page_view + "150" + */ + expected = 150 + got3, exist, err := redisPoolObj_hash.HGet(key, field) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field) + return + } + got3_int64, err := redis.Int64(got3, err) + if err != nil { + t.Fail() + } + if got3_int64 != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got3_int64) + return + } + + /* + # 尝试对字符串值的域执行HINCRBY命令 + + redis> HSET myhash string hello,world # 设定一个字符串值 + (integer) 1 + */ + key2 := "myhash" + field2 := "string" + value2 := "hello,world" + expected4 := 1 + got4, err := redisPoolObj_hash.HSet(key2, field2, value2) + if err != nil { + t.Fail() + } + if got4 != expected4 { + t.Errorf("Expected to get %d, but now got %d", expected4, got4) + return + } + deleteKeys = append(deleteKeys, key2) + + /* + redis> HGET myhash string + "hello,world" + */ + expected5 := "hello,world" + got5_interface, exist, err := redisPoolObj_hash.HGet(key2, field2) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field) + return + } + got5, err := redis.String(got5_interface, err) + if err != nil { + t.Fail() + } + if got5 != expected5 { + t.Errorf("Expected to get %s, but now got %s", expected5, got5) + return + } + + /* + redis> HINCRBY myhash string 1 # 命令执行失败,错误。 + (error) ERR hash value is not an integer + */ + increment = 1 + got, err = redisPoolObj_hash.HIncrBy(key2, field2, increment) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + /* + redis> HGET myhash string # 原值不变 + "hello,world" + */ + expected6 := "hello,world" + got6_interface, exist, err := redisPoolObj_hash.HGet(key2, field2) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field) + return + } + got6, err := redis.String(got6_interface, err) + if err != nil { + t.Fail() + } + if got6 != expected6 { + t.Errorf("Expected to get %s, but now got %s", expected6, got6) + return + } +} + +func TestHIncrByFloat(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 值和增量都是普通小数 + + redis> HSET mykey field 10.50 + (integer) 1 + redis> HINCRBYFLOAT mykey field 0.1 + "10.6" + */ + key := "mykey" + field := "field" + value := 10.50 + expected := 1 + got, err := redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + increment := 0.1 + expected2 := 10.6 + got2, err := redisPoolObj_hash.HIncrByFloat(key, field, increment) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %f, but now got %f", expected2, got2) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + # 值和增量都是指数符号 + + redis> HSET mykey field 5.0e3 + (integer) 0 + redis> HINCRBYFLOAT mykey field 2.0e2 + "5200" + */ + value3 := 5.0e3 + expected3 := 0 + got3, err := redisPoolObj_hash.HSet(key, field, value3) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %d, but now got %d", expected3, got3) + return + } + + increment4 := 2.0e2 + expected4 := 5200.0 + got4, err := redisPoolObj_hash.HIncrByFloat(key, field, increment4) + if err != nil { + t.Fail() + } + if got4 != expected4 { + t.Errorf("Expected to get %f, but now got %f", expected4, got4) + return + } + + /* + # 对不存在的键执行 HINCRBYFLOAT + + redis> EXISTS price + (integer) 0 + redis> HINCRBYFLOAT price milk 3.5 + "3.5" + redis> HGETALL price + 1) "milk" + 2) "3.5" + */ + key5 := "price" + exist5, err := redisPoolObj_hash.Exists(key5) + if err != nil { + t.Fail() + } + if exist5 { + t.Errorf("The key:%s should not exist, but now it does.", key5) + return + } + + field5 := "milk" + increment5 := 3.5 + expected5 := 3.5 + got5, err := redisPoolObj_hash.HIncrByFloat(key5, field5, increment5) + if err != nil { + t.Fail() + } + if got5 != expected5 { + t.Errorf("Expected to get %f, but now got %f", expected5, got5) + return + } + + got5_interface, exist, err := redisPoolObj_hash.HGet(key5, field5) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't", key5, field5) + return + } + got5, err = redis.Float64(got5_interface, err) + if err != nil { + t.Fail() + } + if got5 != expected5 { + t.Errorf("Expected to get %f, but now got %f", expected5, got5) + return + } + + deleteKeys = append(deleteKeys, key5) + + /* + # 对不存在的域进行 HINCRBYFLOAT + + redis> HGETALL price + 1) "milk" + 2) "3.5" + redis> HINCRBYFLOAT price coffee 4.5 # 新增 coffee 域 + "4.5" + redis> HGETALL price + 1) "milk" + 2) "3.5" + 3) "coffee" + 4) "4.5" + */ + key6 := "price" + field6 := "coffee" + increment6 := 4.5 + expected6 := 4.5 + got6, err := redisPoolObj_hash.HIncrByFloat(key6, field6, increment6) + if err != nil { + t.Fail() + } + if got6 != expected6 { + t.Errorf("Expected to get %f, but now got %f", expected6, got6) + return + } + + got6_interface, exist, err := redisPoolObj_hash.HGet(key6, field6) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't", key6, field6) + return + } + got6, err = redis.Float64(got6_interface, err) + if got6 != expected6 { + t.Errorf("Expected to get %f, but now got %f", expected6, got6) + return + } +} + +func TestHMSet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + // HMSet + key := "people" + people := &People{ + Jack: "Jack Ma", + Gump: "Gump Li", + } + err := redisPoolObj_hash.HMSet(key, people) + if err != nil { + t.Fail() + } + + data := make(map[string]interface{}) + data["Jordan"] = "Jordan Zuo" + err = redisPoolObj_hash.HMSet(key, data) + if err != nil { + t.Fail() + } + + deleteKeys = append(deleteKeys, key) + + // HGet + field1 := "Jack" + expected1 := "Jack Ma" + got1_interface, exist1, err := redisPoolObj_hash.HGet(key, field1) + if err != nil { + t.Fail() + } + if !exist1 { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field1) + return + } + got1, err := redis.String(got1_interface, nil) + if err != nil { + t.Fail() + } + if got1 != expected1 { + t.Errorf("Expected to get %s, but now got %s", expected1, got1) + return + } + + // HGet + field2 := "Gump" + expected2 := "Gump Li" + got2_interface, exist2, err := redisPoolObj_hash.HGet(key, field2) + if err != nil { + t.Fail() + } + if !exist2 { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field2) + return + } + got2, err := redis.String(got2_interface, nil) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %s, but now got %s", expected2, got2) + return + } + + field3 := "Jordan" + expected3 := "Jordan Zuo" + got3_interface, exist3, err := redisPoolObj_hash.HGet(key, field3) + if err != nil { + t.Fail() + } + if !exist3 { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field3) + return + } + got3, err := redis.String(got3_interface, nil) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %s, but now got %s", expected3, got3) + return + } +} + +func TestHMGet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> HMSET pet dog "doudou" cat "nounou" # 一次设置多个域 + OK + */ + key := "pet" + field_value_map := make(map[string]interface{}) + field_value_map["dog"] = "doudou" + field_value_map["cat"] = "nounou" + err := redisPoolObj_hash.HMSet(key, field_value_map) + if err != nil { + t.Fail() + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> HMGET pet dog cat fake_pet # 返回值的顺序和传入参数的顺序一样 + 1) "doudou" + 2) "nounou" + 3) (nil) # 不存在的域返回nil值 + */ + expected := []string{"doudou", "nounou", ""} + reply, exist, err := redisPoolObj_hash.HMGet(key, "dog", "cat", "fake_pet") + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should have items, but now it doesn't.", key) + return + } + got, err := redisPoolObj_hash.Strings(reply) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(got, expected) == false { + t.Errorf("Expected to get %v, but got %v", expected, got) + } +} + +func TestHKeys(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 哈希表非空 + + redis> HMSET website google www.google.com yahoo www.yahoo.com + OK + */ + key := "website" + field_value_map := make(map[string]interface{}) + field_value_map["google"] = "www.google.com" + field_value_map["yahoo"] = "www.yahoo.com" + err := redisPoolObj_hash.HMSet(key, field_value_map) + if err != nil { + t.Fail() + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> HKEYS website + 1) "google" + 2) "yahoo" + */ + expected := make([]string, 0, len(field_value_map)) + for k := range field_value_map { + expected = append(expected, k) + } + got, err := redisPoolObj_hash.HKeys(key) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(got, expected) == false { + t.Errorf("Expected to get %v, but got %v", expected, got) + } + + /* + # 空哈希表/key不存在 + + redis> EXISTS fake_key + (integer) 0 + */ + key2 := "fake_key" + exist, err := redisPoolObj_hash.Exists(key2) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s should not exist, but now it does.", key2) + return + } + + /* + redis> HKEYS fake_key + (empty list or set)* + */ + expected2 := make([]string, 0, len(field_value_map)) + got2, err := redisPoolObj_hash.HKeys(key2) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(got2, expected2) == false { + t.Errorf("Expected to get %v, but got %v", expected2, got2) + } +} + +func TestHVals(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 哈希表非空 + + redis> HMSET website google www.google.com yahoo www.yahoo.com + OK + */ + key := "website" + field_value_map := make(map[string]interface{}) + field_value_map["google"] = "www.google.com" + field_value_map["yahoo"] = "www.yahoo.com" + err := redisPoolObj_hash.HMSet(key, field_value_map) + if err != nil { + t.Fail() + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> HVALS website + 1) "www.google.com" + 2) "www.yahoo.com" + */ + expected := make([]string, 0, len(field_value_map)) + for _, v := range field_value_map { + if v_str, ok := v.(string); ok { + expected = append(expected, v_str) + } + } + reply, err := redisPoolObj_hash.HVals(key) + if err != nil { + t.Fail() + } + got, err := redisPoolObj_hash.Strings(reply) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(got, expected) == false { + t.Errorf("Expected to get %v, but got %v", expected, got) + } + + /* + # 空哈希表/不存在的key + + redis> EXISTS not_exists + (integer) 0 + */ + key2 := "fake_key" + exist, err := redisPoolObj_hash.Exists(key2) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s should not exist, but now it does.", key2) + return + } + + /* + redis> HVALS not_exists + (empty list or set) + */ + expected2 := make([]string, 0, len(field_value_map)) + for _, v := range field_value_map { + if v_str, ok := v.(string); ok { + expected2 = append(expected2, v_str) + } + } + reply2, err := redisPoolObj_hash.HVals(key) + if err != nil { + t.Fail() + } + got2, err := redisPoolObj_hash.Strings(reply2) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(got2, expected2) == false { + t.Errorf("Expected to get %v, but got %v", expected2, got2) + } +} + +func TestHGetAll(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> HSET people jack "Jack Sparrow" + (integer) 1 + */ + key := "people" + field1 := "Jack" + value1 := "Jack Sparrow" + expected := 1 + got, err := redisPoolObj_hash.HSet(key, field1, value1) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> HSET people gump "Forrest Gump" + (integer) 1 + */ + field2 := "Gump" + value2 := "Forrest Gump" + expected = 1 + got, err = redisPoolObj_hash.HSet(key, field2, value2) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> HGETALL people + 1) "Jack" # 域 + 2) "Jack Sparrow" # 值 + 3) "Gump" + 4) "Forrest Gump" + */ + + reply, err := redisPoolObj_hash.HGetAll(key) + if err != nil { + t.Fail() + } + field_value_map, err := redisPoolObj_hash.StringMap(reply) + if err != nil { + t.Fail() + } + + expected1 := "Jack Sparrow" + got1, exist1 := field_value_map[field1] + if !exist1 { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field1) + return + } + if got1 != expected1 { + t.Errorf("Expected to get %s, but now got %s", expected1, got1) + return + } + + expected2 := "Forrest Gump" + got2, exist2 := field_value_map[field2] + if !exist2 { + t.Errorf("The key:%s, field:%s should exist, but now it doesn't.", key, field2) + return + } + if got2 != expected2 { + t.Errorf("Expected to get %s, but now got %s", expected2, got2) + return + } +} + +func TestHGetAll_Struct(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> HSET people jack "Jack Sparrow" + (integer) 1 + */ + key := "people" + field := "Jack" + value := "Jack Sparrow" + expected := 1 + got, err := redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> HSET people gump "Forrest Gump" + (integer) 1 + */ + field = "Gump" + value = "Forrest Gump" + expected = 1 + got, err = redisPoolObj_hash.HSet(key, field, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> HGETALL people + 1) "Jack" # 域 + 2) "Jack Sparrow" # 值 + 3) "Gump" + 4) "Forrest Gump" + */ + + got2 := new(People) + expected2 := &People{ + Jack: "Jack Sparrow", + Gump: "Forrest Gump", + } + exist, err := redisPoolObj_hash.HGetAll_Struct(key, got2) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + if got2.TheSame(expected2) == false { + t.Errorf("Expected to get:%s, but now got %s", expected2, got2) + } +} + +type People struct { + Jack string + Gump string +} + +func (this *People) TheSame(other *People) bool { + return this.Jack == other.Jack && this.Gump == other.Gump +} + +func (this *People) String() string { + return fmt.Sprintf("{\"Jack\": %s, \"Gump\":%s}", this.Jack, this.Gump) +} diff --git a/.svn/pristine/1a/1a85336be2fbc6102cfdbb3d5e7b672995ea4226.svn-base b/.svn/pristine/1a/1a85336be2fbc6102cfdbb3d5e7b672995ea4226.svn-base new file mode 100644 index 0000000..e8dd3cd --- /dev/null +++ b/.svn/pristine/1a/1a85336be2fbc6102cfdbb3d5e7b672995ea4226.svn-base @@ -0,0 +1,114 @@ +package redisUtil + +import ( + "testing" + "time" +) + +var ( + redisPoolObj *RedisPool +) + +func init() { + redisPoolObj = NewRedisPool("testPool", "10.1.0.21:6379", "redis_pwd", 5, 500, 200, 10*time.Second, 5*time.Second) +} + +func TestGetName(t *testing.T) { + expected := "testPool" + got := redisPoolObj.GetName() + if expected != got { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } +} + +func TestGetAddress(t *testing.T) { + expected := "10.1.0.21:6379" + got := redisPoolObj.GetAddress() + if expected != got { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } +} + +func converInterfaceSliceToStringSlice(sourceList []interface{}) []string { + targetList := make([]string, 0, len(sourceList)) + for _, item := range sourceList { + if item == nil { + targetList = append(targetList, "") + } else if item_str, ok := item.(string); ok { + targetList = append(targetList, item_str) + } else if item_bytes, ok2 := item.([]byte); ok2 { + targetList = append(targetList, string(item_bytes)) + } + } + + return targetList +} + +func isTwoOrderedSliceEqual(list1, list2 []string) bool { + if list1 == nil && list2 == nil { + return true + } + + if list1 == nil || list2 == nil { + return false + } + + if len(list1) != len(list2) { + return false + } + + for i := 0; i < len(list1); i++ { + if list1[i] != list2[i] { + return false + } + } + + return true +} + +func isTwoUnorderedSliceEqual(list1, list2 []string) bool { + if list1 == nil && list2 == nil { + return true + } + + if list1 == nil || list2 == nil { + return false + } + + if len(list1) != len(list2) { + return false + } + + map1 := make(map[string]struct{}) + map2 := make(map[string]struct{}) + + for _, item := range list1 { + map1[item] = struct{}{} + } + for _, item := range list2 { + map2[item] = struct{}{} + } + + for k := range map1 { + if _, exist := map2[k]; !exist { + return false + } + } + + return true +} + +func getDistinctKeyList(keyList []string) []string { + distinctKeyList := make([]string, 0, len(keyList)) + keyMap := make(map[string]struct{}) + for _, key := range keyList { + if _, exist := keyMap[key]; !exist { + distinctKeyList = append(distinctKeyList, key) + keyMap[key] = struct{}{} + } + } + + return distinctKeyList +} diff --git a/.svn/pristine/1a/1aeca629abfb9fb4344aeefa35ceadca73f1fe4c.svn-base b/.svn/pristine/1a/1aeca629abfb9fb4344aeefa35ceadca73f1fe4c.svn-base new file mode 100644 index 0000000..bd507a9 --- /dev/null +++ b/.svn/pristine/1a/1aeca629abfb9fb4344aeefa35ceadca73f1fe4c.svn-base @@ -0,0 +1,587 @@ +package typeUtil + +import ( + "testing" + "time" +) + +func TestMapDataByte(t *testing.T) { + TestMapDataUint8(t) +} + +func TestMapDataInt(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected int = 0 + + // Test when key doesn't exist + got, err := mapData.Int(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Int(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Int(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataInt8(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected int8 = 0 + + // Test when key doesn't exist + got, err := mapData.Int8(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Int8(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Int8(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataInt16(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected int16 = 0 + + // Test when key doesn't exist + got, err := mapData.Int16(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Int16(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Int16(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataInt32(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected int32 = 0 + + // Test when key doesn't exist + got, err := mapData.Int32(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Int32(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Int32(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataInt64(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected int64 = 0 + + // Test when key doesn't exist + got, err := mapData.Int64(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Int64(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Int64(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataUint(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected uint = 0 + + // Test when key doesn't exist + got, err := mapData.Uint(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Uint(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Uint(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataUint8(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected uint8 = 0 + + // Test when key doesn't exist + got, err := mapData.Uint8(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Uint8(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Uint8(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataUint16(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected uint16 = 0 + + // Test when key doesn't exist + got, err := mapData.Uint16(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Uint16(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Uint16(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataUint32(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected uint32 = 0 + + // Test when key doesn't exist + got, err := mapData.Uint32(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Uint32(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Uint32(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataUint64(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected uint64 = 0 + + // Test when key doesn't exist + got, err := mapData.Uint64(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Uint64(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Uint64(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %d, but got %d", expected, got) + return + } +} + +func TestMapDataFloat32(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected float32 = 0 + + // Test when key doesn't exist + got, err := mapData.Float32(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Float32(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Float32(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %f, but got %f", expected, got) + return + } +} + +func TestMapDataFloat64(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected float64 = 0 + + // Test when key doesn't exist + got, err := mapData.Float64(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Float64(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = 1 + expected = 1 + got, err = mapData.Float64(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %f, but got %f", expected, got) + return + } +} + +func TestMapDataBool(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected bool = true + + // Test when key doesn't exist + got, err := mapData.Bool(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = "abc" + got, err = mapData.Bool(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = true + expected = true + got, err = mapData.Bool(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %t, but got %t", expected, got) + return + } +} + +func TestMapDataString(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected string = "" + + // Test when key doesn't exist + got, err := mapData.String(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist, but type doesn't match + mapData[key] = 123 + expected = "123" + got, err = mapData.String(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %s, but got %s", expected, got) + return + } + + // Test when key exist and value matches + mapData[key] = "hello" + expected = "hello" + got, err = mapData.String(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %s, but got %s", expected, got) + return + } +} + +// Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time +func TestMapDataDateTime(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected time.Time = time.Date(2019, time.December, 25, 12, 0, 0, 0, time.UTC) + + // Test when key doesn't exist + got, err := mapData.DateTime(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist but value doesn't match + mapData[key] = "123" + expected = time.Date(2019, time.December, 25, 12, 0, 0, 0, time.UTC) + got, err = mapData.DateTime(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = time.Date(2019, time.December, 25, 12, 0, 0, 0, time.UTC) + expected = time.Date(2019, time.December, 25, 12, 0, 0, 0, time.UTC) + got, err = mapData.DateTime(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if got != expected { + t.Errorf("Expected %s, but got %s", expected, got) + return + } +} + +func TestMapDataInterface(t *testing.T) { + data := make(map[string]interface{}) + mapData := NewMapData(data) + key := "key" + var expected *Person + + // Test when key doesn't exist + got, err := mapData.Interface(key) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + // Test when key exist and value matches + mapData[key] = NewPerson("Jordan", 34) + expected = NewPerson("Jordan", 34) + got, err = mapData.Interface(key) + if err != nil { + t.Errorf("There should be no error, but now there is:%s", err) + return + } + if gotPersonObj, ok := got.(*Person); !ok { + t.Errorf("Expected type *Person") + } else if gotPersonObj.SameAs(expected) == false { + t.Errorf("Expected %v, but got %v", expected, got) + return + } +} + +type Person struct { + Name string + Age int +} + +func (this *Person) SameAs(other *Person) bool { + return this.Name == other.Name && this.Age == other.Age +} + +func NewPerson(name string, age int) *Person { + return &Person{ + Name: name, + Age: age, + } +} diff --git a/.svn/pristine/1a/1af88023dbc796a3f5f0281152a47b2d363859d6.svn-base b/.svn/pristine/1a/1af88023dbc796a3f5f0281152a47b2d363859d6.svn-base new file mode 100644 index 0000000..87c95ad --- /dev/null +++ b/.svn/pristine/1a/1af88023dbc796a3f5f0281152a47b2d363859d6.svn-base @@ -0,0 +1,54 @@ +package bytesSendUtil + +import ( + "fmt" +) + +/* +实现sender接口 +*/ + +type baseSender struct { + // 待发送的数据channel + waitingDataChan chan dataItem + + // 失败数据缓存 + cachedDataChan chan dataItem + + // 用于停止协程 + done chan struct{} +} + +func newBaseSender() *baseSender { + return &baseSender{ + waitingDataChan: make(chan dataItem, 1024), + cachedDataChan: make(chan dataItem, 1024000), + done: make(chan struct{}), + } +} + +// Sender接口 +// Send: +func (this *baseSender) Send() error { + // baseSender不实现发送 + // 由tcpSender和httpSender实现发送 + return fmt.Errorf("baseSender dose not have Send Method") +} + +// Sender接口 +// Data: 返回待发送的数据channel +func (this *baseSender) Data() <-chan dataItem { + return this.waitingDataChan +} + +// Sender接口 +// Cache:返回失败数据缓存channel +func (this *baseSender) Cache() chan dataItem { + return this.cachedDataChan +} + +// Sender接口 +// Done:返回channel用于判断是否关闭 +func (this *baseSender) Done() <-chan struct{} { + return this.done +} diff --git a/.svn/pristine/1b/1b2c410b7678eef959ff8f8c0e69d4051e45ed17.svn-base b/.svn/pristine/1b/1b2c410b7678eef959ff8f8c0e69d4051e45ed17.svn-base new file mode 100644 index 0000000..616ce39 --- /dev/null +++ b/.svn/pristine/1b/1b2c410b7678eef959ff8f8c0e69d4051e45ed17.svn-base @@ -0,0 +1,83 @@ +package notify_util + +import ( + "fmt" + + "goutil/syncUtil" +) + +var ( + // key:初始化成功的标志名称 val:占位符 + registerNC = make(map[string]*notifyCenter) + mutex = syncUtil.NewRWLocker() +) + +// getItemOrAdd +// @description: 获取注册的通知对象 +// parameter: +// @chanGroup: +// return: +// @*notifyCenter: +func getItemOrAdd(chanGroup string) *notifyCenter { + if isOk, prevStack, currStack := mutex.Lock(deathLockTime); isOk == false { + //记日志 + errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s \n当前堆栈:\n%s", prevStack, currStack) + panic(errMsg) + } + defer mutex.Unlock() + + nc, exists := registerNC[chanGroup] + if exists { + return nc + } + + nc = newNotifyCenter() + registerNC[chanGroup] = nc + + return nc +} + +// Register +// @description: 注册需要被通知的对象 +// parameter: +// @chanGroup:通知的分组标识 +// @chanName:唯一标识 +// @cf:回调方法 +// return: +func Register(chanGroup string, chanName string, cf func()) { + nc := getItemOrAdd(chanGroup) + nc.register(chanName, cf) +} + +// Unregister +// @description: 取消启动成功通知注册 +// parameter: +// @chanGroup:分组标识 +// @name:唯一标识 +// return: +func Unregister(chanGroup string, name string) { + nc := getItemOrAdd(chanGroup) + nc.unregister(name) +} + +// Notify +// @description: 通知分组所有已注册的对象 +// parameter: +// @chanGroup:分组标识 +// return: +func Notify(chanGroup string) { + nc := getItemOrAdd(chanGroup) + nc.notify() +} + +// Notify2 +// @description: 通知所有已注册的对象,该方法会在捕获第一个err的时候停止后续的通知。多用于系统启动的判定 +// parameter: +// @chanGroup:分组标识 +// return: +// @err: +func Notify2(chanGroup string) (err error) { + nc := getItemOrAdd(chanGroup) + err = nc.notify2() + return +} diff --git a/.svn/pristine/1b/1b511d8dc10711a9b500c6dea251529f59d249f0.svn-base b/.svn/pristine/1b/1b511d8dc10711a9b500c6dea251529f59d249f0.svn-base new file mode 100644 index 0000000..316ff00 --- /dev/null +++ b/.svn/pristine/1b/1b511d8dc10711a9b500c6dea251529f59d249f0.svn-base @@ -0,0 +1,35 @@ +### 窗口周期计数器 +窗口周期计数类,用于记录一个窗口周期数量,并且触发某个操作的场景。 +在下一个窗口周期会自动重置次数 + +#### =======================>使用方法说明<========================= + +1.引入包 +2.构造对象并次有 +3.调用对象的增加次数方法 + +```go +package demo + +import ( + "time" + + "goutil/counter_util" +) + +func main() { + // 构造名字叫test的,窗口间隔为1s,计数达到2就会触发警告的窗口计数器 + c := counter_util.NewCounterUtil("test", 2, checkId, func(tag string, num int, ti time.Time) { + //自定义触发动作 + }) + + c.AddNum(1) + c.AddNum(10) +} + +// 窗口周期设定为1s +func checkId(t1, t2 time.Time) bool { + return t1.Second() == t2.Second() +} + +``` \ No newline at end of file diff --git a/.svn/pristine/1b/1bb1d81f707f332983e7042674e7c933e71d089e.svn-base b/.svn/pristine/1b/1bb1d81f707f332983e7042674e7c933e71d089e.svn-base new file mode 100644 index 0000000..368103f --- /dev/null +++ b/.svn/pristine/1b/1bb1d81f707f332983e7042674e7c933e71d089e.svn-base @@ -0,0 +1,40 @@ +package main + +import ( + "common/connection" + "sync" + + _ "common/resultStatus" + "common/webServer" + _ "logincenter/internal/user" +) + +var ( + wg sync.WaitGroup +) + +func init() { + // 设置WaitGroup需要等待的数量,只要有一个服务器出现错误都停止服务器 + wg.Add(1) +} + +func main() { + + //加载配置 + loadConfig() + + // 启动webserver + go webServer.Start(&wg) + + // 阻塞等待,以免main线程退出 + wg.Wait() +} + +// loadConfig 用于加载配置信息。 +// 该函数会读取配置文件或环境变量中的设置,并根据这些设置初始化程序所需的配置。 +// 目前函数的实现为空,需要根据实际的配置加载逻辑进行填充。 +func loadConfig() { + + //构建数据库 + connection.BuildDB() +} diff --git a/.svn/pristine/1b/1bdd83307433453f47a849b07a75501b86ac53eb.svn-base b/.svn/pristine/1b/1bdd83307433453f47a849b07a75501b86ac53eb.svn-base new file mode 100644 index 0000000..affa8ca --- /dev/null +++ b/.svn/pristine/1b/1bdd83307433453f47a849b07a75501b86ac53eb.svn-base @@ -0,0 +1,36 @@ +module logincenter + +go 1.22.10 + +replace ( + common => ../common + framework => ../../framework + goutil => ../../goutil +) + +require common v0.0.0-00010101000000-000000000000 + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + framework v0.0.0-20230425160006-b2d0b0a0b0b0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/gomodule/redigo v1.8.9 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/jinzhu/gorm v1.9.12 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + gorm.io/driver/mysql v1.5.7 // indirect + gorm.io/gorm v1.25.12 // indirect + goutil v0.0.0-20230425160006-b2d0b0a0b0b0 // indirect +) diff --git a/.svn/pristine/1b/1bf0ed25a847601c48c478898d552ab339455646.svn-base b/.svn/pristine/1b/1bf0ed25a847601c48c478898d552ab339455646.svn-base new file mode 100644 index 0000000..681aa64 --- /dev/null +++ b/.svn/pristine/1b/1bf0ed25a847601c48c478898d552ab339455646.svn-base @@ -0,0 +1,6 @@ +package verifyMgr + +/* +此包用于对指定url进行访问验证,以便于在程序启动时可以提前知道目标地址的可访问性, +而不用等到实际需要时再验证;从而造成既定的影响。 +*/ diff --git a/.svn/pristine/1c/1cb4f4122548d93244351bbac432d4a7cdde9667.svn-base b/.svn/pristine/1c/1cb4f4122548d93244351bbac432d4a7cdde9667.svn-base new file mode 100644 index 0000000..610a0e8 --- /dev/null +++ b/.svn/pristine/1c/1cb4f4122548d93244351bbac432d4a7cdde9667.svn-base @@ -0,0 +1,22 @@ +package sensitiveWordsMgr + +import ( + "testing" +) + +// type Persion struct { +// name string +// } + +// 屏蔽字详细信息 +func Test1(t *testing.T) { + //启动获取敏感字 + refreshSensitiveWord() + + words, pos, exist := SensitiveWords("测试,测试") + if exist { + t.Log(words, pos) + } + + t.Log("END") +} diff --git a/.svn/pristine/1c/1cbdbfc80bd20fd584e9675d554ea02cb7d35caa.svn-base b/.svn/pristine/1c/1cbdbfc80bd20fd584e9675d554ea02cb7d35caa.svn-base new file mode 100644 index 0000000..1da475a --- /dev/null +++ b/.svn/pristine/1c/1cbdbfc80bd20fd584e9675d554ea02cb7d35caa.svn-base @@ -0,0 +1,377 @@ +package utils + +import ( + "bytes" + "compress/flate" + "encoding/json" + "fmt" + "goutil/logUtilPlus" + "io/ioutil" + "math/rand" + "net/http" + "runtime/debug" + "strconv" + "strings" + "time" +) + +// 定义常量 +var MinDateTime = time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local) +var MaxDateTime = time.Date(3000, 1, 1, 0, 0, 0, 0, time.Local) +var GuidEmpty = "00000000-0000-0000-0000-000000000000" + +// IsTrue +// @description: 是否为true +// parameter: +// @data: []byte格式的bool信息 +// return: +// @bool: 返回布尔值 +func IsTrue(data []byte) bool { + + if data == nil { + return false + } + + if len(data) == 0 { + return false + } + + if data[0] == 0 { + return false + } else { + return true + } +} + +// ConvertBooleanToBytes +// @description: bool型转换成byte数组 +// parameter: +// @status: 状态 +// return: +// @[]byte: 返回字节数组 +func ConvertBooleanToBytes(status bool) []byte { + + if status == false { + return []byte{0} + } else { + return []byte{1} + } +} + +// StrSliceJoinToStr +// @description: 将[]string组装成字符串 +// parameter: +// @numArray: 源int32数组 +// @sep: 分割字符串 +// return: +// @string: 组成的字符串 +func StrSliceJoinToStr(numArray []string, sep string) string { + str := "" + if numArray == nil || len(numArray) == 0 { + return str + } + + for _, n := range numArray { + str += fmt.Sprintf("%s%s", n, sep) + } + + str = strings.TrimSuffix(str, sep) + + return str +} + +// Int32SliceJoinToStr +// @description: 将[]int32转换成字符串 +// parameter: +// @source: 资源 +// @sep: 分隔符 +// return: +// @result: 字符串 +func Int32SliceJoinToStr(source []int32, sep string) (result string) { + if source == nil || len(source) == 0 { + return "" + } + + for _, s := range source { + result += fmt.Sprintf("%d%s", s, sep) + } + + result = strings.TrimRight(result, sep) + + return +} + +// SplitToStrSlice +// @description: 将字符串切割为[]string +// parameter: +// @s: 输入字符串 +// @sep: 分割字符串 +// @removeEmpty: 是否去除空字符串 +// return: +// @resultSlice: 字符串列表 +func SplitToStrSlice(s, sep string, removeEmpty bool) (resultSlice []string) { + if len(s) == 0 { + return make([]string, 0) + } + + // 先按照分隔符进行切割 + strSlice := strings.Split(s, sep) + + for _, value := range strSlice { + if removeEmpty { + // 去除空格 + if value = strings.TrimSpace(value); value == "" { + continue + } + } + + resultSlice = append(resultSlice, value) + } + + return resultSlice +} + +// ParseTimeString +// @description: 解析时间字符串 +// parameter: +// @timeStr: 时间字符串,例:12:33:12 +// return: +// @hour: 小时 +// @minute: 分钟 +// @second: 秒数 +func ParseTimeString(timeStr string) (hour int, minute int, second int) { + timeSlice := strings.Split(timeStr, ":") + if len(timeSlice) != 3 { + return + } + + hour, _ = strconv.Atoi(timeSlice[0]) + minute, _ = strconv.Atoi(timeSlice[1]) + second, _ = strconv.Atoi(timeSlice[2]) + + return +} + +// Rm_duplicate_string +// @description: 去重 +// parameter: +// @list: 列表 +// return: +// @[]string: 去重后的数据 +func Rm_duplicate_string(list []string) []string { + var x []string = []string{} + for _, i := range list { + if len(x) == 0 { + x = append(x, i) + } else { + for k, v := range x { + if i == v { + break + } + if k == len(x)-1 { + x = append(x, i) + } + } + } + } + return x +} + +// Rm_duplicate_int32 +// @description: 去重 +// parameter: +// @list: 列表数据 +// return: +// @[]int32: 去重后的结果 +func Rm_duplicate_int32(list []int32) []int32 { + var x []int32 = []int32{} + for _, i := range list { + if len(x) == 0 { + x = append(x, i) + } else { + for k, v := range x { + if i == v { + break + } + if k == len(x)-1 { + x = append(x, i) + } + } + } + } + return x +} + +// RandomAarrayOfInt32 +// @description: int32数组乱序 +// parameter: +// @arr: 数组 +// return: +func RandomAarrayOfInt32(arr []int32) { + + if arr == nil { + return + } + + if len(arr) <= 0 { + return + } + + rand.Seed(time.Now().UnixNano()) + + for i := len(arr) - 1; i > 0; i-- { + num := rand.Intn(i + 1) + arr[i], arr[num] = arr[num], arr[i] + } +} + +// RandomAarrayOfString +// @description: string数组乱序 +// parameter: +// @arr: 数组 +// return: +func RandomAarrayOfString(arr []string) { + + if arr == nil { + return + } + + if len(arr) <= 0 { + return + } + + rand.Seed(time.Now().UnixNano()) + + for i := len(arr) - 1; i > 0; i-- { + num := rand.Intn(i + 1) + arr[i], arr[num] = arr[num], arr[i] + } +} + +// LogErrorRecover +// @description: 记录错误 +// parameter: +// return: +func LogErrorRecover() { + if err := recover(); err != nil { + tmsg := fmt.Sprintf("err msg:%s stack:%s", err, debug.Stack()) + logUtilPlus.ErrorLog(tmsg) + } +} + +// LogReqErrorRecover +// @description: 记录错误 +// parameter: +// @r: +// return: +func LogReqErrorRecover(r *http.Request) { + if err := recover(); err != nil { + b, err := json.Marshal(r) + reqStr := "" + if err == nil { + reqStr = string(b) + } + tmsg := fmt.Sprintf("RequestInfo:%s .err msg:%s stack:%s", reqStr, err, debug.Stack()) + logUtilPlus.ErrorLog(tmsg) + } +} + +// StringSliceIsExists +// @description: StringSliceIsExists +// parameter: +// @strList: strList +// @val: val +// return: +// @bool: 是否存在 +func StringSliceIsExists(strList []string, val string) bool { + + if strList == nil { + return false + } + + for _, v := range strList { + if v == val { + return true + } + } + + return false +} + +// Int64SliceIsExists +// @description: Int64SliceIsExists +// parameter: +// @strList: strList +// @val: val +// return: +// @bool: 是否存在 +func Int64SliceIsExists(strList []int64, val int64) bool { + + if strList == nil { + return false + } + + for _, v := range strList { + if v == val { + return true + } + } + + return false +} + +// SliceIsExists +// @description: SliceIsExists +// parameter: +// @n: n +// @f: f +// return: +// @bool: 是否存在 +func SliceIsExists(n int, f func(int) bool) bool { + + for i := 0; i < n; i++ { + if f(i) { + return true + } + } + + return false +} + +// FlateEncode +// @description: 压缩字符串 +// parameter: +// @input: 输入字符列表 +// return: +// @result: 结果字符列表 +// @err: 错误信息 +func FlateEncode(input []byte) (result []byte, err error) { + var buf bytes.Buffer + w, err := flate.NewWriter(&buf, flate.DefaultCompression) + if err != nil { + return nil, err + } + + // 无法使用defer close使用无法拿到结果 + _, err = w.Write(input) + if err != nil { + return nil, err + } + + w.Close() + + result = buf.Bytes() + return +} + +// FlateDecode +// @description: FlateDecode +// parameter: +// @input: 输入字符列表 +// return: +// @result: 结果字符列表 +// @err: 错误信息 +func FlateDecode(input []byte) (result []byte, err error) { + result, err = ioutil.ReadAll(flate.NewReader(bytes.NewReader(input))) + return +} diff --git a/.svn/pristine/1c/1cd69be06a95554c30263afa7ce43d3775f1dcdb.svn-base b/.svn/pristine/1c/1cd69be06a95554c30263afa7ce43d3775f1dcdb.svn-base new file mode 100644 index 0000000..94cef04 --- /dev/null +++ b/.svn/pristine/1c/1cd69be06a95554c30263afa7ce43d3775f1dcdb.svn-base @@ -0,0 +1,34 @@ +package admin + +import ( + "common/connection" +) + +func init() { + //注册数据库 + connection.RegisterDBModel(&Admin{}) +} + +type Admin struct { + ID int64 `gorm:"column:id;primary_key;comment:管理员id;autoIncrementIncrement" json:"id"` + //账号 + Account string `gorm:"column:account;comment:账号" json:"account"` + Name string `gorm:"column:name;comment:管理员名称" json:"name"` + Password string `gorm:"column:password;comment:管理员密码" json:"password"` + //性别 + Sex int32 `gorm:"column:sex;comment:性别" json:"sex"` + //生日 + Birthday string `gorm:"column:birthday;comment:生日" json:"birthday"` + //手机 + Phone int64 `gorm:"column:phone;comment:手机" json:"phone"` + //邮箱 + Email string `gorm:"column:email;comment:邮箱" json:"email"` + //微信群【方便发送通知】 + WechatGroup string `gorm:"column:wechat_group;comment:微信群" json:"wechat_group"` + //备注 + Describe string `gorm:"column:describe;comment:备注" json:"describe"` +} + +func (Admin) TableName() string { + return "admin" +} diff --git a/.svn/pristine/1c/1cd8027881b113926160df0087f10a47ea9e87ff.svn-base b/.svn/pristine/1c/1cd8027881b113926160df0087f10a47ea9e87ff.svn-base new file mode 100644 index 0000000..4edafce --- /dev/null +++ b/.svn/pristine/1c/1cd8027881b113926160df0087f10a47ea9e87ff.svn-base @@ -0,0 +1,62 @@ +package validationUtil + +import ( + "testing" +) + +// 身份证测试 +func TestIdCard(t *testing.T) { + idno := "450325197410077393" + if IsValideIdno(idno) == false { + t.Error("身份证验证出错:", idno) + t.Fail() + } + idno = "36062219701120774X" + if IsValideIdno(idno) == false { + t.Error("身份证验证出错:", idno) + t.Fail() + } + idno = "450325197410071111" + if IsValideIdno(idno) == false { + t.Error("身份证验证出错:", idno) + t.Fail() + } + idno = "3123123123" + if IsValideIdno(idno) == true { + t.Error("身份证验证出错:", idno) + t.Fail() + } +} + +// 邮箱测试 +func TestMail(t *testing.T) { + mail := "nihao@qq.com" + if IsValideEmail(mail) == false { + t.Error("邮箱验证出错:", mail) + t.Fail() + } + mail = "111@qq.com" + if IsValideEmail(mail) == false { + t.Error("邮箱验证出错:", mail) + t.Fail() + } + mail = "111_@qq.com" + if IsValideEmail(mail) == false { + t.Error("邮箱验证出错:", mail) + t.Fail() + } +} + +// 验证中国的手机号 +func TestChinesePhone(t *testing.T) { + phoneNum := "15111111111" + if IsValideChinesePhoneNum(phoneNum) == false { + t.Error("手机号验证出错:", phoneNum) + t.Fail() + } + phoneNum = "11111" + if IsValideChinesePhoneNum(phoneNum) == true { + t.Error("手机号验证出错:", phoneNum) + t.Fail() + } +} diff --git a/.svn/pristine/1c/1ce84cb99036df716050665854c27a1925523227.svn-base b/.svn/pristine/1c/1ce84cb99036df716050665854c27a1925523227.svn-base new file mode 100644 index 0000000..32dfaf9 --- /dev/null +++ b/.svn/pristine/1c/1ce84cb99036df716050665854c27a1925523227.svn-base @@ -0,0 +1,137 @@ +package mysqlUtil + +import ( + "database/sql" + "fmt" + + _ "github.com/go-sql-driver/mysql" + "goutil/logUtil" +) + +// 打开数据库连接 +// connectionString:数据库连接字符串,格式:root:moqikaka3306@tcp(10.1.0.10:3306)/gameserver_data?charset=utf8&parseTime=true&loc=Local&timeout=60s||MaxOpenConns=10||MaxIdleConns=5 +// 返回值: +// 数据库对象 +// 错误对象 +func OpenMysqlConnection(connectionString string) (dbObj *sql.DB, err error) { + dbConfigObj, err1 := NewDBConfig2(connectionString) + if err1 != nil { + err = err1 + return + } + + dbObj, err = OpenMysqlConnection3(dbConfigObj) + return +} + +// 打开数据库连接 +// connectionString:数据库连接字符串 +// maxOpenConns:最大打开的连接数 +// maxIdleConns:最大处于闲置状态的连接数 +// 返回值: +// 数据库对象 +// 错误对象 +func OpenMysqlConnection2(connectionString string, maxOpenConns, maxIdleConns int) (dbObj *sql.DB, err error) { + dbConfigObj := NewDBConfig(connectionString, maxOpenConns, maxIdleConns) + dbObj, err = OpenMysqlConnection3(dbConfigObj) + return +} + +// 建立Mysql数据库连接 +// dbConfigObj:数据库配置对象 +// 返回值: +// 数据库对象 +// 错误对象 +func OpenMysqlConnection3(dbConfigObj *DBConfig) (dbObj *sql.DB, err error) { + // 建立数据库连接 + logUtil.DebugLog("开始连接Mysql数据库") + dbObj, err = sql.Open("mysql", dbConfigObj.ConnectionString) + if err != nil { + err = fmt.Errorf("打开游戏数据库失败,连接字符串为:%s", dbConfigObj.ConnectionString) + return + } + logUtil.DebugLog("连接Mysql数据库成功") + + if dbConfigObj.MaxOpenConns > 0 && dbConfigObj.MaxIdleConns > 0 { + dbObj.SetMaxOpenConns(dbConfigObj.MaxOpenConns) + dbObj.SetMaxIdleConns(dbConfigObj.MaxIdleConns) + } + + if err = dbObj.Ping(); err != nil { + err = fmt.Errorf("Ping数据库失败,连接字符串为:%s,错误信息为:%s", dbConfigObj.ConnectionString, err) + return + } + + return +} + +// 测试数据库连接 +// dbObj:数据库连对象 +// 返回值: +// 错误对象 +func TestConnection(dbObj *sql.DB) error { + command := "SHOW DATABASES;" + rows, err := dbObj.Query(command) + if err != nil { + return err + } + + defer rows.Close() + + return nil +} + +// 开始事务 +// db:数据库对象 +// 返回值: +// 事务对象 +// 错误对象 +func BeginTransaction(dbObj *sql.DB) (*sql.Tx, error) { + tx, err := dbObj.Begin() + if err != nil { + logUtil.Log(fmt.Sprintf("开启事务失败,错误信息:%s", err), logUtil.Error, true) + } + + return tx, err +} + +// 提交事务 +// tx:事务对象 +// 返回值: +// 错误对象 +func CommitTransaction(tx *sql.Tx) error { + err := tx.Commit() + if err != nil { + logUtil.Log(fmt.Sprintf("提交事务失败,错误信息:%s", err), logUtil.Error, true) + } + + return err +} + +// 记录Prepare错误 +// command:执行的SQL语句 +// err:错误对象 +func WritePrepareError(command string, err error) { + logUtil.Log(fmt.Sprintf("Prepare失败,错误信息:%s,command:%s", err, command), logUtil.Error, true) +} + +// 记录Query错误 +// command:执行的SQL语句 +// err:错误对象 +func WriteQueryError(command string, err error) { + logUtil.Log(fmt.Sprintf("Query失败,错误信息:%s,command:%s", err, command), logUtil.Error, true) +} + +// 记录Exec错误 +// command:执行的SQL语句 +// err:错误对象 +func WriteExecError(command string, err error) { + logUtil.Log(fmt.Sprintf("Exec失败,错误信息:%s,command:%s", err, command), logUtil.Error, true) +} + +// 记录Scan错误 +// command:执行的SQL语句 +// err:错误对象 +func WriteScanError(command string, err error) { + logUtil.Log(fmt.Sprintf("Scan失败,错误信息:%s,command:%s", err, command), logUtil.Error, true) +} diff --git a/.svn/pristine/1d/1d02ea53e36d220fc9a9e9944b67bc4d96bd8d26.svn-base b/.svn/pristine/1d/1d02ea53e36d220fc9a9e9944b67bc4d96bd8d26.svn-base new file mode 100644 index 0000000..02eaad6 --- /dev/null +++ b/.svn/pristine/1d/1d02ea53e36d220fc9a9e9944b67bc4d96bd8d26.svn-base @@ -0,0 +1,20 @@ +coroutine-timer支持如下工作: +定时触发设定的回调,最小精度秒级 + +## 使用方式 + +### 增加回调 + +> 1. 导入包 +> 2. 调用AddTimerx添加定时回调,传入相关参数 + +ps: +> 1. AddTimer1,AddTimer2,AddTimer3是内部自动生成的id,内部保证唯一性。外部如果后续要删除该添加的timer,需要持有返回的id信息 +> 2. AddTimer4 需要外部传入id,外部需要保证id的唯一性。并且这个方法会在内部校验id是否已经存在,所以性能上会比其他AddTimer方法慢 + +### 删除回调 + +```go + DeleteTimer(id) +``` + diff --git a/.svn/pristine/1d/1d4e0f007677509afe5a28cf69b7241d9675e0c1.svn-base b/.svn/pristine/1d/1d4e0f007677509afe5a28cf69b7241d9675e0c1.svn-base new file mode 100644 index 0000000..e209ebf --- /dev/null +++ b/.svn/pristine/1d/1d4e0f007677509afe5a28cf69b7241d9675e0c1.svn-base @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "sync" + "time" + + "goutil/mathUtil" + "goutil/stringUtil" +) + +var ( + wg sync.WaitGroup +) + +func init() { + wg.Add(1) +} + +func main() { + playerMgr := newPlayerMgr() + + // insert + go func() { + for { + id := stringUtil.GetNewGUID() + name := fmt.Sprintf("Hero_%s", id) + obj := newPlayer(id, name) + playerMgr.insert(obj) + + insert(obj) + time.Sleep(10 * time.Millisecond) + } + }() + + // update + go func() { + for { + obj := playerMgr.randomSelect() + if obj == nil { + continue + } + suffix := mathUtil.GetRand().GetRandInt(1000) + newName := fmt.Sprintf("Hero_%d", suffix) + obj.resetName(newName) + + update(obj) + time.Sleep(10 * time.Millisecond) + } + }() + + // delete + go func() { + for { + obj := playerMgr.randomSelect() + if obj == nil { + continue + } + playerMgr.delete(obj) + + clear(obj) + time.Sleep(10 * time.Millisecond) + } + }() + + // errorFile + go func() { + for { + time.Sleep(1 * time.Hour) + id := stringUtil.GetNewGUID() + name := fmt.Sprintf("Hero_%s%s", id, id) + obj := newPlayer(id, name) + playerMgr.insert(obj) + print("errorFile") + + insert(obj) + } + + }() + + wg.Wait() +} diff --git a/.svn/pristine/21/213b0a00bea424ffed61b3775e9a3885c7c78fac.svn-base b/.svn/pristine/21/213b0a00bea424ffed61b3775e9a3885c7c78fac.svn-base new file mode 100644 index 0000000..f093bfa --- /dev/null +++ b/.svn/pristine/21/213b0a00bea424ffed61b3775e9a3885c7c78fac.svn-base @@ -0,0 +1,219 @@ +package dfaUtil + +import "strings" + +/* +DFA util, is used to verify whether a sentence has invalid words. +The underlying data structure is trie. +https://en.wikipedia.org/wiki/Trie +*/ + +// dfa util +type DFAUtil struct { + // The root node + root *trieNode +} + +// 搜索语句 +// 由于go不支持tuple,所以为了避免定义多余的struct,特别使用两个list来分别返回匹配的索引的上界和下界 +// 在处理此方法的返回值时,需要两者配合使用 +// 参数: +// +// sentence:语句字符串 +// +// 返回: +// +// 搜索到的开始位置列表 +// 搜索到的结束位置列表 +func (this *DFAUtil) SearchSentence(sentence string) (startIndexList, endIndexList []int) { + sentenceRuneList := []rune(sentence) + for i := 0; i < len(sentenceRuneList); { + //按序匹配每个字 + end := this.searchSentenceByStart(i, sentenceRuneList) + if end < 0 { + //匹配失败,继续匹配下一个字 + i++ + } else { + //匹配成功,记录索引位置 + startIndexList = append(startIndexList, i) + endIndexList = append(endIndexList, end) + + //从匹配到的字后面开始找 + i = end + 1 + } + } + + return +} + +// 从指定的开始位置搜索语句 +// 参数: +// +// start:开始匹配的位置 +// sentenceRuneList:语句字列表 +// +// 返回: +// +// 匹配到的结束位置,未匹配到返回-1 +func (this *DFAUtil) searchSentenceByStart(start int, sentenceRuneList []rune) (endIndex int) { + //当前节点,从根节点开始找 + currNode := this.root + //是否匹配到 + var isMatched bool + + //按顺序匹配字 + for i := start; i < len(sentenceRuneList); { + child, exists := currNode.children[sentenceRuneList[i]] + + //未匹配到则结束,跳出循环(可能匹配到过词结尾) + if !exists { + break + } + + //是否是词末尾,如果是则先记录下来,因为还可能匹配到更长的词 + //比如["金鳞"、"金鳞岂是池中物"] => 匹配"金鳞岂是池中物",匹配到"金鳞"不应该停下来,应继续匹配更长的词 + if child.isEndOfWord { + endIndex = i + isMatched = true + } + + //是否已经到词末尾 + if len(child.children) == 0 { + return endIndex + } else { + //继续与后面的字匹配 + currNode = child + } + + //增加索引匹配下一个位置 + i++ + } + + //匹配结束,若曾经匹配到词末尾,则直接返回匹配到的位置 + if isMatched { + return endIndex + } else { + //没有匹配到词末尾,则返回匹配失败 + return -1 + } +} + +// Insert new word into object +func (this *DFAUtil) InsertWord(word []rune) { + currNode := this.root + for _, c := range word { + if cildNode, exist := currNode.children[c]; !exist { + cildNode = newtrieNode() + currNode.children[c] = cildNode + currNode = cildNode + } else { + currNode = cildNode + } + } + + currNode.isEndOfWord = true +} + +// Check if there is any word in the trie that starts with the given prefix. +func (this *DFAUtil) StartsWith(prefix []rune) bool { + currNode := this.root + for _, c := range prefix { + if childNode, exist := currNode.children[c]; !exist { + return false + } else { + currNode = childNode + } + } + + return true +} + +// Judge if input sentence contains some special caracter +// Return: +// Matc or not +func (this *DFAUtil) IsMatch(sentence string) bool { + startIndexList, _ := this.SearchSentence(sentence) + return len(startIndexList) > 0 +} + +// Handle sentence. Use specified caracter to replace those sensitive caracters. +// input: Input sentence +// replaceCh: candidate +// Return: +// Sentence after manipulation +func (this *DFAUtil) HandleWord(sentence string, replaceCh rune) string { + startIndexList, endIndexList := this.SearchSentence(sentence) + if len(startIndexList) == 0 { + return sentence + } + + // Manipulate + sentenceList := []rune(sentence) + for i := 0; i < len(startIndexList); i++ { + for index := startIndexList[i]; index <= endIndexList[i]; index++ { + sentenceList[index] = replaceCh + } + } + + return string(sentenceList) +} + +// Handle sentence. Use specified caracter to replace those sensitive caracters. +// input: Input sentence +// replaceCh: candidate +// Return: +// Sentence after manipulation +func (this *DFAUtil) HandleWordUseStr(input string, replaceCh string) string { + input2 := strings.ToUpper(input) + + startIndexList, endIndexList := this.SearchSentence(input2) + if len(startIndexList) == 0 { + return input + } + + // Manipulate + inputRune := []rune(input) + replaceChList := []rune(replaceCh) + + //上一次替换掉的数量 + lastReplaceCount := 0 + + for i := 0; i < len(startIndexList); i++ { + + //替换字的索引 + index := len(replaceChList) + + //开始位置--加上替换的词的索引 + starIndex := startIndexList[i] + (i * index) - lastReplaceCount + + //结束位置 + endIndex := endIndexList[i] + (i * index) - lastReplaceCount + + //结束字符串 + sentenceAttr := string(inputRune[endIndex+1:]) + + //替换范围字符串 + inputRune = append(inputRune[:starIndex], replaceChList...) + inputRune = append(inputRune, []rune(sentenceAttr)...) + lastReplaceCount = endIndex + 1 - starIndex + } + + return string(inputRune) +} + +// Create new DfaUtil object +// wordList:word list +func NewDFAUtil(wordList []string) *DFAUtil { + this := &DFAUtil{ + root: newtrieNode(), + } + + for _, word := range wordList { + wordRuneList := []rune(word) + if len(wordRuneList) > 0 { + this.InsertWord(wordRuneList) + } + } + + return this +} diff --git a/.svn/pristine/21/21a7c96834766c7d74d55dbfaf1b49771fd9e489.svn-base b/.svn/pristine/21/21a7c96834766c7d74d55dbfaf1b49771fd9e489.svn-base new file mode 100644 index 0000000..8a386c2 --- /dev/null +++ b/.svn/pristine/21/21a7c96834766c7d74d55dbfaf1b49771fd9e489.svn-base @@ -0,0 +1,54 @@ +# 配置根节点 +root: + # 是否是调试模式 + debug: true + + # Web服务监听地址和端口 + web_server_address: "192.168.50.85:10052" + + # Elasticsearch 地址 + es_urls: "http://10.252.0.70:18099" + + # 数据库配置 + db_config: + admin_db: + # 最大处于开启状态的连接数 + max_open_conns: 0 + + # 最大处于空闲状态的连接数 + max_idle_conns: 0 + + # 数据库连接字符串 + connection_string: "root:Qq5201530300@tcp(192.168.50.110:3306)/admin?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true" + + user_db: + # 最大处于开启状态的连接数 + max_open_conns: 0 + + # 最大处于空闲状态的连接数 + max_idle_conns: 0 + + # 数据库连接字符串 + connection_string: "root:Qq5201530300@tcp(192.168.50.110:3306)/user?charset=utf8&parseTime=true&loc=Local&timeout=30s&multiStatements=true" + + redis_config: + # 数据库连接字符串 + connection_string: "192.168.50.110:6379" + + # 密码, 如果要设置用户Id,则密码设置为:"UserId:Password" + password: "" + + # 数据库序号 + database: 5 + + # 最大活跃连接数 + max_active: 500 + + # 最大空闲的连接数 + max_idle: 200 + + # 连接空闲超时时间,单位:秒 + idle_timeout: 300 + + # 连接超时时间, 单位:秒 + dial_connect_timeout: 10 \ No newline at end of file diff --git a/.svn/pristine/21/21dc46aabd801627575e7862f59be14761f21a15.svn-base b/.svn/pristine/21/21dc46aabd801627575e7862f59be14761f21a15.svn-base new file mode 100644 index 0000000..56a5d9b --- /dev/null +++ b/.svn/pristine/21/21dc46aabd801627575e7862f59be14761f21a15.svn-base @@ -0,0 +1,123 @@ +package redisUtil + +import ( + "fmt" + "strconv" + "strings" + "time" +) + +// Redis配置对象 +type RedisConfig struct { + // 连接字符串 + ConnectionString string + + // 密码 + Password string + + // 数据库编号 + Database int + + // 最大活跃连接数 + MaxActive int + + // 最大空闲连接数 + MaxIdle int + + // 空闲超时 + IdleTimeout time.Duration + + // 连接超时 + DialConnectTimeout time.Duration +} + +// 将redis连接字符串转化为redis config对象 +// 格式:ConnectionString=10.1.0.21:6379;Password=redis_pwd;Database=3;MaxActive=50;MaxIdle=20;IdleTimeout=300;DialConnectTimeout=10; +// redisConfigStr:redis连接字符串 +// 返回值: +// redis config对象 +// 错误对象 +func NewRedisConfig(redisConfigStr string) (redisConfig *RedisConfig, err error) { + var connectionString string + var password string + var database int + var maxActive int + var maxIdle int + var idleTimeout time.Duration + var dialConectTimeout time.Duration + var count int = 7 + var subCount int = 2 + + itemList := strings.Split(redisConfigStr, ";") + // 去掉最后的空数据 + if itemList[len(itemList)-1] == "" { + itemList = itemList[0 : len(itemList)-1] + } + if len(itemList) != count { + err = fmt.Errorf("%s格式不正确,需要包含%d个部分,现在有%d个部分", redisConfigStr, count, len(itemList)) + return + } + + for _, item := range itemList { + subItemList := strings.Split(item, "=") + if len(subItemList) != subCount { + err = fmt.Errorf("%s格式不正确,需要包含%d个部分", item, subCount) + return + } + + // 分别进行判断 + switch strings.ToLower(subItemList[0]) { + case strings.ToLower("ConnectionString"): + connectionString = subItemList[1] + case strings.ToLower("Password"): + password = subItemList[1] + case strings.ToLower("Database"): + if database, err = strconv.Atoi(subItemList[1]); err != nil { + err = fmt.Errorf("%s转化为int型失败", subItemList[1]) + return + } + case strings.ToLower("MaxActive"): + if maxActive, err = strconv.Atoi(subItemList[1]); err != nil { + err = fmt.Errorf("%s转化为int型失败", subItemList[1]) + return + } + case strings.ToLower("MaxIdle"): + if maxIdle, err = strconv.Atoi(subItemList[1]); err != nil { + err = fmt.Errorf("%s转化为int型失败", subItemList[1]) + return + } + case strings.ToLower("IdleTimeout"): + if idleTimeout_int, err1 := strconv.Atoi(subItemList[1]); err1 != nil { + err = fmt.Errorf("%s转化为int型失败", subItemList[1]) + return + } else { + idleTimeout = time.Duration(idleTimeout_int) * time.Second + } + case strings.ToLower("DialConnectTimeout"): + if dialConectTimeout_int, err1 := strconv.Atoi(subItemList[1]); err1 != nil { + err = fmt.Errorf("%s转化为int型失败", subItemList[1]) + return + } else { + dialConectTimeout = time.Duration(dialConectTimeout_int) * time.Second + } + } + } + + redisConfig = NewRedisConfig2(connectionString, password, database, maxActive, maxIdle, idleTimeout, dialConectTimeout) + return +} + +func NewRedisConfig2(connectionString, password string, + database, maxActive, maxIdle int, + idleTimeout, dialConnectTimeout time.Duration) *RedisConfig { + + return &RedisConfig{ + ConnectionString: connectionString, + Password: password, + Database: database, + MaxActive: maxActive, + MaxIdle: maxIdle, + IdleTimeout: idleTimeout, + DialConnectTimeout: dialConnectTimeout, + } +} diff --git a/.svn/pristine/22/220fecaa6504067877bec738054b2ee97658da3d.svn-base b/.svn/pristine/22/220fecaa6504067877bec738054b2ee97658da3d.svn-base new file mode 100644 index 0000000..e7e19ee --- /dev/null +++ b/.svn/pristine/22/220fecaa6504067877bec738054b2ee97658da3d.svn-base @@ -0,0 +1,16 @@ +package mqMgr + +// 消息队列配置对象 +type QueueConfig struct { + // 地域 + Region string + + // 队列名称 + QueueName string + + // API密钥Id + SecretId string + + // API密钥key + SecretKey string +} diff --git a/.svn/pristine/23/2323503bd48538f9d2f8b36722a664b308762e83.svn-base b/.svn/pristine/23/2323503bd48538f9d2f8b36722a664b308762e83.svn-base new file mode 100644 index 0000000..b39c205 --- /dev/null +++ b/.svn/pristine/23/2323503bd48538f9d2f8b36722a664b308762e83.svn-base @@ -0,0 +1,16 @@ +package goroutineMgr + +/* +goroutine的管理包,提供了对goroutine的监控机制 +对外提供的方法为: + +// 监控指定的goroutine +Monitor(goroutineName string) + +// 只添加数量,不监控 +MonitorZero(goroutineName string) + +// 释放监控 +ReleaseMonitor(goroutineName string) + +*/ diff --git a/.svn/pristine/23/23cb9734e39cd278edd81f86a6b942d541ea2921.svn-base b/.svn/pristine/23/23cb9734e39cd278edd81f86a6b942d541ea2921.svn-base new file mode 100644 index 0000000..83a6660 --- /dev/null +++ b/.svn/pristine/23/23cb9734e39cd278edd81f86a6b942d541ea2921.svn-base @@ -0,0 +1,133 @@ +package handleMgr + +import ( + "fmt" + "reflect" + "testing" + "time" +) + +// ---------------申请示例实例-------------- +var ( + data = make(map[int]int, 0) +) + +type testBll struct { +} + +// TestAdd +// @description:测试添加 +// parameter: +// @receiver t: +// @x: +// @y: +// return: +// @*ResponseObject: +func (t testBll) TestAdd(x, y int) *ResponseObject { + responseObj := GetInitResponseObj() + data[x] = y + z := x + y + + print(x) + + responseObj.SetData(z) + responseObj.SetResultStatus(-11111, "错误码") + return responseObj +} + +// See1 +// @description:测试添加 +// parameter: +// @receiver t: +// @x: +// return: +// @*ResponseObject: +func (t testBll) See1(x int) *ResponseObject { + responseObj := GetInitResponseObj() + fmt.Print(x) + return responseObj +} + +// See2 +// @description:测试添加 +// parameter: +// @receiver t: +// @x: +// return: +// @*ResponseObject: +func (t testBll) See2(x int) *ResponseObject { + responseObj := GetInitResponseObj() + time.Sleep(2000 * time.Millisecond) + fmt.Print(x) + return responseObj +} + +func (t testBll) ReMove(x int) *ResponseObject { + responseObj := GetInitResponseObj() + delete(data, x) + return responseObj +} + +// ---------------测试方法-------------- +func TestNew(t *testing.T) { + + var paramItem interface{} + paramItem = 123 + paramFloat64, ok := paramItem.(int) + if ok { + x := reflect.ValueOf(int(paramFloat64)) + t.Log(x) + } + t.Log(paramFloat64) + t.Log(ok) + + //t.Log("A") + //RegisterNewModule("test", new(testBll), 10) + + //parameter := []interface{}{"1", 2} + //x, y, mes := Done("test", "testBll", "TestAdd", parameter, false) + //for key, item := range data { + // t.Log(key, item) + //} + + //t.Log("B2") + //parameter1 := []interface{}{2, 2} + //x, y, mes = Done("test", "testBll", "TestAdd", parameter1, true) + //for key, item := range data { + // t.Log(key, item) + //} + //t.Log(x) + //t.Log(y) + //t.Log(mes) + //t.Log("B3") + // + //t.Log("C") + //parameter2 := []interface{}{2} + //Done("test", "testBll", "ReMove", parameter2, true) + //for key, item := range data { + // t.Log(key, item) + //} + //t.Log("D") + // + //t.Log(time.Now().UnixMilli()) + //parameter3 := []interface{}{1} + //Done("test", "testBll", "See2", parameter3, false) + //t.Log(time.Now().UnixMilli()) + //parameter4 := []interface{}{2} + //Done("test", "testBll", "See1", parameter4, true) + //t.Log(time.Now().UnixMilli()) + //parameter5 := []interface{}{1} + //Done("test", "testBll", "See1", parameter5, true) + //t.Log(time.Now().UnixMilli()) + // + //t.Log("E") + // + //t.Log(time.Now().UnixMilli()) + //for i := 0; i < 1000; i++ { + // Done("test", "testBll", "See1", parameter5, true) + //} + //t.Log(time.Now().UnixMilli()) + //t.Log("F") + + t.Error("G") +} diff --git a/.svn/pristine/24/2408308d2e72184a45660ed9c67c714a06107c62.svn-base b/.svn/pristine/24/2408308d2e72184a45660ed9c67c714a06107c62.svn-base new file mode 100644 index 0000000..c73ae18 --- /dev/null +++ b/.svn/pristine/24/2408308d2e72184a45660ed9c67c714a06107c62.svn-base @@ -0,0 +1,109 @@ +package qcloud + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "time" + + "goutil/mathUtil" + "goutil/webUtil" +) + +const ( + VOICE_CAPTCHA_URL = "https://cloud.tim.qq.com/v5/tlsvoicesvr/sendcvoice" + VOICE_NOTIFICATION_URL = "https://cloud.tim.qq.com/v5/tlsvoicesvr/sendvoiceprompt" + VOICE_TEMPLATE_NOTIFICATION_URL = "https://cloud.tim.qq.com/v5/tlsvoicesvr/sendtvoice" +) + +// calculate sign-string for phone numbers +func calcSig(appKey string, rand int, timeStamp int64, mobile string) string { + sum := sha256.Sum256([]byte(fmt.Sprintf("appkey=%s&random=%d&time=%d&mobile=%s", appKey, rand, timeStamp, mobile))) + return hex.EncodeToString(sum[:]) +} + +// do the http request and parse the response +func request(url string, data map[string]interface{}, appId string, rand int) (success bool, err error) { + url = fmt.Sprintf("%s?sdkappid=%s&random=%d", url, appId, rand) + fmt.Printf("url:%s\n", url) + + contentBytes, err := json.Marshal(data) + if err != nil { + return + } + + fmt.Printf("data:%v\n", string(contentBytes)) + + _, retBytes, err := webUtil.PostByteData2(url, contentBytes, nil, nil) + if err != nil { + return + } + + var responseObj *response + err = json.Unmarshal(retBytes, &responseObj) + if err != nil { + return + } + if responseObj.Result != 0 { + err = fmt.Errorf(responseObj.ErrMsg) + return + } + + success = true + return +} + +func SendVoiceCaptcha(appId, appKey, nation, mobile, captcha string, playTimes int) (success bool, err error) { + rand := mathUtil.GetRand().GetRandRangeInt(100000, 999999) + timeStamp := time.Now().Unix() + + data := make(map[string]interface{}) + data["playtimes"] = playTimes + data["sig"] = calcSig(appKey, rand, timeStamp, mobile) + data["tel"] = newTelField(nation, mobile) + data["time"] = timeStamp + data["ext"] = "" + // dedicated param + data["msg"] = captcha + + success, err = request(VOICE_CAPTCHA_URL, data, appId, rand) + return +} + +func SendVoiceNotification(appId, appKey, nation, mobile, prompt string, playTimes int) (success bool, err error) { + rand := mathUtil.GetRand().GetRandRangeInt(100000, 999999) + timeStamp := time.Now().Unix() + promptType := 2 + + data := make(map[string]interface{}) + data["playtimes"] = playTimes + data["sig"] = calcSig(appKey, rand, timeStamp, mobile) + data["tel"] = newTelField(nation, mobile) + data["time"] = timeStamp + data["ext"] = "" + // dedicated param + data["promptfile"] = prompt + data["prompttype"] = promptType + + success, err = request(VOICE_NOTIFICATION_URL, data, appId, rand) + return +} + +func SendVoiceTemplateNotification(appId, appKey, nation, mobile string, templateId int, params []string, playTimes int) (success bool, err error) { + rand := mathUtil.GetRand().GetRandRangeInt(100000, 999999) + timeStamp := time.Now().Unix() + + data := make(map[string]interface{}) + data["playtimes"] = playTimes + data["sig"] = calcSig(appKey, rand, timeStamp, mobile) + data["tel"] = newTelField(nation, mobile) + data["time"] = timeStamp + data["ext"] = "" + // dedicated param + data["tpl_id"] = templateId + data["params"] = params + + success, err = request(VOICE_TEMPLATE_NOTIFICATION_URL, data, appId, rand) + return +} diff --git a/.svn/pristine/24/242c687d5a16af36ce250d440564fc2b747e6dd4.svn-base b/.svn/pristine/24/242c687d5a16af36ce250d440564fc2b747e6dd4.svn-base new file mode 100644 index 0000000..1f8c312 --- /dev/null +++ b/.svn/pristine/24/242c687d5a16af36ce250d440564fc2b747e6dd4.svn-base @@ -0,0 +1,79 @@ +package gameServerMgr + +import ( + "time" + + . "Framework/managecenterModel" + "goutil/timeUtil" + "goutil/typeUtil" +) + +var ( + mServerGroupObj *ServerGroup +) + +//解析服务器组信息 +func ParseServerGroupInfo(serverGroupObj *ServerGroup) { + mServerGroupObj = serverGroupObj +} + +//获取服务器组对象 +func GetServerGroup() (serverGroupObj *ServerGroup) { + serverGroupObj = mServerGroupObj + + return +} + +//检查服务器是否在维护 +func CheckMaintainStatus() (maintainMessage string, isMaintaining bool) { + serverGroupObj := GetServerGroup() + nowTick := time.Now().Unix() + if serverGroupObj.GroupState == int32(Con_GroupState_Maintain) || (serverGroupObj.MaintainBeginTimeTick <= nowTick && nowTick <= serverGroupObj.MaintainBeginTimeTick+int64(60*serverGroupObj.MaintainMinutes)) { + maintainMessage = serverGroupObj.MaintainMessage + isMaintaining = true + + return + } + + return +} + +//获取服务器维护开始时间时间戳 +func GetMaintainBeginTime() (maintainBeginTimeTick int64) { + serverGroupObj := GetServerGroup() + maintainBeginTimeTick = serverGroupObj.MaintainBeginTimeTick + + return +} + +//获取服务器维护持续时间 单位分钟 +func GetMaintainMinutes() (maintainMinutes int32) { + serverGroupObj := GetServerGroup() + maintainMinutes = serverGroupObj.MaintainMinutes + + return +} + +//获取服务器开服日期 时间戳 +func GetServerOpenDate() (openTimeTick int64) { + serverGroupObj := GetServerGroup() + openTimeTick = serverGroupObj.OpenTimeTick + + return +} + +//当前服务器已开服天数(开服第几天) +//当前开服天数 计算公式:(当前日期 - 开服日期)的总天数 + 1 +func ServerOpenDays() (days int32) { + serverGroupObj := GetServerGroup() + if serverGroupObj.IsOpen() == false { + return 0 + } + + //(当前日期 - 开服日期)的总天数 + 1 + openTimeTick := serverGroupObj.OpenTimeTick + openDate, _ := typeUtil.DateTime(openTimeTick) + days = int32(timeUtil.SubDay(time.Now(), openDate) + 1) + + return +} diff --git a/.svn/pristine/24/24d43d9907392c148b50ae48efa6d7f9e9746822.svn-base b/.svn/pristine/24/24d43d9907392c148b50ae48efa6d7f9e9746822.svn-base new file mode 100644 index 0000000..18cd929 --- /dev/null +++ b/.svn/pristine/24/24d43d9907392c148b50ae48efa6d7f9e9746822.svn-base @@ -0,0 +1,225 @@ +package syncUtil + +import ( + "context" + "fmt" + "sync" + "testing" + "time" +) + +func TestMutex(t *testing.T) { + mu := NewMutex() + mu.Lock() + defer mu.UnLock() + if mu.TryLock() { + t.Errorf("cannot fetch mutex !!!") + } +} + +func TestMutexTryLockTimeout(t *testing.T) { + fmt.Println("start") + mu := NewMutex() + mu.Lock() + go func() { + time.Sleep(20 * time.Second) + mu.UnLock() + }() + // if !mu.TryLockTimeout(500 * time.Microsecond) { + // t.Errorf("cannot fetch mutex in 500us !!!") + // } + if !mu.TryLockTimeout(15 * time.Second) { + t.Errorf("should fetch mutex in 5ms !!!") + } + mu.UnLock() +} + +func TestMutexUnlockTwice(t *testing.T) { + mu := NewMutex() + mu.Lock() + defer func() { + if x := recover(); x != nil { + if x != "unlock of unlocked mutex" { + t.Errorf("unexpect panic") + } + } else { + t.Errorf("should panic after unlock twice") + } + }() + mu.UnLock() + mu.UnLock() +} + +func TestMutexTryLockContext(t *testing.T) { + mu := NewMutex() + ctx, cancel := context.WithCancel(context.Background()) + mu.Lock() + go func() { + time.Sleep(10 * time.Millisecond) + cancel() + }() + if mu.TryLockContext(ctx) { + t.Errorf("cannot fetch mutex !!!") + } +} + +func BenchmarkMutex(b *testing.B) { + mu := NewMutex() + a := 0 + c := 0 + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + mu.Lock() + a++ + mu.UnLock() + mu.Lock() + c = a + mu.UnLock() + } + }) + _ = a + _ = c +} + +func TestMutexGroup(t *testing.T) { + mu := NewMutexGroup() + mu.Lock("g") + defer mu.UnLock("g") + if mu.TryLock("g") { + t.Errorf("cannot fetch mutex !!!") + } +} + +func TestMutexGroupMutliWaitLock(t *testing.T) { + var ( + wg sync.WaitGroup + mu = NewMutexGroup() + cn = 3 + ) + + for i := 0; i < cn; i++ { + wg.Add(1) + go func() { + mu.Lock("h") + time.Sleep(1e7) + mu.UnLock("h") + wg.Done() + }() + } + wg.Wait() + + for i := 0; i < cn; i++ { + wg.Add(1) + go func() { + mu.Lock("g") + time.Sleep(1e7) + mu.UnLockAndFree("g") + wg.Done() + }() + } + wg.Wait() +} + +func TestMutexGroupUnLockAndFree(t *testing.T) { + var ( + wg sync.WaitGroup + mu = NewMutexGroup() + mg = mu.(*mutexGroup) + ) + + for j := 1; j < 5; j++ { + for i := 0; i < j; i++ { + wg.Add(1) + go func() { + mu.Lock("h") + time.Sleep(1e6) + mu.UnLockAndFree("h") + wg.Done() + }() + } + wg.Wait() + mg.mu.Lock() + if _, ok := mg.group["h"]; ok { + t.Error("h mutex exist after UnLockAndFree") + } + mg.mu.Unlock() + } +} + +func TestMutexGroupTryLockFailedAndUnLockAndFree(t *testing.T) { + var ( + wg sync.WaitGroup + mu = NewMutexGroup() + mg = mu.(*mutexGroup) + ) + + for j := 1; j < 5; j++ { + for i := 0; i < j; i++ { + wg.Add(1) + go func() { + if mu.TryLock("h") { + time.Sleep(1e6) + mu.UnLockAndFree("h") + } + wg.Done() + }() + } + wg.Wait() + mg.mu.Lock() + if _, ok := mg.group["h"]; ok { + t.Error("h mutex exist after UnLockAndFree") + } + mg.mu.Unlock() + } +} + +func TestMutexGroupTryLockTimeout(t *testing.T) { + mu := NewMutexGroup() + mu.Lock("g") + go func() { + time.Sleep(1 * time.Millisecond) + mu.UnLock("g") + }() + if mu.TryLockTimeout("g", 500*time.Microsecond) { + t.Errorf("cannot fetch mutex in 500us !!!") + } + if !mu.TryLockTimeout("g", 5*time.Millisecond) { + t.Errorf("should fetch mutex in 5ms !!!") + } + mu.UnLock("g") +} + +func TestMutexGroupTryLockContext(t *testing.T) { + mu := NewMutexGroup() + ctx, cancel := context.WithCancel(context.Background()) + mu.Lock("g") + go func() { + time.Sleep(10 * time.Millisecond) + cancel() + }() + if mu.TryLockContext("g", ctx) { + t.Errorf("cannot fetch mutex !!!") + } +} + +func BenchmarkMutexGroup(b *testing.B) { + mu := NewMutexGroup() + a := 0 + c := 0 + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + mu.Lock("g") + a++ + mu.UnLock("g") + mu.Lock("g") + c = a + mu.UnLock("g") + } + }) + _ = a + _ = c +} diff --git a/.svn/pristine/25/253842466dd2f7a93da426d59d796617815b5714.svn-base b/.svn/pristine/25/253842466dd2f7a93da426d59d796617815b5714.svn-base new file mode 100644 index 0000000..19ce417 --- /dev/null +++ b/.svn/pristine/25/253842466dd2f7a93da426d59d796617815b5714.svn-base @@ -0,0 +1,1575 @@ +package redisUtil + +import ( + "testing" + "time" +) + +var ( + redisPoolObj_set *RedisPool +) + +func init() { + redisPoolObj_set = NewRedisPool("testPool", "10.1.0.21:6379", "redis_pwd", 5, 500, 200, 10*time.Second, 5*time.Second) +} + +func TestSAdd(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 添加单个元素 + + redis> SADD bbs "discuz.net" + (integer) 1 + */ + key := "bbs" + value := "discuz.net" + expected := 1 + got, err := redisPoolObj_set.SAdd(key, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + # 添加重复元素 + + redis> SADD bbs "discuz.net" + (integer) 0 + */ + expected = 0 + got, err = redisPoolObj_set.SAdd(key, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + /* + # 添加多个元素 + + redis> SADD bbs "tianya.cn" "groups.google.com" + (integer) 2 + */ + expected = 2 + got, err = redisPoolObj_set.SAdd(key, "tianya.cn", "groups.google.com") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + /* + redis> SMEMBERS bbs + 1) "discuz.net" + 2) "groups.google.com" + 3) "tianya.cn" + */ + expected2 := []string{"discuz.net", "groups.google.com", "tianya.cn"} + got2_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got2, err := redisPoolObj_set.Strings(got2_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected2, got2) == false { + t.Errorf("Expected to get %v, but got %v\n", expected2, got2) + return + } +} + +func TestSIsMember(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + key := "joe's_movies" + expected := 3 + got, err := redisPoolObj_set.SAdd(key, "hi, lady", "Fast Five", "2012") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> SMEMBERS joe's_movies + 1) "hi, lady" + 2) "Fast Five" + 3) "2012" + */ + expected2 := []string{"hi, lady", "Fast Five", "2012"} + got2_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got2, err := redisPoolObj_set.Strings(got2_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected2, got2) == false { + t.Errorf("Expected to get %v, but got %v\n", expected2, got2) + return + } + + /* + redis> SISMEMBER joe's_movies "bet man" + (integer) 0 + */ + expected3 := false + value := "bet man" + got3, err := redisPoolObj_set.SIsMember(key, value) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %t, but now got %t", expected3, got3) + return + } + + /* + redis> SISMEMBER joe's_movies "Fast Five" + (integer) 1 + */ + expected3 = true + value = "Fast Five" + got3, err = redisPoolObj_set.SIsMember(key, value) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %t, but now got %t", expected3, got3) + return + } + +} + +func TestSPop(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + key := "db" + expected := 3 + got, err := redisPoolObj_set.SAdd(key, "MySQL", "MongoDB", "Redis") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> SMEMBERS db + 1) "MySQL" + 2) "MongoDB" + 3) "Redis" + */ + expected2 := []string{"MySQL", "MongoDB", "Redis"} + got2_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got2, err := redisPoolObj_set.Strings(got2_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected2, got2) == false { + t.Errorf("Expected to get %v, but got %v\n", expected2, got2) + return + } + + /* + redis> SPOP db + "Redis" + + redis> SMEMBERS db + 1) "MySQL" + 2) "MongoDB" + */ + expected3 := make(map[string]struct{}) + for _, item := range expected2 { + expected3[item] = struct{}{} + } + got3_interface, err := redisPoolObj_set.SPop(key) + if err != nil { + t.Fail() + } + got3, err := redisPoolObj_set.String(got3_interface) + if err != nil { + t.Fail() + } + if _, exist := expected3[got3]; !exist { + t.Errorf("Expected to get one of key from %v, but now get %s.", expected3, got3) + return + } + delete(expected3, got3) + + expected4 := make([]string, 0, len(expected3)) + for k := range expected3 { + expected4 = append(expected4, k) + } + + got4_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SPOP db + "MySQL" + + redis> SMEMBERS db + 1) "MongoDB" + */ + + expected5 := make(map[string]struct{}) + for _, item := range expected4 { + expected5[item] = struct{}{} + } + got5_interface, err := redisPoolObj_set.SPop(key) + if err != nil { + t.Fail() + } + got5, err := redisPoolObj_set.String(got5_interface) + if err != nil { + t.Fail() + } + if _, exist := expected5[got5]; !exist { + t.Errorf("Expected to get one of key from %v, but now get %s.", expected5, got5) + return + } + delete(expected5, got5) + + expected6 := make([]string, 0, len(expected5)) + for k := range expected5 { + expected6 = append(expected6, k) + } + + got6_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got6, err := redisPoolObj_set.Strings(got6_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected6, got6) == false { + t.Errorf("Expected to get %v, but got %v\n", expected6, got6) + return + } +} + +func TestSRandMember(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 添加元素 + + redis> SADD fruit apple banana cherry + (integer) 3 + */ + key := "fruit" + expected := 3 + got, err := redisPoolObj_set.SAdd(key, "apple", "banana", "cherry") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + # 只给定 key 参数,返回一个随机元素 + + redis> SRANDMEMBER fruit + "cherry" + */ + expected2 := make(map[string]struct{}) + expected2["apple"] = struct{}{} + expected2["banana"] = struct{}{} + expected2["cherry"] = struct{}{} + + count := 1 + got2_interface, err := redisPoolObj_set.SRandMember(key, count) + if err != nil { + t.Fail() + } + got2_slice, err := redisPoolObj_set.Strings(got2_interface) + if err != nil { + t.Fail() + } + if len(got2_slice) != count { + t.Errorf("Expected to have %d items, but now get %d.", count, len(got2_slice)) + return + } + got2 := got2_slice[0] + if _, exist := expected2[got2]; !exist { + t.Errorf("Expected length %s, but got %s", expected2, got2) + return + } + + /* + # 给定 3 为 count 参数,返回 3 个随机元素 + # 每个随机元素都不相同 + + redis> SRANDMEMBER fruit 3 + 1) "apple" + 2) "banana" + 3) "cherry" + */ + count = 3 + expected3 := make([]string, 0, len(expected2)) + for k := range expected2 { + expected3 = append(expected3, k) + } + got3_interface, err := redisPoolObj_set.SRandMember(key, count) + if err != nil { + t.Fail() + } + got3_slice, err := redisPoolObj_set.Strings(got3_interface) + if err != nil { + t.Fail() + } + if len(got3_slice) != count { + t.Errorf("Expected to have %d items, but now get %d.", count, len(got3_slice)) + return + } + if isTwoUnorderedSliceEqual(expected3, got3_slice) == false { + t.Errorf("Expected to get %v, but got %v\n", expected3, got3_slice) + return + } + + /* + # 给定 -3 为 count 参数,返回 3 个随机元素 + # 元素可能会重复出现多次 + + redis> SRANDMEMBER fruit -3 + 1) "banana" + 2) "cherry" + 3) "apple" + + # 如果 count 是整数,且大于等于集合基数,那么返回整个集合 + + redis> SRANDMEMBER fruit 10 + 1) "apple" + 2) "banana" + 3) "cherry" + + # 如果 count 是负数,且 count 的绝对值大于集合的基数 + # 那么返回的数组的长度为 count 的绝对值 + + redis> SRANDMEMBER fruit -10 + 1) "banana" + 2) "apple" + 3) "banana" + 4) "cherry" + 5) "apple" + 6) "apple" + 7) "cherry" + 8) "apple" + 9) "apple" + 10) "banana" + + # SRANDMEMBER 并不会修改集合内容 + + redis> SMEMBERS fruit + 1) "apple" + 2) "cherry" + 3) "banana" + + # 集合为空时返回 nil 或者空数组 + + redis> SRANDMEMBER not-exists + (nil) + + redis> SRANDMEMBER not-eixsts 10 + (empty list or set) + */ +} + +func TestSRem(t *testing.T) { + deleteKeys := make([]string, 0, 8) + // defer func() { + // // Delete the test keys + // distinctKeyList := getDistinctKeyList(deleteKeys) + // count, err := redisPoolObj_list.Del(distinctKeyList...) + // if err != nil { + // t.Fail() + // } + // if count != len(distinctKeyList) { + // t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + // return + // } + // }() + + /* + # 添加元素 + + redis> SADD languages c lisp python ruby + (integer) 4 + */ + key := "languages" + expected := 4 + got, err := redisPoolObj_set.SAdd(key, "c", "lisp", "python", "ruby") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + # 测试数据 + + redis> SMEMBERS languages + 1) "c" + 2) "lisp" + 3) "python" + 4) "ruby" + */ + expected2 := make(map[string]struct{}) + expected2["c"] = struct{}{} + expected2["lisp"] = struct{}{} + expected2["python"] = struct{}{} + expected2["ruby"] = struct{}{} + + expected4 := make([]string, 0, len(expected2)) + for k := range expected2 { + expected4 = append(expected4, k) + } + + got4_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + # 移除单个元素 + + redis> SREM languages ruby + (integer) 1 + */ + value := "ruby" + expected5 := 1 + got5, err := redisPoolObj_set.SRem(key, value) + if err != nil { + t.Fail() + } + if got5 != expected5 { + t.Errorf("Expected length %d, but got %d", expected5, got5) + return + } + + /* + # 移除不存在元素 + + redis> SREM languages non-exists-language + (integer) 0 + */ + value = "non-exists-language" + expected6 := 0 + got6, err := redisPoolObj_set.SRem(key, value) + if err != nil { + t.Fail() + } + if got6 != expected6 { + t.Errorf("Expected length %d, but got %d", expected6, got6) + return + } + + /* + # 移除多个元素 + + redis> SREM languages lisp python c + (integer) 3 + + redis> SMEMBERS languages + (empty list or set) + */ + expected7 := 3 + got7, err := redisPoolObj_set.SRem(key, "c", "lisp", "python") + if err != nil { + t.Fail() + } + if got7 != expected7 { + t.Errorf("Expected length %d, but got %d", expected7, got7) + return + } + + expected8 := make([]string, 0) + got8_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got8, err := redisPoolObj_set.Strings(got8_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected8, got8) == false { + t.Errorf("Expected to get %v, but got %v\n", expected8, got8) + return + } +} + +func TestSMove(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 添加元素 + + redis> SADD languages c lisp python ruby + (integer) 4 + */ + source := "songs" + expected := 2 + got, err := redisPoolObj_set.SAdd(source, "Billie Jean", "Believe Me") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, source) + + /* + redis> SMEMBERS songs + 1) "Billie Jean" + 2) "Believe Me" + */ + expected2 := []string{"Billie Jean", "Believe Me"} + got2_interface, err := redisPoolObj_set.SMembers(source) + if err != nil { + t.Fail() + } + got2, err := redisPoolObj_set.Strings(got2_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected2, got2) == false { + t.Errorf("Expected to get %v, but got %v\n", expected2, got2) + return + } + + /* + redis> SMEMBERS my_songs + (empty list or set) + */ + destination := "my_songs" + expected3 := []string{} + got3_interface, err := redisPoolObj_set.SMembers(destination) + if err != nil { + t.Fail() + } + got3, err := redisPoolObj_set.Strings(got3_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected3, got3) == false { + t.Errorf("Expected to get %v, but got %v\n", expected3, got3) + return + } + + deleteKeys = append(deleteKeys, destination) + + /* + redis> SMOVE songs my_songs "Believe Me" + (integer) 1 + */ + value := "Believe Me" + expected4 := true + got4, err := redisPoolObj_set.SMove(source, destination, value) + if err != nil { + t.Fail() + } + if got4 != expected4 { + t.Errorf("Expected length %t, but got %t", expected4, got4) + return + } + + /* + redis> SMEMBERS songs + 1) "Billie Jean" + */ + expected5 := []string{"Billie Jean"} + got5_interface, err := redisPoolObj_set.SMembers(source) + if err != nil { + t.Fail() + } + got5, err := redisPoolObj_set.Strings(got5_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected5, got5) == false { + t.Errorf("Expected to get %v, but got %v\n", expected5, got5) + return + } + + /* + redis> SMEMBERS my_songs + 1) "Believe Me" + */ + expected6 := []string{"Believe Me"} + got6_interface, err := redisPoolObj_set.SMembers(destination) + if err != nil { + t.Fail() + } + got6, err := redisPoolObj_set.Strings(got6_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected6, got6) == false { + t.Errorf("Expected to get %v, but got %v\n", expected6, got6) + return + } +} + +func TestSCard(t *testing.T) { + /* + redis> SADD tool pc printer phone + (integer) 3 + */ + key := "tool" + expected := 3 + got, err := redisPoolObj_set.SAdd(key, "pc", "printer", "phone") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + /* + redis> SCARD tool # 非空集合 + (integer) 3 + */ + expected = 3 + got, err = redisPoolObj_set.SCard(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + /* + redis> DEL tool + (integer) 1 + */ + expected = 1 + got, err = redisPoolObj_set.Del(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + /* + redis> SCARD tool # 空集合 + (integer) 0 + */ + expected = 0 + got, err = redisPoolObj_set.SCard(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } +} + +func TestSMembers(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # key 不存在或集合为空 + + redis> EXISTS not_exists_key + (integer) 0 + */ + key := "not_exists_key" + expected := false + got, err := redisPoolObj_set.Exists(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t.", expected, got) + return + } + + /* + redis> SMEMBERS not_exists_key + (empty list or set) + */ + expected2 := make([]string, 0) + got2_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got2, err := redisPoolObj_set.Strings(got2_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected2, got2) == false { + t.Errorf("Expected to get %v, but got %v\n", expected2, got2) + return + } + + /* + # 非空集合 + + redis> SADD language Ruby Python Clojure + (integer) 3 + */ + key = "language" + expected3 := 3 + got3, err := redisPoolObj_set.SAdd(key, "Clojure", "Python", "Ruby") + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %d, but now got %d.", expected3, got3) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + redis> SMEMBERS language + 1) "Python" + 2) "Ruby" + 3) "Clojure" + */ + expected4 := []string{"Clojure", "Python", "Ruby"} + got4_interface, err := redisPoolObj_set.SMembers(key) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } +} + +func TestSInter(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + key1 := "group_1" + expected := 3 + got, err := redisPoolObj_set.SAdd(key1, "LI LEI", "TOM", "JACK") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key1) + + key2 := "group_2" + expected = 2 + got, err = redisPoolObj_set.SAdd(key2, "HAN MEIMEI", "JACK") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key2) + + /* + redis> SMEMBERS group_1 + 1) "LI LEI" + 2) "TOM" + 3) "JACK" + */ + expected4 := []string{"LI LEI", "TOM", "JACK"} + got4_interface, err := redisPoolObj_set.SMembers(key1) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SMEMBERS group_2 + 1) "HAN MEIMEI" + 2) "JACK" + */ + expected4 = []string{"HAN MEIMEI", "JACK"} + got4_interface, err = redisPoolObj_set.SMembers(key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SINTER group_1 group_2 + 1) "JACK" + */ + expected4 = []string{"JACK"} + got4_interface, err = redisPoolObj_set.SInter(key1, key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } +} + +func TestSInterStore(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> SMEMBERS songs + 1) "good bye joe" + 2) "hello,peter" + */ + key1 := "songs" + expected := 2 + got, err := redisPoolObj_set.SAdd(key1, "good bye joe", "hello,peter") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key1) + + expected4 := []string{"good bye joe", "hello,peter"} + got4_interface, err := redisPoolObj_set.SMembers(key1) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SMEMBERS my_songs + 1) "good bye joe" + 2) "falling" + */ + key2 := "my_songs" + expected = 2 + got, err = redisPoolObj_set.SAdd(key2, "good bye joe", "falling") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key2) + + expected4 = []string{"good bye joe", "falling"} + got4_interface, err = redisPoolObj_set.SMembers(key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SINTERSTORE song_interset songs my_songs + (integer) 1 + */ + destination := "song_interset" + expected2 := 1 + got2, err := redisPoolObj_set.SInterStore(destination, key1, key2) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d.", expected2, got2) + return + } + + deleteKeys = append(deleteKeys, destination) + + /* + redis> SMEMBERS song_interset + 1) "good bye joe" + */ + expected4 = []string{"good bye joe"} + got4_interface, err = redisPoolObj_set.SMembers(destination) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } +} + +func TestSUnion(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> SMEMBERS songs + 1) "Billie Jean" + */ + key1 := "songs" + expected := 1 + got, err := redisPoolObj_set.SAdd(key1, "Billie Jean") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key1) + + expected4 := []string{"Billie Jean"} + got4_interface, err := redisPoolObj_set.SMembers(key1) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SMEMBERS my_songs + 1) "Believe Me" + */ + key2 := "my_songs" + expected = 1 + got, err = redisPoolObj_set.SAdd(key2, "Believe Me") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key2) + + expected4 = []string{"Believe Me"} + got4_interface, err = redisPoolObj_set.SMembers(key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SUNION songs my_songs + 1) "Billie Jean" + 2) "Believe Me" + */ + expected4 = []string{"Billie Jean", "Believe Me"} + got4_interface, err = redisPoolObj_set.SUnion(key1, key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } +} + +func TestSUnionStore(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> SMEMBERS NoSQL + 1) "MongoDB" + 2) "Redis" + */ + key1 := "NoSQL" + expected := 2 + got, err := redisPoolObj_set.SAdd(key1, "MongoDB", "Redis") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key1) + + expected4 := []string{"MongoDB", "Redis"} + got4_interface, err := redisPoolObj_set.SMembers(key1) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SMEMBERS SQL + 1) "sqlite" + 2) "MySQL" + */ + key2 := "SQL" + expected = 2 + got, err = redisPoolObj_set.SAdd(key2, "sqlite", "MySQL") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key2) + + expected4 = []string{"sqlite", "MySQL"} + got4_interface, err = redisPoolObj_set.SMembers(key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SUNIONSTORE db NoSQL SQL + (integer) 4 + */ + destination := "db" + expected2 := 4 + got2, err := redisPoolObj_set.SUnionStore(destination, key1, key2) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d.", expected2, got2) + return + } + + deleteKeys = append(deleteKeys, destination) + + /* + redis> SMEMBERS db + 1) "MySQL" + 2) "sqlite" + 3) "MongoDB" + 4) "Redis" + */ + expected4 = []string{"MongoDB", "Redis", "sqlite", "MySQL"} + got4_interface, err = redisPoolObj_set.SMembers(destination) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } +} + +func TestSDiff(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> SMEMBERS peter's_movies + 1) "bet man" + 2) "start war" + 3) "2012" + */ + key1 := "peter's_movies" + expected := 3 + got, err := redisPoolObj_set.SAdd(key1, "bet man", "start war", "2012") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key1) + + expected4 := []string{"bet man", "start war", "2012"} + got4_interface, err := redisPoolObj_set.SMembers(key1) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SMEMBERS joe's_movies + 1) "hi, lady" + 2) "Fast Five" + 3) "2012" + */ + key2 := "joe's_movies" + expected = 3 + got, err = redisPoolObj_set.SAdd(key2, "hi, lady", "Fast Five", "2012") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key2) + + expected4 = []string{"hi, lady", "Fast Five", "2012"} + got4_interface, err = redisPoolObj_set.SMembers(key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SDIFF peter's_movies joe's_movies + 1) "bet man" + 2) "start war" + */ + expected4 = []string{"bet man", "start war"} + got4_interface, err = redisPoolObj_set.SDiff(key1, key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SDIFF joe's_movies peter's_movies + 1) "hi, lady" + 2) "Fast Five" + */ + expected4 = []string{"hi, lady", "Fast Five"} + got4_interface, err = redisPoolObj_set.SDiff(key2, key1) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } +} + +func TestSDiffStore(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> SMEMBERS peter's_movies + 1) "bet man" + 2) "start war" + 3) "2012" + */ + key1 := "peter's_movies" + expected := 3 + got, err := redisPoolObj_set.SAdd(key1, "bet man", "start war", "2012") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key1) + + expected4 := []string{"bet man", "start war", "2012"} + got4_interface, err := redisPoolObj_set.SMembers(key1) + if err != nil { + t.Fail() + } + got4, err := redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SMEMBERS joe's_movies + 1) "hi, lady" + 2) "Fast Five" + 3) "2012" + */ + key2 := "joe's_movies" + expected = 3 + got, err = redisPoolObj_set.SAdd(key2, "hi, lady", "Fast Five", "2012") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d.", expected, got) + return + } + + deleteKeys = append(deleteKeys, key2) + + expected4 = []string{"hi, lady", "Fast Five", "2012"} + got4_interface, err = redisPoolObj_set.SMembers(key2) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SDIFFSTORE joe_diff_peter joe's_movies peter's_movies + (integer) 2 + */ + destination := "joe_diff_peter" + expected2 := 2 + got2, err := redisPoolObj_set.SDiffStore(destination, key1, key2) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d.", expected2, got2) + return + } + + deleteKeys = append(deleteKeys, destination) + + /* + redis> SMEMBERS joe_diff_peter + 1) "bet man" + 2) "start war" + */ + expected4 = []string{"bet man", "start war"} + got4_interface, err = redisPoolObj_set.SMembers(destination) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } + + /* + redis> SDIFFSTORE peter_diff_joe peter's_movies, joe's_movies + (integer) 2 + */ + destination = "peter_diff_joe" + expected2 = 2 + got2, err = redisPoolObj_set.SDiffStore(destination, key2, key1) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d.", expected2, got2) + return + } + + deleteKeys = append(deleteKeys, destination) + + /* + redis> SMEMBERS joe_diff_peter + 1) "hi, lady" + 2) "Fast Five" + */ + expected4 = []string{"hi, lady", "Fast Five"} + got4_interface, err = redisPoolObj_set.SMembers(destination) + if err != nil { + t.Fail() + } + got4, err = redisPoolObj_set.Strings(got4_interface) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected4, got4) == false { + t.Errorf("Expected to get %v, but got %v\n", expected4, got4) + return + } +} diff --git a/.svn/pristine/25/25b8521c8aada772e1f6465d18604e289c9e5489.svn-base b/.svn/pristine/25/25b8521c8aada772e1f6465d18604e289c9e5489.svn-base new file mode 100644 index 0000000..bf5a8fb --- /dev/null +++ b/.svn/pristine/25/25b8521c8aada772e1f6465d18604e289c9e5489.svn-base @@ -0,0 +1,378 @@ +/* +未实现的列表方法: +BLPOP、BRPOP、BRPOPLPUSH +*/ +package redisUtil + +import ( + "github.com/gomodule/redigo/redis" +) + +/* +LPUSH key value [value …] +可用版本: >= 1.0.0 +时间复杂度: O(1) +将一个或多个值 value 插入到列表 key 的表头 + +如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头: 比如说,对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。 + +如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。 + +当 key 存在但不是列表类型时,返回一个错误。 + +Note + +在Redis 2.4版本以前的 LPUSH 命令,都只接受单个 value 值。 + +返回值 +执行 LPUSH 命令后,列表的长度。 +*/ +func (this *RedisPool) LPush(key string, values ...interface{}) (length int, err error) { + conn := this.GetConnection() + defer conn.Close() + + length, err = redis.Int(conn.Do("LPUSH", redis.Args{}.Add(key).AddFlat(values)...)) + return +} + +/* +LPUSHX key value +可用版本: >= 2.2.0 +时间复杂度: O(1) +将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。 + +和 LPUSH key value [value …] 命令相反,当 key 不存在时, LPUSHX 命令什么也不做。 + +返回值 +LPUSHX 命令执行之后,表的长度。 +*/ +func (this *RedisPool) LPushX(key string, values ...interface{}) (length int, err error) { + conn := this.GetConnection() + defer conn.Close() + + length, err = redis.Int(conn.Do("LPUSHX", redis.Args{}.Add(key).AddFlat(values)...)) + return +} + +/* +RPUSH key value [value …] +可用版本: >= 1.0.0 +时间复杂度: O(1) +将一个或多个值 value 插入到列表 key 的表尾(最右边)。 + +如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。 + +如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。 + +当 key 存在但不是列表类型时,返回一个错误。 + +Note + +在 Redis 2.4 版本以前的 RPUSH 命令,都只接受单个 value 值。 + +返回值 +执行 RPUSH 操作后,表的长度。 +*/ +func (this *RedisPool) RPush(key string, values ...interface{}) (length int, err error) { + conn := this.GetConnection() + defer conn.Close() + + length, err = redis.Int(conn.Do("RPUSH", redis.Args{}.Add(key).AddFlat(values)...)) + return +} + +/* +RPUSHX key value +可用版本: >= 2.2.0 +时间复杂度: O(1) +将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。 + +和 RPUSH key value [value …] 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。 + +返回值 +RPUSHX 命令执行之后,表的长度。 +*/ +func (this *RedisPool) RPushX(key string, values ...interface{}) (length int, err error) { + conn := this.GetConnection() + defer conn.Close() + + length, err = redis.Int(conn.Do("RPUSHX", redis.Args{}.Add(key).AddFlat(values)...)) + return +} + +/* +LPOP key +可用版本: >= 1.0.0 +时间复杂度: O(1) +移除并返回列表 key 的头元素。 + +返回值 +列表的头元素。 当 key 不存在时,返回 nil 。 +*/ +func (this *RedisPool) LPop(key string) (item interface{}, exist bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + item, err = conn.Do("LPOP", key) + if err != nil { + return + } + if item == nil { + return + } + + exist = true + + return +} + +/* +RPOP key +可用版本: >= 1.0.0 +时间复杂度: O(1) +移除并返回列表 key 的尾元素。 + +返回值 +列表的尾元素。 当 key 不存在时,返回 nil 。 +*/ +func (this *RedisPool) RPop(key string) (item interface{}, exist bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + item, err = conn.Do("RPOP", key) + if err != nil { + return + } + if item == nil { + return + } + + exist = true + + return +} + +/* +RPOPLPUSH source destination +可用版本: >= 1.2.0 +时间复杂度: O(1) +命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作: + +将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。 + +将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。 + +举个例子,你有两个列表 source 和 destination , source 列表有元素 a, b, c , destination 列表有元素 x, y, z ,执行 RPOPLPUSH source destination 之后, source 列表包含元素 a, b , destination 列表包含元素 c, x, y, z ,并且元素 c 会被返回给客户端。 + +如果 source 不存在,值 nil 被返回,并且不执行其他动作。 + +如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。 + +返回值 +被弹出的元素。 +*/ +func (this *RedisPool) RPopLPush(source, destination string) (item interface{}, err error) { + conn := this.GetConnection() + defer conn.Close() + + item, err = conn.Do("RPOPLPUSH", source, destination) + if err != nil { + return + } + + return +} + +/* +LREM key count value +可用版本: >= 1.0.0 +时间复杂度: O(N), N 为列表的长度。 +根据参数 count 的值,移除列表中与参数 value 相等的元素。 + +count 的值可以是以下几种: + +count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。 + +count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。 + +count = 0 : 移除表中所有与 value 相等的值。 + +返回值 +被移除元素的数量。 因为不存在的 key 被视作空表(empty list),所以当 key 不存在时, LREM 命令总是返回 0 。 +*/ +// 错误对象 +func (this *RedisPool) LRem(key string, count int, value string) (removeCount int, err error) { + conn := this.GetConnection() + defer conn.Close() + + removeCount, err = redis.Int(conn.Do("LREM", key, count, value)) + return +} + +/* +LLEN key +可用版本: >= 1.0.0 +时间复杂度: O(1) +返回列表 key 的长度。 + +如果 key 不存在,则 key 被解释为一个空列表,返回 0 . + +如果 key 不是列表类型,返回一个错误。 + +返回值 +列表 key 的长度。 +*/ +func (this *RedisPool) LLen(key string) (length int, err error) { + conn := this.GetConnection() + defer conn.Close() + + length, err = redis.Int(conn.Do("LLEN", key)) + return +} + +/* +LINDEX key index +可用版本: >= 1.0.0 +时间复杂度:O(N), N 为到达下标 index 过程中经过的元素数量。因此,对列表的头元素和尾元素执行 LINDEX 命令,复杂度为O(1)。 +返回列表 key 中,下标为 index 的元素。 + +下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 + +你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 + +如果 key 不是列表类型,返回一个错误。 + +返回值 +列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range),返回 nil 。 +*/ +func (this *RedisPool) LIndex(key string, index int) (item interface{}, exist bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + item, err = conn.Do("LINDEX", key, index) + if err != nil { + return + } + if item == nil { + return + } + + exist = true + return +} + +/* +LINSERT key BEFORE|AFTER pivot value +可用版本: >= 2.2.0 +时间复杂度: O(N), N 为寻找 pivot 过程中经过的元素数量。 +将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。 + +当 pivot 不存在于列表 key 时,不执行任何操作。 + +当 key 不存在时, key 被视为空列表,不执行任何操作。 + +如果 key 不是列表类型,返回一个错误。 + +返回值 +如果命令执行成功,返回插入操作完成之后,列表的长度。 如果没有找到 pivot ,返回 -1 。 如果 key 不存在或为空列表,返回 0 。 +*/ +func (this *RedisPool) LInsert(key, beforeOrAfter string, pivot, value interface{}) (length int, err error) { + conn := this.GetConnection() + defer conn.Close() + + length, err = redis.Int(conn.Do("LINSERT", key, beforeOrAfter, pivot, value)) + return +} + +/* +LSET key index value +可用版本: >= 1.0.0 +时间复杂度:对头元素或尾元素进行 LSET 操作,复杂度为 O(1)。其他情况下,为 O(N), N 为列表的长度。 +将列表 key 下标为 index 的元素的值设置为 value 。 + +当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。 + +关于列表下标的更多信息,请参考 LINDEX key index 命令。 + +返回值 +操作成功返回 ok ,否则返回错误信息。 +*/ +func (this *RedisPool) LSet(key string, index int, value interface{}) (err error) { + conn := this.GetConnection() + defer conn.Close() + + _, err = conn.Do("LSet", key, index, value) + return +} + +/* +LRANGE key start stop +可用版本: >= 1.0.0 +时间复杂度: O(S+N), S 为偏移量 start , N 为指定区间内元素的数量。 +返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。 + +下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 + +你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 + +注意LRANGE命令和编程语言区间函数的区别 +假如你有一个包含一百个元素的列表,对该列表执行 LRANGE list 0 10 ,结果是一个包含11个元素的列表,这表明 stop 下标也在 LRANGE 命令的取值范围之内(闭区间),这和某些语言的区间函数可能不一致,比如Ruby的 Range.new 、 Array#slice 和Python的 range() 函数。 + +超出范围的下标 +超出范围的下标值不会引起错误。 + +如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大,那么 LRANGE 返回一个空列表。 + +如果 stop 下标比 end 下标还要大,Redis将 stop 的值设置为 end 。 + +返回值 +一个列表,包含指定区间内的元素。 +*/ +func (this *RedisPool) LRange(key string, start, stop int) (reply interface{}, err error) { + conn := this.GetConnection() + defer conn.Close() + + reply, err = conn.Do("LRANGE", key, start, stop) + return +} + +/* +LTRIM key start stop +可用版本: >= 1.0.0 +时间复杂度: O(N), N 为被移除的元素的数量。 +对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 + +举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。 + +下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 + +你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 + +当 key 不是列表类型时,返回一个错误。 + +LTRIM 命令通常和 LPUSH key value [value …] 命令或 RPUSH key value [value …] 命令配合使用,举个例子: + +LPUSH log newest_log +LTRIM log 0 99 +这个例子模拟了一个日志程序,每次将最新日志 newest_log 放到 log 列表中,并且只保留最新的 100 项。注意当这样使用 LTRIM 命令时,时间复杂度是O(1),因为平均情况下,每次只有一个元素被移除。 + +注意LTRIM命令和编程语言区间函数的区别 +假如你有一个包含一百个元素的列表 list ,对该列表执行 LTRIM list 0 10 ,结果是一个包含11个元素的列表,这表明 stop 下标也在 LTRIM 命令的取值范围之内(闭区间),这和某些语言的区间函数可能不一致,比如Ruby的 Range.new 、 Array#slice 和Python的 range() 函数。 + +超出范围的下标 +超出范围的下标值不会引起错误。 + +如果 start 下标比列表的最大下标 end ( LLEN list 减去 1 )还要大,或者 start > stop , LTRIM 返回一个空列表(因为 LTRIM 已经将整个列表清空)。 + +如果 stop 下标比 end 下标还要大,Redis将 stop 的值设置为 end 。 + +返回值 +命令执行成功时,返回 ok 。 +*/ +func (this *RedisPool) LTrim(key string, start, stop int) (err error) { + conn := this.GetConnection() + defer conn.Close() + + _, err = conn.Do("LTRIM", key, start, stop) + return +} diff --git a/.svn/pristine/25/25fe816e9e9fd164ec610c7921a8639c1dcbfb15.svn-base b/.svn/pristine/25/25fe816e9e9fd164ec610c7921a8639c1dcbfb15.svn-base new file mode 100644 index 0000000..c469ac4 --- /dev/null +++ b/.svn/pristine/25/25fe816e9e9fd164ec610c7921a8639c1dcbfb15.svn-base @@ -0,0 +1,131 @@ +package gameServerMgr + +import ( + "encoding/json" + "fmt" + "strings" + + . "Framework/managecenterModel" + "goutil/logUtil" + "goutil/securityUtil" + "goutil/webUtil" +) + +// 登陆助手类 +type LoginUtil struct{} + +// 验证登陆信息 +// partnerId:合作商Id +// userId:合作商用户Id +// loginInfo:登陆信息 +// isIntranet:是否是内网:true,内网;false:外网 +// 返回值: +// 成功与否 +// 错误对象 +func (this *LoginUtil) CheckLoginInfo(partnerId int32, userId, loginInfo string, isIntranet bool) (success bool, err error) { + // 验证用户合法性 + loginItemList := strings.Split(loginInfo, "_") + if len(loginItemList) != 2 { + err = fmt.Errorf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s", partnerId, userId, loginInfo) + return + } + + //将requestUrl地址进行拆分 + requestDomainList := strings.Split(loginItemList[1], ";") + + //请求的主域名 + requestDomain := "" + if isIntranet || len(requestDomainList) == 1 { + requestDomain = requestDomainList[0] + } else { + requestDomain = requestDomainList[1] + } + + //构造请求url + requestUrl := fmt.Sprintf("http://%s/API/CheckDynamicLoginKey.ashx", requestDomain) + + // 定义请求参数 + postDict := make(map[string]string) + postDict["UserId"] = userId + postDict["LoginKey"] = loginItemList[0] + + //请求url,请求头 + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, 30) + + statusCode, returnBytes, err1 := webUtil.PostMapData(requestUrl, postDict, header, transport) + if err1 != nil { + err = fmt.Errorf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s, err:%s", partnerId, userId, loginInfo, err1) + return + } + if statusCode != 200 { + err = fmt.Errorf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s, statusCode:%d", partnerId, userId, loginInfo, statusCode) + return + } + + // 解析返回值 + returnObj := new(ReturnObject) + if err = json.Unmarshal(returnBytes, &returnObj); err != nil { + err = fmt.Errorf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s, err:%s", partnerId, userId, loginInfo, err) + return + } + + // 判断返回状态是否为成功 + if returnObj.Code != 0 { + logUtil.ErrorLog(fmt.Sprintf("CheckLoginInfo Failed. partnerId:%d, userId:%s, loginInfo:%s, Code:%d, Message:%s", partnerId, userId, loginInfo, returnObj.Code, returnObj.Message)) + return + } + + success = true + + return +} + +// 本地验证登陆信息 +// partnerId:合作商Id +// userId:合作商用户Id +// loginInfo:登陆信息 +// 返回值: +// 成功与否 +// 错误对象 +func CheckDynamicTokenLocal(partnerId int32, userId, loginInfo string) (success bool, err error) { + //1001直接返回true + if partnerId == 1001 { + return true, nil + } + + //非1001渠道验证 + if len(loginInfo) == 0 { + success = false + err = fmt.Errorf("Err:%s", "LoginInfo is null!") + return + } + // 验证用户合法性 + loginItemList := strings.Split(loginInfo, "_") + if len(loginItemList) != 2 { + success = false + err = fmt.Errorf("CheckLoginInfo Failed. userId:%s, loginInfo:%s", userId, loginInfo) + return + } + + //生成key + localSign := securityUtil.Md5String(userId+GetSysConfig().DynamicLoginKey+loginItemList[1], true) + + //判断签名是佛正确 + if localSign != loginItemList[0] { + success = false + err = fmt.Errorf("CheckLoginInfo Failed. Sign Check Failed! userId:%s,LocalSign:%s,loginInfo:%s", userId, localSign, loginInfo) + return + } + + success = true + return +} + +// ------------------类型定义和业务逻辑的分隔符------------------------- + +var ( + LoginUtilObj = new(LoginUtil) +) diff --git a/.svn/pristine/26/26022c8a11741f20169313a7438cfe711b0ee295.svn-base b/.svn/pristine/26/26022c8a11741f20169313a7438cfe711b0ee295.svn-base new file mode 100644 index 0000000..d5f7c76 --- /dev/null +++ b/.svn/pristine/26/26022c8a11741f20169313a7438cfe711b0ee295.svn-base @@ -0,0 +1,112 @@ +package webServer + +import ( + "net/http" + + "common/resultStatus" +) + +// 处理函数 +type HandleFunc func(context *ApiContext) *ResponseObject + +// ApiHandler +// +// @description: API处理结构 +type ApiHandler struct { + // API完整路径名称 + apiFullName string + + // 方法定义 + handleFun HandleFunc + + // 方法参数名称集合 + funcParamNames []string +} + +// ApiFullName +// +// @description: API完整路径名称 +// +// parameter: +// +// @receiver this: this +// +// return: +// +// @string: +func (this *ApiHandler) ApiFullName() string { + return this.apiFullName +} + +// HandleFun +// +// @description: 方法定义 +// +// parameter: +// +// @receiver this: this +// +// return: +// +// @HandleFunc: 方法 +func (this *ApiHandler) HandleFun() HandleFunc { + return this.handleFun +} + +// FuncParamNames +// +// @description: 方法参数名称集合 +// +// parameter: +// +// @receiver this: this +// +// return: +// +// @[]string: 方法参数名称集合 +func (this *ApiHandler) FuncParamNames() []string { + return this.funcParamNames +} + +// CheckParam +// +// @description: 检测参数数量 +// +// parameter: +// +// @receiver this: this +// @r: +// +// return: +// +// @resultStatus.ResultStatus: 状态码数据 +func (this *ApiHandler) CheckParam(r *http.Request) resultStatus.ResultStatus { + for _, name := range this.funcParamNames { + if r.Form[name] == nil || len(r.Form[name]) == 0 { + return resultStatus.APIParamError + } + } + + return resultStatus.Success +} + +// newApiHandler +// +// @description: 创建新的请求方法对象 +// +// parameter: +// +// @_apiFullName: API完整路径名称 +// @_funcDefinition: 方法定义 +// @_funcParamNames: 方法参数名称集合 +// +// return: +// +// @*ApiHandler: 请求方法对象 +func newApiHandler(_apiFullName string, _funcDefinition HandleFunc, _funcParamNames ...string) *ApiHandler { + return &ApiHandler{ + apiFullName: _apiFullName, + handleFun: _funcDefinition, + funcParamNames: _funcParamNames, + } +} diff --git a/.svn/pristine/26/2621e7b98a6ac756be9f2d95dd9e284ddb2338b4.svn-base b/.svn/pristine/26/2621e7b98a6ac756be9f2d95dd9e284ddb2338b4.svn-base new file mode 100644 index 0000000..7604d4a --- /dev/null +++ b/.svn/pristine/26/2621e7b98a6ac756be9f2d95dd9e284ddb2338b4.svn-base @@ -0,0 +1,17 @@ +module Framework + +go 1.22.2 + +replace goutil => ../goutil + +require ( + github.com/Shopify/sarama v1.29.1 + github.com/go-sql-driver/mysql v1.5.0 + github.com/gorilla/websocket v1.4.2 + github.com/jinzhu/gorm v1.9.12 + github.com/rabbitmq/amqp091-go v1.8.1 + github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.230 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vms v1.0.230 + goutil v0.0.0-00010101000000-000000000000 +) diff --git a/.svn/pristine/26/262ac8472b6314d517f3a9c48c61c54f3b4d315d.svn-base b/.svn/pristine/26/262ac8472b6314d517f3a9c48c61c54f3b4d315d.svn-base new file mode 100644 index 0000000..5079912 --- /dev/null +++ b/.svn/pristine/26/262ac8472b6314d517f3a9c48c61c54f3b4d315d.svn-base @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.svn/pristine/26/264f287a04ade2aafd862fcba87d65aa33d2dfa4.svn-base b/.svn/pristine/26/264f287a04ade2aafd862fcba87d65aa33d2dfa4.svn-base new file mode 100644 index 0000000..afc3ba7 --- /dev/null +++ b/.svn/pristine/26/264f287a04ade2aafd862fcba87d65aa33d2dfa4.svn-base @@ -0,0 +1,130 @@ +package notify_util + +import ( + "fmt" + + "Framework/goroutineMgr" + "goutil/logUtil" + "goutil/syncUtil" +) + +const ( + deathLockTime = 0 +) + +// notifyCenter +// @description: 玩家信息务逻辑类 +type notifyCenter struct { + // key:初始化成功的标志名称 val:占位符 + registerMap map[string]func() + mutex *syncUtil.RWLocker +} + +// newNotifyCenter +// @description: 构造对象 +// parameter: +// return: +// @*notifyCenter: +func newNotifyCenter() *notifyCenter { + return ¬ifyCenter{ + registerMap: make(map[string]func()), + mutex: syncUtil.NewRWLocker(), + } +} + +// register +// @description: 注册需要被通知的对象 +// parameter: +// @receiver nc: +// @chanName:唯一标识 +// @cf:回调方法 +// return: +func (nc *notifyCenter) register(chanName string, cf func()) { + if isOk, prevStack, currStack := nc.mutex.Lock(deathLockTime); isOk == false { + //记日志 + errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s \n当前堆栈:\n%s", prevStack, currStack) + panic(errMsg) + } + defer nc.mutex.Unlock() + if _, exists := nc.registerMap[chanName]; exists { + panic(fmt.Errorf("registerMap.Register-%s已经存在,请检查", chanName)) + } + + nc.registerMap[chanName] = cf +} + +// @description: 取消启动成功通知注册 +// parameter: +// @receiver nc: +// @name:唯一标识 +// return: +func (nc *notifyCenter) unregister(name string) { + if isOk, prevStack, currStack := nc.mutex.Lock(deathLockTime); isOk == false { + //记日志 + errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s \n当前堆栈:\n%s", prevStack, currStack) + panic(errMsg) + } + defer nc.mutex.Unlock() + + delete(nc.registerMap, name) +} + +// notify +// @description: 通知所有已注册的对象 +// parameter: +// @receiver nc: +// return: +func (nc *notifyCenter) notify() { + // 处理goroutine数量 + goroutineName := "notifyCenter.Notify" + goroutineMgr.MonitorZero(goroutineName) + defer goroutineMgr.ReleaseMonitor(goroutineName) + + if isOk, prevStack, currStack := nc.mutex.RLock(deathLockTime); isOk == false { + //记日志 + errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s \n当前堆栈:\n%s", prevStack, currStack) + panic(errMsg) + } + defer nc.mutex.RUnlock() + + for name, cf := range nc.registerMap { + cf() + msg := fmt.Sprintf("通知:%s初始化成功", name) + logUtil.DebugLog(msg) + } +} + +// notify2 +// @description: 通知所有已注册的对象,该方法会在捕获第一个err的时候停止后续的通知。多用于系统启动的判定 +// parameter: +// @receiver nc: +// return: +// @error: +func (nc *notifyCenter) notify2() (err error) { + // 处理goroutine数量 + goroutineName := "notifyCenter.Notify" + goroutineMgr.MonitorZero(goroutineName) + defer goroutineMgr.ReleaseMonitor(goroutineName) + + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("notify2 err:%s", r) + logUtil.ErrorLog(err.Error()) + } + }() + + if isOk, prevStack, currStack := nc.mutex.RLock(deathLockTime); isOk == false { + //记日志 + errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s \n当前堆栈:\n%s", prevStack, currStack) + panic(errMsg) + } + defer nc.mutex.RUnlock() + + for name, cf := range nc.registerMap { + cf() + msg := fmt.Sprintf("通知:%s初始化成功", name) + logUtil.DebugLog(msg) + } + + return +} diff --git a/.svn/pristine/26/26fd4cb975dbbbc57bf60a2d6c23dd8242dce9b2.svn-base b/.svn/pristine/26/26fd4cb975dbbbc57bf60a2d6c23dd8242dce9b2.svn-base new file mode 100644 index 0000000..f264a26 --- /dev/null +++ b/.svn/pristine/26/26fd4cb975dbbbc57bf60a2d6c23dd8242dce9b2.svn-base @@ -0,0 +1,57 @@ +package timeUtil + +import ( + "testing" + "time" +) + +func TestConverToStandardFormat(t *testing.T) { + str := "2018-10-10T10:10:10" + expected := time.Date(2018, 10, 10, 10, 10, 10, 0, time.Local) + + got, err := ConverToStandardFormat(str) + if err != nil { + t.Errorf("发生错误,错误信息为:%s", err) + } + + if got != expected { + t.Errorf("转换不正确,期待:%s, 实际:%s", expected, got) + } +} + +func TestConvertToInt(t *testing.T) { + date := time.Date(2018, 10, 10, 10, 10, 10, 0, time.Local) + finalInt := ConvertToInt(date) + expecteInt := 20181010 + + if finalInt != expecteInt { + t.Errorf("转换不正确,期待:%d, 实际:%d", expecteInt, finalInt) + } +} + +func TestSubDay(t *testing.T) { + time1 := time.Now().AddDate(0, 0, 5) + time2 := time.Now() + expected := 5 + + got := SubDay(time1, time2) + if got != expected { + t.Errorf("Expected %d, but now got %d.", expected, got) + } +} + +func TestParseTimeString(t *testing.T) { + val := "12:13:14" + expectedHour := 12 + expectedMinute := 13 + expectedSecond := 14 + + err, hour, miniute, second := ParseTimeString(val) + if err != nil { + t.Error(err) + } + + if expectedHour != hour || expectedMinute != miniute || expectedSecond != second { + t.Fail() + } +} diff --git a/.svn/pristine/28/281351a336934c29f0bf81f0e3cfb3ba03e237b0.svn-base b/.svn/pristine/28/281351a336934c29f0bf81f0e3cfb3ba03e237b0.svn-base new file mode 100644 index 0000000..b835d9e --- /dev/null +++ b/.svn/pristine/28/281351a336934c29f0bf81f0e3cfb3ba03e237b0.svn-base @@ -0,0 +1,6 @@ +package internal + +import ( + _ "logincenter/internal/game" + _ "logincenter/internal/user" +) diff --git a/.svn/pristine/28/2872d3f11847c786465856bc05af9651a484188c.svn-base b/.svn/pristine/28/2872d3f11847c786465856bc05af9651a484188c.svn-base new file mode 100644 index 0000000..ebc34cb --- /dev/null +++ b/.svn/pristine/28/2872d3f11847c786465856bc05af9651a484188c.svn-base @@ -0,0 +1,71 @@ +package websocketUtil + +import ( + "errors" + "fmt" + "sync" +) + +var ( + wsmap sync.Map + errLog func(format string, args ...interface{}) + debugLog func(format string, args ...interface{}) +) + +// SetLog +// @Description:设置日志回调函数信息 +// @param errLogFun 错误日志回调函数 +// @param debugLogFun debug日志回调函数 +func SetLog(errLogFun, debugLogFun func(format string, args ...interface{})) { + errLog = errLogFun + debugLog = debugLogFun +} + +// Send +// @Description: 发送数据 +// @param wsurl 发送地址 +// @param st 发送类型,使用websocket下的定义 +// @param data 发送数据 +// @return error +func Send(wsurl string, st int, data []byte) error { + if debugLog == nil || errLog == nil { + return errors.New("websocketUtil未设置errLog,debugLog回调函数,请调用websocketUtil.Setlog函数设置相关信息") + } + + m, err := getOrAdd(wsurl) + if err != nil { + errLog(fmt.Sprintf("websocketUtil.Send error:%s", err)) + return err + } + + m.send(st, data) + + return nil +} + +// getOrAdd +// @Description:获取或者添加对象 +// @param url string +// @return *model +// @return error +func getOrAdd(url string) (*model, error) { + var m *model + var err error + + v, isOk := wsmap.Load(url) + if isOk { + m = v.(*model) + return m, nil + } + + // 不存在,创建对应的socket连接 + m, err = newModel(url) + if err != nil { + return nil, err + } + + // 保存到map + wsmap.Store(url, m) + + return m, err +} diff --git a/.svn/pristine/28/28f055a2b9e8a852f03d50095156e421917e10b3.svn-base b/.svn/pristine/28/28f055a2b9e8a852f03d50095156e421917e10b3.svn-base new file mode 100644 index 0000000..d3ae5d2 --- /dev/null +++ b/.svn/pristine/28/28f055a2b9e8a852f03d50095156e421917e10b3.svn-base @@ -0,0 +1,75 @@ +package goroutineMgr + +import ( + "fmt" + "runtime" + "sync" + + "framework/monitorNewMgr" + "goutil/logUtil" +) + +var ( + goroutineInfoMap map[string]int = make(map[string]int) + goroutineInfoMutex sync.RWMutex + goroutineWarnCount int = 50 +) + +func init() { + monitorNewMgr.RegisterMonitorFunc(monitor) +} + +// 设置系统协程上报阈值 +func SetGoroutineWarnCount(warnCount int) { + goroutineWarnCount = warnCount +} + +func registerGoroutineInfo(goroutineName string, count int) { + goroutineInfoMutex.Lock() + defer goroutineInfoMutex.Unlock() + + goroutineInfoMap[goroutineName] = count +} + +// 监控指定的goroutine +func Monitor(goroutineName string) { + increaseCount(goroutineName) + registerGoroutineInfo(goroutineName, 1) +} + +// 只添加数量,不监控 +func MonitorZero(goroutineName string) { + increaseCount(goroutineName) +} + +// 释放监控 +func ReleaseMonitor(goroutineName string) { + if r := recover(); r != nil { + logUtil.LogUnknownError(r) + } + + decreaseCount(goroutineName) +} + +func monitor() error { + // 判断当前goroutine数量是否达到打印条件(数量查过设置的值就打印) + if goroutineWarnCount >= runtime.NumGoroutine() { + return nil + } + /* + 先记录活跃的goroutine的数量信息 + 然后再判断数量是否匹配 + */ + logGoroutineCountInfo() + + goroutineInfoMutex.RLock() + defer goroutineInfoMutex.RUnlock() + + for goroutineName, expectedCount := range goroutineInfoMap { + if currCount := getGoroutineCount(goroutineName); currCount != expectedCount { + return fmt.Errorf("%s需要%d个goroutine,现在有%d个", goroutineName, expectedCount, currCount) + } + } + + return nil +} diff --git a/.svn/pristine/2a/2a4adce6fe53177181f083b4ac4b0cd9fba5b1fe.svn-base b/.svn/pristine/2a/2a4adce6fe53177181f083b4ac4b0cd9fba5b1fe.svn-base new file mode 100644 index 0000000..eb3d5c4 --- /dev/null +++ b/.svn/pristine/2a/2a4adce6fe53177181f083b4ac4b0cd9fba5b1fe.svn-base @@ -0,0 +1,18 @@ +package monitorNewMgr + +//历史监控信息 +type MonitorHistory struct { + //监控信息 + MonitorMessage string + + //时间戳 + Timestamp int64 +} + +//new一个监控历史信息 +func newMonitorHistory(monitorMessage string, timestamp int64) *MonitorHistory { + return &MonitorHistory{ + MonitorMessage: monitorMessage, + Timestamp: timestamp, + } +} diff --git a/.svn/pristine/2a/2a53f94905747f4fa5f73ac48126d3788f20ea2b.svn-base b/.svn/pristine/2a/2a53f94905747f4fa5f73ac48126d3788f20ea2b.svn-base new file mode 100644 index 0000000..5977d2a --- /dev/null +++ b/.svn/pristine/2a/2a53f94905747f4fa5f73ac48126d3788f20ea2b.svn-base @@ -0,0 +1,343 @@ +package rank_util + +import ( + "sync" +) + +// RankUtil +// @description:排行工具类 +type RankUtil struct { + // maxCount 排行榜最大数量 + maxCount int + + // compar 对比函数 返回含义 -1:ab + compar func(a, b interface{}) int + + // dataList 排行数据 + dataList []*Model + + // dataDict 数据字典 + dataDict map[string]*Model + + // dataLock 数据锁 + dataLock sync.RWMutex +} + +// NewRankUtil +// @description: 构造排行对象 +// parameter: +// @mc:最大容量 +// @comp:元素比对方法 +// return: +func NewRankUtil(mc int, comp func(a, b interface{}) int) *RankUtil { + result := &RankUtil{ + maxCount: mc, + compar: comp, + dataList: make([]*Model, 0, mc), + dataDict: make(map[string]*Model, mc), + } + + return result +} + +// GetMaxCount +// @description: 获取排行榜最大数量 +// parameter: +// @receiver r: +// return: +// @int: +func (r *RankUtil) GetMaxCount() int { + return r.maxCount +} + +// GetCount +// @description: 获取排行榜当前数量 +// parameter: +// @receiver r: +// return: +// @int: +func (r *RankUtil) GetCount() int { + r.dataLock.RLock() + defer r.dataLock.RUnlock() + + return len(r.dataList) +} + +// IsFull +// @description: 判断排行榜是否已经满了 +// parameter: +// @receiver r: +// return: +// @bool: +func (r *RankUtil) IsFull() bool { + r.dataLock.RLock() + defer r.dataLock.RUnlock() + + return len(r.dataList) == r.maxCount +} + +// GetAll +// @description: 获取排行榜内容 +// parameter: +// @receiver r: +// return: +// @[]*Model: +func (r *RankUtil) GetAll() []*Model { + r.dataLock.RLock() + defer r.dataLock.RUnlock() + + result := make([]*Model, 0, len(r.dataList)) + for _, item := range r.dataList { + if item == nil || item.obj == nil { + break + } + + result = append(result, item) + } + + return result +} + +// GetRankListBySkip +// @description: 获取排行榜内容 +// parameter: +// @receiver r: +// @skip:跳过的数量 +// @count:跳过后需要返回的数量 +// return: +// @[]*Model: +func (r *RankUtil) GetRankListBySkip(skip, count int) []*Model { + r.dataLock.RLock() + defer r.dataLock.RUnlock() + + result := make([]*Model, 0, count) + cn := len(r.dataList) + if skip >= cn { + return result + } + + for i := 0; i < count; i++ { + item := r.dataList[skip+i] + if item == nil || item.obj == nil { + break + } + + result = append(result, item) + } + + return result +} + +// GetItemForK +// @description: 根据key获取对象 +// parameter: +// @receiver r: +// @k:key +// return: +// @*Model: +func (r *RankUtil) GetItemForK(k string) *Model { + r.dataLock.RLock() + defer r.dataLock.RUnlock() + + item, _ := r.dataDict[k] + + return item +} + +// GetItemForRank +// @description: 根据排名获取对应对象 +// parameter: +// @receiver r: +// @rank:排名 +// return: +// @*Model: +func (r *RankUtil) GetItemForRank(rank int) *Model { + r.dataLock.RLock() + defer r.dataLock.RUnlock() + + if len(r.dataList) < rank { + return nil + } + + return r.dataList[rank-1] +} + +// Refresh +// @description: 刷新排行榜 +// parameter: +// @receiver r: +// @k:key +// @o:排行持有的对象,业务层不应该持有该对象。否则业务层更改内容,会导致排行榜内容被改变 +// @isup:变动是否升高 +// return: +// @changeRank:排行是否变动 +// @dm:如果有对象,因为排行变动导致掉出排行榜,则返回该对象,否则返回nil +func (r *RankUtil) Refresh(k string, o interface{}, isup bool) (changeRank bool, dm *Model) { + r.dataLock.Lock() + defer r.dataLock.Unlock() + + changeRank = false + curItem, exists := r.dataDict[k] + if isup { + if !exists { + newRank := len(r.dataList) + 1 + curItem = &Model{rank: newRank, key: k, obj: o} + // 排行榜未满,必定入榜,则先加入排行榜 + if newRank <= r.maxCount { + r.dataList = append(r.dataList, curItem) + r.dataDict[curItem.key] = curItem + changeRank = true + _, dm = r.upRank(curItem) + } else { + changeRank, dm = r.upRank(curItem) + } + } else { + curItem.obj = o + changeRank, dm = r.upRank(curItem) + } + } else { + // 如果在排行榜内,从之前往下比较 + if exists { + curItem.obj = o + changeRank = r.downRank(curItem) + } else { + // 如果不在排行榜内,直接结束 + } + } + + return +} + +// Delete +// @description: 删除k指定的对象,很耗性能,不建议高频使用 +// parameter: +// @receiver r: +// @k:key +// return: +// @bool:true:代表key存在排行榜中,并且删除成功 false:其他情况 +func (r *RankUtil) Delete(k string) bool { + r.dataLock.Lock() + defer r.dataLock.Unlock() + + m, exists := r.dataDict[k] + if !exists { + return false + } + + //从当前位置向后移动,到最后的时候,删除 + for { + if m.rank >= len(r.dataList) { + break + } + + am := r.dataList[m.rank] + r.exchange(m, am) + m = am + } + + //最后一个应该是要删除的对象 + r.dataList = append(r.dataList[:m.rank-1:r.maxCount], r.dataList[m.rank:]...) + delete(r.dataDict, k) + + return true +} + +// upRank +// @description: 排行升高 +// parameter: +// @receiver r: +// @curItem:当前对象 +// return: +// @changeRank:排行是否变动 +// @dm:因排行变动被移除排行的对象 +func (r *RankUtil) upRank(curItem *Model) (changeRank bool, dm *Model) { + changeRank = false + for { + // rank=1,排在第一位,下标为0,故这里需要-2为上一位的下标 + beforeIndex := curItem.rank - 2 + if beforeIndex < 0 { + break + } + + beforeItem := r.dataList[beforeIndex] + if r.compar(curItem.obj, beforeItem.obj) <= 0 { + break + } + + // 交换操作 + tdm := r.exchange(curItem, beforeItem) + if tdm != nil { + dm = tdm + } + + curItem = beforeItem + changeRank = true + } + + return +} + +// downRank +// @description: 排行降低 +// parameter: +// @receiver r: +// @curItem:当前对象 +// return: +// @bool: +func (r *RankUtil) downRank(curItem *Model) bool { + changeRank := false + + for { + // rank=1,排在第一位,下标为0,需要对比rank=2的,下标为1,故这里直接取rank即可 + afterIndex := curItem.rank + if afterIndex >= len(r.dataList) { + break + } + + afterItem := r.dataList[afterIndex] + if r.compar(afterItem.obj, curItem.obj) <= 0 { + break + } + + // 交换操作 + r.exchange(curItem, afterItem) + + curItem = afterItem + changeRank = true + } + + return changeRank +} + +// exchange +// @description: 排行对象交换 +// parameter: +// @receiver r: +// @a:对象a +// @b:对象b +// return: +// @delRank:因交换被移除排行榜的对象 +func (r *RankUtil) exchange(a, b *Model) (dm *Model) { + tempObj := a.obj + tempKey := a.key + + a.obj = b.obj + a.key = b.key + b.obj = tempObj + b.key = tempKey + + if a.rank > r.maxCount { + delete(r.dataDict, a.key) + dm = a + } else { + r.dataDict[a.key] = a + } + if b.rank > r.maxCount { + delete(r.dataDict, b.key) + dm = b + } else { + r.dataDict[b.key] = b + } + + return +} diff --git a/.svn/pristine/2a/2a56a5647a58e684f5d5c35587c678482c56dc2d.svn-base b/.svn/pristine/2a/2a56a5647a58e684f5d5c35587c678482c56dc2d.svn-base new file mode 100644 index 0000000..160dfa8 --- /dev/null +++ b/.svn/pristine/2a/2a56a5647a58e684f5d5c35587c678482c56dc2d.svn-base @@ -0,0 +1,32 @@ +package verifyMgr + +import ( + "fmt" + "testing" + + "Framework/managecenterMgr" +) + +func init() { + manageCenterDataSwitchObj := &managecenterMgr.ManageCenterDataSwitch{ + AllDataSwitch: true, + } + managecenterMgr.Start("https://managecentertest-fzxh.public.com", manageCenterDataSwitchObj) +} + +func TestVerify(t *testing.T) { + if errList := Verify(); len(errList) > 0 { + t.Errorf("there should be no error, but now has") + for _, err := range errList { + fmt.Println(err) + } + } + + Init("http://www.baidu.com", Con_Get) + if errList := Verify(); len(errList) > 0 { + t.Errorf("there should be no error, but now has") + for _, err := range errList { + fmt.Println(err) + } + } +} diff --git a/.svn/pristine/2a/2a62442565a8992159b26fd4bcb62dd98d3f8e35.svn-base b/.svn/pristine/2a/2a62442565a8992159b26fd4bcb62dd98d3f8e35.svn-base new file mode 100644 index 0000000..c07a12b --- /dev/null +++ b/.svn/pristine/2a/2a62442565a8992159b26fd4bcb62dd98d3f8e35.svn-base @@ -0,0 +1,14 @@ +package yamlUtil + +import ( + "fmt" + "goutil/jsonUtil" + "testing" +) + +func TestLoadYaml(t *testing.T) { + config, _ := LoadFromFile("config.yaml") + configStr, _ := jsonUtil.DeepClone(config) + + fmt.Print(configStr) +} diff --git a/.svn/pristine/2b/2ba46d976f1f72118d5726c9a45ee3c678037629.svn-base b/.svn/pristine/2b/2ba46d976f1f72118d5726c9a45ee3c678037629.svn-base new file mode 100644 index 0000000..88ad604 --- /dev/null +++ b/.svn/pristine/2b/2ba46d976f1f72118d5726c9a45ee3c678037629.svn-base @@ -0,0 +1,295 @@ +package build + +import ( + "fmt" + "reflect" + "strconv" + + "goutil/xmlUtil/gxpath/internal/query" +) + +// valueType is a return value type. +type valueType int + +const ( + booleanType valueType = iota + numberType + stringType + nodeSetType +) + +func getValueType(i interface{}) valueType { + v := reflect.ValueOf(i) + switch v.Kind() { + case reflect.Float64: + return numberType + case reflect.String: + return stringType + case reflect.Bool: + return booleanType + default: + if _, ok := i.(query.Query); ok { + return nodeSetType + } + } + panic(fmt.Errorf("xpath unknown value type: %v", v.Kind())) +} + +type logical func(query.Iterator, string, interface{}, interface{}) bool + +var logicalFuncs = [][]logical{ + []logical{cmpBoolean_Boolean, nil, nil, nil}, + []logical{nil, cmpNumeric_Numeric, cmpNumeric_String, cmpNumeric_NodeSet}, + []logical{nil, cmpString_Numeric, cmpString_String, cmpString_NodeSet}, + []logical{nil, cmpNodeSet_Numeric, cmpNodeSet_String, cmpNodeSet_NodeSet}, +} + +// number vs number +func cmpNumberNumberF(op string, a, b float64) bool { + switch op { + case "=": + return a == b + case ">": + return a > b + case "<": + return a < b + case ">=": + return a >= b + case "<=": + return a <= b + case "!=": + return a != b + } + return false +} + +// string vs string +func cmpStringStringF(op string, a, b string) bool { + switch op { + case "=": + return a == b + case ">": + return a > b + case "<": + return a < b + case ">=": + return a >= b + case "<=": + return a <= b + case "!=": + return a != b + } + return false +} + +func cmpBooleanBooleanF(op string, a, b bool) bool { + switch op { + case "or": + return a || b + case "and": + return a && b + } + return false +} + +func cmpNumeric_Numeric(t query.Iterator, op string, m, n interface{}) bool { + a := m.(float64) + b := n.(float64) + return cmpNumberNumberF(op, a, b) +} + +func cmpNumeric_String(t query.Iterator, op string, m, n interface{}) bool { + a := m.(float64) + b := n.(string) + num, err := strconv.ParseFloat(b, 64) + if err != nil { + panic(err) + } + return cmpNumberNumberF(op, a, num) +} + +func cmpNumeric_NodeSet(t query.Iterator, op string, m, n interface{}) bool { + a := m.(float64) + b := n.(query.Query) + + for { + node := b.Select(t) + if node == nil { + break + } + num, err := strconv.ParseFloat(node.Value(), 64) + if err != nil { + panic(err) + } + if cmpNumberNumberF(op, a, num) { + return true + } + } + return false +} + +func cmpNodeSet_Numeric(t query.Iterator, op string, m, n interface{}) bool { + a := m.(query.Query) + b := n.(float64) + for { + node := a.Select(t) + if node == nil { + break + } + num, err := strconv.ParseFloat(node.Value(), 64) + if err != nil { + panic(err) + } + if cmpNumberNumberF(op, num, b) { + return true + } + } + return false +} + +func cmpNodeSet_String(t query.Iterator, op string, m, n interface{}) bool { + a := m.(query.Query) + b := n.(string) + for { + node := a.Select(t) + if node == nil { + break + } + if cmpStringStringF(op, b, node.Value()) { + return true + } + } + return false +} + +func cmpNodeSet_NodeSet(t query.Iterator, op string, m, n interface{}) bool { + return false +} + +func cmpString_Numeric(t query.Iterator, op string, m, n interface{}) bool { + a := m.(string) + b := n.(float64) + num, err := strconv.ParseFloat(a, 64) + if err != nil { + panic(err) + } + return cmpNumberNumberF(op, b, num) +} + +func cmpString_String(t query.Iterator, op string, m, n interface{}) bool { + a := m.(string) + b := n.(string) + return cmpStringStringF(op, a, b) +} + +func cmpString_NodeSet(t query.Iterator, op string, m, n interface{}) bool { + a := m.(string) + b := n.(query.Query) + for { + node := b.Select(t) + if node == nil { + break + } + if cmpStringStringF(op, a, node.Value()) { + return true + } + } + return false +} + +func cmpBoolean_Boolean(t query.Iterator, op string, m, n interface{}) bool { + a := m.(bool) + b := n.(bool) + return cmpBooleanBooleanF(op, a, b) +} + +// eqFunc is an `=` operator. +func eqFunc(t query.Iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "=", m, n) +} + +// gtFunc is an `>` operator. +func gtFunc(t query.Iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, ">", m, n) +} + +// geFunc is an `>=` operator. +func geFunc(t query.Iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, ">=", m, n) +} + +// ltFunc is an `<` operator. +func ltFunc(t query.Iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "<", m, n) +} + +// leFunc is an `<=` operator. +func leFunc(t query.Iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "<=", m, n) +} + +// neFunc is an `!=` operator. +func neFunc(t query.Iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "!=", m, n) +} + +// orFunc is an `or` operator. +var orFunc = func(t query.Iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "or", m, n) +} + +func numericExpr(m, n interface{}, cb func(float64, float64) float64) float64 { + typ := reflect.TypeOf(float64(0)) + a := reflect.ValueOf(m).Convert(typ) + b := reflect.ValueOf(n).Convert(typ) + return cb(a.Float(), b.Float()) +} + +// plusFunc is an `+` operator. +var plusFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return a + b + }) +} + +// minusFunc is an `-` operator. +var minusFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return a - b + }) +} + +// mulFunc is an `*` operator. +var mulFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return a * b + }) +} + +// divFunc is an `DIV` operator. +var divFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return a / b + }) +} + +// modFunc is an 'MOD' operator. +var modFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return float64(int(a) % int(b)) + }) +} diff --git a/.svn/pristine/2c/2c280202647fe7e9eb22c3f13cd5afd8135b0dab.svn-base b/.svn/pristine/2c/2c280202647fe7e9eb22c3f13cd5afd8135b0dab.svn-base new file mode 100644 index 0000000..b33943c --- /dev/null +++ b/.svn/pristine/2c/2c280202647fe7e9eb22c3f13cd5afd8135b0dab.svn-base @@ -0,0 +1,91 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 h1:OoL469zqSNrTLSz5zeVF/I6VOO7fiw2bzSzQe4J557c= +github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4/go.mod h1:xe9a/L2aeOgFKKgrO3ibQTnMdpAeL0GC+5/HpGScSa4= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= +github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= +github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= +github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/.svn/pristine/2c/2c42831a7794d3b03ba2af46e7a5709253508107.svn-base b/.svn/pristine/2c/2c42831a7794d3b03ba2af46e7a5709253508107.svn-base new file mode 100644 index 0000000..f03bf19 --- /dev/null +++ b/.svn/pristine/2c/2c42831a7794d3b03ba2af46e7a5709253508107.svn-base @@ -0,0 +1,78 @@ +package jsonUtil + +import ( + "encoding/json" + "strings" +) + +// 使用Number类型来反序列化字符串 +// 当被序列化为interface{}类型时,如果int型的长度大于7,则会被使用科学计数法进行表示 +// 当反序列化时,会无法转换为int类型,会导致错误 +// 所以需要使用Number类型 +// s:输入字符串 +// 返回值: +// 反序列化后的数据 +// 错误对象 +func UnMarshalWithNumberType(s string) (interface{}, error) { + // 构造decode对象 + var decode = json.NewDecoder(strings.NewReader(s)) + decode.UseNumber() + + // decode + var result interface{} + if err := decode.Decode(&result); err != nil { + return nil, err + } + + return result, nil +} + +// 深拷贝对象 +// src:源数据 +// 返回值: +// 新对象 +// 错误对象 +func DeepClone(src interface{}) (interface{}, error) { + var byteSlice []byte + var err error + + // 先序列化为[]byte + if byteSlice, err = json.Marshal(src); err != nil { + return nil, err + } + + // 再反序列化成对象 + var result interface{} + if err := json.Unmarshal(byteSlice, &result); err != nil { + return nil, err + } + + return result, nil +} + +// 使用Number类型来深拷贝对象 +// src:源数据 +// 返回值: +// 新对象 +// 错误对象 +func DeepCloneWithNumberType(src interface{}) (interface{}, error) { + var byteSlice []byte + var err error + + // 先序列化为[]byte + if byteSlice, err = json.Marshal(src); err != nil { + return nil, err + } + + // 构造decode对象 + var decode = json.NewDecoder(strings.NewReader(string(byteSlice))) + decode.UseNumber() + + // decode + var result interface{} + if err := decode.Decode(&result); err != nil { + return nil, err + } + + return result, nil +} diff --git a/.svn/pristine/2d/2de0a01a0fa2a5a57e9f7e655eb3d363f14c41be.svn-base b/.svn/pristine/2d/2de0a01a0fa2a5a57e9f7e655eb3d363f14c41be.svn-base new file mode 100644 index 0000000..b47db9a --- /dev/null +++ b/.svn/pristine/2d/2de0a01a0fa2a5a57e9f7e655eb3d363f14c41be.svn-base @@ -0,0 +1,6 @@ +package exitMgr + +// 程序退出包,提供程序退出时的功能 +// 使用方法: +// 1、先调用RegisterExitFunc方法,将系统退出时需要调用的方法进行注册。 +// 2、在程序退出时调用Exit()方法 diff --git a/.svn/pristine/2d/2de12c2ba27e67d1efdfc163a25f3b7bd611f8a6.svn-base b/.svn/pristine/2d/2de12c2ba27e67d1efdfc163a25f3b7bd611f8a6.svn-base new file mode 100644 index 0000000..8410351 --- /dev/null +++ b/.svn/pristine/2d/2de12c2ba27e67d1efdfc163a25f3b7bd611f8a6.svn-base @@ -0,0 +1,57 @@ +package logUtil + +import ( + "goutil/logUtil/impl-localfile" +) + +// 定义一个全局的日志对象 +var ( + // 日志列表 + logs []ILog + + // 文件log + fileLog *impl_localfile.Logger +) + +func init() { + // 提供默认的日志对象 + fileLog = impl_localfile.NewLogger() + logs = append(logs, fileLog) +} + +// AddLogger +// @description: 添加日志对象 +// parameter: +// +// @l:日志实现 +// +// return: +func SettingLogs(_logs []ILog) { + if _logs == nil || len(_logs) == 0 { + panic("_logs不能为nil或者len(_logs)==0") + } + + logs = _logs +} + +// GetLocalFileLog +// @description: 获取文件日志对象 +// parameter: +// return: +// +// @*log_localfile.Logger: +func GetLocalFileLog() *impl_localfile.Logger { + return fileLog +} + +// SetLogPath +// @description: 设置文件日志路径 +// parameter: +// +// @_logPath:路径 +// +// return: +// Deprecated: use GetLocalFileLog().SetLogPath(_logPath) api instead +func SetLogPath(_logPath string) { + fileLog.SetLogPath(_logPath) +} diff --git a/.svn/pristine/2e/2e2532365bcd2cea0e001934e67db11e0fea1405.svn-base b/.svn/pristine/2e/2e2532365bcd2cea0e001934e67db11e0fea1405.svn-base new file mode 100644 index 0000000..dc86fb1 --- /dev/null +++ b/.svn/pristine/2e/2e2532365bcd2cea0e001934e67db11e0fea1405.svn-base @@ -0,0 +1,78 @@ +package stringUtil + +import ( + "fmt" + "testing" +) + +func TestSplit(t *testing.T) { + s := "1,2;3|4||5,6;7|8||9," + // seps := []string{",", ";", "|", "||"} + retList := Split(s, nil) + if retList[0] != "1" || retList[1] != "2" || retList[2] != "3" || retList[3] != "4" || retList[4] != "5" || retList[5] != "6" || retList[6] != "7" || retList[7] != "8" || retList[8] != "9" { + t.Errorf("ecptected:123456789, but now got:%v", retList) + } +} + +func TestSplitToIntSlice(t *testing.T) { + s := "1, 2, 3, 4, 5, a" + if _, err := SplitToIntSlice(s, ","); err == nil { + t.Errorf("Expected got err, but got nil") + } + + s = "1, 5, 39," + if intSlice, err := SplitToIntSlice(s, ","); err != nil { + t.Errorf("Expected got nil, but got error:%s", err) + } else { + // fmt.Printf("intSlice:%v\n", intSlice) + if intSlice[0] != 1 || intSlice[1] != 5 || intSlice[2] != 39 { + t.Errorf("Expected got %s, but got %v", s, intSlice) + } + } +} + +func TestSplitToIntRegion(t *testing.T) { + idRegionStr := "" + outerSep := "," + innerSep := "-" + var err error + + if _, err = SplitToIntRegion(idRegionStr, outerSep, innerSep); err == nil { + t.Errorf("PraseIdRegion should failed, but now not.err:%s", err) + } + + idRegionStr = "," + if _, err = SplitToIntRegion(idRegionStr, outerSep, innerSep); err == nil { + t.Errorf("PraseIdRegion should failed, but now not.err:%s", err) + } + + idRegionStr = "1-100,101,200" + if _, err = SplitToIntRegion(idRegionStr, outerSep, innerSep); err == nil { + t.Errorf("PraseIdRegion should failed, but now not.err:%s", err) + } + + idRegionStr = "1-100,101-20" + if _, err = SplitToIntRegion(idRegionStr, outerSep, innerSep); err == nil { + t.Errorf("PraseIdRegion should failed, but now not.err:%s", err) + } + + idRegionStr = "1-100,101-200" + if idRegionList, err := SplitToIntRegion(idRegionStr, outerSep, innerSep); err != nil { + t.Errorf("PraseIdRegion should succeed, but now failed.err:%s", err) + } else { + if idRegionList[0].Lower != 1 || idRegionList[0].Upper != 100 || + idRegionList[1].Lower != 101 || idRegionList[1].Upper != 200 { + t.Errorf("SplitToIntRegion should succeed, but now failed. idRegionStr:%s, idRegionList:%v", idRegionStr, idRegionList) + } + } +} + +func TestSplitToFloat64(t *testing.T) { + result, err := SplitToFloat64Slice("1.11,2.22", ",") + if err != nil { + t.Error(err) + return + } + + fmt.Printf("%v\n", result) +} diff --git a/.svn/pristine/2e/2e766b25919f4eac85c32fd101e5bd303ef1190c.svn-base b/.svn/pristine/2e/2e766b25919f4eac85c32fd101e5bd303ef1190c.svn-base new file mode 100644 index 0000000..a3b48b2 --- /dev/null +++ b/.svn/pristine/2e/2e766b25919f4eac85c32fd101e5bd303ef1190c.svn-base @@ -0,0 +1,4 @@ +/* +数据类型转换类(主要针对interface) +*/ +package typeUtil diff --git a/.svn/pristine/2e/2e8e3f2c21083bfc1741db5df016b198b53ae6ad.svn-base b/.svn/pristine/2e/2e8e3f2c21083bfc1741db5df016b198b53ae6ad.svn-base new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.svn/pristine/2e/2e8e3f2c21083bfc1741db5df016b198b53ae6ad.svn-base @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.svn/pristine/2e/2eb9ec388af8b1eec3c306160021488411784adb.svn-base b/.svn/pristine/2e/2eb9ec388af8b1eec3c306160021488411784adb.svn-base new file mode 100644 index 0000000..5b6a313 --- /dev/null +++ b/.svn/pristine/2e/2eb9ec388af8b1eec3c306160021488411784adb.svn-base @@ -0,0 +1,54 @@ +package fileUtil + +import ( + "fmt" + "testing" +) + +func TestGzip(t *testing.T) { + path := GetCurrentPath() + fmt.Printf("CurrPath:%s\n", path) + + fileName := fmt.Sprintf("%s/%s", path, "test.txt") + if err := WriteFile(path, "test.txt", true, "first line\nHello world"); err != nil { + t.Errorf("there should be no error, but now it is:%s", err) + } + + if err := Gzip(fileName, ""); err != nil { + // if err := Gzip(fileName, path); err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } + + if fileList, err := GetFileList(path); err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } else { + for _, item := range fileList { + fmt.Printf("item:%s\n", item) + } + } + + DeleteFile(fileName) +} + +func TestUnGzip(t *testing.T) { + path := GetCurrentPath() + fmt.Printf("CurrPath:%s\n", path) + + fileName := fmt.Sprintf("%s/%s", path, "test.txt.gz") + if err := UnGzip(fileName, ""); err != nil { + // if err := UnGzip(fileName, path); err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } + + content, err := ReadFileContent(fmt.Sprintf("%s/%s", path, "test.txt")) + if err != nil { + t.Errorf("There should be no error, but now it has:%s", err) + } else { + fmt.Printf("content:%s\n", content) + } + + DeleteFile(fileName) + + fileName = fmt.Sprintf("%s/%s", path, "test.txt") + DeleteFile(fileName) +} diff --git a/.svn/pristine/2e/2ebc67fa9c1257d723c197f604ecb9c540c228fd.svn-base b/.svn/pristine/2e/2ebc67fa9c1257d723c197f604ecb9c540c228fd.svn-base new file mode 100644 index 0000000..b82cb50 --- /dev/null +++ b/.svn/pristine/2e/2ebc67fa9c1257d723c197f604ecb9c540c228fd.svn-base @@ -0,0 +1,313 @@ +package webUtil + +import ( + "bytes" + "crypto/tls" + "io/ioutil" + "net/http" + "net/url" +) + +func GetFormHeader() map[string]string { + return map[string]string{"Content-Type": "application/x-www-form-urlencoded"} +} + +func GetJsonHeader() map[string]string { + return map[string]string{"Content-Type": "application/json;charset=UTF-8"} +} + +// POST数据 +// weburl:远程服务器地址 +// data:post的数据集合 +// header:包头集合 +// 返回值: +// 返回的字节 +// 错误对象 +func PostWebData(weburl string, data map[string]string, header map[string]string) (result []byte, err error) { + // 组装POST数据 + postValues := url.Values{} + for key, value := range data { + postValues.Set(key, value) + } + postDataStr := postValues.Encode() + byteData := []byte(postDataStr) + + // 调用发送Byte数组的方法 + result, err = PostByteData(weburl, byteData, header) + + return +} + +// POST Byte数组 +// weburl:远程服务器地址 +// data:post的Byte数组 +// header:包头集合 +// 返回值: +// 返回的字节 +// 错误对象 +func PostByteData(weburl string, data []byte, header map[string]string) (result []byte, err error) { + // 组装POST数据 + reader := bytes.NewReader(data) + + // 构造请求对象 + var request *http.Request + request, err = http.NewRequest("POST", weburl, reader) + if err != nil { + return + } + + // 处理头部(包括默认头部,以及传入的头部集合) + if header == nil { + for k, v := range GetFormHeader() { + request.Header.Add(k, v) + } + } else { + for k, v := range header { + request.Header.Add(k, v) + } + } + + // 构造transport对象 + transport := NewTransport() + transport.DisableKeepAlives = true + + transport = GetTimeoutTransport(transport, 30) + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + // 构造httpClient对象 + client := &http.Client{Transport: transport} + + // 发送数据 + var response *http.Response + response, err = client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + // 读取数据 + result, err = ioutil.ReadAll(response.Body) + + return +} + +// POST Byte数组 +// weburl:远程服务器地址 +// data:post的Byte数组 +// header:包头集合 +// transport: transport对象 +// 返回值: +// 返回的字节 +// 错误对象 +func PostByteDataWithTransport(weburl string, data []byte, header map[string]string, transport *http.Transport) (result *[]byte, err error) { + // 组装POST数据 + reader := bytes.NewReader(data) + + // 构造请求对象 + var request *http.Request + request, err = http.NewRequest("POST", weburl, reader) + if err != nil { + return + } + + // 处理头部 + if header != nil { + for k, v := range header { + request.Header.Add(k, v) + } + } + + // 构造transport对象 + if transport == nil { + transport = NewTransport() + transport.DisableKeepAlives = true + transport = GetTimeoutTransport(transport, 30) + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + } + + // 构造httpClient对象 + client := &http.Client{Transport: transport} + + // 发送数据 + var response *http.Response + response, err = client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + body, err1 := ioutil.ReadAll(response.Body) + if err1 != nil { + err = err1 + return + } + + result = &body + + return +} + +// POST map类型的数据 +// weburl:远程服务器地址 +// data:数据 +// header:包头内容 +// transport:transport对象 +// 返回值 +// http StatusCode +// 字节数组 +// 错误对象 +func PostMapData(weburl string, data map[string]string, header map[string]string, transport *http.Transport) (statusCode int, result []byte, err error) { + // 组装POST数据 + postValues := url.Values{} + for key, value := range data { + postValues.Set(key, value) + } + postDataStr := postValues.Encode() + byteData := []byte(postDataStr) + + statusCode, result, err = PostByteData2(weburl, byteData, header, transport) + return +} + +// POST byte类型的数据(新方法) +// weburl:远程服务器地址 +// data:数据 +// header:包头内容 +// transport:transport对象 +// 返回值 +// http StatusCode +// 字节数组 +// 错误对象 +func PostByteData2(weburl string, data []byte, header map[string]string, transport *http.Transport) (statusCode int, result []byte, err error) { + // 组装POST数据 + reader := bytes.NewReader(data) + + // 构造请求对象 + var request *http.Request + request, err = http.NewRequest("POST", weburl, reader) + if err != nil { + return + } + + // 处理头部 + if header != nil { + for k, v := range header { + request.Header.Add(k, v) + } + } + + // 构造transport对象 + if transport == nil { + transport = NewTransport() + transport.DisableKeepAlives = true + transport = GetTimeoutTransport(transport, 30) + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //关闭证书校验 + } + + // 构造httpClient对象 + client := &http.Client{Transport: transport} + + // 发送数据 + var response *http.Response + response, err = client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + // 获取返回值 + statusCode = response.StatusCode + result, err = ioutil.ReadAll(response.Body) + + return +} + +// POST Byte数组 +// weburl:远程服务器地址 +// data:post的Byte数组 +// header:包头集合 +// 返回值: +// 返回的字节 +// 错误对象 +func PostByteData3(weburl string, data []byte, header map[string]string) (result []byte, err error) { + // 组装POST数据 + reader := bytes.NewReader(data) + + // 构造请求对象 + var request *http.Request + request, err = http.NewRequest("POST", weburl, reader) + if err != nil { + return + } + + request.Header.Set("Content-Type", "application/json;charset=UTF-8") + + // 构造transport对象 + transport := NewTransport() + transport.DisableKeepAlives = true + transport = GetTimeoutTransport(transport, 30) + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + // 构造httpClient对象 + client := &http.Client{Transport: transport} + + // 发送数据 + var response *http.Response + response, err = client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + // 读取数据 + result, err = ioutil.ReadAll(response.Body) + + return +} + +// POST Byte数组 +// weburl:远程服务器地址 +// data:post的Byte数组 +// header:包头集合 +// timeout:超时时间 +// 返回值: +// 返回的字节 +// 错误对象 +func PostByteData4(weburl string, data []byte, header map[string]string, timeout int) (result []byte, err error) { + // 组装POST数据 + reader := bytes.NewReader(data) + + // 构造请求对象 + var request *http.Request + request, err = http.NewRequest("POST", weburl, reader) + if err != nil { + return + } + + request.Header.Set("Content-Type", "application/json;charset=UTF-8") + + // 构造transport对象 + if timeout <= 0 { + timeout = 30 + } + transport := NewTransport() + transport.DisableKeepAlives = true + transport = GetTimeoutTransport(transport, timeout) + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + // 构造httpClient对象 + client := &http.Client{Transport: transport} + + // 发送数据 + var response *http.Response + response, err = client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + // 读取数据 + result, err = ioutil.ReadAll(response.Body) + + return +} diff --git a/.svn/pristine/2f/2f14ad8b60fa320c31dece98ac92ee259e9a5f3e.svn-base b/.svn/pristine/2f/2f14ad8b60fa320c31dece98ac92ee259e9a5f3e.svn-base new file mode 100644 index 0000000..7cba3dc --- /dev/null +++ b/.svn/pristine/2f/2f14ad8b60fa320c31dece98ac92ee259e9a5f3e.svn-base @@ -0,0 +1,40 @@ +package securityUtil + +import ( + "crypto/sha256" + "errors" + "fmt" +) + +// 对字符串进行SHA256加密,并且可以选择返回大、小写 +// s:输入字符串 +// ifUpper:输出是否大写 +// 返回值:sha256加密后的十六进制字符串 +func Sha256String(s string, ifUpper bool) string { + if len(s) == 0 { + panic(errors.New("input string can't be empty")) + } + + buf := Sha256Bytes([]byte(s)) + + if ifUpper { + return fmt.Sprintf("%X", buf) + } else { + return fmt.Sprintf("%x", buf) + } +} + +// 对字符数组进行SHA256加密 +// b:输入字符数组 +// 返回值:sha256加密后的原数据 +func Sha256Bytes(b []byte) []byte { + if len(b) == 0 { + panic(errors.New("input []byte can't be empty")) + } + + sha1Instance := sha256.New() + sha1Instance.Write(b) + result := sha1Instance.Sum(nil) + + return result +} diff --git a/.svn/pristine/30/30949ac53c528a2ecc3d58647e3be3906413ea67.svn-base b/.svn/pristine/30/30949ac53c528a2ecc3d58647e3be3906413ea67.svn-base new file mode 100644 index 0000000..7de2f6d --- /dev/null +++ b/.svn/pristine/30/30949ac53c528a2ecc3d58647e3be3906413ea67.svn-base @@ -0,0 +1,135 @@ +package util + +import ( + "context" + "fmt" + "net" + "strings" + + "google.golang.org/grpc/peer" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" +) + +var ( + moOpt protojson.MarshalOptions + uoOpt protojson.UnmarshalOptions +) + +func init() { + moOpt = protojson.MarshalOptions{ + // Multiline: true, + AllowPartial: true, + UseProtoNames: true, + UseEnumNumbers: true, + EmitUnpopulated: true, + } + uoOpt = protojson.UnmarshalOptions{ + DiscardUnknown: true, + } +} + +// PbCopy +// @description: 将from对象的内容copy给to对象 +// parameter: +// @from:proto.Message +// @to:proto.Message +// return: +// @error:如果失败,则返回错误,否则返回nil +func PbCopy(from, to proto.Message) error { + data, err := proto.Marshal(from) + if err != nil { + return err + } + + return proto.Unmarshal(data, to) +} + +// Pb2Json +// @description: 将pb对象转换为json字符串 +// parameter: +// @m: +// return: +// @string:pb对象的json标识形式 +// @error: +func Pb2Json(m proto.Message) (string, error) { + str, err := moOpt.Marshal(m) + if err != nil { + return "", err + } + + return string(str), nil +} + +// Json2Pb +// @description: 将json字符串转换成对应pb对象 +// parameter: +// @js: +// @m: +// return: +// @error: +func Json2Pb(js string, m proto.Message) error { + return uoOpt.Unmarshal([]byte(js), m) +} + +// Marshal +// @description: 序列化pb对象 +// parameter: +// @m: +// return: +// @[]byte: +// @error: +func Marshal(m proto.Message) ([]byte, error) { + data, err := proto.Marshal(m) + if err != nil { + return nil, err + } + + return data, nil +} + +// Marshal_Panic +// @description: 序列化pb对象 +// parameter: +// @m: +// return: +// @[]byte: +func Marshal_Panic(m proto.Message) []byte { + data, err := Marshal(m) + if err != nil { + panic(fmt.Sprintf("pbUtil Marshal pb错误,err:%s", err)) + } + + return data +} + +// Unmarshal +// @description: 将数据转换为pb对象 +// parameter: +// @data: +// @m: +// return: +func Unmarshal(data []byte, m proto.Message) error { + err := proto.Unmarshal(data, m) + return err +} + +// GetClientIP +// @description: 获取客户端Ip +// parameter: +// @ctx:grpc底层传递过来的上下文对象 +// return: +// @string:客户端ip +// @error:错误对象 +func GetClientIP(ctx context.Context) (string, error) { + pr, ok := peer.FromContext(ctx) + if !ok { + return "", fmt.Errorf("GetClietIP未获取到客户端ip") + } + if pr.Addr == net.Addr(nil) { + return "", fmt.Errorf("GetClientIP 获取到的peer.Addr=nil") + } + addSlice := strings.Split(pr.Addr.String(), ":") + + return addSlice[0], nil +} diff --git a/.svn/pristine/30/30b3aab878ea7aff20885d6b00cc935dbd706a3e.svn-base b/.svn/pristine/30/30b3aab878ea7aff20885d6b00cc935dbd706a3e.svn-base new file mode 100644 index 0000000..bba1bc3 --- /dev/null +++ b/.svn/pristine/30/30b3aab878ea7aff20885d6b00cc935dbd706a3e.svn-base @@ -0,0 +1,15 @@ +package gameServerMgr + +import ( + "fmt" + "testing" +) + +func TestActive(t *testing.T) { + err := ActiveServer("https://managecenterapitest-xxx.79yougame.com/API/ServerActivate.ashx", 20002) + if err != nil { + fmt.Println("xxx") + } + + CheckNewResourceVersion(1001, 20002, 100, "1584085505_769926880ac0ae89a31dcdfef5b94b1e") +} diff --git a/.svn/pristine/30/30ba2f04f4755f5db8d0594c2929c51ee463b213.svn-base b/.svn/pristine/30/30ba2f04f4755f5db8d0594c2929c51ee463b213.svn-base new file mode 100644 index 0000000..82aa9d1 --- /dev/null +++ b/.svn/pristine/30/30ba2f04f4755f5db8d0594c2929c51ee463b213.svn-base @@ -0,0 +1,84 @@ +package impl_console + +import ( + "fmt" + "github.com/fatih/color" +) + +type Logger struct { +} + +// NewLogger +// @description: 构造控制台日志 +// parameter: +// return: +// @*Logger: +func NewLogger() *Logger { + return &Logger{} +} + +// InfoLog +// @description: 信息日志记录 +// parameter: +// @format:日志格式 +// @args:参数列表 +// return: +func (cl *Logger) InfoLog(format string, args ...interface{}) { + c := color.New(color.FgGreen) + s := c.Sprint("Info:") + fmt.Println(s, fmt.Sprintf(format, args...)) +} + +// DebugLog +// @description: 调试日志记录 +// parameter: +// @format:日志格式 +// @args:参数列表 +// return: +func (cl *Logger) DebugLog(format string, args ...interface{}) { + c := color.New(color.FgGreen) + s := c.Sprint("Debug:") + fmt.Println(s, fmt.Sprintf(format, args...)) +} + +// WarnLog +// @description: 警告日志记录 +// parameter: +// @format:日志格式 +// @args:参数列表 +// return: +func (cl *Logger) WarnLog(format string, args ...interface{}) { + c := color.New(color.FgYellow) + _, _ = c.Println("Warn:", fmt.Sprintf(format, args...)) +} + +// ErrorLog +// @description: 错误日志记录 +// parameter: +// @format:日志格式 +// @args:参数列表 +// return: +func (cl *Logger) ErrorLog(format string, args ...interface{}) { + c := color.New(color.FgRed) + _, _ = c.Println("Error:", fmt.Sprintf(format, args...)) +} + +// FatalLog +// @description: 致命错误日志记录 +// parameter: +// @format:日志格式 +// @args:参数列表 +// return: +func (cl *Logger) FatalLog(format string, args ...interface{}) { + c := color.New(color.FgRed) + _, _ = c.Println("Fatal:", fmt.Sprintf(format, args...)) +} + +// CloseLog +// @description: 关闭日志 +// parameter: +// @waitFinish:是否等待日志 +// return: +func (cl *Logger) CloseLog(waitFinish bool) { + +} diff --git a/.svn/pristine/30/30fd49aaef962809ed3ade0ffa38bd43ad47b521.svn-base b/.svn/pristine/30/30fd49aaef962809ed3ade0ffa38bd43ad47b521.svn-base new file mode 100644 index 0000000..a31dd54 --- /dev/null +++ b/.svn/pristine/30/30fd49aaef962809ed3ade0ffa38bd43ad47b521.svn-base @@ -0,0 +1,131 @@ +package redisUtil + +import ( + "context" + "fmt" + "time" + + "github.com/gomodule/redigo/redis" +) + +// 订阅回调函数 +type SubscribeCallback func() error + +// Subscriber +// @description: 订阅者 +type Subscriber struct { + // pool 订阅者连接池 + pool *RedisPool + // callBack 订阅者回调函数 + callBack SubscribeCallback +} + +// NewSubscriber +// @description: 构建一个订阅者 +// parameter: +// @pool: +// @callBack: +// return: +// @*Subscriber: +func NewSubscriber(pool *RedisPool, callBack SubscribeCallback) *Subscriber { + return &Subscriber{pool: pool, callBack: callBack} +} + +// Promulgator +// @description: 发布者 +type Promulgator struct { + // pool 发布者连接池 + pool *RedisPool +} + +// NewPromulgator +// @description: 构建一个发布者 +// parameter: +// @pool: +// return: +// @*Promulgator: +func NewPromulgator(pool *RedisPool) *Promulgator { + return &Promulgator{pool: pool} +} + +// Publish +// @description: 发布消息 +// parameter: +// @receiver s: +// @channel: +// @message: +// return: +// @error: +func (s *Promulgator) Publish(channel, message string) error { + c := s.pool.GetConnection() + defer c.Close() + + _, err := c.Do("PUBLISH", channel, message) + if err != nil { + return fmt.Errorf("redis publish %s %s, err: %v", channel, message, err) + } + //n, err := s.pool.Int(result) + //if err != nil { + // return fmt.Errorf("redis publish %s %s, err: %v", channel, message, err) + //} + + return nil +} + +// Subscribe +// @description: 订阅者订阅消息 +// parameter: +// @receiver s: +// @ctx: +// @channel: 频道 +// return: +// @error: +func (s *Subscriber) Subscribe(ctx context.Context, channel ...string) error { + sub := redis.PubSubConn{Conn: s.pool.GetConnection()} + if err := sub.Subscribe(redis.Args{}.AddFlat(channel)...); err != nil { + return err + } + done := make(chan error, 1) + + // 启动一个新协程去持续订阅消息 + go func() { + defer sub.Close() + for { + switch msg := sub.Receive().(type) { + case error: + done <- fmt.Errorf("redis pubsub receive err: %v", msg) + return + case redis.Message: + if err := s.callBack(); err != nil { + done <- err + return + } + case redis.Subscription: + if msg.Count == 0 { + // 所有的订阅者都退出 + done <- nil + return + } + } + } + }() + + // health check + tick := time.NewTicker(time.Minute) + defer tick.Stop() + for { + select { + case <-ctx.Done(): + if err := sub.Unsubscribe(); err != nil { + return fmt.Errorf("redis pubsub unsubscribe err: %v", err) + } + return nil + case err := <-done: + return err + case <-tick.C: + if err := sub.Ping(""); err != nil { + return err + } + } + } +} diff --git a/.svn/pristine/31/313f27b5bd4317d500dc2743379a8be288c087a9.svn-base b/.svn/pristine/31/313f27b5bd4317d500dc2743379a8be288c087a9.svn-base new file mode 100644 index 0000000..832f309 --- /dev/null +++ b/.svn/pristine/31/313f27b5bd4317d500dc2743379a8be288c087a9.svn-base @@ -0,0 +1,204 @@ +package logSqlSync + +import ( + "database/sql" + "fmt" + "os" + "path/filepath" + "time" + + "Framework/dataSyncMgr/mysqlSync/sqlSync" + "goutil/logUtil" +) + +// 同步对象定义 +type SyncObject struct { + // 服务器组Id + serverGroupId int32 + + // 同步数据的存储路径 + dirPath string + + // 同步数据对象的唯一标识,用于进行重复判断 + identifier string + + // 数据库对象 + dbObj *sql.DB + + // 同步信息对象 + syncingInfoObj *syncingInfo + + // 错误处理对象 + errorHandleObj *syncErrorInfo + + // 同步对象 + syncObj *sqlSync.SyncObject +} + +// 初始化 +// baseObj:基础同步对象 +func (this *SyncObject) Init(baseObj *sqlSync.SyncObject) { + this.syncObj = baseObj + + // 初始化同步信息对象 + syncingInfoObj, err := newSyncingInfoObject(this.serverGroupId, this.dbObj) + if err != nil { + panic(err) + } + //// 初始化错误处理对象 + errorHandleObj, err := newSyncErrorInfoObject(this.dbObj) + if err != nil { + panic(err) + } + this.syncingInfoObj = syncingInfoObj + this.errorHandleObj = errorHandleObj + + // 初始化当前处理的文件 + fileList := sqlSync.GetDataFileList(this.dirPath) + filePath, _ := this.syncingInfoObj.GetSyncingInfo() + if len(filePath) < 0 && len(fileList) > 0 { + this.syncingInfoObj.Update(fileList[0], 0, nil) + } +} + +// 获取正在同步的信息 +// filePath:文件路径 +// offset:文件偏移量 +func (this *SyncObject) GetSyncingInfo() (filePath string, offset int64) { + return this.syncingInfoObj.GetSyncingInfo() +} + +// 更新 +// filePath:文件路径 +// offset:文件偏移量 +// tran:事务对象 +// 返回值: +// error:错误对象 +func (this *SyncObject) Update(filePath string, offset int64, tx *sql.Tx) error { + return this.syncingInfoObj.Update(filePath, offset, tx) +} + +// 同步一条sql语句 +// command:待执行的命令 +// filePath:保存路径 +// offset:文件偏移量 +// 返回值: +// error:错误信息 +func (this *SyncObject) SyncOneSql(command string, filePath string, offset int64) { + var err error + for { + err = sqlSync.ExecuteByTran(this.dbObj, func(tran *sql.Tx) (isCommit bool, err error) { + // 保存sql到数据库 + err = this.syncToMysql(command, tran) + if err != nil { + return + } + + // 保存进度信息到数据库 + err = this.syncingInfoObj.Update(filePath, offset, tran) + if err != nil { + return + } + + isCommit = true + return + }) + + // 如果是连接出错,则仍然循环执行 + if err != nil { + if sqlSync.CheckIfConnectionError(err.Error()) { + time.Sleep(5 * time.Second) + continue + } + } + + // 如果不是数据库连接出错,则算是执行完成 + break + } + + // 如果存在错误,则循环尝试执行 + if err != nil { + this.recordSqlError(command, filePath, offset, err.Error()) + } + + return +} + +// 同步数据到mysql中 +// command:sql语句 +// tx:事务处理对象 +// 返回值: +// error:错误信息 +func (this *SyncObject) syncToMysql(command string, tx *sql.Tx) error { + _, err := tx.Exec(command) + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("mysqlSync/logSqlSync/syncObject.syncToMysql error:%s", err.Error())) + return err + } + + return nil +} + +// 错误处理 +// cmd:待执行的命令 +// filePath:保存路径 +// offset:文件偏移量 +// errMsg:错误信息 +func (this *SyncObject) recordSqlError(command string, filePath string, offset int64, errMsg string) { + errMsg = sqlSync.GetSimpleErrorMessage(errMsg) + + for { + err := sqlSync.ExecuteByTran(this.dbObj, func(tran *sql.Tx) (isCommit bool, err error) { + // 保存sql到数据库 + err = this.errorHandleObj.AddErrorSql(tran, command, errMsg) + if err != nil { + return + } + + // 保存进度信息到数据库 + err = this.syncingInfoObj.Update(filePath, offset, tran) + if err != nil { + return + } + + isCommit = true + return + }) + + if err == nil { + return + } + + time.Sleep(5 * time.Second) + } +} + +// 创新新的mysql同步对象 +// dirPath:存放数据的目录 +// identifier:当前数据的唯一标识(可以使用数据库表名) +// dbObj:数据库对象 +// syncingInfoObj:同步信息记录对象 +// errorHandleObj:错误处理对象 +// 返回值: +// mysql同步对象 +func NewSyncObject(serverGroupId int32, dirPath, identifier string, dbObj *sql.DB) *SyncObject { + dirPath = filepath.Join(dirPath, identifier) + + // 创建更新目录 + err := os.MkdirAll(dirPath, os.ModePerm|os.ModeTemporary) + if err != nil { + err = fmt.Errorf("%s-%s-make dir failed:%s", identifier, "SyncObject.newSyncObject.os.MkdirAll", err) + logUtil.ErrorLog(err.Error()) + panic(err) + } + + // 构造同步信息对象 + result := &SyncObject{ + serverGroupId: serverGroupId, + dirPath: dirPath, + identifier: identifier, + dbObj: dbObj, + } + + return result +} diff --git a/.svn/pristine/31/3167307a52e20e4a543ae33d5269808f02e5b7e4.svn-base b/.svn/pristine/31/3167307a52e20e4a543ae33d5269808f02e5b7e4.svn-base new file mode 100644 index 0000000..82ce3b9 --- /dev/null +++ b/.svn/pristine/31/3167307a52e20e4a543ae33d5269808f02e5b7e4.svn-base @@ -0,0 +1,101 @@ +package bytesSendUtil + +import ( + "goutil/zlibUtil" +) + +type dataItem interface { + // 返回原始数据 + OriginData() []byte + + // 返回发送字节流 + Bytes() []byte + + // 设置发送次数 + SetCount(uint) + + // 返回发送次数 + Count() uint +} + +///////////////////////////////////////////////// +// httpDataItem + +type httpDataItem struct { + // 数据 + data []byte + + // 发送次数 + count uint +} + +func newHTTPData(_data []byte) dataItem { + return &httpDataItem{ + data: _data, + count: 0, + } +} + +// 返回原始数据 +func (this *httpDataItem) OriginData() []byte { + return this.data +} + +// 返回原始数据用于发送 +func (this *httpDataItem) Bytes() []byte { + return this.data +} + +func (this *httpDataItem) SetCount(cnt uint) { + this.count = cnt +} + +func (this *httpDataItem) Count() uint { + return this.count +} + +///////////////////////////////////////////////// +// tcpDataItem + +type tcpDataItem struct { + // 原始数据 + origin []byte + + // 压缩后数据 + data []byte + + // 重试次数 + count uint +} + +func newTCPDataItem(_data []byte) (dataItem, error) { + compressed, err := zlibUtil.Compress([]byte(_data), 5) + if err != nil { + return nil, err + } + + item := &tcpDataItem{ + origin: _data, + data: compressed, + count: 0, + } + return item, nil +} + +// 返回原始数据 +func (this *tcpDataItem) OriginData() []byte { + return this.origin +} + +// 返回压缩数据用于发送 +func (this *tcpDataItem) Bytes() []byte { + return this.data +} + +func (this *tcpDataItem) SetCount(cnt uint) { + this.count = cnt +} + +func (this *tcpDataItem) Count() uint { + return this.count +} diff --git a/.svn/pristine/33/335a13f982390c2ec9a716fcddcea8bc20697680.svn-base b/.svn/pristine/33/335a13f982390c2ec9a716fcddcea8bc20697680.svn-base new file mode 100644 index 0000000..7f68c50 --- /dev/null +++ b/.svn/pristine/33/335a13f982390c2ec9a716fcddcea8bc20697680.svn-base @@ -0,0 +1,183 @@ +package mqMgr + +import ( + "context" + "errors" + "fmt" + "time" + + amqp "github.com/rabbitmq/amqp091-go" +) + +// Queue对象 +type HSYQueue struct { + conn *amqp.Connection + channel *amqp.Channel + // 队列名称 + queueName string + // 交换机 + exchange string + // routing Key + routingKey string + //MQ链接字符串 + mqurl string +} + +// 消息队列配置对象 +type HSYQueueConfig struct { + QueueName string + Exchange string + RoutingKey string + Network string + Port int + UserName string + Password string +} + +// 创建新的Queue对象 +func NewHSYQueue(queueName, exchange, routingKey, userName, password string, network string, port int) *HSYQueue { + queueConfigObj := &HSYQueueConfig{ + QueueName: queueName, + Exchange: exchange, + RoutingKey: routingKey, + UserName: userName, + Password: password, + Network: network, + Port: port, + } + + return NewHSYQueueByConfig(queueConfigObj) +} + +// 通过队列配置对象创建新的Queue对象 +func NewHSYQueueByConfig(queueConfigObj *HSYQueueConfig) *HSYQueue { + queueObj := &HSYQueue{ + queueName: queueConfigObj.QueueName, + exchange: queueConfigObj.Exchange, + routingKey: queueConfigObj.RoutingKey, + mqurl: fmt.Sprintf("amqp://%s:%s@%s:%d/", queueConfigObj.UserName, queueConfigObj.Password, queueConfigObj.Network, queueConfigObj.Port), + } + + if err := queueObj.GetQueueAttributes(); err != nil { + return nil + } + + return queueObj +} + +// 连接RabbitMQ服务器 +func (this *HSYQueue) GetQueueAttributes() (err error) { + this.conn, err = amqp.Dial(this.mqurl) + if err != nil { + return + } + + this.channel, err = this.conn.Channel() + if err != nil { + return + } + + return +} + +// 释放连接 +func (this *HSYQueue) ReleaseRes() { + this.conn.Close() + this.channel.Close() +} + +// SendMessage 发送单条消息 +func (this *HSYQueue) SendMessage(message string, ex string) (err error) { + // 声明队列 + _, err = this.channel.QueueDeclare( + this.queueName, // 队列名 + true, // 是否持久化 + false, // 是否自动删除(前提是至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会自动删除。注意:生产者客户端创建这个队列,或者没有消费者客户端与这个队列连接时,都不会自动删除这个队列) + false, // 是否为排他队列(排他的队列仅对“首次”声明的conn可见[一个conn中的其他channel也能访问该队列],conn结束后队列删除) + false, // 是否阻塞 + nil, // 额外属性 + ) + if err != nil { + err = errors.New("声明队列失败") + return + } + + // 声明交换器 + err = this.channel.ExchangeDeclare( + this.exchange, //交换器名 + ex, //exchange type:一般用fanout、direct、topic + true, // 是否持久化 + false, //是否自动删除(自动删除的前提是至少有一个队列或者交换器与这和交换器绑定,之后所有与这个交换器绑定的队列或者交换器都与此解绑) + false, //设置是否内置的。true表示是内置的交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式 + false, // 是否阻塞 + nil, // 额外属性 + ) + if err != nil { + err = errors.New("声明交换器失败") + return + } + + // Binding + err = this.channel.QueueBind( + this.queueName, // 绑定的队列名称 + this.routingKey, // bindkey 用于消息路由分发的key + this.exchange, // 绑定的exchange名 + false, // 是否阻塞 + nil, // 额外属性 + ) + if err != nil { + err = errors.New("绑定队列和交换器失败") + return + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + err = this.channel.PublishWithContext(ctx, + this.exchange, + this.routingKey, + false, + false, + amqp.Publishing{ + ContentType: "text/plain", + Body: []byte(message), + }) + if err != nil { + err = errors.New("发布消息失败") + return + } + + return +} + +// ReceiveMessage 消费单条消息 +func (this *HSYQueue) ReceiveMessage() (msgs <-chan amqp.Delivery, err error) { + _, err = this.channel.QueueDeclare( + this.queueName, // 队列名 + true, // 是否持久化 + false, // 是否自动删除(前提是至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会自动删除。注意:生产者客户端创建这个队列,或者没有消费者客户端与这个队列连接时,都不会自动删除这个队列) + false, // 是否为排他队列(排他的队列仅对“首次”声明的conn可见[一个conn中的其他channel也能访问该队列],conn结束后队列删除) + false, // 是否阻塞 + nil, // 额外属性(我还不会用) + ) + if err != nil { + err = errors.New("声明队列失败") + return + } + + msgs, err = this.channel.Consume( + this.queueName, // 队列名 + "", // 消费者名,用来区分多个消费者,以实现公平分发或均等分发策略 + true, // 是否自动应答 + false, // 是否排他 + false, // 是否接收只同一个连接中的消息,若为true,则只能接收别的conn中发送的消息 + true, // 队列消费是否阻塞 + nil, // 额外属性 + ) + if err != nil { + err = errors.New("获取消息失败") + return + } + + return +} diff --git a/.svn/pristine/33/33b2559f92484c30f0522d74cc475fcffe1f82f7.svn-base b/.svn/pristine/33/33b2559f92484c30f0522d74cc475fcffe1f82f7.svn-base new file mode 100644 index 0000000..a5085f2 --- /dev/null +++ b/.svn/pristine/33/33b2559f92484c30f0522d74cc475fcffe1f82f7.svn-base @@ -0,0 +1,142 @@ +package stringUtil + +import ( + "regexp" + "runtime" + "sort" + "strconv" + "strings" + "unicode" +) + +// 检查一个字符串是否是空字符串 +// content:上下文字符串 +// 返回值: +// bool:true:空字符串 false:非空字符串 +func IsEmpty(content string) bool { + if len(content) <= 0 { + return true + } + + return strings.IndexFunc(content, func(item rune) bool { + return unicode.IsSpace(item) == false + }) < 0 +} + +// 截取字符串 +// start:开始位置 +// length:截取长度 +// 返回值: +// 截取后的字符串 +func Substring(str string, start, length int) string { + // 先将字符串转化为[]rune格式(由于rune是字符串的基本单位) + runeString := []rune(str) + runeLength := len(runeString) + end := 0 + + // 计算起始位置 + if start > runeLength { + start = runeLength + } + + // 计算终止位置 + end = start + length + if end > runeLength { + end = runeLength + } + + if start > end { + start, end = end, start + } + + return string(runeString[start:end]) +} + +// 根据不同平台获取换行符 +// 返回值: +// 换行符 +func GetNewLineString() string { + switch os := runtime.GOOS; os { + case "windows": + return "\r\n" + default: + return "\n" + } +} + +// 检查是否存在特殊符号 +// 1. emoji字符 +// 2. ascii控制字符 +// 3. \ " ' +// val:待检查的字符串 +// 返回值: +// bool:true:有特殊字符 false:无特殊字符 +func IfHaveSpecialChar(val string) bool { + if len(val) <= 0 { + return false + } + + // 表情符号过滤 + // Wide UCS-4 build + emojiReg, _ := regexp.Compile("[^\U00000000-\U0000FFFF]+") + if emojiReg.Match([]byte(val)) { + return true + } + + // 排除控制字符和特殊字符 + for _, charItem := range val { + // 排除控制字符 + if (charItem > 0 && charItem < 0x20) || charItem == 0x7F { + return true + } + + // 排除部分特殊字符: \ " ' + switch charItem { + case '\\': + fallthrough + case '"': + fallthrough + case '\'': + return true + } + } + + return false +} + +// 判断string数组是否内容唯一 +func IsDistinct_string(list []string) (result bool) { + if len(list) == 0 || len(list) == 1 { + result = true + return + } + + sort.Strings(list) + + for i := 0; i < len(list)-1; i++ { + if list[i] == list[i+1] { + result = false + return + } + } + + result = true + return +} + +// 验证是否是电话号码 +func VerifyPhone(phone string) bool { + regular := "^1[3-9]\\d{9}$" + + reg := regexp.MustCompile(regular) + return reg.MatchString(phone) +} + +// 转型成int64 +func StringToInt64(str string) int64 { + num, err := strconv.ParseInt(str, 10, 64) + if err != nil { + return 0 + } + return num +} diff --git a/.svn/pristine/33/33c823dd0646acce265d7166cd02d78a6807aea2.svn-base b/.svn/pristine/33/33c823dd0646acce265d7166cd02d78a6807aea2.svn-base new file mode 100644 index 0000000..a0802a0 --- /dev/null +++ b/.svn/pristine/33/33c823dd0646acce265d7166cd02d78a6807aea2.svn-base @@ -0,0 +1,12 @@ +package managecenterModel + +// 服务器状态 +type GroupLoad int32 + +const ( + // 正常 + Con_GroupLoad_Normal GroupLoad = 1 + + // 火爆 + Con_GroupLoad_Hot GroupLoad = 2 +) diff --git a/.svn/pristine/33/33f4735ef28dd736d756c6d320e069c3ab89f068.svn-base b/.svn/pristine/33/33f4735ef28dd736d756c6d320e069c3ab89f068.svn-base new file mode 100644 index 0000000..e44e785 --- /dev/null +++ b/.svn/pristine/33/33f4735ef28dd736d756c6d320e069c3ab89f068.svn-base @@ -0,0 +1,53 @@ +package mathUtil + +import ( + "fmt" + "testing" +) + +func TestQuartile(t *testing.T) { + + intList := []int{} + var lower, mid, upper float64 + var err error + lower, mid, upper, err = Quartile_Int(intList) + if err != nil { + fmt.Printf("Error:%s\n", err) + } + + intList = []int{4} + lower, mid, upper, err = Quartile_Int(intList) + if err != nil { + fmt.Printf("Error:%s\n", err) + } + fmt.Printf("LowerQuartile:%f\n", lower) + fmt.Printf("MidQuartile:%f\n", mid) + fmt.Printf("UpperQuartile:%f\n", upper) + + intList = []int{4, 93} + lower, mid, upper, err = Quartile_Int(intList) + if err != nil { + fmt.Printf("Error:%s\n", err) + } + fmt.Printf("LowerQuartile:%f\n", lower) + fmt.Printf("MidQuartile:%f\n", mid) + fmt.Printf("UpperQuartile:%f\n", upper) + + intList = []int{4, 93, 84} + lower, mid, upper, err = Quartile_Int(intList) + if err != nil { + fmt.Printf("Error:%s\n", err) + } + fmt.Printf("LowerQuartile:%f\n", lower) + fmt.Printf("MidQuartile:%f\n", mid) + fmt.Printf("UpperQuartile:%f\n", upper) + + intList = []int{4, 93, 84, 85, 80, 37, 81, 93, 27, 12} + lower, mid, upper, err = Quartile_Int(intList) + if err != nil { + fmt.Printf("Error:%s\n", err) + } + fmt.Printf("LowerQuartile:%f\n", lower) + fmt.Printf("MidQuartile:%f\n", mid) + fmt.Printf("UpperQuartile:%f\n", upper) +} diff --git a/.svn/pristine/34/3439bb7d1781aebf4bed60ed3aadb529219c3f32.svn-base b/.svn/pristine/34/3439bb7d1781aebf4bed60ed3aadb529219c3f32.svn-base new file mode 100644 index 0000000..99730be --- /dev/null +++ b/.svn/pristine/34/3439bb7d1781aebf4bed60ed3aadb529219c3f32.svn-base @@ -0,0 +1,131 @@ +package jsonUtil + +import ( + "encoding/json" + "fmt" + "testing" +) + +func TestUnMarshalWithNumberType(t *testing.T) { + src := make(map[string]int) + src["Name"] = 123 + src["Money"] = 100000000 + + var byteSlice []byte + var err error + if byteSlice, err = json.Marshal(src); err != nil { + t.Errorf("Marshal src failed\n") + } + + if target_interface, err := UnMarshalWithNumberType(string(byteSlice)); err != nil { + t.Errorf("Expected got nil, but got err:%s\n", err) + } else { + if target_map, ok := target_interface.(map[string]interface{}); !ok { + t.Errorf("Expected got nil, but got err:%s\n", err) + } else { + money, ok := target_map["Money"].(json.Number) + money_int, err := money.Int64() + if !ok || err != nil || money_int != 100000000 { + t.Errorf("Expected got 100000000, but got %v, ok:%v, err:%s\n", money_int, ok, err) + } + + fmt.Printf("target_map:%v\n", target_map) + } + } + + intSlice1 := []int{1, 2, 3, 5} + + if byteSlice, err = json.Marshal(intSlice1); err != nil { + t.Errorf("Marshal src failed\n") + } + + if target_interface, err := UnMarshalWithNumberType(string(byteSlice)); err != nil { + t.Errorf("Expected got nil, but got err:%s\n", err) + } else { + fmt.Printf("target_interface:%v\n", target_interface) + if target_slice, ok := target_interface.([]interface{}); !ok { + t.Errorf("Expected got []int, but failed.\n") + } else { + fmt.Printf("target_slice:%v\n", target_slice) + } + } +} + +func TestDeepClone(t *testing.T) { + p1 := NewPlayer(100000000, "Jordan") + if p1_map, err := DeepClone(p1); err != nil { + t.Errorf("Expected nil, but got err:%s", err) + } else { + fmt.Printf("p1:%s\n", p1) + before := fmt.Sprintf("%v", p1_map) + p1.Name = "Jordan Zuo" + fmt.Printf("p1:%s\n", p1) + after := fmt.Sprintf("%v", p1_map) + fmt.Printf("before:%s\n", before) + fmt.Printf("after:%s\n", after) + if before != after { + t.Errorf("Expected before and after same, but got different") + } + } + + intSlice1 := []int{1, 2, 3, 5} + if intSlice2_interface, err := DeepClone(intSlice1); err != nil { + t.Errorf("Expected nil, but got err:%s", err) + } else { + fmt.Printf("intSlice1:%v\n", intSlice1) + before := fmt.Sprintf("%v", intSlice2_interface) + intSlice1 = append(intSlice1, 10) + fmt.Printf("intSlice1:%v\n", intSlice1) + after := fmt.Sprintf("%v", intSlice2_interface) + fmt.Printf("before:%s\n", before) + fmt.Printf("after:%s\n", after) + if before != after { + t.Errorf("Expected before and after same, but got different") + } + } +} + +func TestDeepCloneWithNumberType(t *testing.T) { + p1 := NewPlayer(100000000, "Jordan") + if p1_interface, err := DeepCloneWithNumberType(p1); err != nil { + t.Errorf("Expected nil, but got err:%s", err) + } else { + if p1_map, ok := p1_interface.(map[string]interface{}); !ok { + t.Errorf("Expected nil, but got err:%s", err) + } else { + fmt.Printf("p1:%s\n", p1) + before := fmt.Sprintf("%v", p1_map) + p1.Name = "Jordan Zuo" + fmt.Printf("p1:%s\n", p1) + after := fmt.Sprintf("%v", p1_map) + fmt.Printf("before:%s\n", before) + fmt.Printf("after:%s\n", after) + if before != after { + t.Errorf("Expected before and after same, but got different") + } + + fmt.Printf("p1_interface_map:%v\n", p1_map) + id, ok := p1_map["Id"].(json.Number) + id_int, err := id.Int64() + if !ok || err != nil || id_int != 100000000 { + t.Errorf("Expected got 100000000, but got %v, ok:%v, err:%s\n", id_int, ok, err) + } + } + } +} + +type Player struct { + Id int + Name string +} + +func (player *Player) String() string { + return fmt.Sprintf("{Addr:%v, Id:%v, Name:%s}", &player, player.Id, player.Name) +} + +func NewPlayer(id int, name string) *Player { + return &Player{ + Id: id, + Name: name, + } +} diff --git a/.svn/pristine/34/343fd5ed458ab13b56f9ac7761adf383671377ed.svn-base b/.svn/pristine/34/343fd5ed458ab13b56f9ac7761adf383671377ed.svn-base new file mode 100644 index 0000000..8e52a2b --- /dev/null +++ b/.svn/pristine/34/343fd5ed458ab13b56f9ac7761adf383671377ed.svn-base @@ -0,0 +1,67 @@ +package gameLogMgr + +import ( + "bytes" + "fmt" + "testing" + "time" + + "goutil/debugUtil" + "goutil/stringUtil" + "goutil/timeUtil" +) + +func TestWrite(t *testing.T) { + debugUtil.SetDebug(true) + + brokerList := []string{"10.1.0.202:9092", "10.1.0.204:9092", "10.1.0.205:9092"} + Start(brokerList, "", "") + + topic := "test2" + serverGroupId := int32(20011) + for i := 0; i < 5; i++ { + Write(topic, serverGroupId, getGameLog(i)) + } + + time.Sleep(5 * time.Second) + Stop() +} + +func BenchmarkWrite(b *testing.B) { + debugUtil.SetDebug(true) + topic := "test2" + serverGroupId := int32(20011) + + brokerList := []string{"10.1.0.202:9092", "10.1.0.204:9092", "10.1.0.205:9092"} + Start(brokerList, "", "") + + b.ResetTimer() + for i := 0; i < b.N; i++ { + Write(topic, serverGroupId, getGameLog(i)) + } + b.StopTimer() + + Stop() +} + +func getGameLog(int2 int) string { + //kafkaLog组装 + var buffer bytes.Buffer + buffer.WriteString("{") + buffer.WriteString(fmt.Sprintf("\"#account_id\":\"%s\"", "123456789123456789")) + buffer.WriteString(",") + buffer.WriteString(fmt.Sprintf("\"#time\":\"%s\"", time.Now().Format("2006-01-02 15:04:05"))) + buffer.WriteString(",") + buffer.WriteString(fmt.Sprintf("\"#uuid\":\"%s\"", stringUtil.GetNewGUID())) + buffer.WriteString(",") + buffer.WriteString(fmt.Sprintf("\"#event_id\":\"\"")) + buffer.WriteString(",") + buffer.WriteString(fmt.Sprintf("\"#type\":\"track\"")) + buffer.WriteString(",") + buffer.WriteString(fmt.Sprintf("\"#event_name\":\"achievement_change_log\"")) + buffer.WriteString(",") + buffer.WriteString(fmt.Sprintf("\"properties\":{\"PartnerId\":%d,\"ServerId\":%d,\"Crtime\":\"%s\",\"Crdate\":\"%s\"}", 600021, int2, timeUtil.ToDateTimeString2(time.Now()), timeUtil.ToDateString2(time.Now()))) + buffer.WriteString("}") + + return buffer.String() +} diff --git a/.svn/pristine/34/3449f3eb7da2660d83da36bd4e0b728e917c7f96.svn-base b/.svn/pristine/34/3449f3eb7da2660d83da36bd4e0b728e917c7f96.svn-base new file mode 100644 index 0000000..eb50995 --- /dev/null +++ b/.svn/pristine/34/3449f3eb7da2660d83da36bd4e0b728e917c7f96.svn-base @@ -0,0 +1,231 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Shopify/sarama v1.29.1/go.mod h1:mdtqvCSg8JOxk8PmpTNGyo6wzd4BMm4QXSfDnTXmgkE= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 h1:OoL469zqSNrTLSz5zeVF/I6VOO7fiw2bzSzQe4J557c= +github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4/go.mod h1:xe9a/L2aeOgFKKgrO3ibQTnMdpAeL0GC+5/HpGScSa4= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= +github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rabbitmq/amqp091-go v1.8.1/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.230/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vms v1.0.230/go.mod h1:zElyabRGi8DktckzhT3krsYChstFJdSrzDb7pwF2P58= +github.com/xdg/scram v1.0.3/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/.svn/pristine/34/34c4995e93e1d7fb867c6043db15d57863b64727.svn-base b/.svn/pristine/34/34c4995e93e1d7fb867c6043db15d57863b64727.svn-base new file mode 100644 index 0000000..2539dfb --- /dev/null +++ b/.svn/pristine/34/34c4995e93e1d7fb867c6043db15d57863b64727.svn-base @@ -0,0 +1,47 @@ +package httpSender + +import ( + "errors" + "fmt" + + // "goutil/debugUtil" + "goutil/webUtil" +) + +// 实现Sender相关接口 + +type httpClient struct{} + +// 发送Requester +func (this *httpClient) Send(req Requester) (rspn []byte, err error) { + if req.GetMethod() == "POST" { + rspn, err = this.post(req) + return + } else { + err = errors.New(fmt.Sprintf("request: unsupport method (%s)", req.GetMethod())) + return + } +} + +// 发送 post 请求 +func (*httpClient) post(req Requester) ([]byte, error) { + url := req.GetUrl() + bytes := req.GetData() + + // debugUtil.Printf("httpClient-POST %s\r\n%v\n", url, string(bytes)) + + rspn, err := webUtil.PostByteData(url, bytes, nil) + if err != nil { + return nil, err + } + + // body := []byte("{\"result\":0,\"errmsg\":\"OK\",\"ext\":\"hello-world\",\"sid\":\"6:59106203271444582828\",\"fee\":1}") + + // debugUtil.Printf("httpClient-Res: %s", string(rspn)) + + return rspn, nil +} + +func New() *httpClient { + return new(httpClient) +} diff --git a/.svn/pristine/34/34cd0a6c1e01175f811d01e6be3886accfb3919f.svn-base b/.svn/pristine/34/34cd0a6c1e01175f811d01e6be3886accfb3919f.svn-base new file mode 100644 index 0000000..84fe65e --- /dev/null +++ b/.svn/pristine/34/34cd0a6c1e01175f811d01e6be3886accfb3919f.svn-base @@ -0,0 +1,8 @@ +// ************************************ +// @package: client +// @description: grpc客户端辅助包 +// @author: byron +// @revision history: +// @create date: 2022-01-19 16:50:24 +// ************************************ +package client diff --git a/.svn/pristine/35/3547deaad7e807c519e9f84e8e45315bcb11bee2.svn-base b/.svn/pristine/35/3547deaad7e807c519e9f84e8e45315bcb11bee2.svn-base new file mode 100644 index 0000000..e388016 --- /dev/null +++ b/.svn/pristine/35/3547deaad7e807c519e9f84e8e45315bcb11bee2.svn-base @@ -0,0 +1,63 @@ +package monitorNewMgr + +import ( + "sync" + "time" + + "goutil/stringUtil" +) + +const ( + // CON_MONITOR_HISTORY_SIZE 历史监控信息保存数量 + CON_MONITOR_HISTORY_SIZE = 3 + + // CON_MONITOR_HISTORY_VALID_SECONDS 历史监控信息有效的秒数 + CON_MONITOR_HISTORY_VALID_SECONDS = 30 + + // CON_MONITOR_HISTORY_SIMILARITY_THERSHOLD 历史监控信息相似度的阈值 + CON_MONITOR_HISTORY_SIMILARITY_THERSHOLD = 0.9 +) + +var ( + monitorHistoryList = make([]*MonitorHistory, 0, CON_MONITOR_HISTORY_SIZE) + monitorHistoryMutex sync.Mutex +) + +func checkSimilarity(monitorMessage string, timestamp int64) (valid bool) { + //默认监控信息有效 + valid = true + + monitorHistoryMutex.Lock() + defer monitorHistoryMutex.Unlock() + + // 从后往前(按时间从后往前)遍历,以便于可以及时退出 + for i := len(monitorHistoryList) - 1; i >= 0; i-- { + item := monitorHistoryList[i] + + // 如果已经过期,则不用处理; 返回之前的状态即可(当前的已经过期,则之前的也一定已经过期) + if time.Now().Unix()-item.Timestamp > CON_MONITOR_HISTORY_VALID_SECONDS { + break + } + + // 如果两个字符串的长度相差2倍,则无须继续判断,继续与下一条数据进行比较 + lenA, lenB := len(monitorMessage), len(item.MonitorMessage) + if lenA > 2*lenB || lenB > 2*lenA { + continue + } + + // 判断两个字符串的相似度(如果相似度超过阈值,则此日志无效) + _, similarity := stringUtil.Similarity(monitorMessage, item.MonitorMessage) + if similarity >= CON_MONITOR_HISTORY_SIMILARITY_THERSHOLD { + valid = false + return // 直接返回,无需将当前日志添加到历史列表中,以提高性能 + } + } + + // 将消息添加到历史消息列表中 + monitorHistoryList = append(monitorHistoryList, newMonitorHistory(monitorMessage, timestamp)) + if len(monitorHistoryList) > CON_MONITOR_HISTORY_SIZE { + monitorHistoryList = monitorHistoryList[len(monitorHistoryList)-CON_MONITOR_HISTORY_SIZE:] + } + + return +} diff --git a/.svn/pristine/35/3566bd2849a9eca9f553cedecc4a9b2ebd621b23.svn-base b/.svn/pristine/35/3566bd2849a9eca9f553cedecc4a9b2ebd621b23.svn-base new file mode 100644 index 0000000..9963b15 --- /dev/null +++ b/.svn/pristine/35/3566bd2849a9eca9f553cedecc4a9b2ebd621b23.svn-base @@ -0,0 +1,36 @@ +package user + +import ( + "common/cache" + "common/connection" +) + +func init() { + //注册数据库 + connection.RegisterDBModel(&User{}) +} + +type User struct { + ID int64 `gorm:"column:id;primary_key;comment:用户id;autoIncrementIncrement" json:"id"` + //账号 + Account string `gorm:"column:account;comment:账号" json:"account"` + Name string `gorm:"column:name;comment:用户名称" json:"name"` + Password string `gorm:"column:password;comment:用户密码" json:"password"` + //性别 + Sex int32 `gorm:"column:sex;comment:性别" json:"sex"` + //生日 + Birthday string `gorm:"column:birthday;comment:生日" json:"birthday"` + //手机 + Phone int64 `gorm:"column:phone;comment:手机" json:"phone"` + //邮箱 + Email string `gorm:"column:email;comment:邮箱" json:"email"` + //备注 + Describe string `gorm:"column:describe;comment:备注" json:"describe"` + + //玩家的缓存对象 + Cache *cache.Cache +} + +func (User) TableName() string { + return "user" +} diff --git a/.svn/pristine/35/357e65a8770e13e0ad7e76c3c6635a87600816b2.svn-base b/.svn/pristine/35/357e65a8770e13e0ad7e76c3c6635a87600816b2.svn-base new file mode 100644 index 0000000..0b79498 --- /dev/null +++ b/.svn/pristine/35/357e65a8770e13e0ad7e76c3c6635a87600816b2.svn-base @@ -0,0 +1,83 @@ +package webServer + +import ( + "common/resultStatus" +) + +// ResponseObject +// @description: 响应对象 +type ResponseObject struct { + // 响应结果的状态值 + Code resultStatus.StatusCode + + // Status 状态 + Status int32 + + // 响应结果的状态值所对应的描述信息 + Message string + + // 响应结果的数据 + Value interface{} +} + +// SetResultStatus +// @description: 设置响应结果的状态值 +// parameter: +// @receiver this: this +// @rs: 响应结果的状态值 +// return: +// @*ResponseObject: 响应结果对象 +func (this *ResponseObject) SetResultStatus(rs resultStatus.ResultStatus) *ResponseObject { + this.Code = rs.Code() + this.Message = rs.Message() + + return this +} + +// SetData +// @description: 设置响应对象数据 +// parameter: +// @receiver this: this +// @data: 响应结果的数据 +// return: +// @*ResponseObject: 响应结果对象 +func (this *ResponseObject) SetData(data interface{}) *ResponseObject { + this.Value = data + return this +} + +// IsSuccess +// @description: 是否是请求成功 +// parameter: +// @receiver this:this +// return: +// @bool:是请求成功 +func (this *ResponseObject) IsSuccess() bool { + return this.Code == resultStatus.Success.Code() +} + +// SetCodeStatus +// @description: 同步code和status状态 +// parameter: +// @receiver this:this +// return: +func (this *ResponseObject) SetCodeStatus() { + if this.Code == resultStatus.Success.Code() && resultStatus.StatusCode(this.Status) != resultStatus.Success.Code() { + this.Code = resultStatus.StatusCode(this.Status) + } + + return +} + +// GetInitResponseObj +// @description: 获取初始的响应对象 +// parameter: +// return: +// @*ResponseObject: 响应对象 +func GetInitResponseObj() *ResponseObject { + return &ResponseObject{ + Code: resultStatus.Success.Code(), + Message: "", + Value: nil, + } +} diff --git a/.svn/pristine/35/35d65336c7541bc544702d797fcbda5918ed0177.svn-base b/.svn/pristine/35/35d65336c7541bc544702d797fcbda5918ed0177.svn-base new file mode 100644 index 0000000..9363eea --- /dev/null +++ b/.svn/pristine/35/35d65336c7541bc544702d797fcbda5918ed0177.svn-base @@ -0,0 +1,57 @@ +package managecenterModel + +import ( + . "goutil/mysqlUtil" + . "goutil/redisUtil" +) + +// 数据库连接字符串配置 +type DBConnectionConfig struct { + // 模型数据库内网连接字符串 + GameModelDB string + + // 游戏数据库内网连接字符串 + GameDB string + + // 日志数据库内网连接字符串 + LogDB string + + // Redis连接字符串 + RedisConfig string +} + +// 获取游戏模型数据库连接 +// 返回值: +// 数据库连接配置对象 +// 错误对象 +func (this *DBConnectionConfig) GetGameModelDBConn() (dbConfig *DBConfig, err error) { + dbConfig, err = NewDBConfig2(this.GameModelDB) + return +} + +// 获取游戏数据库连接 +// 返回值: +// 数据库连接配置对象 +// 错误对象 +func (this *DBConnectionConfig) GetGameDBConn() (dbConfig *DBConfig, err error) { + dbConfig, err = NewDBConfig2(this.GameDB) + return +} + +// 获取游戏日志数据库连接 +// 返回值: +// 数据库连接配置对象 +// 错误对象 +func (this *DBConnectionConfig) GetLogDBConn() (dbConfig *DBConfig, err error) { + dbConfig, err = NewDBConfig2(this.LogDB) + return +} + +// 获取Redis配置 +// 返回值: +// redis配置对象 +// 错误对象 +func (this *DBConnectionConfig) GetRedisConfig() (redisConfig *RedisConfig, err error) { + redisConfig, err = NewRedisConfig(this.RedisConfig) + return +} diff --git a/.svn/pristine/36/368ca45601698339d1c23760a5460bde5c1412b5.svn-base b/.svn/pristine/36/368ca45601698339d1c23760a5460bde5c1412b5.svn-base new file mode 100644 index 0000000..c1ed7b6 --- /dev/null +++ b/.svn/pristine/36/368ca45601698339d1c23760a5460bde5c1412b5.svn-base @@ -0,0 +1,221 @@ +/* +未实现的哈希表方法: +MOVE、SCAN、SORT、FLUSHDB、FLUSHALL、SELECT、SWAPDB +*/ +package redisUtil + +import ( + "github.com/gomodule/redigo/redis" +) + +/* +EXISTS key +可用版本: >= 1.0.0 +时间复杂度: O(1) +检查给定 key 是否存在。 + +返回值 +若 key 存在,返回 1 ,否则返回 0 。 +*/ +func (this *RedisPool) Exists(key string) (exist bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + var result int + result, err = redis.Int(conn.Do("EXISTS", key)) + if err != nil { + return + } + + if result == 1 { + exist = true + } + + return +} + +/* +TYPE key +可用版本: >= 1.0.0 +时间复杂度: O(1) +返回 key 所储存的值的类型。 + +返回值 +none (key不存在) + +string (字符串) + +list (列表) + +set (集合) + +zset (有序集) + +hash (哈希表) + +stream (流) +*/ +func (this *RedisPool) Type(key string) (_type string, err error) { + conn := this.GetConnection() + defer conn.Close() + + _type, err = redis.String(conn.Do("TYPE", key)) + return +} + +/* +RENAME key newkey + +将 key 改名为 newkey 。 + +当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。 + +当 newkey 已经存在时, RENAME 命令将覆盖旧值。 + +可用版本: +>= 1.0.0 +时间复杂度: +O(1) +返回值: +改名成功时提示 OK ,失败时候返回一个错误。 +*/ +func (this *RedisPool) Rename(key, newkey string) (err error) { + conn := this.GetConnection() + defer conn.Close() + + _, err = conn.Do("RENAME", key, newkey) + return +} + +/* +RENAMENX key newkey + +当且仅当 newkey 不存在时,将 key 改名为 newkey 。 + +当 key 不存在时,返回一个错误。 + +可用版本: +>= 1.0.0 +时间复杂度: +O(1) +返回值: +修改成功时,返回 1 。 +如果 newkey 已经存在,返回 0 。 +*/ +func (this *RedisPool) RenameNX(key, newkey string) (successful bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + var result int + result, err = redis.Int(conn.Do("RENAMENX", key, newkey)) + if err != nil { + return + } + + if result == 1 { + successful = true + } + + return +} + +/* +DEL key [key ...] + +删除给定的一个或多个 key 。 + +不存在的 key 会被忽略。 + +可用版本: +>= 1.0.0 +时间复杂度: +O(N), N 为被删除的 key 的数量。 +删除单个字符串类型的 key ,时间复杂度为O(1)。 +删除单个列表、集合、有序集合或哈希表类型的 key ,时间复杂度为O(M), M 为以上数据结构内的元素数量。 +返回值: +被删除 key 的数量。 +*/ +func (this *RedisPool) Del(keys ...string) (count int, err error) { + conn := this.GetConnection() + defer conn.Close() + + count, err = redis.Int(conn.Do("DEL", redis.Args{}.AddFlat(keys)...)) + return +} + +/* +从当前数据库中随机返回(不删除)一个 key 。 + +可用版本: +>= 1.0.0 +时间复杂度: +O(1) +返回值: +当数据库不为空时,返回一个 key 。 +当数据库为空时,返回 nil 。 +*/ +func (this *RedisPool) RandomKey() (key string, exist bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + var reply interface{} + reply, err = conn.Do("RANDOMKEY") + if err != nil { + return + } + if reply == nil { + return + } + + key, err = redis.String(reply, err) + if err != nil { + return + } + + exist = true + return +} + +/* +DBSIZE +可用版本: >= 1.0.0 +时间复杂度: O(1) +返回当前数据库的 key 的数量。 + +返回值 +当前数据库的 key 的数量。 +*/ +func (this *RedisPool) DBSize() (keyCount int, err error) { + conn := this.GetConnection() + defer conn.Close() + + keyCount, err = redis.Int(conn.Do("DBSIZE")) + return +} + +/* +KEYS pattern + +查找所有符合给定模式 pattern 的 key 。 + +KEYS * 匹配数据库中所有 key 。 +KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 +KEYS h*llo 匹配 hllo 和 heeeeello 等。 +KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。 +特殊符号用 \ 隔开 + +KEYS 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 key ,你最好还是用 Redis 的集合结构(set)来代替。 +可用版本: +>= 1.0.0 +时间复杂度: +O(N), N 为数据库中 key 的数量。 +返回值: +符合给定模式的 key 列表。 +*/ +func (this *RedisPool) Keys(pattern string) (keyList []string, err error) { + conn := this.GetConnection() + defer conn.Close() + + keyList, err = redis.Strings(conn.Do("KEYS", pattern)) + return +} diff --git a/.svn/pristine/36/36d0e387eafa0d8f7a60cec4a9b30a2133bcc6bb.svn-base b/.svn/pristine/36/36d0e387eafa0d8f7a60cec4a9b30a2133bcc6bb.svn-base new file mode 100644 index 0000000..5808105 --- /dev/null +++ b/.svn/pristine/36/36d0e387eafa0d8f7a60cec4a9b30a2133bcc6bb.svn-base @@ -0,0 +1,409 @@ +package coroutine_timer + +import ( + "fmt" + "math" + "time" + + "goutil/logUtil" + "goutil/stringUtil" +) + +const ( + // 启动暂停时间 + con_STAR_SLEEP_NUM = 3 + + // 秒级定时器卡槽数量 + con_SECOND_SLOT_NUM = 60 + + //分钟级定时器卡槽数量 + con_MINUTES_SLOT_NUM = 60 +) + +var ( + // 秒级定时器下标 + secIndex = 0 + + // 秒级定时器当前开始时间 + secondStarTime int64 + + // 秒级定时器槽 + secondsTimers [con_SECOND_SLOT_NUM]*timersModel + + // 分钟级定时器下标 + minIndex = 0 + + // 分钟级定时器当前开始时间 + minStarTime int64 + + // 分钟级定时器槽 + minutesTimers [con_MINUTES_SLOT_NUM]*timersModel + + // 其他定时器存放槽 + otherTimers *timersModel + + // 操作通道 + cmdChan chan *cmdModel +) + +func init() { + for i := 0; i < con_SECOND_SLOT_NUM; i++ { + secondsTimers[i] = newTimersModel() + } + for i := 0; i < con_MINUTES_SLOT_NUM; i++ { + minutesTimers[i] = newTimersModel() + } + + otherTimers = newTimersModel() + cmdChan = make(chan *cmdModel, 1000) + secondStarTime = time.Now().Unix() + minStarTime = secondStarTime + con_SECOND_SLOT_NUM + + go chanHandler() +} + +// AddTimer +// @description: 添加定时回调 +// parameter: +// +// @afterSecond:延后多少时间执行 +// @exfun:执行方法 +// @obj:执行传入的参数 +// +// return: +// +// @string: +func AddTimer(afterSecond int, exfun func(interface{}), obj interface{}) string { + tick := time.Now().Unix() + int64(afterSecond) + return AddTimer3(tick, exfun, obj) +} + +// AddTimer2 +// @description: 添加定时回调 +// parameter: +// +// @t:执行时间点 +// @exfun:执行方法 +// @obj:执行传入的参数 +// +// return: +// +// @string: +func AddTimer2(t time.Time, exfun func(interface{}), obj interface{}) string { + tick := t.Unix() + return AddTimer3(tick, exfun, obj) +} + +// AddTimer3 +// @description: 添加定时回调 +// parameter: +// +// @tick:执行时间点 +// @exfun:执行方法 +// @obj:执行传入的参数 +// +// return: +// +// @newId: +func AddTimer3(tick int64, exfun func(interface{}), obj interface{}) (newId string) { + newId = stringUtil.GetNewUUID() + newObj := newTimerObj(newId, tick, exfun, obj) + + cnm := newCmdModel(cmd_add, newObj) + cmdChan <- cnm + + return +} + +// AddTimer4 +// @description: 添加定时回调(此方法会在内部校验id,所以性能会比其他AddTimer方法低) +// parameter: +// +// @id:定时id(外部需要自行保证id唯一) +// @tick:执行时间点 +// @exfun:执行方法 +// @obj:执行传入的参数 +// +// return: +// +// @err: +func AddTimer4(id string, tick int64, exfun func(interface{}), obj interface{}) (err error) { + newObj := newTimerObj(id, tick, exfun, obj) + newObj.needCheckId = true + + // 加入处理队列 + cnm := newCmdModel(cmd_add, newObj) + cmdChan <- cnm + + // 等待处理结束 + <-cnm.waitChan + + // 返回处理结果 + err = cnm.err + + return +} + +// DeleteTimer +// @description: 删除定时器 +// parameter: +// +// @id: +// +// return: +func DeleteTimer(id string) { + cnm := newCmdModel(cmd_del, id) + cmdChan <- cnm +} + +// chanHandler +// @description: channel处理 +// parameter: +// return: +func chanHandler() { + defer func() { + if err := recover(); err != nil { + logUtil.ErrorLog("coroutine-timer.excute err:%s", err) + } + }() + + // 暂停一下再处理,避免启动立即处理,其他数据还没准备好 + time.Sleep(con_STAR_SLEEP_NUM * time.Second) + + at := time.After(time.Second * 1) + for { + select { + case cm := <-cmdChan: + switch cm.cmd { + case cmd_add: + cmdAdd(cm) + case cmd_del: + cmdDel(cm) + } + case <-at: + // byron:需要处理时间后调导致跳时间的问题:调整后应该马上执行的 + + // 计算需要执行的次数 + n := time.Now().Unix() - secondStarTime - int64(secIndex) + if n > 0 { + + // 执行对应次数的方法 --- 正常应该只执行1此,调时间后,此处会追时间 + var i int64 + for i = 0; i < n; i++ { + cmdRun() + } + } + + at = time.After(time.Second * 1) + } + } +} + +// cmdAdd +// @description: 添加定时器 +// parameter: +// +// @cm: +// +// return: +func cmdAdd(cm *cmdModel) { + newObj := cm.paramObj.(*timerObj) + if newObj.needCheckId && checkTimerExist(newObj.id) { + cm.err = fmt.Errorf("已经存在id=%s的timer", newObj.id) + cm.waitChan <- struct{}{} + return + } + + // 如果执行时间比当前时间小,则放入最近的调度卡槽,以便尽快执行 + tick := newObj.tick + if tick <= (secondStarTime + int64(secIndex)) { + tick = (secondStarTime + int64(secIndex)) + 1 + } + + // 落在秒钟级别定时器上 + if tick < (secondStarTime + con_SECOND_SLOT_NUM) { + index := (int)(tick - secondStarTime) + secondsTimers[index].addTimer(newObj) + cm.waitChan <- struct{}{} + return + } + + // 落在分钟级别定时器上 + if tick < (minStarTime + con_MINUTES_SLOT_NUM*con_SECOND_SLOT_NUM) { + index := (int)(tick-minStarTime) / con_SECOND_SLOT_NUM + minutesTimers[index].addTimer(newObj) + cm.waitChan <- struct{}{} + return + } + + //落在小时级别定时器上 + otherTimers.addTimer(newObj) + + // 返回操作完成 + cm.waitChan <- struct{}{} +} + +// cmdDel +// @description: 删除timer +// parameter: +// +// @cm: +// +// return: +func cmdDel(cm *cmdModel) { + id := cm.paramObj.(string) + + // 移除秒级别定时器 + for _, item := range secondsTimers { + item.delTimer(id) + } + + // 移除分种级定时器 + for _, item := range minutesTimers { + item.delTimer(id) + } + + // 移除时钟级定时器 + otherTimers.delTimer(id) + + // 返回操作完成 + cm.waitChan <- struct{}{} +} + +// cmdRun +// @description: 运行定时器 +// parameter: +// return: +func cmdRun() { + defer func() { + if err := recover(); err != nil { + logUtil.ErrorLog("coroutine-timer.inExcute err:%s", err) + } + }() + + // 执行秒级定时器 + timers := getSencondTimers() + if len(timers) == 0 { + return + } + + for _, t := range timers { + go safeRun(t) + } +} + +// checkTimerExist +// @description: 校验timer是否存在 +// parameter: +// +// @id:id +// +// return: +// +// @bool: +func checkTimerExist(id string) bool { + // 秒级别定时器检测 + for _, item := range secondsTimers { + if item.exist(id) { + return true + } + } + + // 分种级定时器检测 + for _, item := range minutesTimers { + if item.exist(id) { + return true + } + } + + // 时钟级定时器检测 + return otherTimers.exist(id) +} + +// getSencondTimers +// @description: 获取秒级定时器 +// parameter: +// return: +// +// @result: +func getSencondTimers() (result []*timerObj) { + // 获取对应slot里面的定时对象 + result = secondsTimers[secIndex].getAllTimers2() + secondsTimers[secIndex] = newTimersModel() + secIndex++ + + // 如果达到最大,则重新填装新的调度对象 + if secIndex == con_SECOND_SLOT_NUM { + secIndex = 0 + secondStarTime = secondStarTime + con_SECOND_SLOT_NUM + minTaskList := getMinutesTasks() + for _, t := range minTaskList { + index := t.tick - secondStarTime + secondsTimers[index].addTimer(t) + } + } + + return +} + +// getMinutesTasks +// @description: 获取分钟级定时器 +// parameter: +// return: +// +// @result: +func getMinutesTasks() (result []*timerObj) { + // 获取对应slot里面的定时对象 + result = minutesTimers[minIndex].getAllTimers2() + minutesTimers[minIndex] = newTimersModel() + minIndex++ + + // 如果达到最大,则重新填装新的调度对象 + if minIndex == con_MINUTES_SLOT_NUM { + reInputMin() + } + + return +} + +// reInputMin +// @description: 重新填入分钟级定时器 +// parameter: +// return: +func reInputMin() { + minIndex = 0 + minStarTime = minStarTime + con_MINUTES_SLOT_NUM*con_SECOND_SLOT_NUM + + delMap := make(map[string]struct{}) + for _, t := range otherTimers.getAllTimers() { + index := (t.tick - minStarTime) / con_SECOND_SLOT_NUM + if index > math.MaxInt || index >= con_MINUTES_SLOT_NUM { + continue + } + minutesTimers[index].addTimer(t) + delMap[t.id] = struct{}{} + } + + if len(delMap) > 0 { + for k := range delMap { + otherTimers.delTimer(k) + } + } +} + +// safeRun +// @description: 安全运行定时器回调 +// parameter: +// +// @t: +// +// return: +func safeRun(t *timerObj) { + defer func() { + if err := recover(); err != nil { + logUtil.ErrorLog("coroutine-timer.safeRun id:%s err:%s", t.id, err) + } + }() + + t.excuteAction(t.paramObj) +} diff --git a/.svn/pristine/36/36dd2756b063ca1786642aa7e12792c0a26d104c.svn-base b/.svn/pristine/36/36dd2756b063ca1786642aa7e12792c0a26d104c.svn-base new file mode 100644 index 0000000..a947fe3 --- /dev/null +++ b/.svn/pristine/36/36dd2756b063ca1786642aa7e12792c0a26d104c.svn-base @@ -0,0 +1,16 @@ +#配置项说明 +log.es.enable=false #(false,默认值,关闭es日志记录,后续配置可不填写; true 打开日志记录) +log.es.url= #(es服务地址) +log.es.indexName=1 #(es服务中Index名) +log.es.level=info #(debug|info|warn|error|fatal等级,等于或高于配置项则记录) + +log.file.enable=false #(默认false) +log.file.path=log #(运行目录下log目录,默认logs) +log.file.pre=log #(文件名前缀,默认log) +log.file.enableHour=true #(文件以小时划分,格式:yyyyMMddHH,默认true,false 一天一个文件,格式:yyyyMMdd) +log.file.level=info + +log.console.enable=false #(默认false) +log.console.level=info + +modelcenter.modelDBConnStr=root:moqikaka3306@tcp(10.255.0.10:3306)/xj_model_mr?charset=utf8&parseTime=true&loc=Local&timeout=60s||MaxOpenConns=10||MaxIdleConns=5 #(model数据库信息) \ No newline at end of file diff --git a/.svn/pristine/37/370a9eae2ee1aaaeff3dcc4e23bb2a1391220586.svn-base b/.svn/pristine/37/370a9eae2ee1aaaeff3dcc4e23bb2a1391220586.svn-base new file mode 100644 index 0000000..0fcaa33 --- /dev/null +++ b/.svn/pristine/37/370a9eae2ee1aaaeff3dcc4e23bb2a1391220586.svn-base @@ -0,0 +1,19 @@ +package voicemsgMgr + +//语音配置参数 +type VoiceMessageConfig struct { + //API密钥Id + SecretId string + + //API密钥key + SecretKey string + + //地域 + Region string + + //模板ID + TemplateId string + + //应用后生成的实际SdkAppid + VoiceSdkAppid string +} diff --git a/.svn/pristine/37/374dfacb825adc910983b41ee6e2df86611ca117.svn-base b/.svn/pristine/37/374dfacb825adc910983b41ee6e2df86611ca117.svn-base new file mode 100644 index 0000000..bd36802 --- /dev/null +++ b/.svn/pristine/37/374dfacb825adc910983b41ee6e2df86611ca117.svn-base @@ -0,0 +1,193 @@ +package mailUtil + +import ( + "bytes" + "crypto/tls" + "encoding/base64" + "fmt" + "io/ioutil" + "net" + "net/mail" + "net/smtp" + "path/filepath" + "strings" +) + +// SMTPClient实现 +type simpleClient struct { + host string + port int + isSSL bool + + senderName string + senderAddr string + senderPwd string +} + +// 返回一个simpleClient作为SMTPClient接口 +func SimpleSMTPClient(_host string, _port int, _isSSL bool, + name, address, password string) SMTPClient { + + return &simpleClient{ + host: _host, + port: _port, + isSSL: _isSSL, + + senderName: name, + senderAddr: address, + senderPwd: password, + } +} + +func (this *simpleClient) SetServer(_host string, _port int, _isSSL bool) { + this.host = _host + this.port = _port + this.isSSL = _isSSL +} + +func (this *simpleClient) SetSender(name, address, password string) { + this.senderName = name + this.senderAddr = address + this.senderPwd = password +} + +//发送邮件: +// mailTo 接收方列表 +// subject 主题 +// body 正文 +// isHtmlBody 正文是否html格式 +// attachFiles 附件 +func (this *simpleClient) SendMail( + mailTo []string, + subject, body string, isHtmlBody bool, + attachFiles []string) (err error) { + + defer func() { + if r := recover(); r != nil { + err = r.(error) + } + }() + + // 创建连接 + var conn net.Conn + + if this.isSSL { + // TLS config + tlsconfig := &tls.Config{ + InsecureSkipVerify: true, + ServerName: this.host, + } + conn, err = tls.Dial("tcp", fmt.Sprintf("%s:%d", this.host, this.port), tlsconfig) + } else { + conn, err = net.Dial("tcp", fmt.Sprintf("%s:%d", this.host, this.port)) + } + if err != nil { + return err + } + defer conn.Close() + + // 创建smtp.Client + c, err := smtp.NewClient(conn, this.host) + if err != nil { + return err + } + + // 验证信息 + auth := smtp.PlainAuth("", this.senderAddr, this.senderPwd, this.host) + if err = c.Auth(auth); err != nil { + return err + } + + // 发送方 + from := mail.Address{this.senderName, this.senderAddr} + // 接收方 + to := make([]string, 0, len(mailTo)) + for _, v := range mailTo { + to = append(to, "<"+v+">") + } + + // To && From + if err = c.Mail(from.Address); err != nil { + return err + } + + for _, v := range mailTo { + if err = c.Rcpt(v); err != nil { + return err + } + } + + // 边界 + boundary := "a40acf3c8b7200fc6b04c2f1b3da" + + buff := bytes.NewBuffer(nil) + + // 写入基本信息 + buff.WriteString(fmt.Sprintf("From: %s\r\n", from.String())) + buff.WriteString(fmt.Sprintf("To: %s\r\n", strings.Join(to, ", "))) + buff.WriteString(fmt.Sprintf("Subject: %s\r\n", subject)) + + // 写入邮件头部信息 + if len(attachFiles) > 0 { + buff.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\r\n", boundary)) + + // 写入正文的边界信息 + buff.WriteString(fmt.Sprintf("\r\n--%s\r\n", boundary)) + } + + // 写入正文头部 + if isHtmlBody { + buff.WriteString(fmt.Sprintf("Content-Type: text/html; charset=\"utf-8\"\r\n")) + } else { + buff.WriteString(fmt.Sprintf("Content-Type: text/plain; charset=\"utf-8\"\r\n")) + } + buff.WriteString("\r\n") + // 写入正文内容 + buff.WriteString(body) + + if len(attachFiles) > 0 { + for _, file := range attachFiles { + fileBytes, err := ioutil.ReadFile(file) + if err != nil { + return err + } + + _, fileName := filepath.Split(file) + + // 写入文件信息 + buff.WriteString(fmt.Sprintf("\r\n\r\n--%s\r\n", boundary)) + buff.WriteString("Content-Type: application/octet-stream\r\n") + buff.WriteString("Content-Transfer-Encoding: base64\r\n") + buff.WriteString(fmt.Sprintf("Content-Disposition: attachment; filename=\"%s\"\r\n\r\n", fileName)) + + // 写入文件数据 + b := make([]byte, base64.StdEncoding.EncodedLen(len(fileBytes))) + base64.StdEncoding.Encode(b, fileBytes) + buff.Write(b) + } + + // 写入结束标识 + buff.WriteString(fmt.Sprintf("\r\n--%s--", boundary)) + } + + // Data + w, err := c.Data() + if err != nil { + return err + } + + // 写入邮件数据 + _, err = w.Write(buff.Bytes()) + if err != nil { + return err + } + + err = w.Close() + if err != nil { + return err + } + + c.Quit() + + return nil +} diff --git a/.svn/pristine/37/37b917300c968fc5f809e08ddcf2abcc2774fd2b.svn-base b/.svn/pristine/37/37b917300c968fc5f809e08ddcf2abcc2774fd2b.svn-base new file mode 100644 index 0000000..1de6919 --- /dev/null +++ b/.svn/pristine/37/37b917300c968fc5f809e08ddcf2abcc2774fd2b.svn-base @@ -0,0 +1,186 @@ +package xmlUtil + +import ( + "strings" + "testing" +) + +func findNode(root *Node, name string) *Node { + node := root.FirstChild + for { + if node == nil || node.NodeName == name { + break + } + node = node.NextSibling + } + return node +} + +func childNodes(root *Node, name string) []*Node { + var list []*Node + node := root.FirstChild + for { + if node == nil { + break + } + if node.NodeName == name { + list = append(list, node) + } + node = node.NextSibling + } + return list +} + +func testNode(t *testing.T, n *Node, expected string) { + if n.NodeName != expected { + t.Fatalf("expected node name is %s,but got %s", expected, n.NodeName) + } +} + +func testAttr(t *testing.T, n *Node, name, expected string) { + for _, attr := range n.Attr { + if attr.Name.Local == name && attr.Value == expected { + return + } + } + t.Fatalf("not found attribute %s in the node %s", name, n.NodeName) +} + +func testValue(t *testing.T, val, expected string) { + if val != expected { + t.Fatalf("expected value is %s,but got %s", expected, val) + } +} + +func TestParse(t *testing.T) { + s := ` + + + Harry Potter + 29.99 + + + Learning XML + 39.95 + +` + root, err := LoadFromReader(strings.NewReader(s)) + if err != nil { + t.Error(err) + } + if root.Type != DocumentNode { + t.Fatal("top node of tree is not DocumentNode") + } + + declarNode := root.FirstChild + if declarNode.Type != DeclarationNode { + t.Fatal("first child node of tree is not DeclarationNode") + } + + if declarNode.Attr[0].Name.Local != "version" && declarNode.Attr[0].Value != "1.0" { + t.Fatal("version attribute not expected") + } + + bookstore := root.LastChild + if bookstore.NodeName != "bookstore" { + t.Fatal("bookstore elem not found") + } + if bookstore.FirstChild.NodeName != "\n" { + t.Fatal("first child node of bookstore is not empty node(\n)") + } + books := childNodes(bookstore, "book") + if len(books) != 2 { + t.Fatalf("expected book element count is 2, but got %d", len(books)) + } + // first book element + testNode(t, findNode(books[0], "title"), "title") + testAttr(t, findNode(books[0], "title"), "lang", "en") + testValue(t, findNode(books[0], "price").InnerText(), "29.99") + testValue(t, findNode(books[0], "title").InnerText(), "Harry Potter") + + // second book element + testNode(t, findNode(books[1], "title"), "title") + testAttr(t, findNode(books[1], "title"), "lang", "en") + testValue(t, findNode(books[1], "price").InnerText(), "39.95") + + testValue(t, books[0].OutputXML(), `Harry Potter29.99`) +} + +func TestTooNested(t *testing.T) { + s := ` + + + + + + + + + + + + + + + + + + + ` + root, err := LoadFromReader(strings.NewReader(s)) + if err != nil { + t.Error(err) + } + aaa := findNode(root, "AAA") + if aaa == nil { + t.Fatal("AAA node not exists") + } + ccc := aaa.LastChild + if ccc.NodeName != "CCC" { + t.Fatalf("expected node is CCC,but got %s", ccc.NodeName) + } + bbb := ccc.PrevSibling + if bbb.NodeName != "BBB" { + t.Fatalf("expected node is bbb,but got %s", bbb.NodeName) + } + ddd := findNode(bbb, "DDD") + testNode(t, ddd, "DDD") + testNode(t, ddd.LastChild, "CCC") +} + +func TestSelectElement(t *testing.T) { + s := ` + + + + + + + + + ` + root, err := LoadFromReader(strings.NewReader(s)) + if err != nil { + t.Error(err) + } + version, _ := root.FirstChild.SelectAttr("version") + if version != "1.0" { + t.Fatal("version!=1.0") + } + aaa := findNode(root, "AAA") + var n *Node + n = aaa.SelectElement("BBB") + if n == nil { + t.Fatalf("n is nil") + } + n = aaa.SelectElement("CCC") + if n == nil { + t.Fatalf("n is nil") + } + + var ns []*Node + ns = aaa.SelectElements("CCC") + if len(ns) != 2 { + t.Fatalf("len(ns)!=2") + } +} diff --git a/.svn/pristine/37/37be33c1543987b2fc1e5ad1e0041ffbbef1231f.svn-base b/.svn/pristine/37/37be33c1543987b2fc1e5ad1e0041ffbbef1231f.svn-base new file mode 100644 index 0000000..cd7f37e --- /dev/null +++ b/.svn/pristine/37/37be33c1543987b2fc1e5ad1e0041ffbbef1231f.svn-base @@ -0,0 +1,6 @@ +package reloadMgr + +// 重新加载包,提供重新加载的功能 +// 使用方法: +// 1、先调用RegisterReloadFunc方法,将重新加载时需要调用的方法进行注册。 +// 2、在需要重新加载时调用Reload()方法 diff --git a/.svn/pristine/37/37e94747cff7c5629f6a5f38855e9ad2891bca8e.svn-base b/.svn/pristine/37/37e94747cff7c5629f6a5f38855e9ad2891bca8e.svn-base new file mode 100644 index 0000000..9b8a118 --- /dev/null +++ b/.svn/pristine/37/37e94747cff7c5629f6a5f38855e9ad2891bca8e.svn-base @@ -0,0 +1,208 @@ +package ensureSendUtil + +import ( + "encoding/binary" + "fmt" + "net" + "sync" + "time" + + "goutil/intAndBytesUtil" + "goutil/logUtil" +) + +var ( + errConnectEmpty = fmt.Errorf("scoket reconnecting...") + byterOrder = binary.LittleEndian +) + +// 实现 EnsureSender和sender接口 +type tcpSender struct { + // 需要实现的接口 + EnsureSender + + // 包含sender接口部分实现 + *baseSender + + // 数据目录 + dataFolder string + + // 服务器地址 + address string + + // 连接 + conn net.Conn + + // 用于重连时互斥 + mutex sync.Mutex + + // 用于sendLoop和resendLoop发送退出信号 + closeSignal chan struct{} +} + +// 创建一个tcp数据发送器 +// 参数: +// +// _dataFolder 数据存放目录 +// _address 连接地址 +func NewTCPSender(_dataFolder, _address string) (EnsureSender, error) { + // 连接服务器 + conn, err := net.DialTimeout("tcp", _address, 5*time.Second) + if err != nil { + return nil, err + } + + this := &tcpSender{ + dataFolder: _dataFolder, + baseSender: newBaseSender(), + address: _address, + conn: conn, + closeSignal: make(chan struct{}), + } + + // 新开协程发送数据 + go sendLoop(this, this.closeSignal) + + // 定时重发 + go resendLoop(this, _dataFolder, this.closeSignal) + + // 发送心跳包 + go this.heartBeat() + + return this, nil +} + +// 每隔15秒发送心跳包 +func (this *tcpSender) heartBeat() { + defer func() { + if r := recover(); r != nil { + logUtil.LogUnknownError(r) + } + }() + + tick := time.Tick(time.Second * 15) + + for { + select { + case <-this.Done(): + return + case <-tick: + this.sendBytes([]byte{}) + } + } +} + +// EnsureSender接口 +// Write:写入数据 +func (this *tcpSender) Write(data string) error { + item, err := newTCPDataItem(data) + if err != nil { + return err + } + + this.waitingDataChan <- item + + return nil +} + +// EnsureSender接口 +// Close:关闭 +func (this *tcpSender) Close() error { + close(this.done) + + // 关闭socket连接 + conn := this.conn + if conn != nil { + conn.Close() + } + + // 等待sendLoop和resendLoop退出 + <-this.closeSignal + <-this.closeSignal + + // 保存数据 + _, e1 := saveData(this.Cache(), this.dataFolder) + _, e2 := saveData(this.Data(), this.dataFolder) + + if e2 != nil { + if e1 != nil { + return fmt.Errorf("%s %s", e1, e2) + } + return e2 + } else { + return e1 + } +} + +// Sender接口 +// Send:发送dataItem +func (this *tcpSender) Send(item dataItem) error { + err := this.sendBytes(item.Bytes()) + if err != nil && err != errConnectEmpty { + // 发送失败时发送次数+1 + item.SetCount(item.Count() + 1) + } + + return err +} + +// 发送字节数据 +// 发送格式:[lenght+data] +func (this *tcpSender) sendBytes(data []byte) error { + conn := this.conn + if conn == nil { + return errConnectEmpty + } + + // 将长度转化为字节数组 + header := intAndBytesUtil.Int32ToBytes(int32(len(data)), byterOrder) + + if len(data) > 0 { + data = append(header, data...) + } else { + data = header + } + + _, err := conn.Write(data) + if err != nil { + this.mutex.Lock() + // 发送失败 + // 检查失败的conn是否this.conn(避免多个线程失败后均调用reconnect) + // 是则关闭并重连 + if conn == this.conn { + this.conn.Close() + this.conn = nil + this.mutex.Unlock() + + // 重连 + go this.reconnect() + } else { + this.mutex.Unlock() + } + } + + return err +} + +// 重连服务器 +func (this *tcpSender) reconnect() error { + // lock-it + this.mutex.Lock() + defer this.mutex.Unlock() + + for { + // 检查是否已经重连 + if this.conn != nil { + return nil + } + + conn, err := net.DialTimeout("tcp", this.address, 5*time.Second) + if err != nil { + // 连接失败,5秒后重试 + <-time.After(time.Second * 5) + continue + } + + this.conn = conn + } +} diff --git a/.svn/pristine/37/37fdb38c232c02a13b29a2b8ea947d48e87e0798.svn-base b/.svn/pristine/37/37fdb38c232c02a13b29a2b8ea947d48e87e0798.svn-base new file mode 100644 index 0000000..74e0625 --- /dev/null +++ b/.svn/pristine/37/37fdb38c232c02a13b29a2b8ea947d48e87e0798.svn-base @@ -0,0 +1,54 @@ +提供游戏内的实时排行榜功能,建议最大长度设定<=200 +使用方式: + +```go +package main + +import ( + rank_util "goutil/rank-util" +) + +func main() { + // 构造对象 + r := rank_util.NewRankUtil(20, compar) + + // 刷新排行榜 + m := &rmodel{k: "byrontest", Fap: 110} + ifChangeRank, dm := r.Refresh(m.k, m, true) + + // 获取全部排行榜 + tempList := r.GetAll() + + // 删除某个key + isok := r.Delete("byrontest") +} + +// compar +// @description: 判断对象大小,返回含义 -1:ab +// parameter: +// @a:对象a +// @b:对象b +// return: +// @int: +func compar(a, b interface{}) int { + af := a.(*rmodel).Fap + bf := b.(*rmodel).Fap + if af > bf { + return 1 + } else if af == bf { + return 0 + } else { + return -1 + } +} + +type rmodel struct { + k string + Fap int +} + +``` + + + + diff --git a/.svn/pristine/38/384faa85c664eb83dc8772b69254ad4263c18541.svn-base b/.svn/pristine/38/384faa85c664eb83dc8772b69254ad4263c18541.svn-base new file mode 100644 index 0000000..712fe6a --- /dev/null +++ b/.svn/pristine/38/384faa85c664eb83dc8772b69254ad4263c18541.svn-base @@ -0,0 +1,259 @@ +package stringUtil + +import ( + "testing" +) + +func TestStringToMap_String_String(t *testing.T) { + str := "" + seps := []string{",", "|"} + data, err := StringToMap_String_String(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3" + data, err = StringToMap_String_String(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3,5" + data, err = StringToMap_String_String(str, seps) + if err != nil { + t.Errorf("Expected to get no error. But now there is one:%v.", err) + return + } + + expected := make(map[string]string, 2) + expected["1"] = "2" + expected["3"] = "5" + + if len(expected) != len(data) { + t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data)) + return + } + + for k, v := range data { + if v1, exists := expected[k]; !exists { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } else if v != v1 { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } + } +} + +func TestStringToMap_String_Int(t *testing.T) { + str := "" + seps := []string{",", "|"} + data, err := StringToMap_String_Int(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3" + data, err = StringToMap_String_Int(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3,abc" + data, err = StringToMap_String_Int(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3,5" + data, err = StringToMap_String_Int(str, seps) + if err != nil { + t.Errorf("Expected to get no error. But now there is one:%v.", err) + return + } + + expected := make(map[string]int, 2) + expected["1"] = 2 + expected["3"] = 5 + + if len(expected) != len(data) { + t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data)) + return + } + + for k, v := range data { + if v1, exists := expected[k]; !exists { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } else if v != v1 { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } + } +} + +func TestStringToMap_Int_Int(t *testing.T) { + str := "" + seps := []string{",", "|"} + data, err := StringToMap_Int_Int(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3" + data, err = StringToMap_Int_Int(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3,abc" + data, err = StringToMap_Int_Int(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|a,3" + data, err = StringToMap_Int_Int(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3,5" + data, err = StringToMap_Int_Int(str, seps) + if err != nil { + t.Errorf("Expected to get no error. But now there is one:%v.", err) + return + } + + expected := make(map[int]int, 2) + expected[1] = 2 + expected[3] = 5 + + if len(expected) != len(data) { + t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data)) + return + } + + for k, v := range data { + if v1, exists := expected[k]; !exists { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } else if v != v1 { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } + } +} + +func TestStringToMap_Int32_Int32(t *testing.T) { + str := "" + seps := []string{",", "|"} + data, err := StringToMap_Int32_Int32(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3" + data, err = StringToMap_Int32_Int32(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3,abc" + data, err = StringToMap_Int32_Int32(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|a,3" + data, err = StringToMap_Int32_Int32(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3,5" + data, err = StringToMap_Int32_Int32(str, seps) + if err != nil { + t.Errorf("Expected to get no error. But now there is one:%v.", err) + return + } + + expected := make(map[int32]int32, 2) + expected[1] = 2 + expected[3] = 5 + + if len(expected) != len(data) { + t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data)) + return + } + + for k, v := range data { + if v1, exists := expected[k]; !exists { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } else if v != v1 { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } + } +} + +func TestStringToMap_Int32_Int64(t *testing.T) { + str := "" + seps := []string{",", "|"} + data, err := StringToMap_Int32_Int64(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3" + data, err = StringToMap_Int32_Int64(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|3,abc" + data, err = StringToMap_Int32_Int64(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,2|a,3" + data, err = StringToMap_Int32_Int64(str, seps) + if err == nil { + t.Errorf("Expected to get an error. But now there isn't.") + return + } + + str = "1,36524569852|3,365245698521" + data, err = StringToMap_Int32_Int64(str, seps) + if err != nil { + t.Errorf("Expected to get no error. But now there is one:%v.", err) + return + } + + expected := make(map[int32]int64, 2) + expected[1] = 36524569852 + expected[3] = 365245698521 + + if len(expected) != len(data) { + t.Errorf("The length of expected:%d is not equals to length of data:%d", len(expected), len(data)) + return + } + + for k, v := range data { + if v1, exists := expected[k]; !exists { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } else if v != v1 { + t.Errorf("data is not equals to expected. %v, %v", expected, data) + } + } +} diff --git a/.svn/pristine/39/39a09255683add574e0b3b1b5c7e521de4a47ad3.svn-base b/.svn/pristine/39/39a09255683add574e0b3b1b5c7e521de4a47ad3.svn-base new file mode 100644 index 0000000..62f5371 --- /dev/null +++ b/.svn/pristine/39/39a09255683add574e0b3b1b5c7e521de4a47ad3.svn-base @@ -0,0 +1,100 @@ +// ************************************ +// @package: websocketServer +// @description: websocket服务端 +// @author: +// @revision history: +// @create date: 2022-02-15 14:10:51 +// ************************************ +package websocketServer + +import ( + "github.com/gorilla/websocket" + webServer "Framework/webServer" + "time" +) + +type WsServer struct { + *webServer.HttpServer + + // websocket连接管理 + *connManager +} + +// RegisterWebsocketHandler +// @description: 注册websocket回调 +// parameter: +// +// @receiver ws: +// @path:注册的访问路径 +// @handlerFuncObj:回调方法 +// @configObj:Handler配置对象 +// +// return: +func (ws *WsServer) RegisterWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) { + ws.RegisterHandlerWithUserData(path, hookHandler, configObj, &userDatas{ + server: ws, + eventCallback: eventCallback, + }) +} + +// RegisterRegexWebsocketHandler +// @description: 注册正则websocket回调 +// parameter: +// +// @receiver wss: +// @path:注册的正则访问路径 +// @eventCallback:回调方法 +// @configObj:Handler配置对象 +// +// return: +func (ws *WsServer) RegisterRegexWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) { + ws.RegisterRegexHandlerWithUserData(path, hookHandler, configObj, &userDatas{ + server: ws, + eventCallback: eventCallback, + }) +} + +func NewWsServer(addr string, isCheckIP bool) (server *WsServer) { + server = &WsServer{ + HttpServer: webServer.NewHttpServer(addr, isCheckIP), + connManager: &connManager{ + upgrader: &websocket.Upgrader{}, + allConns: make(map[*websocket.Conn]*Context), + }, + } + + // 开启心跳检测协程 + server.connManager.heartbeatDetect() + + return +} + +func NewWsServer2(addr string, webServerObj webServer.IWebServer) (server *WsServer) { + server = &WsServer{ + HttpServer: webServer.NewHttpServer2(addr, webServerObj), + connManager: &connManager{ + upgrader: &websocket.Upgrader{}, + allConns: make(map[*websocket.Conn]*Context), + }, + } + + // 开启心跳检测协程 + server.connManager.heartbeatDetect() + + return +} + +func NewWsServer3(addr string, isCheckIP bool, readTimeout time.Duration, readHeaderTimeout time.Duration, writeTimeout time.Duration) (server *WsServer) { + server = &WsServer{ + HttpServer: webServer.NewHttpServer3(addr, isCheckIP, readTimeout, readHeaderTimeout, writeTimeout), + connManager: &connManager{ + upgrader: &websocket.Upgrader{}, + allConns: make(map[*websocket.Conn]*Context), + }, + } + + // 开启心跳检测协程 + server.connManager.heartbeatDetect() + + return +} diff --git a/.svn/pristine/3a/3aea22b2166c4d38707ec9cc9c910dd1e4ff2dd8.svn-base b/.svn/pristine/3a/3aea22b2166c4d38707ec9cc9c910dd1e4ff2dd8.svn-base new file mode 100644 index 0000000..8ff61f4 --- /dev/null +++ b/.svn/pristine/3a/3aea22b2166c4d38707ec9cc9c910dd1e4ff2dd8.svn-base @@ -0,0 +1,267 @@ +package mathUtil + +import ( + "fmt" + "testing" +) + +func TestIsContinuous_byte(t *testing.T) { + list := make([]byte, 0, 8) + if IsContinuous_byte(list) == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, 1) + if IsContinuous_byte(list) == false { + t.Errorf("it's should be true, but now false-------2") + } + + list = append(list, 2) + list = append(list, 3) + list = append(list, 4) + list = append(list, 5) + if IsContinuous_byte(list) == false { + t.Errorf("it's should be true, but now false-------3") + } + + list = append(list, 10) + if IsContinuous_byte(list) == true { + t.Errorf("it's should be false, but now true-------3") + } +} + +func TestIsContinuous_int(t *testing.T) { + list := make([]int, 0, 8) + if IsContinuous_int(list) == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, 11) + if IsContinuous_int(list) == false { + t.Errorf("it's should be true, but now false-------2") + } + + list = append(list, 12) + list = append(list, 13) + list = append(list, 14) + list = append(list, 15) + if IsContinuous_int(list) == false { + t.Errorf("it's should be true, but now false-------3") + } + + list = append(list, 10) + if IsContinuous_int(list) == true { + t.Errorf("it's should be false, but now true-------3") + } +} + +func TestIsContinuous_int32(t *testing.T) { + list := make([]int32, 0, 8) + if IsContinuous_int32(list) == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, 1) + if IsContinuous_int32(list) == false { + t.Errorf("it's should be true, but now false-------2") + } + + list = append(list, 2) + list = append(list, 3) + list = append(list, 4) + list = append(list, 5) + if IsContinuous_int32(list) == false { + t.Errorf("it's should be true, but now false-------3") + } + + list = append(list, 10) + if IsContinuous_int32(list) == true { + t.Errorf("it's should be false, but now true-------3") + } +} + +func TestIsContinuous_int64(t *testing.T) { + list := make([]int64, 0, 8) + if IsContinuous_int64(list) == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, 1) + if IsContinuous_int64(list) == false { + t.Errorf("it's should be true, but now false-------2") + } + + list = append(list, 2) + list = append(list, 3) + list = append(list, 4) + list = append(list, 5) + if IsContinuous_int64(list) == false { + t.Errorf("it's should be true, but now false-------3") + } + + list = append(list, 10) + if IsContinuous_int64(list) == true { + t.Errorf("it's should be false, but now true-------3") + } +} + +func TestIsContinuous_Region(t *testing.T) { + list := make([]*IntRegion, 0, 8) + if IsContinuous_Region(list) == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, NewIntRegion(101, 110)) + if IsContinuous_Region(list) == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, NewIntRegion(1, 10)) + if IsContinuous_Region(list) == true { + t.Errorf("it's should be false, but now true-------2") + } + + list = append(list, NewIntRegion(11, 100)) + if IsContinuous_Region(list) == false { + t.Errorf("it's should be true, but now false-------3") + } + +} + +func TestIsOddFullConvered(t *testing.T) { + list := make([]*IntRegion, 0, 8) + min, max := 1, 100 + if IsOddFullConvered(list, min, max) { + t.Errorf("it's should be false, but now true-------1") + } + + list = append(list, NewIntRegion(1, 10)) + if IsOddFullConvered(list, min, max) == true { + t.Errorf("it's should be false, but now true-------2") + } + + list = append(list, NewIntRegion(11, 100)) + if IsOddFullConvered(list, min, max) == false { + t.Errorf("it's should be true, but now false-------1") + } +} + +func TestIsDistinct_byte(t *testing.T) { + list := make([]byte, 0, 8) + result := IsDistinct_byte(list) + fmt.Printf("list:%v,result:%v-------1\n", list, result) + if result == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, 10) + result = IsDistinct_byte(list) + fmt.Printf("list:%v,result:%v-------2\n", list, result) + if result == false { + t.Errorf("it's should be true, but now false-------2") + } + + list = append(list, 10) + result = IsDistinct_byte(list) + fmt.Printf("list:%v,result:%v-------3\n", list, result) + if result { + t.Errorf("it's should be false, but now true-------3") + } + + list = append(list, 0) + result = IsDistinct_byte(list) + fmt.Printf("list:%v,result:%v-------4\n", list, result) + if result { + t.Errorf("it's should be false, but now true-------4") + } +} + +func TestIsDistinct_int(t *testing.T) { + list := make([]int, 0, 8) + result := IsDistinct_int(list) + fmt.Printf("list:%v,result:%v-------1\n", list, result) + if result == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, 10) + result = IsDistinct_int(list) + fmt.Printf("list:%v,result:%v-------2\n", list, result) + if result == false { + t.Errorf("it's should be true, but now false-------2") + } + + list = append(list, 10) + result = IsDistinct_int(list) + fmt.Printf("list:%v,result:%v-------3\n", list, result) + if result { + t.Errorf("it's should be false, but now true-------3") + } + + list = append(list, 0) + result = IsDistinct_int(list) + fmt.Printf("list:%v,result:%v-------4\n", list, result) + if result { + t.Errorf("it's should be false, but now true-------4") + } +} + +func TestIsDistinct_int32(t *testing.T) { + list := make([]int32, 0, 8) + result := IsDistinct_int32(list) + fmt.Printf("list:%v,result:%v-------1\n", list, result) + if result == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, 10) + result = IsDistinct_int32(list) + fmt.Printf("list:%v,result:%v-------2\n", list, result) + if result == false { + t.Errorf("it's should be true, but now false-------2") + } + + list = append(list, 10) + result = IsDistinct_int32(list) + fmt.Printf("list:%v,result:%v-------3\n", list, result) + if result { + t.Errorf("it's should be false, but now true-------3") + } + + list = append(list, 0) + result = IsDistinct_int32(list) + fmt.Printf("list:%v,result:%v-------4\n", list, result) + if result { + t.Errorf("it's should be false, but now true-------4") + } +} + +func TestIsDistinct_int64(t *testing.T) { + list := make([]int64, 0, 8) + result := IsDistinct_int64(list) + fmt.Printf("list:%v,result:%v-------1\n", list, result) + if result == false { + t.Errorf("it's should be true, but now false-------1") + } + + list = append(list, 10) + result = IsDistinct_int64(list) + fmt.Printf("list:%v,result:%v-------2\n", list, result) + if result == false { + t.Errorf("it's should be true, but now false-------2") + } + + list = append(list, 10) + result = IsDistinct_int64(list) + fmt.Printf("list:%v,result:%v-------3\n", list, result) + if result { + t.Errorf("it's should be false, but now true-------3") + } + + list = append(list, 0) + result = IsDistinct_int64(list) + fmt.Printf("list:%v,result:%v-------4\n", list, result) + if result { + t.Errorf("it's should be false, but now true-------4") + } +} diff --git a/.svn/pristine/3b/3bad0f0187ec9411b0df5744d9cd02879fa239f4.svn-base b/.svn/pristine/3b/3bad0f0187ec9411b0df5744d9cd02879fa239f4.svn-base new file mode 100644 index 0000000..df565f6 --- /dev/null +++ b/.svn/pristine/3b/3bad0f0187ec9411b0df5744d9cd02879fa239f4.svn-base @@ -0,0 +1,88 @@ +package logSqlSync + +import ( + "database/sql" + "fmt" + "time" + + "goutil/logUtil" +) + +// 错误信息记录表是否已经初始化 +var ifSyncErrorInfoTableInited bool = false + +// 同步的错误信息处理对象 +type syncErrorInfo struct { + // 数据库连接对象 + db *sql.DB +} + +// 初始化表信息 +func (this *syncErrorInfo) init() error { + // 初始化表结构 + if ifSyncErrorInfoTableInited == false { + err := this.initTable(this.db) + if err == nil { + ifSyncErrorInfoTableInited = true + } + + return err + } + + return nil +} + +// 把同步信息更新到数据库 +// data:待更新的数据 +// 返回值: +// error:错误信息 +func (this *syncErrorInfo) AddErrorSql(tran *sql.Tx, data string, errMsg string) error { + updateSql := "INSERT INTO `sync_error_info` (`SqlString`,`ExecuteTime`,`RetryCount`,`ErrMessage`) VALUES(?,?,?,?);" + + var err error + if tran != nil { + _, err = tran.Exec(updateSql, data, time.Now(), 0, errMsg) + } else { + _, err = this.db.Exec(updateSql, data, time.Now(), 0, errMsg) + } + + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncErrorInfo.AddErrorSql Error:%s", err.Error())) + } + + return err +} + +// 初始化同步信息表结构 +// db:数据库连接对象 +func (this *syncErrorInfo) initTable(db *sql.DB) error { + // 创建同步信息表 + createTableSql := `CREATE TABLE IF NOT EXISTS sync_error_info ( + Id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增Id', + SqlString varchar(1024) NOT NULL COMMENT '执行的sql', + ExecuteTime datetime NOT NULL COMMENT '最近一次执行时间', + RetryCount int NOT NULL COMMENT '重试次数', + ErrMessage text NULL COMMENT '执行错误的信息', + PRIMARY KEY (Id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='未执行成功的sql数据';` + if _, err := db.Exec(createTableSql); err != nil { + logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncErrorInfo.initTable Error:%s", err.Error())) + return err + } + + return nil +} + +// 创建同步信息对象 +// _db:数据库连接对象 +// 返回值: +// 同步信息对象 +func newSyncErrorInfoObject(_db *sql.DB) (result *syncErrorInfo, err error) { + result = &syncErrorInfo{ + db: _db, + } + + err = result.init() + + return result, err +} diff --git a/.svn/pristine/3c/3c161a0814b5fbe104eac0a7b7d76bf8dd007800.svn-base b/.svn/pristine/3c/3c161a0814b5fbe104eac0a7b7d76bf8dd007800.svn-base new file mode 100644 index 0000000..de20829 --- /dev/null +++ b/.svn/pristine/3c/3c161a0814b5fbe104eac0a7b7d76bf8dd007800.svn-base @@ -0,0 +1,56 @@ +package remark + +import ( + "common/httpServer" + "fmt" + "net/http" + + "common/webServer" +) + +// init +// @description: init +// parameter: +// return: +func init() { + webServer.RegisterRemarkFunc(remarkdCallback) + httpServer.RegisterRemarkFunc(remarkdCallback) +} + +// remarkdCallback +// @description: remarkdCallback +// parameter: +// @w: w +// @r: r +// return: +func remarkdCallback(w http.ResponseWriter, r *http.Request) { + + for index, moduleItem := range remarksSlice { + // 输出模块信息 + fmt.Fprintf(w, fmt.Sprintf("%d、%s【Name:%s Author:%s Mendor:%s Date:%s】\n", index+1, moduleItem.Desc, moduleItem.Name, moduleItem.Author, moduleItem.Mendor, moduleItem.Date)) + + // 输出方法列表信息 + for subIndex, methodItem := range moduleItem.MethodRemarkSlice { + fmt.Fprintf(w, fmt.Sprintf(" %d.%d、%s【Name:%s Author:%s Mendor:%s Date:%s】\n", index+1, subIndex+1, methodItem.Desc, methodItem.Name, methodItem.Author, methodItem.Mendor, methodItem.Date)) + + fmt.Fprintln(w, " \t输入参数:") + if len(methodItem.InParam) > 0 { + for _, param := range methodItem.InParam { + fmt.Fprintln(w, " ", param) + } + } else { + fmt.Fprintln(w, " ", "无") + } + + fmt.Fprintln(w, " \t输出参数:") + if methodItem.OutParam != "" { + fmt.Fprintln(w, " ", methodItem.OutParam) + } else { + fmt.Fprintln(w, " ", "无") + } + + fmt.Fprintln(w) + } + } + return +} diff --git a/.svn/pristine/3c/3ca8972a3836e96a64416fbbd2ebafdebd1fc2ab.svn-base b/.svn/pristine/3c/3ca8972a3836e96a64416fbbd2ebafdebd1fc2ab.svn-base new file mode 100644 index 0000000..3a149be --- /dev/null +++ b/.svn/pristine/3c/3ca8972a3836e96a64416fbbd2ebafdebd1fc2ab.svn-base @@ -0,0 +1,46 @@ +// ************************************ +// @package: handleMgr +// @description: 反射类-请求对象 +// @author: +// @revision history: +// @create date: 2022-02-23 16:33:53 +// ************************************ + +package handleMgr + +// RequestObject 请求对象 +type RequestObject struct { + // 请求的模块名称 + ModuleName string + + // 请求的方法名称 + MethodName string + + // 请求的参数数组 + Parameters []interface{} + + // 是否处理返回值 + IsHaveResult bool + + // 执行完成,返回chan监控 + ResultChan chan *ResponseObject +} + +// NewRequestObject +// @description: +// parameter: +// @moduleName:模块名名称 +// @methodName:执行方法名称 +// @parameters:方法参数 +// @isHaveResult:是否处理返回值 +// return: +// @*RequestObject: +func NewRequestObject(moduleName string, methodName string, parameters []interface{}, isHaveResult bool) *RequestObject { + return &RequestObject{ + ModuleName: moduleName, + MethodName: methodName, + Parameters: parameters, + IsHaveResult: isHaveResult, + ResultChan: make(chan *ResponseObject, 1), + } +} diff --git a/.svn/pristine/3e/3e543ef3da7294f5fed68348b9d711e4e403aeb2.svn-base b/.svn/pristine/3e/3e543ef3da7294f5fed68348b9d711e4e403aeb2.svn-base new file mode 100644 index 0000000..910b8dd Binary files /dev/null and b/.svn/pristine/3e/3e543ef3da7294f5fed68348b9d711e4e403aeb2.svn-base differ diff --git a/.svn/pristine/3f/3f2828af3b3e887131b06e7b527762a83a3c41db.svn-base b/.svn/pristine/3f/3f2828af3b3e887131b06e7b527762a83a3c41db.svn-base new file mode 100644 index 0000000..5fb3387 --- /dev/null +++ b/.svn/pristine/3f/3f2828af3b3e887131b06e7b527762a83a3c41db.svn-base @@ -0,0 +1,24 @@ +package ensureSendUtil + +type EnsureSender interface { + // use Write to send data + Write(string) error + + // stop sender + Close() error +} + +// resend和dataSaver通过此接口调用tcpSender与httpSender +type sender interface { + // 发送数据 + Send(dataItem) error + + // 返回待发送的数据channel + Data() <-chan dataItem + + // 返回失败数据缓存channel + Cache() chan dataItem + + // 用于判断是否关闭 + Done() <-chan struct{} +} diff --git a/.svn/pristine/40/405762ee5ebd4d12dbdf32a30bfb9bd84a970159.svn-base b/.svn/pristine/40/405762ee5ebd4d12dbdf32a30bfb9bd84a970159.svn-base new file mode 100644 index 0000000..67fd076 --- /dev/null +++ b/.svn/pristine/40/405762ee5ebd4d12dbdf32a30bfb9bd84a970159.svn-base @@ -0,0 +1,95 @@ +package bytesSendUtil + +import ( + "fmt" + "net" + "testing" + "time" + + "goutil/debugUtil" + "goutil/zlibUtil" +) + +// 保存接收的数据用于校验 +var tcp_recv_msg = make([]byte, 0) + +func init() { + debugUtil.SetDebug(true) +} + +// 创建socket服务器,保存收到的数据 +func server(addr string) net.Listener { + listener, err := net.Listen("tcp", addr) + if err != nil { + panic(err) + } + + go func() { + for { + conn, err := listener.Accept() + if err != nil { + return + } + + for { + buff := make([]byte, 512) + _, err := conn.Read(buff) + if err != nil { + break + } else { + decompressed, err := zlibUtil.Decompress(buff[4:]) + if err != nil { + panic(err) + } else { + tcp_recv_msg = append(tcp_recv_msg, decompressed...) + } + } + } + } + }() + + return listener +} + +func Test_tcp(t *testing.T) { + // 开启服务器 + l := server("127.0.0.1:9559") + + tcp, err := NewTCPSender("./test_tcp", "127.0.0.1:9559") + if err != nil { + t.Error(err) + } + + // 发送消息 + tcp.Write([]byte("tcp-msg-1")) + time.Sleep(time.Millisecond * 50) // 等待协程发送数据 + + // 关闭连接和服务器 + l.Close() + (tcp.(*tcpSender)).conn.Close() + + // 发送消息,此数据会失败 + tcp.Write([]byte("tcp-msg-2")) + // time.Sleep(time.Millisecond * 50) + + // 保存数据 + tcp.Close() + + // 重启,检查是否重发tcp-msg-2 + l = server("127.0.0.1:9559") + tcp, err = NewTCPSender("./test_tcp", "127.0.0.1:9559") + if err != nil { + t.Error(err) + } + + time.Sleep(time.Second * 2) + + if string(tcp_recv_msg) != "tcp-msg-1tcp-msg-2" { + t.Error("message error. got " + string(tcp_recv_msg)) + } else { + fmt.Println("TCP OK") + } + + tcp.Close() + l.Close() +} diff --git a/.svn/pristine/40/409acfe0b7a243190727cdff70cde0a7dcf33931.svn-base b/.svn/pristine/40/409acfe0b7a243190727cdff70cde0a7dcf33931.svn-base new file mode 100644 index 0000000..7e6917e --- /dev/null +++ b/.svn/pristine/40/409acfe0b7a243190727cdff70cde0a7dcf33931.svn-base @@ -0,0 +1,378 @@ +/* +我们使用腾讯云的CMQ作为公司的消息队列基础服务 +产品的说明文档:https://cloud.tencent.com/document/product/406 +*/ +package mqMgr + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + + . "Framework/mqMgr/model" + "goutil/webUtil" +) + +const ( + EMPTY_MESSAGE_ERROR = "消息为空" + EMPTY_HANDLE_ERROR = "句柄为空" + MIN_DELAY_SECONDS = 0 + MIN_POLLING_WAIT_SECONDS = 0 + MAX_POLLING_WAIT_SECONDS = 30 + MAX_BATCH_COUNT = 16 + EMPTY_BATCH_LIST_ERROR = "批量消息为空" + EXCEED_MAX_BATCH_COUNT_ERROR = "批量消息数量超过上限,最多为16条" +) + +// Queue对象 +type Queue struct { + // 地域 + region string + + // 网络类型:内网、外网 + network string + + // 队列名称 + queueName string + + // API密钥Id + secretId string + + // API密钥key + secretKey string +} + +// 执行操作 +func (this *Queue) action(requestObj IRequest, responseObj interface{}) error { + requestObj.SetCommonRequest(NewCommonRequest(requestObj.GetActionName(), this.region, this.secretId, this.queueName)) + + // 组装请求url + paramMap := requestObj.AssembleParamMap() + url, signature, err := AssembleUrl(this.region, this.network, MQ_TYPE_QUEUE, this.secretKey, paramMap) + if err != nil { + return err + } + paramMap["Signature"] = signature + + //请求url,请求头 + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, 10) + + statusCode, result, err := webUtil.PostMapData(url, paramMap, header, transport) + //statusCode, result, err := webUtil.PostMapData(url, paramMap, header, nil) + if err != nil { + return err + } + if statusCode != 200 { + return fmt.Errorf("Wrong status from server:%d", statusCode) + } + + // 解析请求结果 + err = json.Unmarshal(result, responseObj) + + return err +} + +// 处理发送消息延迟的时间 +func (this *Queue) handleDelaySeconds(delaySeconds int) int { + if delaySeconds < MIN_DELAY_SECONDS { + delaySeconds = MIN_DELAY_SECONDS + } + + return delaySeconds +} + +// 处理当没有消息是轮询等待的时间 +func (this *Queue) handlePollingWaitSeconds(pollingWaitSeconds int) int { + if pollingWaitSeconds < MIN_POLLING_WAIT_SECONDS { + pollingWaitSeconds = MIN_POLLING_WAIT_SECONDS + } else if pollingWaitSeconds > MAX_POLLING_WAIT_SECONDS { + pollingWaitSeconds = MAX_POLLING_WAIT_SECONDS + } + + return pollingWaitSeconds +} + +// 验证批量处理的列表 +func (this *Queue) validBatchList(list []string) error { + if list == nil || len(list) == 0 { + return errors.New(EMPTY_BATCH_LIST_ERROR) + } + if len(list) > MAX_BATCH_COUNT { + return errors.New(EXCEED_MAX_BATCH_COUNT_ERROR) + } + + return nil +} + +// error:错误对象 +func (this *Queue) GetQueueAttributes() (err error) { + // 逻辑处理 + requestObj := NewGetQueueAttributesRequest() + responseObj := NewGetQueueAttributesResponse() + + // 发送请求 + err = this.action(requestObj, &responseObj) + if err != nil { + return + } + + if responseObj.IsFailure() { + err = errors.New(responseObj.Message) + return + } + + return +} + +// SendMessage 发送单条消息 +// 参数 +// message:消息内容 +// delaySeconds:单位为秒,表示该消息发送到队列后,需要延时多久用户才可见该消息。 +// 返回值 +// error:错误对象 +func (this *Queue) SendMessage(message string, delaySeconds int) (err error) { + // 参数验证和处理 + if message == "" { + err = errors.New(EMPTY_MESSAGE_ERROR) + return + } + delaySeconds = this.handleDelaySeconds(delaySeconds) + + // 逻辑处理 + requestObj := NewSendMessageRequest(message, delaySeconds) + responseObj := NewSendMessageResponse() + + // 发送请求 + err = this.action(requestObj, &responseObj) + if err != nil { + return + } + + if responseObj.IsFailure() { + err = errors.New(responseObj.Message) + return + } + + return +} + +// BatchSendMessage 批量发送消息 +// 参数 +// messageList:消息内容列表 +// delaySeconds:单位为秒,表示该消息发送到队列后,需要延时多久用户才可见该消息。 +// 返回值 +// error:错误对象 +func (this *Queue) BatchSendMessage(messageList []string, delaySeconds int) (err error) { + // 参数验证和处理 + err = this.validBatchList(messageList) + if err != nil { + return + } + delaySeconds = this.handleDelaySeconds(delaySeconds) + + // 逻辑处理 + requestObj := NewBatchSendMessageRequest(messageList, delaySeconds) + responseObj := NewBatchSendMessageResponse() + + // 发送请求 + err = this.action(requestObj, &responseObj) + if err != nil { + return + } + + if responseObj.IsFailure() { + err = errors.New(responseObj.Message) + return + } + + return +} + +// Receive 消费单条消息 +// pollingWaitSeconds:本次请求的长轮询等待时间。取值范围0 - 30秒,如果不设置该参数,则默认使用队列属性中的 pollingWaitSeconds 值。 +// 返回值 +// receiptHandle:消息句柄 +// message:消息内容 +// exist:是否存在数据 +// err:错误对象 +func (this *Queue) ReceiveMessage(pollingWaitSeconds int) (receiptHandle, message string, exist bool, err error) { + // 参数验证和处理 + pollingWaitSeconds = this.handlePollingWaitSeconds(pollingWaitSeconds) + + // 逻辑处理 + requestObj := NewReceiveMessageRequest(pollingWaitSeconds) + responseObj := NewReceiveMessageResponse() + + // 发送请求 + err = this.action(requestObj, &responseObj) + if err != nil { + return + } + + // 忽略掉没有消息的错误 + if responseObj.HaveNoMessage() { + return + } + + if responseObj.IsFailure() { + err = errors.New(responseObj.Message) + return + } + + receiptHandle = responseObj.ReceiptHandle + message = responseObj.MsgBody + exist = true + + return +} + +// BatchReceiveMessage 批量消费消息 +// 参数 +// numOfMsg:本次消费的消息数量 +// pollingWaitSeconds:本次请求的长轮询等待时间。取值范围0 - 30秒,如果不设置该参数,则默认使用队列属性中的 pollingWaitSeconds 值。 +// 返回值 +// receiptHandleList:消息句柄列表 +// messageList:消息内容列表 +// exist:是否存在数据 +// err:错误对象 +func (this *Queue) BatchReceiveMessage(numOfMsg, pollingWaitSeconds int) (receiptHandleList, messageList []string, exist bool, err error) { + // 参数验证和处理 + if numOfMsg > MAX_BATCH_COUNT { + err = errors.New(EXCEED_MAX_BATCH_COUNT_ERROR) + return + } + pollingWaitSeconds = this.handlePollingWaitSeconds(pollingWaitSeconds) + + // 逻辑处理 + requestObj := NewBatchReceiveMessageRequest(numOfMsg, pollingWaitSeconds) + responseObj := NewBatchReceiveMessageResponse() + + // 发送请求 + err = this.action(requestObj, &responseObj) + if err != nil { + return + } + + // 忽略掉没有消息的错误 + if responseObj.HaveNoMessage() { + return + } + + if responseObj.IsFailure() { + err = errors.New(responseObj.Message) + return + } + + // 组装返回 + receiptHandleList = make([]string, 0, numOfMsg) + messageList = make([]string, 0, numOfMsg) + for _, msgInfo := range responseObj.MsgInfoList { + receiptHandleList = append(receiptHandleList, msgInfo.ReceiptHandle) + messageList = append(messageList, msgInfo.MsgBody) + } + exist = true + + return +} + +// DeleteMessage 删除单条消息 +// 参数 +// receiptHandle:消息句柄 +// 返回值 +// error:错误对象 +func (this *Queue) DeleteMessage(receiptHandle string) (err error) { + // 参数验证和处理 + if receiptHandle == "" { + err = errors.New(EMPTY_HANDLE_ERROR) + return + } + + // 逻辑处理 + requestObj := NewDeleteMessageRequest(receiptHandle) + responseObj := NewDeleteMessageResponse() + + // 发送请求 + err = this.action(requestObj, &responseObj) + if err != nil { + return err + } + + if responseObj.IsFailure() { + err = errors.New(responseObj.Message) + return + } + + return +} + +// BatchDeleteMessage 批量删除消息 +// 参数 +// receiptHandleList:消息句柄列表 +// 返回值 +// errorMap:删除错误的字典(key:删除失败的消息句柄;value:删除失败的原因) +// err:错误对象 +func (this *Queue) BatchDeleteMessage(receiptHandleList []string) (errorMap map[string]string, err error) { + // 参数验证和处理 + err = this.validBatchList(receiptHandleList) + if err != nil { + return + } + + // 逻辑处理 + requestObj := NewBatchDeleteMessageRequest(receiptHandleList) + responseObj := NewBatchDeleteMessageResponse() + + // 发送请求 + err = this.action(requestObj, &responseObj) + if err != nil { + return + } + + if responseObj.IsFailure() { + err = errors.New(responseObj.Message) + // 组装返回 + errorMap = make(map[string]string) + for _, errInfo := range responseObj.ErrorList { + errorMap[errInfo.ReceiptHandle] = errInfo.Message + } + return + } + + return +} + +// 创建新的Queue对象 +func NewQueue(region, queueName, secretId, secretKey string) *Queue { + queueConfigObj := &QueueConfig{ + Region: region, + QueueName: queueName, + SecretId: secretId, + SecretKey: secretKey, + } + + return NewQueueByConfig(queueConfigObj) +} + +// 通过队列配置对象创建新的Queue对象 +func NewQueueByConfig(queueConfigObj *QueueConfig) *Queue { + queueObj := &Queue{ + region: queueConfigObj.Region, + network: MQ_NETWORK_INTERNAL, + queueName: queueConfigObj.QueueName, + secretId: queueConfigObj.SecretId, + secretKey: queueConfigObj.SecretKey, + } + + err := queueObj.GetQueueAttributes() + if err != nil { + if strings.Contains(err.Error(), MQ_NETWORK_INTERNAL) { + queueObj.network = MQ_NETWORK_PUBLIC + } + } + + return queueObj +} diff --git a/.svn/pristine/41/414778273450f16557c41cc40bc68d5bca11839e.svn-base b/.svn/pristine/41/414778273450f16557c41cc40bc68d5bca11839e.svn-base new file mode 100644 index 0000000..5eb1109 --- /dev/null +++ b/.svn/pristine/41/414778273450f16557c41cc40bc68d5bca11839e.svn-base @@ -0,0 +1,109 @@ +package configUtil + +import ( + "encoding/json" + "fmt" + "io/ioutil" +) + +// 读取JSON格式的配置文件 +// config_file_path:配置文件路径 +// 返回值: +// 配置内容的map格式数组 +// 错误对象 +func ReadJsonConfig_Array(config_file_path string) ([]map[string]interface{}, error) { + // 读取配置文件(一次性读取整个文件,则使用ioutil) + bytes, err := ioutil.ReadFile(config_file_path) + if err != nil { + return nil, fmt.Errorf("读取配置文件的内容出错:%s", err) + } + + // 使用json反序列化 + config := make([]map[string]interface{}, 0, 4) + if err = json.Unmarshal(bytes, &config); err != nil { + return nil, fmt.Errorf("反序列化配置文件的内容出错:%s", err) + } + + return config, nil +} + +func getConfigValue(config []map[string]interface{}, configName string) (configValue interface{}, err error) { + var exist bool + for _, configItem := range config { + if configValue, exist = configItem[configName]; exist { + break + } + } + + if !exist { + err = fmt.Errorf("不存在名为%s的配置或配置为空", configName) + } + + return +} + +// 从config配置中获取int类型的配置值 +// config:从config文件中反序列化出来的map对象 +// configName:配置名称 +// 返回值: +// 配置值 +// 错误对象 +func ReadIntJsonValue_Array(config []map[string]interface{}, configName string) (value int, err error) { + configValue, err := getConfigValue(config, configName) + if err != nil { + return + } + + configValue_float, ok := configValue.(float64) + if !ok { + err = fmt.Errorf("%s必须为int型", configName) + return + } + value = int(configValue_float) + + return +} + +// 从config配置中获取string类型的配置值 +// config:从config文件中反序列化出来的map对象 +// configName:配置名称 +// 返回值: +// 配置值 +// 错误对象 +func ReadStringJsonValue_Array(config []map[string]interface{}, configName string) (value string, err error) { + configValue, err := getConfigValue(config, configName) + if err != nil { + return + } + + configValue_string, ok := configValue.(string) + if !ok { + err = fmt.Errorf("%s必须为string型", configName) + return + } + value = configValue_string + + return +} + +// 从config配置中获取string类型的配置值 +// config:从config文件中反序列化出来的map对象 +// configName:配置名称 +// 返回值: +// 配置值 +// 错误对象 +func ReadBoolJsonValue_Array(config []map[string]interface{}, configName string) (value bool, err error) { + configValue, err := getConfigValue(config, configName) + if err != nil { + return + } + + configValue_bool, ok := configValue.(bool) + if !ok { + err = fmt.Errorf("%s必须为bool型", configName) + return + } + value = configValue_bool + + return +} diff --git a/.svn/pristine/42/428d4b97237af34809acbd8293feabe883b1d689.svn-base b/.svn/pristine/42/428d4b97237af34809acbd8293feabe883b1d689.svn-base new file mode 100644 index 0000000..68d7660 --- /dev/null +++ b/.svn/pristine/42/428d4b97237af34809acbd8293feabe883b1d689.svn-base @@ -0,0 +1,37 @@ +package mathUtil + +import ( + "fmt" +) + +// 获取字节大小的描述信息 +// size:字节大小 +// 返回值: +// 描述信息 +func GetSizeDesc(size int64) string { + str := "" + + // 判断输入是否超过int64的范围 + if size < 0 || size > (1<<63-1) { + return str + } + + switch { + case size >= 1024*1024*1024*1024*1024*1024: + str = fmt.Sprintf("%.2fEB", float64(size)/1024/1024/1024/1024/1024/1024) + case size >= 1024*1024*1024*1024*1024: + str = fmt.Sprintf("%.2fPB", float64(size)/1024/1024/1024/1024/1024) + case size >= 1024*1024*1024*1024: + str = fmt.Sprintf("%.2fTB", float64(size)/1024/1024/1024/1024) + case size >= 1024*1024*1024: + str = fmt.Sprintf("%.2fGB", float64(size)/1024/1024/1024) + case size >= 1024*1024: + str = fmt.Sprintf("%dMB", size/1024/1024) + case size >= 1024: + str = fmt.Sprintf("%dKB", size/1024) + default: + str = fmt.Sprintf("%dB", size) + } + + return str +} diff --git a/.svn/pristine/43/431951efd695edc9cc00309e90205cafdb4ea415.svn-base b/.svn/pristine/43/431951efd695edc9cc00309e90205cafdb4ea415.svn-base new file mode 100644 index 0000000..ecfe708 --- /dev/null +++ b/.svn/pristine/43/431951efd695edc9cc00309e90205cafdb4ea415.svn-base @@ -0,0 +1,233 @@ +/* +未实现的哈希表方法: +MOVE、SCAN、SORT、FLUSHDB、FLUSHALL、SELECT、SWAPDB +*/ +package redisUtil + +import ( + "github.com/gomodule/redigo/redis" +) + +/* +EXPIRE key seconds +可用版本: >= 1.0.0 +时间复杂度: O(1) +为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。 + +在 Redis 中,带有生存时间的 key 被称为『易失的』(volatile)。 + +生存时间可以通过使用 DEL 命令来删除整个 key 来移除,或者被 SET 和 GETSET 命令覆写(overwrite),这意味着,如果一个命令只是修改(alter)一个带生存时间的 key 的值而不是用一个新的 key 值来代替(replace)它的话,那么生存时间不会被改变。 + +比如说,对一个 key 执行 INCR 命令,对一个列表进行 LPUSH 命令,或者对一个哈希表执行 HSET 命令,这类操作都不会修改 key 本身的生存时间。 + +另一方面,如果使用 RENAME 对一个 key 进行改名,那么改名后的 key 的生存时间和改名前一样。 + +RENAME 命令的另一种可能是,尝试将一个带生存时间的 key 改名成另一个带生存时间的 another_key ,这时旧的 another_key (以及它的生存时间)会被删除,然后旧的 key 会改名为 another_key ,因此,新的 another_key 的生存时间也和原本的 key 一样。 + +使用 PERSIST 命令可以在不删除 key 的情况下,移除 key 的生存时间,让 key 重新成为一个『持久的』(persistent) key 。 + +更新生存时间 +可以对一个已经带有生存时间的 key 执行 EXPIRE 命令,新指定的生存时间会取代旧的生存时间。 + +过期时间的精确度 +在 Redis 2.4 版本中,过期时间的延迟在 1 秒钟之内 —— 也即是,就算 key 已经过期,但它还是可能在过期之后一秒钟之内被访问到,而在新的 Redis 2.6 版本中,延迟被降低到 1 毫秒之内。 + +Redis 2.1.3 之前的不同之处 +在 Redis 2.1.3 之前的版本中,修改一个带有生存时间的 key 会导致整个 key 被删除,这一行为是受当时复制(replication)层的限制而作出的,现在这一限制已经被修复。 + +返回值 +设置成功返回 1 。 当 key 不存在或者不能为 key 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的生存时间),返回 0 。 +*/ +func (this *RedisPool) Expire(key string, seconds int64) (successful bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + var result int + if result, err = redis.Int(conn.Do("EXPIRE", key, seconds)); err != nil { + return + } + + if result == 1 { + successful = true + } + + return +} + +/* +EXPIREAT key timestamp +可用版本: >= 1.2.0 +时间复杂度: O(1) +EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置生存时间。 + +不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。 + +返回值 +如果生存时间设置成功,返回 1 ; 当 key 不存在或没办法设置生存时间,返回 0 。 +*/ +func (this *RedisPool) ExpireAt(key string, timestamp int64) (successful bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + var result int + if result, err = redis.Int(conn.Do("EXPIREAT", key, timestamp)); err != nil { + return + } + + if result == 1 { + successful = true + } + + return +} + +/* +TTL key +可用版本: >= 1.0.0 +时间复杂度: O(1) +以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 + +返回值 +当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间。 + +Note + +在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。 +*/ +func (this *RedisPool) TTL(key string) (ttl int64, exist, persisted bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + ttl, err = redis.Int64(conn.Do("TTL", key)) + if err != nil { + return + } + + if ttl == -2 { + exist = false + persisted = false + } else if ttl == -1 { + exist = true + persisted = true + } else { + exist = true + persisted = false + } + + return +} + +/* +PERSIST key +可用版本: >= 2.2.0 +时间复杂度: O(1) +移除给定 key 的生存时间,将这个 key 从“易失的”(带生存时间 key )转换成“持久的”(一个不带生存时间、永不过期的 key )。 + +返回值 +当生存时间移除成功时,返回 1 . 如果 key 不存在或 key 没有设置生存时间,返回 0 。 +*/ +func (this *RedisPool) Persist(key string) (successful bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + var result int + if result, err = redis.Int(conn.Do("PERSIST", key)); err != nil { + return + } + + if result == 1 { + successful = true + } + + return +} + +/* +PEXPIRE key milliseconds +可用版本: >= 2.6.0 +时间复杂度: O(1) +这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。 + +返回值 +设置成功,返回 1 key 不存在或设置失败,返回 0 +*/ +func (this *RedisPool) PExpire(key string, milliseconds int64) (successful bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + var result int + if result, err = redis.Int(conn.Do("PEXPIRE", key, milliseconds)); err != nil { + return + } + + if result == 1 { + successful = true + } + + return +} + +/* +PEXPIREAT key milliseconds-timestamp +可用版本: >= 2.6.0 +时间复杂度: O(1) +这个命令和 expireat 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像 expireat 那样,以秒为单位。 + +返回值 +如果生存时间设置成功,返回 1 。 当 key 不存在或没办法设置生存时间时,返回 0 。(查看 EXPIRE key seconds 命令获取更多信息) +*/ +func (this *RedisPool) PExpireAt(key string, milliseconds_timestamp int64) (successful bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + var result int + if result, err = redis.Int(conn.Do("PEXPIREAT", key, milliseconds_timestamp)); err != nil { + return + } + + if result == 1 { + successful = true + } + + return +} + +/* +PTTL key +可用版本: >= 2.6.0 +复杂度: O(1) +这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。 + +返回值 +当 key 不存在时,返回 -2 。 + +当 key 存在但没有设置剩余生存时间时,返回 -1 。 + +否则,以毫秒为单位,返回 key 的剩余生存时间。 + +Note + +在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。 +*/ +func (this *RedisPool) PTTL(key string) (pttl int64, exist bool, persisted bool, err error) { + conn := this.GetConnection() + defer conn.Close() + + pttl, err = redis.Int64(conn.Do("PTTL", key)) + if err != nil { + return + } + + if pttl == -2 { + exist = false + persisted = false + } else if pttl == -1 { + exist = true + persisted = true + } else { + exist = true + persisted = false + } + + return +} diff --git a/.svn/pristine/43/432489717638beef3ca372b2de090fd58b2e17d7.svn-base b/.svn/pristine/43/432489717638beef3ca372b2de090fd58b2e17d7.svn-base new file mode 100644 index 0000000..73b2ef9 --- /dev/null +++ b/.svn/pristine/43/432489717638beef3ca372b2de090fd58b2e17d7.svn-base @@ -0,0 +1,16 @@ +#!/bin/bash + +# 查找 adminServer 的 PID +PID=$(pgrep adminServer) + +if [ -z "$PID" ]; then + echo "adminServer 进程未找到" +else + echo "停止中... (PID: $PID)" + kill $PID + if [ $? -eq 0 ]; then + echo "adminServer 进程已终止 (PID: $PID)" + else + echo "无法终止 adminServer 进程 (PID: $PID)" + fi +fi diff --git a/.svn/pristine/43/4338e30fb77af67f2f9564918a01fa309f8f6815.svn-base b/.svn/pristine/43/4338e30fb77af67f2f9564918a01fa309f8f6815.svn-base new file mode 100644 index 0000000..2ace17a --- /dev/null +++ b/.svn/pristine/43/4338e30fb77af67f2f9564918a01fa309f8f6815.svn-base @@ -0,0 +1,52 @@ +package logUtil + +// ILog +// @description: 日志接口 +type ILog interface { + // InfoLog + // @description: 信息日志记录 + // parameter: + // @format:日志格式 + // @args:参数列表 + // return: + InfoLog(format string, args ...interface{}) + + // DebugLog + // @description: 调试日志记录 + // parameter: + // @format:日志格式 + // @args:参数列表 + // return: + DebugLog(format string, args ...interface{}) + + // WarnLog + // @description: 警告日志记录 + // parameter: + // @format:日志格式 + // @args:参数列表 + // return: + WarnLog(format string, args ...interface{}) + + // ErrorLog + // @description: 错误日志记录 + // parameter: + // @format:日志格式 + // @args:参数列表 + // return: + ErrorLog(format string, args ...interface{}) + + // FatalLog + // @description: 致命错误日志记录 + // parameter: + // @format:日志格式 + // @args:参数列表 + // return: + FatalLog(format string, args ...interface{}) + + // CloseLog + // @description: 关闭日志 + // parameter: + // @waitFinish:是否等待日志 + // return: + CloseLog(waitFinish bool) +} diff --git a/.svn/pristine/43/43442b142f5c5969f7878c2074d3b3ebe0f9c003.svn-base b/.svn/pristine/43/43442b142f5c5969f7878c2074d3b3ebe0f9c003.svn-base new file mode 100644 index 0000000..1fff6e6 --- /dev/null +++ b/.svn/pristine/43/43442b142f5c5969f7878c2074d3b3ebe0f9c003.svn-base @@ -0,0 +1,450 @@ +// ************************************ +// @package: websocketServer +// @description: websocket管理 +// @author: +// @revision history: +// @create date: 2022-02-18 15:38:17 +// ************************************ +package websocketServer + +import ( + "errors" + "github.com/gorilla/websocket" + routineCtrlUtil "goutil/routineCtrlUtil" + "sync" + "time" +) + +const ( + // 默认广播并发数 + con_DEFAULT_BROADCAST_CONCURRENT = 10 +) + +// connManager +// @description: websocket连接管理 +type connManager struct { + // 是否禁止新连接 + disableNewConn bool + + // 广播并发数 + broadcastConcurrent int + + // websocket服务端配置结构 + upgrader *websocket.Upgrader + + // 广播锁-限制 消息广播/关闭所有连接 并发访问 + muBroadcast sync.Mutex + + // 连接池map写锁(增加/删除) + muAllConns sync.Mutex + + // 连接池-所有已连接的websocket + allConns map[*websocket.Conn]*Context + + //------------------- + // 心跳控制 + + // 接收到Ping消息时,是否自动回复Pong + autuPong bool + + // 心跳周期 + heartbeatCycle time.Duration + + // 断连周期数(超过几个心跳周期即自动关闭连接);设置为0即关闭心跳检测功能 + heartbeatCloseCount int + + // 是否已开启心跳检测协程 + isHeartbeatDetectStart bool +} + +// heartbeatDetect +// @description: 开启心跳检测协程 +// parameter: +// +// @receiver connMgr: +// +// return: +func (connMgr *connManager) heartbeatDetect() { + // 限制每个websocket连接管理只开启一个心跳检测协程 + if !connMgr.isHeartbeatDetectStart { + connMgr.isHeartbeatDetectStart = true + + // 开启心跳检测协程 + go func() { + for { + if connMgr.heartbeatCloseCount <= 0 { + // 心跳检测功能已关闭;每秒检测此标志 + time.Sleep(time.Second) + continue + } + + // 心跳检测功能已开启 + + connMgr.muAllConns.Lock() // 连接池map锁 + ctxs_timeout := make([]*Context, 0, len(connMgr.allConns)) // 存放心跳超时,需要关闭的websocket环境 + for _, ctx := range connMgr.allConns { + if time.Since(ctx.heartbeat) > (connMgr.heartbeatCycle*time.Duration(connMgr.heartbeatCloseCount) + 1) { + // 心跳超时,需要关闭的websocket环境加入列表 + ctxs_timeout = append(ctxs_timeout, ctx) + } + } + connMgr.muAllConns.Unlock() // 连接池map及时解锁 + + // 关闭所有心跳超时的连接 + func() { + // 获取广播并发数 + broadcastConcurrent := connMgr.broadcastConcurrent + if broadcastConcurrent <= 0 { + broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT + } + + // 协程并发限制 + rtCtrl := routineCtrlUtil.New(broadcastConcurrent) + for _, ctx := range ctxs_timeout { + ctxTemp := ctx + rtCtrl.Run(func(arg interface{}) { + // 执行受限并发函数 + ctxTemp.Close() + }, nil) + } + + // 等待完成 + rtCtrl.Wait() + }() + + // 休眠半个心跳周期 + slpTime := time.Duration(connMgr.heartbeatCycle / 2) + if slpTime < time.Second { + slpTime = time.Second + } + time.Sleep(slpTime) + } + }() + } +} + +// upgrade +// @description: 升级为websocket +// parameter: +// +// @receiver connMgr: +// @ctx: websocket环境 +// +// return: +// +// @*websocket.Conn: 建立的连接对象 +// @error: +func (connMgr *connManager) upgrade(ctx *Context) (conn *websocket.Conn, err error) { + if connMgr.disableNewConn { + // 禁止新连接 + return nil, errors.New("connManager(disableNewConn)") + } + + // 建立websocket连接 + conn, err = connMgr.upgrader.Upgrade(ctx.GetWebServerContext().GetResponseWriter(), ctx.GetWebServerContext().GetRequest(), nil) + if err != nil { + return + } + + // 添加到连接池 + ctx.conn = conn + connMgr.addConn(conn, ctx) + + return +} + +// addConn +// @description: 添加到连接池 +// parameter: +// +// @receiver connMgr: +// @conn: +// @ctx: +// +// return: +func (connMgr *connManager) addConn(conn *websocket.Conn, ctx *Context) { + connMgr.muAllConns.Lock() + defer connMgr.muAllConns.Unlock() + + connMgr.allConns[conn] = ctx +} + +// delConn +// @description: 将连接从连接池删除 +// parameter: +// +// @receiver connMgr: +// @conn: +// +// return: +func (connMgr *connManager) delConn(conn *websocket.Conn) { + connMgr.muAllConns.Lock() + defer connMgr.muAllConns.Unlock() + + delete(connMgr.allConns, conn) +} + +// renewAllConnsMap +// @description: 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题 +// parameter: +// +// @receiver connMgr: +// +// return: +// +// @map[*websocket.Conn]*Context: 返回原内部使用的连接池(现内部已不再使用) +func (connMgr *connManager) renewAllConnsMap() map[*websocket.Conn]*Context { + connMgr.muAllConns.Lock() + defer connMgr.muAllConns.Unlock() + + // map拷贝 + allConnsCopy := make(map[*websocket.Conn]*Context, len(connMgr.allConns)) + for conn, ctx := range connMgr.allConns { + allConnsCopy[conn] = ctx + } + // map替换;因map删除时只是标记,并非真正删除,使用一段时间后可能会出现大量未使用信息;这里顺便更新一下map + connMgr.allConns, allConnsCopy = allConnsCopy, connMgr.allConns + + return allConnsCopy +} + +// SetBroadcastConcurrent +// @description: 设置广播并发数 +// parameter: +// +// @receiver connMgr: +// @n: 广播并发数 +// +// return: +func (connMgr *connManager) SetBroadcastConcurrent(n int) { + connMgr.broadcastConcurrent = n +} + +// EnableNewConn +// @description: 允许新连接 +// parameter: +// +// @receiver connMgr: +// +// return: +func (connMgr *connManager) EnableNewConn() { + connMgr.disableNewConn = false +} + +// DisableNewConn +// @description: 禁用新连接 +// parameter: +// +// @receiver connMgr: +// +// return: +func (connMgr *connManager) DisableNewConn() { + connMgr.disableNewConn = true +} + +// MulticastMessage +// @description: 多播消息(给指定多用户发送消息) +// parameter: +// +// @receiver connMgr: +// @ctxs: 指定多用户的*Context切片 +// @messageType: websocket类型 +// @data: 发送的数据 +// +// return: +// +// @err: 若有错误,则为最后一个错误 +func (connMgr *connManager) MulticastMessage(ctxs []*Context, messageType int, data []byte) (err error) { + // 广播锁,防重入 + connMgr.muBroadcast.Lock() + defer connMgr.muBroadcast.Unlock() + + // 获取广播并发数 + broadcastConcurrent := connMgr.broadcastConcurrent + if broadcastConcurrent <= 0 { + broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT + } + + // 协程并发限制 + rtCtrl := routineCtrlUtil.New(broadcastConcurrent) + var mu sync.Mutex + for _, ctx := range ctxs { + // 执行受限并发函数 + // 注意:这里的ctx需要使用参数传入Run;否则随时变化的ctx在闭包内使用时,会出现不符合程序要求逻辑的结果 + rtCtrl.Run(func(arg interface{}) { + ctxTemp, _ := arg.(*Context) + e := ctxTemp.SendMessage(messageType, data) + if e != nil { + mu.Lock() + err = e + mu.Unlock() + } + }, ctx) + } + + // 等待完成 + rtCtrl.Wait() + + return +} + +// BroadcastMessage +// @description: 消息广播 +// parameter: +// +// @receiver connMgr: +// @messageType: websocket类型 +// @data: 发送的数据 +// +// return: +// +// @err: 若有错误,则为最后一个错误 +func (connMgr *connManager) BroadcastMessage(messageType int, data []byte) (err error) { + // 广播锁,防重入 + connMgr.muBroadcast.Lock() + defer connMgr.muBroadcast.Unlock() + + // 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题 + allConnsCopy := connMgr.renewAllConnsMap() + + // 获取广播并发数 + broadcastConcurrent := connMgr.broadcastConcurrent + if broadcastConcurrent <= 0 { + broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT + } + + // 协程并发限制 + rtCtrl := routineCtrlUtil.New(broadcastConcurrent) + var mu sync.Mutex + for _, ctx := range allConnsCopy { + // 执行受限并发函数 + // 注意:这里的ctx需要使用参数传入Run;否则随时变化的ctx在闭包内使用时,会出现不符合程序要求逻辑的结果 + rtCtrl.Run(func(arg interface{}) { + ctxTemp, _ := arg.(*Context) + e := ctxTemp.SendMessage(messageType, data) + if e != nil { + mu.Lock() + err = e + mu.Unlock() + } + }, ctx) + } + + // 等待完成 + rtCtrl.Wait() + + return +} + +// CloseAll +// @description: 关闭所有连接 +// parameter: +// +// @receiver connMgr: +// +// return: +func (connMgr *connManager) CloseAll() { + // 广播锁,防重入 + connMgr.muBroadcast.Lock() + defer connMgr.muBroadcast.Unlock() + + // 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题 + allConnsCopy := connMgr.renewAllConnsMap() + + // 获取广播并发数 + broadcastConcurrent := connMgr.broadcastConcurrent + if broadcastConcurrent <= 0 { + broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT + } + + // 协程并发限制 + rtCtrl := routineCtrlUtil.New(broadcastConcurrent) + for _, ctx := range allConnsCopy { + rtCtrl.Run(func(arg interface{}) { + ctxTemp, _ := arg.(*Context) + // 执行受限并发函数 + ctxTemp.Close() + }, ctx) + } + + // 等待完成 + rtCtrl.Wait() +} + +// SetUpgrader +// @description: 设置websocket参数结构 +// parameter: +// +// @receiver connMgr: +// @upgrader: websocket中的websocket.Upgrader结构体指针(可以设置握手超时/读写缓存/是否允许跨域等) +// +// return: +func (connMgr *connManager) SetUpgrader(upgrader *websocket.Upgrader) { + connMgr.upgrader = upgrader +} + +// GetUpgrader +// @description: 获取websocket参数结构 +// parameter: +// +// @receiver connMgr: +// +// return: +// +// @*websocket.Upgrader: websocket中的websocket.Upgrader结构体指针(可以设置握手超时/读写缓存/是否允许跨域等) +func (connMgr *connManager) GetUpgrader() *websocket.Upgrader { + return connMgr.upgrader +} + +// SetAutoPong +// @description: 设置接收到Ping消息时,是否自动回复Pong信息 +// parameter: +// +// @receiver connMgr: +// @autuPong: +// +// return: +func (connMgr *connManager) SetAutoPong(autuPong bool) { + connMgr.autuPong = autuPong +} + +// GetAutoPong +// @description: 获取接收到Ping消息时,是否自动回复Pong信息 +// parameter: +// +// @receiver connMgr: +// +// return: +// +// @bool: +func (connMgr *connManager) GetAutoPong() bool { + return connMgr.autuPong +} + +// SetHeartbeatDetectInfo +// @description: 设置心跳检测信息 +// parameter: +// +// @receiver connMgr: +// @heartbeatCloseCount: 断连周期数(超过几个心跳周期即自动关闭连接);设置为0即关闭心跳检测功能 +// @heartbeatCycle: 心跳周期 +// +// return: +func (connMgr *connManager) SetHeartbeatDetectInfo(heartbeatCloseCount int, heartbeatCycle time.Duration) { + connMgr.heartbeatCycle = heartbeatCycle + connMgr.heartbeatCloseCount = heartbeatCloseCount +} + +// GetHeartbeatDetectInfo +// @description: 获取心跳检测信息 +// parameter: +// +// @receiver connMgr: +// +// return: +// +// @heartbeatCloseCount: 断连周期数(超过几个心跳周期即自动关闭连接) +// @heartbeatCycle: 心跳周期 +func (connMgr *connManager) GetHeartbeatDetectInfo() (heartbeatCloseCount int, heartbeatCycle time.Duration) { + return connMgr.heartbeatCloseCount, connMgr.heartbeatCycle +} diff --git a/.svn/pristine/43/4385e6c1186639ab7ed02dd5ccd2c781cf61b193.svn-base b/.svn/pristine/43/4385e6c1186639ab7ed02dd5ccd2c781cf61b193.svn-base new file mode 100644 index 0000000..890a77f --- /dev/null +++ b/.svn/pristine/43/4385e6c1186639ab7ed02dd5ccd2c781cf61b193.svn-base @@ -0,0 +1,46 @@ +package user + +import ( + "common/connection" + "goutil/logUtilPlus" +) + +// AddUser 添加用户 +// AddUser 添加新的用户到数据库中。 +// 参数 User: 包含用户信息的对象。 +// 返回值: 插入操作影响的行数和可能发生的错误。 +func AddUser(User *User) (int64, error) { + + //处理一些验证 + + // 写入到数据库 + result := connection.GetUserDB().Create(&User) // 通过数据的指针来创建 + + if result.Error != nil { + logUtilPlus.ErrorLog("添加用户失败 错误信息:", result.Error.Error()) + } + return User.ID, nil +} + +// GetUserByID 根据用户ID获取用户信息 +func GetUserByID(UserID int64) (*User, error) { + var User User + + //缓存判断等一些设置 + + result := connection.GetUserDB().First(&User, UserID) + if result.Error != nil { + return nil, result.Error + } + return &User, nil +} + +// 用户登录 +func Login(account string, password string) (*User, error) { + var User User + result := connection.GetUserDB().Where("account = ? AND password = ?", account, password).First(&User) + if result.Error != nil { + return nil, result.Error + } + return &User, nil +} diff --git a/.svn/pristine/43/4394e6533451632d39ca579614e8ddfbf9781d0f.svn-base b/.svn/pristine/43/4394e6533451632d39ca579614e8ddfbf9781d0f.svn-base new file mode 100644 index 0000000..33f6b30 --- /dev/null +++ b/.svn/pristine/43/4394e6533451632d39ca579614e8ddfbf9781d0f.svn-base @@ -0,0 +1,70 @@ +package intAndBytesUtil + +import ( + "encoding/binary" + "testing" +) + +func TestBytesToInt(t *testing.T) { + var givenBigEndian []byte = []byte{0, 0, 1, 0} + var givenLittleEndian []byte = []byte{0, 1, 0, 0} + var expectedInt int32 = 256 + + result := BytesToInt32(givenBigEndian, binary.BigEndian) + if result != expectedInt { + t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenBigEndian, result, expectedInt) + } + + result = BytesToInt32(givenLittleEndian, binary.LittleEndian) + if result != expectedInt { + t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenLittleEndian, result, expectedInt) + } +} + +func TestBytesToInt16(t *testing.T) { + var givenBigEndian []byte = []byte{1, 0} + var givenLittleEndian []byte = []byte{0, 1} + var expectedInt int16 = 256 + + result := BytesToInt16(givenBigEndian, binary.BigEndian) + if result != expectedInt { + t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenBigEndian, result, expectedInt) + } + + result = BytesToInt16(givenLittleEndian, binary.LittleEndian) + if result != expectedInt { + t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenLittleEndian, result, expectedInt) + } +} + +func TestBytesToInt32(t *testing.T) { + var givenBigEndian []byte = []byte{0, 0, 1, 0} + var givenLittleEndian []byte = []byte{0, 1, 0, 0} + var expectedInt int32 = 256 + + result := BytesToInt32(givenBigEndian, binary.BigEndian) + if result != expectedInt { + t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenBigEndian, result, expectedInt) + } + + result = BytesToInt32(givenLittleEndian, binary.LittleEndian) + if result != expectedInt { + t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenLittleEndian, result, expectedInt) + } +} + +func TestBytesToInt64(t *testing.T) { + var givenBigEndian []byte = []byte{0, 0, 0, 0, 0, 0, 1, 0} + var givenLittleEndian []byte = []byte{0, 1, 0, 0, 0, 0, 0, 0} + var expectedInt int64 = 256 + + result := BytesToInt64(givenBigEndian, binary.BigEndian) + if result != expectedInt { + t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenBigEndian, result, expectedInt) + } + + result = BytesToInt64(givenLittleEndian, binary.LittleEndian) + if result != expectedInt { + t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenLittleEndian, result, expectedInt) + } +} diff --git a/.svn/pristine/43/43a87b7137557b0aa604619fa267109dfadd8834.svn-base b/.svn/pristine/43/43a87b7137557b0aa604619fa267109dfadd8834.svn-base new file mode 100644 index 0000000..93600d2 --- /dev/null +++ b/.svn/pristine/43/43a87b7137557b0aa604619fa267109dfadd8834.svn-base @@ -0,0 +1,95 @@ +package ensureSendUtil + +import ( + "fmt" + "net" + "testing" + "time" + + "goutil/debugUtil" + "goutil/zlibUtil" +) + +// 保存接收的数据用于校验 +var tcp_recv_msg = make([]byte, 0) + +func init() { + debugUtil.SetDebug(true) +} + +// 创建socket服务器,保存收到的数据 +func server(addr string) net.Listener { + listener, err := net.Listen("tcp", addr) + if err != nil { + panic(err) + } + + go func() { + for { + conn, err := listener.Accept() + if err != nil { + return + } + + for { + buff := make([]byte, 512) + _, err := conn.Read(buff) + if err != nil { + break + } else { + decompressed, err := zlibUtil.Decompress(buff[4:]) + if err != nil { + panic(err) + } else { + tcp_recv_msg = append(tcp_recv_msg, decompressed...) + } + } + } + } + }() + + return listener +} + +func Test_tcp(t *testing.T) { + // 开启服务器 + l := server("127.0.0.1:9559") + + tcp, err := NewTCPSender("./test_tcp", "127.0.0.1:9559") + if err != nil { + t.Error(err) + } + + // 发送消息 + tcp.Write("tcp-msg-1") + time.Sleep(time.Millisecond * 50) // 等待协程发送数据 + + // 关闭连接和服务器 + l.Close() + (tcp.(*tcpSender)).conn.Close() + + // 发送消息,此数据会失败 + tcp.Write("tcp-msg-2") + // time.Sleep(time.Millisecond * 50) + + // 保存数据 + tcp.Close() + + // 重启,检查是否重发tcp-msg-2 + l = server("127.0.0.1:9559") + tcp, err = NewTCPSender("./test_tcp", "127.0.0.1:9559") + if err != nil { + t.Error(err) + } + + time.Sleep(time.Second * 2) + + if string(tcp_recv_msg) != "tcp-msg-1tcp-msg-2" { + t.Error("message error. got " + string(tcp_recv_msg)) + } else { + fmt.Println("TCP OK") + } + + tcp.Close() + l.Close() +} diff --git a/.svn/pristine/43/43f852c1515a55d48e5d25081f9210b9da4ff66c.svn-base b/.svn/pristine/43/43f852c1515a55d48e5d25081f9210b9da4ff66c.svn-base new file mode 100644 index 0000000..c119522 --- /dev/null +++ b/.svn/pristine/43/43f852c1515a55d48e5d25081f9210b9da4ff66c.svn-base @@ -0,0 +1,35 @@ +package esLogUtil + +import ( + "testing" + "time" +) + +func TestWrite(t *testing.T) { + Start("http://10.1.0.86:9200", "dzg_gs_log_gmc2", 20008) + for i := 0; i < 10000; i++ { + InfoLog("ES在线日志测试") + WarnLog("ES在线日志测试") + DebugLog("ES在线日志测试") + ErrorLog("ES在线日志测试") + FatalLog("ES在线日志测试") + } + Stop() +} + +func BenchmarkWrite(b *testing.B) { + Start("http://106.52.100.147:14001", "20008_gs_log", 20008) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + InfoLog("ES在线日志测试%d", i) + WarnLog("ES在线日志测试%d", i) + DebugLog("ES在线日志测试%d", i) + ErrorLog("ES在线日志测试%d", i) + FatalLog("ES在线日志测试%d", i) + } + b.StopTimer() + + time.Sleep(30 * time.Second) + Stop() +} diff --git a/.svn/pristine/44/441ecb83b8c1a3af9e234f21ac76c082a4f9ff7b.svn-base b/.svn/pristine/44/441ecb83b8c1a3af9e234f21ac76c082a4f9ff7b.svn-base new file mode 100644 index 0000000..47fa1a1 --- /dev/null +++ b/.svn/pristine/44/441ecb83b8c1a3af9e234f21ac76c082a4f9ff7b.svn-base @@ -0,0 +1,33 @@ +package gameServerMgr + +import ( + "encoding/json" + + . "Framework/managecenterModel" +) + +var ( + mChargeConfigMap = make(map[int32][]*ChargeConfig, 0) +) + +//解析充值配置信息 +func ParseChargeConfigInfo(partnerList []*Partner) { + tmpChargeConfigMap := make(map[int32][]*ChargeConfig, 0) + + //循环解析所有合作商里面的充值配置信息 + for _, partner := range partnerList { + var chargeConfigList []*ChargeConfig + if err := json.Unmarshal([]byte(partner.ChargeConfig), &chargeConfigList); err == nil { + tmpChargeConfigMap[partner.Id] = chargeConfigList + } + } + + mChargeConfigMap = tmpChargeConfigMap +} + +// 根据合作商Id获取合作商充值配置对象 +func GetChargeConfigList(partnerId int32) (chargeConfigList []*ChargeConfig, exist bool) { + chargeConfigList, exist = mChargeConfigMap[partnerId] + + return +} diff --git a/.svn/pristine/44/4455e0cfdc1b824c9dcb29ac73ba4313e7b94906.svn-base b/.svn/pristine/44/4455e0cfdc1b824c9dcb29ac73ba4313e7b94906.svn-base new file mode 100644 index 0000000..071d1a4 --- /dev/null +++ b/.svn/pristine/44/4455e0cfdc1b824c9dcb29ac73ba4313e7b94906.svn-base @@ -0,0 +1,47 @@ +package debugUtil + +import "github.com/fatih/color" + +// Code 显示代码 +type Code = color.Attribute + +const ( + Code_Reset Code = color.Reset + Code_Bold Code = color.Bold + Code_Faint Code = color.Faint + Code_Italic Code = color.Italic + Code_Underline Code = color.Underline + Code_BlinkSlow Code = color.BlinkSlow + Code_BlinkRapid Code = color.BlinkRapid + Code_ReverseVideo Code = color.ReverseVideo + Code_Concealed Code = color.Concealed + Code_CrossedOut Code = color.CrossedOut +) + +// ForegroundColor 前景色 +type ForegroundColor = color.Attribute + +const ( + Foreground_Black ForegroundColor = color.FgBlack + Foreground_Red ForegroundColor = color.FgRed + Foreground_Green ForegroundColor = color.FgGreen + Foreground_Yellow ForegroundColor = color.FgYellow + Foreground_Blue ForegroundColor = color.FgBlue + Foreground_Purple ForegroundColor = color.FgMagenta + Foreground_Cyan ForegroundColor = color.FgCyan + Foreground_White ForegroundColor = color.FgWhite +) + +// BackgroundColor 背景色 +type BackgroundColor = color.Attribute + +const ( + BackgroundColor_Black = color.BgBlack + BackgroundColor_Red = color.BgRed + BackgroundColor_Green = color.BgGreen + BackgroundColor_Yellow = color.BgYellow + BackgroundColor_Blue = color.BgBlue + BackgroundColor_Purple = color.BgMagenta + BackgroundColor_Cyan = color.BgCyan + BackgroundColor_White = color.BgWhite +) diff --git a/.svn/pristine/44/4472e6a7a56519f9549a2f2f3f364207e68b78bb.svn-base b/.svn/pristine/44/4472e6a7a56519f9549a2f2f3f364207e68b78bb.svn-base new file mode 100644 index 0000000..fa84949 --- /dev/null +++ b/.svn/pristine/44/4472e6a7a56519f9549a2f2f3f364207e68b78bb.svn-base @@ -0,0 +1,98 @@ +package hash32 + +/* + * ***注意*** + * + * Sum 使用的是[]byte参数;string中文是utf-8编码 + * SumByRune 使用的是[]rune参数;中文使用的是unicode编码 + * + * 两种参数中文编码不同;同一个string调用两个接口得到的hash是不同的!!! 这是要特别注意的 + * + * 对string进行for range操作会自动被[]rune化;一定要注意!!! + * + */ + +const shiftBit = 11 // 每个字节移位数(测试经验值11) +const reverseBit = 32 - shiftBit + +// 快速Hash计算(*** 注意:只取了rune低16位进行hash计算;计算结果与SumByRune不一致 ***) +func FastSumByRune2(in rune, hs uint32) (out uint32) { + out = ((hs << shiftBit) | (hs >> reverseBit)) + uint32(byte(in>>8)) + out = ((out << shiftBit) | (out >> reverseBit)) + uint32(byte(in)) + return +} + +// 快速Hash计算(*** 此计算结果与SumByRune一致 ***) +func FastSumByRune4(in rune, hs uint32) (out uint32) { + out = ((hs << shiftBit) | (hs >> reverseBit)) + uint32(byte(in>>24)) + out = ((out << shiftBit) | (out >> reverseBit)) + uint32(byte(in>>16)) + out = ((out << shiftBit) | (out >> reverseBit)) + uint32(byte(in>>8)) + out = ((out << shiftBit) | (out >> reverseBit)) + uint32(byte(in)) + return +} + +// 原Hash值参数重 +func hsArg(hsOpt ...uint32) (out uint32) { + out = uint32(0) + if len(hsOpt) > 0 { + out = hsOpt[0] + } + return +} + +// Hash计算 +// in - 待hash串 +// hsOpt - 原hash值(在此基础上继续hash) +func Sum(in []byte, hsOpt ...uint32) (out uint32) { + out = hsArg(hsOpt...) + for _, v := range in { + out = ((out << shiftBit) | (out >> reverseBit)) + uint32(v) + } + + return +} + +// Hash计算 +func SumByRune(in rune, hsOpt ...uint32) (out uint32) { + // rune转[]byte + inVal := make([]byte, 4) + inVal[0] = byte(in >> 24) + inVal[1] = byte(in >> 16) + inVal[2] = byte(in >> 8) + inVal[3] = byte(in) + + // *** 经实际测试:不加以下代码运行效率更高 *** + + // 去除前面多余的\x00 + // for { + // if len(inVal) <= 1 { + // // 以免全0异常;至少要保留1位 + // break + // } + // if inVal[0] == 0 { + // inVal = inVal[1:] + // } else { + // break + // } + // } + // 规避hash冲突,如:"N-"与"中"unicode编码均为#4E2D,即会产生hash冲突 + // 若长度>1(即非常规ASCII),所有字节最高位置1 + // if len(inVal) > 1 { + // for i := 0; i < len(inVal); i++ { + // inVal[i] |= 0x80 + // } + // } + out = Sum(inVal, hsOpt...) + + return +} + +// Hash计算 +func SumByRunes(in []rune, hsOpt ...uint32) (out uint32) { + out = hsArg(hsOpt...) + for _, v := range in { + out = SumByRune(v, out) + } + + return +} diff --git a/.svn/pristine/45/452216f78217ea55998820ec3ca6c0e9ae15c4f0.svn-base b/.svn/pristine/45/452216f78217ea55998820ec3ca6c0e9ae15c4f0.svn-base new file mode 100644 index 0000000..54b794f --- /dev/null +++ b/.svn/pristine/45/452216f78217ea55998820ec3ca6c0e9ae15c4f0.svn-base @@ -0,0 +1,3 @@ +DefaultLogPath/ + +/test_*/ diff --git a/.svn/pristine/45/454997784756d5cf8e2dd0c2ef3ccb48f3739826.svn-base b/.svn/pristine/45/454997784756d5cf8e2dd0c2ef3ccb48f3739826.svn-base new file mode 100644 index 0000000..503ebf7 --- /dev/null +++ b/.svn/pristine/45/454997784756d5cf8e2dd0c2ef3ccb48f3739826.svn-base @@ -0,0 +1,103 @@ +package ini_config + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "strings" +) + +// ParseFile +// @description: 从文件读取配置文件,并转化为map对象 +// parameter: +// @filePath:文件路径 +// return: +// @map[string]string: 配置信息 +// @error:错误信息 +func ParseFile(filePath string) (map[string]string, error) { + fn, err := os.Open(filePath) + if err != nil { + panic(err) + } + defer fn.Close() + + kvMap := make(map[string]string) + rd := bufio.NewReader(fn) + for { + data, _, err := rd.ReadLine() + if err != nil || io.EOF == err { + break + } + + line := strings.TrimSpace(string(data)) + if line == "" || line[0:1] == "#" { + continue + } + + var k string + var v string + k, v, err = Parse(line) + if err != nil { + return nil, err + } + + kvMap[k] = v + } + + return kvMap, nil +} + +// Parse +// @description: 转换单行字符串为配置对象 +// parameter: +// @line:单行内容 +// return: +// @string:key +// @string:value +// @error:错误信息 +func Parse(line string) (string, string, error) { + ls := strings.SplitN(line, "=", 2) + if len(ls) != 2 { + return "", "", errors.New(fmt.Sprintf("配置%s中未找到=分隔符", line)) + } + + var key = strings.TrimSpace(ls[0]) + var value string + + i := strings.LastIndex(ls[1], "#") + if i < 0 { + value = strings.TrimSpace(ls[1]) + } else { + s := ls[1][:i] + value = strings.TrimSpace(s) + } + + return key, value, nil +} + +// ParseMultipleLines +// @description: 转换多行字符串为配置对象 +// parameter: +// @content:多行内容(通过\n换行) +// return: +// @map[string]string:配置信息 +// @error:错误信息 +func ParseMultipleLines(content string) (map[string]string, error) { + lines := strings.Split(content, "\n") + kvMap := make(map[string]string) + for _, line := range lines { + if line == "" || line[0:1] == "#" { + continue + } + + k, v, err := Parse(line) + if err != nil { + return nil, err + } + kvMap[k] = v + } + + return kvMap, nil +} diff --git a/.svn/pristine/45/45a09743370b259aefd77d242d38fd7769811a8d.svn-base b/.svn/pristine/45/45a09743370b259aefd77d242d38fd7769811a8d.svn-base new file mode 100644 index 0000000..6480a8d --- /dev/null +++ b/.svn/pristine/45/45a09743370b259aefd77d242d38fd7769811a8d.svn-base @@ -0,0 +1,102 @@ +package timeUtil + +import ( + "fmt" + "strconv" + "strings" + "time" +) + +// 将字符串转换为标准的时间格式 +// str:输入,格式为:2015-10-25T17:07:30 +// 返回值: +// 标准时间格式对象 +// 错误对象 +func ConverToStandardFormat(str string) (result time.Time, err error) { + newStr := strings.Replace(str, "T", ":", -1) + newStr = strings.Replace(newStr, "-", ":", -1) + newStr = strings.Replace(newStr, ".", ":", -1) + + slice := strings.Split(newStr, ":") + slice = slice[:6] // 只取前6位(表示年-月-日 时:分:秒) + + intSlice := make([]int, len(slice)) + for index, item := range slice { + if intItem, err1 := strconv.Atoi(item); err1 != nil { + err = fmt.Errorf("输入字符串的格式错误:%s,转换后的格式为:%s", str, newStr) + return + } else { + intSlice[index] = intItem + } + } + + result = time.Date(intSlice[0], time.Month(intSlice[1]), intSlice[2], intSlice[3], intSlice[4], intSlice[5], 0, time.Local) + return +} + +// 将时间转换为int类型(20160120,共8位) +// t:时间 +// 返回值: +// int类型的数字 +func ConvertToInt(t time.Time) int { + year := int(t.Year()) + month := int(t.Month()) + day := int(t.Day()) + + return year*10e3 + month*10e1 + day +} + +// 计算两个时间的日期差值 +func SubDay(time1, time2 time.Time) int { + // 当前时间距离00:00:00的秒数 + awayFromZero := func(val time.Time) int64 { + hour := val.Hour() + minute := val.Minute() + second := val.Second() + return int64(hour*3600 + minute*60 + second) + } + + // 每天对应的秒数 + var eachDaySecond int64 = 24 * 3600 + + // 计算出两个时间对应的00:00:00时的时间戳 + unix1 := time1.Unix() - awayFromZero(time1) + unix2 := time2.Unix() - awayFromZero(time2) + + if unix1 < unix2 { + return int((unix2 - unix1) / eachDaySecond) + } else { + return int((unix1 - unix2) / eachDaySecond) + } +} + +// 解析时间字符串,要求时间格式形式为:12:59:59 这种形式 +// timeStr:时间字符串 +// 返回值: +// err:错误信息 +// hour:小时值 +// minute:分钟值 +// second:秒数 +func ParseTimeString(timeStr string) (err error, hour int, minute int, second int) { + timeSlice := strings.Split(timeStr, ":") + if len(timeSlice) != 3 { + err = fmt.Errorf("时间字符串格式不正确:%v", timeStr) + return + } + + hour, _ = strconv.Atoi(timeSlice[0]) + minute, _ = strconv.Atoi(timeSlice[1]) + second, _ = strconv.Atoi(timeSlice[2]) + + return +} + +// 获取时间的日期值 +// timeVal:时间值 +// 返回值: +// time.Time:日期值 +func GetDate(timeVal time.Time) time.Time { + year, month, day := timeVal.Date() + + return time.Date(year, month, day, 0, 0, 0, 0, timeVal.Location()) +} diff --git a/.svn/pristine/45/45b8bbbab2a9efeb7b70840597892f85147de079.svn-base b/.svn/pristine/45/45b8bbbab2a9efeb7b70840597892f85147de079.svn-base new file mode 100644 index 0000000..7df92b0 --- /dev/null +++ b/.svn/pristine/45/45b8bbbab2a9efeb7b70840597892f85147de079.svn-base @@ -0,0 +1,208 @@ +package monitorMgr + +import ( + "fmt" + "sync" + "time" + + "goutil/debugUtil" + "goutil/logUtil" + "goutil/webUtil" +) + +var ( + // 报告监控信息的URL + remoteURL = "http://maintenance.7qule.com/Manage/Monitor.ashx" + + // 服务器IP + serverIP string + + // 服务器名称 + serverName string + + // 监控时间间隔(单位:分钟) + monitorInterval = 5 + + // 重复消息发送的时间间隔(单位:分钟) + duplicateInterval = 5 + + // 已经发送的消息 + sentMessageMap = make(map[string]int64) + + // 已经发送消息的锁对象 + sentMessageMutex sync.Mutex + + // 监控方法列表 + monitorFuncList = make([]func() error, 0, 4) + + // 监控方法锁对象 + monitorFuncMutex sync.Mutex +) + +// SetURL ...设置监控信息发送的URL +// url:监控信息发送的URL +func SetURL(url string) { + remoteURL = url +} + +// SetDuplicateInterval ...设置重复消息发送的时间间隔(单位:分钟) +// _duplicateInterval:重复消息发送的时间间隔(单位:分钟) +func SetDuplicateInterval(_duplicateInterval int) { + duplicateInterval = _duplicateInterval +} + +// SetParam ...设置参数 +// _serverIP:服务器IP +// _serverName:服务器名称 +// _monitorInterval:监控时间间隔(单位:分钟) +func SetParam(_serverIP, _serverName string, _monitorInterval int) { + serverIP = _serverIP + serverName = _serverName + monitorInterval = _monitorInterval +} + +// RegisterMonitorFunc ...注册监控方法 +// f:监控方法 +func RegisterMonitorFunc(f func() error) { + monitorFuncMutex.Lock() + defer monitorFuncMutex.Unlock() + + monitorFuncList = append(monitorFuncList, f) +} + +// Start ...启动监控服务(obsolete,建议使用Start2) +// serverIp:服务器IP +// serverName:服务器名称 +// monitorInterval:监控时间间隔(单位:分钟) +func Start(serverIp, serverName string, monitorInterval int) { + monitorConfig := NewMonitorConfig(serverIp, serverName, monitorInterval) + Start2(monitorConfig) +} + +// Start ...启动监控服务2 +// monitorConfig:监控配置对象 +func Start2(monitorConfig *MonitorConfig) { + // 设置参数 + SetParam(monitorConfig.ServerIp, monitorConfig.ServerName, monitorConfig.Interval) + + // 实际的监控方法调用 + monitorFunc := func() { + monitorFuncMutex.Lock() + defer monitorFuncMutex.Unlock() + + for _, item := range monitorFuncList { + if err := item(); err != nil { + Report(err.Error()) + } + } + } + + go func() { + // 处理内部未处理的异常,以免导致主线程退出,从而导致系统崩溃 + defer func() { + if r := recover(); r != nil { + logUtil.LogUnknownError(r) + } + }() + + for { + // 先休眠,避免系统启动时就进行报警 + time.Sleep(time.Minute * time.Duration(monitorInterval)) + + // 实际的监控方法调用 + monitorFunc() + } + }() +} + +// 判断指定时间内是否已经处理过 +// conent:报告内容 +func isDuplicate(content string) bool { + if ts, exists := sentMessageMap[content]; exists && time.Now().Unix()-ts < int64(60*duplicateInterval) { + return true + } + + return false +} + +// 添加到已发送集合中 +// conent:报告内容 +func addToMap(content string) { + sentMessageMap[content] = time.Now().Unix() +} + +// Report ...报告异常信息 +// format:报告内容格式 +// args:具体参数 +func Report(format string, args ...interface{}) { + if len(args) <= 0 { + Report2(format, "") + } else { + Report2(fmt.Sprintf(format, args...), "") + } +} + +// Report ...报告异常信息 +// title:上报的标题 +// contentFmt:报告内容 +// args:参数列表 +func Report2(title, contentFmt string, args ...interface{}) { + content := contentFmt + if len(args) > 0 { + content = fmt.Sprintf(contentFmt, args...) + } + + sentMessageMutex.Lock() + defer sentMessageMutex.Unlock() + + // 判断指定时间内是否已经处理过 + if isDuplicate(title) { + return + } + + logUtil.WarnLog(fmt.Sprintf("MonitorReport:ServerIP:%s,ServerName:%s,Title:%s Content:%s", serverIP, serverName, title, content)) + + // 判断是否是DEBUG模式 + if debugUtil.IsDebug() { + return + } + + detailMsg := title + if len(content) > 0 { + detailMsg = fmt.Sprintf("Title:%s Content:%s", title, content) + } + + // 定义请求参数 + postDict := make(map[string]string) + postDict["ServerIp"] = serverIP + postDict["ServerName"] = serverName + postDict["Content"] = detailMsg + + //请求url,请求头 + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, 30) + + statusCode, returnBytes, err := webUtil.PostMapData(remoteURL, postDict, header, transport) + // 连接服务器,以获取数据 + //returnBytes, err := webUtil.PostWebData(remoteURL, postDict, nil) + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("MonitorReport:,错误信息为:%s", err)) + return + } + if statusCode != 200 { + logUtil.ErrorLog(fmt.Sprintf("MonitorReport:,状态吗为:%d", statusCode)) + return + } + + result := string(returnBytes) + logUtil.WarnLog(fmt.Sprintf("MonitorReport:Result:%s", result)) + + if result != "200" { + logUtil.ErrorLog(fmt.Sprintf("返回值不正确,当前返回值为:%s", result)) + } + + // 添加到已发送集合中 + addToMap(title) +} diff --git a/.svn/pristine/45/45f0c43c59968de8708cb631ec180d949e04a2d8.svn-base b/.svn/pristine/45/45f0c43c59968de8708cb631ec180d949e04a2d8.svn-base new file mode 100644 index 0000000..0314033 --- /dev/null +++ b/.svn/pristine/45/45f0c43c59968de8708cb631ec180d949e04a2d8.svn-base @@ -0,0 +1,186 @@ +package logSqlSync + +import ( + "database/sql" + "fmt" + "time" + + "goutil/logUtil" +) + +// 同步信息表是否已经被初始化 +var ifSyncingTableInited bool = false + +// 同步信息项,保存已经处理过的文件的信息 +type syncingModel struct { + // 服务器组Id + ServerGroupId int32 + + // 待处理文件的绝对路径 + FilePath string + + // 待处理文件的偏移量 + FileOffset int64 + + // 更新时间 + UpdateTime time.Time +} + +// 同步信息对象 +type syncingInfo struct { + // 服务器组Id + ServerGroupId int32 + + // 同步信息项 + item *syncingModel + + // 数据库连接对象 + db *sql.DB +} + +// 获取同步信息 +// filePath:正在同步的文件 +// fileOffset:同步到的位置 +func (this *syncingInfo) GetSyncingInfo() (filePath string, fileOffset int64) { + return this.item.FilePath, this.item.FileOffset +} + +// 更新正在同步的位置和文件信息 +// filePath:文件路径 +// offset:当前同步到的位置 +// tran:事务对象,可以为nil +// 返回值: +// error:处理的错误信息 +func (this *syncingInfo) Update(filePath string, offset int64, tran *sql.Tx) error { + this.item.FilePath = filePath + this.item.FileOffset = offset + this.item.UpdateTime = time.Now() + + // 更新到数据库 + return this.update(this.item, tran) +} + +// 初始化同步信息 +// 返回值: +// error:错误信息 +func (this *syncingInfo) init() error { + // 数据表初始化 + if ifSyncingTableInited == false { + if err := this.initSyncingInfoTable(this.db); err == nil { + ifSyncingTableInited = true + } else { + return err + } + } + + // 获取此表的同步信息 + data, exist, err := this.get() + if err != nil { + return err + } + + // 2. 如果同步信息不存在,则初始化一条到此表 + if exist == false { + data = &syncingModel{ + ServerGroupId: this.ServerGroupId, + FilePath: "", + FileOffset: 0, + UpdateTime: time.Now(), + } + } + + this.item = data + return nil +} + +// 初始化同步信息表结构 +// db:数据库连接对象 +func (this *syncingInfo) initSyncingInfoTable(db *sql.DB) error { + // 创建同步信息表 + createTableSql := `CREATE TABLE IF NOT EXISTS syncing_info ( + ServerGroupId int NOT NULL COMMENT '服务器组Id', + FilePath varchar(500) NOT NULL COMMENT '正在同步的文件路径', + FileOffset bigint(20) NOT NULL COMMENT '偏移量', + UpdateTime datetime NOT NULL COMMENT '最后一次更新时间', + PRIMARY KEY (ServerGroupId) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='正在同步的文件信息';` + if _, err := db.Exec(createTableSql); err != nil { + logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.initSyncingInfoTable Error:%s", err.Error())) + return err + } + + return nil +} + +// 从数据库获取数据 +// 返回值: +// data:获取到的数据 +// exist:是否存在此数据 +// err:错误信息 +func (this *syncingInfo) get() (data *syncingModel, exist bool, err error) { + //// 从数据库查询 + querySql := fmt.Sprintf("SELECT FilePath,FileOffset,UpdateTime FROM syncing_info WHERE ServerGroupId ='%v'", this.ServerGroupId) + var rows *sql.Rows + rows, err = this.db.Query(querySql) + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.get.Query ServerGroupId:%v error:%s", this.ServerGroupId, err.Error())) + return + } + defer rows.Close() + + if rows.Next() == false { + exist = false + return + } + exist = true + + // 读取数据 + data = &syncingModel{ + ServerGroupId: this.ServerGroupId, + } + err = rows.Scan(&data.FilePath, &data.FileOffset, &data.UpdateTime) + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.get.Query ServerGroupId:%v error:%s", this.ServerGroupId, err.Error())) + return + } + + return +} + +// 把同步信息更新到数据库 +// data:待更新的数据 +// tran:事务处理对象 +// 返回值: +// error:错误信息 +func (this *syncingInfo) update(data *syncingModel, tran *sql.Tx) error { + updateSql := "REPLACE INTO `syncing_info` SET `ServerGroupId` = ?, `FilePath` = ?,`FileOffset` = ?, `UpdateTime` = ?;" + var err error + if tran != nil { + _, err = tran.Exec(updateSql, data.ServerGroupId, data.FilePath, data.FileOffset, data.UpdateTime) + } else { + _, err = this.db.Exec(updateSql, data.ServerGroupId, data.FilePath, data.FileOffset, data.UpdateTime) + } + + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.update ServerGroupId:%v error:%s", this.ServerGroupId, err.Error())) + } + + return err +} + +// 创建同步信息对象 +// _dirPath:目录的路径 +// _identifier:当前数据的唯一标识(可以使用数据库表名) +// _db:数据库连接对象 +// 返回值: +// 同步信息对象 +func newSyncingInfoObject(serverGroupId int32, _db *sql.DB) (result *syncingInfo, err error) { + result = &syncingInfo{ + ServerGroupId: serverGroupId, + db: _db, + } + + err = result.init() + + return result, err +} diff --git a/.svn/pristine/46/460e1ba3b9bd0b80cd60485a6013941777b27d7f.svn-base b/.svn/pristine/46/460e1ba3b9bd0b80cd60485a6013941777b27d7f.svn-base new file mode 100644 index 0000000..1ddcb42 --- /dev/null +++ b/.svn/pristine/46/460e1ba3b9bd0b80cd60485a6013941777b27d7f.svn-base @@ -0,0 +1,47 @@ +package coroutine_timer + +const ( + // 添加 + cmd_add = 1 + + // 删除 + cmd_del = 2 +) + +// cmdModel +// @description: 命令对象 +type cmdModel struct { + // cmd 指令 + cmd int + + // paramObj 指令参数 + paramObj interface{} + + // resObj 指令返回对象 + resObj interface{} + + // err 指令返回的错误 + err error + + // waitChan 等待channel + waitChan chan struct{} +} + +// newCmdModel +// @description: 创建cmd模型对象 +// parameter: +// @c:cmd命令 +// @po:参数 +// return: +// @*cmdModel: +func newCmdModel(c int, po interface{}) *cmdModel { + result := &cmdModel{ + cmd: c, + paramObj: po, + resObj: nil, + err: nil, + waitChan: make(chan struct{}, 1), + } + + return result +} diff --git a/.svn/pristine/46/462e834bc4c52b9546cd5900c63f09387213c2e5.svn-base b/.svn/pristine/46/462e834bc4c52b9546cd5900c63f09387213c2e5.svn-base new file mode 100644 index 0000000..8bbc616 --- /dev/null +++ b/.svn/pristine/46/462e834bc4c52b9546cd5900c63f09387213c2e5.svn-base @@ -0,0 +1,166 @@ +package gameServerMgr + +import ( + "fmt" + + . "Framework/managecenterModel" +) + +var ( + mServerMap = make(map[int32][]*Server, 0) +) + +//合作商、服务器组合列表 +type PartnerServer struct { + //合作商Id + mPartnerId int32 + + //服务器Id + mServerId int32 +} + +//解析服务器信息 +func ParseServerInfo(serverList []*Server) { + tempServerMap := make(map[int32][]*Server, 0) + for _, server := range serverList { + _, exist := tempServerMap[server.PartnerId] + if !exist { + tempServerMap[server.PartnerId] = make([]*Server, 0) + } + tempServerMap[server.PartnerId] = append(tempServerMap[server.PartnerId], server) + } + mServerMap = tempServerMap +} + +//获取服务器对象 +func GetServerItem(partnerId, serverId int32) (server *Server, exist bool) { + serverList, existServer := mServerMap[partnerId] + if !existServer { + return + } + for _, serverItem := range serverList { + if serverItem.Id == serverId { + server = serverItem + exist = true + break + } + } + return +} + +//判断服务器是否存在 +func IfServerExists(partnerId, serverId int32) (exists bool) { + _, exists = GetPartnerItem(partnerId) + if !exists { + return + } + _, exists = GetServerItem(partnerId, serverId) + if !exists { + return + } + + return +} + +//获取服务器名称 +func GetServerName(partnerId, serverId int32) (serverName string) { + _, existPartner := GetPartnerItem(partnerId) + if !existPartner { + return + } + server, existServer := GetServerItem(partnerId, serverId) + if !existServer { + return + } + serverName = server.Name + + return +} + +//检测是否有游戏版本更新 +func CheckNewGameVersion(partnerId, serverId, gameVersionId int32) (gameVersionUrl string, exist bool) { + server, existServer := GetServerItem(partnerId, serverId) + if !existServer { + exist = existServer + return + } + + if gameVersionId < server.MinGameVersionId { + partner, existPartner := GetPartnerItem(partnerId) + if !existPartner { + exist = existPartner + return + } + exist = true + gameVersionUrl = partner.GameVersionUrl + } + + return +} + +//获取合作商、服务器的组合字符串 +//字符串格式:PartnerId_ServerId|PartnerId_ServerId| +func GetPartnerServerPairString() (partnerServerPair string) { + for _, ps := range GetPartnerServerPairList() { + partnerServerPair += fmt.Sprintf("%d_%d|", ps.mPartnerId, ps.mServerId) + } + return +} + +//获取合作商、服务器的组合列表 +func GetPartnerServerPairList() (partnerServerList []*PartnerServer) { + for key := range mServerMap { + for _, server := range mServerMap[key] { + if server.GroupId == GetServerGroup().Id { + var ps *PartnerServer = &PartnerServer{server.PartnerId, server.Id} + partnerServerList = append(partnerServerList, ps) + } + } + } + + return +} + +// // 获取合作商、服务器的组合字符串 +// // serverGroupId:服务器组Id +// // 返回值 +// // 合作商、服务器的组合字符串 +// func (this *ManageCenterUtil) GetPartnerServerPairString(serverGroupId int32) string { +// var buf bytes.Buffer + +// serverList := managecenterMgr.GetServerList(serverGroupId) +// for _, item := range serverList { +// buf.WriteString(fmt.Sprintf("%d_%d|", item.PartnerId, item.Id)) +// } + +// return buf.String() +// } + +// // 是否是有效的合作商、服务器组合 +// // partnerId:合作商Id +// // serverId:服务器Id +// // parnterServerPairString:合作商、服务器的组合字符串,格式为:PartnerId_ServerId|PartnerId_ServerId| +// // 返回值 +// // 是否有效 +// func (this *ManageCenterUtil) IfValidPartnerServerPair(partnerId, serverId int32, parnterServerPairString string) bool { +// if parnterServerPairString == "" { +// return false +// } + +// partnerServerPairStringList := strings.Split(parnterServerPairString, "|") +// if len(partnerServerPairStringList) == 0 { +// return false +// } + +// // 获得玩家的合作商、服务器组合字符串 +// partnerServerPair := fmt.Sprintf("%d_%d", partnerId, serverId) + +// // 遍历寻找 +// for _, item := range partnerServerPairStringList { +// if item == partnerServerPair { +// return true +// } +// } + +// return false +// } diff --git a/.svn/pristine/46/46fe9b43a26885328f556159b055b3d369732600.svn-base b/.svn/pristine/46/46fe9b43a26885328f556159b055b3d369732600.svn-base new file mode 100644 index 0000000..a50f921 --- /dev/null +++ b/.svn/pristine/46/46fe9b43a26885328f556159b055b3d369732600.svn-base @@ -0,0 +1,16 @@ +package intUtil + +import ( + "fmt" + "testing" +) + +func Test1(t *testing.T) { + var originalNum int64 = 1234567891011121314 + shuffledNum, err := ShuffleIntDigits(int64(originalNum)) + if err != nil { + fmt.Println("Error:", err) + return + } + fmt.Printf("Original number: %d\nShuffled number: %d\n", originalNum, shuffledNum) +} diff --git a/.svn/pristine/47/47e1f67a37d3cf0affa5dd7f1a866f5375ac5629.svn-base b/.svn/pristine/47/47e1f67a37d3cf0affa5dd7f1a866f5375ac5629.svn-base new file mode 100644 index 0000000..9f8eaa4 --- /dev/null +++ b/.svn/pristine/47/47e1f67a37d3cf0affa5dd7f1a866f5375ac5629.svn-base @@ -0,0 +1,71 @@ +package webServer + +import ( + "net/http" + + "goutil/typeUtil" +) + +// webserver接口 +type IWebServer interface { + // 注册API + // path:注册的访问路径 + // callback:回调方法 + // configObj:Handler配置对象 + RegisterHandler(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig) + + // 注册回调-增加用户自定义数据 + RegisterHandlerWithUserData(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig, userData interface{}) + + RegisterRegexHandler(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig) + + // 注册正则回调-增加用户自定义数据 + RegisterRegexHandlerWithUserData(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig, userData interface{}) + + // 设定Http Header信息 + SetHeader(header map[string]string) + + // 设定HTTP请求方法 + SetMethod(method string) + + // 设定当HTTP请求方法无效时,调用的处理器 + SetInvalidMethodHandler(handler func(*Context)) + + // 设置WebServer请求是否经过了负载均衡中转 + SetIfDelegate(ifDelegate bool) + + // 设定默认页的处理器 + SetDefaultPageHandler(handler func(*Context)) + + // 设定未找到指定的回调时的处理器 + SetNotFoundPageHandler(handler func(*Context)) + + // 设置异常处理函数(默认只会记录在文件) + SetUnHandledPanicHandler(handler func(context *Context, errObj interface{})) + + // 设定在Debug模式下是否需要验证IP地址 + SetIfCheckIPWhenDebug(value bool) + + // 设定当IP无效时调用的处理器 + SetIPInvalidHandler(handler func(*Context)) + + // 设定用于检测参数是否有效的处理器 + SetParamCheckHandler(handler func(typeUtil.MapData, []string, []string) ([]string, []string, bool)) + + // 设定当检测到参数无效时调用的处理器 + SetParamInvalidHandler(handler func(*Context, []string, []string)) + + // 设定处理请求数据的处理器(例如压缩、解密等) + SetRequestDataHandler(handler func(*Context, []byte) ([]byte, error)) + + // 设定处理响应数据的处理器(例如压缩、加密等) + SetResponseDataHandler(handler func(*Context, []byte) ([]byte, error)) + + // 设定请求执行时间的处理器 + SetExecuteTimeHandler(handler func(*Context)) + + // http应答处理 + // responseWriter:应答对象 + // request:请求对象 + ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) +} diff --git a/.svn/pristine/47/47e800dd36b3f0c082e6782f864014eb4e07d2a5.svn-base b/.svn/pristine/47/47e800dd36b3f0c082e6782f864014eb4e07d2a5.svn-base new file mode 100644 index 0000000..94ae227 --- /dev/null +++ b/.svn/pristine/47/47e800dd36b3f0c082e6782f864014eb4e07d2a5.svn-base @@ -0,0 +1,1733 @@ +package redisUtil + +import ( + "testing" + "time" +) + +var ( + redisPoolObj_string *RedisPool +) + +func init() { + redisPoolObj_string = NewRedisPool("testPool", "10.1.0.21:6379", "redis_pwd", 5, 500, 200, 10*time.Second, 5*time.Second) +} + +func TestSet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 对不存在的键进行设置: + + redis> SET key "value" + OK + */ + + key := "key" + value := "value" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET key + "value" + */ + got_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err := redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value { + t.Errorf("Expected to get %s, but now got %s.", value, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + 对已存在的键进行设置: + + redis> SET key "new-value" + OK + */ + value = "new-value" + successful, err = redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET key + "new-value" + */ + got_interface, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value { + t.Errorf("Expected to get %s, but now got %s.", value, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + 使用 EX 选项: + + redis> SET key-with-expire-time "hello" EX 10086 + OK + */ + key = "key-with-expire-time" + value = "hello" + successful, err = redisPoolObj_string.Set(key, value, "EX", 10086, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET key-with-expire-time + "hello" + */ + got_interface, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", "key-with-expire-time") + return + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value { + t.Errorf("Expected to get %s, but now got %s.", value, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> TTL key-with-expire-time + (integer) 10069 + */ + ttl, exist, _, err := redisPoolObj_string.TTL(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't", key) + return + } + if ttl < 10086-5 { + t.Errorf("The TTL of key:%s is wrong. Now it's %d", key, ttl) + return + } + deleteKeys = append(deleteKeys, key) + + /* + 使用 PX 选项: + + redis> SET key-with-pexpire-time "moto" PX 123321 + OK + */ + key = "key-with-pexpire-time" + value = "moto" + successful, err = redisPoolObj_string.Set(key, value, "PX", 123321, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET key-with-pexpire-time + "moto" + */ + got_interface, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value { + t.Errorf("Expected to get %s, but now got %s.", value, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> PTTL key-with-pexpire-time + (integer) 111939 + */ + ttl, exist, _, err = redisPoolObj_string.PTTL(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't", key) + return + } + if ttl < 123321-5000 { + t.Errorf("The TTL of key:%s is wrong. Now it's %d", key, ttl) + return + } + deleteKeys = append(deleteKeys, key) + + /* + 使用 NX 选项: + + redis> SET not-exists-key "value" NX + OK # 键不存在,设置成功 + */ + key = "not-exists-key" + value = "value" + successful, err = redisPoolObj_string.Set(key, value, "", 0, "NX") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET not-exists-key + "value" + */ + got_interface, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value { + t.Errorf("Expected to get %s, but now got %s.", value, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> SET not-exists-key "new-value" NX + (nil) # 键已经存在,设置失败 + + */ + newValue := "new-value" + successful, err = redisPoolObj_string.Set(key, newValue, "", 0, "NX") + if err != nil { + t.Fail() + } + if successful { + t.Errorf("Seting key:%s should fail, but now it doesn't.", key) + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GEt not-exists-key + "value" # 维持原值不变 + */ + got_interface, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value { + t.Errorf("Expected to get %s, but now got %s.", value, got) + return + } + + /* + 使用 XX 选项: + + redis> EXISTS exists-key + (integer) 0 + */ + key = "exists-key" + value = "value" + exist, err = redisPoolObj_string.Exists(key) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("Key:%s should not exist, but now it does exist", key) + } + deleteKeys = append(deleteKeys, key) + + /* + redis> SET exists-key "value" XX + (nil) # 因为键不存在,设置失败 + */ + successful, err = redisPoolObj_string.Set(key, value, "", 0, "XX") + if err != nil { + t.Fail() + } + if successful { + t.Errorf("Seting key:%s should fail, but now it doesn't.", key) + } + deleteKeys = append(deleteKeys, key) + + /* + redis> SET exists-key "value" + OK # 先给键设置一个值 + */ + successful, err = redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Seting key:%s should succeed, but now it doesn't.", key) + } + deleteKeys = append(deleteKeys, key) + + /* + redis> SET exists-key "new-value" XX + OK # 设置新值成功 + */ + value = "new-value" + successful, err = redisPoolObj_string.Set(key, value, "", 0, "XX") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Seting key:%s should succeed, but now it doesn't.", key) + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET exists-key + "new-value" + */ + got_interface, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value { + t.Errorf("Expected to get %s, but now got %s.", value, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> SET int-key 5 + OK # 设置新值成功 + */ + key2 := "int-key" + value2 := 5 + successful, err = redisPoolObj_string.Set(key2, value2, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Seting key:%s should succeed, but now it doesn't.", key) + } + deleteKeys = append(deleteKeys, key2) + + /* + redis> GET int-key + 5 + */ + got_interface, exist, err = redisPoolObj_string.Get(key2) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got2, err := redisPoolObj_string.Int(got_interface) + if err != nil { + t.Fail() + } + if got2 != value2 { + t.Errorf("Expected to get %d, but now got %d.", value2, got2) + return + } +} + +func TestGet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 对不存在的键 key 或是字符串类型的键 key 执行 GET 命令: + + redis> GET db + (nil) + */ + key := "db" + _, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s should not exist, but now it does.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> SET db redis + OK + */ + value := "redis" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET db + "redis" + */ + got_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err := redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value { + t.Errorf("Expected to get %s, but now got %s.", value, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + 对不是字符串类型的键 key 执行 GET 命令: + + redis> DEL db + (integer) 1 + */ + count, err := redisPoolObj_string.Del(key) + if err != nil { + t.Fail() + } + if count != 1 { + t.Errorf("Expected to get 1, but now got %d", count) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> LPUSH db redis mongodb mysql + (integer) 3 + */ + _, err = redisPoolObj_string.LPush(key, "redis", "mongodb", "mysql") + if err != nil { + t.Fail() + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET db + (error) ERR Operation against a key holding the wrong kind of value + */ + _, exist, err = redisPoolObj_string.Get(key) + if err == nil { + t.Fail() + } + deleteKeys = append(deleteKeys, key) +} + +func TestGetSet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + redis> GETSET db mongodb # 没有旧值,返回 nil + (nil) + */ + key := "db" + value1 := "mongodb" + got, exist, err := redisPoolObj_string.GetSet(key, value1) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("There should be no old value, but now there is.") + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET db + "mongodb" + */ + got_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value1 { + t.Errorf("Expected to get %s, but now got %s.", value1, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GETSET db redis # 返回旧值 mongodb + "mongodb" + */ + value2 := "redis" + got_interface, exist, err = redisPoolObj_string.GetSet(key, value2) + if err != nil { + t.Fail() + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value1 { + t.Errorf("Expected to get %s, but now got %s.", value1, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET db + "redis" + */ + got_interface, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err = redisPoolObj_string.String(got_interface) + if err != nil { + t.Fail() + } + if got != value2 { + t.Errorf("Expected to get %s, but now got %s.", value2, got) + return + } + deleteKeys = append(deleteKeys, key) +} + +func TestStrLen(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 获取字符串值的长度: + + redis> SET mykey "Hello world" + OK + */ + key := "mykey" + value := "Hello world" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> STRLEN mykey + (integer) 11 + 不存在的键的长度为 0 : + */ + expectedLength := 11 + got, err := redisPoolObj_string.StrLen(key) + if err != nil { + t.Fail() + } + if got != expectedLength { + t.Errorf("Expected length %d, but got %d", expectedLength, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> STRLEN nonexisting + (integer) 0 + */ + key = "nonexisting" + expectedLength = 0 + got, err = redisPoolObj_string.StrLen(key) + if err != nil { + t.Fail() + } + if got != expectedLength { + t.Errorf("Expected length %d, but got %d", expectedLength, got) + return + } +} + +func TestAppend(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 示例代码 + 对不存在的 key 执行 APPEND : + + redis> EXISTS myphone # 确保 myphone 不存在 + (integer) 0 + */ + key := "myphone" + value := "value" + exist, err := redisPoolObj_string.Exists(key) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("Key:%s should not exist, but now it does exist", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> APPEND myphone "nokia" # 对不存在的 key 进行 APPEND ,等同于 SET myphone "nokia" + (integer) 5 # 字符长度 + 对已存在的字符串进行 APPEND : + */ + value = "nokia" + expected := 5 + got, err := redisPoolObj_string.Append(key, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> APPEND myphone " - 1110" # 长度从 5 个字符增加到 12 个字符 + (integer) 12 + */ + value = " - 1110" + expected = 12 + got, err = redisPoolObj_string.Append(key, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET myphone + "nokia - 1110" + */ + expected2 := "nokia - 1110" + got2_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("Key:%s should exist, but now it doesn't exist", key) + return + } + got2, err := redisPoolObj_string.String(got2_interface) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %s, but now got %s", expected2, got2) + return + } + deleteKeys = append(deleteKeys, key) +} + +func TestSetRange(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 对非空字符串执行 SETRANGE 命令: + + redis> SET greeting "hello world" + OK + */ + key := "greeting" + value := "hello world" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> SETRANGE greeting 6 "Redis" + (integer) 11 + */ + offset := 6 + value = "Redis" + expected := 11 + got, err := redisPoolObj_string.SetRange(key, offset, value) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET greeting + "hello Redis" + */ + expected2 := "hello Redis" + got2_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got2, err := redisPoolObj_string.String(got2_interface) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %s, but now got %s", expected2, got2) + return + } + deleteKeys = append(deleteKeys, key) + + /* + 对空字符串/不存在的键执行 SETRANGE 命令: + + redis> EXISTS empty_string + (integer) 0 + + redis> SETRANGE empty_string 5 "Redis!" # 对不存在的 key 使用 SETRANGE + (integer) 11 + + redis> GET empty_string # 空白处被"\x00"填充 + "\x00\x00\x00\x00\x00Redis!" + */ + key = "empty_string" + _, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s should not exist, but now it does.", key) + return + } + deleteKeys = append(deleteKeys, key) + + offset = 5 + value = "Redis!" + expected3 := 11 + got3, err := redisPoolObj_string.SetRange(key, offset, value) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %d, but now got %d", expected3, got3) + return + } + deleteKeys = append(deleteKeys, key) + + expected4 := "\x00\x00\x00\x00\x00Redis!" + got4_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got4, err := redisPoolObj_string.String(got4_interface) + if err != nil { + t.Fail() + } + if got4 != expected4 { + t.Errorf("Expected to get %s, but now got %s", expected4, got4) + return + } + deleteKeys = append(deleteKeys, key) +} + +func TestGetRange(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + redis> SET greeting "hello, my friend" + OK + */ + key := "greeting" + value := "hello, my friend" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GETRANGE greeting 0 4 # 返回索引0-4的字符,包括4。 + "hello" + */ + start, end := 0, 4 + expected := "hello" + got, err := redisPoolObj_string.GetRange(key, start, end) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GETRANGE greeting -1 -5 # 不支持回绕操作 + "" + */ + start, end = -1, -5 + expected = "" + got, err = redisPoolObj_string.GetRange(key, start, end) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GETRANGE greeting -3 -1 # 负数索引 + "end" + */ + start, end = -3, -1 + expected = "end" + got, err = redisPoolObj_string.GetRange(key, start, end) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GETRANGE greeting 0 -1 # 从第一个到最后一个 + "hello, my friend" + */ + start, end = 0, -1 + expected = "hello, my friend" + got, err = redisPoolObj_string.GetRange(key, start, end) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GETRANGE greeting 0 1008611 # 值域范围不超过实际字符串,超过部分自动被符略 + "hello, my friend" + */ + start, end = 0, 1008611 + expected = "hello, my friend" + got, err = redisPoolObj_string.GetRange(key, start, end) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + deleteKeys = append(deleteKeys, key) +} + +func TestIncr(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + redis> SET page_view 20 + OK + */ + key := "page_view" + value := "20" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> INCR page_view + (integer) 21 + */ + expected := int64(21) + got, err := redisPoolObj_string.Incr(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET page_view # 数字值在 Redis 中以字符串的形式保存 + "21" + */ + expected2 := 21 + got2_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got2, err := redisPoolObj_string.Int(got2_interface) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d", expected2, got2) + return + } + deleteKeys = append(deleteKeys, key) +} + +func TestIncrBy(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 键存在,并且值为数字: + + redis> SET rank 50 + OK + + redis> INCRBY rank 20 + (integer) 70 + + redis> GET rank + "70" + */ + key := "rank" + value := "50" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + increment := int64(20) + expected := int64(70) + got, err := redisPoolObj_string.IncrBy(key, increment) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + expected2 := 70 + got2_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got2, err := redisPoolObj_string.Int(got2_interface) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d", expected2, got2) + return + } + deleteKeys = append(deleteKeys, key) + + /* + 键不存在: + + redis> EXISTS counter + (integer) 0 + */ + key = "counter" + _, exist, err = redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s should not exist, but now it does.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> INCRBY counter 30 + (integer) 30 + */ + increment = int64(30) + expected3 := int64(30) + got3, err := redisPoolObj_string.IncrBy(key, 30) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %d, but now got %d", expected3, got3) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET counter + "30" + */ + expected4 := 30 + got4_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got4, err := redisPoolObj_string.Int(got4_interface) + if err != nil { + t.Fail() + } + if got4 != expected4 { + t.Errorf("Expected to get %d, but now got %d", expected4, got4) + return + } + deleteKeys = append(deleteKeys, key) + + /* + 键存在,但值无法被解释为数字: + + redis> SET book "long long ago..." + OK + + redis> INCRBY book 200 + (error) ERR value is not an integer or out of range + */ + // This feature can't be tested, because the IncrBy function needs an int64 parameter. +} + +func TestIncrByFloat(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + redis> GET decimal + "3.0" + */ + key := "decimal" + value := "3.0" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + expected := 3.0 + got_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got, err := redisPoolObj_string.Float64(got_interface) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %f, but now got %f", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> INCRBYFLOAT decimal 2.56 + "5.56" + */ + increment := 2.56 + expected2 := 5.56 + got2, err := redisPoolObj_string.IncrByFloat(key, increment) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %f, but now got %f", expected2, got2) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> GET decimal + "5.56" + */ + expected3 := 5.56 + got3_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got3, err := redisPoolObj_string.Float64(got3_interface) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %f, but now got %f", expected3, got3) + return + } + deleteKeys = append(deleteKeys, key) +} + +func TestDecrBy(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 对已经存在的键执行 DECRBY 命令: + + redis> SET count 100 + OK + */ + key := "count" + value := 100 + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> DECRBY count 20 + (integer) 80 + 对不存在的键执行 DECRBY 命令: + */ + expected := int64(80) + decrement := int64(20) + got_interface, err := redisPoolObj_string.DecrBy(key, decrement) + if err != nil { + t.Fail() + } + got, err := redisPoolObj_string.Int64(got_interface) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> EXISTS pages + (integer) 0 + */ + key = "pages" + exist, err := redisPoolObj_string.Exists(key) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s should not exist, but now it does", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> DECRBY pages 10 + (integer) -10 + */ + expected = int64(-10) + decrement = int64(10) + got, err = redisPoolObj_string.DecrBy(key, decrement) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + deleteKeys = append(deleteKeys, key) +} + +func TestMSet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 同时对多个键进行设置: + + redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny" + OK + */ + key_value_map := make(map[string]interface{}) + key_value_map["date"] = "2012.3.30" + key_value_map["time"] = "11:00 a.m." + key_value_map["weather"] = "sunny" + err := redisPoolObj_string.MSet(key_value_map) + if err != nil { + t.Fail() + } + + /* + redis> MGET date time weather + 1) "2012.3.30" + 2) "11:00 a.m." + 3) "sunny" + */ + keyList := make([]string, 0, len(key_value_map)) + expected := make([]string, 0, len(key_value_map)) + for k, v := range key_value_map { + keyList = append(keyList, k) + if v_str, ok := v.(string); ok { + expected = append(expected, v_str) + } + } + got_interface, err := redisPoolObj_string.MGet(keyList) + if err != nil { + t.Fail() + } + got, err := redisPoolObj_string.Strings(got_interface) + if err != nil { + t.Fail() + } + if isTwoOrderedSliceEqual(got, expected) == false { + t.Errorf("Expected to get %v, but got %v", expected, got) + return + } + deleteKeys = append(deleteKeys, keyList...) + + /* + 覆盖已有的值: + + redis> MGET k1 k2 + 1) "hello" + 2) "world" + */ + key_value_map = make(map[string]interface{}) + key_value_map["k1"] = "hello" + key_value_map["k2"] = "world" + err = redisPoolObj_string.MSet(key_value_map) + if err != nil { + t.Fail() + } + + /* + + redis> MSET k1 "good" k2 "bye" + OK + */ + key_value_map["k1"] = "good" + key_value_map["k2"] = "bye" + err = redisPoolObj_string.MSet(key_value_map) + if err != nil { + t.Fail() + } + + /* + redis> MGET k1 k2 + 1) "good" + 2) "bye" + */ + keyList = make([]string, 0, len(key_value_map)) + expected = make([]string, 0, len(key_value_map)) + for k, v := range key_value_map { + keyList = append(keyList, k) + if v_str, ok := v.(string); ok { + expected = append(expected, v_str) + } + } + + got_interface, err = redisPoolObj_string.MGet(keyList) + if err != nil { + t.Fail() + } + got, err = redisPoolObj_string.Strings(got_interface) + if err != nil { + t.Fail() + } + if isTwoOrderedSliceEqual(got, expected) == false { + t.Errorf("Expected to get %v, but got %v", expected, got) + return + } + deleteKeys = append(deleteKeys, keyList...) +} + +func TestMSetNX(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + 对不存在的键执行 MSETNX 命令: + + redis> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis" + (integer) 1 + */ + key_value_map := make(map[string]interface{}) + key_value_map["rmdbs"] = "MySQL" + key_value_map["nosql"] = "MongoDB" + key_value_map["key-value-store"] = "redis" + successful, err := redisPoolObj_string.MSetNX(key_value_map) + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("It should be successful, but now it's not.") + return + } + + /* + + redis> MGET rmdbs nosql key-value-store + 1) "MySQL" + 2) "MongoDB" + 3) "redis" + 对某个已经存在的键进行设置: + */ + keyList := make([]string, 0, len(key_value_map)) + expected := make([]string, 0, len(key_value_map)) + for k, v := range key_value_map { + keyList = append(keyList, k) + if v_str, ok := v.(string); ok { + expected = append(expected, v_str) + } + } + got_interface, err := redisPoolObj_string.MGet(keyList) + if err != nil { + t.Fail() + } + got, err := redisPoolObj_string.Strings(got_interface) + if err != nil { + t.Fail() + } + if isTwoOrderedSliceEqual(got, expected) == false { + t.Errorf("Expected to get %v, but got %v", expected, got) + return + } + deleteKeys = append(deleteKeys, keyList...) + + /* + redis> MSETNX rmdbs "Sqlite" language "python" # rmdbs 键已经存在,操作失败 + (integer) 0 + */ + key_value_map = make(map[string]interface{}) + key_value_map["rmdbs"] = "Sqlite" + key_value_map["language"] = "python" + successful, err = redisPoolObj_string.MSetNX(key_value_map) + if err != nil { + t.Fail() + } + if successful { + t.Errorf("It should be not successful, but now it is.") + return + } + + /* + redis> EXISTS language # 因为 MSETNX 命令没有成功执行 + (integer) 0 # 所以 language 键没有被设置 + */ + key := "language" + exist, err := redisPoolObj_string.Exists(key) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("The key:%s should not exist, but now it does.", key) + return + } + + /* + redis> GET rmdbs # rmdbs 键也没有被修改 + "MySQL" + */ + key = "rmdbs" + expected2 := "MySQL" + got2_interface, exist, err := redisPoolObj_string.Get(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("The key:%s should exist, but now it doesn't.", key) + return + } + got2, err := redisPoolObj_string.String(got2_interface) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %v, but got %v", expected2, got2) + return + } +} + +func TestMGet(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + 代码示例 + redis> SET redis redis.com + OK + */ + key := "redis" + value := "redis.com" + successful, err := redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> SET mongodb mongodb.org + OK + */ + key = "mongodb" + value = "mongodb.org" + successful, err = redisPoolObj_string.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set key:%s should be successful, but now it's not.", key) + return + } + deleteKeys = append(deleteKeys, key) + + /* + redis> MGET redis mongodb + 1) "redis.com" + 2) "mongodb.org" + */ + keys := []string{"redis", "mongodb"} + expected := []string{"redis.com", "mongodb.org"} + got_interface, err := redisPoolObj_string.MGet(keys) + if err != nil { + t.Fail() + } + got, err := redisPoolObj_string.Strings(got_interface) + if err != nil { + t.Fail() + } + if isTwoOrderedSliceEqual(got, expected) == false { + t.Errorf("Expected to get %v, but got %v", expected, got) + return + } + + /* + redis> MGET redis mongodb mysql # 不存在的 mysql 返回 nil + 1) "redis.com" + 2) "mongodb.org" + 3) (nil) + */ + keys = []string{"redis", "mongodb", "mysql"} + expected = []string{"redis.com", "mongodb.org", ""} + got_interface, err = redisPoolObj_string.MGet(keys) + if err != nil { + t.Fail() + } + got, err = redisPoolObj_string.Strings(got_interface) + if err != nil { + t.Fail() + } + if isTwoOrderedSliceEqual(got, expected) == false { + t.Errorf("Expected to get %v, but got %v", expected, got) + return + } +} diff --git a/.svn/pristine/48/48003ffa1a6493e340cfad0e3092a40126a4aece.svn-base b/.svn/pristine/48/48003ffa1a6493e340cfad0e3092a40126a4aece.svn-base new file mode 100644 index 0000000..b0552a3 --- /dev/null +++ b/.svn/pristine/48/48003ffa1a6493e340cfad0e3092a40126a4aece.svn-base @@ -0,0 +1,43 @@ +package admin + +import ( + "common/connection" + "goutil/logUtilPlus" +) + +// AddAdmin 添加管理员 +// AddAdmin 添加新的管理员到数据库中。 +// 参数 admin: 包含管理员信息的对象。 +// 返回值: 插入操作影响的行数和可能发生的错误。 +func AddAdmin(admin *Admin) (int64, error) { + + //处理一些验证 + + // 写入到数据库 + result := connection.GetAdminDB().Create(&admin) // 通过数据的指针来创建 + + if result.Error != nil { + logUtilPlus.ErrorLog("添加管理员失败 错误信息:", result.Error.Error()) + } + return admin.ID, nil +} + +// GetAdminByID 根据管理员ID获取管理员信息 +func GetAdminByID(adminID int64) (*Admin, error) { + var admin Admin + result := connection.GetAdminDB().First(&admin, adminID) + if result.Error != nil { + return nil, result.Error + } + return &admin, nil +} + +// 管理员登录 +func Login(account string, password string) (*Admin, error) { + var admin Admin + result := connection.GetAdminDB().Where("account = ? AND password = ?", account, password).First(&admin) + if result.Error != nil { + return nil, result.Error + } + return &admin, nil +} diff --git a/.svn/pristine/48/4852aa2721098eea260b5d302d760e536bb7e64a.svn-base b/.svn/pristine/48/4852aa2721098eea260b5d302d760e536bb7e64a.svn-base new file mode 100644 index 0000000..fc28df4 --- /dev/null +++ b/.svn/pristine/48/4852aa2721098eea260b5d302d760e536bb7e64a.svn-base @@ -0,0 +1,35 @@ +package impl_localfile + +import "sync" + +func (l *Logger) InfoLog(format string, args ...interface{}) { + l.log(getLog(format, args...), info, true) +} + +func (l *Logger) WarnLog(format string, args ...interface{}) { + l.log(getLog(format, args...), warn, true) +} + +func (l *Logger) DebugLog(format string, args ...interface{}) { + l.log(getLog(format, args...), debug, true) +} + +func (l *Logger) ErrorLog(format string, args ...interface{}) { + l.log(getLog(format, args...), _error, true) +} + +func (l *Logger) FatalLog(format string, args ...interface{}) { + l.log(getLog(format, args...), fatal, true) +} + +func (l *Logger) CloseLog(waitFinish bool) { + wg := sync.WaitGroup{} + + // 关闭所有的file + for _, logger := range l.loggerMap { + wg.Add(1) + go logger.Close(&wg, waitFinish) + } + + wg.Wait() +} diff --git a/.svn/pristine/48/486e1cb4731af6df40aa03de3ed2ecdba22db264.svn-base b/.svn/pristine/48/486e1cb4731af6df40aa03de3ed2ecdba22db264.svn-base new file mode 100644 index 0000000..13ca2b8 --- /dev/null +++ b/.svn/pristine/48/486e1cb4731af6df40aa03de3ed2ecdba22db264.svn-base @@ -0,0 +1,135 @@ +package configUtil + +import ( + "fmt" + "testing" + + "goutil/xmlUtil" +) + +// bool值读取测试 +func TestBoolList(t *testing.T) { + xmlConfigData, errMsg := getxmlConfigListData() + if errMsg != nil { + t.Error(errMsg) + t.Fail() + + return + } + + booList, errMsg := xmlConfigData.BoolList("html/body/ul/li/a", "id") + if errMsg != nil { + t.Error(errMsg) + t.Fail() + return + } + fmt.Println("TestBoolList读取到的值:", booList) +} + +// int值读取测试 +func TestIntList(t *testing.T) { + xmlConfigData, errMsg := getxmlConfigListData() + if errMsg != nil { + t.Error(errMsg) + t.Fail() + + return + } + + valList, errMsg := xmlConfigData.IntList("html/body/ul/li/a", "id") + if errMsg != nil { + t.Error(errMsg) + t.Fail() + return + } + fmt.Println("TestInt读取到的值:", valList) +} + +// int64值读取测试 +func TestInt64List(t *testing.T) { + xmlConfigData, errMsg := getxmlConfigListData() + if errMsg != nil { + t.Error(errMsg) + t.Fail() + + return + } + + valList, errMsg := xmlConfigData.Int64List("html/body/ul/li/a", "id") + if errMsg != nil { + t.Error(errMsg) + t.Fail() + return + } + fmt.Println("TestInt64读取到的值:", valList) +} + +// Float值读取测试 +func TestFloatList(t *testing.T) { + xmlConfigData, errMsg := getxmlConfigListData() + if errMsg != nil { + t.Error(errMsg) + t.Fail() + + return + } + + valList, errMsg := xmlConfigData.FloatList("html/body/ul/li/a", "id") + if errMsg != nil { + t.Error(errMsg) + t.Fail() + return + } + fmt.Println("TestFloat读取到的值:", valList) +} + +// 字符串读取测试 +func TestStringList(t *testing.T) { + xmlConfigData, errMsg := getxmlConfigListData() + if errMsg != nil { + t.Error(errMsg) + t.Fail() + + return + } + + valList, errMsg := xmlConfigData.StringList("html/body/ul/li/a", "id") + if errMsg != nil { + t.Error(errMsg) + t.Fail() + return + } + fmt.Println("TestString读取到的值:", valList) +} + +func getxmlConfigListData() (xmlConfigData *XmlConfig, errMsg error) { + content := ` + + + Hello + + + +

This is a H1

+ +

+ Hello,This is an example for gxpath. +

+
footer script
+ + + ` + var root *xmlUtil.Node + root, errMsg = xmlUtil.LoadFromString(content) + if errMsg == nil { + xmlConfigData = NewXmlConfig() + xmlConfigData.LoadFromXmlNode(root) + } + + return +} diff --git a/.svn/pristine/48/48765b4ca5ea1ebef8ef05e1ac43f034ae2cc57a.svn-base b/.svn/pristine/48/48765b4ca5ea1ebef8ef05e1ac43f034ae2cc57a.svn-base new file mode 100644 index 0000000..2233230 --- /dev/null +++ b/.svn/pristine/48/48765b4ca5ea1ebef8ef05e1ac43f034ae2cc57a.svn-base @@ -0,0 +1,4 @@ +/* +数学助手包,提供一些与数学相关的助手方法 +*/ +package mathUtil diff --git a/.svn/pristine/48/48c5b123aaa4f5248637d444f7ab2c0fef970cc8.svn-base b/.svn/pristine/48/48c5b123aaa4f5248637d444f7ab2c0fef970cc8.svn-base new file mode 100644 index 0000000..f74b1ba --- /dev/null +++ b/.svn/pristine/48/48c5b123aaa4f5248637d444f7ab2c0fef970cc8.svn-base @@ -0,0 +1,216 @@ +// 适用于大量http(s)请求,连接复用 +package webUtil + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptrace" + "net/url" + "time" +) + +type Client struct { + traceCtx context.Context + client *http.Client +} + +type TransportOPT struct { + //超时时间 + Timeout time.Duration + + //代理字符串,如"http://127.0.0.1:1080" + ProxyString string + + //最大保持连接数 + MaxIdleConns int + + //每个主机的最大保持连接数 + MaxIdleConnsPerHost int + + //单主机最大连接数 + MaxConnsPerHost int + + //保持连接的超时时间 + IdleConnTimeout time.Duration + + //禁止保持连接 + DisableKeepAlives bool +} + +// GET请求 +func (c *Client) Get(urlStr string, header map[string]string) (result []byte, err error) { + req, err := http.NewRequestWithContext(c.traceCtx, http.MethodGet, urlStr, nil) + if err != nil { + //fmt.Println(err) + return + } + + // 处理头部(包括默认头部,以及传入的头部集合) + if header == nil { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + } else { + for k, v := range header { + req.Header.Add(k, v) + } + } + + res, err := c.client.Do(req) + if err != nil { + //fmt.Println(err) + return + } + defer res.Body.Close() + + result, err = ioutil.ReadAll(res.Body) + + return +} + +// POST请求 +func (c *Client) PostWithMap(urlStr string, data map[string]string, header map[string]string) (result []byte, err error) { + // 组装POST数据 + postValues := url.Values{} + for key, value := range data { + postValues.Set(key, value) + } + postDataStr := postValues.Encode() + byteData := []byte(postDataStr) + + var req *http.Request + req, err = http.NewRequestWithContext(c.traceCtx, http.MethodPost, urlStr, bytes.NewReader(byteData)) + if err != nil { + //fmt.Println(err) + return + } + + // 处理头部(包括默认头部,以及传入的头部集合) + if header == nil { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + } else { + for k, v := range header { + req.Header.Add(k, v) + } + } + + var res *http.Response + res, err = c.client.Do(req) + if err != nil { + fmt.Println(err) + return + } + defer res.Body.Close() + + result, err = ioutil.ReadAll(res.Body) + + return +} + +// POST请求 +func (c *Client) PostWithByte(urlStr string, data []byte, header map[string]string) (result []byte, err error) { + var req *http.Request + req, err = http.NewRequestWithContext(c.traceCtx, http.MethodPost, urlStr, bytes.NewReader(data)) + if err != nil { + //fmt.Println(err) + return + } + + // 处理头部(包括默认头部,以及传入的头部集合) + if header == nil { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + } else { + for k, v := range header { + req.Header.Add(k, v) + } + } + + var res *http.Response + res, err = c.client.Do(req) + if err != nil { + fmt.Println(err) + return + } + defer res.Body.Close() + + result, err = ioutil.ReadAll(res.Body) + + return +} + +// 新建Client对象 +// transportOPT参数说明 +// +// Timeout - 连接绝对超时时间 +// ProxyString - 代理字符串 +// MaxIdleConns - 最大空闲连接数 +// MaxIdleConnsPerHost - 每个目标主机的最大空闲连接数 +// MaxConnsPerHost - 每个目标主机的最大连接数 +// IdleConnTimeout - 空闲连接超时时间 +// DisableKeepAlives - 禁用连接保持(要使用连接复用,此值不传入或传入false;否则连接可能不会复用) +func NewClient(transportOPT *TransportOPT) (c *Client) { + c = &Client{} + + //代理 + getProxy := func() func(*http.Request) (*url.URL, error) { + if (transportOPT != nil) && len(transportOPT.ProxyString) > 0 { + uri, _ := url.Parse(transportOPT.ProxyString) + return http.ProxyURL(uri) + } + + return nil + } + + // 默认参数 + timeout := 30 * time.Second + maxIdleConns := 60000 + maxIdleConnsPerHost := 30000 + maxConnsPerHost := 30000 + idleConnTimeout := time.Minute * 1 + disableKeepAlives := false + + if transportOPT != nil { + // 根据传入参数修改默认参数 + if transportOPT.Timeout > 0 { + timeout = transportOPT.Timeout + } + if transportOPT.MaxIdleConns > 0 { + maxIdleConns = transportOPT.MaxIdleConns + } + if transportOPT.MaxIdleConnsPerHost > 0 { + maxIdleConnsPerHost = transportOPT.MaxIdleConnsPerHost + } + if transportOPT.MaxConnsPerHost > 0 { + maxConnsPerHost = transportOPT.MaxConnsPerHost + } + if transportOPT.IdleConnTimeout > 0 { + idleConnTimeout = transportOPT.IdleConnTimeout + } + + disableKeepAlives = transportOPT.DisableKeepAlives + } + + clientTrace := &httptrace.ClientTrace{ + //GotConn: func(gci httptrace.GotConnInfo) { + // fmt.Printf("conn was reused: %t\n", gci.Reused) + //}, + } + + c.traceCtx = httptrace.WithClientTrace(context.Background(), clientTrace) + c.client = &http.Client{ + Timeout: timeout, + + Transport: &http.Transport{ + Proxy: getProxy(), + MaxIdleConns: maxIdleConns, + MaxIdleConnsPerHost: maxIdleConnsPerHost, + MaxConnsPerHost: maxConnsPerHost, + IdleConnTimeout: idleConnTimeout, + DisableKeepAlives: disableKeepAlives, + // ForceAttemptHTTP2: true, + }, + } + + return +} diff --git a/.svn/pristine/49/492bfe99e7af5f1f82645c1b1302f1536f95c33f.svn-base b/.svn/pristine/49/492bfe99e7af5f1f82645c1b1302f1536f95c33f.svn-base new file mode 100644 index 0000000..0007c44 --- /dev/null +++ b/.svn/pristine/49/492bfe99e7af5f1f82645c1b1302f1536f95c33f.svn-base @@ -0,0 +1,225 @@ +package connection + +import ( + "context" + "fmt" + "framework/sqlAsyncMgr" + goredis "github.com/go-redis/redis/v8" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "goutil/logUtilPlus" + "time" + + // _ "github.com/go-sql-driver/mysql" + config "common/configsYaml" + "goutil/mysqlUtil" + "goutil/redisUtil" +) + +var ( + adminDB *gorm.DB //管理员数据库对象 + userDB *gorm.DB //用户数据库对象 + gameModelDB *gorm.DB // 游戏模型数据库对象 + gameDB *gorm.DB // 游戏数据库 + gamePlayerDB *gorm.DB // 玩家库 + redisDB *goredis.Client // 游戏redis连接客户端 + syncMgr *sqlAsyncMgr.SqlAsyncUtil // 同步管理对象 + syncFileSize = 1024 * 1024 // 同步文件大小 + fileMaxSaveTime = 24 * 7 // 保留7天的sql文件 +) + +var excuteSqlFunc func(*gorm.DB, ITable, string) error +var loghandle func(s string, is ...interface{}) +var defaultType = SyncSql + +type ITable interface { + TableName() string +} + +type SqlExecuteType int32 + +const ( + SyncSql SqlExecuteType = iota + ASyncSql + Name = "BaseDal" +) + +// init +// @description: init +// parameter: +// return: +func init() { + + //管理中心数据库配置 + adminDB = initMysql(config.GetDbConfig().GetAdminConfig()) + userDB = initMysql(config.GetDbConfig().GetUserConfig()) + + // 初始化游戏模型数据库 + gameModelDBConfig := config.GetDbConfig().GetGameModelConfig() + gameModelDB = initMysql(gameModelDBConfig) + + // 初始化crossSever 游戏数据库 + gameDBConfig := config.GetDbConfig().GetGameConfig() + gameDB = initMysql(gameDBConfig) + gamePlayerDB = initMysql(config.GetDbConfig().GetPlayerConfig()) + + // 初始化redis-client + excuteSqlFunc = func(gdb *gorm.DB, table ITable, sql string) error { + db := gdb.Exec(sql) + if db.Error != nil { + loghandle("sql执行错误:%s;错误信息:%v", sql, db.Error.Error()) + return db.Error + } + + return nil + } + + redisDB = initRedis(config.GetDbConfig().GetRedisConfig()) +} + +// 初始化Mysql +// initMysql +// @description: 初始化Mysql +// parameter: +// @dbConfig: dbConfig +// return: +// @*gorm.DB: DB +func initMysql(dbConfig *mysqlUtil.DBConfig) *gorm.DB { + + //不存在配置 + if dbConfig == nil || dbConfig.ConnectionString == "" { + return nil + } + logUtilPlus.WarnLog("开始连接mysql:%s", dbConfig.ConnectionString) + dbObj, err := gorm.Open(mysql.Open(dbConfig.ConnectionString), &gorm.Config{}) + if err != nil { + panic(fmt.Errorf("初始化数据库:%s失败,错误信息为:%s", dbConfig.ConnectionString, err)) + } + logUtilPlus.WarnLog("连接mysql:%s成功", dbConfig.ConnectionString) + + return dbObj +} + +// initRedis +// @description: 初始化redis客户端 +// parameter: +// @redisConfig: redisConfig +// return: +// @*goredis.Client: Client +func initRedis(redisConfig *redisUtil.RedisConfig) *goredis.Client { + + client := goredis.NewClient(&goredis.Options{ + Addr: redisConfig.ConnectionString, + Password: redisConfig.Password, + DB: redisConfig.Database, + IdleTimeout: redisConfig.IdleTimeout, + DialTimeout: redisConfig.DialConnectTimeout, + }) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + + ping, err := client.Ping(ctx).Result() + if err != nil { + panic(fmt.Errorf("ping->redis:%s失败,DB:%s,错误信息为:%s", redisConfig.ConnectionString, redisConfig.Database, err)) + } + + logUtilPlus.WarnLog("ping->redis:%s成功,信息为:%s", redisConfig.ConnectionString, ping) + return client +} + +// GetAdminDB +// @description: 获取admin库db实例 +// parameter: +// return: +// @*gorm.DB:admin库db实例 +func GetAdminDB() *gorm.DB { + return adminDB +} + +// GetUserDB +// @description: 获取user库db实例 +// parameter: +// return: +// @*gorm.DB:user库db实例 +func GetUserDB() *gorm.DB { + return userDB +} + +// GetGameDB +// @description: 获取game库db实例 +// parameter: +// return: +// @*gorm.DB:game库db实例 +func GetGameDB() *gorm.DB { + return gameDB +} + +// GetPlayerDB +// @description: 获取玩家库db实例 +// parameter: +// return: +// @*gorm.DB:玩家库db实例 +func GetPlayerDB() *gorm.DB { + return gamePlayerDB +} + +// GetGameModelDB +// @description: 获取model库db实例 +// parameter: +// return: +// @*gorm.DB:model库db实例 +func GetGameModelDB() *gorm.DB { + return gameModelDB +} + +// GetRedisClient +// @description: 获取redisdb实例 +// parameter: +// return: +// @*goredis.Client:redisdb实例 +func GetRedisClient() *goredis.Client { + return redisDB +} + +// GetAll +// @description: 获取model数据 +// parameter: +// @dataList:数据列表 +// return: +// @error:错误信息 +func GetAll(dataList interface{}) error { + mysqlObj := GetGameModelDB() + if mysqlObj = mysqlObj.Find(dataList); mysqlObj.Error != nil { + WriteLog("dal.GetAll", mysqlObj.Error) + return mysqlObj.Error + } + + return nil +} + +// GetGameModelData +// @description: 获取GameModel数据 +// parameter: +// @moduleName:模块名称 +// @dataList:数据列表 +// return: +// @error:错误信息 +func GetGameModelData(moduleName string, dataList interface{}) error { + if result := gameModelDB.Find(dataList); result.Error != nil { + WriteLog(moduleName+"GetGameModelData", result.Error) + return result.Error + } + + return nil +} + +// WriteLog +// @description: 记录错误日志 +// parameter: +// @command:命令 +// @err:错误信息 +// return: +func WriteLog(command string, err error) { + logUtilPlus.ErrorLog(fmt.Sprintf("Scan失败,错误信息:%s,command:%s", err, command)) +} diff --git a/.svn/pristine/49/496a3674ea3bdc4d3c6456f7cd29c29cd7bd701d.svn-base b/.svn/pristine/49/496a3674ea3bdc4d3c6456f7cd29c29cd7bd701d.svn-base new file mode 100644 index 0000000..7fb2dac --- /dev/null +++ b/.svn/pristine/49/496a3674ea3bdc4d3c6456f7cd29c29cd7bd701d.svn-base @@ -0,0 +1,58 @@ +package model + +// 消费消息请求对象 +type GetQueueAttributesRequest struct { + // 公共请求参数 + common *CommonRequest +} + +// 获取请求方法名 +func (this *GetQueueAttributesRequest) GetActionName() string { + return "GetQueueAttributes" +} + +// SetCommonRequestObject 设置公共请求对象 +func (this *GetQueueAttributesRequest) SetCommonRequest(commonRequest *CommonRequest) { + this.common = commonRequest +} + +// AssembleParamMap 组装参数字典 +// 返回值 +// map[string]string:请求参数字典 +func (this *GetQueueAttributesRequest) AssembleParamMap() map[string]string { + paramMap := this.common.AssembleParamMap() + + return paramMap +} + +func NewGetQueueAttributesRequest() *GetQueueAttributesRequest { + return &GetQueueAttributesRequest{} +} + +// 消费消息请求返回结果对象 +type GetQueueAttributesResponse struct { + *CommonResponse + + MaxMsgHeapNum int `json:"maxMsgHeapNum"` // 最大堆积消息数。取值范围在公测期间为 1,000,000 - 10,000,000,正式上线后范围可达到 1000,000-1000,000,000。默认取值在公测期间为 10,000,000,正式上线后为 100,000,000。 + PollingWaitSeconds int `json:"pollingWaitSeconds"` // 消息接收长轮询等待时间。取值范围0 - 30秒,默认值0。 + VisibilityTimeout int `json:"visibilityTimeout"` // 消息可见性超时。取值范围1 - 43200秒(即12小时内),默认值30。 + MaxMsgSize int `json:"maxMsgSize"` // 消息最大长度。取值范围1024 - 1048576 Byte(即1K - 1024K),默认值65536。 + MsgRetentionSeconds int `json:"msgRetentionSeconds"` // 消息保留周期。取值范围60-1296000秒(1min-15天),默认值345600秒(4 天)。 + CreateTime int `json:"createTime"` // 队列的创建时间。返回 Unix 时间戳,精确到秒。 + LastModifyTime int `json:"lastModifyTime"` // 最后一次修改队列属性的时间。返回 Unix 时间戳,精确到秒。 + ActiveMsgNum int `json:"activeMsgNum"` // 在队列中处于 Active 状态(不处于被消费状态)的消息总数,为近似值。 + InactiveMsgNum int `json:"inactiveMsgNum"` // 在队列中处于 Inactive 状态(正处于被消费状态)的消息总数,为近似值。 + RewindSeconds int `json:"rewindSeconds"` // 回溯队列的消息回溯时间最大值,取值范围0 - 43200秒,0表示不开启消息回溯。 + RewindmsgNum int `json:"rewindmsgNum"` // 已调用 DelMsg 接口删除,但还在回溯保留时间内的消息数量。 + MinMsgTime int `json:"minMsgTime"` // 消息最小未消费时间,单位为秒。 + QueueName string `json:"queueName"` // 消息队列名字。 + QueueId string `json:"queueId"` // 消息队列ID。 + CreateUin int64 `json:"createUin"` // 创建者Uin。 + Bps int `json:"Bps"` // 带宽限制。 + Qps int `json:"qps"` // 每秒钟生产消息条数的限制,消费消息的大小是该值的1.1倍。 + Tags []string `json:"tags"` // 关联的标签。 +} + +func NewGetQueueAttributesResponse() *GetQueueAttributesResponse { + return &GetQueueAttributesResponse{} +} diff --git a/.svn/pristine/49/4995fa2b02485de6eb3a2c938963067ee4ef19bf.svn-base b/.svn/pristine/49/4995fa2b02485de6eb3a2c938963067ee4ef19bf.svn-base new file mode 100644 index 0000000..0160c32 --- /dev/null +++ b/.svn/pristine/49/4995fa2b02485de6eb3a2c938963067ee4ef19bf.svn-base @@ -0,0 +1,7 @@ +package httpSender + +// 发送器 +// 用于发送Requester +type Sender interface { + Send(req Requester) ([]byte, error) +} diff --git a/.svn/pristine/49/49ee5106c29cff02591a87a5b23b6d636baf73e0.svn-base b/.svn/pristine/49/49ee5106c29cff02591a87a5b23b6d636baf73e0.svn-base new file mode 100644 index 0000000..ec7d8cd --- /dev/null +++ b/.svn/pristine/49/49ee5106c29cff02591a87a5b23b6d636baf73e0.svn-base @@ -0,0 +1,126 @@ +package contextcheckMgr + +import ( + "encoding/json" + "fmt" + "math/rand" + "sort" + "strconv" + "time" + + "goutil/logUtil" + "goutil/securityUtil" + "goutil/webUtil" +) + +var ( + //接口密钥Id + msecretId string = "c98276c73c122eaa65163fe431cbf7d4" + //接口密钥key + msecretKey string = "3d2b39f824fa2f992494e17be500e303" + //业务ID + mbusinessId string = "9559ce74b5c5d24f6b124799a53c7431" + //接口请求地址 + mapiurl string = "http://as.dun.163.com/v3/text/check" + //版本号 + mversion string = "v3.1" +) + +//参数设置 +func SetPara(secretId, secretKey, businessId, apiurl, version string) { + msecretId = secretId + msecretKey = secretKey + mbusinessId = businessId + mapiurl = apiurl + mversion = version +} + +//content:用户发表内容 +//account:玩家账号(用户唯一标识) +//nickname:角色名称 +//extStr1:角色区服名称 +//extStr2:UserId +//ip:用户IP地址,建议抄送,辅助机审策略精准调优 +//extLon1:区服ID +//返回值 code: 0:通过, 1:嫌疑,2:不通过 +//文本内容检测 +func TextCheck(content, account, nickname, extStr1, extStr2, ip string, extLon1 int64) (code int, err error) { + //构造请求参数 + postDataDict := make(map[string]string) + postDataDict["secretId"] = msecretId + postDataDict["businessId"] = mbusinessId + postDataDict["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10) + postDataDict["nonce"] = strconv.FormatInt(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(10000000000), 10) + rawString := fmt.Sprintf("%v%v%v", account, postDataDict["timestamp"], content) + postDataDict["dataId"] = securityUtil.Md5String(rawString, false) + postDataDict["content"] = content + postDataDict["version"] = mversion + postDataDict["account"] = account + postDataDict["nickname"] = nickname + postDataDict["extLon1"] = strconv.FormatInt(extLon1, 10) + // postDataDict["extLon2"] = extLon2 + postDataDict["extStr1"] = extStr1 + postDataDict["extStr2"] = extStr2 + postDataDict["ip"] = ip + postDataDict["signature"] = getSignature(postDataDict) + + //请求url,请求头 + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, 30) + + //请求接口 + statusCode, result, err := webUtil.PostMapData(mapiurl, postDataDict, header, transport) + //定义错误信息 + var logMessage string + + //post请求错误 + if err != nil { + logMessage = fmt.Sprintf("TextCheck:,错误信息为:%s", err.Error()) + logUtil.ErrorLog(logMessage) + return + } + if statusCode != 200 { + logMessage = fmt.Sprintf("TextCheck:%d is wrong", statusCode) + logUtil.ErrorLog(logMessage) + err = fmt.Errorf("TextCheck:%d is wrong", statusCode) + return + } + + //反序列化结果 + var checkResponseObj *ResultModel + err = json.Unmarshal(result, &checkResponseObj) + if err != nil { + logMessage = fmt.Sprintf("json.Unmarshal(checkResponseObj),err:%s", err.Error()) + logUtil.ErrorLog(logMessage) + return + } + + //判断接口是否调用成功 + if checkResponseObj.Code != 200 { + logMessage = fmt.Sprintf("TextCheck接口调用失败,ResultStatus %d", checkResponseObj.Code) + err = fmt.Errorf("TextCheck接口调用失败,code:%d", checkResponseObj.Code) + return + } + + //返回检测结果 + code = checkResponseObj.Result.Action + return +} + +//生成签名字符串 +func getSignature(postDataDict map[string]string) string { + var paramStr string + keys := make([]string, 0, len(postDataDict)) + for k := range postDataDict { + keys = append(keys, k) + } + sort.Strings(keys) + for _, key := range keys { + paramStr += key + postDataDict[key] + } + paramStr += msecretKey + + return securityUtil.Md5String(paramStr, false) +} diff --git a/.svn/pristine/4a/4a49ef451d4b9f74fdb2c8830143bbaec17f3ce3.svn-base b/.svn/pristine/4a/4a49ef451d4b9f74fdb2c8830143bbaec17f3ce3.svn-base new file mode 100644 index 0000000..b96f89c --- /dev/null +++ b/.svn/pristine/4a/4a49ef451d4b9f74fdb2c8830143bbaec17f3ce3.svn-base @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + \ No newline at end of file diff --git a/.svn/pristine/4b/4b8e1ac3d261e7448019224293b8c2f300ee0ab3.svn-base b/.svn/pristine/4b/4b8e1ac3d261e7448019224293b8c2f300ee0ab3.svn-base new file mode 100644 index 0000000..efc382b --- /dev/null +++ b/.svn/pristine/4b/4b8e1ac3d261e7448019224293b8c2f300ee0ab3.svn-base @@ -0,0 +1,27 @@ +package zooKeeperMgr + +import ( + "testing" + "time" + + "github.com/samuel/go-zookeeper/zk" +) + +func TestCascadeCreate(t *testing.T) { + zkConfigObj := &ZooKeeperConfig { + Servers: "172.27.0.4:2181,172.27.0.6:2181,172.27.0.9:2181", + StartPath: "/Develop/GameServer", + SessionTimeout: 10 * time.Second, + } + + conn, _, err := zk.Connect(zkConfigObj.GetServerList(), zkConfigObj.SessionTimeout) + if err != nil { + panic(err) + } + defer conn.Close() + + err = CascadeCreate(conn, zkConfigObj.StartPath) + if err != nil { + t.Errorf("There should be no error, but now there is:%v", err) + } +} \ No newline at end of file diff --git a/.svn/pristine/4c/4c23f994a6d4b535e3554239a36e580922efb062.svn-base b/.svn/pristine/4c/4c23f994a6d4b535e3554239a36e580922efb062.svn-base new file mode 100644 index 0000000..1030862 --- /dev/null +++ b/.svn/pristine/4c/4c23f994a6d4b535e3554239a36e580922efb062.svn-base @@ -0,0 +1,77 @@ +package sqlAsyncMgr + +import ( + "sync" + "sync/atomic" +) + +// SqlAsyncIdentityStatistics sql标识统计类 +type SqlAsyncIdentityStatistics struct { + // 锁对象 + m sync.Mutex + + // 当前正在同步的sql数量 + syncCount int32 + + // 待同步的统计 + statisticData map[string]*StatisticModel +} + +// newSqlAsyncIdentityStatistics 创建新StatisticModel对象 +func newSqlAsyncIdentityStatistics() *SqlAsyncIdentityStatistics { + return &SqlAsyncIdentityStatistics{ + statisticData: make(map[string]*StatisticModel), + } +} + +// getItem 获取指定统计对象 +func (this *SqlAsyncIdentityStatistics) getItem(_identityId string, isCreate bool) *StatisticModel { + this.m.Lock() + defer this.m.Unlock() + + if item, exists := this.statisticData[_identityId]; exists { + return item + } + + if isCreate == false { + return nil + } + + newItem := newStatisticModel(_identityId) + this.statisticData[_identityId] = newItem + + return newItem +} + +// AddCount 指定标识添加数量 +func (this *SqlAsyncIdentityStatistics) AddCount(_identityId string, count int32) { + model := this.getItem(_identityId, true) + model.AddCount(count) + + // 原子操作相加 + atomic.AddInt32(&this.syncCount, count) +} + +// Reduce 指定标识减少数量 +func (this *SqlAsyncIdentityStatistics) Reduce(_identityId string, count int32) { + if model := this.getItem(_identityId, false); model != nil { + model.ReduceCount(count) + } + + // 原子操作相减 + atomic.AddInt32(&this.syncCount, -count) +} + +// GetCount 获取指定标识的数量 +func (this *SqlAsyncIdentityStatistics) GetCount(_identityId string) int32 { + if model := this.getItem(_identityId, false); model != nil { + return model.Count + } + + return 0 +} + +// GetAllCount 获取总的待写入数据 +func (this *SqlAsyncIdentityStatistics) GetAllCount() int32 { + return this.syncCount +} diff --git a/.svn/pristine/4c/4cdf5c756ca8b6b4c1684486b413f058cbcdef5b.svn-base b/.svn/pristine/4c/4cdf5c756ca8b6b4c1684486b413f058cbcdef5b.svn-base new file mode 100644 index 0000000..4f400e2 --- /dev/null +++ b/.svn/pristine/4c/4cdf5c756ca8b6b4c1684486b413f058cbcdef5b.svn-base @@ -0,0 +1,18 @@ +package managecenterModel + +// 服务器组热度 +type GroupHeat int32 + +const ( + // 正常 + Con_GroupHeat_Normal GroupHeat = 1 + + // 新服 + Con_GroupHeat_New GroupHeat = 2 + + // 推荐 + Con_GroupHeat_Recommend GroupHeat = 3 + + // 热门 + Con_GroupHeat_Heat GroupHeat = 4 +) diff --git a/.svn/pristine/4d/4d9ed17b45d8fe9611097a5640452068f52cfc06.svn-base b/.svn/pristine/4d/4d9ed17b45d8fe9611097a5640452068f52cfc06.svn-base new file mode 100644 index 0000000..fa17bbf --- /dev/null +++ b/.svn/pristine/4d/4d9ed17b45d8fe9611097a5640452068f52cfc06.svn-base @@ -0,0 +1,208 @@ +package bytesSendUtil + +import ( + "encoding/binary" + "fmt" + "net" + "sync" + "time" + + "goutil/intAndBytesUtil" + "goutil/logUtil" +) + +var ( + errConnectEmpty = fmt.Errorf("scoket reconnecting...") + byterOrder = binary.LittleEndian +) + +// 实现 EnsureSender和sender接口 +type tcpSender struct { + // 需要实现的接口 + EnsureSender + + // 包含sender接口部分实现 + *baseSender + + // 数据目录 + dataFolder string + + // 服务器地址 + address string + + // 连接 + conn net.Conn + + // 用于重连时互斥 + mutex sync.Mutex + + // 用于sendLoop和resendLoop发送退出信号 + closeSignal chan struct{} +} + +// 创建一个tcp数据发送器 +// 参数: +// +// _dataFolder 数据存放目录 +// _address 连接地址 +func NewTCPSender(_dataFolder, _address string) (EnsureSender, error) { + // 连接服务器 + conn, err := net.DialTimeout("tcp", _address, 5*time.Second) + if err != nil { + return nil, err + } + + this := &tcpSender{ + dataFolder: _dataFolder, + baseSender: newBaseSender(), + address: _address, + conn: conn, + closeSignal: make(chan struct{}), + } + + // 新开协程发送数据 + go sendLoop(this, this.closeSignal) + + // 定时重发 + go resendLoop(this, _dataFolder, this.closeSignal) + + // 发送心跳包 + go this.heartBeat() + + return this, nil +} + +// 每隔15秒发送心跳包 +func (this *tcpSender) heartBeat() { + defer func() { + if r := recover(); r != nil { + logUtil.LogUnknownError(r) + } + }() + + tick := time.Tick(time.Second * 15) + + for { + select { + case <-this.Done(): + return + case <-tick: + this.sendBytes([]byte{}) + } + } +} + +// EnsureSender接口 +// Write:写入数据 +func (this *tcpSender) Write(data []byte) error { + item, err := newTCPDataItem(data) + if err != nil { + return err + } + + this.waitingDataChan <- item + + return nil +} + +// EnsureSender接口 +// Close:关闭 +func (this *tcpSender) Close() error { + close(this.done) + + // 关闭socket连接 + conn := this.conn + if conn != nil { + conn.Close() + } + + // 等待sendLoop和resendLoop退出 + <-this.closeSignal + <-this.closeSignal + + // 保存数据 + _, e1 := saveData(this.Cache(), this.dataFolder) + _, e2 := saveData(this.Data(), this.dataFolder) + + if e2 != nil { + if e1 != nil { + return fmt.Errorf("%s %s", e1, e2) + } + return e2 + } else { + return e1 + } +} + +// Sender接口 +// Send:发送dataItem +func (this *tcpSender) Send(item dataItem) error { + err := this.sendBytes(item.Bytes()) + if err != nil && err != errConnectEmpty { + // 发送失败时发送次数+1 + item.SetCount(item.Count() + 1) + } + + return err +} + +// 发送字节数据 +// 发送格式:[lenght+data] +func (this *tcpSender) sendBytes(data []byte) error { + conn := this.conn + if conn == nil { + return errConnectEmpty + } + + // 将长度转化为字节数组 + header := intAndBytesUtil.Int32ToBytes(int32(len(data)), byterOrder) + + if len(data) > 0 { + data = append(header, data...) + } else { + data = header + } + + _, err := conn.Write(data) + if err != nil { + this.mutex.Lock() + // 发送失败 + // 检查失败的conn是否this.conn(避免多个线程失败后均调用reconnect) + // 是则关闭并重连 + if conn == this.conn { + this.conn.Close() + this.conn = nil + this.mutex.Unlock() + + // 重连 + go this.reconnect() + } else { + this.mutex.Unlock() + } + } + + return err +} + +// 重连服务器 +func (this *tcpSender) reconnect() error { + // lock-it + this.mutex.Lock() + defer this.mutex.Unlock() + + for { + // 检查是否已经重连 + if this.conn != nil { + return nil + } + + conn, err := net.DialTimeout("tcp", this.address, 5*time.Second) + if err != nil { + // 连接失败,5秒后重试 + <-time.After(time.Second * 5) + continue + } + + this.conn = conn + } +} diff --git a/.svn/pristine/4d/4de7d0e1719fe7c5227e762a9cfdbfea79af5c81.svn-base b/.svn/pristine/4d/4de7d0e1719fe7c5227e762a9cfdbfea79af5c81.svn-base new file mode 100644 index 0000000..2242ca7 --- /dev/null +++ b/.svn/pristine/4d/4de7d0e1719fe7c5227e762a9cfdbfea79af5c81.svn-base @@ -0,0 +1,37 @@ +version: '3' +services: + mysql: + image: mysql:8.0 + container_name: mysql-admin + environment: + MYSQL_ROOT_PASSWORD: 123456 + MYSQL_DATABASE: admin,user + volumes: + - /my/own/datadir:/var/lib/mysql + ports: + - "3306:3306" + redis: + image: redis:7.0 + container_name: redis-admin + ports: + - "6379:6379" + volumes: + - redis_data:/data + restart: always + command: ["redis-server", "--appendonly", "yes"] + + admin-center: + build: + context: . + dockerfile: Dockerfile + container_name: admin-center + ports: + - "10051:10051" + volumes: + - ./app:/app + depends_on: + - mysql + - redis + +volumes: + redis_data: \ No newline at end of file diff --git a/.svn/pristine/4e/4e0d2175915e4e0a382656f419b23ec37c1dea9a.svn-base b/.svn/pristine/4e/4e0d2175915e4e0a382656f419b23ec37c1dea9a.svn-base new file mode 100644 index 0000000..8f3ebec --- /dev/null +++ b/.svn/pristine/4e/4e0d2175915e4e0a382656f419b23ec37c1dea9a.svn-base @@ -0,0 +1,77 @@ +// Package routineCtrlUtil +// +// @description: 协程控制-用于海量循环中,限制并发的最大同时执行协程数 +// @author: +// @revision history: +// @create date: 2022-02-23 17:23:06 +package routineCtrlUtil + +import "sync" + +// RoutineCtrl +// +// @description: 控制同时运行的协程数 +type RoutineCtrl struct { + wg *sync.WaitGroup + chNum chan struct{} +} + +// Run +// +// @description: 循环内待执行的协程,封装在f函数参数内执行。f函数的最大并发运行数受New参数maxNum限制 +// 注意:*** 待执行函数引用外变变量,程序可能会出现不符合逻辑的结果(外部变量变化时,闭包函数获取到的是变化后的变量值) *** +// *** 闭包函数避坑说明 *** +// 方式1)将待执行函数内使用的外部变量,用参数传入,可避免不符合逻辑的结果 +// 方式2)将待执行函数内使用的外部变量,使用一个临时局部变量将其值“固定”下来,闭包内使用临时局部变量(临时局部变量不会再被修改) +// 示例:routine_ctrl_test.go -> TestRoutineCtrl +// +// parameter: +// +// @receiver rtCtrl: +// @f: 循环内待执行的协程 +// +// return: +func (rtCtrl *RoutineCtrl) Run(f func(interface{}), arg interface{}) { + rtCtrl.wg.Add(1) + rtCtrl.chNum <- struct{}{} + go func() { + defer func() { + <-rtCtrl.chNum + rtCtrl.wg.Done() + recover() // 异常捕获 + }() + + f(arg) // 调用实际函数体 + }() +} + +// Wait +// +// @description: 在循环外面等待所有协程执行结束后返回 +// +// parameter: +// +// @receiver rtCtrl: +// +// return: +func (rtCtrl *RoutineCtrl) Wait() { + rtCtrl.wg.Wait() +} + +// New +// +// @description: 产生一个协程控制对象 +// +// parameter: +// +// @maxNum: 限制调用Run时的f函数的最大运行协程数 +// +// return: +// +// @*RoutineCtrl: +func New(maxNum int) *RoutineCtrl { + return &RoutineCtrl{ + wg: &sync.WaitGroup{}, + chNum: make(chan struct{}, maxNum), + } +} diff --git a/.svn/pristine/51/5134bf90a024b2d740a38545632f8b07a313f9ec.svn-base b/.svn/pristine/51/5134bf90a024b2d740a38545632f8b07a313f9ec.svn-base new file mode 100644 index 0000000..1cd3267 --- /dev/null +++ b/.svn/pristine/51/5134bf90a024b2d740a38545632f8b07a313f9ec.svn-base @@ -0,0 +1,182 @@ +package webUtil + +import ( + "fmt" + "io/ioutil" + "net/http" + "strings" +) + +// GET数据 +// weburl:远程服务器地址 +// header:包头集合 +// 返回值: +// 返回的字节 +// 错误对象 +func GetWebData(weburl string, header map[string]string) (result []byte, err error) { + // 构造请求对象 + var request *http.Request + request, err = http.NewRequest("GET", weburl, nil) + if err != nil { + return + } + + // 处理包头 + if header != nil { + for k, v := range header { + request.Header.Add(k, v) + } + } + + // 构造transport对象 + transport := NewTransport() + transport.DisableKeepAlives = true + transport = GetTimeoutTransport(transport, 30) + + // 构造httpClient对象 + client := &http.Client{Transport: transport} + + // 发送数据 + var response *http.Response + response, err = client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + // 读取数据 + if response.StatusCode == http.StatusOK { + result, err = ioutil.ReadAll(response.Body) + if err != nil { + return + } + } + + return +} + +// GET数据(新方法) +// weburl:远程服务器地址 +// data:数据集合 +// header:包头内容 +// transport:transport对象 +// 返回值 +// http StatusCode +// 字节数组 +// 错误对象 +func GetWebData2(weburl string, data map[string]string, header map[string]string, transport *http.Transport) (statusCode int, result []byte, err error) { + // 处理data,将data以key=value的形式拼接到weburl后,形成一个完整的url + dataStr := "" + count := 0 + for k, v := range data { + if count == len(data)-1 { + dataStr += fmt.Sprintf("%s=%s", k, v) + } else { + dataStr += fmt.Sprintf("%s=%s&", k, v) + } + count += 1 + } + + if dataStr != "" { + if strings.Contains(weburl, "?") { + weburl = fmt.Sprintf("%s&%s", weburl, dataStr) + } else { + weburl = fmt.Sprintf("%s?%s", weburl, dataStr) + } + } + + // 构造请求对象 + var request *http.Request + request, err = http.NewRequest("GET", weburl, nil) + if err != nil { + return + } + + // 处理头部 + if header != nil { + for k, v := range header { + request.Header.Add(k, v) + } + } + + // 构造transport对象 + if transport == nil { + transport = NewTransport() + transport.DisableKeepAlives = true + transport = GetTimeoutTransport(transport, 30) + } + + // 构造httpClient对象 + client := &http.Client{Transport: transport} + + // 发送数据 + var response *http.Response + response, err = client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + // 获取返回值 + statusCode = response.StatusCode + result, err = ioutil.ReadAll(response.Body) + + return +} + +// GET数据(新方法) +// weburl:远程服务器地址 +// dataStr:参数字符串 +// header:包头内容 +// transport:transport对象 +// 返回值 +// http StatusCode +// 字节数组 +// 错误对象 +func GetWebData3(weburl string, dataStr string, header map[string]string, transport *http.Transport) (statusCode int, result []byte, err error) { + if dataStr != "" { + if strings.Contains(weburl, "?") { + weburl = fmt.Sprintf("%s&%s", weburl, dataStr) + } else { + weburl = fmt.Sprintf("%s?%s", weburl, dataStr) + } + } + + // 构造请求对象 + var request *http.Request + request, err = http.NewRequest("GET", weburl, nil) + if err != nil { + return + } + + // 处理头部 + if header != nil { + for k, v := range header { + request.Header.Add(k, v) + } + } + + // 构造transport对象 + if transport == nil { + transport = NewTransport() + transport.DisableKeepAlives = true + transport = GetTimeoutTransport(transport, 30) + } + + // 构造httpClient对象 + client := &http.Client{Transport: transport} + + // 发送数据 + var response *http.Response + response, err = client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + // 获取返回值 + statusCode = response.StatusCode + result, err = ioutil.ReadAll(response.Body) + + return +} diff --git a/.svn/pristine/51/51904f3f8b846194d5b8e73a078da71adaae6dfd.svn-base b/.svn/pristine/51/51904f3f8b846194d5b8e73a078da71adaae6dfd.svn-base new file mode 100644 index 0000000..c9bfdad --- /dev/null +++ b/.svn/pristine/51/51904f3f8b846194d5b8e73a078da71adaae6dfd.svn-base @@ -0,0 +1,4 @@ +/* +用于提供验证AppStore充值的逻辑 +*/ +package appChargeUtil diff --git a/.svn/pristine/51/51e48b01a62c7b4795266420a89faf8955b3a29c.svn-base b/.svn/pristine/51/51e48b01a62c7b4795266420a89faf8955b3a29c.svn-base new file mode 100644 index 0000000..d2f0e91 --- /dev/null +++ b/.svn/pristine/51/51e48b01a62c7b4795266420a89faf8955b3a29c.svn-base @@ -0,0 +1,13 @@ +package managecenterModel + +// MC系统配置列表对象 +type SysConfig struct { + // 新服有效天数 + NewServerValidDays int32 `json:"NewServerValidDays"` + + // 用户Id + WhiteListServerIds string `json:"WhiteListServerIds"` + + //登录本地验证key + DynamicLoginKey string `json:"DynamicLoginKey"` +} diff --git a/.svn/pristine/52/52095a281285493617e456ee5193122cba2fe3e3.svn-base b/.svn/pristine/52/52095a281285493617e456ee5193122cba2fe3e3.svn-base new file mode 100644 index 0000000..c1e47c4 --- /dev/null +++ b/.svn/pristine/52/52095a281285493617e456ee5193122cba2fe3e3.svn-base @@ -0,0 +1,186 @@ +package mathUtil + +import ( + "sort" +) + +// 判断传入的byte型数组是否连续 +func IsContinuous_byte(list []byte) bool { + if len(list) == 0 || len(list) == 1 { + return true + } + + list_int64 := make([]int64, len(list), len(list)) + for i, v := range list { + list_int64[i] = int64(v) + } + + return IsContinuous_int64(list_int64) +} + +// 判断传入的int型数组是否连续 +func IsContinuous_int(list []int) bool { + if len(list) == 0 || len(list) == 1 { + return true + } + + list_int64 := make([]int64, len(list), len(list)) + for i, v := range list { + list_int64[i] = int64(v) + } + + return IsContinuous_int64(list_int64) +} + +// 判断传入的int型数组是否连续 +func IsContinuous_int32(list []int32) bool { + if len(list) == 0 || len(list) == 1 { + return true + } + + list_int64 := make([]int64, len(list), len(list)) + for i, v := range list { + list_int64[i] = int64(v) + } + + return IsContinuous_int64(list_int64) +} + +// 判断传入的int型数组是否连续 +func IsContinuous_int64(list []int64) bool { + if len(list) == 0 || len(list) == 1 { + return true + } + + if int64(len(list)) != list[len(list)-1]-list[0]+1 { + return false + } + + for i := 0; i < len(list)-1; i++ { + if list[i]+1 != list[i+1] { + return false + } + } + + return true +} + +// 判断区间是否连续 +func IsContinuous_Region(list []*IntRegion) bool { + if len(list) == 0 || len(list) == 1 { + return true + } + + sort.Slice(list, func(i, j int) bool { return list[i].Lower < list[j].Lower }) + + for i := 0; i < len(list)-1; i++ { + if list[i].IsSorted() == false || list[i+1].IsSorted() == false { + return false + } + + if list[i].Upper+1 != list[i+1].Lower { + return false + } + } + + return true +} + +// 判断传入的概率是否全覆盖 +func IsOddFullConvered(list []*IntRegion, min, max int) bool { + if len(list) == 0 { + return false + } + + if list[0].Lower != min || list[len(list)-1].Upper != max { + return false + } + + sort.Slice(list, func(i, j int) bool { return list[i].Lower < list[j].Lower }) + + for i := 0; i < len(list)-1; i++ { + if list[i].IsSorted() == false || list[i+1].IsSorted() == false { + return false + } + + if list[i].Upper+1 != list[i+1].Lower { + return false + } + } + + return true +} + +func IsDistinct_byte(list []byte) (result bool) { + if len(list) == 0 || len(list) == 1 { + result = true + return + } + + list_int64 := make([]int64, len(list), len(list)) + for i, v := range list { + list_int64[i] = int64(v) + } + + return IsDistinct_int64(list_int64) +} + +func IsDistinct_int(list []int) (result bool) { + if len(list) == 0 || len(list) == 1 { + result = true + return + } + + list_int64 := make([]int64, len(list), len(list)) + for i, v := range list { + list_int64[i] = int64(v) + } + + return IsDistinct_int64(list_int64) +} + +func IsDistinct_int32(list []int32) (result bool) { + if len(list) == 0 || len(list) == 1 { + result = true + return + } + + list_int64 := make([]int64, len(list), len(list)) + for i, v := range list { + list_int64[i] = int64(v) + } + + return IsDistinct_int64(list_int64) +} + +// 判断int64数组是否内容唯一 +func IsDistinct_int64(list []int64) (result bool) { + if len(list) == 0 || len(list) == 1 { + result = true + return + } + + sort.Slice(list, func(i, j int) bool { return list[i] < list[j] }) + + for i := 0; i < len(list)-1; i++ { + if list[i] == list[i+1] { + result = false + return + } + } + + result = true + return +} + +//// 将int转成uint类型(因goutil指定go版本过低,不支持泛型,未实际加入;要使用的人取消注释,并指定允许泛型的go版本) +//// 应用场景:atomic.AddUint64 想减1时 +//// +//// x := uint64(1000) +//// y := int64(-1) +//// atomic.AddUint64(&x, intToUint[int64, uint64](y)) +//func intToUint[T1 int8 | int16 | int32 | int64 | int, T2 uint8 | uint16 | uint32 | uint64 | uint](x T1) T2 { +// // 写到函数内,两种方式都可以;若直接使用,只能使用^T2(-x - 1);若使用T2(x)方式,x为负值时转为uint类语法检查无法通过 +// return ^T2(-x - 1) +// // return T2(x) +//} diff --git a/.svn/pristine/52/521f814a989f3a71d3af9af1cc1514017f4c3b2d.svn-base b/.svn/pristine/52/521f814a989f3a71d3af9af1cc1514017f4c3b2d.svn-base new file mode 100644 index 0000000..1c5773c --- /dev/null +++ b/.svn/pristine/52/521f814a989f3a71d3af9af1cc1514017f4c3b2d.svn-base @@ -0,0 +1,53 @@ +package stringUtil + +import ( + "testing" +) + +func TestBase64Encode(t *testing.T) { + greeting := "Hello world" + encoded := Base64Encode(greeting) + decoded, err := Base64Decode(encoded) + if err != nil { + t.Errorf("There should be no error, but now there is one:%s", err) + return + } + + if greeting != decoded { + t.Errorf("Expected %s, but got %s", greeting, decoded) + return + } +} + +func TestBase64Encode2(t *testing.T) { + greeting := []byte("Hello world") + encoded := Base64Encode2(greeting) + decoded, err := Base64Decode2(encoded) + if err != nil { + t.Errorf("There should be no error, but now there is one:%s", err) + return + } + + if isEqual(greeting, decoded) == false { + t.Errorf("Expected %s, but got %s", greeting, decoded) + return + } +} + +func isEqual(s1, s2 []byte) bool { + if s1 == nil || s2 == nil { + return true + } + + if len(s1) != len(s2) { + return false + } + + for i := 0; i < len(s1); i++ { + if s1[i] != s2[i] { + return false + } + } + + return true +} diff --git a/.svn/pristine/52/5237995ae7afcad71966e2a8f30ed0f0ee23991f.svn-base b/.svn/pristine/52/5237995ae7afcad71966e2a8f30ed0f0ee23991f.svn-base new file mode 100644 index 0000000..41cbcc5 --- /dev/null +++ b/.svn/pristine/52/5237995ae7afcad71966e2a8f30ed0f0ee23991f.svn-base @@ -0,0 +1,14 @@ +package impl_console + +import ( + "testing" +) + +func TestInfoLog(t *testing.T) { + log := NewLogger() + log.DebugLog("Debug test") + log.InfoLog("Info test") + log.WarnLog("Warn test") + log.ErrorLog("Error test") + log.FatalLog("Fatal test") +} diff --git a/.svn/pristine/52/526ed4f4997979f5889d26f7a025ec34dd3405f1.svn-base b/.svn/pristine/52/526ed4f4997979f5889d26f7a025ec34dd3405f1.svn-base new file mode 100644 index 0000000..6eb647c --- /dev/null +++ b/.svn/pristine/52/526ed4f4997979f5889d26f7a025ec34dd3405f1.svn-base @@ -0,0 +1,132 @@ +package managecenterMgr + +import ( + "fmt" + "testing" +) + +func init() { + manageCenterDataSwitchObj := &ManageCenterDataSwitch{ + AllDataSwitch: true, + } + Start("https://managecenterapi-sd3.7qule.com/", manageCenterDataSwitchObj) + + item, exist := GetAreaLabelDBByGroupId(82) + if exist { + fmt.Printf("%v", item) + } +} + +func TestPartner(t *testing.T) { + partnerList := GetPartnerList() + fmt.Printf("PartnerList count:%v\n", len(partnerList)) + if len(partnerList) == 0 { + t.Errorf("There is no partner.") + return + } + + firstPartner := partnerList[0] + _, exist := GetPartner(firstPartner.Id) + if !exist { + t.Errorf("Partner with Id:%d should exist, but now it doesn't.", firstPartner.Id) + return + } + + _, exist = GetPartnerByAlias(firstPartner.Alias) + if !exist { + t.Errorf("Partner with Alias:%s should exist, but now it doesn't.", firstPartner.Alias) + return + } + + _, exist, err := GetOtherConfigInfo(firstPartner.Id, "LoginHandler") + if err != nil { + t.Errorf("There should no error for Partner:%d, but now there is one:%v", err, firstPartner.Id) + return + } + if !exist { + t.Errorf("Partner with Id:%d should have an other config named LoginHandler, but now there isn't.", firstPartner.Id) + return + } +} + +func TestServer(t *testing.T) { + serverGroupList := GetServerGroupList() + if len(serverGroupList) == 0 { + t.Errorf("There is no ServerGroup.") + return + } + firstServerGroup := serverGroupList[0] + + serverList := GetServerListByGroupId(firstServerGroup.Id) + fmt.Printf("There are %d servers of GroupId:%d\n", len(serverList), firstServerGroup.Id) + + firstServer := serverList[0] + serverList = GetServerListByPartnerId(firstServer.PartnerId) + fmt.Printf("There are %d servers of PartnerId:%d\n", len(serverList), firstServer.PartnerId) + + _, exist := GetServerItem(firstServer.PartnerId, firstServer.Id) + if !exist { + t.Errorf("There is no server with PartnerId:%d, ServerId:%d.", firstServer.PartnerId, firstServer.Id) + return + } + + distinctServerIdList := GetDistinctServerIdList() + fmt.Printf("There are %d distinct ServerId\n", len(distinctServerIdList)) +} + +func TestServerGroup(t *testing.T) { + serverGroupList := GetServerGroupList() + if len(serverGroupList) == 0 { + t.Errorf("There is no ServerGroup.") + return + } + + firstServerGroup := serverGroupList[0] + _, exist := GetServerGroupItem(firstServerGroup.Id) + if !exist { + t.Errorf("The ServerGroup with Id:%d should exist, but now it doesn't.", firstServerGroup.Id) + return + } + + serverList := GetServerListByGroupId(firstServerGroup.Id) + if len(serverList) == 0 { + t.Errorf("There is no server of ServerGroupId:%d", firstServerGroup.Id) + return + } + firstServer := serverList[0] + _, _, exist = GetServerGroup(firstServer.PartnerId, firstServer.Id) + if !exist { + t.Errorf("The ServerGroup with PartnerId:%d, ServerId:%d should exist, but now it doesn't.", firstServer.PartnerId, firstServer.Id) + return + } +} + +func TestResourceVersion(t *testing.T) { + list := GetResourceVersionList() + fmt.Printf("There are %d resource versions.\n", len(list)) +} + +func TestUserWhiteList(t *testing.T) { + fmt.Printf("There are %d whiteLists.\n", len(whiteListMap)) + if len(whiteListMap) == 0 { + return + } + + var partnerId int32 + var userId string + for _, v := range whiteListMap { + for _, _v := range v { + partnerId = _v.PartnerId + userId = _v.UserId + break + } + break + } + + expected := true + got := IsInWhiteList(partnerId, userId) + if got != expected { + t.Errorf("Expected to get %t, but got %t", expected, got) + return + } +} diff --git a/.svn/pristine/54/5445c6a66d28f994d025ce139e3a8e09bfb68196.svn-base b/.svn/pristine/54/5445c6a66d28f994d025ce139e3a8e09bfb68196.svn-base new file mode 100644 index 0000000..5a8d915 --- /dev/null +++ b/.svn/pristine/54/5445c6a66d28f994d025ce139e3a8e09bfb68196.svn-base @@ -0,0 +1,16 @@ +package runtimeUtil + +import "runtime" + +// 获取当前正在使用的内存大小,单位:字节数 +// 具体参见文档: +// 1. http://blog.csdn.net/webxscan/article/details/72857292 +// 2. https://studygolang.com/static/pkgdoc/pkg/runtime.htm#MemStats +// 返回值: +// int64:正在使用的内存大小 +func GetMemSize() uint64 { + var memStat runtime.MemStats + runtime.ReadMemStats(&memStat) + + return memStat.Alloc +} diff --git a/.svn/pristine/54/54a0e682fd6262e24fa94fe5e10814532f88b5bf.svn-base b/.svn/pristine/54/54a0e682fd6262e24fa94fe5e10814532f88b5bf.svn-base new file mode 100644 index 0000000..fc2e539 --- /dev/null +++ b/.svn/pristine/54/54a0e682fd6262e24fa94fe5e10814532f88b5bf.svn-base @@ -0,0 +1,247 @@ +package managecenterMgr + +import ( + "encoding/json" + "errors" + "fmt" + "sort" + + "Framework/ipMgr" + "Framework/managecenterModel" + . "Framework/managecenterModel" + "goutil/logUtil" + "goutil/webUtil" +) + +var ( + // 服务器组集合 + serverGroupMap = make(map[int32]*ServerGroup, 512) + serverGroupHash string + + // 服务器组变化方法集合 (完整列表,新增列表,删除列表,更新列表) + serverGroupChangeFuncMap = make(map[string]func([]*ServerGroup, []*ServerGroup, []*ServerGroup, []*ServerGroup)) +) + +func init() { + ipMgr.RegisterIpCheckFunc("ServerGroupIpCheck", isIpValid) +} + +// 重新加载服务器组 +func reloadServerGroup(isInit bool) error { + //logUtil.DebugLog("开始刷新服务器组信息") + + url := getManageCenterUrl("/API/ServerGroupList.ashx") + + // 定义请求参数 + postDict := make(map[string]string) + postDict["GroupType"] = "Mix" + postDict["HashValue"] = serverGroupHash + + //请求url,请求头 + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, 30) + + statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, transport) + //statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, nil) + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取服务器组列表出错,url:%s,错误信息为:%s", url, err)) + return err + } + if statusCode != 200 { + logUtil.ErrorLog(fmt.Sprintf("获取服务器组列表出错,url:%s,错误码为:%d", url, statusCode)) + return err + } + + // 解析返回值 + returnObj := new(ReturnObject) + if err = json.Unmarshal(returnBytes, &returnObj); err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取服务器组列表出错,反序列化返回值出错,错误信息为:%s", err)) + return err + } + + // 判断返回状态是否为成功 + if returnObj.Code != 0 { + // 数据没有变化,所以没有获取到新的数据,不能算错误。 + if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" { + //如果本地集合为空,且数据又没变化时,重新初始化一下本地hash值 + if len(serverGroupMap) == 0 { + serverGroupHash = "" + } + return nil + } else { + msg := fmt.Sprintf("获取服务器组列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message) + logUtil.ErrorLog(msg) + return errors.New(msg) + } + } + + // 解析Data + tmpServerGroupList := make([]*ServerGroup, 0, 512) + if data, ok := returnObj.Data.(string); !ok { + msg := "获取服务器组列表出错,返回的数据不是string类型" + logUtil.ErrorLog(msg) + return errors.New(msg) + } else { + if err = json.Unmarshal([]byte(data), &tmpServerGroupList); err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取服务器组列表出错,反序列化数据出错,错误信息为:%s", err)) + return err + } + } + + //logUtil.DebugLog(fmt.Sprintf("刷新服务器组信息结束,服务器组数量:%d", len(tmpServerGroupList))) + + tmpServerGroupMap := make(map[int32]*ServerGroup, 512) + for _, item := range tmpServerGroupList { + tmpServerGroupMap[item.Id] = item + } + + // 处理服务器组是否变化情况 + addList, deleteList, updateList := handleServerGroupChange(GetServerGroupMap(), tmpServerGroupMap) + triggerServerGroupChangeFunc(tmpServerGroupList, addList, deleteList, updateList) + + // 赋值给最终的ServerGroupMap + serverGroupMap = tmpServerGroupMap + serverGroupHash = returnObj.HashValue + + //通知变更 + mcDataChangeCallBack(managecenterModel.ServerGroupData, isInit) + + return nil +} + +// 处理服务器组是否变化情况 +// originalServerGroupMap: 当前服务器组集合 +// newServerGroupMap: 新的服务器组集合 +func handleServerGroupChange(currServerGroupMap, newServerGroupMap map[int32]*ServerGroup) ( + addList []*ServerGroup, deleteList []*ServerGroup, updateList []*ServerGroup) { + + // 判断是否有新增的数据 + for k, v := range newServerGroupMap { + if _, exist := currServerGroupMap[k]; !exist { + addList = append(addList, v) + } + } + + // 判断是否有删除的数据 + for k, v := range currServerGroupMap { + if _, exist := newServerGroupMap[k]; !exist { + deleteList = append(deleteList, v) + } + } + + // 判断是否有更新的数据 + for k, currItem := range currServerGroupMap { + if newItem, exist := newServerGroupMap[k]; exist { + if currItem.IsEqual(newItem) == false { + updateList = append(updateList, newItem) + } + } + } + + return +} + +// 触发服务器组变化的方法 +func triggerServerGroupChangeFunc(allList []*ServerGroup, addList []*ServerGroup, deleteList []*ServerGroup, updateList []*ServerGroup) { + // 如果有注册服务器组变化的方法 + if len(serverGroupChangeFuncMap) > 0 { + for _, serverGroupChangeFunc := range serverGroupChangeFuncMap { + serverGroupChangeFunc(allList, addList, deleteList, updateList) + } + } +} + +// 注册服务器组变化方法 +// funcName:方法名称 +// serverGroupChangeFunc:服务器组变化方法 +func RegisterServerGroupChangeFunc(funcName string, serverGroupChangeFunc func([]*ServerGroup, []*ServerGroup, []*ServerGroup, []*ServerGroup)) { + if _, exists := serverGroupChangeFuncMap[funcName]; exists { + panic(fmt.Errorf("RegisterServerGroupChange:%s已经存在,请检查", funcName)) + } + serverGroupChangeFuncMap[funcName] = serverGroupChangeFunc + + logUtil.DebugLog(fmt.Sprintf("注册服务器组变化方法 funcName:%s,当前共有%d个注册", funcName, len(serverGroupChangeFuncMap))) +} + +// 获取服务器组集合 +// 返回值: +// 服务器组集合 +func GetServerGroupMap() (retServerGroupMap map[int32]*ServerGroup) { + retServerGroupMap = make(map[int32]*ServerGroup, 128) + for k, v := range serverGroupMap { + retServerGroupMap[k] = v + } + + return +} + +// 获取服务器组列表 +// 返回值: +// 服务器组列表 +func GetServerGroupList() (serverGroupList []*ServerGroup) { + for _, item := range serverGroupMap { + serverGroupList = append(serverGroupList, item) + } + + sort.Slice(serverGroupList, func(i, j int) bool { + return serverGroupList[i].SortByIdAsc(serverGroupList[j]) + }) + + return +} + +// 获取服务器组项 +// id +// 返回值: +// 服务器组对象 +// 是否存在 +func GetServerGroupItem(id int32) (serverGroupObj *ServerGroup, exist bool) { + serverGroupObj, exist = serverGroupMap[id] + return +} + +// 根据合作商Id、服务器Id获取服务器组对象 +// partnerId:合作商Id +// serverId:服务器Id +// 返回值: +// 服务器组对象 +// 服务器对象 +// 是否存在 +func GetServerGroup(partnerId, serverId int32) (serverGroupObj *ServerGroup, serverObj *Server, exist bool) { + var partnerObj *Partner + + // 获取合作商对象 + partnerObj, exist = GetPartner(partnerId) + if !exist { + return + } + + // 获取服务器对象 + serverObj, exist = GetServer(partnerObj, serverId) + if !exist { + return + } + + // 获取服务器组对象 + serverGroupObj, exist = GetServerGroupItem(serverObj.GroupId) + return +} + +// 判断IP是否有效 +// ip:指定IP地址 +// 返回值: +// IP是否有效 +func isIpValid(ip string) (exist bool) { + for _, v := range serverGroupMap { + for _, item := range v.GetIPList() { + if ip == item { + exist = true + return + } + } + } + + return +} diff --git a/.svn/pristine/54/54b903c8c997feaac3b622c39ef0886b149d80e8.svn-base b/.svn/pristine/54/54b903c8c997feaac3b622c39ef0886b149d80e8.svn-base new file mode 100644 index 0000000..b2e1aaa --- /dev/null +++ b/.svn/pristine/54/54b903c8c997feaac3b622c39ef0886b149d80e8.svn-base @@ -0,0 +1,41 @@ +package webUtil + +import ( + "testing" +) + +func TestGetWebData(t *testing.T) { + weburl := "http://www.baidu.com" + resp, err := GetWebData(weburl, nil) + if err != nil { + t.Errorf("测试错误,返回的结果为:%s", err) + } + + if len(resp) == 0 { + t.Errorf("返回的数据为空,期望不为空") + } +} + +func TestGetWebData2(t *testing.T) { + weburl := "http://www.baidu.com" + data := make(map[string]string) + status, resp, err := GetWebData2(weburl, data, nil, nil) + if status != 200 || err != nil { + t.Errorf("Test failed. status:%d, err:%s", status, err) + } + + if len(resp) == 0 { + t.Errorf("The result is empty, but we expect not empty") + } + + data["Name"] = "Jordan" + data["Age"] = "32" + status, resp, err = GetWebData2(weburl, data, nil, nil) + if status != 200 || err != nil { + t.Errorf("Test failed. status:%d, err:%s", status, err) + } + + if len(resp) == 0 { + t.Errorf("The result is empty, but we expect not empty") + } +} diff --git a/.svn/pristine/54/54fbc9bfaa37789ec76a10782c878db5e00b7e43.svn-base b/.svn/pristine/54/54fbc9bfaa37789ec76a10782c878db5e00b7e43.svn-base new file mode 100644 index 0000000..1be16f4 --- /dev/null +++ b/.svn/pristine/54/54fbc9bfaa37789ec76a10782c878db5e00b7e43.svn-base @@ -0,0 +1,26 @@ +package qirui + +import ( + "fmt" + + "goutil/webUtil" +) + +const ( + SEND_MESSAGE_URL = "http://api.qirui.com:7891/mt" +) + +func SendMessage(apiKey, apiSecret, mobile, message string) (bool, error) { + smsUrl := fmt.Sprintf("%s?dc=15&un=%s&pw=%s&da=%s&sm=%s&tf=3&rf=2&rd=1", SEND_MESSAGE_URL, apiKey, apiSecret, mobile, message) + status, resp, err := webUtil.GetWebData3(smsUrl, "", webUtil.GetJsonHeader(), nil) + if err != nil { + return false, err + } + + if status != 200 { + return false, fmt.Errorf("StatusCode is %d", status) + } + + fmt.Printf("qirui.SendMessage:%s, %s, %s\n", mobile, message, string(resp)) + return true, nil +} diff --git a/.svn/pristine/55/55d454d62218b6c17d558654dfe26659205489a0.svn-base b/.svn/pristine/55/55d454d62218b6c17d558654dfe26659205489a0.svn-base new file mode 100644 index 0000000..3c68c5b --- /dev/null +++ b/.svn/pristine/55/55d454d62218b6c17d558654dfe26659205489a0.svn-base @@ -0,0 +1,15 @@ +package securityUtil + +import ( + "testing" +) + +func TestSha256(t *testing.T) { + source := "oauthConsumerKey=1Nocz0wk0Hi8oGgSosogC4K4k&oauthToken=TOKEN_%2B8vQAR1eoD3ujiGstjzdyakEgbkyvWhfzF1fChQJ46EH07n%2FQvrazkMqy%2BhuprqU&oauthSignatureMethod=HMAC-SHA1&oauthTimestamp=1508486834&oauthNonce=5409983431934290948&oauthVersion=1.0&" + sign := "813c8202a31c73371ae0bbe13cb49d65c94da3de2877345603271ca14e5e4bcd" + + result := Sha256String(source, false) + if result != sign { + t.Fatalf("Sha256编码结果不一致") + } +} diff --git a/.svn/pristine/55/55d4f6929df5269adfb1bb29dba1fb1b34ce16bd.svn-base b/.svn/pristine/55/55d4f6929df5269adfb1bb29dba1fb1b34ce16bd.svn-base new file mode 100644 index 0000000..b64025d --- /dev/null +++ b/.svn/pristine/55/55d4f6929df5269adfb1bb29dba1fb1b34ce16bd.svn-base @@ -0,0 +1,99 @@ +package sqlSync + +import ( + "database/sql" + "fmt" + "strings" + "time" + + "goutil/logUtil" +) + +// 以事务的方式执行 +// db:数据库对象 +// funcObj:对应的具体处理函数 +// 返回值: +// error:处理是否存在错误 +func ExecuteByTran(db *sql.DB, funcObj func(tran *sql.Tx) (isCommit bool, err error)) error { + tran, err := db.Begin() + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("start transaction error:%v", err.Error())) + return err + } + + // 事务处理 + isCommit := false + defer func() { + if isCommit { + err = tran.Commit() + } else { + err = tran.Rollback() + } + + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("transaction end error:%v", err.Error())) + } + }() + + isCommit, err = funcObj(tran) + + return err +} + +// 循环执行知道返回成功为止 +// funcObj:待执行的函数 +// interval:执行间隔时间 +func WaitForOk(funcObj func() bool, interval time.Duration) { + for { + if funcObj() == false { + time.Sleep(interval) + } + + break + } +} + +// 检查是否是连接错误 +// errMsg:错误信息 +// 返回值: +// bool:true:连接错误 false:其他异常 +func CheckIfConnectionError(errMsg string) bool { + //// 连接被关闭 + ifConnectionClose := strings.Contains(errMsg, "A connection attempt failed because the connected party did not properly respond") + if ifConnectionClose { + return true + } + + // 使用过程中连接断开 + ifConnectionClose = strings.Contains(errMsg, "No connection could be made") + if ifConnectionClose { + return true + } + + // 事务处理过程中连接断开的提示 + ifConnectionClose = strings.Contains(errMsg, "bad connection") + if ifConnectionClose { + return true + } + + // socket压根儿连不上的处理 + ifConnectionClose = strings.Contains(errMsg, "A socket operation was attempted to an unreachable network") + if ifConnectionClose { + return true + } + + // 用户无法访问 + return strings.Contains(errMsg, "Access denied for user") +} + +// 获取比较简洁的错误信息 +// errMsg:错误信息 +// 返回值: +// string:比较简洁的错误信息 +func GetSimpleErrorMessage(errMsg string) string { + if strings.Contains(errMsg, "Error 1064: You have an error in your SQL syntax") { + return "SqlError" + } + + return errMsg +} diff --git a/.svn/pristine/56/56917ecd3dd2f5232b9c9c3ca1dcfaed71e2c9bb.svn-base b/.svn/pristine/56/56917ecd3dd2f5232b9c9c3ca1dcfaed71e2c9bb.svn-base new file mode 100644 index 0000000..62b18ea --- /dev/null +++ b/.svn/pristine/56/56917ecd3dd2f5232b9c9c3ca1dcfaed71e2c9bb.svn-base @@ -0,0 +1,91 @@ +package stringUtil + +import ( + "testing" +) + +func TestSimilarity(t *testing.T) { + source := "" + target := "" + expectedDistance := 0 + expectedSimilarity := 0.0 + gotDistance, gotSimilarity := Similarity(source, target) + if gotDistance != expectedDistance { + t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance) + return + } + if gotSimilarity != expectedSimilarity { + t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity) + return + } + + source = "Hello" + target = "" + expectedDistance = 5 + expectedSimilarity = 0.0 + gotDistance, gotSimilarity = Similarity(source, target) + if gotDistance != expectedDistance { + t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance) + return + } + if gotSimilarity != expectedSimilarity { + t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity) + return + } + + source = "" + target = "Hello" + expectedDistance = 5 + expectedSimilarity = 0.0 + gotDistance, gotSimilarity = Similarity(source, target) + if gotDistance != expectedDistance { + t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance) + return + } + if gotSimilarity != expectedSimilarity { + t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity) + return + } + + source = "Helo" + target = "Hello" + expectedDistance = 1 + expectedSimilarity = 4.0 / 5.0 + gotDistance, gotSimilarity = Similarity(source, target) + if gotDistance != expectedDistance { + t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance) + return + } + if gotSimilarity != expectedSimilarity { + t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity) + return + } + + source = "kitten" + target = "sitten" + expectedDistance = 1 + expectedSimilarity = 5.0 / 6.0 + gotDistance, gotSimilarity = Similarity(source, target) + if gotDistance != expectedDistance { + t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance) + return + } + if gotSimilarity != expectedSimilarity { + t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity) + return + } + + source = "Michael Jordan" + target = "Michael Jordan" + expectedDistance = 0 + expectedSimilarity = 1 + gotDistance, gotSimilarity = Similarity(source, target) + if gotDistance != expectedDistance { + t.Errorf("Expected to get %d, now got %d", expectedDistance, gotDistance) + return + } + if gotSimilarity != expectedSimilarity { + t.Errorf("Expected to get %f, now got %f", expectedSimilarity, gotSimilarity) + return + } +} diff --git a/.svn/pristine/56/56f885374bb697f0fe69c523d081a0ef9645d4bf.svn-base b/.svn/pristine/56/56f885374bb697f0fe69c523d081a0ef9645d4bf.svn-base new file mode 100644 index 0000000..3d317b0 --- /dev/null +++ b/.svn/pristine/56/56f885374bb697f0fe69c523d081a0ef9645d4bf.svn-base @@ -0,0 +1,32 @@ +package securityUtil + +import ( + "testing" +) + +func TestSha1String(t *testing.T) { + s := "hello world" + result := Sha1String(s, true) + if result != "2AAE6C35C94FCFB415DBE95F408B9CE91EE846ED" { + t.Errorf("Sha1String(\"hello world\") failed.Got %s, expected %s", result, "2AAE6C35C94FCFB415DBE95F408B9CE91EE846ED") + } + + result = Sha1String(s, false) + if result != "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed" { + t.Errorf("Sha1String(\"hello world\") failed.Got %s, expected %s", result, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed") + } +} + +func TestSha1Bytes(t *testing.T) { + s := "hello world" + b := []byte(s) + result := Sha1Bytes(b, true) + if result != "2AAE6C35C94FCFB415DBE95F408B9CE91EE846ED" { + t.Errorf("Sha1Bytes(\"hello world\") failed.Got %s, expected %s", result, "2AAE6C35C94FCFB415DBE95F408B9CE91EE846ED") + } + + result = Sha1Bytes(b, false) + if result != "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed" { + t.Errorf("Sha1Bytes(\"hello world\") failed.Got %s, expected %s", result, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed") + } +} diff --git a/.svn/pristine/57/576810f1d094644512c078a85a8cf10b20959f04.svn-base b/.svn/pristine/57/576810f1d094644512c078a85a8cf10b20959f04.svn-base new file mode 100644 index 0000000..964cfe6 --- /dev/null +++ b/.svn/pristine/57/576810f1d094644512c078a85a8cf10b20959f04.svn-base @@ -0,0 +1,81 @@ +// ************************************ +// @package: handleMgr +// @description: 全局操作接口管理API类 +// @author: +// @revision history: +// @create date: 2022-02-23 16:24:59 +// ************************************ + +package handleMgr + +/* +用于提供全局操作接口管理API类 +*/ + +/* +接口说明 + +接口1: +// RegisterNewModule +// @description: 注册方法 +// parameter: +// @moduleName:模块名 +// @structObject:模块对象 +// @monitorTime:监控日志超时时间,传入0是用默认值100 +// return: + +示例:RegisterNewModule("test", new(testBll), 0) + +接口2: +// Done +// @description: 执行访问 +// parameter: +// @logicalId:逻辑实例Id-同一串行错误类的唯一标识 +// @moduleName:模块名 +// @funcName:执行方法名称 +// @parameter:方法参数 +// @isHaveResult:是否处理返回值 +// return: +// @data:返还对象 +// @code:错误码-0未无错误 +// @message:错误说明-空字符串为无错误 + +示例:data,code,mes := Done("test", "testBll", "Add", parameter, false) + +注意: +注册的类实现的方法返回值必须是*ResponseObject为返回对象 +示例: + +type testBll struct { +} + +// TestAdd +// @description:测试添加 +// parameter: +// @receiver t: +// @x: +// @y: +// return: +// @*ResponseObject: +func (t testBll) TestAdd(x, y int) *ResponseObject { + responseObj := GetInitResponseObj() + data[x] = y + z := x + y + + responseObj.SetData(z) + responseObj.SetResultStatus("错误码") + return responseObj +} + +func TestNew(t *testing.T) { + // 注册类 + RegisterNewModule("test", new(testBll), 10) + + // 调用方法 + data, code, mes := Done("test", "testBll", "TestAdd", parameter, false) + + // 可以重复注册多个类,逻辑实例Id保持一致即可 + RegisterNewModule("test", new(test2Bll), 10) + data, code, mes := Done("test", "test2Bll", "TestAdd", parameter, false) +} +*/ diff --git a/.svn/pristine/57/57ed580996c3cd3c94a7b7422b369a6540ad167a.svn-base b/.svn/pristine/57/57ed580996c3cd3c94a7b7422b369a6540ad167a.svn-base new file mode 100644 index 0000000..90a70e3 --- /dev/null +++ b/.svn/pristine/57/57ed580996c3cd3c94a7b7422b369a6540ad167a.svn-base @@ -0,0 +1,198 @@ +package stringUtil + +// 表情符号集合 +var emojiData map[rune]rune + +func init() { + emojiData = make(map[rune]rune, 1024) + + addEmojiChar() +} + +// 添加一个范围的unicode +// start:unicode起始位置 +// endlist:unicode结束位置 +func addUnicodeRange(start rune, endlist ...rune) { + if len(endlist) <= 0 { + // 添加单个的 + emojiData[start] = start + return + } + + end := endlist[0] + if start > end { + return + } + + // 添加范围的 + for i := start; i <= end; i++ { + emojiData[i] = i + } +} + +// 增加emoji表情符号 +// 表情字符大全参考: +// https://zh.wikipedia.org/wiki/%E7%B9%AA%E6%96%87%E5%AD%97 +// 对应unicode版本号:Unicode 10.0版本 +func addEmojiChar() { + addUnicodeRange(0x00A9) + addUnicodeRange(0x00AE) + + addUnicodeRange(0x203C) + addUnicodeRange(0x2049) + addUnicodeRange(0x2122) + addUnicodeRange(0x2139) + addUnicodeRange(0x2194, 0x2199) + addUnicodeRange(0x21A9, 0x21AA) + addUnicodeRange(0x231A, 0x231B) + addUnicodeRange(0x2328) + addUnicodeRange(0x23CF) + addUnicodeRange(0x23E9, 0x23F3) + addUnicodeRange(0x23F8, 0x23FA) + addUnicodeRange(0x24C2) + addUnicodeRange(0x25AA, 0x25AB) + addUnicodeRange(0x25B6) + addUnicodeRange(0x25C0) + addUnicodeRange(0x25FB, 0x25FE) + + addUnicodeRange(0x2600, 0x2604) + addUnicodeRange(0x260E) + addUnicodeRange(0x2611) + addUnicodeRange(0x2614, 0x2615) + addUnicodeRange(0x2618) + addUnicodeRange(0x261D) + addUnicodeRange(0x2620) + addUnicodeRange(0x2622, 0x2623) + addUnicodeRange(0x2626) + addUnicodeRange(0x262A) + addUnicodeRange(0x262E, 0x262F) + addUnicodeRange(0x2638, 0x263A) + addUnicodeRange(0x2640) + addUnicodeRange(0x2642) + addUnicodeRange(0x2648, 0x2653) + addUnicodeRange(0x2660) + addUnicodeRange(0x2663) + addUnicodeRange(0x2665, 0x2666) + addUnicodeRange(0x2668) + addUnicodeRange(0x267B) + addUnicodeRange(0x267F) + addUnicodeRange(0x2692, 0x2697) + addUnicodeRange(0x2699) + addUnicodeRange(0x269B, 0x269C) + + addUnicodeRange(0x26A0, 0x26A1) + addUnicodeRange(0x26AA, 0x26AB) + addUnicodeRange(0x26B0, 0x26B1) + addUnicodeRange(0x26BD, 0x26BE) + addUnicodeRange(0x26C4, 0x26C5) + addUnicodeRange(0x26C8) + addUnicodeRange(0x26CE, 0x26CF) + addUnicodeRange(0x26D1) + addUnicodeRange(0x26D3, 0x26D4) + addUnicodeRange(0x26E9, 0x26EA) + addUnicodeRange(0x26F0, 0x26F5) + addUnicodeRange(0x26F7, 0x26FA) + addUnicodeRange(0x26FD) + + addUnicodeRange(0x2702) + addUnicodeRange(0x2705) + addUnicodeRange(0x2708, 0x270D) + addUnicodeRange(0x270F) + addUnicodeRange(0x2712) + addUnicodeRange(0x2714) + addUnicodeRange(0x2716) + addUnicodeRange(0x271D) + addUnicodeRange(0x2721) + addUnicodeRange(0x2728) + addUnicodeRange(0x2733, 0x2734) + addUnicodeRange(0x2744) + addUnicodeRange(0x2747) + addUnicodeRange(0x274C) + addUnicodeRange(0x274E) + addUnicodeRange(0x2753, 0x2755) + addUnicodeRange(0x2757) + addUnicodeRange(0x2763, 0x2764) + addUnicodeRange(0x2795, 0x2797) + addUnicodeRange(0x27A1) + addUnicodeRange(0x27B0) + addUnicodeRange(0x27BF) + addUnicodeRange(0x2934, 0x2935) + addUnicodeRange(0x2B05, 0x2B07) + addUnicodeRange(0x2B1B, 0x2B1C) + addUnicodeRange(0x2B50) + addUnicodeRange(0x2B55) + addUnicodeRange(0x3030) + addUnicodeRange(0x303D) + addUnicodeRange(0x3297, 0x3299) + addUnicodeRange(0x3299) + addUnicodeRange(0x1F004) + addUnicodeRange(0x1F0CF) + addUnicodeRange(0x1F170, 0x1F171) + addUnicodeRange(0x1F17E, 0x1F17F) + addUnicodeRange(0x1F18E) + + addUnicodeRange(0x1F191, 0x1F19A) + addUnicodeRange(0x1F201, 0x1F202) + addUnicodeRange(0x1F21A) + addUnicodeRange(0x1F22F) + addUnicodeRange(0x1F232, 0x1F23A) + addUnicodeRange(0x1F250, 0x1F251) + addUnicodeRange(0x1F300, 0x1F321) + addUnicodeRange(0x1F324, 0x1F393) + addUnicodeRange(0x1F396, 0x1F397) + addUnicodeRange(0x1F399, 0x1F39B) + addUnicodeRange(0x1F39E, 0x1F3F0) + addUnicodeRange(0x1F3F3, 0x1F3F5) + addUnicodeRange(0x1F3F7, 0x1F53D) + + addUnicodeRange(0x1F549, 0x1F54E) + addUnicodeRange(0x1F550, 0x1F567) + addUnicodeRange(0x1F56F, 0x1F570) + addUnicodeRange(0x1F573, 0x1F57A) + addUnicodeRange(0x1F587) + addUnicodeRange(0x1F58A, 0x1F58D) + addUnicodeRange(0x1F590) + addUnicodeRange(0x1F595, 0x1F596) + addUnicodeRange(0x1F5A4, 0x1F5A5) + addUnicodeRange(0x1F5A8) + addUnicodeRange(0x1F5B1, 0x1F5B2) + addUnicodeRange(0x1F5BC) + addUnicodeRange(0x1F5C2, 0x1F5C4) + addUnicodeRange(0x1F5D1, 0x1F5D3) + addUnicodeRange(0x1F5DC, 0x1F5DE) + addUnicodeRange(0x1F5E1) + addUnicodeRange(0x1F5E3) + addUnicodeRange(0x1F5E8) + addUnicodeRange(0x1F5EF) + addUnicodeRange(0x1F5F3) + addUnicodeRange(0x1F5FA, 0x1F6C5) + addUnicodeRange(0x1F6CB, 0x1F6D2) + addUnicodeRange(0x1F6E0, 0x1F6E5) + addUnicodeRange(0x1F6E8) + addUnicodeRange(0x1F6EB, 0x1F6EC) + addUnicodeRange(0x1F6F0) + addUnicodeRange(0x1F6F3, 0x1F6F8) + addUnicodeRange(0x1F910, 0x1F93A) + addUnicodeRange(0x1F93B, 0x1F93E) + addUnicodeRange(0x1F940, 0x1F945) + addUnicodeRange(0x1F947, 0x1F94C) + addUnicodeRange(0x1F950, 0x1F96B) + addUnicodeRange(0x1F980, 0x1F997) + addUnicodeRange(0x1F9C0) + addUnicodeRange(0x1F9D0, 0x1F9E6) +} + +// 检查是否含有表情字符 +// val:待查看的字符串 +// 返回值: +// 是否包含有表情字符 +func IfHaveEmoji(val string) bool { + // 由于golang在内存中本来就是使用的Unicode,所以可以直接进行匹配操作 + for _, charItem := range val { + if _, eixst := emojiData[charItem]; eixst { + return true + } + } + + return false +} diff --git a/.svn/pristine/58/587f9e024e52f1a9c27470de900d08085d5fc9d1.svn-base b/.svn/pristine/58/587f9e024e52f1a9c27470de900d08085d5fc9d1.svn-base new file mode 100644 index 0000000..567adf9 --- /dev/null +++ b/.svn/pristine/58/587f9e024e52f1a9c27470de900d08085d5fc9d1.svn-base @@ -0,0 +1,20 @@ +package mailUtil + +import ( + "testing" +) + +func TestSendMail(t *testing.T) { + svr := SimpleSMTPClient("smtp.exmail.qq.com", 465, true, "name", "service@public.com", "Sv123456") + err := svr.SendMail([]string{"164760769@qq.com"}, + "邮件发送测试", + "

这是邮件正文

", + true, + []string{ + "./doc.go", + "./simpleClient_test.go", + }) + if err != nil { + t.Error(err) + } +} diff --git a/.svn/pristine/59/5921c843b6a9a0d075c29e4af206bb73d7e042a4.svn-base b/.svn/pristine/59/5921c843b6a9a0d075c29e4af206bb73d7e042a4.svn-base new file mode 100644 index 0000000..e9637bc --- /dev/null +++ b/.svn/pristine/59/5921c843b6a9a0d075c29e4af206bb73d7e042a4.svn-base @@ -0,0 +1,860 @@ +package redisUtil + +import ( + "testing" + "time" +) + +var ( + redisPoolObj_db *RedisPool +) + +func init() { + redisPoolObj_db = NewRedisPool("testPool", "10.1.0.21:6379", "redis_pwd", 5, 500, 200, 10*time.Second, 5*time.Second) +} + +func TestExists(t *testing.T) { + /* + redis> SET db "redis" + OK + */ + key := "db" + value := "redis" + successful, err := redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set the key:%s should be successful, but now it's not.", key) + return + } + + /* + redis> EXISTS db + (integer) 1 + */ + exist, err := redisPoolObj_db.Exists(key) + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("Set the key:%s should exist, but now it doesn't.", key) + return + } + + /* + redis> DEL db + (integer) 1 + */ + expected := 1 + got, err := redisPoolObj_db.Del(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + /* + redis> EXISTS db + (integer) 0 + */ + exist, err = redisPoolObj_db.Exists(key) + if err != nil { + t.Fail() + } + if exist { + t.Errorf("Set the key:%s should not exist, but now it does.", key) + return + } +} + +func TestType(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 字符串 + + redis> SET weather "sunny" + OK + + redis> TYPE weather + string + */ + key := "weather" + value := "sunny" + + successful, err := redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if !successful { + t.Errorf("Set the key:%s should be successful, but now it's not.", key) + return + } + + expected := "string" + got, err := redisPoolObj_db.Type(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + # 列表 + + redis> LPUSH book_list "programming in scala" + (integer) 1 + + redis> TYPE book_list + list + */ + key = "book_list" + value = "programming in scala" + expected2 := 1 + got2, err := redisPoolObj_db.LPush(key, value) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d", expected2, got2) + return + } + + expected = "list" + got, err = redisPoolObj_db.Type(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) + + /* + # 集合 + + redis> SADD pat "dog" + (integer) 1 + + redis> TYPE pat + set + */ + + key = "pat" + value = "dog" + expected3 := 1 + got3, err := redisPoolObj_db.SAdd(key, value) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %d, but now got %d", expected3, got3) + return + } + + expected = "set" + got, err = redisPoolObj_db.Type(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + + deleteKeys = append(deleteKeys, key) +} + +func TestRename(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # key 存在且 newkey 不存在 + + redis> SET message "hello world" + OK + + redis> RENAME message greeting + OK + + redis> EXISTS message # message 不复存在 + (integer) 0 + + redis> EXISTS greeting # greeting 取而代之 + (integer) 1 + */ + key := "message" + value := "hello world" + expected := true + got, err := redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + newkey := "greeting" + err = redisPoolObj_db.Rename(key, newkey) + if err != nil { + t.Fail() + } + + expected = false + got, err = redisPoolObj_db.Exists(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + expected = true + got, err = redisPoolObj_db.Exists(newkey) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + deleteKeys = append(deleteKeys, newkey) + + /* + # 当 key 不存在时,返回错误 + + redis> RENAME fake_key never_exists + (error) ERR no such key + */ + key = "fake_key" + newkey = "never_exists" + err = redisPoolObj_db.Rename(key, newkey) + if err == nil { + t.Errorf("There should be one error, but now there isn't.") + return + } + + /* + # newkey 已存在时, RENAME 会覆盖旧 newkey + + redis> SET pc "lenovo" + OK + + redis> SET personal_computer "dell" + OK + + redis> RENAME pc personal_computer + OK + + redis> GET pc + (nil) + + redis:1> GET personal_computer # 原来的值 dell 被覆盖了 + "lenovo" + */ + key = "pc" + value = "lenovo" + expected = true + got, err = redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + key = "personal_computer" + value = "dell" + expected = true + got, err = redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + key = "pc" + newkey = "personal_computer" + err = redisPoolObj_db.Rename(key, newkey) + if err != nil { + t.Fail() + } + + expected = false + got, err = redisPoolObj_db.Exists(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + expected = true + got, err = redisPoolObj_db.Exists(newkey) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + deleteKeys = append(deleteKeys, newkey) +} + +func TestRenameNX(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_string.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # newkey 不存在,改名成功 + + redis> SET player "MPlyaer" + OK + + redis> EXISTS best_player + (integer) 0 + + redis> RENAMENX player best_player + (integer) 1 + */ + key := "player" + value := "MPlayer" + expected := true + got, err := redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + newkey := "best_player" + expected = false + got, err = redisPoolObj_db.Exists(newkey) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + expected = true + got, err = redisPoolObj_db.RenameNX(key, newkey) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + deleteKeys = append(deleteKeys, newkey) + + /* + # newkey存在时,失败 + + redis> SET animal "bear" + OK + + redis> SET favorite_animal "butterfly" + OK + + redis> RENAMENX animal favorite_animal + (integer) 0 + + redis> get animal + "bear" + + redis> get favorite_animal + "butterfly" + */ + key = "animal" + value = "bear" + expected = true + got, err = redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + key = "favorite_animal" + value = "butterfly" + expected = true + got, err = redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + deleteKeys = append(deleteKeys, key) + + expected = false + got, err = redisPoolObj_db.RenameNX(key, newkey) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + key2 := "animal" + expected2 := "bear" + got2_interface, exist2, err := redisPoolObj_db.Get(key2) + if err != nil { + t.Fail() + } + if !exist2 { + t.Errorf("The key:%s should exist, but now it doesn't.", key2) + return + } + got2, err := redisPoolObj_db.String(got2_interface) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %s, but now got %s", expected2, got2) + return + } + + key3 := "animal" + expected3 := "bear" + got3_interface, exist3, err := redisPoolObj_db.Get(key3) + if err != nil { + t.Fail() + } + if !exist3 { + t.Errorf("The key:%s should exist, but now it doesn't.", key3) + return + } + got3, err := redisPoolObj_db.String(got3_interface) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %s, but now got %s", expected3, got3) + return + } +} + +func TestDel(t *testing.T) { + /* + # 删除单个 key + + redis> SET name huangz + OK + + redis> DEL name + (integer) 1 + */ + key := "name" + value := "huangz" + expected := true + got, err := redisPoolObj_db.Set(key, value, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + expected2 := 1 + got2, err := redisPoolObj_db.Del(key) + if err != nil { + t.Fail() + } + if got2 != expected2 { + t.Errorf("Expected to get %d, but now got %d", expected2, got2) + return + } + + /* + # 删除一个不存在的 key + + redis> EXISTS phone + (integer) 0 + + redis> DEL phone # 失败,没有 key 被删除 + (integer) 0 + */ + key = "phone" + expected = false + got, err = redisPoolObj_db.Exists(key) + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + expected3 := 0 + got3, err := redisPoolObj_db.Del(key) + if err != nil { + t.Fail() + } + if got3 != expected3 { + t.Errorf("Expected to get %d, but now got %d", expected3, got3) + return + } + + /* + # 同时删除多个 key + + redis> SET name "redis" + OK + + redis> SET type "key-value store" + OK + + redis> SET website "redis.com" + OK + + redis> DEL name type website + (integer) 3 + */ + key1 := "name" + value1 := "redis" + expected = true + got, err = redisPoolObj_db.Set(key1, value1, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + key2 := "type" + value2 := "key-value store" + expected = true + got, err = redisPoolObj_db.Set(key2, value2, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + key3 := "website" + value3 := "redis.com" + expected = true + got, err = redisPoolObj_db.Set(key3, value3, "", 0, "") + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %t, but now got %t", expected, got) + return + } + + expected4 := 3 + got4, err := redisPoolObj_db.Del(key1, key2, key3) + if err != nil { + t.Fail() + } + if got4 != expected4 { + t.Errorf("Expected to get %d, but now got %d", expected4, got4) + return + } +} + +func TestRandomKey(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + # 数据库为空 + + redis> RANDOMKEY + (nil) + */ + expected := "" + got, exist, err := redisPoolObj_db.RandomKey() + if err != nil { + t.Fail() + } + if exist { + t.Errorf("RandomKey doesn't exist, but now it does.") + return + } + if got != expected { + t.Errorf("Expected to get %s, but now got %s", expected, got) + return + } + + /* + # 数据库不为空 + + redis> MSET fruit "apple" drink "beer" food "cookies" # 设置多个 key + OK + + redis> RANDOMKEY + "fruit" + + redis> RANDOMKEY + "food" + + redis> KEYS * # 查看数据库内所有key,证明 RANDOMKEY 并不删除 key + 1) "food" + 2) "drink" + 3) "fruit" + */ + key_value_map := make(map[string]interface{}) + key_value_map["fruit"] = "apple" + key_value_map["drink"] = "beer" + key_value_map["food"] = "cookies" + err = redisPoolObj_db.MSet(key_value_map) + if err != nil { + t.Fail() + } + + got, exist, err = redisPoolObj_db.RandomKey() + if err != nil { + t.Fail() + } + if !exist { + t.Errorf("RandomKey should exist, but now it doesn't.") + return + } + if _, exist = key_value_map[got]; !exist { + t.Errorf("RandomKey should exist, but now it doesn't.") + return + } + + expected2 := make([]string, 0, len(key_value_map)) + for k := range key_value_map { + expected2 = append(expected2, k) + deleteKeys = append(deleteKeys, k) + } + got2, err := redisPoolObj_db.Keys("*") + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected2, got2) == false { + t.Errorf("Expected to get %v, but got %v\n", expected2, got2) + return + } +} + +func TestDBSize(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> DBSIZE + (integer) 0 + + redis> SET new_key "hello_moto" # 增加一个 key 试试 + OK + + redis> DBSIZE + (integer) 1 + */ + expected := 0 + got, err := redisPoolObj_db.DBSize() + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } + + key := "new_key" + value := "hello_moto" + redisPoolObj_db.Set(key, value, "", 0, "") + + deleteKeys = append(deleteKeys, key) + + expected = 1 + got, err = redisPoolObj_db.DBSize() + if err != nil { + t.Fail() + } + if got != expected { + t.Errorf("Expected to get %d, but now got %d", expected, got) + return + } +} + +func TestKeys(t *testing.T) { + deleteKeys := make([]string, 0, 8) + defer func() { + // Delete the test keys + distinctKeyList := getDistinctKeyList(deleteKeys) + count, err := redisPoolObj_list.Del(distinctKeyList...) + if err != nil { + t.Fail() + } + if count != len(distinctKeyList) { + t.Errorf("Expected to get %d, but now got %d", len(distinctKeyList), count) + return + } + }() + + /* + redis> MSET one 1 two 2 three 3 four 4 # 一次设置 4 个 key + OK + */ + key_value_map := make(map[string]interface{}) + key_value_map["one"] = "1" + key_value_map["two"] = "2" + key_value_map["three"] = "3" + key_value_map["four"] = "4" + err := redisPoolObj_db.MSet(key_value_map) + if err != nil { + t.Fail() + } + + for k := range key_value_map { + deleteKeys = append(deleteKeys, k) + } + + /* + redis> KEYS *o* + 1) "four" + 2) "two" + 3) "one" + */ + pattern := "*o*" + expected := []string{"four", "two", "one"} + got, err := redisPoolObj_db.Keys(pattern) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected, got) == false { + t.Errorf("Expected to get %v, but got %v\n", expected, got) + return + } + + /* + redis> KEYS t?? + 1) "two" + */ + pattern = "t??" + expected = []string{"two"} + got, err = redisPoolObj_db.Keys(pattern) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected, got) == false { + t.Errorf("Expected to get %v, but got %v\n", expected, got) + return + } + + /* + redis> KEYS t[w]* + 1) "two" + */ + pattern = "t[w]*" + expected = []string{"two"} + got, err = redisPoolObj_db.Keys(pattern) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected, got) == false { + t.Errorf("Expected to get %v, but got %v\n", expected, got) + return + } + + /* + redis> KEYS * # 匹配数据库内所有 key + 1) "four" + 2) "three" + 3) "two" + 4) "one" + */ + pattern = "*" + expected = []string{"two", "one", "three", "four"} + got, err = redisPoolObj_db.Keys(pattern) + if err != nil { + t.Fail() + } + if isTwoUnorderedSliceEqual(expected, got) == false { + t.Errorf("Expected to get %v, but got %v\n", expected, got) + return + } +} diff --git a/.svn/pristine/59/59644769e5532c6fa13a4bdf8e311311407deff0.svn-base b/.svn/pristine/59/59644769e5532c6fa13a4bdf8e311311407deff0.svn-base new file mode 100644 index 0000000..e01a089 --- /dev/null +++ b/.svn/pristine/59/59644769e5532c6fa13a4bdf8e311311407deff0.svn-base @@ -0,0 +1,400 @@ +package httpServer + +import ( + config "common/configsYaml" + "common/resultStatus" + "common/webServer" + "goutil/logUtilPlus" + "reflect" + "strconv" + "strings" +) + +const ( + // 供客户端访问的模块的后缀 + con_ModuleSuffix = "Module" + + // 定义用于分隔模块名称和方法名称的分隔符 + con_DelimeterOfObjAndMethod = "_" +) + +var ( + // 定义存放所有方法映射的变量 + methodMap = make(map[string]*methodAndInOutTypes) + + // 函数返回值类型 + responseType reflect.Type = reflect.TypeOf(new(webServer.ResponseObject)) +) + +// getStructName +// @description: 获取结构体类型的名称 +// parameter: +// @structType: 结构体类型 +// return: +// @string: 结构体类型的名称 +func getStructName(structType reflect.Type) string { + reflectTypeStr := structType.String() + reflectTypeArr := strings.Split(reflectTypeStr, ".") + + return reflectTypeArr[len(reflectTypeArr)-1] +} + +// getFullModuleName +// @description: 获取完整的模块名称 +// parameter: +// @moduleName: 模块名称 +// return: +// @string: 完整的模块名称 +func getFullModuleName(moduleName string) string { + return moduleName + con_ModuleSuffix +} + +// getFullMethodName +// @description: 获取完整的方法名称 +// parameter: +// @structName: 结构体名称 +// @methodName: 方法名称 +// return: +// @string: 完整的方法名称 +func getFullMethodName(structName, methodName string) string { + return structName + con_DelimeterOfObjAndMethod + methodName +} + +// resolveMethodInOutParams +// @description: 解析方法的输入输出参数 +// parameter: +// @method: 方法对应的反射值 +// return: +// @inTypes: 输入参数类型集合 +// @outTypes: 输出参数类型集合 +func resolveMethodInOutParams(method reflect.Value) (inTypes []reflect.Type, outTypes []reflect.Type) { + methodType := method.Type() + for i := 0; i < methodType.NumIn(); i++ { + inTypes = append(inTypes, methodType.In(i)) + } + + for i := 0; i < methodType.NumOut(); i++ { + outTypes = append(outTypes, methodType.Out(i)) + } + + return +} + +// RegisterFunction +// @description: 将需要对客户端提供方法的对象进行注册 +// parameter: +// @structObject: 对象 +// return: +func RegisterFunction(structObject interface{}) { + // 获取structObject对应的反射 Type 和 Value + reflectValue := reflect.ValueOf(structObject) + reflectType := reflect.TypeOf(structObject) + + // 提取对象类型名称 + structName := getStructName(reflectType) + + // 获取structObject中返回值为responseObject的方法 + for i := 0; i < reflectType.NumMethod(); i++ { + // 获得方法名称 + methodName := reflectType.Method(i).Name + + // 获得方法及其输入参数的类型列表 + method := reflectValue.MethodByName(methodName) + inTypes, outTypes := resolveMethodInOutParams(method) + + // 判断输出参数数量是否正确 + if len(outTypes) != 1 { + continue + } + + // 判断返回值是否为responseObject + if outTypes[0] != responseType { + continue + } + + // 添加到列表中 + methodMap[getFullMethodName(structName, methodName)] = newmethodAndInOutTypes(method, inTypes, outTypes) + } +} + +// CallFunction +// @description: 调用方法 +// parameter: +// @requestObj: 客户端对象 +// return: +// @responseObj: 请求对象 +func CallFunction(requestObj *webServer.RequestObject) (responseObj *webServer.ResponseObject) { + responseObj = webServer.GetInitResponseObj() + + var methodAndInOutTypes *methodAndInOutTypes + var ok bool + + // 根据传入的ModuleName和MethodName找到对应的方法对象 + key := getFullMethodName(requestObj.ModuleName, requestObj.MethodName) + if methodAndInOutTypes, ok = methodMap[key]; !ok { + logUtilPlus.ErrorLog("找不到指定的方法:%s", key) + responseObj.SetResultStatus(resultStatus.NotSpecificMethod) + return + } + + // 判断参数数量是否相同 + inTypesLength := len(methodAndInOutTypes.InTypes) + paramLength := len(requestObj.Parameters) + if paramLength != inTypesLength { + logUtilPlus.ErrorLog("传入的参数数量不符,本地方法%s的参数数量:%d,传入的参数数量为:%d", key, inTypesLength, paramLength) + responseObj.SetResultStatus(resultStatus.ParamNotMatch) + return + } + + // 构造参数 + in := make([]reflect.Value, inTypesLength) + for i := 0; i < inTypesLength; i++ { + inTypeItem := methodAndInOutTypes.InTypes[i] + paramItem := requestObj.Parameters[i] + + // 已支持类型:Client,Player(非基本类型) + // 已支持类型:Bool,Int,Int8,Int16,Int32,Int64,Uint,Uint8,Uint16,Uint32,Uint64,Float32,Float64,String + // 已支持类型:以及上面所列出类型的Slice类型 + // 未支持类型:Uintptr,Complex64,Complex128,Array,Chan,Func,Interface,Map,Ptr,Struct,UnsafePointer + // 由于byte与int8同义,rune与int32同义,所以并不需要单独处理 + // 枚举参数的类型,并进行类型转换 + switch inTypeItem.Kind() { + case reflect.Bool: + if param_bool, ok := paramItem.(bool); ok { + in[i] = reflect.ValueOf(param_bool) + } + case reflect.Int: + if param_float64, ok := paramItem.(int); ok { + in[i] = reflect.ValueOf(int(param_float64)) + } + case reflect.Int8: + if param_float64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(int8(param_float64)) + } + case reflect.Int16: + if param_float64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(int16(param_float64)) + } + case reflect.Int32: + if param_float64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(int32(param_float64)) + } + case reflect.Int64: + if param_float64, ok := paramItem.(int64); ok { + in[i] = reflect.ValueOf(int64(param_float64)) + } else if param_uint64, ok := paramItem.(uint64); ok { + in[i] = reflect.ValueOf(int64(param_uint64)) + } else if param_string, ok := paramItem.(string); ok { + + i64, err := strconv.ParseInt(param_string, 10, 64) + + if err == nil { + in[i] = reflect.ValueOf(i64) + } + } + case reflect.Uint: + if param_float64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(uint(param_float64)) + } + case reflect.Uint8: + if param_float64, ok := paramItem.(uint8); ok { + in[i] = reflect.ValueOf(uint8(param_float64)) + } + case reflect.Uint16: + if param_float64, ok := paramItem.(uint16); ok { + in[i] = reflect.ValueOf(uint16(param_float64)) + } + case reflect.Uint32: + if param_float64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(uint32(param_float64)) + } + case reflect.Uint64: + if param_float64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(uint64(param_float64)) + } + case reflect.Float32: + if param_float64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(float32(param_float64)) + } + case reflect.Float64: + if param_float64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(param_float64) + } + case reflect.String: + if param_string, ok := paramItem.(string); ok { + in[i] = reflect.ValueOf(param_string) + } + case reflect.Slice: + // 如果是Slice类型,则需要对其中的项再次进行类型判断及类型转换 + if param_interface, ok := paramItem.([]interface{}); ok { + switch inTypeItem.String() { + case "[]bool": + params_inner := make([]bool, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_bool, ok := param_interface[i].(bool); ok { + params_inner[i] = param_bool + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int": + params_inner := make([]int, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(int); ok { + params_inner[i] = int(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int8": + params_inner := make([]int8, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(float64); ok { + params_inner[i] = int8(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int16": + params_inner := make([]int16, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(float64); ok { + params_inner[i] = int16(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int32": + params_inner := make([]int32, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + param_float64, ok := param_interface[i].(int32) + if ok { + params_inner[i] = int32(param_float64) + continue + } else { + param_int16, right := param_interface[i].(uint16) + if right == true { + params_inner[i] = int32(param_int16) + } + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int64": + params_inner := make([]int64, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(int64); ok { + params_inner[i] = int64(param_float64) + } else if param_uint64, ok := param_interface[i].(uint64); ok { + params_inner[i] = int64(param_uint64) + } else if param_string, ok := param_interface[i].(string); ok { + + i64, err := strconv.ParseInt(param_string, 10, 64) + + if err == nil { + params_inner[i] = i64 + } + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]uint": + params_inner := make([]uint, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(uint); ok { + params_inner[i] = uint(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + // case "[]uint8": 特殊处理 + case "[]uint16": + params_inner := make([]uint16, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(uint16); ok { + params_inner[i] = uint16(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]uint32": + params_inner := make([]uint32, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(uint32); ok { + params_inner[i] = uint32(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]uint64": + params_inner := make([]uint64, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(uint64); ok { + params_inner[i] = uint64(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]float32": + params_inner := make([]float32, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(float64); ok { + params_inner[i] = float32(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]float64": + params_inner := make([]float64, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(float64); ok { + params_inner[i] = param_float64 + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]string": + params_inner := make([]string, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_string, ok := param_interface[i].(string); ok { + params_inner[i] = param_string + } + } + in[i] = reflect.ValueOf(params_inner) + } + } else if inTypeItem.String() == "[]uint8" { // 由于[]uint8在传输过程中会被转化成字符串,所以单独处理; + if param_string, ok := paramItem.(string); ok { + param_uint8 := ([]uint8)(param_string) + in[i] = reflect.ValueOf(param_uint8) + } + } + } + } + + // 判断是否有无效的参数(传入的参数类型和方法定义的类型不匹配导致没有赋值) + for _, item := range in { + if reflect.Value.IsValid(item) == false { + logUtilPlus.ErrorLog("type:%v,value:%v.方法%s传入的参数%v无效", reflect.TypeOf(item), reflect.ValueOf(item), key, requestObj.Parameters) + responseObj.SetResultStatus(resultStatus.ParamInValid) + return + } + } + + // 传入参数,调用方法 + if config.DEBUG { + if requestObj.MethodName != "GetRefreshData" { + logUtilPlus.DebugLog("Begin Call Func:module:%v, method:%v,inParams:%v\n\n", requestObj.ModuleName, requestObj.MethodName, in) + } + } + + out := methodAndInOutTypes.Method.Call(in) + + if config.DEBUG { + if requestObj.MethodName != "GetRefreshData" { + for i, v := range in { + logUtilPlus.DebugLog("\nparams %v,%v\n", i, v) + } + } + } + + // 并输出结果到客户端(由于只有一个返回值,所以取out[0]) + if responseObj, ok = (&out[0]).Interface().(*webServer.ResponseObject); !ok { + logUtilPlus.ErrorLog("返回值类型推断为ResponseObject 出错, tyep is :%v", reflect.TypeOf(out[0])) + responseObj.SetResultStatus(resultStatus.ParamInValid) + return + } + if config.DEBUG { + if requestObj.MethodName != "GetRefreshData" { + logUtilPlus.DebugLog("返回数据:code:%v, data:%v, mess:%v\n\n", responseObj.Code, responseObj.Value, responseObj.Message) + } + } + return +} diff --git a/.svn/pristine/59/59761351ace94d6dc0a08b6752112ec23c9e90ea.svn-base b/.svn/pristine/59/59761351ace94d6dc0a08b6752112ec23c9e90ea.svn-base new file mode 100644 index 0000000..d54c4b9 --- /dev/null +++ b/.svn/pristine/59/59761351ace94d6dc0a08b6752112ec23c9e90ea.svn-base @@ -0,0 +1,82 @@ +/* + 此包提供通用的HTTP/HTTPS服务器功能; + 使用方法如下: + 1、初始化一个HttpServer/HttpsServer + server := NewHttpServer(addr string, isCheckIP bool) + 或 + server := NewHttpsServer(addr, certFileName, keyFileName string, isCheckIP bool) + 其中参数说明如下: + addr:服务器监听地址 + isCheckIP:是否需要验证客户端IP(此设置针对所有的请求,对于每个请求也可以单独设置;以此设置为优先) + certFileName:证书文件的路径 + keyFileName:密钥文件的路径 + + 2、设置server的属性 + 在服务器运行过程中,会有一些默认的行为,如果想要改变默认行为,可以通过调用以下的方法进行设置 + + 1)、设定Http Header信息 + SetHeader(header map[string]string) + 默认的Http Header为空;如果设定了Http Header,则在每次请求时,都会给ResponseWriter加上该header属性 + 2)、设定HTTP请求方法 + SetMethod(method string) + 默认情况下,对请求的方法没有任何限制;如果设定了Method,则只允许该Method访问 + 3)、设定当HTTP请求方法无效时,调用的处理器 + SetInvalidMethodHandler(handler func(*Context)) + 默认情况下,如果请求方法与所设置的方法不一致时,会返回406错误;如果设置了此属性,则会调用此属性进行处理 + 4)、设定默认页的处理器 + SetDefaultPageHandler(handler func(*Context)) + 默认页指的是/, /favicon.ico这两个页面;默认情况下,仅仅是输出Welcome to home page.;如果需要针对做一些处理,可以设置此属性 + 5)、设定未找到指定的回调时的处理器 + SetNotFoundPageHandler(handler func(*Context)) + 当服务器找不到对应的地址的Handler时,会返回404错误。如果需要处理一些非固定的地址时,可以使用此方法;比如回调地址中包含AppId,所以导致地址可变 + 6)、设定在Debug模式下是否需要验证IP地址 + SetIfCheckIPWhenDebug(value bool) + 默认情况下,在DEBUG模式时不验证IP;可以通过此属性改变此此行为 + 7)、设定当IP无效时调用的处理器 + SetIPInvalidHandler(handler func(*Context)) + 当需要验证IP并且IP无效时,默认情况下会返回401错误;如果设定了此属性,则可以改变该行为 + 8)、设定当检测到参数无效时调用的处理器 + SetParamInvalidHandler(handler func(*Context)) + 当检测到参数无效时,默认情况下会返回500错误;如果设置了此属性,则可以改变该行为 + 9)、设定处理请求数据的处理器(例如压缩、解密等) + SetRequestDataHandler(handler func(*Context, []byte) ([]byte, error)) + 如果设定此属性,则在处理接收到的请求数据时,会调用此属性 + 10)、设定处理响应数据的处理器(例如压缩、加密等) + SetResponseDataHandler(handler func(*Context, []byte) ([]byte, error)) + 如果设定此属性,则在处理返回给客户端的数据时,会调用此属性 + 11)、设定请求执行时间的处理器 + SetExecuteTimeHandler(handler func(*Context)) + 如果在请求结束后想要处理调用的时间,则需要设置此属性;例如请求时间过长则记录日志等 + + 3、注册handler + server.RegisterHandler(path string, handlerFuncObj handlerFunc, configObj *HandlerConfig) + 参数如下: + // path:注册的访问路径 + // callback:回调方法 + // configObj:Handler配置对象 + 例如:server.RegisterHandler("/get/notice", getNoticeConfig, &webServer.HandlerConfig{IsCheckIP: false, ParamNameList: []string{"appid"}}) + + 4、启动对应的服务器 + server.Start(wg *sync.WaitGroup) + + 5、context中提供了很多实用的方法 + 1)、GetRequestPath() string:获取请求路径(该路径不带参数) + 2)、GetRequestIP() string:获取请求的客户端的IP地址 + 3)、GetExecuteSeconds() int64:获取请求执行的秒数。当然也可以通过获取StartTime, EndTime属性自己进行更高精度的处理 + 4)、String() string:将context里面的内容进行格式化,主要用于记录日志 + 5)、FormValue(key string) string:获取请求的参数值(包括GET/POST/PUT/DELETE等所有参数) + 6)、PostFormValue(key string) string:获取POST的参数值 + 7)、GetFormValueData() typeUtil.MapData:获取所有参数的MapData类型(包括GET/POST/PUT/DELETE等所有参数) + 8)、GetPostFormValueData() typeUtil.MapData:获取POST参数的MapData类型 + 9)、GetMultipartFormValueData() typeUtil.MapData:获取MultipartForm的MapData类型 + 10)、GetRequestBytes() (result []byte, exists bool, err error):获取请求字节数据 + 11)、GetRequestString() (result string, exists bool, err error):获取请求字符串数据 + 12)、Unmarshal(obj interface{}) (exists bool, err error):反序列化为对象(JSON) + 13)、WriteString(result string):输出字符串给客户端 + 14)、WriteJson(result interface{}):输出json数据给客户端 + 15)、RedirectTo(url string):重定向到其它页面 + 如果以上的方法不能满足需求,则可以调用以下的方法来获取原始的Request/ResponseWriter对象进行处理 + 16)、GetRequest() *http.Request:获取请求对象 + 17)、GetResponseWriter() http.ResponseWriter:获取响应对象 +*/ +package webServer diff --git a/.svn/pristine/59/59b53e67e3409c1fc1075865f0d23cd455d28d1f.svn-base b/.svn/pristine/59/59b53e67e3409c1fc1075865f0d23cd455d28d1f.svn-base new file mode 100644 index 0000000..fdd8647 --- /dev/null +++ b/.svn/pristine/59/59b53e67e3409c1fc1075865f0d23cd455d28d1f.svn-base @@ -0,0 +1,184 @@ +package managecenterModel + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "goutil/stringUtil" +) + +// 服务器组 +type ServerGroup struct { + // 服务器组Id + Id int32 `json:"GroupID"` + + // 服务器组名称 + Name string `json:"GroupName"` + + // 服务器组Url + Url string `json:"GroupUrl"` + + // 聊天服务器Url + ChatServerUrl string `json:"ChatServerUrl"` + + // 数据库连接配置 + DBConnectionConfig string `json:"DBConnectionConfig"` + + // 服务器组状态(1:正常;2:维护) + GroupState int32 `json:"GroupState"` + + // 服务器组热度(1:正常;2:新服;3:推荐) + GroupHeat int32 `json:"GroupHeat"` + + // 服务器组负载(1:正常;2:火爆) + GroupLoad int32 `json:"GroupLoad"` + + // 服务器开服时间对应的Unix时间戳 + OpenTimeTick int64 `json:OpenTimeTick` + + // 服务器组Ip(外网IP;内网IP;回调GS内网端口) + Ip string `json:"GroupIp"` + + // 正式服或测试服;1:正式服;2:测试服 + OfficialOrTest int32 `json:"OfficialOrTest"` + + // 服务器组类型 + Type int32 `json:"GroupType"` + + // 服务器组排序 + Order int32 `json:"GroupOrder"` + + // 服务器组维护开始时间对应的时间戳 + MaintainBeginTimeTick int64 `json:MaintainBeginTimeTick` + + // 维护持续分钟数 + MaintainMinutes int32 `json:"MaintainMinutes"` + + // 维护信息 + MaintainMessage string `json:"MaintainMessage"` + + // 游戏监听地址 + GameListenAddr string `json:"GameListenAddr"` + + // 回调监听地址 + CallbackListenAddr string `json:"CallbackListenAddr"` + + // 外网回调地址 + ExternalCallbackUrl string `json:"ExternalCallbackUrl"` + + // 内网回调地址 + InternalCallbackUrl string `json:"InternalCallbackUrl"` + + // 是否在主群组(机房)内 + IsInMainGroup bool `json:"IsInMainGroup"` + + // 监控端口 + GopsPort string `json:"GopsPort"` +} + +// 排序方法(默认按照Id进行升序排序) +// target:另一个服务器组对象 +// 是否是小于 +func (this *ServerGroup) SortByIdAsc(target *ServerGroup) bool { + return this.Id < target.Id +} + +// 按照开服时间进行升序排序 +// target:另一个服务器组对象 +// 是否是小于 +func (this *ServerGroup) SortByOpenTimeAsc(target *ServerGroup) bool { + return this.OpenTimeTick < target.OpenTimeTick +} + +// 获取数据库配置对象 +// 返回值: +// 数据库配置对象 +// 错误对象 +func (this *ServerGroup) GetDBConfig() (*DBConnectionConfig, error) { + var dbConfig *DBConnectionConfig + if err := json.Unmarshal([]byte(this.DBConnectionConfig), &dbConfig); err != nil { + return nil, err + } + + return dbConfig, nil +} + +// 获取ip列表 +// 返回值: +// ip列表 +func (this *ServerGroup) GetIPList() []string { + return stringUtil.Split(this.Ip, nil) +} + +// 服务器组是否开启 +// 返回值: +// 是否开启 +func (this *ServerGroup) IsOpen() bool { + return this.OpenTimeTick < time.Now().Unix() +} + +// 获取游戏服务器的回调地址 +// suffix:地址后缀 +// 返回值 +// 游戏服务器的回调地址 +func (this *ServerGroup) GetGSCallbackUrl(suffix string) string { + // 如果是在主群组(机房)内,则使用内网地址,否则使用外网地址 + url := "" + if this.IsInMainGroup { + url = this.InternalCallbackUrl + } else { + url = this.ExternalCallbackUrl + } + + if url != "" { + if strings.HasSuffix(url, "/") { + return fmt.Sprintf("%s%s", url, suffix) + } else { + return fmt.Sprintf("%s/%s", url, suffix) + } + } + + // 兼容旧的ManageCenter版本 + ipList := this.GetIPList() + + // 外网IP;内网IP;回调GS内网端口;如果数量小于3,则直接使用配置的GroupUrl;否则使用第3个值 + if len(ipList) < 3 { + if strings.HasSuffix(this.Url, "/") { + return fmt.Sprintf("%s%s", this.Url, suffix) + } else { + return fmt.Sprintf("%s/%s", this.Url, suffix) + } + } else { + return fmt.Sprintf("http://%s:%s/%s", ipList[1], ipList[2], suffix) + } +} + +// 判断服务器组是否相同 +// target:目标服务器组 +// 是否相同 +func (this *ServerGroup) IsEqual(target *ServerGroup) bool { + return this.Id == target.Id && + this.Name == target.Name && + this.Url == target.Url && + this.ChatServerUrl == target.ChatServerUrl && + this.DBConnectionConfig == target.DBConnectionConfig && + this.GroupState == target.GroupState && + this.GroupHeat == target.GroupHeat && + this.GroupLoad == target.GroupLoad && + this.OpenTimeTick == target.OpenTimeTick && + this.Ip == target.Ip && + this.OfficialOrTest == target.OfficialOrTest && + this.Type == target.Type && + this.Order == target.Order && + this.MaintainBeginTimeTick == target.MaintainBeginTimeTick && + this.MaintainMinutes == target.MaintainMinutes && + this.MaintainMessage == target.MaintainMessage && + this.GameListenAddr == target.GameListenAddr && + this.CallbackListenAddr == target.CallbackListenAddr && + this.ExternalCallbackUrl == target.ExternalCallbackUrl && + this.InternalCallbackUrl == target.InternalCallbackUrl && + this.IsInMainGroup == target.IsInMainGroup && + this.GopsPort == target.GopsPort +} diff --git a/.svn/pristine/59/59bf7d0767b223adba34dffed1cabbbbbcb8210a.svn-base b/.svn/pristine/59/59bf7d0767b223adba34dffed1cabbbbbcb8210a.svn-base new file mode 100644 index 0000000..d868a9d --- /dev/null +++ b/.svn/pristine/59/59bf7d0767b223adba34dffed1cabbbbbcb8210a.svn-base @@ -0,0 +1,13 @@ +package model + +// 错误信息对象 +type ErrorInfo struct { + // 错误码 + Code int `json:"code"` + + // 错误提示信息 + Message string `json:"message"` + + // 对应删除失败的消息句柄 + ReceiptHandle string `json:"receiptHandle"` +} diff --git a/.svn/pristine/5a/5a189554277f63f045f0d9feff1a77292f1eada0.svn-base b/.svn/pristine/5a/5a189554277f63f045f0d9feff1a77292f1eada0.svn-base new file mode 100644 index 0000000..dc864a9 --- /dev/null +++ b/.svn/pristine/5a/5a189554277f63f045f0d9feff1a77292f1eada0.svn-base @@ -0,0 +1,93 @@ +package ipMgr + +import ( + "encoding/json" + "fmt" + "time" + + "goutil/securityUtil" + "goutil/webUtil" +) + +var ( + IP_SERVICE_URL = "http://ipip.7qule.com/query" +) + +// 服务器的响应对象 +type QueryResponse struct { + // 响应结果的状态值 + ResultStatus string + + // 响应结果的数据 + Data *IPInfo +} + +// IP信息对象 +type IPInfo struct { + // 所属大陆块 + Continent string + + // 国家 + Country string + + // 省份 + Region string + + // 城市 + City string + + // 网络服务提供商 + Isp string +} + +// 查询ip地址的详细信息 +// appId: 为应用分配的唯一标识 +// appSecret: 为应用分配的密钥 +// ip: 待查询的ip地址 +// isDomestic: 是否为国内的IP +// timeout:超时时间(单位:秒) +// 返回值: +// ipInfoObj: IP地址信息对象 +// err: 错误对象 +func Query(appId, appSecret, ip string, isDomestic bool, timeout int) (ipInfoObj *IPInfo, err error) { + timeStamp := fmt.Sprintf("%d", time.Now().Unix()) + rawString := fmt.Sprintf("AppId=%s&IP=%s&Timestamp=%s&AppSecret=%s", appId, ip, timeStamp, appSecret) + sign := securityUtil.Md5String(rawString, true) + + postData := make(map[string]string, 5) + postData["AppId"] = appId + postData["IP"] = ip + postData["IsDomestic"] = fmt.Sprintf("%t", isDomestic) + postData["Timestamp"] = timeStamp + postData["Sign"] = sign + + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, timeout) + + statusCode, result, err := webUtil.PostMapData(IP_SERVICE_URL, postData, header, transport) + //statusCode, result, err := webUtil.PostMapData(IP_SERVICE_URL, postData, header, transport) + if err != nil { + return + } + if statusCode != 200 { + err = fmt.Errorf("StatusCode:%d is wrong.", statusCode) + return + } + + var queryResponseObj *QueryResponse + err = json.Unmarshal(result, &queryResponseObj) + if err != nil { + return + } + + if queryResponseObj.ResultStatus != "" { + err = fmt.Errorf("Query result:%s", queryResponseObj.ResultStatus) + return + } + + ipInfoObj = queryResponseObj.Data + + return +} diff --git a/.svn/pristine/5a/5aaba2322ee53e31116a0cc59afcda10b566881f.svn-base b/.svn/pristine/5a/5aaba2322ee53e31116a0cc59afcda10b566881f.svn-base new file mode 100644 index 0000000..4931c7e --- /dev/null +++ b/.svn/pristine/5a/5aaba2322ee53e31116a0cc59afcda10b566881f.svn-base @@ -0,0 +1,27 @@ +package syncUtil + +import ( + "fmt" + "testing" +) + +var ( + rwLockerUtilObj = NewRWLockerUtil() +) + +func RWLockerUtil_TestGetLock(t *testing.T) { + count := 100 + for i := 1; i <= count; i++ { + rwLockerUtilObj.GetLock(fmt.Sprintf("%d", i)) + if lockerCount := len(rwLockerUtilObj.lockerMap); lockerCount != i { + t.Errorf("(GetLock)Expected %d locker, but now got: %d", count, lockerCount) + } + } + + for i := count; i > 0; i-- { + rwLockerUtilObj.ReleaseLock(fmt.Sprintf("%d", i)) + if lockerCount := len(rwLockerUtilObj.lockerMap); lockerCount != i-1 { + t.Errorf("(ReleaseLock)Expected %d locker, but now got: %d", count, lockerCount) + } + } +} diff --git a/.svn/pristine/5b/5b1d2eb77b85e4e36232243c7273ed32a23df5dc.svn-base b/.svn/pristine/5b/5b1d2eb77b85e4e36232243c7273ed32a23df5dc.svn-base new file mode 100644 index 0000000..57f1cf1 --- /dev/null +++ b/.svn/pristine/5b/5b1d2eb77b85e4e36232243c7273ed32a23df5dc.svn-base @@ -0,0 +1,120 @@ + + + + + + + + + + + + { + "associatedIndex": 4 +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + file://$PROJECT_DIR$/common/configs/init.go + 34 + + + file://$PROJECT_DIR$/common/httpServer/reflect.go + 362 + + + + + + + + + + \ No newline at end of file diff --git a/.svn/pristine/5b/5b7144648d38e77bea09228526e4a1cc66a86fd9.svn-base b/.svn/pristine/5b/5b7144648d38e77bea09228526e4a1cc66a86fd9.svn-base new file mode 100644 index 0000000..a953b31 --- /dev/null +++ b/.svn/pristine/5b/5b7144648d38e77bea09228526e4a1cc66a86fd9.svn-base @@ -0,0 +1,175 @@ +package managecenterMgr + +import ( + "encoding/json" + "errors" + "fmt" + + "Framework/managecenterModel" + . "Framework/managecenterModel" + "goutil/logUtil" + "goutil/webUtil" +) + +var ( + serverMap = make(map[int32]map[int32]*Server, 128) + serverDistinctMap = make(map[int32]*Server, 1024) + serverHash string +) + +// 重新加载服务器 +func reloadServer(isInit bool) error { + //logUtil.DebugLog("开始刷新服务器列表") + + url := getManageCenterUrl("/API/ServerList.ashx") + + // 定义请求参数 + postDict := make(map[string]string) + postDict["GroupType"] = "Mix" + postDict["HashValue"] = serverHash + + //请求url,请求头 + header := webUtil.GetFormHeader() + transport := webUtil.NewTransport() + transport.DisableKeepAlives = true + transport = webUtil.GetTimeoutTransport(transport, 30) + + statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, transport) + //statusCode, returnBytes, err := webUtil.PostMapData(url, postDict, header, nil) + if err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取服务器列表出错,url:%s,错误信息为:%s", url, err)) + return err + } + if statusCode != 200 { + logUtil.ErrorLog(fmt.Sprintf("获取服务器列表出错,url:%s,错误码为:%d", url, statusCode)) + return err + } + + // 解析返回值 + returnObj := new(ReturnObject) + if err = json.Unmarshal(returnBytes, &returnObj); err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取服务器列表出错,反序列化返回值出错,错误信息为:%s, str:%s", err, string(returnBytes))) + return err + } + + // 判断返回状态是否成功 + if returnObj.Code != 0 { + // 数据没有变化,所以没有获取到新的数据,不能算错误。 + if returnObj.Code == 47 || returnObj.Message == "DataNotChanged" { + //如果本地集合为空,且数据又没变化时,重新初始化一下本地hash值 + if len(serverMap) == 0 { + serverHash = "" + } + return nil + } else { + msg := fmt.Sprintf("获取服务器列表出错,返回状态:%d,信息为:%s", returnObj.Code, returnObj.Message) + logUtil.ErrorLog(msg) + return errors.New(msg) + } + } + + // 解析Data + tmpServerList := make([]*Server, 0, 1024) + if data, ok := returnObj.Data.(string); !ok { + msg := "获取服务器列表出错,返回的数据不是string类型" + logUtil.ErrorLog(msg) + return errors.New(msg) + } else { + if err = json.Unmarshal([]byte(data), &tmpServerList); err != nil { + logUtil.ErrorLog(fmt.Sprintf("获取服务器列表出错,反序列化数据出错,错误信息为:%s", err)) + return err + } + } + + //logUtil.DebugLog(fmt.Sprintf("刷新服务器信息结束,服务器数量:%d", len(tmpServerList))) + + tmpServerMap := make(map[int32]map[int32]*Server, 128) + tmpServerDistinctMap := make(map[int32]*Server, 1024) + for _, item := range tmpServerList { + // 构造tmpServerMap数据 + if _, ok := tmpServerMap[item.PartnerId]; !ok { + tmpServerMap[item.PartnerId] = make(map[int32]*Server, 1024) + } + tmpServerMap[item.PartnerId][item.Id] = item + + // 构造tmpServerDistinctMap数据 + tmpServerDistinctMap[item.Id] = item + } + + // 赋值给最终的serverMap、serverDistinctMap + serverMap = tmpServerMap + serverDistinctMap = tmpServerDistinctMap + serverHash = returnObj.HashValue + + //通知变更 + mcDataChangeCallBack(managecenterModel.ServerData, isInit) + + return nil +} + +// 根据服务器组Id获取对应的服务器列表 +// serverGroupId:服务器组Id +// 返回值: +// 服务器列表 +func GetServerListByGroupId(serverGroupId int32) (serverList []*Server) { + for _, subServerMap := range serverMap { + for _, item := range subServerMap { + if item.GroupId == serverGroupId { + serverList = append(serverList, item) + } + } + } + + return +} + +// 根据合作商Id获取对应的服务器列表 +// partnerId:合作商Id +// 返回值: +// 服务器列表 +func GetServerListByPartnerId(partnerId int32) (serverList []*Server) { + for _, item := range serverMap[partnerId] { + serverList = append(serverList, item) + } + + return +} + +// 根据合作商对象、服务器Id获取服务器对象 +// partnerObj:合作商对象 +// serverId:服务器Id +// 返回值: +// 服务器对象 +// 是否存在 +func GetServer(partnerObj *Partner, serverId int32) (serverObj *Server, exist bool) { + if subServerMap, exist1 := serverMap[partnerObj.Id]; exist1 { + serverObj, exist = subServerMap[serverId] + } + + return +} + +// 根据合作商Id、服务器Id获取服务器对象 +// partnerId:合作商Id +// serverId:服务器Id +// 返回值: +// 服务器对象 +// 是否存在 +func GetServerItem(partnerId, serverId int32) (serverObj *Server, exist bool) { + if subServerMap, exist1 := serverMap[partnerId]; exist1 { + serverObj, exist = subServerMap[serverId] + } + + return +} + +// 获取不重复的服务器Id列表 +// 返回值: +// 不重复的服务器Id列表 +func GetDistinctServerIdList() (distinctServerIdList []int32) { + for _, item := range serverDistinctMap { + distinctServerIdList = append(distinctServerIdList, item.Id) + } + + return +} diff --git a/.svn/pristine/5b/5ba8ba3ff47876b2475132ee02919a860a69a8d5.svn-base b/.svn/pristine/5b/5ba8ba3ff47876b2475132ee02919a860a69a8d5.svn-base new file mode 100644 index 0000000..039612a --- /dev/null +++ b/.svn/pristine/5b/5ba8ba3ff47876b2475132ee02919a860a69a8d5.svn-base @@ -0,0 +1,19 @@ +package monitorMgr + +import ( + "testing" +) + +func TestDuplicate(t *testing.T) { + SetParam("20.255.0.7", "Test", 5) + + content := "content" + + if isDuplicate(content) == true { + t.Errorf("%s不应该重复却重复了", content) + } + addToMap(content) + if isDuplicate(content) == false { + t.Errorf("%s应该重复却没有重复", content) + } +} diff --git a/.svn/pristine/5b/5bae2a2351dc932639f48484b5f38da44c769cab.svn-base b/.svn/pristine/5b/5bae2a2351dc932639f48484b5f38da44c769cab.svn-base new file mode 100644 index 0000000..d582285 --- /dev/null +++ b/.svn/pristine/5b/5bae2a2351dc932639f48484b5f38da44c769cab.svn-base @@ -0,0 +1,70 @@ +package webServer + +import ( + "fmt" + "net/http" + "sync" + + "goutil/logUtil" +) + +// Https服务器对象 +type HttpsServer struct { + addr string + certFileName string + keyFileName string + IWebServer + server http.Server +} + +func (this *HttpsServer) SetAddr(addr string) { + this.addr = addr + this.server.Addr = addr +} + +// 启动HttpsServer +func (this *HttpsServer) Start(wg *sync.WaitGroup) { + defer func() { + wg.Done() + }() + + // 开启监听 + msg := fmt.Sprintf("http server begins to listen on: %s...", this.addr) + fmt.Println(msg) + logUtil.InfoLog(msg) + + if err := this.server.ListenAndServeTLS(this.certFileName, this.keyFileName); err != nil { + panic(fmt.Sprintf("https server ListenAndServeTLS Error:%v", err)) + } +} + +// 创建新的HttpsServer +// isCheckIP:该属性已丢弃,可以任意赋值 +func NewHttpsServer(addr, certFileName, keyFileName string, isCheckIP bool) *HttpsServer { + webServerObj := NewWebServer(isCheckIP) + + return &HttpsServer{ + addr: addr, + certFileName: certFileName, + keyFileName: keyFileName, + IWebServer: webServerObj, + server: http.Server{ + Addr: addr, + Handler: webServerObj, + }, + } +} + +// 创建新的HttpsServer +func NewHttpsServer2(addr, certFileName, keyFileName string, webServerObj IWebServer) *HttpsServer { + return &HttpsServer{ + addr: addr, + certFileName: certFileName, + keyFileName: keyFileName, + IWebServer: webServerObj, + server: http.Server{ + Addr: addr, + Handler: webServerObj, + }, + } +} diff --git a/.svn/pristine/5b/5be359c1bf55a499ca0575b8b4af358bbfbb7565.svn-base b/.svn/pristine/5b/5be359c1bf55a499ca0575b8b4af358bbfbb7565.svn-base new file mode 100644 index 0000000..271273f --- /dev/null +++ b/.svn/pristine/5b/5be359c1bf55a499ca0575b8b4af358bbfbb7565.svn-base @@ -0,0 +1,131 @@ +package deviceUtil + +import ( + "testing" +) + +func TestConvertMacToStarndardFormat(t *testing.T) { + mac := "" + expected := "" + got := ConvertMacToStandardFormat(mac) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "00:00:00:00:00:00" + expected = "" + got = ConvertMacToStandardFormat(mac) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "02:00:00:00:00:00" + expected = "" + got = ConvertMacToStandardFormat(mac) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "02:00:00:00:00" + expected = "" + got = ConvertMacToStandardFormat(mac) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "020000000020" + expected = "02:00:00:00:00:20" + got = ConvertMacToStandardFormat(mac) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "02:00:00:00:00:20" + expected = "02:00:00:00:00:20" + got = ConvertMacToStandardFormat(mac) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } +} + +func TestConvertIdfaToStandardFormat(t *testing.T) { + idfa := "" + expected := "" + got := ConvertIdfaToStandardFormat(idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + idfa = "00000000-0000-0000-0000-000000000000" + expected = "" + got = ConvertIdfaToStandardFormat(idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + idfa = "00000000-0000-0000-0000-000000000000-123" + expected = "00000000-0000-0000-0000-000000000000-123" + got = ConvertIdfaToStandardFormat(idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + idfa = "00000000-1234-5678-0000-000000000000" + expected = "00000000-1234-5678-0000-000000000000" + got = ConvertIdfaToStandardFormat(idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + idfa = "00000000123456780000000000000000" + expected = "00000000-1234-5678-0000-000000000000" + got = ConvertIdfaToStandardFormat(idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } +} + +func TestGetIdentifier(t *testing.T) { + mac := "" + idfa := "" + expected := "" + got := GetIdentifier(mac, idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "00:00:00:00:00:00" + expected = "" + got = GetIdentifier(mac, idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "02:00:00:00:00:00" + expected = "" + got = GetIdentifier(mac, idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "020000000020" + expected = "02:00:00:00:00:20" + got = GetIdentifier(mac, idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + mac = "02:00:00:00:00:20" + expected = "02:00:00:00:00:20" + got = GetIdentifier(mac, idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } + + idfa = "00000000123456780000000000000000" + expected = "00000000-1234-5678-0000-000000000000" + got = GetIdentifier(mac, idfa) + if got != expected { + t.Errorf("Expected: %s, but got:%s", expected, got) + } +} diff --git a/.svn/pristine/5c/5ce606a1bf41c73ac8d2169614eb70b18e7551ae.svn-base b/.svn/pristine/5c/5ce606a1bf41c73ac8d2169614eb70b18e7551ae.svn-base new file mode 100644 index 0000000..a31c5dc --- /dev/null +++ b/.svn/pristine/5c/5ce606a1bf41c73ac8d2169614eb70b18e7551ae.svn-base @@ -0,0 +1,56 @@ +package mysqlUtil + +import ( + "fmt" + "testing" + "time" +) + +func TestOpenMysqlConnection(t *testing.T) { + connectionString := "root:moqikaka3306@tcp(10.1.0.10:3306)/gameserver_data?charset=utf8&parseTime=true&loc=Local&timeout=60s||MaxOpenConns=10||MaxIdleConns=5" + + if _, err := OpenMysqlConnection(connectionString); err != nil { + t.Errorf("there should be no err, but now has:%s", err) + } +} + +func TestOpenMysqlConnection2(t *testing.T) { + connectionString := "root:moqikaka3306@tcp(10.1.0.10:3306)/gameserver_data?charset=utf8&parseTime=true&loc=Local&timeout=60s" + maxOpenConns := 10 + maxIdleConns := 5 + + if _, err := OpenMysqlConnection2(connectionString, maxOpenConns, maxIdleConns); err != nil { + t.Errorf("there should be no err, but now has:%s", err) + } +} + +func TestOpenMysqlConnection3(t *testing.T) { + dbConfigObj := NewDBConfig("root:moqikaka3306@tcp(10.1.0.10:3306)/sdkcenter?charset=utf8&parseTime=true&loc=Local&timeout=10s", 5, 2) + if _, err := OpenMysqlConnection3(dbConfigObj); err != nil { + t.Errorf("there should be no err, but now has:%s", err) + } +} + +func TestTestConnection(t *testing.T) { + dbConfigObj := NewDBConfig("root:moqikaka3306@tcp(10.1.0.10:3306)/sdkcenter?charset=utf8&parseTime=true&loc=Local&timeout=10s", 5, 2) + dbObj, err := OpenMysqlConnection3(dbConfigObj) + if err != nil { + t.Errorf("there should be no err, but now has:%s", err) + } + + succeedCount := 0 + expectedCount := 5 + for i := 0; i < expectedCount; i++ { + if err := TestConnection(dbObj); err != nil { + fmt.Printf("%s:%s\n", time.Now(), err) + } else { + succeedCount += 1 + fmt.Printf("%s:%s\n", time.Now(), "ok") + } + time.Sleep(time.Second * 3) + } + + if succeedCount != expectedCount { + t.Errorf("ExecptedCount:%d, but got %d", expectedCount, succeedCount) + } +} diff --git a/.svn/pristine/5d/5dc12fc1c712eed283d8593d10c63d946be7337c.svn-base b/.svn/pristine/5d/5dc12fc1c712eed283d8593d10c63d946be7337c.svn-base new file mode 100644 index 0000000..dcbbee5 --- /dev/null +++ b/.svn/pristine/5d/5dc12fc1c712eed283d8593d10c63d946be7337c.svn-base @@ -0,0 +1,218 @@ +package webServer + +import ( + "encoding/json" + "fmt" + "goutil/jsonUtil" + "goutil/logUtilPlus" + "goutil/typeUtil" + "goutil/zlibUtil" + "io/ioutil" + "net/http" +) + +// ApiContext +// @description: Api请求上下文对象 +type ApiContext struct { + // 请求对象 + request *http.Request + + // 应答写对象 + responseWriter http.ResponseWriter + + // 请求数据 + requestBytes []byte + + // 字典形式的请求数据 + requestDataByMap typeUtil.MapData + + //获取头部信息 + header *http.Header +} + +// GetRequest +// @description: 获取请求对象 +// parameter: +// @receiver this: this +// return: +// @*http.Request: 请求对象 +func (this *ApiContext) GetRequest() *http.Request { + return this.request +} + +// GetResponseWriter +// @description: 获取应答写对象 +// parameter: +// @receiver this: this +// return: +// @http.ResponseWriter: 应答写对象 +func (this *ApiContext) GetResponseWriter() http.ResponseWriter { + return this.responseWriter +} + +// GetRequestBytes +// @description: 获取请求字节数据 +// parameter: +// @receiver this: this +// return: +// @[]byte: 请求字节数组 +func (this *ApiContext) GetRequestBytes() []byte { + return this.requestBytes +} + +// readContent +// @description: 读取内容 +// parameter: +// @receiver this: this 请求对象 +// @isZlib: 是否数据压缩 +// return: +// @content: 二进制格式的内容 +// @err: 错误对象 +func (this *ApiContext) readContent(isZlib bool) (content []byte, err error) { + var buffer []byte + + defer this.request.Body.Close() + if buffer, err = ioutil.ReadAll(this.request.Body); err != nil { + logUtilPlus.ErrorLog(fmt.Sprintf("url:%s,读取数据出错,错误信息为:%s", this.request.RequestURI, err)) + return + } + + // 不压缩,则直接返回 + if isZlib == false { + this.requestBytes = buffer + + return buffer, err + } + + // 解压数据 + if content, err = zlibUtil.Decompress(buffer); err != nil { + logUtilPlus.ErrorLog(fmt.Sprintf("url:%s,解压缩数据出错,错误信息为:%s", this.request.RequestURI, err)) + return + } + + this.requestBytes = content + + return +} + +// Unmarshal +// @description: 反序列化 +// parameter: +// @receiver this: this +// @obj: 反序列化结果数据 +// return: +// @error: 反序列化错误数据 +func (this *ApiContext) Unmarshal(obj interface{}) error { + contentData := this.GetRequestBytes() + + var errMsg error + + // 反序列化 + if obj, errMsg = json.Marshal(contentData); errMsg != nil { + logUtilPlus.ErrorLog(fmt.Sprintf("反序列化%s出错,错误信息为:%s", string(contentData), errMsg.Error())) + return errMsg + } + + return nil +} + +// RequestDataByMap +// @description: 获取请求的map格式数据 +// parameter: +// @receiver this: this +// return: +// @typeUtil.MapData: map数据 +// @error: 错误信息 +func (this *ApiContext) RequestDataByMap() (typeUtil.MapData, error) { + if this.requestDataByMap != nil { + return this.requestDataByMap, nil + } + + var data typeUtil.MapData + if err := this.Unmarshal(&data); err != nil { + return nil, err + } + + this.requestDataByMap = data + + return this.requestDataByMap, nil +} + +// RequestDataBySlice +// @description: 获取请求的slice格式数据 +// parameter: +// @receiver this: this +// return: +// @[]interface{}: 返回的数组数据 +func (this *ApiContext) RequestDataBySlice() []interface{} { + result := make([]interface{}, 0, 8) + for _, value := range this.requestDataByMap { + result = append(result, value) + } + return result +} + +// RequestDataBySlice2 +// @description: 获取请求的slice格式数据 +// parameter: +// @receiver this: this +// return: +// @[]interface{}: 返回的数组数据 +// @error: +func (this *ApiContext) RequestDataBySlice2() (interface{}, error) { + contentData := this.GetRequestBytes() + + // 反序列化 + var result interface{} + var errMsg error + if result, errMsg = jsonUtil.UnMarshalWithNumberType(string(contentData)); errMsg != nil { + logUtilPlus.ErrorLog(fmt.Sprintf("用[]interface{}反序列化%s出错,错误信息为:%s", string(contentData), errMsg.Error())) + return nil, errMsg + } + return result, nil +} + +// RequestDataBySlice2ByJson +// @description: 获取请求的slice格式数据 +// parameter: +// @receiver this: this +// return: +// @[]interface{}: 返回的数组数据 +// @error: +func (this *ApiContext) RequestDataBySlice2ByJson() ([]interface{}, error) { + contentData := this.GetRequestBytes() + + // 反序列化 + result := make([]interface{}, 0, 8) + if errMsg := json.Unmarshal(contentData, &result); errMsg != nil { + logUtilPlus.ErrorLog(fmt.Sprintf("用[]interface{}反序列化%s出错,错误信息为:%s", string(contentData), errMsg.Error())) + return nil, errMsg + } + + return result, nil +} + +// NewApiContext +// @description: 新建API上下文对象 +// parameter: +// @_request: 请求对象 +// @_responseWriter: 应答写对象 +// @isZlib: 数据是否压缩 +// return: +// @*ApiContext: 上下文 +// @error: 错误信息 +func NewApiContext(_request *http.Request, _responseWriter http.ResponseWriter, isZlib bool) (*ApiContext, error) { + context := &ApiContext{ + request: _request, + header: &_request.Header, + responseWriter: _responseWriter, + } + + // 读取数据 + _, errMsg := context.readContent(isZlib) + if errMsg != nil { + return nil, errMsg + } + + return context, nil +} diff --git a/.svn/pristine/5d/5dca3ad5e01acc3892a93342d49523e7afb43b05.svn-base b/.svn/pristine/5d/5dca3ad5e01acc3892a93342d49523e7afb43b05.svn-base new file mode 100644 index 0000000..93eccef --- /dev/null +++ b/.svn/pristine/5d/5dca3ad5e01acc3892a93342d49523e7afb43b05.svn-base @@ -0,0 +1,99 @@ +package securityUtil + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "errors" +) + +var ( + // ErrInvalidBlockSize indicates hash blocksize <= 0. + ErrInvalidBlockSize = errors.New("invalid blocksize") + + // ErrInvalidPKCS7Data indicates bad input to PKCS7 pad or unpad. + ErrInvalidPKCS7Data = errors.New("invalid PKCS7 data (empty or not padded)") + + // ErrInvalidPKCS7Padding indicates PKCS7 unpad fails to bad input. + ErrInvalidPKCS7Padding = errors.New("invalid padding on input") +) + +// pkcs7Pad right-pads the given byte slice with 1 to n bytes, where +// n is the block size. The size of the result is x times n, where x +// is at least 1. +func pkcs7Pad(b []byte, blocksize int) ([]byte, error) { + if b == nil || len(b) == 0 { + return nil, ErrInvalidPKCS7Data + } + if blocksize <= 0 { + return nil, ErrInvalidBlockSize + } + n := blocksize - (len(b) % blocksize) + pb := make([]byte, len(b)+n) + copy(pb, b) + copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n)) + + return pb, nil +} + +// pkcs7Unpad validates and unpads data from the given bytes slice. +// The returned value will be 1 to n bytes smaller depending on the +// amount of padding, where n is the block size. +func pkcs7Unpad(b []byte, blocksize int) ([]byte, error) { + if b == nil || len(b) == 0 { + return nil, ErrInvalidPKCS7Data + } + if blocksize <= 0 { + return nil, ErrInvalidBlockSize + } + if len(b)%blocksize != 0 { + return nil, ErrInvalidPKCS7Padding + } + + c := b[len(b)-1] + n := int(c) + if n == 0 || n > len(b) { + return nil, ErrInvalidPKCS7Padding + } + + for i := 0; i < n; i++ { + if b[len(b)-n+i] != c { + return nil, ErrInvalidPKCS7Padding + } + } + + return b[:len(b)-n], nil +} + +func AESEncrypt_CBC_Pkcs7(src []byte, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + src, err = pkcs7Pad(src, block.BlockSize()) + if err != nil { + return nil, err + } + + blockmode := cipher.NewCBCEncrypter(block, key) + blockmode.CryptBlocks(src, src) + + return src, nil +} + +func AESDecrypt_CBC_Pkcs7(src []byte, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + blockmode := cipher.NewCBCDecrypter(block, key) + blockmode.CryptBlocks(src, src) + src, err = pkcs7Unpad(src, block.BlockSize()) + if err != nil { + return nil, err + } + + return src, nil +} diff --git a/.svn/pristine/5d/5df6cb671df6614fa95300a808373169e18b0950.svn-base b/.svn/pristine/5d/5df6cb671df6614fa95300a808373169e18b0950.svn-base new file mode 100644 index 0000000..28587cd --- /dev/null +++ b/.svn/pristine/5d/5df6cb671df6614fa95300a808373169e18b0950.svn-base @@ -0,0 +1,87 @@ +package httpServer + +import ( + "common/webServer" + "net/http" + + "common/resultStatus" +) + +// 处理函数 +type HandleFunc func(context *ApiContext) *webServer.ResponseObject + +// ApiHandler +// @description: API处理结构 +type ApiHandler struct { + // API完整路径名称 + apiFullName string + + // 方法定义 + handleFun HandleFunc + + // 方法参数名称集合 + funcParamNames []string +} + +// ApiFullName +// @description: API完整路径名称 +// parameter: +// @receiver this: this +// return: +// @string: +func (this *ApiHandler) ApiFullName() string { + return this.apiFullName +} + +// HandleFun +// @description: 方法定义 +// parameter: +// @receiver this: this +// return: +// @HandleFunc: 方法 +func (this *ApiHandler) HandleFun() HandleFunc { + return this.handleFun +} + +// FuncParamNames +// @description: 方法参数名称集合 +// parameter: +// @receiver this: this +// return: +// @[]string: 方法参数名称集合 +func (this *ApiHandler) FuncParamNames() []string { + return this.funcParamNames +} + +// CheckParam +// @description: 检测参数数量 +// parameter: +// @receiver this: this +// @r: +// return: +// @resultStatus.ResultStatus: 状态码数据 +func (this *ApiHandler) CheckParam(r *http.Request) resultStatus.ResultStatus { + for _, name := range this.funcParamNames { + if r.Form[name] == nil || len(r.Form[name]) == 0 { + return resultStatus.APIParamError + } + } + + return resultStatus.Success +} + +// newApiHandler +// @description: 创建新的请求方法对象 +// parameter: +// @_apiFullName: API完整路径名称 +// @_funcDefinition: 方法定义 +// @_funcParamNames: 方法参数名称集合 +// return: +// @*ApiHandler: 请求方法对象 +func newApiHandler(_apiFullName string, _funcDefinition HandleFunc, _funcParamNames ...string) *ApiHandler { + return &ApiHandler{ + apiFullName: _apiFullName, + handleFun: _funcDefinition, + funcParamNames: _funcParamNames, + } +} diff --git a/.svn/pristine/5e/5e0f209f6e9be1f84238e9cb97288fda3cb63dd8.svn-base b/.svn/pristine/5e/5e0f209f6e9be1f84238e9cb97288fda3cb63dd8.svn-base new file mode 100644 index 0000000..50e10d2 --- /dev/null +++ b/.svn/pristine/5e/5e0f209f6e9be1f84238e9cb97288fda3cb63dd8.svn-base @@ -0,0 +1,345 @@ +package xmlUtil + +import ( + "bytes" + "container/list" + "encoding/xml" + "errors" + "fmt" + "io" + "strings" +) + +// A NodeType is the type of a Node. +type NodeType uint + +const ( + // 文档对象节点(根节点) + DocumentNode NodeType = iota + + // 头不声明节点 + DeclarationNode + + // 元素节点 + ElementNode + + // 节点文本 + TextNode + + // 注释 + CommentNode +) + +// xml节点对象 +type Node struct { + Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node + + Type NodeType + NodeName string + Namespace string + Attr []xml.Attr + + level int // node level in the tree +} + +// InnerText returns the text between the start and end tags of the object. +func (n *Node) InnerText() string { + if n.Type == TextNode || n.Type == CommentNode { + return n.NodeName + } + + var buf bytes.Buffer + for child := n.FirstChild; child != nil; child = child.NextSibling { + // filt commentnode + if child.Type == CommentNode { + continue + } + + buf.WriteString(child.InnerText()) + } + + return buf.String() +} + +func outputXML(buf *bytes.Buffer, n *Node) { + if n.Type == TextNode || n.Type == CommentNode { + buf.WriteString(strings.TrimSpace(n.NodeName)) + return + } + buf.WriteString("<" + n.NodeName) + for _, attr := range n.Attr { + if attr.Name.Space != "" { + buf.WriteString(fmt.Sprintf(` %s:%s="%s"`, attr.Name.Space, attr.Name.Local, attr.Value)) + } else { + buf.WriteString(fmt.Sprintf(` %s="%s"`, attr.Name.Local, attr.Value)) + } + } + buf.WriteString(">") + for child := n.FirstChild; child != nil; child = child.NextSibling { + outputXML(buf, child) + } + buf.WriteString(fmt.Sprintf("", n.NodeName)) +} + +// OutputXML returns the text that including tags name. +func (n *Node) OutputXML() string { + var buf bytes.Buffer + outputXML(&buf, n) + return buf.String() +} + +// get all children +func (n *Node) Children() []*Node { + childrenList := make([]*Node, 0) + nowChild := n.FirstChild + for { + if nowChild == nil { + break + } + + childrenList = append(childrenList, nowChild) + if nowChild == n.LastChild { + break + } + + nowChild = nowChild.NextSibling + } + + return childrenList +} + +// get children len +func (n *Node) ChildrenLen() int { + var count int = 0 + nowChild := n.FirstChild + for { + if nowChild == nil { + break + } + + count += 1 + if nowChild == n.LastChild { + break + } + + nowChild = nowChild.NextSibling + } + + return count +} + +// get all attribute +func (n *Node) ALLAttribute() []xml.Attr { + if n.Attr == nil { + return nil + } + + return n.Attr[:] +} + +// 获取属性个数 +func (n *Node) AttributeLen() int { + if n.Attr == nil { + return 0 + } + + return len(n.Attr) +} + +// 输出所有(主要用于测试) +func (this *Node) OutALL() { + stack := list.New() + tmpItem := this + for { + if tmpItem != nil { + stack.PushBack(tmpItem) + tmpItem = tmpItem.NextSibling + } + + break + } + + for { + if stack.Len() <= 0 { + break + } + + nowNode := stack.Front().Value.(*Node) + stack.Remove(stack.Front()) + for _, item := range nowNode.Children() { + stack.PushFront(item) + } + + fmt.Println("name:", nowNode.NodeName, " level: ", nowNode.level, " attr:", nowNode.Attr) + } +} + +// SelectElements finds child elements with the specified name. +func (n *Node) SelectElements(name string) []*Node { + return Find(n, name) +} + +// SelectElements finds child elements with the specified name. +func (n *Node) SelectElement(name string) *Node { + return FindOne(n, name) +} + +// SelectAttr returns the attribute value with the specified name. +func (n *Node) SelectAttr(name string) (string, bool) { + var local, space string + local = name + if i := strings.Index(name, ":"); i > 0 { + space = name[:i] + local = name[i+1:] + } + for _, attr := range n.Attr { + if attr.Name.Local == local && attr.Name.Space == space { + return attr.Value, true + } + } + return "", false +} + +// 给节点添加属性值 +func addAttr(n *Node, key, val string) { + var attr xml.Attr + if i := strings.Index(key, ":"); i > 0 { + attr = xml.Attr{ + Name: xml.Name{Space: key[:i], Local: key[i+1:]}, + Value: val, + } + } else { + attr = xml.Attr{ + Name: xml.Name{Local: key}, + Value: val, + } + } + + n.Attr = append(n.Attr, attr) +} + +// 给节点添加子节点 +func addChild(parent, n *Node) { + n.Parent = parent + if parent.FirstChild == nil { + parent.FirstChild = n + } else { + parent.LastChild.NextSibling = n + n.PrevSibling = parent.LastChild + } + + parent.LastChild = n +} + +// 给节点添加兄弟节点 +func addSibling(sibling, n *Node) { + n.Parent = sibling.Parent + sibling.NextSibling = n + n.PrevSibling = sibling + if sibling.Parent != nil { + sibling.Parent.LastChild = n + } +} + +// 从reader里面加载xml文档 +func LoadFromReader(r io.Reader) (*Node, error) { + var ( + decoder = xml.NewDecoder(r) //// xml解码对象 + doc = &Node{Type: DocumentNode} + level = 0 + declared = false + ) + var prev *Node = doc + for { + tok, err := decoder.Token() + switch { + case err == io.EOF: + goto quit + case err != nil: + return nil, err + } + + switch tok := tok.(type) { + case xml.StartElement: + //if !declared { // if have no xml node,we also need add children + // return nil, errors.New("xml: document is invalid") + //} + // if there is no xml node.then create it + if declared == false { + level++ + + tmpNode := &Node{Type: DeclarationNode, level: level} + addAttr(tmpNode, "version", "1.0") + addAttr(tmpNode, "encoding", "UTF-8") + declared = true + if level == prev.level { + addSibling(prev, tmpNode) + } else if level > prev.level { + addChild(prev, tmpNode) + } + + prev = tmpNode + } + node := &Node{ + Type: ElementNode, + NodeName: tok.Name.Local, + Namespace: tok.Name.Space, + Attr: tok.Attr, + level: level, + } + //fmt.Println(fmt.Sprintf("start > %s : %d", node.Data, level)) + if level == prev.level { + addSibling(prev, node) + } else if level > prev.level { + addChild(prev, node) + } else if level < prev.level { + for i := prev.level - level; i > 1; i-- { + prev = prev.Parent + } + addSibling(prev.Parent, node) + } + prev = node + level++ + case xml.EndElement: + level-- + case xml.CharData: + node := &Node{Type: TextNode, NodeName: string(tok), level: level} + if level == prev.level { + addSibling(prev, node) + } else if level > prev.level { + addChild(prev, node) + } + case xml.Comment: + node := &Node{Type: CommentNode, NodeName: string(tok), level: level} + if level == prev.level { + addSibling(prev, node) + } else if level > prev.level { + addChild(prev, node) + } + case xml.ProcInst: // Processing Instruction + if declared || (!declared && tok.Target != "xml") { + return nil, errors.New("xml: document is invalid") + } + level++ + node := &Node{Type: DeclarationNode, level: level} + pairs := strings.Split(string(tok.Inst), " ") + for _, pair := range pairs { + pair = strings.TrimSpace(pair) + if i := strings.Index(pair, "="); i > 0 { + addAttr(node, pair[:i], strings.Trim(pair[i+1:], `"`)) + } + } + declared = true + if level == prev.level { + addSibling(prev, node) + } else if level > prev.level { + addChild(prev, node) + } + prev = node + case xml.Directive: + } + + } +quit: + return doc, nil +} diff --git a/.svn/pristine/5e/5e69ecefe93f6f0a7f5115c7b8607aed51ee86b3.svn-base b/.svn/pristine/5e/5e69ecefe93f6f0a7f5115c7b8607aed51ee86b3.svn-base new file mode 100644 index 0000000..f3af9dd Binary files /dev/null and b/.svn/pristine/5e/5e69ecefe93f6f0a7f5115c7b8607aed51ee86b3.svn-base differ diff --git a/.svn/pristine/5e/5eefdb2ff77b3c733abee24187f2c857e1575160.svn-base b/.svn/pristine/5e/5eefdb2ff77b3c733abee24187f2c857e1575160.svn-base new file mode 100644 index 0000000..ce4bd83 --- /dev/null +++ b/.svn/pristine/5e/5eefdb2ff77b3c733abee24187f2c857e1575160.svn-base @@ -0,0 +1,394 @@ +package baseUtil + +import ( + "testing" +) + +func TestNew(t *testing.T) { + elements := "" + _, err := New(elements) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + elements = "00" + _, err = New(elements) + if err == nil { + t.Errorf("There should be an error, but now there isn't.") + return + } + + elements = "01" + _, err = New(elements) + if err != nil { + t.Errorf("There should be no error, but now there is one:%v.", err) + return + } +} + +func TestNewBase2(t *testing.T) { + _, err := NewBase2() + if err != nil { + t.Errorf("There should be no error, but now there is one:%v.", err) + return + } +} + +func TestNewBase8(t *testing.T) { + _, err := NewBase8() + if err != nil { + t.Errorf("There should be no error, but now there is one:%v.", err) + return + } +} + +func TestNewBase16(t *testing.T) { + _, err := NewBase16() + if err != nil { + t.Errorf("There should be no error, but now there is one:%v.", err) + return + } +} + +func TestNewBase26(t *testing.T) { + _, err := NewBase26() + if err != nil { + t.Errorf("There should be no error, but now there is one:%v.", err) + return + } +} + +func TestNewBase36(t *testing.T) { + _, err := NewBase36() + if err != nil { + t.Errorf("There should be no error, but now there is one:%v.", err) + return + } +} + +func TestNewBase62(t *testing.T) { + _, err := NewBase62() + if err != nil { + t.Errorf("There should be no error, but now there is one:%v.", err) + return + } +} + +func TestTransform(t *testing.T) { + base2, _ := NewBase2() + base8, _ := NewBase8() + base16, _ := NewBase16() + base26, _ := NewBase26() + base36, _ := NewBase36() + base62, _ := NewBase62() + + var source uint64 = 0 + expected := "0" + got := base2.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "0" + got = base8.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "0" + got = base16.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "a" + got = base26.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "0" + got = base36.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "0" + got = base62.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + source = 1 + expected = "1" + got = base2.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "1" + got = base8.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "1" + got = base16.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "b" + got = base26.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "1" + got = base36.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "1" + got = base62.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + source = 2 + expected = "10" + got = base2.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "2" + got = base8.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "2" + got = base16.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "c" + got = base26.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "2" + got = base36.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "2" + got = base62.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + source = 100 + expected = "1100100" + got = base2.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "144" + got = base8.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "64" + got = base16.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "dw" + got = base26.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "2s" + got = base36.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } + + expected = "1C" + got = base62.Transform(source) + if got != expected { + t.Errorf("Expected to get %s, but got %s", expected, got) + return + } +} + +func TestParse(t *testing.T) { + base2, _ := NewBase2() + base8, _ := NewBase8() + base16, _ := NewBase16() + base26, _ := NewBase26() + base36, _ := NewBase36() + base62, _ := NewBase62() + + expected := uint64(0) + got := base2.Parse("0") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base8.Parse("0") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base16.Parse("0") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base26.Parse("a") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base36.Parse("0") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base62.Parse("0") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + + expected = uint64(1) + got = base2.Parse("1") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base8.Parse("1") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base16.Parse("1") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base26.Parse("b") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base36.Parse("1") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base62.Parse("1") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + + expected = uint64(2) + got = base2.Parse("10") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base8.Parse("2") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base16.Parse("2") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base26.Parse("c") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base36.Parse("2") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base62.Parse("2") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + + expected = uint64(100) + got = base2.Parse("1100100") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base8.Parse("144") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base16.Parse("64") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base26.Parse("dw") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base36.Parse("2s") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } + got = base62.Parse("1C") + if got != expected { + t.Errorf("Expected to get %d, but got %d", expected, got) + return + } +} diff --git a/.svn/pristine/5f/5f3c79403def080514a6099b44ebf7859d676dfa.svn-base b/.svn/pristine/5f/5f3c79403def080514a6099b44ebf7859d676dfa.svn-base new file mode 100644 index 0000000..5d5e3cc --- /dev/null +++ b/.svn/pristine/5f/5f3c79403def080514a6099b44ebf7859d676dfa.svn-base @@ -0,0 +1,25 @@ +package typeUtil + +// bool值转换为int +// value:待转换的值 +// 返回值: +// bool:转换结果 +func BoolToInt(value bool) int { + if value { + return 1 + } else { + return 0 + } +} + +// int转换为bool值 +// value:待转换的值 +// 返回值: +// bool:转换结果 +func IntToBool(value int) bool { + if value > 0 { + return true + } else { + return false + } +} diff --git a/.svn/pristine/60/6010f6e6b4ef4842fdf73cda2293b84c0a1a594e.svn-base b/.svn/pristine/60/6010f6e6b4ef4842fdf73cda2293b84c0a1a594e.svn-base new file mode 100644 index 0000000..b77f21d --- /dev/null +++ b/.svn/pristine/60/6010f6e6b4ef4842fdf73cda2293b84c0a1a594e.svn-base @@ -0,0 +1,89 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4 h1:OoL469zqSNrTLSz5zeVF/I6VOO7fiw2bzSzQe4J557c= +github.com/elastic/go-elasticsearch/v8 v8.0.0-20210916085751-c2fb55d91ba4/go.mod h1:xe9a/L2aeOgFKKgrO3ibQTnMdpAeL0GC+5/HpGScSa4= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws= +github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= +github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= +github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/.svn/pristine/60/60e222efc80001d9b4fd6ad73d8acf97f1791a12.svn-base b/.svn/pristine/60/60e222efc80001d9b4fd6ad73d8acf97f1791a12.svn-base new file mode 100644 index 0000000..51cfd01 --- /dev/null +++ b/.svn/pristine/60/60e222efc80001d9b4fd6ad73d8acf97f1791a12.svn-base @@ -0,0 +1,40 @@ +package sqlAsyncMgr + +import ( + "sync" +) + +// 标识内容模型对象 +type StatisticModel struct { + // 锁对象 + m sync.Mutex + + // 标识 + IdentityId string + + // 待同步的数量 + Count int32 +} + +// AddCount 添加指定数量 +func (this *StatisticModel) AddCount(addcount int32) { + this.m.Lock() + defer this.m.Unlock() + + this.Count = this.Count + addcount +} + +// ReduceCount 添加指定数量 +func (this *StatisticModel) ReduceCount(recount int32) { + this.m.Lock() + defer this.m.Unlock() + + this.Count = this.Count - recount +} + +// newStatisticModel 创建新StatisticModel对象 +func newStatisticModel(ident string) *StatisticModel { + return &StatisticModel{ + IdentityId: ident, + } +} diff --git a/.svn/pristine/61/618fd6a64917cdc9be9a1c4e95d8be9514c251bc.svn-base b/.svn/pristine/61/618fd6a64917cdc9be9a1c4e95d8be9514c251bc.svn-base new file mode 100644 index 0000000..6f91617 --- /dev/null +++ b/.svn/pristine/61/618fd6a64917cdc9be9a1c4e95d8be9514c251bc.svn-base @@ -0,0 +1,28 @@ +package model + +// CommonResponse 公共请求结果对象 +type CommonResponse struct { + // 错误码 + Code ResultStatus `json:"code"` + + // 错误提示信息 + Message string `json:"message"` + + // 服务器生成的请求Id + RequestId string `json:"requestId"` +} + +// IsSuccess 请求结果是否成功 +func (this *CommonResponse) IsSuccess() bool { + return this.Code == Success +} + +// IsFailure 请求结果是否失败 +func (this *CommonResponse) IsFailure() bool { + return this.Code != Success +} + +// HasMessage 请求结果是否有信息 +func (this *CommonResponse) HaveNoMessage() bool { + return this.Code == NoMessage +} diff --git a/.svn/pristine/62/62cd714157ac917a85023be10ae67e3cb858fc36.svn-base b/.svn/pristine/62/62cd714157ac917a85023be10ae67e3cb858fc36.svn-base new file mode 100644 index 0000000..e60cbe6 --- /dev/null +++ b/.svn/pristine/62/62cd714157ac917a85023be10ae67e3cb858fc36.svn-base @@ -0,0 +1,84 @@ +// ************************************ +// @package: websocketServer +// @description: websocket加密服务端 +// @author: +// @revision history: +// @create date: 2022-02-15 16:18:45 +// ************************************ +package websocketServer + +import ( + "github.com/gorilla/websocket" + webServer "Framework/webServer" +) + +type WssServer struct { + *webServer.HttpsServer + + // websocket连接管理 + *connManager +} + +// RegisterWebsocketHandler +// @description: 注册websocket回调 +// parameter: +// +// @receiver ws: +// @path:注册的访问路径 +// @handlerFuncObj:回调方法 +// @configObj:Handler配置对象 +// +// return: +func (wss *WssServer) RegisterWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) { + wss.RegisterHandlerWithUserData(path, hookHandler, configObj, &userDatas{ + server: wss, + eventCallback: eventCallback, + }) +} + +// RegisterRegexWebsocketHandler +// @description: 注册正则websocket回调 +// parameter: +// +// @receiver wss: +// @path:注册的正则访问路径 +// @eventCallback:回调方法 +// @configObj:Handler配置对象 +// +// return: +func (wss *WssServer) RegisterRegexWebsocketHandler(path string, eventCallback *EventCallbackFuncs, configObj *webServer.HandlerConfig) { + wss.RegisterRegexHandlerWithUserData(path, hookHandler, configObj, &userDatas{ + server: wss, + eventCallback: eventCallback, + }) +} + +func NewWssServer(addr, certFileName, keyFileName string, isCheckIP bool) (server *WssServer) { + server = &WssServer{ + HttpsServer: webServer.NewHttpsServer(addr, certFileName, keyFileName, isCheckIP), + connManager: &connManager{ + upgrader: &websocket.Upgrader{}, + allConns: make(map[*websocket.Conn]*Context), + }, + } + + // 开启心跳检测协程 + server.connManager.heartbeatDetect() + + return +} + +func NewHttpsServer2(addr, certFileName, keyFileName string, webServerObj webServer.IWebServer) (server *WssServer) { + server = &WssServer{ + HttpsServer: webServer.NewHttpsServer2(addr, certFileName, keyFileName, webServerObj), + connManager: &connManager{ + upgrader: &websocket.Upgrader{}, + allConns: make(map[*websocket.Conn]*Context), + }, + } + + // 开启心跳检测协程 + server.connManager.heartbeatDetect() + + return +} diff --git a/.svn/pristine/63/63b5eeb5c16e41033bcb6a62a5b8f4381c1269d3.svn-base b/.svn/pristine/63/63b5eeb5c16e41033bcb6a62a5b8f4381c1269d3.svn-base new file mode 100644 index 0000000..7ec6fc4 --- /dev/null +++ b/.svn/pristine/63/63b5eeb5c16e41033bcb6a62a5b8f4381c1269d3.svn-base @@ -0,0 +1,10 @@ +package managecenterModel + +// 白名单列表对象 +type WhiteList struct { + // 合作商Id + PartnerId int32 `json:"PartnerId"` + + // 用户Id + UserId string `json:"UserId"` +} diff --git a/.svn/pristine/64/647fb4a8049def9bef1529c3cee8e41064f42398.svn-base b/.svn/pristine/64/647fb4a8049def9bef1529c3cee8e41064f42398.svn-base new file mode 100644 index 0000000..f9b78ef --- /dev/null +++ b/.svn/pristine/64/647fb4a8049def9bef1529c3cee8e41064f42398.svn-base @@ -0,0 +1,16 @@ +package qcloud + +// 发送短信请求结构 +type smsData struct { + // 公共字段 + *commonField + + // 短信字段 + // 根据类型,对其中一个结构的字段进行赋值 + *msgSmsField + *tmplSmsField +} + +func newSmsData(common *commonField, msg *msgSmsField, tmpl *tmplSmsField) *smsData { + return &smsData{common, msg, tmpl} +} diff --git a/.svn/pristine/64/64c8d30cc5e3ebe389ecf298872d498c1627b692.svn-base b/.svn/pristine/64/64c8d30cc5e3ebe389ecf298872d498c1627b692.svn-base new file mode 100644 index 0000000..79dfc1a --- /dev/null +++ b/.svn/pristine/64/64c8d30cc5e3ebe389ecf298872d498c1627b692.svn-base @@ -0,0 +1,431 @@ +package webServer + +import ( + config "common/configsYaml" + "common/resultStatus" + "goutil/logUtilPlus" + "reflect" + "strconv" + "strings" +) + +const ( + // 供客户端访问的模块的后缀 + con_ModuleSuffix = "Module" + + // 定义用于分隔模块名称和方法名称的分隔符 + con_DelimeterOfObjAndMethod = "_" +) + +var ( + // 定义存放所有方法映射的变量 + methodMap = make(map[string]*methodAndInOutTypes) + + // 函数返回值类型 + responseType reflect.Type = reflect.TypeOf(new(ResponseObject)) +) + +// getStructName +// +// @description: 获取结构体类型的名称 +// +// parameter: +// +// @structType: 结构体类型 +// +// return: +// +// @string: 结构体类型的名称 +func getStructName(structType reflect.Type) string { + reflectTypeStr := structType.String() + reflectTypeArr := strings.Split(reflectTypeStr, ".") + + return reflectTypeArr[len(reflectTypeArr)-1] +} + +// getFullModuleName +// +// @description: 获取完整的模块名称 +// +// parameter: +// +// @moduleName: 模块名称 +// +// return: +// +// @string: 完整的模块名称 +func getFullModuleName(moduleName string) string { + return moduleName + con_ModuleSuffix +} + +// getFullMethodName +// +// @description: 获取完整的方法名称 +// +// parameter: +// +// @structName: 结构体名称 +// @methodName: 方法名称 +// +// return: +// +// @string: 完整的方法名称 +func getFullMethodName(structName, methodName string) string { + return structName + con_DelimeterOfObjAndMethod + methodName +} + +// resolveMethodInOutParams +// +// @description: 解析方法的输入输出参数 +// +// parameter: +// +// @method: 方法对应的反射值 +// +// return: +// +// @inTypes: 输入参数类型集合 +// @outTypes: 输出参数类型集合 +func resolveMethodInOutParams(method reflect.Value) (inTypes []reflect.Type, outTypes []reflect.Type) { + methodType := method.Type() + for i := 0; i < methodType.NumIn(); i++ { + inTypes = append(inTypes, methodType.In(i)) + } + + for i := 0; i < methodType.NumOut(); i++ { + outTypes = append(outTypes, methodType.Out(i)) + } + + return +} + +// RegisterFunction +// +// @description: 将需要对客户端提供方法的对象进行注册 +// +// parameter: +// +// @structObject: 对象 +// +// return: +func RegisterFunction(structObject interface{}) { + // 获取structObject对应的反射 Type 和 Value + reflectValue := reflect.ValueOf(structObject) + reflectType := reflect.TypeOf(structObject) + + // 提取对象类型名称 + structName := getStructName(reflectType) + + // 获取structObject中返回值为responseObject的方法 + for i := 0; i < reflectType.NumMethod(); i++ { + // 获得方法名称 + methodName := reflectType.Method(i).Name + + // 获得方法及其输入参数的类型列表 + method := reflectValue.MethodByName(methodName) + inTypes, outTypes := resolveMethodInOutParams(method) + + // 判断输出参数数量是否正确 + if len(outTypes) != 1 { + continue + } + + // 判断返回值是否为responseObject + if outTypes[0] != responseType { + continue + } + + // 添加到列表中 + methodMap[getFullMethodName(structName, methodName)] = newmethodAndInOutTypes(method, inTypes, outTypes) + } +} + +// CallFunction +// +// @description: 调用方法 +// +// parameter: +// +// @requestObj: 客户端对象 +// +// return: +// +// @responseObj: 请求对象 +func CallFunction(requestObj *RequestObject) (responseObj *ResponseObject) { + responseObj = GetInitResponseObj() + + var methodAndInOutTypes *methodAndInOutTypes + var ok bool + + // 根据传入的ModuleName和MethodName找到对应的方法对象 + key := getFullMethodName(requestObj.ModuleName, requestObj.MethodName) + if methodAndInOutTypes, ok = methodMap[key]; !ok { + logUtilPlus.ErrorLog("找不到指定的方法:%s", key) + responseObj.SetResultStatus(resultStatus.NotSpecificMethod) + return + } + + // 判断参数数量是否相同 + inTypesLength := len(methodAndInOutTypes.InTypes) + paramLength := len(requestObj.Parameters) + if paramLength != inTypesLength { + logUtilPlus.ErrorLog("传入的参数数量不符,本地方法%s的参数数量:%d,传入的参数数量为:%d", key, inTypesLength, paramLength) + responseObj.SetResultStatus(resultStatus.ParamNotMatch) + return + } + + // 构造参数 + in := make([]reflect.Value, inTypesLength) + for i := 0; i < inTypesLength; i++ { + inTypeItem := methodAndInOutTypes.InTypes[i] + paramItem := requestObj.Parameters[i] + + // 已支持类型:Client,Player(非基本类型) + // 已支持类型:Bool,Int,Int8,Int16,Int32,Int64,Uint,Uint8,Uint16,Uint32,Uint64,Float32,Float64,String + // 已支持类型:以及上面所列出类型的Slice类型 + // 未支持类型:Uintptr,Complex64,Complex128,Array,Chan,Func,Interface,Map,Ptr,Struct,UnsafePointer + // 由于byte与int8同义,rune与int32同义,所以并不需要单独处理 + // 枚举参数的类型,并进行类型转换 + switch inTypeItem.Kind() { + case reflect.Bool: + if paramBool, ok := paramItem.(bool); ok { + in[i] = reflect.ValueOf(paramBool) + } + case reflect.Int: + if paramInt, ok := paramItem.(int); ok { + in[i] = reflect.ValueOf(int(paramInt)) + } + case reflect.Int8: + if paramInt8, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(int8(paramInt8)) + } + case reflect.Int16: + if paramInt16, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(int16(paramInt16)) + } + case reflect.Int32: + if paramInt32, ok := paramItem.(int32); ok { + in[i] = reflect.ValueOf(paramInt32) + } else if paramFloat64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(int32(paramFloat64)) + } + case reflect.Int64: + if paramInt64, ok := paramItem.(int64); ok { + in[i] = reflect.ValueOf(paramInt64) + } else if paramUint64, ok := paramItem.(uint64); ok { + in[i] = reflect.ValueOf(int64(paramUint64)) + } else if paramString, ok := paramItem.(string); ok { + + i64, err := strconv.ParseInt(paramString, 10, 64) + if err == nil { + in[i] = reflect.ValueOf(i64) + } + } else if paramFloat64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(int64(paramFloat64)) + } + case reflect.Uint: + if paramUint, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(uint(paramUint)) + } + case reflect.Uint8: + if paramUint8, ok := paramItem.(uint8); ok { + in[i] = reflect.ValueOf(uint8(paramUint8)) + } + case reflect.Uint16: + if paramUint16, ok := paramItem.(uint16); ok { + in[i] = reflect.ValueOf(uint16(paramUint16)) + } + case reflect.Uint32: + if paramUint32, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(uint32(paramUint32)) + } + case reflect.Uint64: + if paramUint64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(uint64(paramUint64)) + } + case reflect.Float32: + if paramFloat32, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(float32(paramFloat32)) + } + case reflect.Float64: + if paramFloat64, ok := paramItem.(float64); ok { + in[i] = reflect.ValueOf(paramFloat64) + } + case reflect.String: + if paramString, ok := paramItem.(string); ok { + in[i] = reflect.ValueOf(paramString) + } + case reflect.Slice: + // 如果是Slice类型,则需要对其中的项再次进行类型判断及类型转换 + if param_interface, ok := paramItem.([]interface{}); ok { + switch inTypeItem.String() { + case "[]bool": + params_inner := make([]bool, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_bool, ok := param_interface[i].(bool); ok { + params_inner[i] = param_bool + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int": + params_inner := make([]int, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(int); ok { + params_inner[i] = int(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int8": + params_inner := make([]int8, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(float64); ok { + params_inner[i] = int8(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int16": + params_inner := make([]int16, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(float64); ok { + params_inner[i] = int16(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int32": + params_inner := make([]int32, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + param_float64, ok := param_interface[i].(int32) + if ok { + params_inner[i] = int32(param_float64) + continue + } else { + param_int16, right := param_interface[i].(uint16) + if right == true { + params_inner[i] = int32(param_int16) + } + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]int64": + params_inner := make([]int64, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(int64); ok { + params_inner[i] = int64(param_float64) + } else if param_uint64, ok := param_interface[i].(uint64); ok { + params_inner[i] = int64(param_uint64) + } else if param_string, ok := param_interface[i].(string); ok { + + i64, err := strconv.ParseInt(param_string, 10, 64) + + if err == nil { + params_inner[i] = i64 + } + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]uint": + params_inner := make([]uint, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(uint); ok { + params_inner[i] = uint(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + // case "[]uint8": 特殊处理 + case "[]uint16": + params_inner := make([]uint16, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(uint16); ok { + params_inner[i] = uint16(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]uint32": + params_inner := make([]uint32, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(uint32); ok { + params_inner[i] = uint32(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]uint64": + params_inner := make([]uint64, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(uint64); ok { + params_inner[i] = uint64(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]float32": + params_inner := make([]float32, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(float64); ok { + params_inner[i] = float32(param_float64) + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]float64": + params_inner := make([]float64, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_float64, ok := param_interface[i].(float64); ok { + params_inner[i] = param_float64 + } + } + in[i] = reflect.ValueOf(params_inner) + case "[]string": + params_inner := make([]string, len(param_interface), len(param_interface)) + for i := 0; i < len(param_interface); i++ { + if param_string, ok := param_interface[i].(string); ok { + params_inner[i] = param_string + } + } + in[i] = reflect.ValueOf(params_inner) + } + } else if inTypeItem.String() == "[]uint8" { // 由于[]uint8在传输过程中会被转化成字符串,所以单独处理; + if param_string, ok := paramItem.(string); ok { + param_uint8 := ([]uint8)(param_string) + in[i] = reflect.ValueOf(param_uint8) + } + } + } + } + + // 判断是否有无效的参数(传入的参数类型和方法定义的类型不匹配导致没有赋值) + for _, item := range in { + if reflect.Value.IsValid(item) == false { + logUtilPlus.ErrorLog("type:%v,value:%v.方法%s传入的参数%v无效", reflect.TypeOf(item), reflect.ValueOf(item), key, requestObj.Parameters) + responseObj.SetResultStatus(resultStatus.ParamInValid) + return + } + } + + // 传入参数,调用方法 + if config.DEBUG { + if requestObj.MethodName != "GetRefreshData" { + logUtilPlus.DebugLog("Begin Call Func:module:%v, method:%v,inParams:%v\n\n", requestObj.ModuleName, requestObj.MethodName, in) + } + } + + out := methodAndInOutTypes.Method.Call(in) + + if config.DEBUG { + if requestObj.MethodName != "GetRefreshData" { + for i, v := range in { + logUtilPlus.DebugLog("\nparams %v,%v\n", i, v) + } + } + } + + // 并输出结果到客户端(由于只有一个返回值,所以取out[0]) + if responseObj, ok = (&out[0]).Interface().(*ResponseObject); !ok { + logUtilPlus.ErrorLog("返回值类型推断为ResponseObject 出错, tyep is :%v", reflect.TypeOf(out[0])) + responseObj.SetResultStatus(resultStatus.ParamInValid) + return + } + if config.DEBUG { + if requestObj.MethodName != "GetRefreshData" { + logUtilPlus.DebugLog("返回数据:code:%v, data:%v, mess:%v\n\n", responseObj.Code, responseObj.Value, responseObj.Message) + } + } + return +} diff --git a/.svn/pristine/65/652413db7a8b435762332e2dca283ce69d621742.svn-base b/.svn/pristine/65/652413db7a8b435762332e2dca283ce69d621742.svn-base new file mode 100644 index 0000000..aadb398 --- /dev/null +++ b/.svn/pristine/65/652413db7a8b435762332e2dca283ce69d621742.svn-base @@ -0,0 +1,33 @@ +/* +由于Go不提供超时锁,所以自己实现了支持超时机制的互斥锁Locker和读写锁RWLocker。 +为了方便供第三方程序使用,提供了根据Key获取超时互斥锁和超时读写锁的复合对象LockerUtil和RWLockerUtil。 +为了在出现锁超时时方便查找问题,会记录上次成功获得锁时的堆栈信息;并且在本次获取锁失败时,同时返回上次成功时的堆栈信息和本次的堆栈信息。 +*/ +package syncUtil + +const ( + // 默认超时的毫秒数(1小时) + con_Default_Timeout_Milliseconds = 60 * 60 * 1000 + + // 写锁保护时间(纳秒) + con_Write_Protect_Nanoseconds = 5 * 1000 * 1000 +) + +var ( + // 是否记录堆栈信息的状态 + if_record_stack_info = false +) + +// 获取超时时间 +func getTimeout(timeout int) int { + if timeout > 0 { + return timeout + } else { + return con_Default_Timeout_Milliseconds + } +} + +// 设置是否记录堆栈信息的状态 +func SetIfRecordStackInfo(value bool) { + if_record_stack_info = value +} diff --git a/.svn/pristine/65/65e92da884776f00b5f5b2567d61c4e002873e42.svn-base b/.svn/pristine/65/65e92da884776f00b5f5b2567d61c4e002873e42.svn-base new file mode 100644 index 0000000..d46d9e0 --- /dev/null +++ b/.svn/pristine/65/65e92da884776f00b5f5b2567d61c4e002873e42.svn-base @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +