Merge branch 'develop'
This commit is contained in:
commit
9e93a64449
|
@ -18,4 +18,4 @@ jobs:
|
|||
bump-minor-pre-major: true
|
||||
bump-patch-for-minor-pre-major: true
|
||||
changelog-types: '[{"type":"other","section":"Other | 其他更改","hidden":false},{"type":"revert","section":"Reverts | 回退","hidden":false},{"type":"feat","section":"Features | 新特性","hidden":false},{"type":"fix","section":"Bug Fixes | 修复","hidden":false},{"type":"improvement","section":"Feature Improvements | 改进","hidden":false},{"type":"docs","section":"Docs | 文档优化","hidden":false},{"type":"style","section":"Styling | 可读性优化","hidden":false},{"type":"refactor","section":"Code Refactoring | 重构","hidden":false},{"type":"perf","section":"Performance Improvements | 性能优化","hidden":false},{"type":"test","section":"Tests | 新增或优化测试用例","hidden":false},{"type":"build","section":"Build System | 影响构建的修改","hidden":false},{"type":"ci","section":"CI | 更改我们的 CI 配置文件和脚本","hidden":false}]'
|
||||
release-as: 0.5.0
|
||||
# release-as: 0.5.0
|
40
README.md
40
README.md
|
@ -187,46 +187,6 @@ func main() {
|
|||
```
|
||||
在分布式环境中,如果存在类似于多服务器需要同时间刷新配置时,可使用`Cron`表达式设置定时任务。
|
||||
|
||||
### 流操作
|
||||
可以通过 `stream` 包快速开启对`切片`和`map`的流式操作,例如:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/utils/stream"
|
||||
"github.com/kercylan98/minotaur/utils/streams"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := stream.WithSlice([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}).
|
||||
Copy().
|
||||
Shuffle().
|
||||
Filter(true, func(index int, item int) bool {
|
||||
return item%2 == 0
|
||||
}).
|
||||
Zoom(20).
|
||||
Each(true, func(index int, item int) bool {
|
||||
t.Log(index, item)
|
||||
return false
|
||||
}).
|
||||
Chunk(3).
|
||||
EachT(func(index int, item stream.Slice[int]) bool {
|
||||
t.Log(item)
|
||||
return false
|
||||
}).
|
||||
Merge().
|
||||
FillBy(func(index int, value int) int {
|
||||
if value == 0 {
|
||||
return 999
|
||||
}
|
||||
return value
|
||||
})
|
||||
|
||||
fmt.Println(s)
|
||||
}
|
||||
```
|
||||
|
||||
### 基于`xlsx`文件的配置导出工具
|
||||
该导出器的`xlsx`文件配置使用`JSON`语法进行复杂类型配置,具体可参考图例
|
||||
- **[`planner/pce/exporter`](planner/pce/exporter)** 是实现了基于`xlsx`文件的配置导出工具,可直接编译成可执行文件使用;
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
# Configuration
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
configuration 基于配置导表功能实现的配置加载及刷新功能
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[Init](#Init)|配置初始化
|
||||
|[Load](#Load)|加载配置
|
||||
|[Refresh](#Refresh)|刷新配置
|
||||
|[WithTickerLoad](#WithTickerLoad)|通过定时器加载配置
|
||||
|[StopTickerLoad](#StopTickerLoad)|停止通过定时器加载配置
|
||||
|[RegConfigRefreshEvent](#RegConfigRefreshEvent)|当配置刷新时将立即执行被注册的事件处理函数
|
||||
|[OnConfigRefreshEvent](#OnConfigRefreshEvent)|暂无描述...
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[RefreshEventHandle](#refresheventhandle)|配置刷新事件处理函数
|
||||
|`INTERFACE`|[Loader](#loader)|配置加载器
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func Init(loader ...Loader)
|
||||
<span id="Init"></span>
|
||||
> 配置初始化
|
||||
> - 在初始化后会立即加载配置
|
||||
|
||||
***
|
||||
#### func Load()
|
||||
<span id="Load"></span>
|
||||
> 加载配置
|
||||
> - 加载后并不会刷新线上配置,需要执行 Refresh 函数对线上配置进行刷新
|
||||
|
||||
***
|
||||
#### func Refresh()
|
||||
<span id="Refresh"></span>
|
||||
> 刷新配置
|
||||
|
||||
***
|
||||
#### func WithTickerLoad(ticker *timer.Ticker, interval time.Duration)
|
||||
<span id="WithTickerLoad"></span>
|
||||
> 通过定时器加载配置
|
||||
> - 通过定时器加载配置后,会自动刷新线上配置
|
||||
> - 调用该函数后不会立即刷新,而是在 interval 后加载并刷新一次配置,之后每隔 interval 加载并刷新一次配置
|
||||
|
||||
***
|
||||
#### func StopTickerLoad()
|
||||
<span id="StopTickerLoad"></span>
|
||||
> 停止通过定时器加载配置
|
||||
|
||||
***
|
||||
#### func RegConfigRefreshEvent(handle RefreshEventHandle)
|
||||
<span id="RegConfigRefreshEvent"></span>
|
||||
> 当配置刷新时将立即执行被注册的事件处理函数
|
||||
|
||||
***
|
||||
#### func OnConfigRefreshEvent()
|
||||
<span id="OnConfigRefreshEvent"></span>
|
||||
|
||||
***
|
||||
### RefreshEventHandle `STRUCT`
|
||||
配置刷新事件处理函数
|
||||
```go
|
||||
type RefreshEventHandle func()
|
||||
```
|
||||
### Loader `INTERFACE`
|
||||
配置加载器
|
||||
```go
|
||||
type Loader interface {
|
||||
Load()
|
||||
Refresh()
|
||||
}
|
||||
```
|
|
@ -0,0 +1,15 @@
|
|||
# Main
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,15 @@
|
|||
# Main
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,15 @@
|
|||
# Main
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,15 @@
|
|||
# Main
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,15 @@
|
|||
# Main
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -1,38 +1,13 @@
|
|||
# Game
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/game)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
Game 包提供了游戏领域中常见的功能实现,例如活动、任务、战斗、房间等实现。
|
||||
开发者可以使用它来快速构建游戏中的常见功能,例如游戏活动、任务系统、多人房间等。
|
||||
game 目录下包含了各类通用的游戏玩法性内容,其中该目录主要为基础性内容,具体目录将对应不同的游戏功能性内容。
|
||||
|
||||
> 目前还在考虑逐步将该包移除,未来项目结构可能会进行调整
|
||||
|
||||
## package activity [`活动`](./activity)
|
||||
提供了通用的活动设计,开发者可以使用它来设计和实现游戏中的活动机制。活动是游戏中重要的激励和玩法设计元素,它可以是一次性的,也可以是周期性的。活动系统框架将包括活动的创建、开启、关闭、奖励等功能,开发者可以根据游戏类型和风格,定制不同类型的活动,并设定相应的奖励机制,以增加游戏的可玩性和挑战性。
|
||||
|
||||
活动整体的配置将通过可选项的方式进行配置。
|
||||
</details>
|
||||
|
||||
> 在 `activity` 包中提供了以下 6 种事件:
|
||||
> - 即将开始的活动事件
|
||||
> - 活动开始事件
|
||||
> - 活动结束事件
|
||||
> - 活动结束后延长展示开始事件
|
||||
> - 活动结束后延长展示结束事件
|
||||
> - 新的一天事件
|
||||
|
||||
## package fight [`战斗`](./fight)
|
||||
在 `fight` 中目前仅提供了回合制[`TurnBased`](./fight/turn_based.go)的实现。
|
||||
- [`TurnBased`](./fight/turn_based.go) 仅提供了回合制的基本实现,开发者可以根据自己的需求进行扩展。其中包括:回合切换、回合开始、回合结束、回合超时、根据速度调节下次行动间隔。
|
||||
|
||||
## package space [`空间`](./space)
|
||||
计划提供游戏中常见的空间设计,例如房间、地图等。开发者可以使用它来快速构建游戏中的常见空间,例如多人房间、地图等。
|
||||
> 目前仅提供了房间的基本实现
|
||||
|
||||
- [`Room`](./space/room_manager.go) 提供了房间的基本实现,开发者可以根据自己的需求进行扩展。
|
||||
- 房间通过 [`RoomManager`](./space/room_manager.go) 进行管理,由 [`RoomController`](./space/room_controller.go) 进行控制;
|
||||
- 实现了加入、退出、事件、查询、销毁、座位、带顺序座位号、密码、人数上限等常用的基础功能。
|
||||
|
||||
## package task [`任务`](./task)
|
||||
提供了通用的任务设计,开发者可以使用它来设计和实现游戏中的任务机制。任务是游戏中重要的激励和玩法设计元素,它可以是一次性的,也可以是周期性的。任务系统框架将包括任务的创建、开启、关闭、奖励等功能,开发者可以根据游戏类型和风格,定制不同类型的任务,并设定相应的奖励机制,以增加游戏的可玩性和挑战性。
|
||||
|
||||
> 该包仅实现了任务基本状态的管理,例如任务类型、分配、事件、状态变化等,开发者可以根据自己的需求进行扩展。
|
||||
***
|
||||
|
|
|
@ -1,12 +1,294 @@
|
|||
# Activity
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/game/activity)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
`activity` 是为不同类型的活动提供灵活的状态管理实现,支持活动的预告、开始、结束、延长展示等状态。
|
||||
activity 活动状态管理
|
||||
|
||||
## 设计思路
|
||||
- 为不同类型的活动提供灵活的状态管理框架,支持活动的预告、开始、结束、延长展示等状态。
|
||||
- 支持事件驱动,根据活动状态变化和时间触发事件。
|
||||
- 允许活动循环,并支持配置延长展示时间。
|
||||
- 在多线程环境下使用互斥锁进行同步。
|
||||
- 使用反射处理不同类型的活动数据。
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[SetTicker](#SetTicker)|设置自定义定时器,该方法必须在使用活动系统前调用,且只能调用一次
|
||||
|[LoadGlobalData](#LoadGlobalData)|加载所有活动全局数据
|
||||
|[LoadEntityData](#LoadEntityData)|加载所有活动实体数据
|
||||
|[LoadOrRefreshActivity](#LoadOrRefreshActivity)|加载或刷新活动
|
||||
|[DefineNoneDataActivity](#DefineNoneDataActivity)|声明无数据的活动类型
|
||||
|[DefineGlobalDataActivity](#DefineGlobalDataActivity)|声明拥有全局数据的活动类型
|
||||
|[DefineEntityDataActivity](#DefineEntityDataActivity)|声明拥有实体数据的活动类型
|
||||
|[DefineGlobalAndEntityDataActivity](#DefineGlobalAndEntityDataActivity)|声明拥有全局数据和实体数据的活动类型
|
||||
|[RegUpcomingEvent](#RegUpcomingEvent)|注册即将开始的活动事件处理器
|
||||
|[OnUpcomingEvent](#OnUpcomingEvent)|即将开始的活动事件
|
||||
|[RegStartedEvent](#RegStartedEvent)|注册活动开始事件处理器
|
||||
|[OnStartedEvent](#OnStartedEvent)|活动开始事件
|
||||
|[RegEndedEvent](#RegEndedEvent)|注册活动结束事件处理器
|
||||
|[OnEndedEvent](#OnEndedEvent)|活动结束事件
|
||||
|[RegExtendedShowStartedEvent](#RegExtendedShowStartedEvent)|注册活动结束后延长展示开始事件处理器
|
||||
|[OnExtendedShowStartedEvent](#OnExtendedShowStartedEvent)|活动结束后延长展示开始事件
|
||||
|[RegExtendedShowEndedEvent](#RegExtendedShowEndedEvent)|注册活动结束后延长展示结束事件处理器
|
||||
|[OnExtendedShowEndedEvent](#OnExtendedShowEndedEvent)|活动结束后延长展示结束事件
|
||||
|[RegNewDayEvent](#RegNewDayEvent)|注册新的一天事件处理器
|
||||
|[OnNewDayEvent](#OnNewDayEvent)|新的一天事件
|
||||
|[NewOptions](#NewOptions)|创建活动选项
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Activity](#activity)|活动描述
|
||||
|`STRUCT`|[Controller](#controller)|活动控制器
|
||||
|`INTERFACE`|[BasicActivityController](#basicactivitycontroller)|暂无描述...
|
||||
|`INTERFACE`|[NoneDataActivityController](#nonedataactivitycontroller)|无数据活动控制器
|
||||
|`INTERFACE`|[GlobalDataActivityController](#globaldataactivitycontroller)|全局数据活动控制器
|
||||
|`INTERFACE`|[EntityDataActivityController](#entitydataactivitycontroller)|实体数据活动控制器
|
||||
|`INTERFACE`|[GlobalAndEntityDataActivityController](#globalandentitydataactivitycontroller)|全局数据和实体数据活动控制器
|
||||
|`STRUCT`|[DataMeta](#datameta)|全局活动数据
|
||||
|`STRUCT`|[EntityDataMeta](#entitydatameta)|活动实体数据
|
||||
|`STRUCT`|[UpcomingEventHandler](#upcomingeventhandler)|暂无描述...
|
||||
|`STRUCT`|[Options](#options)|活动选项
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func SetTicker(size int, options ...timer.Option)
|
||||
<span id="SetTicker"></span>
|
||||
> 设置自定义定时器,该方法必须在使用活动系统前调用,且只能调用一次
|
||||
|
||||
***
|
||||
#### func LoadGlobalData(handler func (activityType any))
|
||||
<span id="LoadGlobalData"></span>
|
||||
> 加载所有活动全局数据
|
||||
|
||||
***
|
||||
#### func LoadEntityData(handler func (activityType any))
|
||||
<span id="LoadEntityData"></span>
|
||||
> 加载所有活动实体数据
|
||||
|
||||
***
|
||||
#### func LoadOrRefreshActivity(activityType Type, activityId ID, options ...*Options) error
|
||||
<span id="LoadOrRefreshActivity"></span>
|
||||
> 加载或刷新活动
|
||||
> - 通常在活动配置刷新时候将活动通过该方法注册或刷新
|
||||
|
||||
***
|
||||
#### func DefineNoneDataActivity(activityType Type) NoneDataActivityController[Type, ID, *none, none, *none]
|
||||
<span id="DefineNoneDataActivity"></span>
|
||||
> 声明无数据的活动类型
|
||||
|
||||
***
|
||||
#### func DefineGlobalDataActivity(activityType Type) GlobalDataActivityController[Type, ID, Data, none, *none]
|
||||
<span id="DefineGlobalDataActivity"></span>
|
||||
> 声明拥有全局数据的活动类型
|
||||
|
||||
***
|
||||
#### func DefineEntityDataActivity(activityType Type) EntityDataActivityController[Type, ID, *none, EntityID, EntityData]
|
||||
<span id="DefineEntityDataActivity"></span>
|
||||
> 声明拥有实体数据的活动类型
|
||||
|
||||
***
|
||||
#### func DefineGlobalAndEntityDataActivity(activityType Type) GlobalAndEntityDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
<span id="DefineGlobalAndEntityDataActivity"></span>
|
||||
> 声明拥有全局数据和实体数据的活动类型
|
||||
|
||||
***
|
||||
#### func RegUpcomingEvent(activityType Type, handler UpcomingEventHandler[ID], priority ...int)
|
||||
<span id="RegUpcomingEvent"></span>
|
||||
> 注册即将开始的活动事件处理器
|
||||
|
||||
***
|
||||
#### func OnUpcomingEvent(activity *Activity[Type, ID])
|
||||
<span id="OnUpcomingEvent"></span>
|
||||
> 即将开始的活动事件
|
||||
|
||||
***
|
||||
#### func RegStartedEvent(activityType Type, handler StartedEventHandler[ID], priority ...int)
|
||||
<span id="RegStartedEvent"></span>
|
||||
> 注册活动开始事件处理器
|
||||
|
||||
***
|
||||
#### func OnStartedEvent(activity *Activity[Type, ID])
|
||||
<span id="OnStartedEvent"></span>
|
||||
> 活动开始事件
|
||||
|
||||
***
|
||||
#### func RegEndedEvent(activityType Type, handler EndedEventHandler[ID], priority ...int)
|
||||
<span id="RegEndedEvent"></span>
|
||||
> 注册活动结束事件处理器
|
||||
|
||||
***
|
||||
#### func OnEndedEvent(activity *Activity[Type, ID])
|
||||
<span id="OnEndedEvent"></span>
|
||||
> 活动结束事件
|
||||
|
||||
***
|
||||
#### func RegExtendedShowStartedEvent(activityType Type, handler ExtendedShowStartedEventHandler[ID], priority ...int)
|
||||
<span id="RegExtendedShowStartedEvent"></span>
|
||||
> 注册活动结束后延长展示开始事件处理器
|
||||
|
||||
***
|
||||
#### func OnExtendedShowStartedEvent(activity *Activity[Type, ID])
|
||||
<span id="OnExtendedShowStartedEvent"></span>
|
||||
> 活动结束后延长展示开始事件
|
||||
|
||||
***
|
||||
#### func RegExtendedShowEndedEvent(activityType Type, handler ExtendedShowEndedEventHandler[ID], priority ...int)
|
||||
<span id="RegExtendedShowEndedEvent"></span>
|
||||
> 注册活动结束后延长展示结束事件处理器
|
||||
|
||||
***
|
||||
#### func OnExtendedShowEndedEvent(activity *Activity[Type, ID])
|
||||
<span id="OnExtendedShowEndedEvent"></span>
|
||||
> 活动结束后延长展示结束事件
|
||||
|
||||
***
|
||||
#### func RegNewDayEvent(activityType Type, handler NewDayEventHandler[ID], priority ...int)
|
||||
<span id="RegNewDayEvent"></span>
|
||||
> 注册新的一天事件处理器
|
||||
|
||||
***
|
||||
#### func OnNewDayEvent(activity *Activity[Type, ID])
|
||||
<span id="OnNewDayEvent"></span>
|
||||
> 新的一天事件
|
||||
|
||||
***
|
||||
#### func NewOptions() *Options
|
||||
<span id="NewOptions"></span>
|
||||
> 创建活动选项
|
||||
|
||||
***
|
||||
### Activity `STRUCT`
|
||||
活动描述
|
||||
```go
|
||||
type Activity[Type generic.Basic, ID generic.Basic] struct {
|
||||
id ID
|
||||
t Type
|
||||
options *Options
|
||||
state byte
|
||||
lazy bool
|
||||
tickerKey string
|
||||
retention time.Duration
|
||||
retentionKey string
|
||||
mutex sync.RWMutex
|
||||
getLastNewDayTime func() time.Time
|
||||
setLastNewDayTime func(time.Time)
|
||||
clearData func()
|
||||
initializeData func()
|
||||
}
|
||||
```
|
||||
### Controller `STRUCT`
|
||||
活动控制器
|
||||
```go
|
||||
type Controller[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] struct {
|
||||
t Type
|
||||
activities map[ID]*Activity[Type, ID]
|
||||
globalData map[ID]*DataMeta[Data]
|
||||
entityData map[ID]map[EntityID]*EntityDataMeta[EntityData]
|
||||
entityTof reflect.Type
|
||||
globalInit func(activityId ID, data *DataMeta[Data])
|
||||
entityInit func(activityId ID, entityId EntityID, data *EntityDataMeta[EntityData])
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
```
|
||||
### BasicActivityController `INTERFACE`
|
||||
|
||||
```go
|
||||
type BasicActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] interface {
|
||||
IsOpen(activityId ID) bool
|
||||
IsShow(activityId ID) bool
|
||||
IsOpenOrShow(activityId ID) bool
|
||||
Refresh(activityId ID)
|
||||
}
|
||||
```
|
||||
### NoneDataActivityController `INTERFACE`
|
||||
无数据活动控制器
|
||||
```go
|
||||
type NoneDataActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] interface {
|
||||
BasicActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
InitializeNoneData(handler func(activityId ID, data *DataMeta[Data])) NoneDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
}
|
||||
```
|
||||
### GlobalDataActivityController `INTERFACE`
|
||||
全局数据活动控制器
|
||||
```go
|
||||
type GlobalDataActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] interface {
|
||||
BasicActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
GetGlobalData(activityId ID) Data
|
||||
InitializeGlobalData(handler func(activityId ID, data *DataMeta[Data])) GlobalDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
}
|
||||
```
|
||||
### EntityDataActivityController `INTERFACE`
|
||||
实体数据活动控制器
|
||||
```go
|
||||
type EntityDataActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] interface {
|
||||
BasicActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
GetEntityData(activityId ID, entityId EntityID) EntityData
|
||||
InitializeEntityData(handler func(activityId ID, entityId EntityID, data *EntityDataMeta[EntityData])) EntityDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
}
|
||||
```
|
||||
### GlobalAndEntityDataActivityController `INTERFACE`
|
||||
全局数据和实体数据活动控制器
|
||||
```go
|
||||
type GlobalAndEntityDataActivityController[Type generic.Basic, ID generic.Basic, Data any, EntityID generic.Basic, EntityData any] interface {
|
||||
BasicActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
GetGlobalData(activityId ID) Data
|
||||
GetEntityData(activityId ID, entityId EntityID) EntityData
|
||||
InitializeGlobalAndEntityData(handler func(activityId ID, data *DataMeta[Data]), entityHandler func(activityId ID, entityId EntityID, data *EntityDataMeta[EntityData])) GlobalAndEntityDataActivityController[Type, ID, Data, EntityID, EntityData]
|
||||
}
|
||||
```
|
||||
### DataMeta `STRUCT`
|
||||
全局活动数据
|
||||
```go
|
||||
type DataMeta[Data any] struct {
|
||||
once sync.Once
|
||||
Data Data
|
||||
LastNewDay time.Time
|
||||
}
|
||||
```
|
||||
### EntityDataMeta `STRUCT`
|
||||
活动实体数据
|
||||
```go
|
||||
type EntityDataMeta[Data any] struct {
|
||||
once sync.Once
|
||||
Data Data
|
||||
LastNewDay time.Time
|
||||
}
|
||||
```
|
||||
### UpcomingEventHandler `STRUCT`
|
||||
|
||||
```go
|
||||
type UpcomingEventHandler[ID generic.Basic] func(activityId ID)
|
||||
```
|
||||
### Options `STRUCT`
|
||||
活动选项
|
||||
```go
|
||||
type Options struct {
|
||||
Tl *times.StateLine[byte]
|
||||
Loop time.Duration
|
||||
}
|
||||
```
|
||||
#### func (*Options) WithUpcomingTime(t time.Time) *Options
|
||||
> 设置活动预告时间
|
||||
***
|
||||
#### func (*Options) WithStartTime(t time.Time) *Options
|
||||
> 设置活动开始时间
|
||||
***
|
||||
#### func (*Options) WithEndTime(t time.Time) *Options
|
||||
> 设置活动结束时间
|
||||
***
|
||||
#### func (*Options) WithExtendedShowTime(t time.Time) *Options
|
||||
> 设置延长展示时间
|
||||
***
|
||||
#### func (*Options) WithLoop(interval time.Duration) *Options
|
||||
> 设置活动循环,时间间隔小于等于 0 表示不循环
|
||||
> - 当活动状态展示结束后,会根据该选项设置的时间间隔重新开始
|
||||
***
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
# Main
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,15 @@
|
|||
# Activities
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,15 @@
|
|||
# Demoactivity
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,32 @@
|
|||
# Types
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[DemoActivityData](#demoactivitydata)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
### DemoActivityData `STRUCT`
|
||||
|
||||
```go
|
||||
type DemoActivityData struct {
|
||||
LoginNum int
|
||||
}
|
||||
```
|
|
@ -1,18 +1,100 @@
|
|||
# Fight
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
## TurnBased [`回合制`]((https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased))
|
||||
暂无介绍...
|
||||
|
||||
### 设计思路
|
||||
- 在每个回合中计算下一次行动时间间隔。然后,会根据当前行动时间间隔选择下一个行动实体。
|
||||
- 当选择到下一个行动实体后,进入行动阶段。在行动阶段中,会先触发 [`TurnBasedEntitySwitchEvent`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased.RegTurnBasedEntitySwitchEvent) 事件,然后开始计时。
|
||||
- 当计时结束时,如果实体还未完成行动,则会触发 [`TurnBasedEntityActionTimeoutEvent`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased.RegTurnBasedEntityActionTimeoutEvent) 事件。如果实体已经完成行动,则会触发 [`TurnBasedEntityActionFinishEvent`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased.RegTurnBasedEntityActionFinishEvent) 事件。
|
||||
- 当实体完成行动后,会触发 [`TurnBasedEntityActionSubmitEvent`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/fight#TurnBased.RegTurnBasedEntityActionSubmitEvent) 事件。
|
||||
|
||||
回合制功能的设计思路主要考虑了以下几个方面:
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
* 灵活性:`TurnBased` 类型提供了丰富的属性和方法,可以满足不同游戏的需要。
|
||||
* 可扩展性:`TurnBased` 类型还提供了 `AddCamp`、`GetCamp`、`SetActionTimeout` 等方法,可以根据需要扩展回合制功能。
|
||||
* 事件驱动:回合制功能使用事件驱动的方式来通知回合制状态变化。
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewTurnBased](#NewTurnBased)|创建一个新的回合制
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[TurnBased](#turnbased)|回合制
|
||||
|`INTERFACE`|[TurnBasedControllerInfo](#turnbasedcontrollerinfo)|暂无描述...
|
||||
|`INTERFACE`|[TurnBasedControllerAction](#turnbasedcontrolleraction)|暂无描述...
|
||||
|`STRUCT`|[TurnBasedController](#turnbasedcontroller)|回合制控制器
|
||||
|`STRUCT`|[TurnBasedEntitySwitchEventHandler](#turnbasedentityswitcheventhandler)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewTurnBased(calcNextTurnDuration func ( Camp, Entity) time.Duration) *TurnBased[CampID, EntityID, Camp, Entity]
|
||||
<span id="NewTurnBased"></span>
|
||||
> 创建一个新的回合制
|
||||
> - calcNextTurnDuration 将返回下一次行动时间间隔,适用于按照速度计算下一次行动时间间隔的情况。当返回 0 时,将使用默认的行动超时时间
|
||||
|
||||
***
|
||||
### TurnBased `STRUCT`
|
||||
回合制
|
||||
```go
|
||||
type TurnBased[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] struct {
|
||||
*turnBasedEvents[CampID, EntityID, Camp, Entity]
|
||||
controller *TurnBasedController[CampID, EntityID, Camp, Entity]
|
||||
ticker *time.Ticker
|
||||
actionWaitTicker *time.Ticker
|
||||
actioning bool
|
||||
actionMutex sync.RWMutex
|
||||
entities []Entity
|
||||
campRel map[EntityID]Camp
|
||||
calcNextTurnDuration func(Camp, Entity) time.Duration
|
||||
actionTimeoutHandler func(Camp, Entity) time.Duration
|
||||
signal chan signal
|
||||
round int
|
||||
currCamp Camp
|
||||
currEntity Entity
|
||||
currActionTimeout time.Duration
|
||||
currStart time.Time
|
||||
closeMutex sync.RWMutex
|
||||
closed bool
|
||||
}
|
||||
```
|
||||
### TurnBasedControllerInfo `INTERFACE`
|
||||
|
||||
```go
|
||||
type TurnBasedControllerInfo[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] interface {
|
||||
GetRound() int
|
||||
GetCamp() Camp
|
||||
GetEntity() Entity
|
||||
GetActionTimeoutDuration() time.Duration
|
||||
GetActionStartTime() time.Time
|
||||
GetActionEndTime() time.Time
|
||||
Stop()
|
||||
}
|
||||
```
|
||||
### TurnBasedControllerAction `INTERFACE`
|
||||
|
||||
```go
|
||||
type TurnBasedControllerAction[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] interface {
|
||||
TurnBasedControllerInfo[CampID, EntityID, Camp, Entity]
|
||||
Finish()
|
||||
Refresh(duration time.Duration) time.Time
|
||||
}
|
||||
```
|
||||
### TurnBasedController `STRUCT`
|
||||
回合制控制器
|
||||
```go
|
||||
type TurnBasedController[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] struct {
|
||||
tb *TurnBased[CampID, EntityID, Camp, Entity]
|
||||
}
|
||||
```
|
||||
### TurnBasedEntitySwitchEventHandler `STRUCT`
|
||||
|
||||
```go
|
||||
type TurnBasedEntitySwitchEventHandler[CampID comparable, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] func(controller TurnBasedControllerAction[CampID, EntityID, Camp, Entity])
|
||||
```
|
||||
|
|
|
@ -1,54 +1,95 @@
|
|||
# Space
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
计划提供游戏中常见的空间设计,例如房间、地图等。开发者可以使用它来快速构建游戏中的常见空间,例如多人房间、地图等。
|
||||
space 游戏中常见的空间设计,例如房间、地图等
|
||||
|
||||
## Room [`房间`]((https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager))
|
||||
房间在 `Minotaur` 中仅仅只是一个可以为任意可比较类型的 `ID`,当需要将现有或新设计的房间纳入 [`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理时,需要实现 [`Room`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理时,仅需要实现 [`generic.IdR`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/generic#IdR) 接口即可。
|
||||
|
||||
该功能由
|
||||
[`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager)、
|
||||
[`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController)
|
||||
组成。
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
当创建一个新的房间并纳入 [`RoomManager`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomManager) 管理后,将会得到一个 [`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController)。通过 [`RoomController`](https://pkg.go.dev/github.com/kercylan98/minotaur/game/space#RoomController) 可以对房间进行管理,例如:获取房间信息、加入房间、退出房间等。
|
||||
|
||||
### 使用示例
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewRoomManager](#NewRoomManager)|创建房间管理器 RoomManager 的实例
|
||||
|[NewRoomControllerOptions](#NewRoomControllerOptions)|创建房间控制器选项
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[RoomController](#roomcontroller)|对房间进行操作的控制器,由 RoomManager 接管后返回
|
||||
|`STRUCT`|[RoomManager](#roommanager)|房间管理器是用于对房间进行管理的基本单元,通过该实例可以对房间进行增删改查等操作
|
||||
|`STRUCT`|[RoomAssumeControlEventHandle](#roomassumecontroleventhandle)|暂无描述...
|
||||
|`STRUCT`|[RoomControllerOptions](#roomcontrolleroptions)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewRoomManager() *RoomManager[EntityID, RoomID, Entity, Room]
|
||||
<span id="NewRoomManager"></span>
|
||||
> 创建房间管理器 RoomManager 的实例
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/game/space"
|
||||
)
|
||||
|
||||
type Room struct {
|
||||
Id int64
|
||||
}
|
||||
|
||||
func (r *Room) GetId() int64 {
|
||||
return r.Id
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
Id string
|
||||
}
|
||||
|
||||
func (p *Player) GetId() string {
|
||||
return p.Id
|
||||
}
|
||||
|
||||
func main() {
|
||||
func ExampleNewRoomManager() {
|
||||
var rm = space.NewRoomManager[string, int64, *Player, *Room]()
|
||||
var room = &Room{Id: 1}
|
||||
var controller = rm.AssumeControl(room)
|
||||
|
||||
if err := controller.AddEntity(&Player{Id: "1"}); err != nil {
|
||||
// 房间密码不匹配或者房间已满
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(controller.GetEntityCount()) // 1
|
||||
fmt.Println(rm == nil)
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func NewRoomControllerOptions() *RoomControllerOptions[EntityID, RoomID, Entity, Room]
|
||||
<span id="NewRoomControllerOptions"></span>
|
||||
> 创建房间控制器选项
|
||||
|
||||
***
|
||||
### RoomController `STRUCT`
|
||||
对房间进行操作的控制器,由 RoomManager 接管后返回
|
||||
```go
|
||||
type RoomController[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct {
|
||||
manager *RoomManager[EntityID, RoomID, Entity, Room]
|
||||
options *RoomControllerOptions[EntityID, RoomID, Entity, Room]
|
||||
room Room
|
||||
entities map[EntityID]Entity
|
||||
entitiesRWMutex sync.RWMutex
|
||||
vacancy []int
|
||||
seat []*EntityID
|
||||
owner *EntityID
|
||||
}
|
||||
```
|
||||
### RoomManager `STRUCT`
|
||||
房间管理器是用于对房间进行管理的基本单元,通过该实例可以对房间进行增删改查等操作
|
||||
- 该实例是线程安全的
|
||||
```go
|
||||
type RoomManager[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct {
|
||||
*roomManagerEvents[EntityID, RoomID, Entity, Room]
|
||||
roomsRWMutex sync.RWMutex
|
||||
rooms map[RoomID]*RoomController[EntityID, RoomID, Entity, Room]
|
||||
}
|
||||
```
|
||||
### RoomAssumeControlEventHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type RoomAssumeControlEventHandle[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] func(controller *RoomController[EntityID, RoomID, Entity, Room])
|
||||
```
|
||||
### RoomControllerOptions `STRUCT`
|
||||
|
||||
```go
|
||||
type RoomControllerOptions[EntityID comparable, RoomID comparable, Entity generic.IdR[EntityID], Room generic.IdR[RoomID]] struct {
|
||||
maxEntityCount *int
|
||||
password *string
|
||||
ownerInherit bool
|
||||
ownerInheritHandler func(controller *RoomController[EntityID, RoomID, Entity, Room]) *EntityID
|
||||
}
|
||||
```
|
||||
|
|
|
@ -0,0 +1,286 @@
|
|||
# Task
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[Cond](#Cond)|创建任务条件
|
||||
|[RegisterRefreshTaskCounterEvent](#RegisterRefreshTaskCounterEvent)|注册特定任务类型的刷新任务计数器事件处理函数
|
||||
|[OnRefreshTaskCounterEvent](#OnRefreshTaskCounterEvent)|触发特定任务类型的刷新任务计数器事件
|
||||
|[RegisterRefreshTaskConditionEvent](#RegisterRefreshTaskConditionEvent)|注册特定任务类型的刷新任务条件事件处理函数
|
||||
|[OnRefreshTaskConditionEvent](#OnRefreshTaskConditionEvent)|触发特定任务类型的刷新任务条件事件
|
||||
|[WithType](#WithType)|设置任务类型
|
||||
|[WithCondition](#WithCondition)|设置任务完成条件,当满足条件时,任务状态为完成
|
||||
|[WithCounter](#WithCounter)|设置任务计数器,当计数器达到要求时,任务状态为完成
|
||||
|[WithOverflowCounter](#WithOverflowCounter)|设置可溢出的任务计数器,当计数器达到要求时,任务状态为完成
|
||||
|[WithDeadline](#WithDeadline)|设置任务截止时间,超过截至时间并且任务未完成时,任务状态为失败
|
||||
|[WithLimitedDuration](#WithLimitedDuration)|设置任务限时,超过限时时间并且任务未完成时,任务状态为失败
|
||||
|[NewTask](#NewTask)|生成任务
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Condition](#condition)|任务条件
|
||||
|`STRUCT`|[RefreshTaskCounterEventHandler](#refreshtaskcountereventhandler)|暂无描述...
|
||||
|`STRUCT`|[Option](#option)|任务选项
|
||||
|`STRUCT`|[Status](#status)|暂无描述...
|
||||
|`STRUCT`|[Task](#task)|是对任务信息进行描述和处理的结构体
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func Cond(k any, v any) Condition
|
||||
<span id="Cond"></span>
|
||||
> 创建任务条件
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestCond(t *testing.T) {
|
||||
task := NewTask(WithType("T"), WithCounter(5), WithCondition(Cond("N", 5).Cond("M", 10)))
|
||||
task.AssignConditionValueAndRefresh("N", 5)
|
||||
task.AssignConditionValueAndRefresh("M", 10)
|
||||
RegisterRefreshTaskCounterEvent[*Player](task.Type, func(taskType string, trigger *Player, count int64) {
|
||||
fmt.Println("Player", count)
|
||||
for _, t := range trigger.tasks[taskType] {
|
||||
fmt.Println(t.CurrCount, t.IncrementCounter(count).Status)
|
||||
}
|
||||
})
|
||||
RegisterRefreshTaskConditionEvent[*Player](task.Type, func(taskType string, trigger *Player, condition Condition) {
|
||||
fmt.Println("Player", condition)
|
||||
for _, t := range trigger.tasks[taskType] {
|
||||
fmt.Println(t.CurrCount, t.AssignConditionValueAndRefresh("N", 5).Status)
|
||||
}
|
||||
})
|
||||
RegisterRefreshTaskCounterEvent[*Monster](task.Type, func(taskType string, trigger *Monster, count int64) {
|
||||
fmt.Println("Monster", count)
|
||||
})
|
||||
player := &Player{tasks: map[string][]*Task{task.Type: {task}}}
|
||||
OnRefreshTaskCounterEvent(task.Type, player, 1)
|
||||
OnRefreshTaskCounterEvent(task.Type, player, 2)
|
||||
OnRefreshTaskCounterEvent(task.Type, player, 3)
|
||||
OnRefreshTaskCounterEvent(task.Type, new(Monster), 3)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func RegisterRefreshTaskCounterEvent(taskType string, handler RefreshTaskCounterEventHandler[Trigger])
|
||||
<span id="RegisterRefreshTaskCounterEvent"></span>
|
||||
> 注册特定任务类型的刷新任务计数器事件处理函数
|
||||
|
||||
***
|
||||
#### func OnRefreshTaskCounterEvent(taskType string, trigger any, count int64)
|
||||
<span id="OnRefreshTaskCounterEvent"></span>
|
||||
> 触发特定任务类型的刷新任务计数器事件
|
||||
|
||||
***
|
||||
#### func RegisterRefreshTaskConditionEvent(taskType string, handler RefreshTaskConditionEventHandler[Trigger])
|
||||
<span id="RegisterRefreshTaskConditionEvent"></span>
|
||||
> 注册特定任务类型的刷新任务条件事件处理函数
|
||||
|
||||
***
|
||||
#### func OnRefreshTaskConditionEvent(taskType string, trigger any, condition Condition)
|
||||
<span id="OnRefreshTaskConditionEvent"></span>
|
||||
> 触发特定任务类型的刷新任务条件事件
|
||||
|
||||
***
|
||||
#### func WithType(taskType string) Option
|
||||
<span id="WithType"></span>
|
||||
> 设置任务类型
|
||||
|
||||
***
|
||||
#### func WithCondition(condition Condition) Option
|
||||
<span id="WithCondition"></span>
|
||||
> 设置任务完成条件,当满足条件时,任务状态为完成
|
||||
> - 任务条件值需要变更时可通过 Task.AssignConditionValueAndRefresh 方法变更
|
||||
> - 当多次设置该选项时,后面的设置会覆盖之前的设置
|
||||
|
||||
***
|
||||
#### func WithCounter(counter int64, initCount ...int64) Option
|
||||
<span id="WithCounter"></span>
|
||||
> 设置任务计数器,当计数器达到要求时,任务状态为完成
|
||||
> - 一些场景下,任务计数器可能会溢出,此时可通过 WithOverflowCounter 设置可溢出的任务计数器
|
||||
> - 当多次设置该选项时,后面的设置会覆盖之前的设置
|
||||
> - 如果需要初始化计数器的值,可通过 initCount 参数设置
|
||||
|
||||
***
|
||||
#### func WithOverflowCounter(counter int64, initCount ...int64) Option
|
||||
<span id="WithOverflowCounter"></span>
|
||||
> 设置可溢出的任务计数器,当计数器达到要求时,任务状态为完成
|
||||
> - 当多次设置该选项时,后面的设置会覆盖之前的设置
|
||||
> - 如果需要初始化计数器的值,可通过 initCount 参数设置
|
||||
|
||||
***
|
||||
#### func WithDeadline(deadline time.Time) Option
|
||||
<span id="WithDeadline"></span>
|
||||
> 设置任务截止时间,超过截至时间并且任务未完成时,任务状态为失败
|
||||
|
||||
***
|
||||
#### func WithLimitedDuration(start time.Time, duration time.Duration) Option
|
||||
<span id="WithLimitedDuration"></span>
|
||||
> 设置任务限时,超过限时时间并且任务未完成时,任务状态为失败
|
||||
|
||||
***
|
||||
#### func NewTask(options ...Option) *Task
|
||||
<span id="NewTask"></span>
|
||||
> 生成任务
|
||||
|
||||
***
|
||||
### Condition `STRUCT`
|
||||
任务条件
|
||||
```go
|
||||
type Condition map[any]any
|
||||
```
|
||||
#### func (Condition) Cond(k any, v any) Condition
|
||||
> 创建任务条件
|
||||
***
|
||||
#### func (Condition) GetString(key any) string
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetInt(key any) int
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetInt8(key any) int8
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetInt16(key any) int16
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetInt32(key any) int32
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetInt64(key any) int64
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetUint(key any) uint
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetUint8(key any) uint8
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetUint16(key any) uint16
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetUint32(key any) uint32
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetUint64(key any) uint64
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetFloat32(key any) float32
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetFloat64(key any) float64
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetBool(key any) bool
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetTime(key any) time.Time
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetDuration(key any) time.Duration
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetByte(key any) byte
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetBytes(key any) []byte
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetRune(key any) rune
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetRunes(key any) []rune
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
#### func (Condition) GetAny(key any) any
|
||||
> 获取特定类型的任务条件值,该值必须与预期类型一致,否则返回零值
|
||||
***
|
||||
### RefreshTaskCounterEventHandler `STRUCT`
|
||||
|
||||
```go
|
||||
type RefreshTaskCounterEventHandler[Trigger any] func(taskType string, trigger Trigger, count int64)
|
||||
```
|
||||
### Option `STRUCT`
|
||||
任务选项
|
||||
```go
|
||||
type Option func(task *Task)
|
||||
```
|
||||
### Status `STRUCT`
|
||||
|
||||
```go
|
||||
type Status byte
|
||||
```
|
||||
#### func (Status) String() string
|
||||
***
|
||||
### Task `STRUCT`
|
||||
是对任务信息进行描述和处理的结构体
|
||||
```go
|
||||
type Task struct {
|
||||
Type string
|
||||
Status Status
|
||||
Cond Condition
|
||||
CondValue map[any]any
|
||||
Counter int64
|
||||
CurrCount int64
|
||||
CurrOverflow bool
|
||||
Deadline time.Time
|
||||
StartTime time.Time
|
||||
LimitedDuration time.Duration
|
||||
}
|
||||
```
|
||||
#### func (*Task) IsComplete() bool
|
||||
> 判断任务是否已完成
|
||||
***
|
||||
#### func (*Task) IsFailed() bool
|
||||
> 判断任务是否已失败
|
||||
***
|
||||
#### func (*Task) IsReward() bool
|
||||
> 判断任务是否已领取奖励
|
||||
***
|
||||
#### func (*Task) ReceiveReward() bool
|
||||
> 领取任务奖励,当任务状态为已完成时,才能领取奖励,此时返回 true,并且任务状态变更为已领取奖励
|
||||
***
|
||||
#### func (*Task) IncrementCounter(incr int64) *Task
|
||||
> 增加计数器的值,当 incr 为负数时,计数器的值不会发生变化
|
||||
> - 如果需要溢出计数器,可通过 WithOverflowCounter 设置可溢出的任务计数器
|
||||
***
|
||||
#### func (*Task) DecrementCounter(decr int64) *Task
|
||||
> 减少计数器的值,当 decr 为负数时,计数器的值不会发生变化
|
||||
***
|
||||
#### func (*Task) AssignConditionValueAndRefresh(key any, value any) *Task
|
||||
> 分配条件值并刷新任务状态
|
||||
***
|
||||
#### func (*Task) AssignConditionValueAndRefreshByCondition(condition Condition) *Task
|
||||
> 分配条件值并刷新任务状态
|
||||
***
|
||||
#### func (*Task) ResetStatus() *Task
|
||||
> 重置任务状态
|
||||
> - 该函数会将任务状态重置为已接受状态后,再刷新任务状态
|
||||
> - 当任务条件变更,例如任务计数要求为 10,已经完成的情况下,将任务计数要求变更为 5 或 20,此时任务状态由于是已完成或已领取状态,不会自动刷新,需要调用该函数刷新任务状态
|
||||
***
|
|
@ -0,0 +1,68 @@
|
|||
# Notify
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
notify 包含了对外部第三方通知的实现,如机器人消息等
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewManager](#NewManager)|通过指定的 Sender 创建一个通知管理器, senders 包中提供了一些内置的 Sender
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Manager](#manager)|通知管理器,可用于将通知同时发送至多个渠道
|
||||
|`INTERFACE`|[Notify](#notify)|通用通知接口定义
|
||||
|`INTERFACE`|[Sender](#sender)|通知发送器接口声明
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewManager(senders ...Sender) *Manager
|
||||
<span id="NewManager"></span>
|
||||
> 通过指定的 Sender 创建一个通知管理器, senders 包中提供了一些内置的 Sender
|
||||
|
||||
***
|
||||
### Manager `STRUCT`
|
||||
通知管理器,可用于将通知同时发送至多个渠道
|
||||
```go
|
||||
type Manager struct {
|
||||
senders []Sender
|
||||
notifyChannel chan Notify
|
||||
closeChannel chan struct{}
|
||||
}
|
||||
```
|
||||
#### func (*Manager) PushNotify(notify Notify)
|
||||
> 推送通知
|
||||
***
|
||||
#### func (*Manager) Release()
|
||||
> 释放通知管理器
|
||||
***
|
||||
### Notify `INTERFACE`
|
||||
通用通知接口定义
|
||||
```go
|
||||
type Notify interface {
|
||||
Format() (string, error)
|
||||
}
|
||||
```
|
||||
### Sender `INTERFACE`
|
||||
通知发送器接口声明
|
||||
```go
|
||||
type Sender interface {
|
||||
Push(notify Notify) error
|
||||
}
|
||||
```
|
|
@ -0,0 +1,226 @@
|
|||
# Notifies
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
notifies 包含了内置通知内容的实现
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewFeiShu](#NewFeiShu)|创建飞书通知消息
|
||||
|[FeiShuMessageWithText](#FeiShuMessageWithText)|飞书文本消息
|
||||
|[FeiShuMessageWithRichText](#FeiShuMessageWithRichText)|飞书富文本消息
|
||||
|[FeiShuMessageWithImage](#FeiShuMessageWithImage)|飞书图片消息
|
||||
|[FeiShuMessageWithInteractive](#FeiShuMessageWithInteractive)|飞书卡片消息
|
||||
|[FeiShuMessageWithShareChat](#FeiShuMessageWithShareChat)|飞书分享群名片
|
||||
|[FeiShuMessageWithShareUser](#FeiShuMessageWithShareUser)|飞书分享个人名片
|
||||
|[FeiShuMessageWithAudio](#FeiShuMessageWithAudio)|飞书语音消息
|
||||
|[FeiShuMessageWithMedia](#FeiShuMessageWithMedia)|飞书视频消息
|
||||
|[FeiShuMessageWithMediaAndCover](#FeiShuMessageWithMediaAndCover)|飞书带封面的视频消息
|
||||
|[FeiShuMessageWithFile](#FeiShuMessageWithFile)|飞书文件消息
|
||||
|[FeiShuMessageWithSticker](#FeiShuMessageWithSticker)|飞书表情包消息
|
||||
|[NewFeiShuRichText](#NewFeiShuRichText)|创建一个飞书富文本
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[FeiShu](#feishu)|飞书通知消息
|
||||
|`STRUCT`|[FeiShuMessage](#feishumessage)|暂无描述...
|
||||
|`STRUCT`|[FeiShuRichText](#feishurichtext)|飞书富文本结构
|
||||
|`STRUCT`|[FeiShuRichTextContent](#feishurichtextcontent)|飞书富文本内容体
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewFeiShu(message FeiShuMessage) *FeiShu
|
||||
<span id="NewFeiShu"></span>
|
||||
> 创建飞书通知消息
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithText(text string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithText"></span>
|
||||
> 飞书文本消息
|
||||
> - 支持通过换行符进行消息换行
|
||||
> - 支持通过 <at user_id="OpenID">名字</at> 进行@用户
|
||||
> - 支持通过 <at user_id="all">所有人</at> 进行@所有人(必须满足所在群开启@所有人功能。)
|
||||
>
|
||||
> 支持加粗、斜体、下划线、删除线四种样式,可嵌套使用:
|
||||
> - 加粗: <b>文本示例</b>
|
||||
> - 斜体: <i>文本示例</i>
|
||||
> - 下划线 : <u>文本示例</u>
|
||||
> - 删除线: <s>文本示例</s>
|
||||
>
|
||||
> 超链接使用说明
|
||||
> - 超链接的使用格式为[文本](链接), 如[Feishu Open Platform](https://open.feishu.cn) 。
|
||||
> - 请确保链接是合法的,否则会以原始内容发送消息。
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithRichText(richText *FeiShuRichText) FeiShuMessage
|
||||
<span id="FeiShuMessageWithRichText"></span>
|
||||
> 飞书富文本消息
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithImage(imageKey string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithImage"></span>
|
||||
> 飞书图片消息
|
||||
> - imageKey 可通过上传图片接口获取
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithInteractive(json string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithInteractive"></span>
|
||||
> 飞书卡片消息
|
||||
> - json 表示卡片的 json 数据或者消息模板的 json 数据
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithShareChat(chatId string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithShareChat"></span>
|
||||
> 飞书分享群名片
|
||||
> - chatId 群ID获取方式请参见群ID说明
|
||||
>
|
||||
> 群ID说明:https://open.feishu.cn/document/server-docs/group/chat/chat-id-description
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithShareUser(userId string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithShareUser"></span>
|
||||
> 飞书分享个人名片
|
||||
> - userId 表示用户的 OpenID 获取方式请参见了解更多:如何获取 Open ID
|
||||
>
|
||||
> 如何获取 Open ID:https://open.feishu.cn/document/faq/trouble-shooting/how-to-obtain-openid
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithAudio(fileKey string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithAudio"></span>
|
||||
> 飞书语音消息
|
||||
> - fileKey 语音文件Key,可通过上传文件接口获取
|
||||
>
|
||||
> 上传文件:https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithMedia(fileKey string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithMedia"></span>
|
||||
> 飞书视频消息
|
||||
> - fileKey 视频文件Key,可通过上传文件接口获取
|
||||
>
|
||||
> 上传文件:https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithMediaAndCover(fileKey string, imageKey string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithMediaAndCover"></span>
|
||||
> 飞书带封面的视频消息
|
||||
> - fileKey 视频文件Key,可通过上传文件接口获取
|
||||
> - imageKey 图片文件Key,可通过上传文件接口获取
|
||||
>
|
||||
> 上传文件:https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithFile(fileKey string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithFile"></span>
|
||||
> 飞书文件消息
|
||||
> - fileKey 文件Key,可通过上传文件接口获取
|
||||
>
|
||||
> 上传文件:https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create
|
||||
|
||||
***
|
||||
#### func FeiShuMessageWithSticker(fileKey string) FeiShuMessage
|
||||
<span id="FeiShuMessageWithSticker"></span>
|
||||
> 飞书表情包消息
|
||||
> - fileKey 表情包文件Key,目前仅支持发送机器人收到的表情包,可通过接收消息事件的推送获取表情包 file_key。
|
||||
>
|
||||
> 接收消息事件:https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/events/receive
|
||||
|
||||
***
|
||||
#### func NewFeiShuRichText() *FeiShuRichText
|
||||
<span id="NewFeiShuRichText"></span>
|
||||
> 创建一个飞书富文本
|
||||
|
||||
***
|
||||
### FeiShu `STRUCT`
|
||||
飞书通知消息
|
||||
```go
|
||||
type FeiShu struct {
|
||||
Content any
|
||||
MsgType string
|
||||
}
|
||||
```
|
||||
#### func (*FeiShu) Format() string, error
|
||||
> 格式化通知内容
|
||||
***
|
||||
### FeiShuMessage `STRUCT`
|
||||
|
||||
```go
|
||||
type FeiShuMessage func(feishu *FeiShu)
|
||||
```
|
||||
### FeiShuRichText `STRUCT`
|
||||
飞书富文本结构
|
||||
```go
|
||||
type FeiShuRichText struct {
|
||||
content map[string]*FeiShuRichTextContent
|
||||
}
|
||||
```
|
||||
#### func (*FeiShuRichText) Create(lang string, title string) *FeiShuRichTextContent
|
||||
> 创建一个特定语言和标题的富文本内容
|
||||
***
|
||||
### FeiShuRichTextContent `STRUCT`
|
||||
飞书富文本内容体
|
||||
```go
|
||||
type FeiShuRichTextContent struct {
|
||||
richText *FeiShuRichText
|
||||
Title string
|
||||
Content [][]map[string]any
|
||||
}
|
||||
```
|
||||
#### func (*FeiShuRichTextContent) AddText(text string, styles ...string) *FeiShuRichTextContent
|
||||
> 添加文本
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) AddUnescapeText(text string, styles ...string) *FeiShuRichTextContent
|
||||
> 添加 unescape 解码的文本
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) AddLink(text string, href string, styles ...string) *FeiShuRichTextContent
|
||||
> 添加超链接文本
|
||||
> - 请确保链接地址的合法性,否则消息会发送失败
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) AddAt(userId string, styles ...string) *FeiShuRichTextContent
|
||||
> 添加@的用户
|
||||
> - @单个用户时,userId 字段必须是有效值
|
||||
> - @所有人填"all"。
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) AddAtWithUsername(userId string, username string, styles ...string) *FeiShuRichTextContent
|
||||
> 添加包含用户名的@用户
|
||||
> - @单个用户时,userId 字段必须是有效值
|
||||
> - @所有人填"all"。
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) AddImg(imageKey string) *FeiShuRichTextContent
|
||||
> 添加图片
|
||||
> - imageKey 表示图片的唯一标识,可通过上传图片接口获取
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) AddMedia(fileKey string) *FeiShuRichTextContent
|
||||
> 添加视频
|
||||
> - fileKey 表示视频文件的唯一标识,可通过上传文件接口获取
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) AddMediaWithCover(fileKey string, imageKey string) *FeiShuRichTextContent
|
||||
> 添加包含封面的视频
|
||||
> - fileKey 表示视频文件的唯一标识,可通过上传文件接口获取
|
||||
> - imageKey 表示图片的唯一标识,可通过上传图片接口获取
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) AddEmotion(emojiType string) *FeiShuRichTextContent
|
||||
> 添加表情
|
||||
> - emojiType 表示表情类型,部分可选值请参见表情文案。
|
||||
>
|
||||
> 表情文案:https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce
|
||||
***
|
||||
#### func (*FeiShuRichTextContent) Ok() *FeiShuRichText
|
||||
> 确认完成,将返回 FeiShuRichText 可继续创建多语言富文本
|
||||
***
|
|
@ -0,0 +1,68 @@
|
|||
# Senders
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
senders Package 包含了内置通知发送器的实现
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewFeiShu](#NewFeiShu)|根据特定的 webhook 地址创建飞书发送器
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[FeiShu](#feishu)|飞书发送器
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewFeiShu(webhook string) *FeiShu
|
||||
<span id="NewFeiShu"></span>
|
||||
> 根据特定的 webhook 地址创建飞书发送器
|
||||
|
||||
***
|
||||
### FeiShu `STRUCT`
|
||||
飞书发送器
|
||||
```go
|
||||
type FeiShu struct {
|
||||
client *resty.Client
|
||||
webhook string
|
||||
}
|
||||
```
|
||||
#### func (*FeiShu) Push(notify notify.Notify) error
|
||||
> 推送通知
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestFeiShu_Push(t *testing.T) {
|
||||
fs := NewFeiShu("https://open.feishu.cn/open-apis/bot/v2/hook/d886f30f-814c-47b1-aeb0-b508da0f7f22")
|
||||
rt := notifies.NewFeiShu(notifies.FeiShuMessageWithRichText(notifies.NewFeiShuRichText().Create("zh_cn", "标题咯").AddText("哈哈哈").Ok()))
|
||||
if err := fs.Push(rt); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,13 @@
|
|||
# Planner
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
planner 包含了策划工具相关的内容
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,520 @@
|
|||
# Pce
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewExporter](#NewExporter)|创建导出器
|
||||
|[GetFieldGolangType](#GetFieldGolangType)|获取字段的 Golang 类型
|
||||
|[GetFields](#GetFields)|获取所有内置支持的字段
|
||||
|[NewLoader](#NewLoader)|创建加载器
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`INTERFACE`|[Config](#config)|配置解析接口
|
||||
|`INTERFACE`|[DataTmpl](#datatmpl)|数据导出模板
|
||||
|`STRUCT`|[Exporter](#exporter)|导出器
|
||||
|`INTERFACE`|[Field](#field)|基本字段类型接口
|
||||
|`STRUCT`|[Int](#int)|暂无描述...
|
||||
|`STRUCT`|[Int8](#int8)|暂无描述...
|
||||
|`STRUCT`|[Int16](#int16)|暂无描述...
|
||||
|`STRUCT`|[Int32](#int32)|暂无描述...
|
||||
|`STRUCT`|[Int64](#int64)|暂无描述...
|
||||
|`STRUCT`|[Uint](#uint)|暂无描述...
|
||||
|`STRUCT`|[Uint8](#uint8)|暂无描述...
|
||||
|`STRUCT`|[Uint16](#uint16)|暂无描述...
|
||||
|`STRUCT`|[Uint32](#uint32)|暂无描述...
|
||||
|`STRUCT`|[Uint64](#uint64)|暂无描述...
|
||||
|`STRUCT`|[Float32](#float32)|暂无描述...
|
||||
|`STRUCT`|[Float64](#float64)|暂无描述...
|
||||
|`STRUCT`|[String](#string)|暂无描述...
|
||||
|`STRUCT`|[Bool](#bool)|暂无描述...
|
||||
|`STRUCT`|[Byte](#byte)|暂无描述...
|
||||
|`STRUCT`|[Rune](#rune)|暂无描述...
|
||||
|`STRUCT`|[Complex64](#complex64)|暂无描述...
|
||||
|`STRUCT`|[Complex128](#complex128)|暂无描述...
|
||||
|`STRUCT`|[Uintptr](#uintptr)|暂无描述...
|
||||
|`STRUCT`|[Double](#double)|暂无描述...
|
||||
|`STRUCT`|[Float](#float)|暂无描述...
|
||||
|`STRUCT`|[Long](#long)|暂无描述...
|
||||
|`STRUCT`|[Short](#short)|暂无描述...
|
||||
|`STRUCT`|[Char](#char)|暂无描述...
|
||||
|`STRUCT`|[Number](#number)|暂无描述...
|
||||
|`STRUCT`|[Integer](#integer)|暂无描述...
|
||||
|`STRUCT`|[Boolean](#boolean)|暂无描述...
|
||||
|`STRUCT`|[Loader](#loader)|配置加载器
|
||||
|`STRUCT`|[DataInfo](#datainfo)|配置数据
|
||||
|`STRUCT`|[DataField](#datafield)|配置数据字段
|
||||
|`INTERFACE`|[Tmpl](#tmpl)|配置结构模板接口
|
||||
|`STRUCT`|[TmplField](#tmplfield)|模板字段
|
||||
|`STRUCT`|[TmplStruct](#tmplstruct)|模板结构
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewExporter() *Exporter
|
||||
<span id="NewExporter"></span>
|
||||
> 创建导出器
|
||||
|
||||
***
|
||||
#### func GetFieldGolangType(field Field) string
|
||||
<span id="GetFieldGolangType"></span>
|
||||
> 获取字段的 Golang 类型
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestGetFieldGolangType(t *testing.T) {
|
||||
fmt.Println(pce.GetFieldGolangType(new(pce.String)))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func GetFields() []Field
|
||||
<span id="GetFields"></span>
|
||||
> 获取所有内置支持的字段
|
||||
|
||||
***
|
||||
#### func NewLoader(fields []Field) *Loader
|
||||
<span id="NewLoader"></span>
|
||||
> 创建加载器
|
||||
> - 加载器被用于加载配置表的数据和结构信息
|
||||
|
||||
***
|
||||
### Config `INTERFACE`
|
||||
配置解析接口
|
||||
- 用于将配置文件解析为可供分析的数据结构
|
||||
- 可以在 cs 包中找到内置提供的实现及其模板,例如 cs.XlsxIndexConfig
|
||||
```go
|
||||
type Config interface {
|
||||
GetConfigName() string
|
||||
GetDisplayName() string
|
||||
GetDescription() string
|
||||
GetIndexCount() int
|
||||
GetFields() []DataField
|
||||
GetData() [][]DataInfo
|
||||
}
|
||||
```
|
||||
### DataTmpl `INTERFACE`
|
||||
数据导出模板
|
||||
```go
|
||||
type DataTmpl interface {
|
||||
Render(data map[any]any) (string, error)
|
||||
}
|
||||
```
|
||||
### Exporter `STRUCT`
|
||||
导出器
|
||||
```go
|
||||
type Exporter struct{}
|
||||
```
|
||||
#### func (*Exporter) ExportStruct(tmpl Tmpl, tmplStruct ...*TmplStruct) []byte, error
|
||||
> 导出结构
|
||||
***
|
||||
#### func (*Exporter) ExportData(tmpl DataTmpl, data map[any]any) []byte, error
|
||||
> 导出数据
|
||||
***
|
||||
### Field `INTERFACE`
|
||||
基本字段类型接口
|
||||
```go
|
||||
type Field interface {
|
||||
TypeName() string
|
||||
Zero() any
|
||||
Parse(value string) any
|
||||
}
|
||||
```
|
||||
### Int `STRUCT`
|
||||
|
||||
```go
|
||||
type Int int
|
||||
```
|
||||
#### func (Int) TypeName() string
|
||||
***
|
||||
#### func (Int) Zero() any
|
||||
***
|
||||
#### func (Int) Parse(value string) any
|
||||
***
|
||||
### Int8 `STRUCT`
|
||||
|
||||
```go
|
||||
type Int8 int8
|
||||
```
|
||||
#### func (Int8) TypeName() string
|
||||
***
|
||||
#### func (Int8) Zero() any
|
||||
***
|
||||
#### func (Int8) Parse(value string) any
|
||||
***
|
||||
### Int16 `STRUCT`
|
||||
|
||||
```go
|
||||
type Int16 int16
|
||||
```
|
||||
#### func (Int16) TypeName() string
|
||||
***
|
||||
#### func (Int16) Zero() any
|
||||
***
|
||||
#### func (Int16) Parse(value string) any
|
||||
***
|
||||
### Int32 `STRUCT`
|
||||
|
||||
```go
|
||||
type Int32 int32
|
||||
```
|
||||
#### func (Int32) TypeName() string
|
||||
***
|
||||
#### func (Int32) Zero() any
|
||||
***
|
||||
#### func (Int32) Parse(value string) any
|
||||
***
|
||||
### Int64 `STRUCT`
|
||||
|
||||
```go
|
||||
type Int64 int64
|
||||
```
|
||||
#### func (Int64) TypeName() string
|
||||
***
|
||||
#### func (Int64) Zero() any
|
||||
***
|
||||
#### func (Int64) Parse(value string) any
|
||||
***
|
||||
### Uint `STRUCT`
|
||||
|
||||
```go
|
||||
type Uint uint
|
||||
```
|
||||
#### func (Uint) TypeName() string
|
||||
***
|
||||
#### func (Uint) Zero() any
|
||||
***
|
||||
#### func (Uint) Parse(value string) any
|
||||
***
|
||||
### Uint8 `STRUCT`
|
||||
|
||||
```go
|
||||
type Uint8 uint8
|
||||
```
|
||||
#### func (Uint8) TypeName() string
|
||||
***
|
||||
#### func (Uint8) Zero() any
|
||||
***
|
||||
#### func (Uint8) Parse(value string) any
|
||||
***
|
||||
### Uint16 `STRUCT`
|
||||
|
||||
```go
|
||||
type Uint16 uint16
|
||||
```
|
||||
#### func (Uint16) TypeName() string
|
||||
***
|
||||
#### func (Uint16) Zero() any
|
||||
***
|
||||
#### func (Uint16) Parse(value string) any
|
||||
***
|
||||
### Uint32 `STRUCT`
|
||||
|
||||
```go
|
||||
type Uint32 uint32
|
||||
```
|
||||
#### func (Uint32) TypeName() string
|
||||
***
|
||||
#### func (Uint32) Zero() any
|
||||
***
|
||||
#### func (Uint32) Parse(value string) any
|
||||
***
|
||||
### Uint64 `STRUCT`
|
||||
|
||||
```go
|
||||
type Uint64 uint64
|
||||
```
|
||||
#### func (Uint64) TypeName() string
|
||||
***
|
||||
#### func (Uint64) Zero() any
|
||||
***
|
||||
#### func (Uint64) Parse(value string) any
|
||||
***
|
||||
### Float32 `STRUCT`
|
||||
|
||||
```go
|
||||
type Float32 float32
|
||||
```
|
||||
#### func (Float32) TypeName() string
|
||||
***
|
||||
#### func (Float32) Zero() any
|
||||
***
|
||||
#### func (Float32) Parse(value string) any
|
||||
***
|
||||
### Float64 `STRUCT`
|
||||
|
||||
```go
|
||||
type Float64 float64
|
||||
```
|
||||
#### func (Float64) TypeName() string
|
||||
***
|
||||
#### func (Float64) Zero() any
|
||||
***
|
||||
#### func (Float64) Parse(value string) any
|
||||
***
|
||||
### String `STRUCT`
|
||||
|
||||
```go
|
||||
type String string
|
||||
```
|
||||
#### func (String) TypeName() string
|
||||
***
|
||||
#### func (String) Zero() any
|
||||
***
|
||||
#### func (String) Parse(value string) any
|
||||
***
|
||||
### Bool `STRUCT`
|
||||
|
||||
```go
|
||||
type Bool bool
|
||||
```
|
||||
#### func (Bool) TypeName() string
|
||||
***
|
||||
#### func (Bool) Zero() any
|
||||
***
|
||||
#### func (Bool) Parse(value string) any
|
||||
***
|
||||
### Byte `STRUCT`
|
||||
|
||||
```go
|
||||
type Byte byte
|
||||
```
|
||||
#### func (Byte) TypeName() string
|
||||
***
|
||||
#### func (Byte) Zero() any
|
||||
***
|
||||
#### func (Byte) Parse(value string) any
|
||||
***
|
||||
### Rune `STRUCT`
|
||||
|
||||
```go
|
||||
type Rune rune
|
||||
```
|
||||
#### func (Rune) TypeName() string
|
||||
***
|
||||
#### func (Rune) Zero() any
|
||||
***
|
||||
#### func (Rune) Parse(value string) any
|
||||
***
|
||||
### Complex64 `STRUCT`
|
||||
|
||||
```go
|
||||
type Complex64 complex64
|
||||
```
|
||||
#### func (Complex64) TypeName() string
|
||||
***
|
||||
#### func (Complex64) Zero() any
|
||||
***
|
||||
#### func (Complex64) Parse(value string) any
|
||||
***
|
||||
### Complex128 `STRUCT`
|
||||
|
||||
```go
|
||||
type Complex128 complex128
|
||||
```
|
||||
#### func (Complex128) TypeName() string
|
||||
***
|
||||
#### func (Complex128) Zero() any
|
||||
***
|
||||
#### func (Complex128) Parse(value string) any
|
||||
***
|
||||
### Uintptr `STRUCT`
|
||||
|
||||
```go
|
||||
type Uintptr uintptr
|
||||
```
|
||||
#### func (Uintptr) TypeName() string
|
||||
***
|
||||
#### func (Uintptr) Zero() any
|
||||
***
|
||||
#### func (Uintptr) Parse(value string) any
|
||||
***
|
||||
### Double `STRUCT`
|
||||
|
||||
```go
|
||||
type Double float64
|
||||
```
|
||||
#### func (Double) TypeName() string
|
||||
***
|
||||
#### func (Double) Zero() any
|
||||
***
|
||||
#### func (Double) Parse(value string) any
|
||||
***
|
||||
### Float `STRUCT`
|
||||
|
||||
```go
|
||||
type Float float32
|
||||
```
|
||||
#### func (Float) TypeName() string
|
||||
***
|
||||
#### func (Float) Zero() any
|
||||
***
|
||||
#### func (Float) Parse(value string) any
|
||||
***
|
||||
### Long `STRUCT`
|
||||
|
||||
```go
|
||||
type Long int64
|
||||
```
|
||||
#### func (Long) TypeName() string
|
||||
***
|
||||
#### func (Long) Zero() any
|
||||
***
|
||||
#### func (Long) Parse(value string) any
|
||||
***
|
||||
### Short `STRUCT`
|
||||
|
||||
```go
|
||||
type Short int16
|
||||
```
|
||||
#### func (Short) TypeName() string
|
||||
***
|
||||
#### func (Short) Zero() any
|
||||
***
|
||||
#### func (Short) Parse(value string) any
|
||||
***
|
||||
### Char `STRUCT`
|
||||
|
||||
```go
|
||||
type Char int8
|
||||
```
|
||||
#### func (Char) TypeName() string
|
||||
***
|
||||
#### func (Char) Zero() any
|
||||
***
|
||||
#### func (Char) Parse(value string) any
|
||||
***
|
||||
### Number `STRUCT`
|
||||
|
||||
```go
|
||||
type Number float64
|
||||
```
|
||||
#### func (Number) TypeName() string
|
||||
***
|
||||
#### func (Number) Zero() any
|
||||
***
|
||||
#### func (Number) Parse(value string) any
|
||||
***
|
||||
### Integer `STRUCT`
|
||||
|
||||
```go
|
||||
type Integer int64
|
||||
```
|
||||
#### func (Integer) TypeName() string
|
||||
***
|
||||
#### func (Integer) Zero() any
|
||||
***
|
||||
#### func (Integer) Parse(value string) any
|
||||
***
|
||||
### Boolean `STRUCT`
|
||||
|
||||
```go
|
||||
type Boolean bool
|
||||
```
|
||||
#### func (Boolean) TypeName() string
|
||||
***
|
||||
#### func (Boolean) Zero() any
|
||||
***
|
||||
#### func (Boolean) Parse(value string) any
|
||||
***
|
||||
### Loader `STRUCT`
|
||||
配置加载器
|
||||
```go
|
||||
type Loader struct {
|
||||
fields map[string]Field
|
||||
}
|
||||
```
|
||||
#### func (*Loader) LoadStruct(config Config) *TmplStruct
|
||||
> 加载结构
|
||||
***
|
||||
#### func (*Loader) LoadData(config Config) map[any]any
|
||||
> 加载配置并得到配置数据
|
||||
***
|
||||
### DataInfo `STRUCT`
|
||||
配置数据
|
||||
```go
|
||||
type DataInfo struct {
|
||||
DataField
|
||||
Value string
|
||||
}
|
||||
```
|
||||
### DataField `STRUCT`
|
||||
配置数据字段
|
||||
```go
|
||||
type DataField struct {
|
||||
Index int
|
||||
Name string
|
||||
Desc string
|
||||
Type string
|
||||
ExportType string
|
||||
}
|
||||
```
|
||||
### Tmpl `INTERFACE`
|
||||
配置结构模板接口
|
||||
```go
|
||||
type Tmpl interface {
|
||||
Render(templates ...*TmplStruct) (string, error)
|
||||
}
|
||||
```
|
||||
### TmplField `STRUCT`
|
||||
模板字段
|
||||
```go
|
||||
type TmplField struct {
|
||||
Name string
|
||||
Desc string
|
||||
Type string
|
||||
Struct *TmplStruct
|
||||
Index int
|
||||
slice bool
|
||||
isIndex bool
|
||||
}
|
||||
```
|
||||
#### func (*TmplField) IsIndex() bool
|
||||
> 是否是索引字段
|
||||
***
|
||||
#### func (*TmplField) IsStruct() bool
|
||||
> 是否是结构类型
|
||||
***
|
||||
#### func (*TmplField) IsSlice() bool
|
||||
> 是否是切片类型
|
||||
***
|
||||
### TmplStruct `STRUCT`
|
||||
模板结构
|
||||
```go
|
||||
type TmplStruct struct {
|
||||
Name string
|
||||
Desc string
|
||||
Fields []*TmplField
|
||||
IndexCount int
|
||||
}
|
||||
```
|
||||
#### func (*TmplStruct) AllChildren() []*TmplStruct
|
||||
> 获取所有子结构
|
||||
***
|
|
@ -0,0 +1,62 @@
|
|||
# Cs
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewXlsx](#NewXlsx)|暂无描述...
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[XlsxExportType](#xlsxexporttype)|暂无描述...
|
||||
|`STRUCT`|[Xlsx](#xlsx)|内置的 Xlsx 配置
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewXlsx(sheet *xlsx.Sheet, exportType XlsxExportType) *Xlsx
|
||||
<span id="NewXlsx"></span>
|
||||
|
||||
***
|
||||
### XlsxExportType `STRUCT`
|
||||
|
||||
```go
|
||||
type XlsxExportType int
|
||||
```
|
||||
### Xlsx `STRUCT`
|
||||
内置的 Xlsx 配置
|
||||
```go
|
||||
type Xlsx struct {
|
||||
sheet *xlsx.Sheet
|
||||
exportType XlsxExportType
|
||||
}
|
||||
```
|
||||
#### func (*Xlsx) GetConfigName() string
|
||||
***
|
||||
#### func (*Xlsx) GetDisplayName() string
|
||||
***
|
||||
#### func (*Xlsx) GetDescription() string
|
||||
***
|
||||
#### func (*Xlsx) GetIndexCount() int
|
||||
***
|
||||
#### func (*Xlsx) GetFields() []pce.DataField
|
||||
***
|
||||
#### func (*Xlsx) GetData() [][]pce.DataInfo
|
||||
***
|
|
@ -0,0 +1,15 @@
|
|||
# Main
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,117 @@
|
|||
# Cmd
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[Execute](#Execute)|将所有子命令添加到根命令并适当设置标志。这是由 main.main() 调用的。 rootCmd 只需要发生一次
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func Execute()
|
||||
<span id="Execute"></span>
|
||||
> 将所有子命令添加到根命令并适当设置标志。这是由 main.main() 调用的。 rootCmd 只需要发生一次
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestExecute(t *testing.T) {
|
||||
var filePath, outPath, exclude, exportType, prefix string
|
||||
exportType = "s"
|
||||
filePath = `.\游戏配置.xlsx`
|
||||
filePath = `../xlsx_template.xlsx`
|
||||
outPath = `.`
|
||||
isDir, err := file.IsDir(outPath)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
isDir = filepath.Ext(outPath) == ""
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if !isDir {
|
||||
panic(errors.New("output must be a directory path"))
|
||||
}
|
||||
_ = os.MkdirAll(outPath, os.ModePerm)
|
||||
fpd, err := file.IsDir(filePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var xlsxFiles []string
|
||||
if fpd {
|
||||
files, err := os.ReadDir(filePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, f := range files {
|
||||
if f.IsDir() || !strings.HasSuffix(f.Name(), ".xlsx") || strings.HasPrefix(f.Name(), "~") {
|
||||
continue
|
||||
}
|
||||
xlsxFiles = append(xlsxFiles, filepath.Join(filePath, f.Name()))
|
||||
}
|
||||
} else {
|
||||
xlsxFiles = append(xlsxFiles, filePath)
|
||||
}
|
||||
var exporter = pce.NewExporter()
|
||||
loader := pce.NewLoader(pce.GetFields())
|
||||
excludes := collection.ConvertSliceToBoolMap(str.SplitTrimSpace(exclude, ","))
|
||||
for _, xlsxFile := range xlsxFiles {
|
||||
xf, err := xlsx.OpenFile(xlsxFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, sheet := range xf.Sheets {
|
||||
var cx *cs.Xlsx
|
||||
switch strings.TrimSpace(strings.ToLower(exportType)) {
|
||||
case "c":
|
||||
cx = cs.NewXlsx(sheet, cs.XlsxExportTypeClient)
|
||||
case "s":
|
||||
cx = cs.NewXlsx(sheet, cs.XlsxExportTypeServer)
|
||||
}
|
||||
if strings.HasPrefix(cx.GetDisplayName(), "#") || strings.HasPrefix(cx.GetConfigName(), "#") || excludes[cx.GetConfigName()] || excludes[cx.GetDisplayName()] {
|
||||
continue
|
||||
}
|
||||
if raw, err := exporter.ExportData(tmpls.NewJSON(), loader.LoadData(cx)); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
var jsonPath string
|
||||
if len(prefix) == 0 {
|
||||
jsonPath = filepath.Join(outPath, fmt.Sprintf("%s.json", cx.GetConfigName()))
|
||||
} else {
|
||||
jsonPath = filepath.Join(outPath, fmt.Sprintf("%s.%s.json", prefix, cx.GetConfigName()))
|
||||
}
|
||||
if err := file.WriterFile(jsonPath, raw); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,68 @@
|
|||
# Tmpls
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewGolang](#NewGolang)|创建一个 Golang 配置导出模板
|
||||
|[NewJSON](#NewJSON)|暂无描述...
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Golang](#golang)|配置导出模板
|
||||
|`STRUCT`|[JSON](#json)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewGolang(packageName string) *Golang
|
||||
<span id="NewGolang"></span>
|
||||
> 创建一个 Golang 配置导出模板
|
||||
|
||||
***
|
||||
#### func NewJSON() *JSON
|
||||
<span id="NewJSON"></span>
|
||||
|
||||
***
|
||||
### Golang `STRUCT`
|
||||
配置导出模板
|
||||
```go
|
||||
type Golang struct {
|
||||
Package string
|
||||
Templates []*pce.TmplStruct
|
||||
}
|
||||
```
|
||||
#### func (*Golang) Render(templates ...*pce.TmplStruct) string, error
|
||||
***
|
||||
#### func (*Golang) GetVariable(config *pce.TmplStruct) string
|
||||
***
|
||||
#### func (*Golang) GetConfigName(config *pce.TmplStruct) string
|
||||
***
|
||||
#### func (*Golang) HasIndex(config *pce.TmplStruct) bool
|
||||
***
|
||||
### JSON `STRUCT`
|
||||
|
||||
```go
|
||||
type JSON struct {
|
||||
jsonIter.API
|
||||
}
|
||||
```
|
||||
#### func (*JSON) Render(data map[any]any) string, error
|
||||
***
|
|
@ -0,0 +1,975 @@
|
|||
# Server
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
server 提供了包含多种网络类型的服务器实现
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewBot](#NewBot)|创建一个机器人,目前仅支持 Socket 服务器
|
||||
|[WithBotNetworkDelay](#WithBotNetworkDelay)|设置机器人网络延迟及波动范围
|
||||
|[WithBotWriter](#WithBotWriter)|设置机器人写入器,默认为 os.Stdout
|
||||
|[DefaultWebsocketUpgrader](#DefaultWebsocketUpgrader)|暂无描述...
|
||||
|[NewHttpHandleWrapper](#NewHttpHandleWrapper)|创建一个新的 http 处理程序包装器
|
||||
|[NewHttpContext](#NewHttpContext)|基于 gin.Context 创建一个新的 HttpContext
|
||||
|[NewGinWrapper](#NewGinWrapper)|创建 gin 包装器,用于对 NewHttpWrapper 函数的替代
|
||||
|[HasMessageType](#HasMessageType)|检查是否存在指定的消息类型
|
||||
|[NewMultipleServer](#NewMultipleServer)|暂无描述...
|
||||
|[GetNetworks](#GetNetworks)|获取所有支持的网络模式
|
||||
|[WithLowMessageDuration](#WithLowMessageDuration)|通过指定慢消息时长的方式创建服务器,当消息处理时间超过指定时长时,将会输出 WARN 类型的日志
|
||||
|[WithAsyncLowMessageDuration](#WithAsyncLowMessageDuration)|通过指定异步消息的慢消息时长的方式创建服务器,当消息处理时间超过指定时长时,将会输出 WARN 类型的日志
|
||||
|[WithWebsocketConnInitializer](#WithWebsocketConnInitializer)|通过 websocket 连接初始化的方式创建服务器,当 initializer 返回错误时,服务器将不会处理该连接的后续逻辑
|
||||
|[WithWebsocketUpgrade](#WithWebsocketUpgrade)|通过指定 websocket.Upgrader 的方式创建服务器
|
||||
|[WithConnWriteBufferSize](#WithConnWriteBufferSize)|通过连接写入缓冲区大小的方式创建服务器
|
||||
|[WithDispatcherBufferSize](#WithDispatcherBufferSize)|通过消息分发器缓冲区大小的方式创建服务器
|
||||
|[WithMessageStatistics](#WithMessageStatistics)|通过消息统计的方式创建服务器
|
||||
|[WithPacketWarnSize](#WithPacketWarnSize)|通过数据包大小警告的方式创建服务器,当数据包大小超过指定大小时,将会输出 WARN 类型的日志
|
||||
|[WithLimitLife](#WithLimitLife)|通过限制最大生命周期的方式创建服务器
|
||||
|[WithWebsocketWriteCompression](#WithWebsocketWriteCompression)|通过数据写入压缩的方式创建Websocket服务器
|
||||
|[WithWebsocketCompression](#WithWebsocketCompression)|通过数据压缩的方式创建Websocket服务器
|
||||
|[WithDeadlockDetect](#WithDeadlockDetect)|通过死锁、死循环、永久阻塞检测的方式创建服务器
|
||||
|[WithDisableAsyncMessage](#WithDisableAsyncMessage)|通过禁用异步消息的方式创建服务器
|
||||
|[WithAsyncPoolSize](#WithAsyncPoolSize)|通过指定异步消息池大小的方式创建服务器
|
||||
|[WithWebsocketReadDeadline](#WithWebsocketReadDeadline)|设置 Websocket 读取超时时间
|
||||
|[WithTicker](#WithTicker)|通过定时器创建服务器,为服务器添加定时器功能
|
||||
|[WithTLS](#WithTLS)|通过安全传输层协议TLS创建服务器
|
||||
|[WithGRPCServerOptions](#WithGRPCServerOptions)|通过GRPC的可选项创建GRPC服务器
|
||||
|[WithWebsocketMessageType](#WithWebsocketMessageType)|设置仅支持特定类型的Websocket消息
|
||||
|[WithPProf](#WithPProf)|通过性能分析工具PProf创建服务器
|
||||
|[New](#New)|根据特定网络类型创建一个服务器
|
||||
|[BindService](#BindService)|绑定服务到特定 Server,被绑定的服务将会在 Server 初始化时执行 Service.OnInit 方法
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Bot](#bot)|暂无描述...
|
||||
|`STRUCT`|[BotOption](#botoption)|暂无描述...
|
||||
|`STRUCT`|[Conn](#conn)|服务器连接单次消息的包装
|
||||
|`STRUCT`|[ConsoleParams](#consoleparams)|控制台参数
|
||||
|`STRUCT`|[MessageReadyEventHandler](#messagereadyeventhandler)|暂无描述...
|
||||
|`STRUCT`|[Http](#http)|基于 gin.Engine 包装的 http 服务器
|
||||
|`STRUCT`|[HttpContext](#httpcontext)|基于 gin.Context 的 http 请求上下文
|
||||
|`STRUCT`|[HandlerFunc](#handlerfunc)|暂无描述...
|
||||
|`STRUCT`|[ContextPacker](#contextpacker)|暂无描述...
|
||||
|`STRUCT`|[HttpRouter](#httprouter)|暂无描述...
|
||||
|`STRUCT`|[HttpWrapperHandleFunc](#httpwrapperhandlefunc)|暂无描述...
|
||||
|`STRUCT`|[HttpWrapper](#httpwrapper)|http 包装器
|
||||
|`STRUCT`|[HttpWrapperGroup](#httpwrappergroup)|http 包装器
|
||||
|`STRUCT`|[MessageType](#messagetype)|暂无描述...
|
||||
|`STRUCT`|[Message](#message)|服务器消息
|
||||
|`STRUCT`|[MultipleServer](#multipleserver)|暂无描述...
|
||||
|`STRUCT`|[Network](#network)|暂无描述...
|
||||
|`STRUCT`|[Option](#option)|暂无描述...
|
||||
|`STRUCT`|[Server](#server)|网络服务器
|
||||
|`INTERFACE`|[Service](#service)|兼容传统 service 设计模式的接口
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewBot(srv *Server, options ...BotOption) *Bot
|
||||
<span id="NewBot"></span>
|
||||
> 创建一个机器人,目前仅支持 Socket 服务器
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewBot(t *testing.T) {
|
||||
srv := server.New(server.NetworkWebsocket)
|
||||
srv.RegConnectionOpenedEvent(func(srv *server.Server, conn *server.Conn) {
|
||||
t.Logf("connection opened: %s", conn.GetID())
|
||||
conn.Close()
|
||||
conn.Write([]byte("hello"))
|
||||
})
|
||||
srv.RegConnectionClosedEvent(func(srv *server.Server, conn *server.Conn, err any) {
|
||||
t.Logf("connection closed: %s", conn.GetID())
|
||||
})
|
||||
srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
|
||||
t.Logf("connection %s receive packet: %s", conn.GetID(), string(packet))
|
||||
conn.Write([]byte("world"))
|
||||
})
|
||||
srv.RegStartFinishEvent(func(srv *server.Server) {
|
||||
bot := server.NewBot(srv, server.WithBotNetworkDelay(100, 20), server.WithBotWriter(func(bot *server.Bot) io.Writer {
|
||||
return &Writer{t: t, bot: bot}
|
||||
}))
|
||||
bot.JoinServer()
|
||||
time.Sleep(time.Second)
|
||||
bot.SendPacket([]byte("hello"))
|
||||
})
|
||||
_ = srv.Run(":9600")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func WithBotNetworkDelay(delay time.Duration, fluctuation time.Duration) BotOption
|
||||
<span id="WithBotNetworkDelay"></span>
|
||||
> 设置机器人网络延迟及波动范围
|
||||
> - delay 延迟
|
||||
> - fluctuation 波动范围
|
||||
|
||||
***
|
||||
#### func WithBotWriter(construction func (bot *Bot) io.Writer) BotOption
|
||||
<span id="WithBotWriter"></span>
|
||||
> 设置机器人写入器,默认为 os.Stdout
|
||||
|
||||
***
|
||||
#### func DefaultWebsocketUpgrader() *websocket.Upgrader
|
||||
<span id="DefaultWebsocketUpgrader"></span>
|
||||
|
||||
***
|
||||
#### func NewHttpHandleWrapper(srv *Server, packer ContextPacker[Context]) *Http[Context]
|
||||
<span id="NewHttpHandleWrapper"></span>
|
||||
> 创建一个新的 http 处理程序包装器
|
||||
> - 默认使用 server.HttpContext 作为上下文,如果需要依赖其作为新的上下文,可以通过 NewHttpContext 创建
|
||||
|
||||
***
|
||||
#### func NewHttpContext(ctx *gin.Context) *HttpContext
|
||||
<span id="NewHttpContext"></span>
|
||||
> 基于 gin.Context 创建一个新的 HttpContext
|
||||
|
||||
***
|
||||
#### func NewGinWrapper(server *gin.Engine, pack func (ctx *gin.Context) CTX) *HttpWrapper[CTX]
|
||||
<span id="NewGinWrapper"></span>
|
||||
> 创建 gin 包装器,用于对 NewHttpWrapper 函数的替代
|
||||
|
||||
***
|
||||
#### func HasMessageType(mt MessageType) bool
|
||||
<span id="HasMessageType"></span>
|
||||
> 检查是否存在指定的消息类型
|
||||
|
||||
***
|
||||
#### func NewMultipleServer(serverHandle ...func () ((addr string, srv *Server))) *MultipleServer
|
||||
<span id="NewMultipleServer"></span>
|
||||
|
||||
***
|
||||
#### func GetNetworks() []Network
|
||||
<span id="GetNetworks"></span>
|
||||
> 获取所有支持的网络模式
|
||||
|
||||
***
|
||||
#### func WithLowMessageDuration(duration time.Duration) Option
|
||||
<span id="WithLowMessageDuration"></span>
|
||||
> 通过指定慢消息时长的方式创建服务器,当消息处理时间超过指定时长时,将会输出 WARN 类型的日志
|
||||
> - 默认值为 DefaultLowMessageDuration
|
||||
> - 当 duration <= 0 时,表示关闭慢消息检测
|
||||
|
||||
***
|
||||
#### func WithAsyncLowMessageDuration(duration time.Duration) Option
|
||||
<span id="WithAsyncLowMessageDuration"></span>
|
||||
> 通过指定异步消息的慢消息时长的方式创建服务器,当消息处理时间超过指定时长时,将会输出 WARN 类型的日志
|
||||
> - 默认值为 DefaultAsyncLowMessageDuration
|
||||
> - 当 duration <= 0 时,表示关闭慢消息检测
|
||||
|
||||
***
|
||||
#### func WithWebsocketConnInitializer(initializer func (writer http.ResponseWriter, request *http.Request, conn *websocket.Conn) error) Option
|
||||
<span id="WithWebsocketConnInitializer"></span>
|
||||
> 通过 websocket 连接初始化的方式创建服务器,当 initializer 返回错误时,服务器将不会处理该连接的后续逻辑
|
||||
> - 该选项仅在创建 NetworkWebsocket 服务器时有效
|
||||
|
||||
***
|
||||
#### func WithWebsocketUpgrade(upgrader *websocket.Upgrader) Option
|
||||
<span id="WithWebsocketUpgrade"></span>
|
||||
> 通过指定 websocket.Upgrader 的方式创建服务器
|
||||
> - 默认值为 DefaultWebsocketUpgrader
|
||||
> - 该选项仅在创建 NetworkWebsocket 服务器时有效
|
||||
|
||||
***
|
||||
#### func WithConnWriteBufferSize(size int) Option
|
||||
<span id="WithConnWriteBufferSize"></span>
|
||||
> 通过连接写入缓冲区大小的方式创建服务器
|
||||
> - 默认值为 DefaultConnWriteBufferSize
|
||||
> - 设置合适的缓冲区大小可以提高服务器性能,但是会占用更多的内存
|
||||
|
||||
***
|
||||
#### func WithDispatcherBufferSize(size int) Option
|
||||
<span id="WithDispatcherBufferSize"></span>
|
||||
> 通过消息分发器缓冲区大小的方式创建服务器
|
||||
> - 默认值为 DefaultDispatcherBufferSize
|
||||
> - 设置合适的缓冲区大小可以提高服务器性能,但是会占用更多的内存
|
||||
|
||||
***
|
||||
#### func WithMessageStatistics(duration time.Duration, limit int) Option
|
||||
<span id="WithMessageStatistics"></span>
|
||||
> 通过消息统计的方式创建服务器
|
||||
> - 默认不开启,当 duration 和 limit 均大于 0 的时候,服务器将记录每 duration 期间的消息数量,并保留最多 limit 条
|
||||
|
||||
***
|
||||
#### func WithPacketWarnSize(size int) Option
|
||||
<span id="WithPacketWarnSize"></span>
|
||||
> 通过数据包大小警告的方式创建服务器,当数据包大小超过指定大小时,将会输出 WARN 类型的日志
|
||||
> - 默认值为 DefaultPacketWarnSize
|
||||
> - 当 size <= 0 时,表示不设置警告
|
||||
|
||||
***
|
||||
#### func WithLimitLife(t time.Duration) Option
|
||||
<span id="WithLimitLife"></span>
|
||||
> 通过限制最大生命周期的方式创建服务器
|
||||
> - 通常用于测试服务器,服务器将在到达最大生命周期时自动关闭
|
||||
|
||||
***
|
||||
#### func WithWebsocketWriteCompression() Option
|
||||
<span id="WithWebsocketWriteCompression"></span>
|
||||
> 通过数据写入压缩的方式创建Websocket服务器
|
||||
> - 默认不开启数据压缩
|
||||
|
||||
***
|
||||
#### func WithWebsocketCompression(level int) Option
|
||||
<span id="WithWebsocketCompression"></span>
|
||||
> 通过数据压缩的方式创建Websocket服务器
|
||||
> - 默认不开启数据压缩
|
||||
|
||||
***
|
||||
#### func WithDeadlockDetect(t time.Duration) Option
|
||||
<span id="WithDeadlockDetect"></span>
|
||||
> 通过死锁、死循环、永久阻塞检测的方式创建服务器
|
||||
> - 当检测到死锁、死循环、永久阻塞时,服务器将会生成 WARN 类型的日志,关键字为 "SuspectedDeadlock"
|
||||
> - 默认不开启死锁检测
|
||||
|
||||
***
|
||||
#### func WithDisableAsyncMessage() Option
|
||||
<span id="WithDisableAsyncMessage"></span>
|
||||
> 通过禁用异步消息的方式创建服务器
|
||||
|
||||
***
|
||||
#### func WithAsyncPoolSize(size int) Option
|
||||
<span id="WithAsyncPoolSize"></span>
|
||||
> 通过指定异步消息池大小的方式创建服务器
|
||||
> - 当通过 WithDisableAsyncMessage 禁用异步消息时,此选项无效
|
||||
> - 默认值为 DefaultAsyncPoolSize
|
||||
|
||||
***
|
||||
#### func WithWebsocketReadDeadline(t time.Duration) Option
|
||||
<span id="WithWebsocketReadDeadline"></span>
|
||||
> 设置 Websocket 读取超时时间
|
||||
> - 默认: DefaultWebsocketReadDeadline
|
||||
> - 当 t <= 0 时,表示不设置超时时间
|
||||
|
||||
***
|
||||
#### func WithTicker(poolSize int, size int, connSize int, autonomy bool) Option
|
||||
<span id="WithTicker"></span>
|
||||
> 通过定时器创建服务器,为服务器添加定时器功能
|
||||
> - poolSize:指定服务器定时器池大小,当池子内的定时器数量超出该值后,多余的定时器在释放时将被回收,该值小于等于 0 时将使用 timer.DefaultTickerPoolSize
|
||||
> - size:服务器定时器时间轮大小
|
||||
> - connSize:服务器连接定时器时间轮大小,当该值小于等于 0 的时候,在新连接建立时将不再为其创建定时器
|
||||
> - autonomy:定时器是否独立运行(独立运行的情况下不会作为服务器消息运行,会导致并发问题)
|
||||
|
||||
***
|
||||
#### func WithTLS(certFile string, keyFile string) Option
|
||||
<span id="WithTLS"></span>
|
||||
> 通过安全传输层协议TLS创建服务器
|
||||
> - 支持:Http、Websocket
|
||||
|
||||
***
|
||||
#### func WithGRPCServerOptions(options ...grpc.ServerOption) Option
|
||||
<span id="WithGRPCServerOptions"></span>
|
||||
> 通过GRPC的可选项创建GRPC服务器
|
||||
|
||||
***
|
||||
#### func WithWebsocketMessageType(messageTypes ...int) Option
|
||||
<span id="WithWebsocketMessageType"></span>
|
||||
> 设置仅支持特定类型的Websocket消息
|
||||
|
||||
***
|
||||
#### func WithPProf(pattern ...string) Option
|
||||
<span id="WithPProf"></span>
|
||||
> 通过性能分析工具PProf创建服务器
|
||||
|
||||
***
|
||||
#### func New(network Network, options ...Option) *Server
|
||||
<span id="New"></span>
|
||||
> 根据特定网络类型创建一个服务器
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleNew() {
|
||||
srv := server.New(server.NetworkWebsocket, server.WithLimitLife(time.Millisecond))
|
||||
srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
|
||||
conn.Write(packet)
|
||||
})
|
||||
if err := srv.Run(":9999"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
srv := server.New(server.NetworkWebsocket, server.WithPProf())
|
||||
srv.RegStartBeforeEvent(func(srv *server.Server) {
|
||||
fmt.Println("启动前")
|
||||
})
|
||||
srv.RegStartFinishEvent(func(srv *server.Server) {
|
||||
fmt.Println("启动完成")
|
||||
})
|
||||
srv.RegConnectionClosedEvent(func(srv *server.Server, conn *server.Conn, err any) {
|
||||
fmt.Println("关闭", conn.GetID(), err, "IncrCount", srv.GetOnlineCount())
|
||||
})
|
||||
srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
|
||||
conn.Write(packet)
|
||||
})
|
||||
if err := srv.Run(":9999"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func BindService(srv *Server, services ...Service)
|
||||
<span id="BindService"></span>
|
||||
> 绑定服务到特定 Server,被绑定的服务将会在 Server 初始化时执行 Service.OnInit 方法
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleBindService() {
|
||||
srv := server.New(server.NetworkNone, server.WithLimitLife(time.Second))
|
||||
server.BindService(srv, new(TestService))
|
||||
if err := srv.RunNone(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestBindService(t *testing.T) {
|
||||
srv := server.New(server.NetworkNone, server.WithLimitLife(time.Second))
|
||||
server.BindService(srv, new(TestService))
|
||||
if err := srv.RunNone(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### Bot `STRUCT`
|
||||
|
||||
```go
|
||||
type Bot struct {
|
||||
conn *Conn
|
||||
joined atomic.Bool
|
||||
}
|
||||
```
|
||||
#### func (*Bot) JoinServer()
|
||||
> 加入服务器
|
||||
***
|
||||
#### func (*Bot) LeaveServer()
|
||||
> 离开服务器
|
||||
***
|
||||
#### func (*Bot) SetNetworkDelay(delay time.Duration, fluctuation time.Duration)
|
||||
> 设置网络延迟和波动范围
|
||||
> - delay 延迟
|
||||
> - fluctuation 波动范围
|
||||
***
|
||||
#### func (*Bot) SetWriter(writer io.Writer)
|
||||
> 设置写入器
|
||||
***
|
||||
#### func (*Bot) SendPacket(packet []byte)
|
||||
> 发送数据包到服务器
|
||||
***
|
||||
#### func (*Bot) SendWSPacket(wst int, packet []byte)
|
||||
> 发送 WebSocket 数据包到服务器
|
||||
***
|
||||
### BotOption `STRUCT`
|
||||
|
||||
```go
|
||||
type BotOption func(bot *Bot)
|
||||
```
|
||||
### Conn `STRUCT`
|
||||
服务器连接单次消息的包装
|
||||
```go
|
||||
type Conn struct {
|
||||
*connection
|
||||
wst int
|
||||
ctx context.Context
|
||||
}
|
||||
```
|
||||
#### func (*Conn) Ticker() *timer.Ticker
|
||||
> 获取定时器
|
||||
***
|
||||
#### func (*Conn) GetServer() *Server
|
||||
> 获取服务器
|
||||
***
|
||||
#### func (*Conn) GetOpenTime() time.Time
|
||||
> 获取连接打开时间
|
||||
***
|
||||
#### func (*Conn) GetOnlineTime() time.Duration
|
||||
> 获取连接在线时长
|
||||
***
|
||||
#### func (*Conn) GetWebsocketRequest() *http.Request
|
||||
> 获取websocket请求
|
||||
***
|
||||
#### func (*Conn) IsBot() bool
|
||||
> 是否是机器人连接
|
||||
***
|
||||
#### func (*Conn) RemoteAddr() net.Addr
|
||||
> 获取远程地址
|
||||
***
|
||||
#### func (*Conn) GetID() string
|
||||
> 获取连接ID
|
||||
> - 为远程地址的字符串形式
|
||||
***
|
||||
#### func (*Conn) GetIP() string
|
||||
> 获取连接IP
|
||||
***
|
||||
#### func (*Conn) IsClosed() bool
|
||||
> 是否已经关闭
|
||||
***
|
||||
#### func (*Conn) SetData(key any, value any) *Conn
|
||||
> 设置连接数据,该数据将在连接关闭前始终存在
|
||||
***
|
||||
#### func (*Conn) GetData(key any) any
|
||||
> 获取连接数据
|
||||
***
|
||||
#### func (*Conn) ViewData() map[any]any
|
||||
> 查看只读的连接数据
|
||||
***
|
||||
#### func (*Conn) SetMessageData(key any, value any) *Conn
|
||||
> 设置消息数据,该数据将在消息处理完成后释放
|
||||
***
|
||||
#### func (*Conn) GetMessageData(key any) any
|
||||
> 获取消息数据
|
||||
***
|
||||
#### func (*Conn) ReleaseData() *Conn
|
||||
> 释放数据
|
||||
***
|
||||
#### func (*Conn) IsWebsocket() bool
|
||||
> 是否是websocket连接
|
||||
***
|
||||
#### func (*Conn) GetWST() int
|
||||
> 获取本次 websocket 消息类型
|
||||
> - 默认将与发送类型相同
|
||||
***
|
||||
#### func (*Conn) SetWST(wst int) *Conn
|
||||
> 设置本次 websocket 消息类型
|
||||
***
|
||||
#### func (*Conn) PushAsyncMessage(caller func () error, callback func (err error), mark ...log.Field)
|
||||
> 推送异步消息,该消息将通过 Server.PushShuntAsyncMessage 函数推送
|
||||
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
|
||||
***
|
||||
#### func (*Conn) PushUniqueAsyncMessage(name string, caller func () error, callback func (err error), mark ...log.Field)
|
||||
> 推送唯一异步消息,该消息将通过 Server.PushUniqueShuntAsyncMessage 函数推送
|
||||
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
|
||||
> - 不同的是当上一个相同的 unique 消息未执行完成时,将会忽略该消息
|
||||
***
|
||||
#### func (*Conn) Write(packet []byte, callback ...func (err error))
|
||||
> 向连接中写入数据
|
||||
***
|
||||
#### func (*Conn) Close(err ...error)
|
||||
> 关闭连接
|
||||
***
|
||||
### ConsoleParams `STRUCT`
|
||||
控制台参数
|
||||
```go
|
||||
type ConsoleParams map[string][]string
|
||||
```
|
||||
#### func (ConsoleParams) Get(key string) string
|
||||
> 获取参数值
|
||||
***
|
||||
#### func (ConsoleParams) GetValues(key string) []string
|
||||
> 获取参数值
|
||||
***
|
||||
#### func (ConsoleParams) GetValueNum(key string) int
|
||||
> 获取参数值数量
|
||||
***
|
||||
#### func (ConsoleParams) Has(key string) bool
|
||||
> 是否存在参数
|
||||
***
|
||||
#### func (ConsoleParams) Add(key string, value string)
|
||||
> 添加参数
|
||||
***
|
||||
#### func (ConsoleParams) Del(key string)
|
||||
> 删除参数
|
||||
***
|
||||
#### func (ConsoleParams) Clear()
|
||||
> 清空参数
|
||||
***
|
||||
### MessageReadyEventHandler `STRUCT`
|
||||
|
||||
```go
|
||||
type MessageReadyEventHandler func(srv *Server)
|
||||
```
|
||||
### Http `STRUCT`
|
||||
基于 gin.Engine 包装的 http 服务器
|
||||
```go
|
||||
type Http[Context any] struct {
|
||||
srv *Server
|
||||
*gin.Engine
|
||||
*HttpRouter[Context]
|
||||
}
|
||||
```
|
||||
#### func (*Http) Gin() *gin.Engine
|
||||
***
|
||||
### HttpContext `STRUCT`
|
||||
基于 gin.Context 的 http 请求上下文
|
||||
```go
|
||||
type HttpContext struct {
|
||||
*gin.Context
|
||||
}
|
||||
```
|
||||
#### func (*HttpContext) Gin() *gin.Context
|
||||
> 获取 gin.Context
|
||||
***
|
||||
#### func (*HttpContext) ReadTo(dest any) error
|
||||
> 读取请求数据到指定结构体,如果失败则返回错误
|
||||
***
|
||||
### HandlerFunc `STRUCT`
|
||||
|
||||
```go
|
||||
type HandlerFunc[Context any] func(ctx Context)
|
||||
```
|
||||
### ContextPacker `STRUCT`
|
||||
|
||||
```go
|
||||
type ContextPacker[Context any] func(ctx *gin.Context) Context
|
||||
```
|
||||
### HttpRouter `STRUCT`
|
||||
|
||||
```go
|
||||
type HttpRouter[Context any] struct {
|
||||
srv *Server
|
||||
group gin.IRouter
|
||||
packer ContextPacker[Context]
|
||||
}
|
||||
```
|
||||
#### func (*HttpRouter) Handle(httpMethod string, relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 使用给定的路径和方法注册新的请求句柄和中间件
|
||||
> - 最后一个处理程序应该是真正的处理程序,其他处理程序应该是可以而且应该在不同路由之间共享的中间件。
|
||||
***
|
||||
#### func (*HttpRouter) POST(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("POST", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) GET(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("GET", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) DELETE(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("DELETE", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) PATCH(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("PATCH", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) PUT(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("PUT", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) OPTIONS(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("OPTIONS", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) HEAD(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("HEAD", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) CONNECT(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("CONNECT", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) TRACE(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 是 Handle("TRACE", path, handlers) 的快捷方式
|
||||
***
|
||||
#### func (*HttpRouter) Any(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 注册一个匹配所有 HTTP 方法的路由
|
||||
> - GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
|
||||
***
|
||||
#### func (*HttpRouter) Match(methods []string, relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 注册一个匹配指定 HTTP 方法的路由
|
||||
> - GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
|
||||
***
|
||||
#### func (*HttpRouter) StaticFile(relativePath string, filepath string) *HttpRouter[Context]
|
||||
> 注册单个路由以便为本地文件系统的单个文件提供服务。
|
||||
> - 例如: StaticFile("favicon.ico", "./resources/favicon.ico")
|
||||
***
|
||||
#### func (*HttpRouter) StaticFileFS(relativePath string, filepath string, fs http.FileSystem) *HttpRouter[Context]
|
||||
> 与 `StaticFile` 类似,但可以使用自定义的 `http.FileSystem` 代替。
|
||||
> - 例如: StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false})
|
||||
> - 由于依赖于 gin.Engine 默认情况下使用:gin.Dir
|
||||
***
|
||||
#### func (*HttpRouter) Static(relativePath string, root string) *HttpRouter[Context]
|
||||
> 提供来自给定文件系统根目录的文件。
|
||||
> - 例如: Static("/static", "/var/www")
|
||||
***
|
||||
#### func (*HttpRouter) StaticFS(relativePath string, fs http.FileSystem) *HttpRouter[Context]
|
||||
> 与 `Static` 类似,但可以使用自定义的 `http.FileSystem` 代替。
|
||||
> - 例如: StaticFS("/static", Dir{"/var/www", false})
|
||||
> - 由于依赖于 gin.Engine 默认情况下使用:gin.Dir
|
||||
***
|
||||
#### func (*HttpRouter) Group(relativePath string, handlers ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 创建一个新的路由组。您应该添加所有具有共同中间件的路由。
|
||||
> - 例如: v1 := slf.Group("/v1")
|
||||
***
|
||||
#### func (*HttpRouter) Use(middleware ...HandlerFunc[Context]) *HttpRouter[Context]
|
||||
> 将中间件附加到路由组。
|
||||
***
|
||||
### HttpWrapperHandleFunc `STRUCT`
|
||||
|
||||
```go
|
||||
type HttpWrapperHandleFunc[CTX any] func(ctx CTX)
|
||||
```
|
||||
### HttpWrapper `STRUCT`
|
||||
http 包装器
|
||||
```go
|
||||
type HttpWrapper[CTX any] struct {
|
||||
server *gin.Engine
|
||||
packHandle func(ctx *gin.Context) CTX
|
||||
}
|
||||
```
|
||||
#### func (*HttpWrapper) Handle(httpMethod string, relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 处理请求
|
||||
***
|
||||
#### func (*HttpWrapper) Use(middleware ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 使用中间件
|
||||
***
|
||||
#### func (*HttpWrapper) GET(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 GET 请求
|
||||
***
|
||||
#### func (*HttpWrapper) POST(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 POST 请求
|
||||
***
|
||||
#### func (*HttpWrapper) DELETE(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 DELETE 请求
|
||||
***
|
||||
#### func (*HttpWrapper) PATCH(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 PATCH 请求
|
||||
***
|
||||
#### func (*HttpWrapper) PUT(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 PUT 请求
|
||||
***
|
||||
#### func (*HttpWrapper) OPTIONS(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 OPTIONS 请求
|
||||
***
|
||||
#### func (*HttpWrapper) HEAD(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 HEAD 请求
|
||||
***
|
||||
#### func (*HttpWrapper) Trace(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 Trace 请求
|
||||
***
|
||||
#### func (*HttpWrapper) Connect(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 Connect 请求
|
||||
***
|
||||
#### func (*HttpWrapper) Any(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册 Any 请求
|
||||
***
|
||||
#### func (*HttpWrapper) Match(methods []string, relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapper[CTX]
|
||||
> 注册与您声明的指定方法相匹配的路由。
|
||||
***
|
||||
#### func (*HttpWrapper) StaticFile(relativePath string, filepath string) *HttpWrapper[CTX]
|
||||
> 注册 StaticFile 请求
|
||||
***
|
||||
#### func (*HttpWrapper) Static(relativePath string, root string) *HttpWrapper[CTX]
|
||||
> 注册 Static 请求
|
||||
***
|
||||
#### func (*HttpWrapper) StaticFS(relativePath string, fs http.FileSystem) *HttpWrapper[CTX]
|
||||
> 注册 StaticFS 请求
|
||||
***
|
||||
#### func (*HttpWrapper) Group(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 创建一个新的路由组。您应该添加所有具有共同中间件的路由。
|
||||
***
|
||||
### HttpWrapperGroup `STRUCT`
|
||||
http 包装器
|
||||
```go
|
||||
type HttpWrapperGroup[CTX any] struct {
|
||||
wrapper *HttpWrapper[CTX]
|
||||
group *gin.RouterGroup
|
||||
}
|
||||
```
|
||||
#### func (*HttpWrapperGroup) Handle(httpMethod string, relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 处理请求
|
||||
***
|
||||
#### func (*HttpWrapperGroup) Use(middleware ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 使用中间件
|
||||
***
|
||||
#### func (*HttpWrapperGroup) GET(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 注册 GET 请求
|
||||
***
|
||||
#### func (*HttpWrapperGroup) POST(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 注册 POST 请求
|
||||
***
|
||||
#### func (*HttpWrapperGroup) DELETE(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 注册 DELETE 请求
|
||||
***
|
||||
#### func (*HttpWrapperGroup) PATCH(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 注册 PATCH 请求
|
||||
***
|
||||
#### func (*HttpWrapperGroup) PUT(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 注册 PUT 请求
|
||||
***
|
||||
#### func (*HttpWrapperGroup) OPTIONS(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 注册 OPTIONS 请求
|
||||
***
|
||||
#### func (*HttpWrapperGroup) Group(relativePath string, handlers ...HttpWrapperHandleFunc[CTX]) *HttpWrapperGroup[CTX]
|
||||
> 创建分组
|
||||
***
|
||||
### MessageType `STRUCT`
|
||||
|
||||
```go
|
||||
type MessageType byte
|
||||
```
|
||||
#### func (MessageType) String() string
|
||||
> 返回消息类型的字符串表示
|
||||
***
|
||||
### Message `STRUCT`
|
||||
服务器消息
|
||||
```go
|
||||
type Message struct {
|
||||
dis *dispatcher.Dispatcher[string, *Message]
|
||||
conn *Conn
|
||||
err error
|
||||
ordinaryHandler func()
|
||||
exceptionHandler func() error
|
||||
errHandler func(err error)
|
||||
marks []log.Field
|
||||
packet []byte
|
||||
producer string
|
||||
name string
|
||||
t MessageType
|
||||
}
|
||||
```
|
||||
#### func (*Message) GetProducer() string
|
||||
***
|
||||
#### func (*Message) MessageType() MessageType
|
||||
> 返回消息类型
|
||||
***
|
||||
#### func (*Message) String() string
|
||||
> 返回消息的字符串表示
|
||||
***
|
||||
### MultipleServer `STRUCT`
|
||||
|
||||
```go
|
||||
type MultipleServer struct {
|
||||
servers []*Server
|
||||
addresses []string
|
||||
exitEventHandles []func()
|
||||
}
|
||||
```
|
||||
#### func (*MultipleServer) Run()
|
||||
***
|
||||
#### func (*MultipleServer) RegExitEvent(handle func ())
|
||||
> 注册退出事件
|
||||
***
|
||||
#### func (*MultipleServer) OnExitEvent()
|
||||
***
|
||||
### Network `STRUCT`
|
||||
|
||||
```go
|
||||
type Network string
|
||||
```
|
||||
#### func (Network) IsSocket() bool
|
||||
> 返回当前服务器的网络模式是否为 Socket 模式
|
||||
***
|
||||
### Option `STRUCT`
|
||||
|
||||
```go
|
||||
type Option func(srv *Server)
|
||||
```
|
||||
### Server `STRUCT`
|
||||
网络服务器
|
||||
```go
|
||||
type Server struct {
|
||||
*event
|
||||
*runtime
|
||||
*option
|
||||
*connMgr
|
||||
dispatcherMgr *dispatcher.Manager[string, *Message]
|
||||
ginServer *gin.Engine
|
||||
httpServer *http.Server
|
||||
grpcServer *grpc.Server
|
||||
gServer *gNet
|
||||
multiple *MultipleServer
|
||||
ants *ants.Pool
|
||||
messagePool *hub.ObjectPool[*Message]
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
systemSignal chan os.Signal
|
||||
closeChannel chan struct{}
|
||||
multipleRuntimeErrorChan chan error
|
||||
messageCounter atomic.Int64
|
||||
addr string
|
||||
network Network
|
||||
closed uint32
|
||||
services []func()
|
||||
}
|
||||
```
|
||||
#### func (*Server) Run(addr string) (err error)
|
||||
> 使用特定地址运行服务器
|
||||
> - server.NetworkTcp (addr:":8888")
|
||||
> - server.NetworkTcp4 (addr:":8888")
|
||||
> - server.NetworkTcp6 (addr:":8888")
|
||||
> - server.NetworkUdp (addr:":8888")
|
||||
> - server.NetworkUdp4 (addr:":8888")
|
||||
> - server.NetworkUdp6 (addr:":8888")
|
||||
> - server.NetworkUnix (addr:"socketPath")
|
||||
> - server.NetworkHttp (addr:":8888")
|
||||
> - server.NetworkWebsocket (addr:":8888/ws")
|
||||
> - server.NetworkKcp (addr:":8888")
|
||||
> - server.NetworkNone (addr:"")
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleServer_Run() {
|
||||
srv := server.New(server.NetworkWebsocket, server.WithLimitLife(time.Millisecond))
|
||||
srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
|
||||
conn.Write(packet)
|
||||
})
|
||||
if err := srv.Run(":9999"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func (*Server) IsSocket() bool
|
||||
> 是否是 Socket 模式
|
||||
***
|
||||
#### func (*Server) RunNone() error
|
||||
> 是 Run("") 的简写,仅适用于运行 NetworkNone 服务器
|
||||
***
|
||||
#### func (*Server) Context() context.Context
|
||||
> 获取服务器上下文
|
||||
***
|
||||
#### func (*Server) TimeoutContext(timeout time.Duration) context.Context, context.CancelFunc
|
||||
> 获取服务器超时上下文,context.WithTimeout 的简写
|
||||
***
|
||||
#### func (*Server) Ticker() *timer.Ticker
|
||||
> 获取服务器定时器
|
||||
***
|
||||
#### func (*Server) Shutdown()
|
||||
> 主动停止运行服务器
|
||||
***
|
||||
#### func (*Server) GRPCServer() *grpc.Server
|
||||
> 当网络类型为 NetworkGRPC 时将被允许获取 grpc 服务器,否则将会发生 panic
|
||||
***
|
||||
#### func (*Server) HttpRouter() gin.IRouter
|
||||
> 当网络类型为 NetworkHttp 时将被允许获取路由器进行路由注册,否则将会发生 panic
|
||||
> - 通过该函数注册的路由将无法在服务器关闭时正常等待请求结束
|
||||
>
|
||||
> Deprecated: 从 Minotaur 0.0.29 开始,由于设计原因已弃用,该函数将直接返回 *gin.Server 对象,导致无法正常的对请求结束时进行处理
|
||||
***
|
||||
#### func (*Server) HttpServer() *Http[*HttpContext]
|
||||
> 替代 HttpRouter 的函数,返回一个 *Http[*HttpContext] 对象
|
||||
> - 通过该函数注册的路由将在服务器关闭时正常等待请求结束
|
||||
> - 如果需要自行包装 Context 对象,可以使用 NewHttpHandleWrapper 方法
|
||||
***
|
||||
#### func (*Server) GetMessageCount() int64
|
||||
> 获取当前服务器中消息的数量
|
||||
***
|
||||
#### func (*Server) UseShunt(conn *Conn, name string)
|
||||
> 切换连接所使用的消息分流渠道,当分流渠道 name 不存在时将会创建一个新的分流渠道,否则将会加入已存在的分流渠道
|
||||
> - 默认情况下,所有连接都使用系统通道进行消息分发,当指定消息分流渠道且为分流消息类型时,将会使用指定的消息分流渠道进行消息分发
|
||||
> - 分流渠道会在连接断开时标记为驱逐状态,当分流渠道中的所有消息处理完毕且没有新连接使用时,将会被清除
|
||||
***
|
||||
#### func (*Server) HasShunt(name string) bool
|
||||
> 检查特定消息分流渠道是否存在
|
||||
***
|
||||
#### func (*Server) GetConnCurrShunt(conn *Conn) string
|
||||
> 获取连接当前所使用的消息分流渠道
|
||||
***
|
||||
#### func (*Server) GetShuntNum() int
|
||||
> 获取消息分流渠道数量
|
||||
***
|
||||
#### func (*Server) PushSystemMessage(handler func (), mark ...log.Field)
|
||||
> 向服务器中推送 MessageTypeSystem 消息
|
||||
> - 系统消息仅包含一个可执行函数,将在系统分发器中执行
|
||||
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
|
||||
***
|
||||
#### func (*Server) PushAsyncMessage(caller func () error, callback func (err error), mark ...log.Field)
|
||||
> 向服务器中推送 MessageTypeAsync 消息
|
||||
> - 异步消息将在服务器的异步消息队列中进行处理,处理完成 caller 的阻塞操作后,将会通过系统消息执行 callback 函数
|
||||
> - callback 函数将在异步消息处理完成后进行调用,无论过程是否产生 err,都将被执行,允许为 nil
|
||||
> - 需要注意的是,为了避免并发问题,caller 函数请仅处理阻塞操作,其他操作应该在 callback 函数中进行
|
||||
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
|
||||
***
|
||||
#### func (*Server) PushShuntAsyncMessage(conn *Conn, caller func () error, callback func (err error), mark ...log.Field)
|
||||
> 向特定分发器中推送 MessageTypeAsync 消息,消息执行与 MessageTypeAsync 一致
|
||||
> - 需要注意的是,当未指定 UseShunt 时,将会通过 PushAsyncMessage 进行转发
|
||||
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
|
||||
***
|
||||
#### func (*Server) PushPacketMessage(conn *Conn, wst int, packet []byte, mark ...log.Field)
|
||||
> 向服务器中推送 MessageTypePacket 消息
|
||||
> - 当存在 UseShunt 的选项时,将会根据选项中的 shuntMatcher 进行分发,否则将在系统分发器中处理消息
|
||||
***
|
||||
#### func (*Server) PushTickerMessage(name string, caller func (), mark ...log.Field)
|
||||
> 向服务器中推送 MessageTypeTicker 消息
|
||||
> - 通过该函数推送定时消息,当消息触发时将在系统分发器中处理消息
|
||||
> - 可通过 timer.Ticker 或第三方定时器将执行函数(caller)推送到该消息中进行处理,可有效的避免线程安全问题
|
||||
> - 参数 name 仅用作标识该定时器名称
|
||||
>
|
||||
> 定时消息执行不会有特殊的处理,仅标记为定时任务,也就是允许将各类函数通过该消息发送处理,但是并不建议
|
||||
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
|
||||
***
|
||||
#### func (*Server) PushShuntTickerMessage(conn *Conn, name string, caller func (), mark ...log.Field)
|
||||
> 向特定分发器中推送 MessageTypeTicker 消息,消息执行与 MessageTypeTicker 一致
|
||||
> - 需要注意的是,当未指定 UseShunt 时,将会通过 PushTickerMessage 进行转发
|
||||
> - mark 为可选的日志标记,当发生异常时,将会在日志中进行体现
|
||||
***
|
||||
#### func (*Server) PushUniqueAsyncMessage(unique string, caller func () error, callback func (err error), mark ...log.Field)
|
||||
> 向服务器中推送 MessageTypeAsync 消息,消息执行与 MessageTypeAsync 一致
|
||||
> - 不同的是当上一个相同的 unique 消息未执行完成时,将会忽略该消息
|
||||
***
|
||||
#### func (*Server) PushUniqueShuntAsyncMessage(conn *Conn, unique string, caller func () error, callback func (err error), mark ...log.Field)
|
||||
> 向特定分发器中推送 MessageTypeAsync 消息,消息执行与 MessageTypeAsync 一致
|
||||
> - 需要注意的是,当未指定 UseShunt 时,将会通过系统分流渠道进行转发
|
||||
> - 不同的是当上一个相同的 unique 消息未执行完成时,将会忽略该消息
|
||||
***
|
||||
#### func (*Server) PushShuntMessage(conn *Conn, caller func (), mark ...log.Field)
|
||||
> 向特定分发器中推送 MessageTypeShunt 消息,消息执行与 MessageTypeSystem 一致,不同的是将会在特定分发器中执行
|
||||
***
|
||||
#### func (*Server) GetDurationMessageCount() int64
|
||||
> 获取当前 WithMessageStatistics 设置的 duration 期间的消息量
|
||||
***
|
||||
#### func (*Server) GetDurationMessageCountByOffset(offset int) int64
|
||||
> 获取特定偏移次数的 WithMessageStatistics 设置的 duration 期间的消息量
|
||||
> - 该值小于 0 时,将与 GetDurationMessageCount 无异,否则将返回 +n 个期间的消息量,例如 duration 为 1 分钟,limit 为 10,那么 offset 为 1 的情况下,获取的则是上一分钟消息量
|
||||
***
|
||||
#### func (*Server) GetAllDurationMessageCount() []int64
|
||||
> 获取所有 WithMessageStatistics 设置的 duration 期间的消息量
|
||||
***
|
||||
#### func (*Server) HasMessageStatistics() bool
|
||||
> 是否了开启消息统计
|
||||
***
|
||||
### Service `INTERFACE`
|
||||
兼容传统 service 设计模式的接口
|
||||
```go
|
||||
type Service interface {
|
||||
OnInit(srv *Server)
|
||||
}
|
||||
```
|
|
@ -0,0 +1,265 @@
|
|||
# Client
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewClient](#NewClient)|创建客户端
|
||||
|[CloneClient](#CloneClient)|克隆客户端
|
||||
|[NewTCP](#NewTCP)|暂无描述...
|
||||
|[NewUnixDomainSocket](#NewUnixDomainSocket)|暂无描述...
|
||||
|[NewWebsocket](#NewWebsocket)|创建 websocket 客户端
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Client](#client)|客户端
|
||||
|`INTERFACE`|[Core](#core)|暂无描述...
|
||||
|`STRUCT`|[ConnectionClosedEventHandle](#connectionclosedeventhandle)|暂无描述...
|
||||
|`STRUCT`|[Packet](#packet)|暂无描述...
|
||||
|`STRUCT`|[TCP](#tcp)|暂无描述...
|
||||
|`STRUCT`|[UnixDomainSocket](#unixdomainsocket)|暂无描述...
|
||||
|`STRUCT`|[Websocket](#websocket)|websocket 客户端
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewClient(core Core) *Client
|
||||
<span id="NewClient"></span>
|
||||
> 创建客户端
|
||||
|
||||
***
|
||||
#### func CloneClient(client *Client) *Client
|
||||
<span id="CloneClient"></span>
|
||||
> 克隆客户端
|
||||
|
||||
***
|
||||
#### func NewTCP(addr string) *Client
|
||||
<span id="NewTCP"></span>
|
||||
|
||||
***
|
||||
#### func NewUnixDomainSocket(addr string) *Client
|
||||
<span id="NewUnixDomainSocket"></span>
|
||||
|
||||
***
|
||||
#### func NewWebsocket(addr string) *Client
|
||||
<span id="NewWebsocket"></span>
|
||||
> 创建 websocket 客户端
|
||||
|
||||
***
|
||||
### Client `STRUCT`
|
||||
客户端
|
||||
```go
|
||||
type Client struct {
|
||||
*events
|
||||
core Core
|
||||
mutex sync.Mutex
|
||||
closed bool
|
||||
pool *hub.ObjectPool[*Packet]
|
||||
loop *writeloop.Channel[*Packet]
|
||||
loopBufferSize int
|
||||
block chan struct{}
|
||||
}
|
||||
```
|
||||
#### func (*Client) Run(block ...bool) error
|
||||
> 运行客户端,当客户端已运行时,会先关闭客户端再重新运行
|
||||
> - block 以阻塞方式运行
|
||||
***
|
||||
#### func (*Client) RunByBufferSize(size int, block ...bool) error
|
||||
> 指定写入循环缓冲区大小运行客户端,当客户端已运行时,会先关闭客户端再重新运行
|
||||
> - block 以阻塞方式运行
|
||||
***
|
||||
#### func (*Client) IsConnected() bool
|
||||
> 是否已连接
|
||||
***
|
||||
#### func (*Client) Close(err ...error)
|
||||
> 关闭
|
||||
***
|
||||
#### func (*Client) WriteWS(wst int, packet []byte, callback ...func (err error))
|
||||
> 向连接中写入指定 websocket 数据类型
|
||||
> - wst: websocket模式中指定消息类型
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestClient_WriteWS(t *testing.T) {
|
||||
var wait sync.WaitGroup
|
||||
wait.Add(1)
|
||||
srv := server.New(server.NetworkWebsocket)
|
||||
srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
|
||||
srv.Shutdown()
|
||||
})
|
||||
srv.RegStopEvent(func(srv *server.Server) {
|
||||
wait.Done()
|
||||
})
|
||||
srv.RegMessageReadyEvent(func(srv *server.Server) {
|
||||
cli := client.NewWebsocket("ws://127.0.0.1:9999")
|
||||
cli.RegConnectionOpenedEvent(func(conn *client.Client) {
|
||||
conn.WriteWS(2, []byte("Hello"))
|
||||
})
|
||||
if err := cli.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
if err := srv.Run(":9999"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wait.Wait()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Client) Write(packet []byte, callback ...func (err error))
|
||||
> 向连接中写入数据
|
||||
***
|
||||
#### func (*Client) GetServerAddr() string
|
||||
> 获取服务器地址
|
||||
***
|
||||
### Core `INTERFACE`
|
||||
|
||||
```go
|
||||
type Core interface {
|
||||
Run(runState chan error, receive func(wst int, packet []byte))
|
||||
Write(packet *Packet) error
|
||||
Close()
|
||||
GetServerAddr() string
|
||||
Clone() Core
|
||||
}
|
||||
```
|
||||
### ConnectionClosedEventHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type ConnectionClosedEventHandle func(conn *Client, err any)
|
||||
```
|
||||
### Packet `STRUCT`
|
||||
|
||||
```go
|
||||
type Packet struct {
|
||||
wst int
|
||||
data []byte
|
||||
callback func(err error)
|
||||
}
|
||||
```
|
||||
### TCP `STRUCT`
|
||||
|
||||
```go
|
||||
type TCP struct {
|
||||
conn net.Conn
|
||||
addr string
|
||||
closed bool
|
||||
}
|
||||
```
|
||||
#### func (*TCP) Run(runState chan error, receive func (wst int, packet []byte))
|
||||
***
|
||||
#### func (*TCP) Write(packet *Packet) error
|
||||
***
|
||||
#### func (*TCP) Close()
|
||||
***
|
||||
#### func (*TCP) GetServerAddr() string
|
||||
***
|
||||
#### func (*TCP) Clone() Core
|
||||
***
|
||||
### UnixDomainSocket `STRUCT`
|
||||
|
||||
```go
|
||||
type UnixDomainSocket struct {
|
||||
conn net.Conn
|
||||
addr string
|
||||
closed bool
|
||||
}
|
||||
```
|
||||
#### func (*UnixDomainSocket) Run(runState chan error, receive func (wst int, packet []byte))
|
||||
***
|
||||
#### func (*UnixDomainSocket) Write(packet *Packet) error
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestUnixDomainSocket_Write(t *testing.T) {
|
||||
var closed = make(chan struct{})
|
||||
srv := server.New(server.NetworkUnix)
|
||||
srv.RegConnectionReceivePacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte) {
|
||||
t.Log(string(packet))
|
||||
conn.Write(packet)
|
||||
})
|
||||
srv.RegStartFinishEvent(func(srv *server.Server) {
|
||||
time.Sleep(time.Second)
|
||||
cli := client.NewUnixDomainSocket("./test.sock")
|
||||
cli.RegConnectionOpenedEvent(func(conn *client.Client) {
|
||||
conn.Write([]byte("Hello~"))
|
||||
})
|
||||
cli.RegConnectionReceivePacketEvent(func(conn *client.Client, wst int, packet []byte) {
|
||||
t.Log(packet)
|
||||
closed <- struct{}{}
|
||||
})
|
||||
if err := cli.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
go func() {
|
||||
if err := srv.Run("./test.sock"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
<-closed
|
||||
srv.Shutdown()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*UnixDomainSocket) Close()
|
||||
***
|
||||
#### func (*UnixDomainSocket) GetServerAddr() string
|
||||
***
|
||||
#### func (*UnixDomainSocket) Clone() Core
|
||||
***
|
||||
### Websocket `STRUCT`
|
||||
websocket 客户端
|
||||
```go
|
||||
type Websocket struct {
|
||||
addr string
|
||||
conn *websocket.Conn
|
||||
closed bool
|
||||
mu sync.Mutex
|
||||
}
|
||||
```
|
||||
#### func (*Websocket) Run(runState chan error, receive func (wst int, packet []byte))
|
||||
***
|
||||
#### func (*Websocket) Write(packet *Packet) error
|
||||
***
|
||||
#### func (*Websocket) Close()
|
||||
***
|
||||
#### func (*Websocket) GetServerAddr() string
|
||||
***
|
||||
#### func (*Websocket) Clone() Core
|
||||
***
|
|
@ -0,0 +1,249 @@
|
|||
# Gateway
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
gateway 是用于处理服务器消息的网关模块,适用于对客户端消息进行处理、转发的情况。
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewEndpoint](#NewEndpoint)|创建网关端点
|
||||
|[WithEndpointStateEvaluator](#WithEndpointStateEvaluator)|设置端点健康值评估函数
|
||||
|[WithEndpointConnectionPoolSize](#WithEndpointConnectionPoolSize)|设置端点连接池大小
|
||||
|[WithEndpointReconnectInterval](#WithEndpointReconnectInterval)|设置端点重连间隔
|
||||
|[NewGateway](#NewGateway)|基于 server.Server 创建 Gateway 网关服务器
|
||||
|[WithEndpointSelector](#WithEndpointSelector)|设置端点选择器
|
||||
|[MarshalGatewayOutPacket](#MarshalGatewayOutPacket)|将数据包转换为网关出网数据包
|
||||
|[UnmarshalGatewayOutPacket](#UnmarshalGatewayOutPacket)|将网关出网数据包转换为数据包
|
||||
|[MarshalGatewayInPacket](#MarshalGatewayInPacket)|将数据包转换为网关入网数据包
|
||||
|[UnmarshalGatewayInPacket](#UnmarshalGatewayInPacket)|将网关入网数据包转换为数据包
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Endpoint](#endpoint)|网关端点
|
||||
|`STRUCT`|[EndpointOption](#endpointoption)|网关端点选项
|
||||
|`STRUCT`|[ConnectionOpenedEventHandle](#connectionopenedeventhandle)|暂无描述...
|
||||
|`STRUCT`|[EndpointSelector](#endpointselector)|暂无描述...
|
||||
|`STRUCT`|[Gateway](#gateway)|基于 server.Server 实现的网关服务器
|
||||
|`STRUCT`|[Option](#option)|网关选项
|
||||
|`INTERFACE`|[Scanner](#scanner)|端点扫描器
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewEndpoint(name string, cli *client.Client, options ...EndpointOption) *Endpoint
|
||||
<span id="NewEndpoint"></span>
|
||||
> 创建网关端点
|
||||
|
||||
***
|
||||
#### func WithEndpointStateEvaluator(evaluator func (costUnixNano float64) float64) EndpointOption
|
||||
<span id="WithEndpointStateEvaluator"></span>
|
||||
> 设置端点健康值评估函数
|
||||
|
||||
***
|
||||
#### func WithEndpointConnectionPoolSize(size int) EndpointOption
|
||||
<span id="WithEndpointConnectionPoolSize"></span>
|
||||
> 设置端点连接池大小
|
||||
> - 默认为 DefaultEndpointConnectionPoolSize
|
||||
> - 端点连接池大小决定了网关服务器与端点服务器建立的连接数,如果 <= 0 则会使用默认值
|
||||
> - 在网关服务器中,多个客户端在发送消息到端点服务器时,会共用一个连接,适当的增大连接池大小可以提高网关服务器的承载能力
|
||||
|
||||
***
|
||||
#### func WithEndpointReconnectInterval(interval time.Duration) EndpointOption
|
||||
<span id="WithEndpointReconnectInterval"></span>
|
||||
> 设置端点重连间隔
|
||||
> - 默认为 DefaultEndpointReconnectInterval
|
||||
> - 端点在连接失败后会在该间隔后重连,如果 <= 0 则不会重连
|
||||
|
||||
***
|
||||
#### func NewGateway(srv *server.Server, scanner Scanner, options ...Option) *Gateway
|
||||
<span id="NewGateway"></span>
|
||||
> 基于 server.Server 创建 Gateway 网关服务器
|
||||
|
||||
***
|
||||
#### func WithEndpointSelector(selector EndpointSelector) Option
|
||||
<span id="WithEndpointSelector"></span>
|
||||
> 设置端点选择器
|
||||
> - 默认情况下,网关会随机选择一个端点作为目标,如果需要自定义端点选择器,可以通过该选项设置
|
||||
|
||||
***
|
||||
#### func MarshalGatewayOutPacket(addr string, packet []byte) []byte, error
|
||||
<span id="MarshalGatewayOutPacket"></span>
|
||||
> 将数据包转换为网关出网数据包
|
||||
> - | identifier(4) | ipv4(4) | port(2) | packet |
|
||||
|
||||
***
|
||||
#### func UnmarshalGatewayOutPacket(data []byte) (addr string, packet []byte, err error)
|
||||
<span id="UnmarshalGatewayOutPacket"></span>
|
||||
> 将网关出网数据包转换为数据包
|
||||
> - | identifier(4) | ipv4(4) | port(2) | packet |
|
||||
|
||||
***
|
||||
#### func MarshalGatewayInPacket(addr string, currentTime int64, packet []byte) []byte, error
|
||||
<span id="MarshalGatewayInPacket"></span>
|
||||
> 将数据包转换为网关入网数据包
|
||||
> - | ipv4(4) | port(2) | cost(4) | packet |
|
||||
|
||||
***
|
||||
#### func UnmarshalGatewayInPacket(data []byte) (addr string, sendTime int64, packet []byte, err error)
|
||||
<span id="UnmarshalGatewayInPacket"></span>
|
||||
> 将网关入网数据包转换为数据包
|
||||
> - | ipv4(4) | port(2) | cost(4) | packet |
|
||||
|
||||
***
|
||||
### Endpoint `STRUCT`
|
||||
网关端点
|
||||
- 每一个端点均表示了一个目标服务,网关会将数据包转发到该端点,由该端点负责将数据包转发到目标服务。
|
||||
- 每个端点会建立一个连接池,默认大小为 DefaultEndpointConnectionPoolSize,可通过 WithEndpointConnectionPoolSize 进行设置。
|
||||
- 网关在转发数据包时会自行根据延迟维护端点健康值,端点健康值越高,网关越倾向于将数据包转发到该端点。
|
||||
- 端点支持连接未中断前始终将数据包转发到特定端点,这样可以保证连接的状态维持。
|
||||
|
||||
连接池:
|
||||
- 连接池大小决定了网关服务器与端点服务器建立的连接数,例如当连接池大小为 1 时,那么所有连接到该端点的客户端都会共用一个连接。
|
||||
- 连接池的设计可以突破单机理论 65535 个 WebSocket 客户端的限制,适当的增大连接池大小可以提高网关服务器的承载能力。
|
||||
```go
|
||||
type Endpoint struct {
|
||||
gateway *Gateway
|
||||
client []*client.Client
|
||||
name string
|
||||
address string
|
||||
state atomic.Float64
|
||||
evaluator func(costUnixNano float64) float64
|
||||
connections *haxmap.Map[string, *server.Conn]
|
||||
rci time.Duration
|
||||
cps int
|
||||
}
|
||||
```
|
||||
#### func (*Endpoint) GetName() string
|
||||
> 获取端点名称
|
||||
***
|
||||
#### func (*Endpoint) GetAddress() string
|
||||
> 获取端点地址
|
||||
***
|
||||
#### func (*Endpoint) GetState() float64
|
||||
> 获取端点健康值
|
||||
***
|
||||
#### func (*Endpoint) Forward(conn *server.Conn, packet []byte, callback ...func (err error))
|
||||
> 转发数据包到该端点
|
||||
> - 端点在处理数据包时,应区分数据包为普通直连数据包还是网关数据包。可通过 UnmarshalGatewayOutPacket 进行数据包解析,当解析失败且无其他数据包协议时,可认为该数据包为普通直连数据包。
|
||||
***
|
||||
### EndpointOption `STRUCT`
|
||||
网关端点选项
|
||||
```go
|
||||
type EndpointOption func(endpoint *Endpoint)
|
||||
```
|
||||
### ConnectionOpenedEventHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type ConnectionOpenedEventHandle func(gateway *Gateway, conn *server.Conn)
|
||||
```
|
||||
### EndpointSelector `STRUCT`
|
||||
|
||||
```go
|
||||
type EndpointSelector func(endpoints []*Endpoint) *Endpoint
|
||||
```
|
||||
### Gateway `STRUCT`
|
||||
基于 server.Server 实现的网关服务器
|
||||
- 网关服务器是一个特殊的服务器,它会通过扫描器扫描端点列表,然后连接到端点列表中的所有端点,当端点连接成功后,网关服务器会将客户端的连接数据转发到端点服务器
|
||||
- 由于该网关为多个客户端共享一个端点的连接,所以不会受限于单机 65535 个端口的限制
|
||||
- 需要注意的是,网关可以通过扫描器得到每个端点需要建立多少个连接,该连接总数将受限与 65535 个端口的限制
|
||||
|
||||
一些特性:
|
||||
- 支持 server.Server 所支持的所有 Socket 网络类型
|
||||
- 支持将客户端网络类型进行不同的转换,例如:客户端使用 Websocket 连接,但是网关服务器可以将其转换为 TCP 端点的连接
|
||||
- 支持客户端消息绑定,在客户端未断开连接的情况下,可以将客户端的连接绑定到某个端点,这样该客户端的所有消息都会转发到该端点
|
||||
- 根据端点延迟实时调整端点状态评分,根据评分选择最优的端点,默认评分算法为:1 / (1 + 1.5 * ${DelaySeconds})
|
||||
```go
|
||||
type Gateway struct {
|
||||
*events
|
||||
srv *server.Server
|
||||
scanner Scanner
|
||||
es map[string]map[string]*Endpoint
|
||||
esm sync.Mutex
|
||||
ess EndpointSelector
|
||||
closed bool
|
||||
running bool
|
||||
cce map[string]*Endpoint
|
||||
cceLock sync.RWMutex
|
||||
}
|
||||
```
|
||||
#### func (*Gateway) Run(addr string) error
|
||||
> 运行网关
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestGateway_Run(t *testing.T) {
|
||||
gw := gateway.NewGateway(server.New(server.NetworkWebsocket, server.WithDeadlockDetect(time.Second*3)), new(Scanner))
|
||||
gw.RegConnectionReceivePacketEventHandle(func(gateway *gateway.Gateway, conn *server.Conn, packet []byte) {
|
||||
endpoint, err := gateway.GetConnEndpoint("test", conn)
|
||||
if err == nil {
|
||||
endpoint.Forward(conn, packet)
|
||||
}
|
||||
})
|
||||
gw.RegEndpointConnectReceivePacketEventHandle(func(gateway *gateway.Gateway, endpoint *gateway.Endpoint, conn *server.Conn, packet []byte) {
|
||||
conn.Write(packet)
|
||||
})
|
||||
if err := gw.Run(":8888"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Gateway) Shutdown()
|
||||
> 关闭网关
|
||||
***
|
||||
#### func (*Gateway) Server() *server.Server
|
||||
> 获取网关服务器核心
|
||||
***
|
||||
#### func (*Gateway) GetEndpoint(name string) *Endpoint, error
|
||||
> 获取一个可用的端点
|
||||
> - name: 端点名称
|
||||
***
|
||||
#### func (*Gateway) GetConnEndpoint(name string, conn *server.Conn) *Endpoint, error
|
||||
> 获取一个可用的端点,如果客户端已经连接到了某个端点,将优先返回该端点
|
||||
> - 当连接到的端点不可用或没有连接记录时,效果同 GetEndpoint 相同
|
||||
> - 当连接行为为有状态时,推荐使用该方法
|
||||
***
|
||||
#### func (*Gateway) SwitchEndpoint(source *Endpoint, dest *Endpoint)
|
||||
> 将端点端点的所有连接切换到另一个端点
|
||||
***
|
||||
### Option `STRUCT`
|
||||
网关选项
|
||||
```go
|
||||
type Option func(gateway *Gateway)
|
||||
```
|
||||
### Scanner `INTERFACE`
|
||||
端点扫描器
|
||||
```go
|
||||
type Scanner interface {
|
||||
GetEndpoints() ([]*Endpoint, error)
|
||||
GetInterval() time.Duration
|
||||
}
|
||||
```
|
||||
#### func (*Scanner) GetEndpoints() []*gateway.Endpoint, error
|
||||
***
|
||||
#### func (*Scanner) GetInterval() time.Duration
|
||||
***
|
|
@ -0,0 +1,239 @@
|
|||
# Dispatcher
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewDispatcher](#NewDispatcher)|创建一个新的消息分发器 Dispatcher 实例
|
||||
|[NewManager](#NewManager)|生成消息分发器管理器
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Action](#action)|消息分发器操作器,用于暴露外部可操作的消息分发器函数
|
||||
|`STRUCT`|[Handler](#handler)|消息处理器
|
||||
|`STRUCT`|[Dispatcher](#dispatcher)|用于服务器消息处理的消息分发器
|
||||
|`STRUCT`|[Manager](#manager)|消息分发器管理器
|
||||
|`INTERFACE`|[Message](#message)|暂无描述...
|
||||
|`INTERFACE`|[Producer](#producer)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewDispatcher(bufferSize int, name string, handler Handler[P, M]) *Dispatcher[P, M]
|
||||
<span id="NewDispatcher"></span>
|
||||
> 创建一个新的消息分发器 Dispatcher 实例
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleNewDispatcher() {
|
||||
m := new(atomic.Int64)
|
||||
fm := new(atomic.Int64)
|
||||
w := new(sync.WaitGroup)
|
||||
w.Add(1)
|
||||
d := dispatcher.NewDispatcher(1024, "example-dispatcher", func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
m.Add(1)
|
||||
})
|
||||
d.SetClosedHandler(func(dispatcher *dispatcher.Action[string, *TestMessage]) {
|
||||
w.Done()
|
||||
})
|
||||
var producers = []string{"producer1", "producer2", "producer3"}
|
||||
for i := 0; i < len(producers); i++ {
|
||||
p := producers[i]
|
||||
for i := 0; i < 10; i++ {
|
||||
d.Put(&TestMessage{producer: p})
|
||||
}
|
||||
d.SetProducerDoneHandler(p, func(p string, dispatcher *dispatcher.Action[string, *TestMessage]) {
|
||||
fm.Add(1)
|
||||
})
|
||||
}
|
||||
d.Start()
|
||||
d.Expel()
|
||||
w.Wait()
|
||||
fmt.Println(fmt.Sprintf("producer num: %d, producer done: %d, finished: %d", len(producers), fm.Load(), m.Load()))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewDispatcher(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
bufferSize int
|
||||
handler dispatcher.Handler[string, *TestMessage]
|
||||
shouldPanic bool
|
||||
}{{name: "TestNewDispatcher_BufferSize0AndHandlerNil", bufferSize: 0, handler: nil, shouldPanic: true}, {name: "TestNewDispatcher_BufferSize0AndHandlerNotNil", bufferSize: 0, handler: func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
}, shouldPanic: true}, {name: "TestNewDispatcher_BufferSize1AndHandlerNil", bufferSize: 1, handler: nil, shouldPanic: true}, {name: "TestNewDispatcher_BufferSize1AndHandlerNotNil", bufferSize: 1, handler: func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
}, shouldPanic: false}}
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil && !c.shouldPanic {
|
||||
t.Errorf("NewDispatcher() should not panic, but panic: %v", r)
|
||||
}
|
||||
}()
|
||||
dispatcher.NewDispatcher(c.bufferSize, c.name, c.handler)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func NewManager(bufferSize int, handler Handler[P, M]) *Manager[P, M]
|
||||
<span id="NewManager"></span>
|
||||
> 生成消息分发器管理器
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleNewManager() {
|
||||
mgr := dispatcher.NewManager[string, *TestMessage](10124*16, func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
})
|
||||
mgr.BindProducer("player_001", "shunt-001")
|
||||
mgr.BindProducer("player_002", "shunt-002")
|
||||
mgr.BindProducer("player_003", "shunt-sys")
|
||||
mgr.BindProducer("player_004", "shunt-sys")
|
||||
mgr.UnBindProducer("player_001")
|
||||
mgr.UnBindProducer("player_002")
|
||||
mgr.UnBindProducer("player_003")
|
||||
mgr.UnBindProducer("player_004")
|
||||
mgr.Wait()
|
||||
fmt.Println("done")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewManager(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
bufferSize int
|
||||
handler dispatcher.Handler[string, *TestMessage]
|
||||
shouldPanic bool
|
||||
}{{name: "TestNewManager_BufferSize0AndHandlerNil", bufferSize: 0, handler: nil, shouldPanic: true}, {name: "TestNewManager_BufferSize0AndHandlerNotNil", bufferSize: 0, handler: func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
}, shouldPanic: true}, {name: "TestNewManager_BufferSize1AndHandlerNil", bufferSize: 1, handler: nil, shouldPanic: true}, {name: "TestNewManager_BufferSize1AndHandlerNotNil", bufferSize: 1, handler: func(dispatcher *dispatcher.Dispatcher[string, *TestMessage], message *TestMessage) {
|
||||
}, shouldPanic: false}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil && !c.shouldPanic {
|
||||
t.Errorf("NewManager() should not panic, but panic: %v", r)
|
||||
}
|
||||
}()
|
||||
dispatcher.NewManager[string, *TestMessage](c.bufferSize, c.handler)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### Action `STRUCT`
|
||||
消息分发器操作器,用于暴露外部可操作的消息分发器函数
|
||||
```go
|
||||
type Action[P Producer, M Message[P]] struct {
|
||||
unlock bool
|
||||
d *Dispatcher[P, M]
|
||||
}
|
||||
```
|
||||
### Handler `STRUCT`
|
||||
消息处理器
|
||||
```go
|
||||
type Handler[P Producer, M Message[P]] func(dispatcher *Dispatcher[P, M], message M)
|
||||
```
|
||||
### Dispatcher `STRUCT`
|
||||
用于服务器消息处理的消息分发器
|
||||
|
||||
这个消息分发器为并发安全的生产者和消费者模型,生产者可以是任意类型,消费者必须是 Message 接口的实现。
|
||||
生产者可以通过 Put 方法并发安全地将消息放入消息分发器,消息执行过程不会阻塞到 Put 方法,同时允许在 Start 方法之前调用 Put 方法。
|
||||
在执行 Start 方法后,消息分发器会阻塞地从消息缓冲区中读取消息,然后执行消息处理器,消息处理器的执行过程不会阻塞到消息的生产。
|
||||
|
||||
为了保证消息不丢失,内部采用了 buffer.RingUnbounded 作为缓冲区实现,并且消息分发器不提供 Close 方法。
|
||||
如果需要关闭消息分发器,可以通过 Expel 方法设置驱逐计划,当消息分发器中没有任何消息时,将会被释放。
|
||||
同时,也可以使用 UnExpel 方法取消驱逐计划。
|
||||
|
||||
为什么提供 Expel 和 UnExpel 方法:
|
||||
- 在连接断开时,当需要执行一系列消息处理时,如果直接关闭消息分发器,可能会导致消息丢失。所以提供了 Expel 方法,可以在消息处理完成后再关闭消息分发器。
|
||||
- 当消息还未处理完成时连接重连,如果没有取消驱逐计划,可能会导致消息分发器被关闭。所以提供了 UnExpel 方法,可以在连接重连后取消驱逐计划。
|
||||
```go
|
||||
type Dispatcher[P Producer, M Message[P]] struct {
|
||||
buf *buffer.RingUnbounded[M]
|
||||
uniques *haxmap.Map[string, struct{}]
|
||||
handler Handler[P, M]
|
||||
expel bool
|
||||
mc int64
|
||||
pmc map[P]int64
|
||||
pmcF map[P]func(p P, dispatcher *Action[P, M])
|
||||
lock sync.RWMutex
|
||||
name string
|
||||
closedHandler atomic.Pointer[func(dispatcher *Action[P, M])]
|
||||
abort chan struct{}
|
||||
}
|
||||
```
|
||||
### Manager `STRUCT`
|
||||
消息分发器管理器
|
||||
```go
|
||||
type Manager[P Producer, M Message[P]] struct {
|
||||
handler Handler[P, M]
|
||||
sys *Dispatcher[P, M]
|
||||
dispatchers map[string]*Dispatcher[P, M]
|
||||
member map[string]map[P]struct{}
|
||||
curr map[P]*Dispatcher[P, M]
|
||||
lock sync.RWMutex
|
||||
w sync.WaitGroup
|
||||
size int
|
||||
closedHandler func(name string)
|
||||
createdHandler func(name string)
|
||||
}
|
||||
```
|
||||
### Message `INTERFACE`
|
||||
|
||||
```go
|
||||
type Message[P comparable] interface {
|
||||
GetProducer() P
|
||||
}
|
||||
```
|
||||
### Producer `INTERFACE`
|
||||
|
||||
```go
|
||||
type Producer interface {
|
||||
comparable
|
||||
}
|
||||
```
|
|
@ -0,0 +1,48 @@
|
|||
# Logger
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Ants](#ants)|暂无描述...
|
||||
|`STRUCT`|[GNet](#gnet)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
### Ants `STRUCT`
|
||||
|
||||
```go
|
||||
type Ants struct{}
|
||||
```
|
||||
#### func (*Ants) Printf(format string, args ...interface {})
|
||||
***
|
||||
### GNet `STRUCT`
|
||||
|
||||
```go
|
||||
type GNet struct{}
|
||||
```
|
||||
#### func (*GNet) Debugf(format string, args ...interface {})
|
||||
***
|
||||
#### func (*GNet) Infof(format string, args ...interface {})
|
||||
***
|
||||
#### func (*GNet) Warnf(format string, args ...interface {})
|
||||
***
|
||||
#### func (*GNet) Errorf(format string, args ...interface {})
|
||||
***
|
||||
#### func (*GNet) Fatalf(format string, args ...interface {})
|
||||
***
|
|
@ -1,9 +1,156 @@
|
|||
# Lockstep [`锁步(帧)同步`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/lockstep#Lockstep)
|
||||
# Lockstep
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/server/lockstep)
|
||||
> 它是一个不限制网络类型的实现,仅需要对应连接实现 [`lockstep.Client`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/lockstep#Client) 接口即可。
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
该包提供了一个并发安全的锁步(帧)同步实现,其中内置了频率设置、帧上限、序列化、初始帧、追帧等功能。可使用其来快速构建和管理锁步(帧)同步。
|
||||
|
||||
锁步(帧)同步是一种特殊的同步,它可以并发安全地将数据同步到底层连接。
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewLockstep](#NewLockstep)|创建一个锁步(帧)同步默认实现的组件(Lockstep)进行返回
|
||||
|[WithFrameLimit](#WithFrameLimit)|通过特定逻辑帧上限创建锁步(帧)同步组件
|
||||
|[WithFrameRate](#WithFrameRate)|通过特定逻辑帧率创建锁步(帧)同步组件
|
||||
|[WithSerialization](#WithSerialization)|通过特定的序列化方式将每一帧的数据进行序列化
|
||||
|[WithInitFrame](#WithInitFrame)|通过特定的初始帧创建锁步(帧)同步组件
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`INTERFACE`|[Client](#client)|帧同步客户端接口定义
|
||||
|`STRUCT`|[StoppedEventHandle](#stoppedeventhandle)|暂无描述...
|
||||
|`STRUCT`|[Lockstep](#lockstep)|锁步(帧)同步默认实现
|
||||
|`STRUCT`|[Option](#option)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewLockstep(options ...Option[ClientID, Command]) *Lockstep[ClientID, Command]
|
||||
<span id="NewLockstep"></span>
|
||||
> 创建一个锁步(帧)同步默认实现的组件(Lockstep)进行返回
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewLockstep(t *testing.T) {
|
||||
ls := lockstep.NewLockstep[string, int](lockstep.WithInitFrame[string, int](1))
|
||||
ls.JoinClient(&Cli{id: "player_1"})
|
||||
ls.JoinClient(&Cli{id: "player_2"})
|
||||
count := 0
|
||||
ls.StartBroadcast()
|
||||
endChan := make(chan bool)
|
||||
go func() {
|
||||
for {
|
||||
ls.AddCommand(random.Int(1, 9999))
|
||||
count++
|
||||
if count >= 10 {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond * time.Duration(random.Int(10, 200)))
|
||||
}
|
||||
ls.StopBroadcast()
|
||||
endChan <- true
|
||||
}()
|
||||
<-endChan
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println("end")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func WithFrameLimit(frameLimit int64) Option[ClientID, Command]
|
||||
<span id="WithFrameLimit"></span>
|
||||
> 通过特定逻辑帧上限创建锁步(帧)同步组件
|
||||
> - 当达到上限时将停止广播
|
||||
|
||||
***
|
||||
#### func WithFrameRate(frameRate int64) Option[ClientID, Command]
|
||||
<span id="WithFrameRate"></span>
|
||||
> 通过特定逻辑帧率创建锁步(帧)同步组件
|
||||
> - 默认情况下为 15/s
|
||||
|
||||
***
|
||||
#### func WithSerialization(handle func (frame int64, commands []Command) []byte) Option[ClientID, Command]
|
||||
<span id="WithSerialization"></span>
|
||||
> 通过特定的序列化方式将每一帧的数据进行序列化
|
||||
>
|
||||
> - 默认情况下为将被序列化为以下结构体的JSON字符串
|
||||
>
|
||||
> type Frame struct {
|
||||
> Frame int `json:"frame"`
|
||||
> Commands []Command `json:"commands"`
|
||||
> }
|
||||
|
||||
***
|
||||
#### func WithInitFrame(initFrame int64) Option[ClientID, Command]
|
||||
<span id="WithInitFrame"></span>
|
||||
> 通过特定的初始帧创建锁步(帧)同步组件
|
||||
> - 默认情况下为 0,即第一帧索引为 0
|
||||
|
||||
***
|
||||
### Client `INTERFACE`
|
||||
帧同步客户端接口定义
|
||||
- 客户端应该具备ID及写入数据包的实现
|
||||
```go
|
||||
type Client[ID comparable] interface {
|
||||
GetID() ID
|
||||
Write(packet []byte, callback ...func(err error))
|
||||
}
|
||||
```
|
||||
### StoppedEventHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type StoppedEventHandle[ClientID comparable, Command any] func(lockstep *Lockstep[ClientID, Command])
|
||||
```
|
||||
### Lockstep `STRUCT`
|
||||
锁步(帧)同步默认实现
|
||||
- 支持最大帧上限 WithFrameLimit
|
||||
- 自定逻辑帧频率,默认为每秒15帧(帧/66ms) WithFrameRate
|
||||
- 自定帧序列化方式 WithSerialization
|
||||
- 从特定帧开始追帧
|
||||
- 兼容各种基于TCP/UDP/Unix的网络类型,可通过客户端实现其他网络类型同步
|
||||
```go
|
||||
type Lockstep[ClientID comparable, Command any] struct {
|
||||
running bool
|
||||
runningLock sync.RWMutex
|
||||
initFrame int64
|
||||
frameRate int64
|
||||
frameLimit int64
|
||||
serialization func(frame int64, commands []Command) []byte
|
||||
clients map[ClientID]Client[ClientID]
|
||||
clientFrame map[ClientID]int64
|
||||
clientLock sync.RWMutex
|
||||
currentFrame int64
|
||||
currentCommands []Command
|
||||
currentFrameLock sync.RWMutex
|
||||
frameCache map[int64][]byte
|
||||
frameCacheLock sync.RWMutex
|
||||
ticker *time.Ticker
|
||||
lockstepStoppedEventHandles []StoppedEventHandle[ClientID, Command]
|
||||
}
|
||||
```
|
||||
### Option `STRUCT`
|
||||
|
||||
```go
|
||||
type Option[ClientID comparable, Command any] func(lockstep *Lockstep[ClientID, Command])
|
||||
```
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
# Router
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewMultistage](#NewMultistage)|创建一个支持多级分类的路由器
|
||||
|[WithRouteTrim](#WithRouteTrim)|路由修剪选项
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[MultistageBind](#multistagebind)|多级分类路由绑定函数
|
||||
|`STRUCT`|[Multistage](#multistage)|支持多级分类的路由器
|
||||
|`STRUCT`|[MultistageOption](#multistageoption)|路由器选项
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewMultistage(options ...MultistageOption[HandleFunc]) *Multistage[HandleFunc]
|
||||
<span id="NewMultistage"></span>
|
||||
> 创建一个支持多级分类的路由器
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleNewMultistage() {
|
||||
router.NewMultistage[func()]()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func WithRouteTrim(handle func (route any) any) MultistageOption[HandleFunc]
|
||||
<span id="WithRouteTrim"></span>
|
||||
> 路由修剪选项
|
||||
> - 将在路由注册前对路由进行对应处理
|
||||
|
||||
***
|
||||
### MultistageBind `STRUCT`
|
||||
多级分类路由绑定函数
|
||||
```go
|
||||
type MultistageBind[HandleFunc any] func(HandleFunc)
|
||||
```
|
||||
#### func (MultistageBind) Bind(handleFunc HandleFunc)
|
||||
> 将处理函数绑定到预设的路由中
|
||||
***
|
||||
### Multistage `STRUCT`
|
||||
支持多级分类的路由器
|
||||
```go
|
||||
type Multistage[HandleFunc any] struct {
|
||||
routes map[any]HandleFunc
|
||||
subs map[any]*Multistage[HandleFunc]
|
||||
tag any
|
||||
trim func(route any) any
|
||||
}
|
||||
```
|
||||
#### func (*Multistage) Register(routes ...any) MultistageBind[HandleFunc]
|
||||
> 注册路由是结合 Sub 和 Route 的快捷方式,用于一次性注册多级路由
|
||||
> - 该函数将返回一个注册函数,可通过调用其将路由绑定到特定处理函数,例如:router.Register("a", "b").Bind(onExec())
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleMultistage_Register() {
|
||||
r := router.NewMultistage[func()]()
|
||||
r.Register("System", "Network", "Ping")(func() {
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func (*Multistage) Route(route any, handleFunc HandleFunc)
|
||||
> 为特定路由绑定处理函数,被绑定的处理函数将可以通过 Match 函数进行匹配
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleMultistage_Route() {
|
||||
r := router.NewMultistage[func()]()
|
||||
r.Route("ServerTime", func() {
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func (*Multistage) Match(routes ...any) HandleFunc
|
||||
> 匹配已绑定处理函数的路由,返回处理函数
|
||||
> - 如果未找到将会返回空指针
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleMultistage_Match() {
|
||||
r := router.NewMultistage[func()]()
|
||||
r.Route("ServerTime", func() {
|
||||
})
|
||||
r.Register("System", "Network", "Ping").Bind(func() {
|
||||
})
|
||||
r.Match("ServerTime")()
|
||||
r.Match("System", "Network", "Ping")()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestMultistage_Match(t *testing.T) {
|
||||
r := router.NewMultistage[func()]()
|
||||
r.Sub("System").Route("Heartbeat", func() {
|
||||
fmt.Println("Heartbeat")
|
||||
})
|
||||
r.Route("ServerTime", func() {
|
||||
fmt.Println("ServerTime")
|
||||
})
|
||||
r.Register("System", "Network", "Ping")(func() {
|
||||
fmt.Println("Ping")
|
||||
})
|
||||
r.Register("System", "Network", "Echo").Bind(onEcho)
|
||||
r.Match("System", "Heartbeat")()
|
||||
r.Match("ServerTime")()
|
||||
r.Match("System", "Network", "Ping")()
|
||||
r.Match("System", "Network", "Echo")()
|
||||
fmt.Println(r.Match("None") == nil)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Multistage) Sub(route any) *Multistage[HandleFunc]
|
||||
> 获取子路由器
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleMultistage_Sub() {
|
||||
r := router.NewMultistage[func()]()
|
||||
r.Sub("System").Route("Heartbeat", func() {
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
### MultistageOption `STRUCT`
|
||||
路由器选项
|
||||
```go
|
||||
type MultistageOption[HandleFunc any] func(multistage *Multistage[HandleFunc])
|
||||
```
|
|
@ -1,41 +1,63 @@
|
|||
# WriteLoop
|
||||
# Writeloop
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
该包提供了一个并发安全的写循环实现。开发者可以使用它来快速构建和管理写入操作。
|
||||
暂无介绍...
|
||||
|
||||
写循环是一种特殊的循环,它可以并发安全地将数据写入到底层连接。写循环在 `Minotaur` 中是一个泛型类型,可以处理任意类型的消息。
|
||||
|
||||
## Unbounded [`基于无界缓冲区的写循环`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Unbounded)
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
基于无界缓冲区的写循环实现,它可以处理任意数量的消息。它使用 [`Pool`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/concurrent#Pool) 来管理消息对象,使用 [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer#Unbounded) 来管理消息队列。
|
||||
|
||||
> [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Unbounded) 使用了 [`Pool`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/concurrent#Pool) 和 [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer#Unbounded) 进行实现。
|
||||
> 通过 [`Pool`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/concurrent#Pool) 创建的消息对象无需手动释放,它会在写循环处理完消息后自动回收。
|
||||
> 包级函数定义
|
||||
|
||||
## Channel [`基于 chan 的写循环`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Channel)
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewChannel](#NewChannel)|创建基于 Channel 的写循环
|
||||
|[NewUnbounded](#NewUnbounded)|创建写循环
|
||||
|
||||
基于 [`chan`](https://pkg.go.dev/builtin#chan) 的写循环实现,拥有极高的吞吐量。它使用 [`Pool`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/concurrent#Pool) 来管理消息对象,使用 [`Channel`](https://pkg.go.dev/builtin#chan) 来管理消息队列。
|
||||
|
||||
## 如何选择
|
||||
- [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Unbounded) 适用于消息体较小、消息量庞大、消息处理时间较慢的场景,由于没有消息数量限制,所以它可以处理任意数量的消息,但是它的吞吐量较低,并且会占用大量的内存。
|
||||
- [`Channel`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Channel) 适用于消息体较大、消息量较小、消息处理时间较快的场景,由于使用了 [`Channel`](https://pkg.go.dev/builtin#chan) 来管理消息队列,所以它的吞吐量较高,但是它的消息数量是有限制的,如果消息数量超过了限制,那么写循环会阻塞,造成无法及时响应消息(例如心跳中断等)。
|
||||
> 类型定义
|
||||
|
||||
> 通常来说,建议使用 [`Channel`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Channel) 来实现写循环,因为它的吞吐量更高,并且绝大多数情况是很难达到阻塞的。
|
||||
### 使用示例
|
||||
> 该示例由 [`Unbounded`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Unbounded) 实现,[`Channel`](https://pkg.go.dev/github.com/kercylan98/minotaur/server/writeloop#Channel) 的使用方法与之类似。
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Channel](#channel)|基于 chan 的写循环,与 Unbounded 相同,但是使用 Channel 实现
|
||||
|`STRUCT`|[Unbounded](#unbounded)|写循环
|
||||
|`INTERFACE`|[WriteLoop](#writeloop)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewChannel(pool *hub.ObjectPool[Message], channelSize int, writeHandler func (message Message) error, errorHandler func (err any)) *Channel[Message]
|
||||
<span id="NewChannel"></span>
|
||||
> 创建基于 Channel 的写循环
|
||||
> - pool 用于管理 Message 对象的缓冲池,在创建 Message 对象时也应该使用该缓冲池,以便复用 Message 对象。 Channel 会在写入完成后将 Message 对象放回缓冲池
|
||||
> - channelSize Channel 的大小
|
||||
> - writeHandler 写入处理函数
|
||||
> - errorHandler 错误处理函数
|
||||
>
|
||||
> 传入 writeHandler 的消息对象是从 Channel 中获取的,因此 writeHandler 不应该持有消息对象的引用,同时也不应该主动释放消息对象
|
||||
|
||||
***
|
||||
#### func NewUnbounded(pool *hub.ObjectPool[Message], writeHandler func (message Message) error, errorHandler func (err any)) *Unbounded[Message]
|
||||
<span id="NewUnbounded"></span>
|
||||
> 创建写循环
|
||||
> - pool 用于管理 Message 对象的缓冲池,在创建 Message 对象时也应该使用该缓冲池,以便复用 Message 对象。 Unbounded 会在写入完成后将 Message 对象放回缓冲池
|
||||
> - writeHandler 写入处理函数
|
||||
> - errorHandler 错误处理函数
|
||||
>
|
||||
> 传入 writeHandler 的消息对象是从 pool 中获取的,并且在 writeHandler 执行完成后会被放回 pool 中,因此 writeHandler 不应该持有消息对象的引用,同时也不应该主动释放消息对象
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/server/writeloop"
|
||||
"github.com/kercylan98/minotaur/utils/hub"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pool := concurrent.NewPool[Message](func() *Message {
|
||||
func ExampleNewUnbounded() {
|
||||
pool := hub.NewObjectPool[Message](func() *Message {
|
||||
return &Message{}
|
||||
}, func(data *Message) {
|
||||
data.ID = 0
|
||||
|
@ -49,16 +71,157 @@ func main() {
|
|||
}, func(err any) {
|
||||
fmt.Println(err)
|
||||
})
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
m := pool.Get()
|
||||
m.ID = i
|
||||
wl.Put(m)
|
||||
}
|
||||
|
||||
wait.Wait()
|
||||
wl.Close()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
在这个示例中,我们创建了一个写循环,然后将一些消息放入写循环。每个消息都会被 `writeHandle` 函数处理,如果在处理过程中发生错误,`errorHandle` 函数会被调用。在使用完写循环后,我们需要关闭它。
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewUnbounded(t *testing.T) {
|
||||
wl := writeloop.NewUnbounded(wp, func(message *Message) error {
|
||||
t.Log(message.ID)
|
||||
return nil
|
||||
}, func(err any) {
|
||||
t.Log(err)
|
||||
})
|
||||
assert.NotNil(t, wl)
|
||||
wl.Close()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### Channel `STRUCT`
|
||||
基于 chan 的写循环,与 Unbounded 相同,但是使用 Channel 实现
|
||||
```go
|
||||
type Channel[T any] struct {
|
||||
c chan T
|
||||
}
|
||||
```
|
||||
#### func (*Channel) Put(message T)
|
||||
> 将数据放入写循环,message 应该来源于 hub.ObjectPool
|
||||
***
|
||||
#### func (*Channel) Close()
|
||||
> 关闭写循环
|
||||
***
|
||||
### Unbounded `STRUCT`
|
||||
写循环
|
||||
- 用于将数据并发安全的写入到底层连接
|
||||
```go
|
||||
type Unbounded[Message any] struct {
|
||||
buf *buffer.Unbounded[Message]
|
||||
}
|
||||
```
|
||||
#### func (*Unbounded) Put(message Message)
|
||||
> 将数据放入写循环,message 应该来源于 hub.ObjectPool
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestUnbounded_Put(t *testing.T) {
|
||||
wl := writeloop.NewUnbounded(wp, func(message *Message) error {
|
||||
t.Log(message.ID)
|
||||
return nil
|
||||
}, func(err any) {
|
||||
t.Log(err)
|
||||
})
|
||||
assert.NotNil(t, wl)
|
||||
for i := 0; i < 100; i++ {
|
||||
m := wp.Get()
|
||||
m.ID = i
|
||||
wl.Put(m)
|
||||
}
|
||||
wl.Close()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起基准测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func BenchmarkUnbounded_Put(b *testing.B) {
|
||||
wl := writeloop.NewUnbounded(wp, func(message *Message) error {
|
||||
return nil
|
||||
}, nil)
|
||||
defer func() {
|
||||
wl.Close()
|
||||
}()
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
wl.Put(wp.Get())
|
||||
}
|
||||
})
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Unbounded) Close()
|
||||
> 关闭写循环
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestUnbounded_Close(t *testing.T) {
|
||||
wl := writeloop.NewUnbounded(wp, func(message *Message) error {
|
||||
t.Log(message.ID)
|
||||
return nil
|
||||
}, func(err any) {
|
||||
t.Log(err)
|
||||
})
|
||||
assert.NotNil(t, wl)
|
||||
for i := 0; i < 100; i++ {
|
||||
m := wp.Get()
|
||||
m.ID = i
|
||||
wl.Put(m)
|
||||
}
|
||||
wl.Close()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### WriteLoop `INTERFACE`
|
||||
|
||||
```go
|
||||
type WriteLoop[Message any] interface {
|
||||
Put(message Message)
|
||||
Close()
|
||||
}
|
||||
```
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Utils
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
utils 旨在提供一组用于处理通用功能的函数和数据结构。该包旨在简化通用功能的实现,并提供一致的接口和易于使用的功能。
|
||||
主要特性:
|
||||
- 通用功能:utils 包支持处理各种通用功能,如字符串处理、日期时间操作和文件操作等。您可以使用这些功能来解决各种通用问题,并提高代码的复用性和可维护性。
|
||||
- 数据结构:该包提供了一系列通用的数据结构,如栈、队列、链表和哈希表等。这些数据结构可以用于存储和操作各种类型的数据,并提供高效的访问和操作能力。
|
||||
- 算法实现:utils 包还提供了一些常用的算法实现,如排序算法、搜索算法和图算法等。这些算法可以用于解决各种问题,并提供高效的计算和处理能力。
|
||||
- 工具函数:该包还提供了一些通用的工具函数,如字符串处理、日期时间操作和文件操作等。这些工具函数可以帮助您简化代码编写,处理文本数据,操作日期时间,读写文件等。
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -1,10 +1,99 @@
|
|||
# AOI (Area of Interest)
|
||||
# Aoi
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/aoi)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
AOI (Area of Interest) 是一种常见的游戏服务器技术,用于处理大量玩家在同一空间内的交互问题。在 `Minotaur` 中,我们提供了一个基于 Go 语言的 AOI 实现。
|
||||
aoi 提供了一种有效的方法来处理 AOI(Area of Interest)问题。
|
||||
|
||||
## TwoDimensional [`二维AOI`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/aoi#TwoDimensional)
|
||||
AOI 问题是在大规模多人在线游戏中常见的问题,它涉及到确定哪些对象对玩家来说是“感兴趣的”,
|
||||
也就是说,哪些对象在玩家的视野范围内。
|
||||
|
||||
[`TwoDimensional`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/aoi#TwoDimensional)
|
||||
是一个二维 AOI 的实现。它提供了添加实体、删除实体、刷新实体、获取焦点实体等方法。每个实体需要实现 [`TwoDimensionalEntity`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/aoi#TwoDimensionalEntity) 接口,该接口包含了获取实体 ID、获取实体坐标、获取实体视野半径等方法。
|
||||
这个包提供了一种数据结构和一些方法来有效地解决这个问题。
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewTwoDimensional](#NewTwoDimensional)|暂无描述...
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[TwoDimensional](#twodimensional)|暂无描述...
|
||||
|`INTERFACE`|[TwoDimensionalEntity](#twodimensionalentity)|基于2D定义的AOI对象功能接口
|
||||
|`STRUCT`|[EntityJoinVisionEventHandle](#entityjoinvisioneventhandle)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewTwoDimensional(width int, height int, areaWidth int, areaHeight int) *TwoDimensional[EID, PosType, E]
|
||||
<span id="NewTwoDimensional"></span>
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewTwoDimensional(t *testing.T) {
|
||||
aoiTW := aoi.NewTwoDimensional[int64, float64, *Ent](10000, 10000, 100, 100)
|
||||
start := time.Now()
|
||||
for i := 0; i < 50000; i++ {
|
||||
aoiTW.AddEntity(&Ent{guid: int64(i), pos: geometry.NewPoint[float64](float64(random.Int64(0, 10000)), float64(random.Int64(0, 10000))), vision: 200})
|
||||
}
|
||||
fmt.Println("添加耗时:", time.Since(start))
|
||||
start = time.Now()
|
||||
aoiTW.SetSize(10100, 10100)
|
||||
fmt.Println("重设大小耗时:", time.Since(start))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### TwoDimensional `STRUCT`
|
||||
|
||||
```go
|
||||
type TwoDimensional[EID generic.Basic, PosType generic.SignedNumber, E TwoDimensionalEntity[EID, PosType]] struct {
|
||||
*event[EID, PosType, E]
|
||||
rw sync.RWMutex
|
||||
width float64
|
||||
height float64
|
||||
areaWidth float64
|
||||
areaHeight float64
|
||||
areaWidthLimit int
|
||||
areaHeightLimit int
|
||||
areas [][]map[EID]E
|
||||
focus map[EID]map[EID]E
|
||||
repartitionQueue []func()
|
||||
}
|
||||
```
|
||||
### TwoDimensionalEntity `INTERFACE`
|
||||
基于2D定义的AOI对象功能接口
|
||||
- AOI 对象提供了 AOI 系统中常用的属性,诸如位置坐标和视野范围等
|
||||
```go
|
||||
type TwoDimensionalEntity[EID generic.Basic, PosType generic.SignedNumber] interface {
|
||||
GetTwoDimensionalEntityID() EID
|
||||
GetVision() float64
|
||||
GetPosition() geometry.Point[PosType]
|
||||
}
|
||||
```
|
||||
### EntityJoinVisionEventHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type EntityJoinVisionEventHandle[EID generic.Basic, PosType generic.SignedNumber, E TwoDimensionalEntity[EID, PosType]] func(entity E)
|
||||
```
|
||||
|
|
|
@ -1,17 +1,194 @@
|
|||
# Arrangement
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/arrangement)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
`Arrangement`包提供了一种灵活的方式来管理和操作编排区域。它包含了一些用于处理编排区域和编排选项的函数和类型。
|
||||
arrangement 包提供了一些有用的函数来处理数组的排列。
|
||||
|
||||
## Area [`编排区域`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/arrangement#Area)
|
||||
`Area`类型代表一个编排区域,它包含了一些方法,如`GetAreaInfo`、`GetItems`、`IsAllow`、`IsConflict`、`GetConflictItems`和`GetScore`,这些方法可以用来获取区域信息、获取区域中的所有成员、检查一个成员是否可以被添加到该区域中、检查一个成员是否会造成冲突、获取与一个成员产生冲突的所有其他成员以及获取该区域的评估分数。
|
||||
更多的详细信息和使用示例,可以参考每个函数的文档。
|
||||
|
||||
## Option [`编排选项`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/arrangement#Option)
|
||||
`Option`类型代表一个编排选项,它是一个函数,可以用来修改编排的行为。例如,`WithRetryThreshold`、`WithConstraintHandle`和`WithConflictHandle`函数可以用来设置编排时的重试阈值、约束处理函数和冲突处理函数。
|
||||
|
||||
## AreaOption [`编排区域选项`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/arrangement#AreaOption)
|
||||
`AreaOption`类型代表一个编排区域选项,它是一个函数,可以用来修改编排区域的行为。例如,`WithAreaConstraint`、`WithAreaConflict`和`WithAreaEvaluate`函数可以用来设置编排区域的约束条件、冲突条件和评估函数。
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
## 示例代码
|
||||
[点击查看](./arrangement_test.go)
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[WithAreaConstraint](#WithAreaConstraint)|设置编排区域的约束条件
|
||||
|[WithAreaConflict](#WithAreaConflict)|设置编排区域的冲突条件,冲突处理函数需要返回造成冲突的成员列表
|
||||
|[WithAreaEvaluate](#WithAreaEvaluate)|设置编排区域的评估函数
|
||||
|[NewArrangement](#NewArrangement)|创建一个新的编排
|
||||
|[WithItemFixed](#WithItemFixed)|设置成员的固定编排区域
|
||||
|[WithItemPriority](#WithItemPriority)|设置成员的优先级
|
||||
|[WithItemNotAllow](#WithItemNotAllow)|设置成员不允许的编排区域
|
||||
|[WithRetryThreshold](#WithRetryThreshold)|设置编排时的重试阈值
|
||||
|[WithConstraintHandle](#WithConstraintHandle)|设置编排时触发约束时的处理函数
|
||||
|[WithConflictHandle](#WithConflictHandle)|设置编排时触发冲突时的处理函数
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Area](#area)|编排区域
|
||||
|`STRUCT`|[AreaOption](#areaoption)|编排区域选项
|
||||
|`STRUCT`|[AreaConstraintHandle](#areaconstrainthandle)|暂无描述...
|
||||
|`STRUCT`|[Arrangement](#arrangement)|用于针对多条数据进行合理编排的数据结构
|
||||
|`STRUCT`|[Editor](#editor)|提供了大量辅助函数的编辑器
|
||||
|`INTERFACE`|[Item](#item)|编排成员
|
||||
|`STRUCT`|[ItemOption](#itemoption)|编排成员选项
|
||||
|`STRUCT`|[ItemFixedAreaHandle](#itemfixedareahandle)|暂无描述...
|
||||
|`STRUCT`|[Option](#option)|编排选项
|
||||
|`STRUCT`|[ConstraintHandle](#constrainthandle)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func WithAreaConstraint(constraint AreaConstraintHandle[ID, AreaInfo]) AreaOption[ID, AreaInfo]
|
||||
<span id="WithAreaConstraint"></span>
|
||||
> 设置编排区域的约束条件
|
||||
> - 该约束用于判断一个成员是否可以被添加到该编排区域中
|
||||
> - 与 WithAreaConflict 不同的是,约束通常用于非成员关系导致的硬性约束,例如:成员的等级过滤、成员的性别等
|
||||
|
||||
***
|
||||
#### func WithAreaConflict(conflict AreaConflictHandle[ID, AreaInfo]) AreaOption[ID, AreaInfo]
|
||||
<span id="WithAreaConflict"></span>
|
||||
> 设置编排区域的冲突条件,冲突处理函数需要返回造成冲突的成员列表
|
||||
> - 该冲突用于判断一个成员是否可以被添加到该编排区域中
|
||||
> - 与 WithAreaConstraint 不同的是,冲突通常用于成员关系导致的软性约束,例如:成员的职业唯一性、成员的种族唯一性等
|
||||
|
||||
***
|
||||
#### func WithAreaEvaluate(evaluate AreaEvaluateHandle[ID, AreaInfo]) AreaOption[ID, AreaInfo]
|
||||
<span id="WithAreaEvaluate"></span>
|
||||
> 设置编排区域的评估函数
|
||||
> - 该评估函数将影响成员被编入区域的优先级
|
||||
|
||||
***
|
||||
#### func NewArrangement(options ...Option[ID, AreaInfo]) *Arrangement[ID, AreaInfo]
|
||||
<span id="NewArrangement"></span>
|
||||
> 创建一个新的编排
|
||||
|
||||
***
|
||||
#### func WithItemFixed(matcher ItemFixedAreaHandle[AreaInfo]) ItemOption[ID, AreaInfo]
|
||||
<span id="WithItemFixed"></span>
|
||||
> 设置成员的固定编排区域
|
||||
|
||||
***
|
||||
#### func WithItemPriority(priority ItemPriorityHandle[ID, AreaInfo]) ItemOption[ID, AreaInfo]
|
||||
<span id="WithItemPriority"></span>
|
||||
> 设置成员的优先级
|
||||
|
||||
***
|
||||
#### func WithItemNotAllow(verify ItemNotAllowVerifyHandle[ID, AreaInfo]) ItemOption[ID, AreaInfo]
|
||||
<span id="WithItemNotAllow"></span>
|
||||
> 设置成员不允许的编排区域
|
||||
|
||||
***
|
||||
#### func WithRetryThreshold(threshold int) Option[ID, AreaInfo]
|
||||
<span id="WithRetryThreshold"></span>
|
||||
> 设置编排时的重试阈值
|
||||
> - 当每一轮编排结束任有成员未被编排时,将会进行下一轮编排,直到编排次数达到该阈值
|
||||
> - 默认的阈值为 10 次
|
||||
|
||||
***
|
||||
#### func WithConstraintHandle(handle ConstraintHandle[ID, AreaInfo]) Option[ID, AreaInfo]
|
||||
<span id="WithConstraintHandle"></span>
|
||||
> 设置编排时触发约束时的处理函数
|
||||
> - 当约束条件触发时,将会调用该函数。如果无法在该函数中处理约束,应该继续返回 err,尝试进行下一层的约束处理
|
||||
> - 当该函数的返回值为 nil 时,表示约束已经被处理,将会命中当前的编排区域
|
||||
> - 当所有的约束处理函数都无法处理约束时,将会进入下一个编排区域的尝试,如果均无法完成,将会将该成员加入到编排队列的末端,等待下一次编排
|
||||
>
|
||||
> 有意思的是,硬性约束应该永远是无解的,而当需要进行一些打破规则的操作时,则可以透过该函数传入的 editor 进行操作
|
||||
|
||||
***
|
||||
#### func WithConflictHandle(handle ConflictHandle[ID, AreaInfo]) Option[ID, AreaInfo]
|
||||
<span id="WithConflictHandle"></span>
|
||||
> 设置编排时触发冲突时的处理函数
|
||||
> - 当冲突条件触发时,将会调用该函数。如果无法在该函数中处理冲突,应该继续返回这一批成员,尝试进行下一层的冲突处理
|
||||
> - 当该函数的返回值长度为 0 时,表示冲突已经被处理,将会命中当前的编排区域
|
||||
> - 当所有的冲突处理函数都无法处理冲突时,将会进入下一个编排区域的尝试,如果均无法完成,将会将该成员加入到编排队列的末端,等待下一次编排
|
||||
|
||||
***
|
||||
### Area `STRUCT`
|
||||
编排区域
|
||||
```go
|
||||
type Area[ID comparable, AreaInfo any] struct {
|
||||
info AreaInfo
|
||||
items map[ID]Item[ID]
|
||||
constraints []AreaConstraintHandle[ID, AreaInfo]
|
||||
conflicts []AreaConflictHandle[ID, AreaInfo]
|
||||
evaluate AreaEvaluateHandle[ID, AreaInfo]
|
||||
}
|
||||
```
|
||||
### AreaOption `STRUCT`
|
||||
编排区域选项
|
||||
```go
|
||||
type AreaOption[ID comparable, AreaInfo any] func(area *Area[ID, AreaInfo])
|
||||
```
|
||||
### AreaConstraintHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type AreaConstraintHandle[ID comparable, AreaInfo any] func(area *Area[ID, AreaInfo], item Item[ID]) error
|
||||
```
|
||||
### Arrangement `STRUCT`
|
||||
用于针对多条数据进行合理编排的数据结构
|
||||
- 我不知道这个数据结构的具体用途,但是我觉得这个数据结构应该是有用的
|
||||
- 目前我能想到的用途只有我的过往经历:排课
|
||||
- 如果是在游戏领域,或许适用于多人小队匹配编排等类似情况
|
||||
```go
|
||||
type Arrangement[ID comparable, AreaInfo any] struct {
|
||||
areas []*Area[ID, AreaInfo]
|
||||
items map[ID]Item[ID]
|
||||
fixed map[ID]ItemFixedAreaHandle[AreaInfo]
|
||||
priority map[ID][]ItemPriorityHandle[ID, AreaInfo]
|
||||
itemNotAllow map[ID][]ItemNotAllowVerifyHandle[ID, AreaInfo]
|
||||
threshold int
|
||||
constraintHandles []ConstraintHandle[ID, AreaInfo]
|
||||
conflictHandles []ConflictHandle[ID, AreaInfo]
|
||||
}
|
||||
```
|
||||
### Editor `STRUCT`
|
||||
提供了大量辅助函数的编辑器
|
||||
```go
|
||||
type Editor[ID comparable, AreaInfo any] struct {
|
||||
a *Arrangement[ID, AreaInfo]
|
||||
pending []Item[ID]
|
||||
fails []Item[ID]
|
||||
falls map[ID]struct{}
|
||||
retryCount int
|
||||
}
|
||||
```
|
||||
### Item `INTERFACE`
|
||||
编排成员
|
||||
```go
|
||||
type Item[ID comparable] interface {
|
||||
GetID() ID
|
||||
Equal(item Item[ID]) bool
|
||||
}
|
||||
```
|
||||
### ItemOption `STRUCT`
|
||||
编排成员选项
|
||||
```go
|
||||
type ItemOption[ID comparable, AreaInfo any] func(arrangement *Arrangement[ID, AreaInfo], item Item[ID])
|
||||
```
|
||||
### ItemFixedAreaHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type ItemFixedAreaHandle[AreaInfo any] func(areaInfo AreaInfo) bool
|
||||
```
|
||||
### Option `STRUCT`
|
||||
编排选项
|
||||
```go
|
||||
type Option[ID comparable, AreaInfo any] func(arrangement *Arrangement[ID, AreaInfo])
|
||||
```
|
||||
### ConstraintHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type ConstraintHandle[ID comparable, AreaInfo any] func(editor *Editor[ID, AreaInfo], area *Area[ID, AreaInfo], item Item[ID], err error) error
|
||||
```
|
||||
|
|
|
@ -1,71 +1,304 @@
|
|||
# Buffer
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
该包提供了多种缓冲区实现,包括环形缓冲区和无界缓冲区。开发者可以使用它来快速构建和管理缓冲区。
|
||||
buffer 提供了缓冲区相关的实用程序。
|
||||
|
||||
## Ring [`环形缓冲区`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer#Ring)
|
||||
包括创建、读取和写入缓冲区的函数。
|
||||
|
||||
环形缓冲区是一种特殊的缓冲区,它的头尾是相连的。当缓冲区满时,新的元素会覆盖旧的元素。环形缓冲区在 `Minotaur` 中是一个泛型类型,可以容纳任意类型的元素。
|
||||
这个包还提供了一个无界缓冲区的实现,可以在不使用额外 goroutine 的情况下实现无界缓冲区。
|
||||
|
||||
## Unbounded [`无界缓冲区`](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/buffer#Unbounded)
|
||||
无界缓冲区的所有方法都是线程安全的,除了用于同步的互斥锁外,不会阻塞任何东西。
|
||||
|
||||
该缓冲区来源于 gRPC 的实现,用于在不使用额外 goroutine 的情况下实现无界缓冲区。无界缓冲区是一种特殊的缓冲区,它的大小可以动态扩展,不会出现溢出的情况。无界缓冲区在 `Minotaur` 中也是一个泛型类型,可以容纳任意类型的元素。
|
||||
|
||||
### 使用示例
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewRing](#NewRing)|创建一个并发不安全的环形缓冲区
|
||||
|[NewRingUnbounded](#NewRingUnbounded)|创建一个并发安全的基于环形缓冲区实现的无界缓冲区
|
||||
|[NewUnbounded](#NewUnbounded)|创建一个无界缓冲区
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Ring](#ring)|环形缓冲区
|
||||
|`STRUCT`|[RingUnbounded](#ringunbounded)|基于环形缓冲区实现的无界缓冲区
|
||||
|`STRUCT`|[Unbounded](#unbounded)|是无界缓冲区的实现
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewRing(initSize ...int) *Ring[T]
|
||||
<span id="NewRing"></span>
|
||||
> 创建一个并发不安全的环形缓冲区
|
||||
> - initSize: 初始容量
|
||||
>
|
||||
> 当初始容量小于 2 或未设置时,将会使用默认容量 2
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
环形缓冲区:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/utils/buffer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ring := buffer.NewRing[int](5)
|
||||
for i := 0; i < 5; i++ {
|
||||
ring.Write(i)
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
v, _ := ring.Read()
|
||||
fmt.Println(v) // 0 1 2 3 4
|
||||
}
|
||||
func TestNewRing(t *testing.T) {
|
||||
ring := buffer.NewRing[int]()
|
||||
for i := 0; i < 100; i++ {
|
||||
ring.Write(i)
|
||||
t.Log(ring.Read())
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
无界缓冲区:
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func NewRingUnbounded(bufferSize int) *RingUnbounded[T]
|
||||
<span id="NewRingUnbounded"></span>
|
||||
> 创建一个并发安全的基于环形缓冲区实现的无界缓冲区
|
||||
|
||||
***
|
||||
#### func NewUnbounded() *Unbounded[V]
|
||||
<span id="NewUnbounded"></span>
|
||||
> 创建一个无界缓冲区
|
||||
> - generateNil: 生成空值的函数,该函数仅需始终返回 nil 即可
|
||||
>
|
||||
> 该缓冲区来源于 gRPC 的实现,用于在不使用额外 goroutine 的情况下实现无界缓冲区
|
||||
> - 该缓冲区的所有方法都是线程安全的,除了用于同步的互斥锁外,不会阻塞任何东西
|
||||
|
||||
***
|
||||
### Ring `STRUCT`
|
||||
环形缓冲区
|
||||
```go
|
||||
type Ring[T any] struct {
|
||||
buf []T
|
||||
initSize int
|
||||
size int
|
||||
r int
|
||||
w int
|
||||
}
|
||||
```
|
||||
#### func (*Ring) Read() T, error
|
||||
> 读取数据
|
||||
<details>
|
||||
<summary>查看 / 收起基准测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/utils/buffer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
unbounded := buffer.NewUnbounded[int]()
|
||||
for i := 0; i < 10; i++ {
|
||||
unbounded.Put(i)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case v, ok := <-unbounded.Get():
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
unbounded.Load()
|
||||
fmt.Println(v) // 0 1 2 3 4 5 6 7 8 9
|
||||
if v == 9 {
|
||||
unbounded.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
func BenchmarkRing_Read(b *testing.B) {
|
||||
ring := buffer.NewRing[int](1024)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ring.Write(i)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = ring.Read()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Ring) ReadAll() []T
|
||||
> 读取所有数据
|
||||
***
|
||||
#### func (*Ring) Peek() (t T, err error)
|
||||
> 查看数据
|
||||
***
|
||||
#### func (*Ring) Write(v T)
|
||||
> 写入数据
|
||||
<details>
|
||||
<summary>查看 / 收起基准测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func BenchmarkRing_Write(b *testing.B) {
|
||||
ring := buffer.NewRing[int](1024)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ring.Write(i)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Ring) IsEmpty() bool
|
||||
> 是否为空
|
||||
***
|
||||
#### func (*Ring) Cap() int
|
||||
> 返回缓冲区容量
|
||||
***
|
||||
#### func (*Ring) Len() int
|
||||
> 返回缓冲区长度
|
||||
***
|
||||
#### func (*Ring) Reset()
|
||||
> 重置缓冲区
|
||||
***
|
||||
### RingUnbounded `STRUCT`
|
||||
基于环形缓冲区实现的无界缓冲区
|
||||
```go
|
||||
type RingUnbounded[T any] struct {
|
||||
ring *Ring[T]
|
||||
rrm sync.Mutex
|
||||
cond *sync.Cond
|
||||
rc chan T
|
||||
closed bool
|
||||
closedMutex sync.RWMutex
|
||||
closedSignal chan struct{}
|
||||
}
|
||||
```
|
||||
#### func (*RingUnbounded) Write(v T)
|
||||
> 写入数据
|
||||
<details>
|
||||
<summary>查看 / 收起基准测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func BenchmarkRingUnbounded_Write(b *testing.B) {
|
||||
ring := buffer.NewRingUnbounded[int](1024 * 16)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ring.Write(i)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*RingUnbounded) Read() chan T
|
||||
> 读取数据
|
||||
<details>
|
||||
<summary>查看 / 收起基准测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func BenchmarkRingUnbounded_Read(b *testing.B) {
|
||||
ring := buffer.NewRingUnbounded[int](1024 * 16)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ring.Write(i)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
<-ring.Read()
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*RingUnbounded) Closed() bool
|
||||
> 判断缓冲区是否已关闭
|
||||
***
|
||||
#### func (*RingUnbounded) Close() chan struct {}
|
||||
> 关闭缓冲区,关闭后将不再接收新数据,但是已有数据仍然可以读取
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestRingUnbounded_Close(t *testing.T) {
|
||||
ring := buffer.NewRingUnbounded[int](1024 * 16)
|
||||
for i := 0; i < 100; i++ {
|
||||
ring.Write(i)
|
||||
}
|
||||
t.Log("write done")
|
||||
ring.Close()
|
||||
t.Log("close done")
|
||||
for v := range ring.Read() {
|
||||
ring.Write(v)
|
||||
t.Log(v)
|
||||
}
|
||||
t.Log("read done")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### Unbounded `STRUCT`
|
||||
是无界缓冲区的实现
|
||||
```go
|
||||
type Unbounded[V any] struct {
|
||||
c chan V
|
||||
closed bool
|
||||
mu sync.Mutex
|
||||
backlog []V
|
||||
}
|
||||
```
|
||||
#### func (*Unbounded) Put(t V)
|
||||
> 将数据放入缓冲区
|
||||
***
|
||||
#### func (*Unbounded) Load()
|
||||
> 将缓冲区中的数据发送到读取通道中,如果缓冲区中没有数据,则不会发送
|
||||
> - 在每次 Get 后都应该执行该函数
|
||||
***
|
||||
#### func (*Unbounded) Get() chan V
|
||||
> 获取读取通道
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestUnbounded_Get(t *testing.T) {
|
||||
ub := buffer.NewUnbounded[int]()
|
||||
for i := 0; i < 100; i++ {
|
||||
ub.Put(i + 1)
|
||||
fmt.Println(<-ub.Get())
|
||||
ub.Load()
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Unbounded) Close()
|
||||
> 关闭
|
||||
***
|
||||
#### func (*Unbounded) IsClosed() bool
|
||||
> 是否已关闭
|
||||
***
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkRingWrite(b *testing.B) {
|
||||
func BenchmarkRing_Write(b *testing.B) {
|
||||
ring := buffer.NewRing[int](1024)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -13,7 +13,7 @@ func BenchmarkRingWrite(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkRingRead(b *testing.B) {
|
||||
func BenchmarkRing_Read(b *testing.B) {
|
||||
ring := buffer.NewRing[int](1024)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ring.Write(i)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,205 @@
|
|||
# Listings
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewMatrix](#NewMatrix)|创建一个新的 Matrix 实例。
|
||||
|[NewPagedSlice](#NewPagedSlice)|创建一个新的 PagedSlice 实例。
|
||||
|[NewPrioritySlice](#NewPrioritySlice)|创建一个优先级切片
|
||||
|[NewSyncSlice](#NewSyncSlice)|创建一个 SyncSlice
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Matrix](#matrix)|暂无描述...
|
||||
|`STRUCT`|[PagedSlice](#pagedslice)|是一个高效的动态数组,它通过分页管理内存并减少频繁的内存分配来提高性能。
|
||||
|`STRUCT`|[PrioritySlice](#priorityslice)|是一个优先级切片
|
||||
|`STRUCT`|[SyncSlice](#syncslice)|是基于 sync.RWMutex 实现的线程安全的 slice
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewMatrix(dimensions ...int) *Matrix[V]
|
||||
<span id="NewMatrix"></span>
|
||||
> 创建一个新的 Matrix 实例。
|
||||
|
||||
***
|
||||
#### func NewPagedSlice(pageSize int) *PagedSlice[T]
|
||||
<span id="NewPagedSlice"></span>
|
||||
> 创建一个新的 PagedSlice 实例。
|
||||
|
||||
***
|
||||
#### func NewPrioritySlice(lengthAndCap ...int) *PrioritySlice[V]
|
||||
<span id="NewPrioritySlice"></span>
|
||||
> 创建一个优先级切片
|
||||
|
||||
***
|
||||
#### func NewSyncSlice(length int, cap int) *SyncSlice[V]
|
||||
<span id="NewSyncSlice"></span>
|
||||
> 创建一个 SyncSlice
|
||||
|
||||
***
|
||||
### Matrix `STRUCT`
|
||||
|
||||
```go
|
||||
type Matrix[V any] struct {
|
||||
dimensions []int
|
||||
data []V
|
||||
}
|
||||
```
|
||||
#### func (*Matrix) Get(index ...int) *V
|
||||
> 获取矩阵中给定索引的元素。
|
||||
***
|
||||
#### func (*Matrix) Set(index []int, value V)
|
||||
> 设置矩阵中给定索引的元素。
|
||||
***
|
||||
#### func (*Matrix) Dimensions() []int
|
||||
> 返回矩阵的维度大小。
|
||||
***
|
||||
#### func (*Matrix) Clear()
|
||||
> 清空矩阵。
|
||||
***
|
||||
### PagedSlice `STRUCT`
|
||||
是一个高效的动态数组,它通过分页管理内存并减少频繁的内存分配来提高性能。
|
||||
```go
|
||||
type PagedSlice[T any] struct {
|
||||
pages [][]T
|
||||
pageSize int
|
||||
len int
|
||||
lenLast int
|
||||
}
|
||||
```
|
||||
#### func (*PagedSlice) Add(value T)
|
||||
> 添加一个元素到 PagedSlice 中。
|
||||
***
|
||||
#### func (*PagedSlice) Get(index int) *T
|
||||
> 获取 PagedSlice 中给定索引的元素。
|
||||
***
|
||||
#### func (*PagedSlice) Set(index int, value T)
|
||||
> 设置 PagedSlice 中给定索引的元素。
|
||||
***
|
||||
#### func (*PagedSlice) Len() int
|
||||
> 返回 PagedSlice 中元素的数量。
|
||||
***
|
||||
#### func (*PagedSlice) Clear()
|
||||
> 清空 PagedSlice。
|
||||
***
|
||||
#### func (*PagedSlice) Range(f func (index int, value T) bool)
|
||||
> 迭代 PagedSlice 中的所有元素。
|
||||
***
|
||||
### PrioritySlice `STRUCT`
|
||||
是一个优先级切片
|
||||
```go
|
||||
type PrioritySlice[V any] struct {
|
||||
items []*priorityItem[V]
|
||||
}
|
||||
```
|
||||
#### func (*PrioritySlice) Len() int
|
||||
> 返回切片长度
|
||||
***
|
||||
#### func (*PrioritySlice) Cap() int
|
||||
> 返回切片容量
|
||||
***
|
||||
#### func (*PrioritySlice) Clear()
|
||||
> 清空切片
|
||||
***
|
||||
#### func (*PrioritySlice) Append(v V, p int)
|
||||
> 添加元素
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestPrioritySlice_Append(t *testing.T) {
|
||||
var s = listings.NewPrioritySlice[string]()
|
||||
s.Append("name_1", 2)
|
||||
s.Append("name_2", 1)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*PrioritySlice) Appends(priority int, vs ...V)
|
||||
> 添加元素
|
||||
***
|
||||
#### func (*PrioritySlice) Get(index int) V, int
|
||||
> 获取元素
|
||||
***
|
||||
#### func (*PrioritySlice) GetValue(index int) V
|
||||
> 获取元素值
|
||||
***
|
||||
#### func (*PrioritySlice) GetPriority(index int) int
|
||||
> 获取元素优先级
|
||||
***
|
||||
#### func (*PrioritySlice) Set(index int, value V, priority int)
|
||||
> 设置元素
|
||||
***
|
||||
#### func (*PrioritySlice) SetValue(index int, value V)
|
||||
> 设置元素值
|
||||
***
|
||||
#### func (*PrioritySlice) SetPriority(index int, priority int)
|
||||
> 设置元素优先级
|
||||
***
|
||||
#### func (*PrioritySlice) Action(action func (items []*priorityItem[V]) []*priorityItem[V])
|
||||
> 直接操作切片,如果返回值不为 nil,则替换切片
|
||||
***
|
||||
#### func (*PrioritySlice) Range(action func (index int, item *priorityItem[V]) bool)
|
||||
> 遍历切片,如果返回值为 false,则停止遍历
|
||||
***
|
||||
#### func (*PrioritySlice) RangeValue(action func (index int, value V) bool)
|
||||
> 遍历切片值,如果返回值为 false,则停止遍历
|
||||
***
|
||||
#### func (*PrioritySlice) RangePriority(action func (index int, priority int) bool)
|
||||
> 遍历切片优先级,如果返回值为 false,则停止遍历
|
||||
***
|
||||
#### func (*PrioritySlice) Slice() []V
|
||||
> 返回切片
|
||||
***
|
||||
#### func (*PrioritySlice) String() string
|
||||
> 返回切片字符串
|
||||
***
|
||||
### SyncSlice `STRUCT`
|
||||
是基于 sync.RWMutex 实现的线程安全的 slice
|
||||
```go
|
||||
type SyncSlice[V any] struct {
|
||||
rw sync.RWMutex
|
||||
data []V
|
||||
}
|
||||
```
|
||||
#### func (*SyncSlice) Get(index int) V
|
||||
***
|
||||
#### func (*SyncSlice) GetWithRange(start int, end int) []V
|
||||
***
|
||||
#### func (*SyncSlice) Set(index int, value V)
|
||||
***
|
||||
#### func (*SyncSlice) Append(values ...V)
|
||||
***
|
||||
#### func (*SyncSlice) Release()
|
||||
***
|
||||
#### func (*SyncSlice) Clear()
|
||||
***
|
||||
#### func (*SyncSlice) GetData() []V
|
||||
***
|
|
@ -0,0 +1,47 @@
|
|||
# Mappings
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewSyncMap](#NewSyncMap)|创建一个 SyncMap
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[SyncMap](#syncmap)|是基于 sync.RWMutex 实现的线程安全的 map
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewSyncMap(source ...map[K]V) *SyncMap[K, V]
|
||||
<span id="NewSyncMap"></span>
|
||||
> 创建一个 SyncMap
|
||||
|
||||
***
|
||||
### SyncMap `STRUCT`
|
||||
是基于 sync.RWMutex 实现的线程安全的 map
|
||||
- 适用于要考虑并发读写但是并发读写的频率不高的情况
|
||||
```go
|
||||
type SyncMap[K comparable, V any] struct {
|
||||
lock sync.RWMutex
|
||||
data map[K]V
|
||||
atom bool
|
||||
}
|
||||
```
|
|
@ -1,25 +1,389 @@
|
|||
# Combination
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/combination)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
`Combination` 包是一个实用的工具,提供了一系列用于生成和处理组合的函数,以帮助开发者处理复杂的组合问题。
|
||||
combination 包提供了一些实用的组合函数。
|
||||
|
||||
## 特性
|
||||
|
||||
### 泛型类型
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
在 `Minotaur` 中,我们的组合函数是泛型类型,这意味着它们可以处理任意类型的元素,为开发者提供了灵活性,使得这个包可以在各种不同的场景和应用中使用。
|
||||
|
||||
### 算法描述
|
||||
> 包级函数定义
|
||||
|
||||
我们的组合函数使用了特定的算法,以便快速地生成和处理组合。这些算法被设计为能够处理各种复杂的组合问题,以确保结果的准确性。
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewCombination](#NewCombination)|创建一个新的组合器
|
||||
|[WithEvaluation](#WithEvaluation)|设置组合评估函数
|
||||
|[NewMatcher](#NewMatcher)|创建一个新的匹配器
|
||||
|[WithMatcherEvaluation](#WithMatcherEvaluation)|设置匹配器评估函数
|
||||
|[WithMatcherLeastLength](#WithMatcherLeastLength)|通过匹配最小长度的组合创建匹配器
|
||||
|[WithMatcherLength](#WithMatcherLength)|通过匹配长度的组合创建匹配器
|
||||
|[WithMatcherMostLength](#WithMatcherMostLength)|通过匹配最大长度的组合创建匹配器
|
||||
|[WithMatcherIntervalLength](#WithMatcherIntervalLength)|通过匹配长度区间的组合创建匹配器
|
||||
|[WithMatcherContinuity](#WithMatcherContinuity)|通过匹配连续的组合创建匹配器
|
||||
|[WithMatcherSame](#WithMatcherSame)|通过匹配相同的组合创建匹配器
|
||||
|[WithMatcherNCarryM](#WithMatcherNCarryM)|通过匹配 N 携带 M 的组合创建匹配器
|
||||
|[WithMatcherNCarryIndependentM](#WithMatcherNCarryIndependentM)|通过匹配 N 携带独立 M 的组合创建匹配器
|
||||
|[NewValidator](#NewValidator)|创建一个新的校验器
|
||||
|[WithValidatorHandle](#WithValidatorHandle)|通过特定的验证函数对组合进行验证
|
||||
|[WithValidatorHandleLength](#WithValidatorHandleLength)|校验组合的长度是否符合要求
|
||||
|[WithValidatorHandleLengthRange](#WithValidatorHandleLengthRange)|校验组合的长度是否在指定的范围内
|
||||
|[WithValidatorHandleLengthMin](#WithValidatorHandleLengthMin)|校验组合的长度是否大于等于指定的最小值
|
||||
|[WithValidatorHandleLengthMax](#WithValidatorHandleLengthMax)|校验组合的长度是否小于等于指定的最大值
|
||||
|[WithValidatorHandleLengthNot](#WithValidatorHandleLengthNot)|校验组合的长度是否不等于指定的值
|
||||
|[WithValidatorHandleTypeLength](#WithValidatorHandleTypeLength)|校验组合成员类型数量是否为指定的值
|
||||
|[WithValidatorHandleTypeLengthRange](#WithValidatorHandleTypeLengthRange)|校验组合成员类型数量是否在指定的范围内
|
||||
|[WithValidatorHandleTypeLengthMin](#WithValidatorHandleTypeLengthMin)|校验组合成员类型数量是否大于等于指定的最小值
|
||||
|[WithValidatorHandleTypeLengthMax](#WithValidatorHandleTypeLengthMax)|校验组合成员类型数量是否小于等于指定的最大值
|
||||
|[WithValidatorHandleTypeLengthNot](#WithValidatorHandleTypeLengthNot)|校验组合成员类型数量是否不等于指定的值
|
||||
|[WithValidatorHandleContinuous](#WithValidatorHandleContinuous)|校验组合成员是否连续
|
||||
|[WithValidatorHandleContinuousNot](#WithValidatorHandleContinuousNot)|校验组合成员是否不连续
|
||||
|[WithValidatorHandleGroupContinuous](#WithValidatorHandleGroupContinuous)|校验组合成员是否能够按类型分组并且连续
|
||||
|[WithValidatorHandleGroupContinuousN](#WithValidatorHandleGroupContinuousN)|校验组合成员是否能够按分组为 n 组类型并且连续
|
||||
|[WithValidatorHandleNCarryM](#WithValidatorHandleNCarryM)| 校验组合成员是否匹配 N 携带相同的 M 的组合
|
||||
|[WithValidatorHandleNCarryIndependentM](#WithValidatorHandleNCarryIndependentM)|校验组合成员是否匹配 N 携带独立的 M 的组合
|
||||
|
||||
### 易于使用
|
||||
|
||||
`Combination` 包的设计目标是使得开发者可以轻松地使用它。我们提供了清晰的文档和指南,帮助开发者理解和使用我们的组合函数。
|
||||
> 类型定义
|
||||
|
||||
## 用途
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Combination](#combination)|用于从多个匹配器内提取组合的数据结构
|
||||
|`STRUCT`|[Option](#option)|组合器选项
|
||||
|`INTERFACE`|[Item](#item)|暂无描述...
|
||||
|`STRUCT`|[Matcher](#matcher)|用于从一组数据内提取组合的数据结构
|
||||
|`STRUCT`|[MatcherOption](#matcheroption)|匹配器选项
|
||||
|`STRUCT`|[Validator](#validator)|用于对组合进行验证的校验器
|
||||
|`STRUCT`|[ValidatorOption](#validatoroption)|暂无描述...
|
||||
|
||||
`Combination` 包可以在处理任何涉及到组合的问题时使用。无论是在数据分析、机器学习、算法设计,还是在其他需要处理组合的场景中,`Combination` 包都能够提供帮助。
|
||||
</details>
|
||||
|
||||
我们鼓励开发者探索 `Combination` 包的可能用途,并分享他们的经验和发现。
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewCombination(options ...Option[T]) *Combination[T]
|
||||
<span id="NewCombination"></span>
|
||||
> 创建一个新的组合器
|
||||
|
||||
***
|
||||
#### func WithEvaluation(evaluate func (items []T) float64) Option[T]
|
||||
<span id="WithEvaluation"></span>
|
||||
> 设置组合评估函数
|
||||
> - 用于对组合进行评估,返回一个分值的评价函数
|
||||
> - 通过该选项将设置所有匹配器的默认评估函数为该函数
|
||||
> - 通过匹配器选项 WithMatcherEvaluation 可以覆盖该默认评估函数
|
||||
> - 默认的评估函数将返回一个随机数
|
||||
|
||||
***
|
||||
#### func NewMatcher(options ...MatcherOption[T]) *Matcher[T]
|
||||
<span id="NewMatcher"></span>
|
||||
> 创建一个新的匹配器
|
||||
|
||||
***
|
||||
#### func WithMatcherEvaluation(evaluate func (items []T) float64) MatcherOption[T]
|
||||
<span id="WithMatcherEvaluation"></span>
|
||||
> 设置匹配器评估函数
|
||||
> - 用于对组合进行评估,返回一个分值的评价函数
|
||||
> - 通过该选项将覆盖匹配器的默认(WithEvaluation)评估函数
|
||||
|
||||
***
|
||||
#### func WithMatcherLeastLength(length int) MatcherOption[T]
|
||||
<span id="WithMatcherLeastLength"></span>
|
||||
> 通过匹配最小长度的组合创建匹配器
|
||||
> - length: 组合的长度,表示需要匹配的组合最小数量
|
||||
|
||||
***
|
||||
#### func WithMatcherLength(length int) MatcherOption[T]
|
||||
<span id="WithMatcherLength"></span>
|
||||
> 通过匹配长度的组合创建匹配器
|
||||
> - length: 组合的长度,表示需要匹配的组合数量
|
||||
|
||||
***
|
||||
#### func WithMatcherMostLength(length int) MatcherOption[T]
|
||||
<span id="WithMatcherMostLength"></span>
|
||||
> 通过匹配最大长度的组合创建匹配器
|
||||
> - length: 组合的长度,表示需要匹配的组合最大数量
|
||||
|
||||
***
|
||||
#### func WithMatcherIntervalLength(min int, max int) MatcherOption[T]
|
||||
<span id="WithMatcherIntervalLength"></span>
|
||||
> 通过匹配长度区间的组合创建匹配器
|
||||
> - min: 组合的最小长度,表示需要匹配的组合最小数量
|
||||
> - max: 组合的最大长度,表示需要匹配的组合最大数量
|
||||
|
||||
***
|
||||
#### func WithMatcherContinuity(getIndex func (item T) Index) MatcherOption[T]
|
||||
<span id="WithMatcherContinuity"></span>
|
||||
> 通过匹配连续的组合创建匹配器
|
||||
> - index: 用于获取组合中元素的索引值,用于判断是否连续
|
||||
|
||||
***
|
||||
#### func WithMatcherSame(count int, getType func (item T) E) MatcherOption[T]
|
||||
<span id="WithMatcherSame"></span>
|
||||
> 通过匹配相同的组合创建匹配器
|
||||
> - count: 组合中相同元素的数量,当 count <= 0 时,表示相同元素的数量不限
|
||||
> - getType: 用于获取组合中元素的类型,用于判断是否相同
|
||||
|
||||
***
|
||||
#### func WithMatcherNCarryM(n int, m int, getType func (item T) E) MatcherOption[T]
|
||||
<span id="WithMatcherNCarryM"></span>
|
||||
> 通过匹配 N 携带 M 的组合创建匹配器
|
||||
> - n: 组合中元素的数量,表示需要匹配的组合数量,n 的类型需要全部相同
|
||||
> - m: 组合中元素的数量,表示需要匹配的组合数量,m 的类型需要全部相同
|
||||
> - getType: 用于获取组合中元素的类型,用于判断是否相同
|
||||
|
||||
***
|
||||
#### func WithMatcherNCarryIndependentM(n int, m int, getType func (item T) E) MatcherOption[T]
|
||||
<span id="WithMatcherNCarryIndependentM"></span>
|
||||
> 通过匹配 N 携带独立 M 的组合创建匹配器
|
||||
> - n: 组合中元素的数量,表示需要匹配的组合数量,n 的类型需要全部相同
|
||||
> - m: 组合中元素的数量,表示需要匹配的组合数量,m 的类型无需全部相同
|
||||
> - getType: 用于获取组合中元素的类型,用于判断是否相同
|
||||
|
||||
***
|
||||
#### func NewValidator(options ...ValidatorOption[T]) *Validator[T]
|
||||
<span id="NewValidator"></span>
|
||||
> 创建一个新的校验器
|
||||
|
||||
***
|
||||
#### func WithValidatorHandle(handle func (items []T) bool) ValidatorOption[T]
|
||||
<span id="WithValidatorHandle"></span>
|
||||
> 通过特定的验证函数对组合进行验证
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleLength(length int) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleLength"></span>
|
||||
> 校验组合的长度是否符合要求
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleLengthRange(min int, max int) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleLengthRange"></span>
|
||||
> 校验组合的长度是否在指定的范围内
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleLengthMin(min int) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleLengthMin"></span>
|
||||
> 校验组合的长度是否大于等于指定的最小值
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleLengthMax(max int) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleLengthMax"></span>
|
||||
> 校验组合的长度是否小于等于指定的最大值
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleLengthNot(length int) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleLengthNot"></span>
|
||||
> 校验组合的长度是否不等于指定的值
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleTypeLength(length int, getType func (item T) E) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleTypeLength"></span>
|
||||
> 校验组合成员类型数量是否为指定的值
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleTypeLengthRange(min int, max int, getType func (item T) E) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleTypeLengthRange"></span>
|
||||
> 校验组合成员类型数量是否在指定的范围内
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleTypeLengthMin(min int, getType func (item T) E) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleTypeLengthMin"></span>
|
||||
> 校验组合成员类型数量是否大于等于指定的最小值
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleTypeLengthMax(max int, getType func (item T) E) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleTypeLengthMax"></span>
|
||||
> 校验组合成员类型数量是否小于等于指定的最大值
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleTypeLengthNot(length int, getType func (item T) E) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleTypeLengthNot"></span>
|
||||
> 校验组合成员类型数量是否不等于指定的值
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleContinuous(getIndex func (item T) Index) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleContinuous"></span>
|
||||
> 校验组合成员是否连续
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleContinuousNot(getIndex func (item T) Index) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleContinuousNot"></span>
|
||||
> 校验组合成员是否不连续
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleGroupContinuous(getType func (item T) E, getIndex func (item T) Index) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleGroupContinuous"></span>
|
||||
> 校验组合成员是否能够按类型分组并且连续
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleGroupContinuousN(n int, getType func (item T) E, getIndex func (item T) Index) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleGroupContinuousN"></span>
|
||||
> 校验组合成员是否能够按分组为 n 组类型并且连续
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleNCarryM(n int, m int, getType func (item T) E) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleNCarryM"></span>
|
||||
> 校验组合成员是否匹配 N 携带相同的 M 的组合
|
||||
> - n: 组合中元素的数量,表示需要匹配的组合数量,n 的类型需要全部相同
|
||||
> - m: 组合中元素的数量,表示需要匹配的组合数量,m 的类型需要全部相同
|
||||
> - getType: 用于获取组合中元素的类型,用于判断是否相同
|
||||
|
||||
***
|
||||
#### func WithValidatorHandleNCarryIndependentM(n int, m int, getType func (item T) E) ValidatorOption[T]
|
||||
<span id="WithValidatorHandleNCarryIndependentM"></span>
|
||||
> 校验组合成员是否匹配 N 携带独立的 M 的组合
|
||||
> - n: 组合中元素的数量,表示需要匹配的组合数量,n 的类型需要全部相同
|
||||
> - m: 组合中元素的数量,表示需要匹配的组合数量,m 的类型无需全部相同
|
||||
> - getType: 用于获取组合中元素的类型,用于判断是否相同
|
||||
|
||||
***
|
||||
### Combination `STRUCT`
|
||||
用于从多个匹配器内提取组合的数据结构
|
||||
```go
|
||||
type Combination[T Item] struct {
|
||||
evaluate func([]T) float64
|
||||
matchers map[string]*Matcher[T]
|
||||
priority []string
|
||||
}
|
||||
```
|
||||
#### func (*Combination) NewMatcher(name string, options ...MatcherOption[T]) *Combination[T]
|
||||
> 添加一个新的匹配器
|
||||
***
|
||||
#### func (*Combination) AddMatcher(name string, matcher *Matcher[T]) *Combination[T]
|
||||
> 添加一个匹配器
|
||||
***
|
||||
#### func (*Combination) RemoveMatcher(name string) *Combination[T]
|
||||
> 移除一个匹配器
|
||||
***
|
||||
#### func (*Combination) Combinations(items []T) (result [][]T)
|
||||
> 从一组数据中提取所有符合匹配器规则的组合
|
||||
***
|
||||
#### func (*Combination) CombinationsToName(items []T) (result map[string][][]T)
|
||||
> 从一组数据中提取所有符合匹配器规则的组合,并返回匹配器名称
|
||||
***
|
||||
#### func (*Combination) Best(items []T) (name string, result []T)
|
||||
> 从一组数据中提取符合匹配器规则的最佳组合
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestCombination_Best(t *testing.T) {
|
||||
combine := combination.NewCombination(combination.WithEvaluation(func(items []*Poker) float64 {
|
||||
var total float64
|
||||
for _, item := range items {
|
||||
total += float64(item.Point)
|
||||
}
|
||||
return total
|
||||
}))
|
||||
combine.NewMatcher("炸弹", combination.WithMatcherSame[*Poker, int](4, func(item *Poker) int {
|
||||
return item.Point
|
||||
})).NewMatcher("三带一", combination.WithMatcherNCarryM[*Poker, int](3, 1, func(item *Poker) int {
|
||||
return item.Point
|
||||
}))
|
||||
var cards = []*Poker{{Point: 2, Color: 1}, {Point: 2, Color: 2}, {Point: 2, Color: 3}, {Point: 3, Color: 4}, {Point: 4, Color: 1}, {Point: 4, Color: 2}, {Point: 5, Color: 3}, {Point: 6, Color: 4}, {Point: 7, Color: 1}, {Point: 8, Color: 2}, {Point: 9, Color: 3}, {Point: 10, Color: 4}, {Point: 11, Color: 1}, {Point: 12, Color: 2}, {Point: 13, Color: 3}, {Point: 10, Color: 3}, {Point: 11, Color: 2}, {Point: 12, Color: 1}, {Point: 13, Color: 4}, {Point: 10, Color: 2}}
|
||||
name, result := combine.Worst(cards)
|
||||
fmt.Println("best:", name)
|
||||
for _, item := range result {
|
||||
fmt.Println(item)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Combination) Worst(items []T) (name string, result []T)
|
||||
> 从一组数据中提取符合匹配器规则的最差组合
|
||||
***
|
||||
### Option `STRUCT`
|
||||
组合器选项
|
||||
```go
|
||||
type Option[T Item] func(*Combination[T])
|
||||
```
|
||||
### Item `INTERFACE`
|
||||
|
||||
```go
|
||||
type Item interface{}
|
||||
```
|
||||
### Matcher `STRUCT`
|
||||
用于从一组数据内提取组合的数据结构
|
||||
```go
|
||||
type Matcher[T Item] struct {
|
||||
evaluate func(items []T) float64
|
||||
filter []func(items []T) [][]T
|
||||
}
|
||||
```
|
||||
#### func (*Matcher) AddFilter(filter func (items []T) [][]T)
|
||||
> 添加一个筛选器
|
||||
> - 筛选器用于对组合进行筛选,返回一个二维数组,每个数组内的元素都是一个组合
|
||||
***
|
||||
#### func (*Matcher) Combinations(items []T) [][]T
|
||||
> 从一组数据中提取所有符合筛选器规则的组合
|
||||
***
|
||||
#### func (*Matcher) Best(items []T) []T
|
||||
> 从一组数据中提取符筛选器规则的最佳组合
|
||||
***
|
||||
#### func (*Matcher) Worst(items []T) []T
|
||||
> 从一组数据中提取符筛选器规则的最差组合
|
||||
***
|
||||
### MatcherOption `STRUCT`
|
||||
匹配器选项
|
||||
```go
|
||||
type MatcherOption[T Item] func(matcher *Matcher[T])
|
||||
```
|
||||
### Validator `STRUCT`
|
||||
用于对组合进行验证的校验器
|
||||
```go
|
||||
type Validator[T Item] struct {
|
||||
vh []func(items []T) bool
|
||||
}
|
||||
```
|
||||
#### func (*Validator) Validate(items []T) bool
|
||||
> 校验组合是否符合要求
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestValidator_Validate(t *testing.T) {
|
||||
v := combination.NewValidator[*Card](combination.WithValidatorHandleContinuous[*Card, int](func(item *Card) int {
|
||||
switch item.Point {
|
||||
case "A":
|
||||
return 1
|
||||
case "2", "3", "4", "5", "6", "7", "8", "9", "10":
|
||||
return super.StringToInt(item.Point)
|
||||
case "J":
|
||||
return 11
|
||||
case "Q":
|
||||
return 12
|
||||
case "K":
|
||||
return 13
|
||||
}
|
||||
return -1
|
||||
}), combination.WithValidatorHandleLength[*Card](3))
|
||||
cards := []*Card{{Point: "2", Color: "Spade"}, {Point: "4", Color: "Heart"}, {Point: "3", Color: "Diamond"}}
|
||||
fmt.Println(v.Validate(cards))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### ValidatorOption `STRUCT`
|
||||
|
||||
```go
|
||||
type ValidatorOption[T Item] func(validator *Validator[T])
|
||||
```
|
||||
|
|
|
@ -1,5 +1,62 @@
|
|||
# Compress
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur/utils/compress)
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
该包提供了GZIP、ZIP和TAR的压缩和解压缩实现。开发者可以使用它来快速进行数据的压缩和解压缩。
|
||||
compress 提供了一些用于压缩和解压缩数据的函数。
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[GZipCompress](#GZipCompress)|对数据进行GZip压缩,返回bytes.Buffer和错误信息
|
||||
|[GZipUnCompress](#GZipUnCompress)|对已进行GZip压缩的数据进行解压缩,返回字节数组及错误信息
|
||||
|[TARCompress](#TARCompress)|对数据进行TAR压缩,返回bytes.Buffer和错误信息
|
||||
|[TARUnCompress](#TARUnCompress)|对已进行TAR压缩的数据进行解压缩,返回字节数组及错误信息
|
||||
|[ZIPCompress](#ZIPCompress)|对数据进行ZIP压缩,返回bytes.Buffer和错误信息
|
||||
|[ZIPUnCompress](#ZIPUnCompress)|对已进行ZIP压缩的数据进行解压缩,返回字节数组及错误信息
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func GZipCompress(data []byte) bytes.Buffer, error
|
||||
<span id="GZipCompress"></span>
|
||||
> 对数据进行GZip压缩,返回bytes.Buffer和错误信息
|
||||
|
||||
***
|
||||
#### func GZipUnCompress(dataByte []byte) []byte, error
|
||||
<span id="GZipUnCompress"></span>
|
||||
> 对已进行GZip压缩的数据进行解压缩,返回字节数组及错误信息
|
||||
|
||||
***
|
||||
#### func TARCompress(data []byte) bytes.Buffer, error
|
||||
<span id="TARCompress"></span>
|
||||
> 对数据进行TAR压缩,返回bytes.Buffer和错误信息
|
||||
|
||||
***
|
||||
#### func TARUnCompress(dataByte []byte) []byte, error
|
||||
<span id="TARUnCompress"></span>
|
||||
> 对已进行TAR压缩的数据进行解压缩,返回字节数组及错误信息
|
||||
|
||||
***
|
||||
#### func ZIPCompress(data []byte) bytes.Buffer, error
|
||||
<span id="ZIPCompress"></span>
|
||||
> 对数据进行ZIP压缩,返回bytes.Buffer和错误信息
|
||||
|
||||
***
|
||||
#### func ZIPUnCompress(dataByte []byte) []byte, error
|
||||
<span id="ZIPUnCompress"></span>
|
||||
> 对已进行ZIP压缩的数据进行解压缩,返回字节数组及错误信息
|
||||
|
||||
***
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
# Crypto
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[EncryptBase64](#EncryptBase64)|对数据进行Base64编码
|
||||
|[DecodedBase64](#DecodedBase64)|对数据进行Base64解码
|
||||
|[EncryptCRC32](#EncryptCRC32)|对字符串进行CRC加密并返回其结果。
|
||||
|[DecodedCRC32](#DecodedCRC32)|对字节数组进行CRC加密并返回其结果。
|
||||
|[EncryptMD5](#EncryptMD5)|对字符串进行MD5加密并返回其结果。
|
||||
|[DecodedMD5](#DecodedMD5)|对字节数组进行MD5加密并返回其结果。
|
||||
|[EncryptSHA1](#EncryptSHA1)|对字符串进行SHA1加密并返回其结果。
|
||||
|[DecodedSHA1](#DecodedSHA1)|对字节数组进行SHA1加密并返回其结果。
|
||||
|[EncryptSHA256](#EncryptSHA256)|对字符串进行SHA256加密并返回其结果。
|
||||
|[DecodedSHA256](#DecodedSHA256)|对字节数组进行SHA256加密并返回其结果。
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func EncryptBase64(data []byte) string
|
||||
<span id="EncryptBase64"></span>
|
||||
> 对数据进行Base64编码
|
||||
|
||||
***
|
||||
#### func DecodedBase64(data string) []byte, error
|
||||
<span id="DecodedBase64"></span>
|
||||
> 对数据进行Base64解码
|
||||
|
||||
***
|
||||
#### func EncryptCRC32(str string) uint32
|
||||
<span id="EncryptCRC32"></span>
|
||||
> 对字符串进行CRC加密并返回其结果。
|
||||
|
||||
***
|
||||
#### func DecodedCRC32(data []byte) uint32
|
||||
<span id="DecodedCRC32"></span>
|
||||
> 对字节数组进行CRC加密并返回其结果。
|
||||
|
||||
***
|
||||
#### func EncryptMD5(str string) string
|
||||
<span id="EncryptMD5"></span>
|
||||
> 对字符串进行MD5加密并返回其结果。
|
||||
|
||||
***
|
||||
#### func DecodedMD5(data []byte) string
|
||||
<span id="DecodedMD5"></span>
|
||||
> 对字节数组进行MD5加密并返回其结果。
|
||||
|
||||
***
|
||||
#### func EncryptSHA1(str string) string
|
||||
<span id="EncryptSHA1"></span>
|
||||
> 对字符串进行SHA1加密并返回其结果。
|
||||
|
||||
***
|
||||
#### func DecodedSHA1(data []byte) string
|
||||
<span id="DecodedSHA1"></span>
|
||||
> 对字节数组进行SHA1加密并返回其结果。
|
||||
|
||||
***
|
||||
#### func EncryptSHA256(str string) string
|
||||
<span id="EncryptSHA256"></span>
|
||||
> 对字符串进行SHA256加密并返回其结果。
|
||||
|
||||
***
|
||||
#### func DecodedSHA256(data []byte) string
|
||||
<span id="DecodedSHA256"></span>
|
||||
> 对字节数组进行SHA256加密并返回其结果。
|
||||
|
||||
***
|
|
@ -0,0 +1,133 @@
|
|||
# Deck
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
deck 包中的内容用于针对一堆内容的管理,适用但不限于牌堆、麻将牌堆等情况。
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewDeck](#NewDeck)|创建一个新的甲板
|
||||
|[NewGroup](#NewGroup)|创建一个新的组
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Deck](#deck)|甲板,用于针对一堆 Group 进行管理的数据结构
|
||||
|`STRUCT`|[Group](#group)|甲板中的组,用于针对一堆内容进行管理的数据结构
|
||||
|`INTERFACE`|[Item](#item)|甲板成员
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewDeck() *Deck[I]
|
||||
<span id="NewDeck"></span>
|
||||
> 创建一个新的甲板
|
||||
|
||||
***
|
||||
#### func NewGroup(guid int64, fillHandle func (guid int64) []I) *Group[I]
|
||||
<span id="NewGroup"></span>
|
||||
> 创建一个新的组
|
||||
|
||||
***
|
||||
### Deck `STRUCT`
|
||||
甲板,用于针对一堆 Group 进行管理的数据结构
|
||||
```go
|
||||
type Deck[I Item] struct {
|
||||
groups map[int64]*Group[I]
|
||||
sort []int64
|
||||
}
|
||||
```
|
||||
#### func (*Deck) AddGroup(group *Group[I])
|
||||
> 将一个组添加到甲板中
|
||||
***
|
||||
#### func (*Deck) RemoveGroup(guid int64)
|
||||
> 移除甲板中的一个组
|
||||
***
|
||||
#### func (*Deck) GetCount() int
|
||||
> 获取甲板中的组数量
|
||||
***
|
||||
#### func (*Deck) GetGroups() map[int64]*Group[I]
|
||||
> 获取所有组
|
||||
***
|
||||
#### func (*Deck) GetGroupsSlice() []*Group[I]
|
||||
> 获取所有组
|
||||
***
|
||||
#### func (*Deck) GetNext(guid int64) *Group[I]
|
||||
> 获取特定组的下一个组
|
||||
***
|
||||
#### func (*Deck) GetPrev(guid int64) *Group[I]
|
||||
> 获取特定组的上一个组
|
||||
***
|
||||
### Group `STRUCT`
|
||||
甲板中的组,用于针对一堆内容进行管理的数据结构
|
||||
```go
|
||||
type Group[I Item] struct {
|
||||
guid int64
|
||||
fillHandle func(guid int64) []I
|
||||
items []I
|
||||
}
|
||||
```
|
||||
#### func (*Group) GetGuid() int64
|
||||
> 获取组的 guid
|
||||
***
|
||||
#### func (*Group) Fill()
|
||||
> 将该组的数据填充为 WithGroupFillHandle 中设置的内容
|
||||
***
|
||||
#### func (*Group) Pop() (item I)
|
||||
> 从顶部获取一个内容
|
||||
***
|
||||
#### func (*Group) PopN(n int) (items []I)
|
||||
> 从顶部获取指定数量的内容
|
||||
***
|
||||
#### func (*Group) PressOut() (item I)
|
||||
> 从底部压出一个内容
|
||||
***
|
||||
#### func (*Group) PressOutN(n int) (items []I)
|
||||
> 从底部压出指定数量的内容
|
||||
***
|
||||
#### func (*Group) Push(item I)
|
||||
> 向顶部压入一个内容
|
||||
***
|
||||
#### func (*Group) PushN(items []I)
|
||||
> 向顶部压入指定数量的内容
|
||||
***
|
||||
#### func (*Group) Insert(item I)
|
||||
> 向底部插入一个内容
|
||||
***
|
||||
#### func (*Group) InsertN(items []I)
|
||||
> 向底部插入指定数量的内容
|
||||
***
|
||||
#### func (*Group) Pull(index int) (item I)
|
||||
> 从特定位置拔出一个内容
|
||||
***
|
||||
#### func (*Group) Thrust(index int, item I)
|
||||
> 向特定位置插入一个内容
|
||||
***
|
||||
#### func (*Group) IsFree() bool
|
||||
> 检查组是否为空
|
||||
***
|
||||
#### func (*Group) GetCount() int
|
||||
> 获取组中剩余的内容数量
|
||||
***
|
||||
#### func (*Group) GetItem(index int) I
|
||||
> 获取组中的指定内容
|
||||
***
|
||||
### Item `INTERFACE`
|
||||
甲板成员
|
||||
```go
|
||||
type Item interface{}
|
||||
```
|
|
@ -0,0 +1,103 @@
|
|||
# File
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[PathExist](#PathExist)|路径是否存在
|
||||
|[IsDir](#IsDir)|路径是否是文件夹
|
||||
|[WriterFile](#WriterFile)|向特定文件写入内容
|
||||
|[ReadOnce](#ReadOnce)|单次读取文件
|
||||
|[ReadBlockHook](#ReadBlockHook)|分块读取文件
|
||||
|[ReadLine](#ReadLine)|分行读取文件
|
||||
|[LineCount](#LineCount)|统计文件行数
|
||||
|[Paths](#Paths)|获取指定目录下的所有文件路径
|
||||
|[ReadLineWithParallel](#ReadLineWithParallel)|并行的分行读取文件并行处理,处理过程中会将每一行的内容传入 handlerFunc 中进行处理
|
||||
|[FindLineChunks](#FindLineChunks)|查找文件按照每行划分的分块,每个分块的大小将在 chunkSize 和分割后的分块距离行首及行尾的距离中范围内
|
||||
|[FindLineChunksByOffset](#FindLineChunksByOffset)|该函数与 FindLineChunks 类似,不同的是该函数可以指定 offset 从指定位置开始读取文件
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func PathExist(path string) bool, error
|
||||
<span id="PathExist"></span>
|
||||
> 路径是否存在
|
||||
|
||||
***
|
||||
#### func IsDir(path string) bool, error
|
||||
<span id="IsDir"></span>
|
||||
> 路径是否是文件夹
|
||||
|
||||
***
|
||||
#### func WriterFile(filePath string, content []byte) error
|
||||
<span id="WriterFile"></span>
|
||||
> 向特定文件写入内容
|
||||
|
||||
***
|
||||
#### func ReadOnce(filePath string) []byte, error
|
||||
<span id="ReadOnce"></span>
|
||||
> 单次读取文件
|
||||
> - 一次性对整个文件进行读取,小文件读取可以很方便的一次性将文件内容读取出来,而大文件读取会造成性能影响。
|
||||
|
||||
***
|
||||
#### func ReadBlockHook(filePath string, bufferSize int, hook func (data []byte)) error
|
||||
<span id="ReadBlockHook"></span>
|
||||
> 分块读取文件
|
||||
> - 将filePath路径对应的文件数据并将读到的每一部分传入hook函数中,当过程中如果产生错误则会返回error。
|
||||
> - 分块读取可以在读取速度和内存消耗之间有一个很好的平衡。
|
||||
|
||||
***
|
||||
#### func ReadLine(filePath string, hook func (line string)) error
|
||||
<span id="ReadLine"></span>
|
||||
> 分行读取文件
|
||||
> - 将filePath路径对应的文件数据并将读到的每一行传入hook函数中,当过程中如果产生错误则会返回error。
|
||||
|
||||
***
|
||||
#### func LineCount(filePath string) int
|
||||
<span id="LineCount"></span>
|
||||
> 统计文件行数
|
||||
|
||||
***
|
||||
#### func Paths(dir string) []string
|
||||
<span id="Paths"></span>
|
||||
> 获取指定目录下的所有文件路径
|
||||
> - 包括了子目录下的文件
|
||||
> - 不包含目录
|
||||
|
||||
***
|
||||
#### func ReadLineWithParallel(filename string, chunkSize int64, handlerFunc func ( string), start ...int64) (n int64, err error)
|
||||
<span id="ReadLineWithParallel"></span>
|
||||
> 并行的分行读取文件并行处理,处理过程中会将每一行的内容传入 handlerFunc 中进行处理
|
||||
> - 由于是并行处理,所以处理过程中的顺序是不确定的。
|
||||
> - 可通过 start 参数指定开始读取的位置,如果不指定则从文件开头开始读取。
|
||||
|
||||
***
|
||||
#### func FindLineChunks(file *os.File, chunkSize int64) [][2]int64
|
||||
<span id="FindLineChunks"></span>
|
||||
> 查找文件按照每行划分的分块,每个分块的大小将在 chunkSize 和分割后的分块距离行首及行尾的距离中范围内
|
||||
> - 使用该函数得到的分块是完整的行,不会出现行被分割的情况
|
||||
> - 当过程中发生错误将会发生 panic
|
||||
> - 返回值的成员是一个长度为 2 的数组,第一个元素是分块的起始位置,第二个元素是分块的结束位置
|
||||
|
||||
***
|
||||
#### func FindLineChunksByOffset(file *os.File, offset int64, chunkSize int64) [][2]int64
|
||||
<span id="FindLineChunksByOffset"></span>
|
||||
> 该函数与 FindLineChunks 类似,不同的是该函数可以指定 offset 从指定位置开始读取文件
|
||||
|
||||
***
|
|
@ -0,0 +1,91 @@
|
|||
# Fsm
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewFSM](#NewFSM)|创建一个新的状态机
|
||||
|[WithEnterBeforeEvent](#WithEnterBeforeEvent)|设置状态进入前的回调
|
||||
|[WithEnterAfterEvent](#WithEnterAfterEvent)|设置状态进入后的回调
|
||||
|[WithUpdateEvent](#WithUpdateEvent)|设置状态内刷新的回调
|
||||
|[WithExitBeforeEvent](#WithExitBeforeEvent)|设置状态退出前的回调
|
||||
|[WithExitAfterEvent](#WithExitAfterEvent)|设置状态退出后的回调
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[FSM](#fsm)|状态机
|
||||
|`STRUCT`|[Option](#option)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewFSM(data Data) *FSM[State, Data]
|
||||
<span id="NewFSM"></span>
|
||||
> 创建一个新的状态机
|
||||
|
||||
***
|
||||
#### func WithEnterBeforeEvent(fn func (state *FSM[State, Data])) Option[State, Data]
|
||||
<span id="WithEnterBeforeEvent"></span>
|
||||
> 设置状态进入前的回调
|
||||
> - 在首次设置状态时,状态机本身的当前状态为零值状态
|
||||
|
||||
***
|
||||
#### func WithEnterAfterEvent(fn func (state *FSM[State, Data])) Option[State, Data]
|
||||
<span id="WithEnterAfterEvent"></span>
|
||||
> 设置状态进入后的回调
|
||||
|
||||
***
|
||||
#### func WithUpdateEvent(fn func (state *FSM[State, Data])) Option[State, Data]
|
||||
<span id="WithUpdateEvent"></span>
|
||||
> 设置状态内刷新的回调
|
||||
|
||||
***
|
||||
#### func WithExitBeforeEvent(fn func (state *FSM[State, Data])) Option[State, Data]
|
||||
<span id="WithExitBeforeEvent"></span>
|
||||
> 设置状态退出前的回调
|
||||
> - 该阶段状态机的状态为退出前的状态,而非新的状态
|
||||
|
||||
***
|
||||
#### func WithExitAfterEvent(fn func (state *FSM[State, Data])) Option[State, Data]
|
||||
<span id="WithExitAfterEvent"></span>
|
||||
> 设置状态退出后的回调
|
||||
> - 该阶段状态机的状态为新的状态,而非退出前的状态
|
||||
|
||||
***
|
||||
### FSM `STRUCT`
|
||||
状态机
|
||||
```go
|
||||
type FSM[State comparable, Data any] struct {
|
||||
prev *State
|
||||
current *State
|
||||
data Data
|
||||
states map[State]struct{}
|
||||
enterBeforeEventHandles map[State][]func(state *FSM[State, Data])
|
||||
enterAfterEventHandles map[State][]func(state *FSM[State, Data])
|
||||
updateEventHandles map[State][]func(state *FSM[State, Data])
|
||||
exitBeforeEventHandles map[State][]func(state *FSM[State, Data])
|
||||
exitAfterEventHandles map[State][]func(state *FSM[State, Data])
|
||||
}
|
||||
```
|
||||
### Option `STRUCT`
|
||||
|
||||
```go
|
||||
type Option[State comparable, Data any] func(fsm *FSM[State, Data], state State)
|
||||
```
|
|
@ -0,0 +1,163 @@
|
|||
# Astgo
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewPackage](#NewPackage)|暂无描述...
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Comment](#comment)|暂无描述...
|
||||
|`STRUCT`|[Field](#field)|暂无描述...
|
||||
|`STRUCT`|[File](#file)|暂无描述...
|
||||
|`STRUCT`|[Function](#function)|暂无描述...
|
||||
|`STRUCT`|[Package](#package)|暂无描述...
|
||||
|`STRUCT`|[Struct](#struct)|暂无描述...
|
||||
|`STRUCT`|[Type](#type)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewPackage(dir string) *Package, error
|
||||
<span id="NewPackage"></span>
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewPackage(t *testing.T) {
|
||||
p, err := astgo.NewPackage(`/Users/kercylan/Coding.localized/Go/minotaur/server`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(super.MarshalIndentJSON(p, "", " ")))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### Comment `STRUCT`
|
||||
|
||||
```go
|
||||
type Comment struct {
|
||||
Comments []string
|
||||
Clear []string
|
||||
}
|
||||
```
|
||||
### Field `STRUCT`
|
||||
|
||||
```go
|
||||
type Field struct {
|
||||
Anonymous bool
|
||||
Name string
|
||||
Type *Type
|
||||
Comments *Comment
|
||||
}
|
||||
```
|
||||
### File `STRUCT`
|
||||
|
||||
```go
|
||||
type File struct {
|
||||
af *ast.File
|
||||
owner *Package
|
||||
FilePath string
|
||||
Structs []*Struct
|
||||
Functions []*Function
|
||||
Comment *Comment
|
||||
}
|
||||
```
|
||||
#### func (*File) Package() string
|
||||
***
|
||||
### Function `STRUCT`
|
||||
|
||||
```go
|
||||
type Function struct {
|
||||
decl *ast.FuncDecl
|
||||
Name string
|
||||
Internal bool
|
||||
Generic []*Field
|
||||
Params []*Field
|
||||
Results []*Field
|
||||
Comments *Comment
|
||||
Struct *Field
|
||||
IsExample bool
|
||||
IsTest bool
|
||||
IsBenchmark bool
|
||||
Test bool
|
||||
}
|
||||
```
|
||||
#### func (*Function) Code() string
|
||||
***
|
||||
### Package `STRUCT`
|
||||
|
||||
```go
|
||||
type Package struct {
|
||||
Dir string
|
||||
Name string
|
||||
Dirs []string
|
||||
Files []*File
|
||||
Functions map[string]*Function
|
||||
}
|
||||
```
|
||||
#### func (*Package) StructFunc(name string) []*Function
|
||||
***
|
||||
#### func (*Package) PackageFunc() []*Function
|
||||
***
|
||||
#### func (*Package) Structs() []*Struct
|
||||
***
|
||||
#### func (*Package) FileComments() *Comment
|
||||
***
|
||||
#### func (*Package) GetUnitTest(f *Function) *Function
|
||||
***
|
||||
#### func (*Package) GetExampleTest(f *Function) *Function
|
||||
***
|
||||
#### func (*Package) GetBenchmarkTest(f *Function) *Function
|
||||
***
|
||||
### Struct `STRUCT`
|
||||
|
||||
```go
|
||||
type Struct struct {
|
||||
Name string
|
||||
Internal bool
|
||||
Interface bool
|
||||
Comments *Comment
|
||||
Generic []*Field
|
||||
Fields []*Field
|
||||
Type *Type
|
||||
Test bool
|
||||
}
|
||||
```
|
||||
### Type `STRUCT`
|
||||
|
||||
```go
|
||||
type Type struct {
|
||||
expr ast.Expr
|
||||
Sign string
|
||||
IsPointer bool
|
||||
Name string
|
||||
}
|
||||
```
|
|
@ -0,0 +1,30 @@
|
|||
package astgo
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newComment(cg *ast.CommentGroup) *Comment {
|
||||
c := &Comment{}
|
||||
if cg == nil {
|
||||
return c
|
||||
}
|
||||
for i, comment := range cg.List {
|
||||
c.Comments = append(c.Comments, comment.Text)
|
||||
cc := strings.TrimPrefix(strings.Replace(comment.Text, "// ", "//", 1), "//")
|
||||
if i == 0 {
|
||||
s := strings.SplitN(cc, " ", 2)
|
||||
if len(s) == 2 {
|
||||
cc = s[1]
|
||||
}
|
||||
}
|
||||
c.Clear = append(c.Clear, cc)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
type Comment struct {
|
||||
Comments []string
|
||||
Clear []string
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package astgo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
)
|
||||
|
||||
func newField(field *ast.Field) []*Field {
|
||||
if len(field.Names) == 0 {
|
||||
return []*Field{{
|
||||
Anonymous: true,
|
||||
Type: newType(field.Type),
|
||||
Comments: newComment(field.Comment),
|
||||
}}
|
||||
} else {
|
||||
var fs []*Field
|
||||
for _, name := range field.Names {
|
||||
if name.String() == "Format" {
|
||||
fmt.Println()
|
||||
}
|
||||
fs = append(fs, &Field{
|
||||
Anonymous: false,
|
||||
Name: name.String(),
|
||||
Type: newType(field.Type),
|
||||
Comments: newComment(field.Comment),
|
||||
})
|
||||
}
|
||||
return fs
|
||||
}
|
||||
}
|
||||
|
||||
type Field struct {
|
||||
Anonymous bool // 匿名字段
|
||||
Name string // 字段名称
|
||||
Type *Type // 字段类型
|
||||
Comments *Comment // 注释
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package astgo
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newFile(owner *Package, filePath string) (*File, error) {
|
||||
af, err := parser.ParseFile(token.NewFileSet(), filePath, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f := &File{
|
||||
af: af,
|
||||
owner: owner,
|
||||
FilePath: filePath,
|
||||
Comment: newComment(af.Doc),
|
||||
}
|
||||
for _, decl := range af.Decls {
|
||||
switch typ := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
f.Functions = append(f.Functions, newFunction(typ))
|
||||
case *ast.GenDecl:
|
||||
_, ok := typ.Specs[0].(*ast.TypeSpec)
|
||||
if ok {
|
||||
s := newStruct(typ)
|
||||
f.Structs = append(f.Structs, s)
|
||||
if strings.HasSuffix(filePath, "_test.go") {
|
||||
s.Test = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
type File struct {
|
||||
af *ast.File // 抽象语法树文件
|
||||
owner *Package // 所属包
|
||||
FilePath string // 文件路径
|
||||
Structs []*Struct // 包含的结构体
|
||||
Functions []*Function // 包含的函数
|
||||
Comment *Comment // 文件注释
|
||||
}
|
||||
|
||||
func (f *File) Package() string {
|
||||
return f.af.Name.String()
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package astgo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/token"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newFunction(astFunc *ast.FuncDecl) *Function {
|
||||
f := &Function{
|
||||
decl: astFunc,
|
||||
Name: astFunc.Name.String(),
|
||||
Comments: newComment(astFunc.Doc),
|
||||
}
|
||||
f.IsTest = strings.HasPrefix(f.Name, "Test")
|
||||
f.IsBenchmark = strings.HasPrefix(f.Name, "Benchmark")
|
||||
f.IsExample = strings.HasPrefix(f.Name, "Example")
|
||||
f.Test = f.IsTest || f.IsBenchmark || f.IsExample
|
||||
f.Internal = f.Name[0] >= 97 && f.Name[0] <= 122
|
||||
if astFunc.Type.TypeParams != nil {
|
||||
for _, field := range astFunc.Type.TypeParams.List {
|
||||
f.Generic = append(f.Generic, newField(field)...)
|
||||
}
|
||||
}
|
||||
if astFunc.Type.Params != nil {
|
||||
for _, field := range astFunc.Type.Params.List {
|
||||
f.Params = append(f.Params, newField(field)...)
|
||||
}
|
||||
}
|
||||
if astFunc.Type.Results != nil {
|
||||
for _, field := range astFunc.Type.Results.List {
|
||||
f.Results = append(f.Results, newField(field)...)
|
||||
}
|
||||
}
|
||||
if astFunc.Recv != nil {
|
||||
f.Struct = newField(astFunc.Recv.List[0])[0]
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
type Function struct {
|
||||
decl *ast.FuncDecl
|
||||
Name string // 函数名
|
||||
Internal bool // 内部函数
|
||||
Generic []*Field // 泛型定义
|
||||
Params []*Field // 参数字段
|
||||
Results []*Field // 返回值字段
|
||||
Comments *Comment // 注释
|
||||
Struct *Field // 结构体函数对应的结构体字段
|
||||
IsExample bool // 是否为测试用例
|
||||
IsTest bool // 是否为单元测试
|
||||
IsBenchmark bool // 是否为基准测试
|
||||
Test bool // 是否为测试函数
|
||||
}
|
||||
|
||||
func (f *Function) Code() string {
|
||||
var bb bytes.Buffer
|
||||
if err := format.Node(&bb, token.NewFileSet(), f.decl); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bb.String() + "\n"
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package astgo
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newName(expr ast.Expr) string {
|
||||
var str strings.Builder
|
||||
switch e := expr.(type) {
|
||||
//case *ast.KeyValueExpr:
|
||||
//case *ast.ArrayType:
|
||||
//case *ast.StructType:
|
||||
//case *ast.FuncType:
|
||||
//case *ast.InterfaceType:
|
||||
//case *ast.MapType:
|
||||
//case *ast.ChanType:
|
||||
case *ast.Ident:
|
||||
str.WriteString(e.Name)
|
||||
case *ast.Ellipsis:
|
||||
str.WriteString(newName(e.Elt))
|
||||
//case *ast.BasicLit:
|
||||
//case *ast.FuncLit:
|
||||
//case *ast.CompositeLit:
|
||||
//case *ast.ParenExpr:
|
||||
case *ast.SelectorExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
case *ast.IndexExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
case *ast.IndexListExpr:
|
||||
case *ast.SliceExpr:
|
||||
case *ast.TypeAssertExpr:
|
||||
case *ast.CallExpr:
|
||||
case *ast.StarExpr:
|
||||
str.WriteString(newName(e.X))
|
||||
case *ast.UnaryExpr:
|
||||
case *ast.BinaryExpr:
|
||||
}
|
||||
return str.String()
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package astgo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/utils/str"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func NewPackage(dir string) (*Package, error) {
|
||||
pkg := &Package{Dir: dir, Functions: map[string]*Function{}}
|
||||
fs, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, f := range fs {
|
||||
path := filepath.Join(pkg.Dir, f.Name())
|
||||
if f.IsDir() {
|
||||
pkg.Dirs = append(pkg.Dirs, path)
|
||||
continue
|
||||
}
|
||||
if filepath.Ext(path) != ".go" {
|
||||
continue
|
||||
}
|
||||
f, err := newFile(pkg, path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
pkg.Files = append(pkg.Files, f)
|
||||
for _, function := range f.Functions {
|
||||
function := function
|
||||
key := function.Name
|
||||
if function.Struct != nil {
|
||||
key = fmt.Sprintf("%s.%s", function.Struct.Name, key)
|
||||
}
|
||||
pkg.Functions[key] = function
|
||||
}
|
||||
}
|
||||
if len(pkg.Files) == 0 {
|
||||
return nil, errors.New("not found go ext file")
|
||||
}
|
||||
pkg.Name = pkg.Files[0].Package()
|
||||
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
type Package struct {
|
||||
Dir string
|
||||
Name string
|
||||
Dirs []string
|
||||
Files []*File
|
||||
Functions map[string]*Function
|
||||
}
|
||||
|
||||
func (p *Package) StructFunc(name string) []*Function {
|
||||
var fs []*Function
|
||||
for _, file := range p.Files {
|
||||
for _, function := range file.Functions {
|
||||
if function.Struct == nil {
|
||||
continue
|
||||
}
|
||||
if function.Struct.Type.Name == name {
|
||||
fs = append(fs, function)
|
||||
}
|
||||
}
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
func (p *Package) PackageFunc() []*Function {
|
||||
var fs []*Function
|
||||
for _, file := range p.Files {
|
||||
for _, function := range file.Functions {
|
||||
if function.Struct == nil {
|
||||
fs = append(fs, function)
|
||||
}
|
||||
}
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
func (p *Package) Structs() []*Struct {
|
||||
var structs []*Struct
|
||||
for _, file := range p.Files {
|
||||
for _, s := range file.Structs {
|
||||
structs = append(structs, s)
|
||||
}
|
||||
}
|
||||
return structs
|
||||
}
|
||||
|
||||
func (p *Package) FileComments() *Comment {
|
||||
var comment = newComment(nil)
|
||||
for _, file := range p.Files {
|
||||
for _, c := range file.Comment.Comments {
|
||||
comment.Comments = append(comment.Comments, c)
|
||||
}
|
||||
for _, c := range file.Comment.Clear {
|
||||
comment.Clear = append(comment.Clear, c)
|
||||
}
|
||||
}
|
||||
return comment
|
||||
}
|
||||
|
||||
func (p *Package) GetUnitTest(f *Function) *Function {
|
||||
if f.Struct == nil {
|
||||
return p.Functions[fmt.Sprintf("Test%s", str.FirstUpper(f.Name))]
|
||||
}
|
||||
return p.Functions[fmt.Sprintf("Test%s_%s", f.Struct.Type.Name, f.Name)]
|
||||
}
|
||||
|
||||
func (p *Package) GetExampleTest(f *Function) *Function {
|
||||
if f.Struct == nil {
|
||||
return p.Functions[fmt.Sprintf("Example%s", str.FirstUpper(f.Name))]
|
||||
}
|
||||
return p.Functions[fmt.Sprintf("Example%s_%s", f.Struct.Type.Name, f.Name)]
|
||||
}
|
||||
|
||||
func (p *Package) GetBenchmarkTest(f *Function) *Function {
|
||||
if f.Struct == nil {
|
||||
return p.Functions[fmt.Sprintf("Benchmark%s", str.FirstUpper(f.Name))]
|
||||
}
|
||||
return p.Functions[fmt.Sprintf("Benchmark%s_%s", f.Struct.Type.Name, f.Name)]
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package astgo_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/utils/generator/astgo"
|
||||
"github.com/kercylan98/minotaur/utils/super"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewPackage(t *testing.T) {
|
||||
p, err := astgo.NewPackage(`/Users/kercylan/Coding.localized/Go/minotaur/server`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(super.MarshalIndentJSON(p, "", " ")))
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package astgo
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
)
|
||||
|
||||
func newStruct(astGen *ast.GenDecl) *Struct {
|
||||
astTypeSpec := astGen.Specs[0].(*ast.TypeSpec)
|
||||
s := &Struct{
|
||||
Name: astTypeSpec.Name.String(),
|
||||
Comments: newComment(astGen.Doc),
|
||||
}
|
||||
s.Internal = s.Name[0] >= 97 && s.Name[0] <= 122
|
||||
if astTypeSpec.TypeParams != nil {
|
||||
for _, field := range astTypeSpec.TypeParams.List {
|
||||
s.Generic = append(s.Generic, newField(field)...)
|
||||
}
|
||||
}
|
||||
|
||||
switch ts := astTypeSpec.Type.(type) {
|
||||
case *ast.StructType:
|
||||
if ts.Fields != nil {
|
||||
for _, field := range ts.Fields.List {
|
||||
s.Fields = append(s.Fields, newField(field)...)
|
||||
}
|
||||
}
|
||||
case *ast.InterfaceType:
|
||||
s.Interface = true
|
||||
if ts.Methods != nil {
|
||||
for _, field := range ts.Methods.List {
|
||||
s.Fields = append(s.Fields, newField(field)...)
|
||||
}
|
||||
}
|
||||
default:
|
||||
s.Type = newType(ts)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type Struct struct {
|
||||
Name string // 结构体名称
|
||||
Internal bool // 内部结构体
|
||||
Interface bool // 接口定义
|
||||
Comments *Comment // 注释
|
||||
Generic []*Field // 泛型类型
|
||||
Fields []*Field // 结构体字段
|
||||
Type *Type // 和结构体字段二选一,处理类似 type a string 的情况
|
||||
Test bool // 是否是测试结构体
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
package astgo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newType(expr ast.Expr) *Type {
|
||||
var typ = &Type{
|
||||
expr: expr,
|
||||
Name: newName(expr),
|
||||
}
|
||||
var str strings.Builder
|
||||
switch e := typ.expr.(type) {
|
||||
case *ast.KeyValueExpr:
|
||||
k, v := newType(e.Key), newType(e.Value)
|
||||
str.WriteString(fmt.Sprintf("%s : %s", k.Sign, v.Sign))
|
||||
case *ast.ArrayType:
|
||||
isSlice := e.Len == nil
|
||||
str.WriteByte('[')
|
||||
if !isSlice {
|
||||
length := newType(e.Len)
|
||||
str.WriteString(length.Sign)
|
||||
}
|
||||
str.WriteByte(']')
|
||||
element := newType(e.Elt)
|
||||
str.WriteString(element.Sign)
|
||||
case *ast.StructType:
|
||||
str.WriteString("struct {")
|
||||
if e.Fields != nil && len(e.Fields.List) > 0 {
|
||||
str.WriteString("\n")
|
||||
for _, field := range e.Fields.List {
|
||||
f := newField(field)[0]
|
||||
str.WriteString(fmt.Sprintf("%s %s\n", f.Name, f.Type.Sign))
|
||||
}
|
||||
}
|
||||
str.WriteString("}")
|
||||
case *ast.FuncType:
|
||||
var handler = func(fls *ast.FieldList) string {
|
||||
var s string
|
||||
if fls != nil {
|
||||
var brackets bool
|
||||
var params []string
|
||||
for _, field := range fls.List {
|
||||
f := newField(field)[0]
|
||||
if !f.Anonymous {
|
||||
brackets = true
|
||||
}
|
||||
params = append(params, fmt.Sprintf("%s %s", f.Name, f.Type.Sign))
|
||||
}
|
||||
s = strings.Join(params, ", ")
|
||||
if brackets {
|
||||
s = "(" + s + ")"
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
str.WriteString(strings.TrimSpace(fmt.Sprintf("func %s %s", func() string {
|
||||
f := handler(e.Params)
|
||||
if len(strings.TrimSpace(f)) == 0 {
|
||||
return "()"
|
||||
}
|
||||
if !strings.HasPrefix(f, "(") {
|
||||
return "(" + f + ")"
|
||||
}
|
||||
return f
|
||||
}(), func() string {
|
||||
f := handler(e.Results)
|
||||
if e.Results != nil && len(e.Results.List) >= 2 && !strings.HasSuffix(f, "(") {
|
||||
return "(" + f + ")"
|
||||
}
|
||||
return f
|
||||
}())))
|
||||
case *ast.InterfaceType:
|
||||
str.WriteString("interface {")
|
||||
if e.Methods != nil && len(e.Methods.List) > 0 {
|
||||
str.WriteString("\n")
|
||||
for _, field := range e.Methods.List {
|
||||
f := newField(field)[0]
|
||||
str.WriteString(fmt.Sprintf("%s\n", f.Type.Sign))
|
||||
}
|
||||
}
|
||||
str.WriteString("}")
|
||||
case *ast.MapType:
|
||||
k, v := newType(e.Key), newType(e.Value)
|
||||
str.WriteString(fmt.Sprintf("map[%s]%s", k.Sign, v.Sign))
|
||||
case *ast.ChanType:
|
||||
t := newType(e.Value)
|
||||
str.WriteString(fmt.Sprintf("chan %s", t.Sign))
|
||||
case *ast.Ident:
|
||||
str.WriteString(e.Name)
|
||||
case *ast.Ellipsis:
|
||||
element := newType(e.Elt)
|
||||
str.WriteString(fmt.Sprintf("...%s", element.Sign))
|
||||
case *ast.BasicLit:
|
||||
str.WriteString(e.Value)
|
||||
//case *ast.FuncLit:
|
||||
//case *ast.CompositeLit:
|
||||
//case *ast.ParenExpr:
|
||||
case *ast.SelectorExpr:
|
||||
t := newType(e.X)
|
||||
str.WriteString(fmt.Sprintf("%s.%s", t.Sign, e.Sel.Name))
|
||||
case *ast.IndexExpr:
|
||||
t := newType(e.X)
|
||||
generic := newType(e.Index)
|
||||
str.WriteString(fmt.Sprintf("%s[%s]", t.Sign, generic.Sign))
|
||||
case *ast.IndexListExpr:
|
||||
self := newType(e.X)
|
||||
var genericStr []string
|
||||
for _, index := range e.Indices {
|
||||
g := newType(index)
|
||||
genericStr = append(genericStr, g.Sign)
|
||||
}
|
||||
str.WriteString(fmt.Sprintf("%s[%s]", self.Sign, strings.Join(genericStr, ", ")))
|
||||
case *ast.SliceExpr:
|
||||
case *ast.TypeAssertExpr:
|
||||
case *ast.CallExpr:
|
||||
case *ast.StarExpr:
|
||||
typ.IsPointer = true
|
||||
t := newType(e.X)
|
||||
str.WriteString(fmt.Sprintf("*%s", t.Sign))
|
||||
case *ast.UnaryExpr:
|
||||
str.WriteString(fmt.Sprintf("%s%s", e.Op.String(), newType(e.X).Sign))
|
||||
case *ast.BinaryExpr:
|
||||
str.WriteString(newType(e.X).Sign)
|
||||
str.WriteString(fmt.Sprintf(" %s ", e.Op.String()))
|
||||
str.WriteString(newType(e.Y).Sign)
|
||||
}
|
||||
typ.Sign = str.String()
|
||||
return typ
|
||||
}
|
||||
|
||||
type Type struct {
|
||||
expr ast.Expr
|
||||
Sign string // 类型签名
|
||||
IsPointer bool // 指针类型
|
||||
Name string // 类型名称
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
# Genreadme
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[New](#New)|暂无描述...
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Builder](#builder)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func New(pkgDirPath string, output string) *Builder, error
|
||||
<span id="New"></span>
|
||||
|
||||
***
|
||||
### Builder `STRUCT`
|
||||
|
||||
```go
|
||||
type Builder struct {
|
||||
p *astgo.Package
|
||||
b *strings.Builder
|
||||
o string
|
||||
}
|
||||
```
|
||||
#### func (*Builder) Generate() error
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestBuilder_Generate(t *testing.T) {
|
||||
filepath.Walk("/Users/kercylan/Coding.localized/Go/minotaur", func(path string, info fs.FileInfo, err error) error {
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(strings.TrimPrefix(path, "/Users/kercylan/Coding.localized/Go/minotaur"), ".") {
|
||||
return nil
|
||||
}
|
||||
b, err := New(path, filepath.Join(path, "README.md"))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if err = b.Generate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,345 @@
|
|||
package genreadme
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/utils/collection"
|
||||
"github.com/kercylan98/minotaur/utils/file"
|
||||
"github.com/kercylan98/minotaur/utils/generator/astgo"
|
||||
"github.com/kercylan98/minotaur/utils/str"
|
||||
"github.com/kercylan98/minotaur/utils/super"
|
||||
"go/format"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func New(pkgDirPath string, output string) (*Builder, error) {
|
||||
p, err := astgo.NewPackage(pkgDirPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := &Builder{
|
||||
p: p,
|
||||
b: new(strings.Builder),
|
||||
o: output,
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
type Builder struct {
|
||||
p *astgo.Package
|
||||
b *strings.Builder
|
||||
o string
|
||||
}
|
||||
|
||||
func (b *Builder) Generate() error {
|
||||
//fmt.Println(string(super.MarshalIndentJSON(b.p, "", " ")))
|
||||
b.genHeader()
|
||||
b.genMenus()
|
||||
b.genStructs()
|
||||
|
||||
return file.WriterFile(b.o, []byte(b.b.String()))
|
||||
}
|
||||
|
||||
func (b *Builder) genHeader() {
|
||||
b.title(1, str.FirstUpper(b.p.Name))
|
||||
b.newLine()
|
||||
b.newLine(fmt.Sprintf(`[](https://pkg.go.dev/github.com/kercylan98/minotaur)`))
|
||||
b.newLine(fmt.Sprintf(``))
|
||||
if len(b.p.FileComments().Clear) != 0 {
|
||||
b.newLine().newLine(b.p.FileComments().Clear...).newLine()
|
||||
} else {
|
||||
b.newLine().newLine("暂无介绍...").newLine()
|
||||
}
|
||||
b.newLine()
|
||||
}
|
||||
|
||||
func (b *Builder) genMenus() {
|
||||
var genTitleOnce sync.Once
|
||||
var genTitle = func() {
|
||||
genTitleOnce.Do(func() {
|
||||
b.title(2, "目录导航")
|
||||
b.newLine("列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️")
|
||||
b.detailsStart("展开 / 折叠目录导航")
|
||||
})
|
||||
}
|
||||
|
||||
packageFunction := b.p.PackageFunc()
|
||||
var structList []*astgo.Struct
|
||||
for _, f := range b.p.Files {
|
||||
if strings.HasSuffix(f.FilePath, "_test.go") {
|
||||
continue
|
||||
}
|
||||
for _, structInfo := range f.Structs {
|
||||
if structInfo.Test || structInfo.Internal {
|
||||
continue
|
||||
}
|
||||
structList = append(structList, structInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if len(packageFunction) > 0 {
|
||||
var pfGenOnce sync.Once
|
||||
var pfGen = func() {
|
||||
pfGenOnce.Do(func() {
|
||||
genTitle()
|
||||
b.quote("包级函数定义").newLine()
|
||||
b.tableCel("函数名称", "描述")
|
||||
})
|
||||
}
|
||||
for _, function := range packageFunction {
|
||||
if function.Test || function.Internal {
|
||||
continue
|
||||
}
|
||||
pfGen()
|
||||
b.tableRow(
|
||||
fmt.Sprintf("[%s](#%s)", function.Name, function.Name),
|
||||
collection.FindFirstOrDefaultInSlice(function.Comments.Clear, "暂无描述..."),
|
||||
)
|
||||
}
|
||||
b.newLine().newLine()
|
||||
}
|
||||
|
||||
if len(structList) > 0 {
|
||||
var structGenOnce sync.Once
|
||||
var structGen = func() {
|
||||
structGenOnce.Do(func() {
|
||||
genTitle()
|
||||
b.quote("类型定义").newLine()
|
||||
b.tableCel("类型", "名称", "描述")
|
||||
})
|
||||
}
|
||||
for _, structInfo := range structList {
|
||||
if structInfo.Test || structInfo.Internal {
|
||||
continue
|
||||
}
|
||||
structGen()
|
||||
b.tableRow(
|
||||
super.If(structInfo.Interface, "`INTERFACE`", "`STRUCT`"),
|
||||
fmt.Sprintf("[%s](#%s)", structInfo.Name, strings.ToLower(structInfo.Name)),
|
||||
collection.FindFirstOrDefaultInSlice(structInfo.Comments.Clear, "暂无描述..."),
|
||||
)
|
||||
}
|
||||
}
|
||||
b.detailsEnd()
|
||||
b.newLine("***")
|
||||
}
|
||||
|
||||
func (b *Builder) genStructs() {
|
||||
var titleOnce sync.Once
|
||||
var titleBuild = func() {
|
||||
titleOnce.Do(func() {
|
||||
b.title(2, "详情信息")
|
||||
})
|
||||
}
|
||||
|
||||
var funcHandler = func(params []*astgo.Field) string {
|
||||
var s string
|
||||
var brackets bool
|
||||
var paramsStr []string
|
||||
for _, field := range params {
|
||||
if !field.Anonymous {
|
||||
brackets = true
|
||||
}
|
||||
paramsStr = append(paramsStr, fmt.Sprintf("%s %s", field.Name, field.Type.Sign))
|
||||
}
|
||||
s = strings.Join(paramsStr, ", ")
|
||||
if brackets {
|
||||
s = "(" + s + ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
for _, function := range b.p.PackageFunc() {
|
||||
if function.Internal || function.Test {
|
||||
continue
|
||||
}
|
||||
titleBuild()
|
||||
b.title(4, strings.TrimSpace(fmt.Sprintf("func %s%s %s",
|
||||
function.Name,
|
||||
func() string {
|
||||
f := funcHandler(function.Params)
|
||||
if !strings.HasPrefix(f, "(") {
|
||||
f = "(" + f + ")"
|
||||
}
|
||||
return f
|
||||
}(),
|
||||
funcHandler(function.Results),
|
||||
)))
|
||||
b.newLine(fmt.Sprintf(`<span id="%s"></span>`, function.Name))
|
||||
b.quote()
|
||||
for _, comment := range function.Comments.Clear {
|
||||
b.quote(comment)
|
||||
}
|
||||
b.newLine()
|
||||
if example := b.p.GetExampleTest(function); example != nil {
|
||||
b.newLine("示例代码:", "```go\n", example.Code(), "```\n")
|
||||
}
|
||||
if unitTest := b.p.GetUnitTest(function); unitTest != nil {
|
||||
b.detailsStart("查看 / 收起单元测试")
|
||||
b.newLine("```go\n", unitTest.Code(), "```\n")
|
||||
b.detailsEnd()
|
||||
}
|
||||
if benchmarkTest := b.p.GetBenchmarkTest(function); benchmarkTest != nil {
|
||||
b.detailsStart("查看 / 收起基准测试")
|
||||
b.newLine("```go\n", benchmarkTest.Code(), "```\n")
|
||||
b.detailsEnd()
|
||||
}
|
||||
b.newLine("***")
|
||||
}
|
||||
|
||||
for _, f := range b.p.Files {
|
||||
for _, structInfo := range f.Structs {
|
||||
if structInfo.Internal || structInfo.Test {
|
||||
continue
|
||||
}
|
||||
titleBuild()
|
||||
b.title(3, fmt.Sprintf("%s `%s`", structInfo.Name, super.If(structInfo.Interface, "INTERFACE", "STRUCT")))
|
||||
b.newLine(structInfo.Comments.Clear...)
|
||||
b.newLine("```go")
|
||||
structDefine := fmt.Sprintf("type %s %s",
|
||||
func() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(structInfo.Name)
|
||||
if len(structInfo.Generic) > 0 {
|
||||
sb.WriteString("[")
|
||||
var gs []string
|
||||
for _, field := range structInfo.Generic {
|
||||
gs = append(gs, fmt.Sprintf("%s %s", field.Name, field.Type.Sign))
|
||||
}
|
||||
sb.WriteString(strings.Join(gs, ", "))
|
||||
sb.WriteString("]")
|
||||
}
|
||||
return sb.String()
|
||||
}(),
|
||||
func() string {
|
||||
var sb strings.Builder
|
||||
if structInfo.Type == nil {
|
||||
var head = "struct"
|
||||
if structInfo.Interface {
|
||||
head = "interface"
|
||||
}
|
||||
sb.WriteString(head + " {")
|
||||
if len(structInfo.Fields) > 0 {
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
if structInfo.Interface {
|
||||
for _, field := range structInfo.Fields {
|
||||
sb.WriteString(fmt.Sprintf("\t%s %s\n", field.Name, strings.TrimPrefix(field.Type.Sign, "func")))
|
||||
}
|
||||
} else {
|
||||
for _, field := range structInfo.Fields {
|
||||
sb.WriteString(fmt.Sprintf("\t%s %s\n", field.Name, field.Type.Sign))
|
||||
}
|
||||
}
|
||||
sb.WriteString("}")
|
||||
} else {
|
||||
sb.WriteString(structInfo.Type.Sign)
|
||||
}
|
||||
return sb.String()
|
||||
}())
|
||||
sdb, err := format.Source([]byte(structDefine))
|
||||
if err != nil {
|
||||
fmt.Println(structDefine)
|
||||
panic(err)
|
||||
}
|
||||
b.newLine(string(sdb))
|
||||
b.newLine("```")
|
||||
|
||||
for _, function := range b.p.StructFunc(structInfo.Name) {
|
||||
if function.Internal || function.Test {
|
||||
continue
|
||||
}
|
||||
b.title(4, strings.TrimSpace(fmt.Sprintf("func (%s%s) %s%s %s",
|
||||
super.If(function.Struct.Type.IsPointer, "*", ""),
|
||||
structInfo.Name,
|
||||
function.Name,
|
||||
func() string {
|
||||
f := funcHandler(function.Params)
|
||||
if !strings.HasPrefix(f, "(") {
|
||||
f = "(" + f + ")"
|
||||
}
|
||||
return f
|
||||
}(),
|
||||
funcHandler(function.Results),
|
||||
)))
|
||||
b.quote()
|
||||
for _, comment := range function.Comments.Clear {
|
||||
b.quote(comment)
|
||||
}
|
||||
if function.Name == "Write" {
|
||||
fmt.Println()
|
||||
}
|
||||
if example := b.p.GetExampleTest(function); example != nil {
|
||||
b.newLine("示例代码:", "```go\n", example.Code(), "```\n")
|
||||
}
|
||||
if unitTest := b.p.GetUnitTest(function); unitTest != nil {
|
||||
b.detailsStart("查看 / 收起单元测试")
|
||||
b.newLine("```go\n", unitTest.Code(), "```\n")
|
||||
b.detailsEnd()
|
||||
}
|
||||
if benchmarkTest := b.p.GetBenchmarkTest(function); benchmarkTest != nil {
|
||||
b.detailsStart("查看 / 收起基准测试")
|
||||
b.newLine("```go\n", benchmarkTest.Code(), "```\n")
|
||||
b.detailsEnd()
|
||||
}
|
||||
b.newLine("***")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) newLine(text ...string) *Builder {
|
||||
if len(text) == 0 {
|
||||
b.b.WriteString("\n")
|
||||
return b
|
||||
}
|
||||
for _, s := range text {
|
||||
b.b.WriteString(s + "\n")
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) title(lv int, str string) *Builder {
|
||||
var l string
|
||||
for i := 0; i < lv; i++ {
|
||||
l += "#"
|
||||
}
|
||||
b.b.WriteString(l + " " + str)
|
||||
b.b.WriteString("\n")
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) quote(str ...string) *Builder {
|
||||
for _, s := range str {
|
||||
b.b.WriteString("> " + s)
|
||||
b.newLine()
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) tableCel(str ...string) *Builder {
|
||||
var a string
|
||||
var c string
|
||||
for _, s := range str {
|
||||
a += "|" + s
|
||||
c += "|:--"
|
||||
}
|
||||
b.newLine(a, c)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Builder) tableRow(str ...string) *Builder {
|
||||
var c string
|
||||
for _, s := range str {
|
||||
c += "|" + s
|
||||
}
|
||||
return b.newLine(c)
|
||||
}
|
||||
|
||||
func (b *Builder) detailsStart(title string) *Builder {
|
||||
return b.newLine("<details>", "<summary>"+title+"</summary>").newLine().newLine()
|
||||
}
|
||||
|
||||
func (b *Builder) detailsEnd() *Builder {
|
||||
return b.newLine().newLine("</details>").newLine().newLine()
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package genreadme
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuilder_Generate(t *testing.T) {
|
||||
//b, err := New(`/Users/kercylan/Coding.localized/Go/minotaur/utils/buffer`, `/Users/kercylan/Coding.localized/Go/minotaur/utils/buffer/README.md`)
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
//if err = b.Generate(); err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
//return
|
||||
filepath.Walk("/Users/kercylan/Coding.localized/Go/minotaur", func(path string, info fs.FileInfo, err error) error {
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(strings.TrimPrefix(path, "/Users/kercylan/Coding.localized/Go/minotaur"), ".") {
|
||||
return nil
|
||||
}
|
||||
b, err := New(
|
||||
path,
|
||||
filepath.Join(path, "README.md"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if err = b.Generate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
# Generic
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
generic 目的在于提供一组基于泛型的用于处理通用功能的函数和数据结构。该包旨在简化通用功能的实现,并提供一致的接口和易于使用的功能。
|
||||
主要特性:
|
||||
- 通用功能:generic 包支持处理各种通用功能,如数据结构操作、算法实现和常用工具等。您可以使用这些功能来解决各种通用问题,并提高代码的复用性和可维护性。
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[IsNil](#IsNil)|检查指定的值是否为 nil
|
||||
|[IsAllNil](#IsAllNil)|检查指定的值是否全部为 nil
|
||||
|[IsHasNil](#IsHasNil)|检查指定的值是否存在 nil
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`INTERFACE`|[IdR](#idr)|暂无描述...
|
||||
|`INTERFACE`|[IDR](#idr)|暂无描述...
|
||||
|`INTERFACE`|[IdW](#idw)|暂无描述...
|
||||
|`INTERFACE`|[IDW](#idw)|暂无描述...
|
||||
|`INTERFACE`|[IdR2W](#idr2w)|暂无描述...
|
||||
|`INTERFACE`|[IDR2W](#idr2w)|暂无描述...
|
||||
|`INTERFACE`|[Ordered](#ordered)|可排序类型
|
||||
|`INTERFACE`|[Number](#number)|数字类型
|
||||
|`INTERFACE`|[SignedNumber](#signednumber)|有符号数字类型
|
||||
|`INTERFACE`|[Integer](#integer)|整数类型
|
||||
|`INTERFACE`|[Signed](#signed)|有符号整数类型
|
||||
|`INTERFACE`|[Unsigned](#unsigned)|无符号整数类型
|
||||
|`INTERFACE`|[UnsignedNumber](#unsignednumber)|无符号数字类型
|
||||
|`INTERFACE`|[Float](#float)|浮点类型
|
||||
|`INTERFACE`|[Basic](#basic)|基本类型
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func IsNil(v V) bool
|
||||
<span id="IsNil"></span>
|
||||
> 检查指定的值是否为 nil
|
||||
|
||||
***
|
||||
#### func IsAllNil(v ...V) bool
|
||||
<span id="IsAllNil"></span>
|
||||
> 检查指定的值是否全部为 nil
|
||||
|
||||
***
|
||||
#### func IsHasNil(v ...V) bool
|
||||
<span id="IsHasNil"></span>
|
||||
> 检查指定的值是否存在 nil
|
||||
|
||||
***
|
||||
### IdR `INTERFACE`
|
||||
|
||||
```go
|
||||
type IdR[ID comparable] interface {
|
||||
GetId() ID
|
||||
}
|
||||
```
|
||||
### IDR `INTERFACE`
|
||||
|
||||
```go
|
||||
type IDR[ID comparable] interface {
|
||||
GetID() ID
|
||||
}
|
||||
```
|
||||
### IdW `INTERFACE`
|
||||
|
||||
```go
|
||||
type IdW[ID comparable] interface {
|
||||
SetId(id ID)
|
||||
}
|
||||
```
|
||||
### IDW `INTERFACE`
|
||||
|
||||
```go
|
||||
type IDW[ID comparable] interface {
|
||||
SetID(id ID)
|
||||
}
|
||||
```
|
||||
### IdR2W `INTERFACE`
|
||||
|
||||
```go
|
||||
type IdR2W[ID comparable] interface {
|
||||
IdR[ID]
|
||||
IdW[ID]
|
||||
}
|
||||
```
|
||||
### IDR2W `INTERFACE`
|
||||
|
||||
```go
|
||||
type IDR2W[ID comparable] interface {
|
||||
IDR[ID]
|
||||
IDW[ID]
|
||||
}
|
||||
```
|
||||
### Ordered `INTERFACE`
|
||||
可排序类型
|
||||
```go
|
||||
type Ordered interface {
|
||||
Integer | Float | ~string
|
||||
}
|
||||
```
|
||||
### Number `INTERFACE`
|
||||
数字类型
|
||||
```go
|
||||
type Number interface {
|
||||
Integer | Float
|
||||
}
|
||||
```
|
||||
### SignedNumber `INTERFACE`
|
||||
有符号数字类型
|
||||
```go
|
||||
type SignedNumber interface {
|
||||
Signed | Float
|
||||
}
|
||||
```
|
||||
### Integer `INTERFACE`
|
||||
整数类型
|
||||
```go
|
||||
type Integer interface {
|
||||
Signed | Unsigned
|
||||
}
|
||||
```
|
||||
### Signed `INTERFACE`
|
||||
有符号整数类型
|
||||
```go
|
||||
type Signed interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
```
|
||||
### Unsigned `INTERFACE`
|
||||
无符号整数类型
|
||||
```go
|
||||
type Unsigned interface {
|
||||
UnsignedNumber | ~uintptr
|
||||
}
|
||||
```
|
||||
### UnsignedNumber `INTERFACE`
|
||||
无符号数字类型
|
||||
```go
|
||||
type UnsignedNumber interface {
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
|
||||
}
|
||||
```
|
||||
### Float `INTERFACE`
|
||||
浮点类型
|
||||
```go
|
||||
type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
```
|
||||
### Basic `INTERFACE`
|
||||
基本类型
|
||||
```go
|
||||
type Basic interface {
|
||||
Signed | Unsigned | Float | ~string | ~bool | ~byte
|
||||
}
|
||||
```
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
|||
# Astar
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
astar 提供用于实现 A* 算法的函数和数据结构。A* 算法是一种常用的路径搜索算法,用于在图形或网络中找到最短路径。该包旨在简化 A* 算法的实现过程,并提供一致的接口和易于使用的功能。
|
||||
主要特性:
|
||||
- 图形表示:astar 包支持使用图形或网络来表示路径搜索的环境。您可以定义节点和边,以构建图形,并在其中执行路径搜索。
|
||||
- A* 算法:该包提供了 A* 算法的实现,用于在图形中找到最短路径。A* 算法使用启发式函数来评估节点的优先级,并选择最有希望的节点进行扩展,以达到最短路径的目标。
|
||||
- 自定义启发式函数:您可以根据具体问题定义自己的启发式函数,以指导 A* 算法的搜索过程。启发式函数用于估计从当前节点到目标节点的代价,以帮助算法选择最佳路径。
|
||||
- 可定制性:astar 包提供了一些可定制的选项,以满足不同场景下的需求。您可以设置节点的代价、边的权重等参数,以调整算法的行为。
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[Find](#Find)|使用 A* 算法在导航网格上查找从起点到终点的最短路径,并返回路径上的节点序列。
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`INTERFACE`|[Graph](#graph)|适用于 A* 算法的图数据结构接口定义,表示导航网格,其中包含了节点和连接节点的边。
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func Find(graph Graph[Node], start Node, end Node, cost func (a Node) V, heuristic func (a Node) V) []Node
|
||||
<span id="Find"></span>
|
||||
> 使用 A* 算法在导航网格上查找从起点到终点的最短路径,并返回路径上的节点序列。
|
||||
>
|
||||
> 参数:
|
||||
> - graph: 图对象,类型为 Graph[Node],表示导航网格。
|
||||
> - start: 起点节点,类型为 Node,表示路径的起点。
|
||||
> - end: 终点节点,类型为 Node,表示路径的终点。
|
||||
> - cost: 路径代价函数,类型为 func(a, b Node) V,用于计算两个节点之间的代价。
|
||||
> - heuristic: 启发函数,类型为 func(a, b Node) V,用于估计从当前节点到目标节点的启发式代价。
|
||||
>
|
||||
> 返回值:
|
||||
> - []Node: 节点序列,表示从起点到终点的最短路径。如果找不到路径,则返回空序列。
|
||||
>
|
||||
> 注意事项:
|
||||
> - graph 对象表示导航网格,其中包含了节点和连接节点的边。
|
||||
> - start 和 end 分别表示路径的起点和终点。
|
||||
> - cost 函数用于计算两个节点之间的代价,可以根据实际情况自定义实现。
|
||||
> - heuristic 函数用于估计从当前节点到目标节点的启发式代价,可以根据实际情况自定义实现。
|
||||
> - 函数使用了 A* 算法来搜索最短路径。
|
||||
> - 函数内部使用了堆数据结构来管理待处理的节点。
|
||||
> - 函数返回一个节点序列,表示从起点到终点的最短路径。如果找不到路径,则返回空序列。
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleFind() {
|
||||
graph := Graph{FloorPlan: geometry.FloorPlan{"===========", "X XX X X", "X X XX X", "X XX X", "X XXX X", "X XX X X", "X XX X X", "==========="}}
|
||||
paths := astar.Find[geometry.Point[int], int](graph, geometry.NewPoint(1, 1), geometry.NewPoint(8, 6), func(a, b geometry.Point[int]) int {
|
||||
return geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(a, b))
|
||||
}, func(a, b geometry.Point[int]) int {
|
||||
return geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(a, b))
|
||||
})
|
||||
for _, path := range paths {
|
||||
graph.Put(path, '.')
|
||||
}
|
||||
fmt.Println(graph)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
### Graph `INTERFACE`
|
||||
适用于 A* 算法的图数据结构接口定义,表示导航网格,其中包含了节点和连接节点的边。
|
||||
```go
|
||||
type Graph[Node comparable] interface {
|
||||
Neighbours(node Node) []Node
|
||||
}
|
||||
```
|
||||
#### func (Graph) Neighbours(point geometry.Point[int]) []geometry.Point[int]
|
||||
***
|
|
@ -0,0 +1,114 @@
|
|||
# Dp
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
dp (DistributionPattern) 提供用于在二维数组中根据不同的特征标记为数组成员建立分布链接的函数和数据结构。该包的目标是实现快速查找与给定位置成员具有相同特征且位置紧邻的其他成员。
|
||||
主要特性:
|
||||
- 分布链接机制:dp 包提供了一种分布链接的机制,可以根据成员的特征将它们链接在一起。这样,可以快速查找与给定成员具有相同特征且位置紧邻的其他成员。
|
||||
- 二维数组支持:该包支持在二维数组中建立分布链接。可以将二维数组中的成员视为节点,并根据其特征进行链接。
|
||||
- 快速查找功能:使用 dp 包提供的函数,可以快速查找与给定位置成员具有相同特征且位置紧邻的其他成员。这有助于在二维数组中进行相关性分析或查找相邻成员。
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewDistributionPattern](#NewDistributionPattern)|构建一个分布图实例
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[DistributionPattern](#distributionpattern)|分布图
|
||||
|`STRUCT`|[Link](#link)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewDistributionPattern(sameKindVerifyHandle func (itemA Item) bool) *DistributionPattern[Item]
|
||||
<span id="NewDistributionPattern"></span>
|
||||
> 构建一个分布图实例
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewDistributionPattern(t *testing.T) {
|
||||
dp := NewDistributionPattern[int](func(itemA, itemB int) bool {
|
||||
return itemA == itemB
|
||||
})
|
||||
matrix := []int{1, 1, 2, 2, 2, 2, 1, 2, 2}
|
||||
dp.LoadMatrixWithPos(3, matrix)
|
||||
for pos, link := range dp.links {
|
||||
fmt.Println(pos, link, fmt.Sprintf("%p", link))
|
||||
}
|
||||
fmt.Println()
|
||||
matrix[6] = 2
|
||||
dp.Refresh(6)
|
||||
for pos, link := range dp.links {
|
||||
fmt.Println(pos, link, fmt.Sprintf("%p", link))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### DistributionPattern `STRUCT`
|
||||
分布图
|
||||
```go
|
||||
type DistributionPattern[Item any] struct {
|
||||
matrix []Item
|
||||
links map[int]map[int]Item
|
||||
sameKindVerifyHandle func(itemA Item) bool
|
||||
width int
|
||||
usePos bool
|
||||
}
|
||||
```
|
||||
#### func (*DistributionPattern) GetLinks(pos int) (result []Link[Item])
|
||||
> 获取关联的成员
|
||||
> - 其中包含传入的 pos 成员
|
||||
***
|
||||
#### func (*DistributionPattern) HasLink(pos int) bool
|
||||
> 检查一个位置是否包含除它本身外的其他关联成员
|
||||
***
|
||||
#### func (*DistributionPattern) LoadMatrix(matrix [][]Item)
|
||||
> 通过二维矩阵加载分布图
|
||||
> - 通过该函数加载的分布图使用的矩阵是复制后的矩阵,因此无法直接通过刷新(Refresh)来更新分布关系
|
||||
> - 需要通过直接刷新的方式请使用 LoadMatrixWithPos
|
||||
***
|
||||
#### func (*DistributionPattern) LoadMatrixWithPos(width int, matrix []Item)
|
||||
> 通过二维矩阵加载分布图
|
||||
***
|
||||
#### func (*DistributionPattern) Refresh(pos int)
|
||||
> 刷新特定位置的分布关系
|
||||
> - 由于 LoadMatrix 的矩阵是复制后的矩阵,所以任何外部的改动都不会影响到分布图的变化,在这种情况下,刷新将没有任何意义
|
||||
> - 需要通过直接刷新的方式请使用 LoadMatrixWithPos 加载矩阵,或者通过 RefreshWithItem 函数进行刷新
|
||||
***
|
||||
#### func (*DistributionPattern) RefreshWithItem(pos int, item Item)
|
||||
> 通过特定的成员刷新特定位置的分布关系
|
||||
> - 如果矩阵通过 LoadMatrixWithPos 加载,将会重定向至 Refresh
|
||||
***
|
||||
### Link `STRUCT`
|
||||
|
||||
```go
|
||||
type Link[V any] struct {
|
||||
Pos int
|
||||
Item V
|
||||
}
|
||||
```
|
|
@ -0,0 +1,97 @@
|
|||
# Matrix
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
matrix 提供了一个简单的二维数组的实现
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewMatrix](#NewMatrix)|生成特定宽高的二维矩阵
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Matrix](#matrix)|二维矩阵
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewMatrix(width int, height int) *Matrix[T]
|
||||
<span id="NewMatrix"></span>
|
||||
> 生成特定宽高的二维矩阵
|
||||
> - 虽然提供了通过x、y坐标的操作函数,但是建议无论如何使用pos进行处理
|
||||
> - 该矩阵为XY,而非YX
|
||||
|
||||
***
|
||||
### Matrix `STRUCT`
|
||||
二维矩阵
|
||||
```go
|
||||
type Matrix[T any] struct {
|
||||
w int
|
||||
h int
|
||||
m []T
|
||||
}
|
||||
```
|
||||
#### func (*Matrix) GetWidth() int
|
||||
> 获取二维矩阵宽度
|
||||
***
|
||||
#### func (*Matrix) GetHeight() int
|
||||
> 获取二维矩阵高度
|
||||
***
|
||||
#### func (*Matrix) GetWidth2Height() (width int, height int)
|
||||
> 获取二维矩阵的宽度和高度
|
||||
***
|
||||
#### func (*Matrix) GetMatrix() [][]T
|
||||
> 获取二维矩阵
|
||||
> - 通常建议使用 GetMatrixWithPos 进行处理这样将拥有更高的效率
|
||||
***
|
||||
#### func (*Matrix) GetMatrixWithPos() []T
|
||||
> 获取顺序的矩阵
|
||||
***
|
||||
#### func (*Matrix) Get(x int, y int) (value T)
|
||||
> 获取特定坐标的内容
|
||||
***
|
||||
#### func (*Matrix) GetExist(x int, y int) (value T, exist bool)
|
||||
> 获取特定坐标的内容,如果不存在则返回 false
|
||||
***
|
||||
#### func (*Matrix) GetWithPos(pos int) (value T)
|
||||
> 获取特定坐标的内容
|
||||
***
|
||||
#### func (*Matrix) Set(x int, y int, data T)
|
||||
> 设置特定坐标的内容
|
||||
***
|
||||
#### func (*Matrix) SetWithPos(pos int, data T)
|
||||
> 设置特定坐标的内容
|
||||
***
|
||||
#### func (*Matrix) Swap(x1 int, y1 int, x2 int, y2 int)
|
||||
> 交换两个位置的内容
|
||||
***
|
||||
#### func (*Matrix) SwapWithPos(pos1 int, pos2 int)
|
||||
> 交换两个位置的内容
|
||||
***
|
||||
#### func (*Matrix) TrySwap(x1 int, y1 int, x2 int, y2 int, expressionHandle func (matrix *Matrix[T]) bool)
|
||||
> 尝试交换两个位置的内容,交换后不满足表达式时进行撤销
|
||||
***
|
||||
#### func (*Matrix) TrySwapWithPos(pos1 int, pos2 int, expressionHandle func (matrix *Matrix[T]) bool)
|
||||
> 尝试交换两个位置的内容,交换后不满足表达式时进行撤销
|
||||
***
|
||||
#### func (*Matrix) FillFull(generateHandle func (x int) T)
|
||||
> 根据提供的生成器填充整个矩阵
|
||||
***
|
||||
#### func (*Matrix) FillFullWithPos(generateHandle func (pos int) T)
|
||||
> 根据提供的生成器填充整个矩阵
|
||||
***
|
|
@ -0,0 +1,129 @@
|
|||
# Navmesh
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
navmesh 提供了用于导航网格处理的函数和数据结构。导航网格是一种常用的数据结构,用于在游戏开发和虚拟环境中进行路径规划和导航。该包旨在简化导航网格的创建、查询和操作过程,并提供高效的导航功能。
|
||||
主要特性:
|
||||
- 导航网格表示:navmesh 包支持使用导航网格来表示虚拟环境中的可行走区域和障碍物。您可以定义多边形区域和连接关系,以构建导航网格,并在其中执行路径规划和导航。
|
||||
- 导航算法:采用了 A* 算法作为导航算法,用于在导航网格中找到最短路径或最优路径。这些算法使用启发式函数和代价评估来指导路径搜索,并提供高效的路径规划能力。
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewNavMesh](#NewNavMesh)|创建一个新的导航网格,并返回一个指向该导航网格的指针。
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[NavMesh](#navmesh)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewNavMesh(shapes []geometry.Shape[V], meshShrinkAmount V) *NavMesh[V]
|
||||
<span id="NewNavMesh"></span>
|
||||
> 创建一个新的导航网格,并返回一个指向该导航网格的指针。
|
||||
>
|
||||
> 参数:
|
||||
> - shapes: 形状切片,类型为 []geometry.Shape[V],表示导航网格中的形状。
|
||||
> - meshShrinkAmount: 网格缩小量,类型为 V,表示导航网格的缩小量。
|
||||
>
|
||||
> 返回值:
|
||||
> - *NavMesh[V]: 指向创建的导航网格的指针。
|
||||
>
|
||||
> 注意事项:
|
||||
> - 导航网格的形状可以是任何几何形状。
|
||||
> - meshShrinkAmount 表示导航网格的缩小量,用于在形状之间创建链接时考虑形状的缩小效果。
|
||||
> - 函数内部使用了泛型类型参数 V,可以根据需要指定形状的坐标类型。
|
||||
> - 函数返回一个指向创建的导航网格的指针。
|
||||
>
|
||||
> 使用建议:
|
||||
> - 确保 NavMesh 计算精度的情况下,V 建议使用 float64 类型
|
||||
|
||||
***
|
||||
### NavMesh `STRUCT`
|
||||
|
||||
```go
|
||||
type NavMesh[V generic.SignedNumber] struct {
|
||||
meshShapes []*shape[V]
|
||||
meshShrinkAmount V
|
||||
}
|
||||
```
|
||||
#### func (*NavMesh) Neighbours(node *shape[V]) []*shape[V]
|
||||
> 实现 astar.Graph 的接口,用于向 A* 算法提供相邻图形
|
||||
***
|
||||
#### func (*NavMesh) Find(point geometry.Point[V], maxDistance V) (distance V, findPoint geometry.Point[V], findShape geometry.Shape[V])
|
||||
> 用于在 NavMesh 中查找离给定点最近的形状,并返回距离、找到的点和找到的形状。
|
||||
>
|
||||
> 参数:
|
||||
> - point: 给定的点,类型为 geometry.Point[V],表示一个 V 维度的点坐标。
|
||||
> - maxDistance: 最大距离,类型为 V,表示查找的最大距离限制。
|
||||
>
|
||||
> 返回值:
|
||||
> - distance: 距离,类型为 V,表示离给定点最近的形状的距离。
|
||||
> - findPoint: 找到的点,类型为 geometry.Point[V],表示离给定点最近的点坐标。
|
||||
> - findShape: 找到的形状,类型为 geometry.Shape[V],表示离给定点最近的形状。
|
||||
>
|
||||
> 注意事项:
|
||||
> - 如果给定点在 NavMesh 中的某个形状内部或者在形状的边上,距离为 0,找到的形状为该形状,找到的点为给定点。
|
||||
> - 如果给定点不在任何形状内部或者形状的边上,将计算给定点到每个形状的距离,并找到最近的形状和对应的点。
|
||||
> - 距离的计算采用几何学中的投影点到形状的距离。
|
||||
> - 函数返回离给定点最近的形状的距离、找到的点和找到的形状。
|
||||
***
|
||||
#### func (*NavMesh) FindPath(start geometry.Point[V], end geometry.Point[V]) (result []geometry.Point[V])
|
||||
> 函数用于在 NavMesh 中查找从起点到终点的路径,并返回路径上的点序列。
|
||||
>
|
||||
> 参数:
|
||||
> - start: 起点,类型为 geometry.Point[V],表示路径的起始点。
|
||||
> - end: 终点,类型为 geometry.Point[V],表示路径的终点。
|
||||
>
|
||||
> 返回值:
|
||||
> - result: 路径上的点序列,类型为 []geometry.Point[V]。
|
||||
>
|
||||
> 注意事项:
|
||||
> - 函数首先根据起点和终点的位置,找到离它们最近的形状作为起点形状和终点形状。
|
||||
> - 如果起点或终点不在任何形状内部,且 NavMesh 的 meshShrinkAmount 大于0,则会考虑缩小的形状。
|
||||
> - 使用 A* 算法在 NavMesh 上搜索从起点形状到终点形状的最短路径。
|
||||
> - 使用漏斗算法对路径进行优化,以得到最终的路径点序列。
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleNavMesh_FindPath() {
|
||||
fp := geometry.FloorPlan{"=================================", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "X X", "================================="}
|
||||
var walkable []geometry.Shape[int]
|
||||
walkable = append(walkable, geometry.NewShape(geometry.NewPoint(5, 5), geometry.NewPoint(15, 5), geometry.NewPoint(15, 15), geometry.NewPoint(5, 15)), geometry.NewShape(geometry.NewPoint(15, 5), geometry.NewPoint(25, 5), geometry.NewPoint(25, 15), geometry.NewPoint(15, 15)), geometry.NewShape(geometry.NewPoint(15, 15), geometry.NewPoint(25, 15), geometry.NewPoint(25, 25), geometry.NewPoint(15, 25)))
|
||||
for _, shape := range walkable {
|
||||
for _, edge := range shape.Edges() {
|
||||
sx, bx := maths.MinMax(edge.GetStart().GetX(), edge.GetEnd().GetX())
|
||||
sy, by := maths.MinMax(edge.GetStart().GetY(), edge.GetEnd().GetY())
|
||||
for x := sx; x <= bx; x++ {
|
||||
for y := sy; y <= by; y++ {
|
||||
fp.Put(geometry.NewPoint[int](x, y), '+')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nm := navmesh.NewNavMesh(walkable, 0)
|
||||
path := nm.FindPath(geometry.NewPoint(6, 6), geometry.NewPoint(18, 24))
|
||||
for _, point := range path {
|
||||
fp.Put(geometry.NewPoint(point.GetX(), point.GetY()), 'G')
|
||||
}
|
||||
fmt.Println(fp)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
|
@ -0,0 +1,178 @@
|
|||
# Hub
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewObjectPool](#NewObjectPool)|创建一个 ObjectPool
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[ObjectPool](#objectpool)|基于 sync.Pool 实现的线程安全的对象池
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewObjectPool(generator func () *T, releaser func (data *T)) *ObjectPool[*T]
|
||||
<span id="NewObjectPool"></span>
|
||||
> 创建一个 ObjectPool
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleNewObjectPool() {
|
||||
var p = hub.NewObjectPool[map[int]int](func() *map[int]int {
|
||||
return &map[int]int{}
|
||||
}, func(data *map[int]int) {
|
||||
collection.ClearMap(*data)
|
||||
})
|
||||
m := *p.Get()
|
||||
m[1] = 1
|
||||
p.Release(&m)
|
||||
fmt.Println(m)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewObjectPool(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
generator func() *map[string]int
|
||||
releaser func(data *map[string]int)
|
||||
shouldPanic bool
|
||||
}{{name: "TestNewObjectPool_NilGenerator", generator: nil, releaser: func(data *map[string]int) {
|
||||
}, shouldPanic: true}, {name: "TestNewObjectPool_NilReleaser", generator: func() *map[string]int {
|
||||
return &map[string]int{}
|
||||
}, releaser: nil, shouldPanic: true}, {name: "TestNewObjectPool_NilGeneratorAndReleaser", generator: nil, releaser: nil, shouldPanic: true}, {name: "TestNewObjectPool_Normal", generator: func() *map[string]int {
|
||||
return &map[string]int{}
|
||||
}, releaser: func(data *map[string]int) {
|
||||
}, shouldPanic: false}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if err := recover(); c.shouldPanic && err == nil {
|
||||
t.Error("TestNewObjectPool should panic")
|
||||
}
|
||||
}()
|
||||
_ = hub.NewObjectPool[map[string]int](c.generator, c.releaser)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### ObjectPool `STRUCT`
|
||||
基于 sync.Pool 实现的线程安全的对象池
|
||||
- 一些高频临时生成使用的对象可以通过 ObjectPool 进行管理,例如属性计算等
|
||||
```go
|
||||
type ObjectPool[T any] struct {
|
||||
p sync.Pool
|
||||
releaser func(data T)
|
||||
}
|
||||
```
|
||||
#### func (*ObjectPool) Get() T
|
||||
> 获取一个对象
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestObjectPool_Get(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
generator func() *map[string]int
|
||||
releaser func(data *map[string]int)
|
||||
}{{name: "TestObjectPool_Get_Normal", generator: func() *map[string]int {
|
||||
return &map[string]int{}
|
||||
}, releaser: func(data *map[string]int) {
|
||||
for k := range *data {
|
||||
delete(*data, k)
|
||||
}
|
||||
}}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
pool := hub.NewObjectPool[map[string]int](c.generator, c.releaser)
|
||||
if actual := pool.Get(); len(*actual) != 0 {
|
||||
t.Error("TestObjectPool_Get failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*ObjectPool) Release(data T)
|
||||
> 将使用完成的对象放回缓冲区
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestObjectPool_Release(t *testing.T) {
|
||||
var cases = []struct {
|
||||
name string
|
||||
generator func() *map[string]int
|
||||
releaser func(data *map[string]int)
|
||||
}{{name: "TestObjectPool_Release_Normal", generator: func() *map[string]int {
|
||||
return &map[string]int{}
|
||||
}, releaser: func(data *map[string]int) {
|
||||
for k := range *data {
|
||||
delete(*data, k)
|
||||
}
|
||||
}}}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
pool := hub.NewObjectPool[map[string]int](c.generator, c.releaser)
|
||||
msg := pool.Get()
|
||||
m := *msg
|
||||
m["test"] = 1
|
||||
pool.Release(msg)
|
||||
if len(m) != 0 {
|
||||
t.Error("TestObjectPool_Release failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,379 @@
|
|||
# Huge
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewFloat](#NewFloat)|创建一个 Float
|
||||
|[NewFloatByString](#NewFloatByString)|通过字符串创建一个 Float
|
||||
|[NewInt](#NewInt)|创建一个 Int
|
||||
|[NewIntByString](#NewIntByString)|通过字符串创建一个 Int
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Float](#float)|暂无描述...
|
||||
|`STRUCT`|[Int](#int)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewFloat(x T) *Float
|
||||
<span id="NewFloat"></span>
|
||||
> 创建一个 Float
|
||||
|
||||
***
|
||||
#### func NewFloatByString(i string) *Float
|
||||
<span id="NewFloatByString"></span>
|
||||
> 通过字符串创建一个 Float
|
||||
> - 如果字符串不是一个合法的数字,则返回 0
|
||||
|
||||
***
|
||||
#### func NewInt(x T) *Int
|
||||
<span id="NewInt"></span>
|
||||
> 创建一个 Int
|
||||
|
||||
***
|
||||
#### func NewIntByString(i string) *Int
|
||||
<span id="NewIntByString"></span>
|
||||
> 通过字符串创建一个 Int
|
||||
> - 如果字符串不是一个合法的数字,则返回 0
|
||||
|
||||
***
|
||||
### Float `STRUCT`
|
||||
|
||||
```go
|
||||
type Float big.Float
|
||||
```
|
||||
#### func (*Float) Copy() *Float
|
||||
***
|
||||
#### func (*Float) Set(i *Float) *Float
|
||||
***
|
||||
#### func (*Float) IsZero() bool
|
||||
***
|
||||
#### func (*Float) ToBigFloat() *big.Float
|
||||
***
|
||||
#### func (*Float) Cmp(i *Float) int
|
||||
> 比较,当 slf > i 时返回 1,当 slf < i 时返回 -1,当 slf == i 时返回 0
|
||||
***
|
||||
#### func (*Float) GreaterThan(i *Float) bool
|
||||
> 大于
|
||||
***
|
||||
#### func (*Float) GreaterThanOrEqualTo(i *Float) bool
|
||||
> 大于或等于
|
||||
***
|
||||
#### func (*Float) LessThan(i *Float) bool
|
||||
> 小于
|
||||
***
|
||||
#### func (*Float) LessThanOrEqualTo(i *Float) bool
|
||||
> 小于或等于
|
||||
***
|
||||
#### func (*Float) EqualTo(i *Float) bool
|
||||
> 等于
|
||||
***
|
||||
#### func (*Float) Float64() float64
|
||||
***
|
||||
#### func (*Float) String() string
|
||||
***
|
||||
#### func (*Float) Add(i *Float) *Float
|
||||
***
|
||||
#### func (*Float) Sub(i *Float) *Float
|
||||
***
|
||||
#### func (*Float) Mul(i *Float) *Float
|
||||
***
|
||||
#### func (*Float) Div(i *Float) *Float
|
||||
***
|
||||
#### func (*Float) Sqrt() *Float
|
||||
> 平方根
|
||||
***
|
||||
#### func (*Float) Abs() *Float
|
||||
> 返回数字的绝对值
|
||||
***
|
||||
#### func (*Float) Sign() int
|
||||
> 返回数字的符号
|
||||
> - 1:正数
|
||||
> - 0:零
|
||||
> - -1:负数
|
||||
***
|
||||
#### func (*Float) IsPositive() bool
|
||||
> 是否为正数
|
||||
***
|
||||
#### func (*Float) IsNegative() bool
|
||||
> 是否为负数
|
||||
***
|
||||
### Int `STRUCT`
|
||||
|
||||
```go
|
||||
type Int big.Int
|
||||
```
|
||||
#### func (*Int) Copy() *Int
|
||||
***
|
||||
#### func (*Int) Set(i *Int) *Int
|
||||
***
|
||||
#### func (*Int) SetInt(i int) *Int
|
||||
***
|
||||
#### func (*Int) SetInt8(i int8) *Int
|
||||
***
|
||||
#### func (*Int) SetInt16(i int16) *Int
|
||||
***
|
||||
#### func (*Int) SetInt32(i int32) *Int
|
||||
***
|
||||
#### func (*Int) SetInt64(i int64) *Int
|
||||
***
|
||||
#### func (*Int) SetUint(i uint) *Int
|
||||
***
|
||||
#### func (*Int) SetUint8(i uint8) *Int
|
||||
***
|
||||
#### func (*Int) SetUint16(i uint16) *Int
|
||||
***
|
||||
#### func (*Int) SetUint32(i uint32) *Int
|
||||
***
|
||||
#### func (*Int) SetUint64(i uint64) *Int
|
||||
***
|
||||
#### func (*Int) IsZero() bool
|
||||
***
|
||||
#### func (*Int) ToBigint() *big.Int
|
||||
***
|
||||
#### func (*Int) Cmp(i *Int) int
|
||||
> 比较,当 slf > i 时返回 1,当 slf < i 时返回 -1,当 slf == i 时返回 0
|
||||
***
|
||||
#### func (*Int) GreaterThan(i *Int) bool
|
||||
> 大于
|
||||
***
|
||||
#### func (*Int) GreaterThanOrEqualTo(i *Int) bool
|
||||
> 大于或等于
|
||||
***
|
||||
#### func (*Int) LessThan(i *Int) bool
|
||||
> 小于
|
||||
***
|
||||
#### func (*Int) LessThanOrEqualTo(i *Int) bool
|
||||
> 小于或等于
|
||||
***
|
||||
#### func (*Int) EqualTo(i *Int) bool
|
||||
> 等于
|
||||
***
|
||||
#### func (*Int) Int64() int64
|
||||
***
|
||||
#### func (*Int) String() string
|
||||
***
|
||||
#### func (*Int) Add(i *Int) *Int
|
||||
***
|
||||
#### func (*Int) AddInt(i int) *Int
|
||||
***
|
||||
#### func (*Int) AddInt8(i int8) *Int
|
||||
***
|
||||
#### func (*Int) AddInt16(i int16) *Int
|
||||
***
|
||||
#### func (*Int) AddInt32(i int32) *Int
|
||||
***
|
||||
#### func (*Int) AddInt64(i int64) *Int
|
||||
***
|
||||
#### func (*Int) AddUint(i uint) *Int
|
||||
***
|
||||
#### func (*Int) AddUint8(i uint8) *Int
|
||||
***
|
||||
#### func (*Int) AddUint16(i uint16) *Int
|
||||
***
|
||||
#### func (*Int) AddUint32(i uint32) *Int
|
||||
***
|
||||
#### func (*Int) AddUint64(i uint64) *Int
|
||||
***
|
||||
#### func (*Int) Mul(i *Int) *Int
|
||||
***
|
||||
#### func (*Int) MulInt(i int) *Int
|
||||
***
|
||||
#### func (*Int) MulInt8(i int8) *Int
|
||||
***
|
||||
#### func (*Int) MulInt16(i int16) *Int
|
||||
***
|
||||
#### func (*Int) MulInt32(i int32) *Int
|
||||
***
|
||||
#### func (*Int) MulInt64(i int64) *Int
|
||||
***
|
||||
#### func (*Int) MulUint(i uint) *Int
|
||||
***
|
||||
#### func (*Int) MulUint8(i uint8) *Int
|
||||
***
|
||||
#### func (*Int) MulUint16(i uint16) *Int
|
||||
***
|
||||
#### func (*Int) MulUint32(i uint32) *Int
|
||||
***
|
||||
#### func (*Int) MulUint64(i uint64) *Int
|
||||
***
|
||||
#### func (*Int) Sub(i *Int) *Int
|
||||
***
|
||||
#### func (*Int) SubInt(i int) *Int
|
||||
***
|
||||
#### func (*Int) SubInt8(i int8) *Int
|
||||
***
|
||||
#### func (*Int) SubInt16(i int16) *Int
|
||||
***
|
||||
#### func (*Int) SubInt32(i int32) *Int
|
||||
***
|
||||
#### func (*Int) SubInt64(i int64) *Int
|
||||
***
|
||||
#### func (*Int) SubUint(i uint) *Int
|
||||
***
|
||||
#### func (*Int) SubUint8(i uint8) *Int
|
||||
***
|
||||
#### func (*Int) SubUint16(i uint16) *Int
|
||||
***
|
||||
#### func (*Int) SubUint32(i uint32) *Int
|
||||
***
|
||||
#### func (*Int) SubUint64(i uint64) *Int
|
||||
***
|
||||
#### func (*Int) Div(i *Int) *Int
|
||||
***
|
||||
#### func (*Int) DivInt(i int) *Int
|
||||
***
|
||||
#### func (*Int) DivInt8(i int8) *Int
|
||||
***
|
||||
#### func (*Int) DivInt16(i int16) *Int
|
||||
***
|
||||
#### func (*Int) DivInt32(i int32) *Int
|
||||
***
|
||||
#### func (*Int) DivInt64(i int64) *Int
|
||||
***
|
||||
#### func (*Int) DivUint(i uint) *Int
|
||||
***
|
||||
#### func (*Int) DivUint8(i uint8) *Int
|
||||
***
|
||||
#### func (*Int) DivUint16(i uint16) *Int
|
||||
***
|
||||
#### func (*Int) DivUint32(i uint32) *Int
|
||||
***
|
||||
#### func (*Int) DivUint64(i uint64) *Int
|
||||
***
|
||||
#### func (*Int) Mod(i *Int) *Int
|
||||
***
|
||||
#### func (*Int) ModInt(i int) *Int
|
||||
***
|
||||
#### func (*Int) ModInt8(i int8) *Int
|
||||
***
|
||||
#### func (*Int) ModInt16(i int16) *Int
|
||||
***
|
||||
#### func (*Int) ModInt32(i int32) *Int
|
||||
***
|
||||
#### func (*Int) ModInt64(i int64) *Int
|
||||
***
|
||||
#### func (*Int) ModUint(i uint) *Int
|
||||
***
|
||||
#### func (*Int) ModUint8(i uint8) *Int
|
||||
***
|
||||
#### func (*Int) ModUint16(i uint16) *Int
|
||||
***
|
||||
#### func (*Int) ModUint32(i uint32) *Int
|
||||
***
|
||||
#### func (*Int) ModUint64(i uint64) *Int
|
||||
***
|
||||
#### func (*Int) Pow(i *Int) *Int
|
||||
***
|
||||
#### func (*Int) PowInt(i int) *Int
|
||||
***
|
||||
#### func (*Int) PowInt8(i int8) *Int
|
||||
***
|
||||
#### func (*Int) PowInt16(i int16) *Int
|
||||
***
|
||||
#### func (*Int) PowInt32(i int32) *Int
|
||||
***
|
||||
#### func (*Int) PowInt64(i int64) *Int
|
||||
***
|
||||
#### func (*Int) PowUint(i uint) *Int
|
||||
***
|
||||
#### func (*Int) PowUint8(i uint8) *Int
|
||||
***
|
||||
#### func (*Int) PowUint16(i uint16) *Int
|
||||
***
|
||||
#### func (*Int) PowUint32(i uint32) *Int
|
||||
***
|
||||
#### func (*Int) PowUint64(i uint64) *Int
|
||||
***
|
||||
#### func (*Int) Lsh(i int) *Int
|
||||
> 左移
|
||||
***
|
||||
#### func (*Int) Rsh(i int) *Int
|
||||
> 右移
|
||||
***
|
||||
#### func (*Int) And(i *Int) *Int
|
||||
> 与
|
||||
***
|
||||
#### func (*Int) AndNot(i *Int) *Int
|
||||
> 与非
|
||||
***
|
||||
#### func (*Int) Or(i *Int) *Int
|
||||
> 或
|
||||
***
|
||||
#### func (*Int) Xor(i *Int) *Int
|
||||
> 异或
|
||||
***
|
||||
#### func (*Int) Not() *Int
|
||||
> 非
|
||||
***
|
||||
#### func (*Int) Sqrt() *Int
|
||||
> 平方根
|
||||
***
|
||||
#### func (*Int) GCD(i *Int) *Int
|
||||
> 最大公约数
|
||||
***
|
||||
#### func (*Int) LCM(i *Int) *Int
|
||||
> 最小公倍数
|
||||
***
|
||||
#### func (*Int) ModInverse(i *Int) *Int
|
||||
> 模反元素
|
||||
***
|
||||
#### func (*Int) ModSqrt(i *Int) *Int
|
||||
> 模平方根
|
||||
***
|
||||
#### func (*Int) BitLen() int
|
||||
> 二进制长度
|
||||
***
|
||||
#### func (*Int) Bit(i int) uint
|
||||
> 二进制位
|
||||
***
|
||||
#### func (*Int) SetBit(i int, v uint) *Int
|
||||
> 设置二进制位
|
||||
***
|
||||
#### func (*Int) Neg() *Int
|
||||
> 返回数字的相反数
|
||||
***
|
||||
#### func (*Int) Abs() *Int
|
||||
> 返回数字的绝对值
|
||||
***
|
||||
#### func (*Int) Sign() int
|
||||
> 返回数字的符号
|
||||
> - 1:正数
|
||||
> - 0:零
|
||||
> - -1:负数
|
||||
***
|
||||
#### func (*Int) IsPositive() bool
|
||||
> 是否为正数
|
||||
***
|
||||
#### func (*Int) IsNegative() bool
|
||||
> 是否为负数
|
||||
***
|
||||
#### func (*Int) IsEven() bool
|
||||
> 是否为偶数
|
||||
***
|
||||
#### func (*Int) IsOdd() bool
|
||||
> 是否为奇数
|
||||
***
|
||||
#### func (*Int) ProportionalCalc(proportional *Int, formula func (v *Int) *Int) *Int
|
||||
> 比例计算,该函数会再 formula 返回值的基础上除以 proportional
|
||||
> - formula 为计算公式,该公式的参数为调用该函数的 Int 的拷贝
|
||||
***
|
|
@ -0,0 +1,86 @@
|
|||
# Leaderboard
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewBinarySearch](#NewBinarySearch)|创建一个基于内存的二分查找排行榜
|
||||
|[WithBinarySearchCount](#WithBinarySearchCount)|通过限制排行榜竞争者数量来创建排行榜
|
||||
|[WithBinarySearchASC](#WithBinarySearchASC)|通过升序的方式创建排行榜
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[BinarySearch](#binarysearch)|暂无描述...
|
||||
|`STRUCT`|[BinarySearchRankChangeEventHandle](#binarysearchrankchangeeventhandle)|暂无描述...
|
||||
|`STRUCT`|[BinarySearchOption](#binarysearchoption)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewBinarySearch(options ...BinarySearchOption[CompetitorID, Score]) *BinarySearch[CompetitorID, Score]
|
||||
<span id="NewBinarySearch"></span>
|
||||
> 创建一个基于内存的二分查找排行榜
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleNewBinarySearch() {
|
||||
bs := leaderboard2.NewBinarySearch[string, int](leaderboard2.WithBinarySearchCount[string, int](10))
|
||||
fmt.Println(bs != nil)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func WithBinarySearchCount(rankCount int) BinarySearchOption[CompetitorID, Score]
|
||||
<span id="WithBinarySearchCount"></span>
|
||||
> 通过限制排行榜竞争者数量来创建排行榜
|
||||
> - 默认情况下允许100位竞争者
|
||||
|
||||
***
|
||||
#### func WithBinarySearchASC() BinarySearchOption[CompetitorID, Score]
|
||||
<span id="WithBinarySearchASC"></span>
|
||||
> 通过升序的方式创建排行榜
|
||||
> - 默认情况下为降序
|
||||
|
||||
***
|
||||
### BinarySearch `STRUCT`
|
||||
|
||||
```go
|
||||
type BinarySearch[CompetitorID comparable, Score generic.Ordered] struct {
|
||||
*binarySearchEvent[CompetitorID, Score]
|
||||
asc bool
|
||||
rankCount int
|
||||
competitors *mappings.SyncMap[CompetitorID, Score]
|
||||
scores []*scoreItem[CompetitorID, Score]
|
||||
rankChangeEventHandles []BinarySearchRankChangeEventHandle[CompetitorID, Score]
|
||||
rankClearBeforeEventHandles []BinarySearchRankClearBeforeEventHandle[CompetitorID, Score]
|
||||
}
|
||||
```
|
||||
### BinarySearchRankChangeEventHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type BinarySearchRankChangeEventHandle[CompetitorID comparable, Score generic.Ordered] func(leaderboard *BinarySearch[CompetitorID, Score], competitorId CompetitorID, oldRank int, oldScore Score)
|
||||
```
|
||||
### BinarySearchOption `STRUCT`
|
||||
|
||||
```go
|
||||
type BinarySearchOption[CompetitorID comparable, Score generic.Ordered] func(list *BinarySearch[CompetitorID, Score])
|
||||
```
|
|
@ -0,0 +1,427 @@
|
|||
# Log
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[CallerBasicFormat](#CallerBasicFormat)|返回调用者的基本格式
|
||||
|[Println](#Println)|暂无描述...
|
||||
|[Default](#Default)|获取默认的日志记录器
|
||||
|[SetDefault](#SetDefault)|设置默认的日志记录器
|
||||
|[SetDefaultBySlog](#SetDefaultBySlog)|设置默认的日志记录器
|
||||
|[Debug](#Debug)|在 DebugLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|[Info](#Info)|在 InfoLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|[Warn](#Warn)|在 WarnLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|[Error](#Error)|在 ErrorLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|[DPanic](#DPanic)|在 DPanicLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|[Panic](#Panic)|在 PanicLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|[Fatal](#Fatal)|在 FatalLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|[Skip](#Skip)|构造一个无操作字段,这在处理其他 Field 构造函数中的无效输入时通常很有用
|
||||
|[Duration](#Duration)|使用给定的键和值构造一个字段。编码器控制持续时间的序列化方式
|
||||
|[DurationP](#DurationP)|构造一个带有 time.Duration 的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Bool](#Bool)|构造一个带有布尔值的字段
|
||||
|[BoolP](#BoolP)|构造一个带有布尔值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[String](#String)|构造一个带有字符串值的字段
|
||||
|[StringP](#StringP)|构造一个带有字符串值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Int](#Int)|构造一个带有整数值的字段
|
||||
|[IntP](#IntP)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Int8](#Int8)|构造一个带有整数值的字段
|
||||
|[Int8P](#Int8P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Int16](#Int16)|构造一个带有整数值的字段
|
||||
|[Int16P](#Int16P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Int32](#Int32)|构造一个带有整数值的字段
|
||||
|[Int32P](#Int32P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Int64](#Int64)|构造一个带有整数值的字段
|
||||
|[Int64P](#Int64P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Uint](#Uint)|构造一个带有整数值的字段
|
||||
|[UintP](#UintP)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Uint8](#Uint8)|构造一个带有整数值的字段
|
||||
|[Uint8P](#Uint8P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Uint16](#Uint16)|构造一个带有整数值的字段
|
||||
|[Uint16P](#Uint16P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Uint32](#Uint32)|构造一个带有整数值的字段
|
||||
|[Uint32P](#Uint32P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Uint64](#Uint64)|构造一个带有整数值的字段
|
||||
|[Uint64P](#Uint64P)|构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Float](#Float)|构造一个带有浮点值的字段
|
||||
|[FloatP](#FloatP)|构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Float32](#Float32)|构造一个带有浮点值的字段
|
||||
|[Float32P](#Float32P)|构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Float64](#Float64)|构造一个带有浮点值的字段
|
||||
|[Float64P](#Float64P)|构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Time](#Time)|构造一个带有时间值的字段
|
||||
|[TimeP](#TimeP)|构造一个带有时间值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|[Any](#Any)|构造一个带有任意值的字段
|
||||
|[Group](#Group)|返回分组字段
|
||||
|[Stack](#Stack)|返回堆栈字段
|
||||
|[Err](#Err)|构造一个带有错误值的字段
|
||||
|[NewHandler](#NewHandler)|创建一个更偏向于人类可读的处理程序,该处理程序也是默认的处理程序
|
||||
|[NewLogger](#NewLogger)|创建一个新的日志记录器
|
||||
|[NewMultiHandler](#NewMultiHandler)|创建一个新的多处理程序
|
||||
|[NewOptions](#NewOptions)|创建一个新的日志选项
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Field](#field)|暂无描述...
|
||||
|`STRUCT`|[Logger](#logger)|暂无描述...
|
||||
|`STRUCT`|[MultiHandler](#multihandler)|暂无描述...
|
||||
|`STRUCT`|[Option](#option)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func CallerBasicFormat(file string, line int) (repFile string, refLine string)
|
||||
<span id="CallerBasicFormat"></span>
|
||||
> 返回调用者的基本格式
|
||||
|
||||
***
|
||||
#### func Println(str string, color string, desc string)
|
||||
<span id="Println"></span>
|
||||
|
||||
***
|
||||
#### func Default() *Logger
|
||||
<span id="Default"></span>
|
||||
> 获取默认的日志记录器
|
||||
|
||||
***
|
||||
#### func SetDefault(l *Logger)
|
||||
<span id="SetDefault"></span>
|
||||
> 设置默认的日志记录器
|
||||
|
||||
***
|
||||
#### func SetDefaultBySlog(l *slog.Logger)
|
||||
<span id="SetDefaultBySlog"></span>
|
||||
> 设置默认的日志记录器
|
||||
|
||||
***
|
||||
#### func Debug(msg string, args ...any)
|
||||
<span id="Debug"></span>
|
||||
> 在 DebugLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|
||||
***
|
||||
#### func Info(msg string, args ...any)
|
||||
<span id="Info"></span>
|
||||
> 在 InfoLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|
||||
***
|
||||
#### func Warn(msg string, args ...any)
|
||||
<span id="Warn"></span>
|
||||
> 在 WarnLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|
||||
***
|
||||
#### func Error(msg string, args ...any)
|
||||
<span id="Error"></span>
|
||||
> 在 ErrorLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
|
||||
***
|
||||
#### func DPanic(msg string, args ...any)
|
||||
<span id="DPanic"></span>
|
||||
> 在 DPanicLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
> - 如果记录器处于开发模式,它就会出现 panic(DPanic 的意思是“development panic”)。这对于捕获可恢复但不应该发生的错误很有用
|
||||
> - 该 panic 仅在 NewHandler 中创建的处理器会生效
|
||||
|
||||
***
|
||||
#### func Panic(msg string, args ...any)
|
||||
<span id="Panic"></span>
|
||||
> 在 PanicLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
> - 即使禁用了 PanicLevel 的日志记录,记录器也会出现 panic
|
||||
|
||||
***
|
||||
#### func Fatal(msg string, args ...any)
|
||||
<span id="Fatal"></span>
|
||||
> 在 FatalLevel 记录一条消息。该消息包括在日志站点传递的任何字段以及记录器上累积的任何字段
|
||||
> - 然后记录器调用 os.Exit(1),即使 FatalLevel 的日志记录被禁用
|
||||
|
||||
***
|
||||
#### func Skip(vs ...any) slog.Attr
|
||||
<span id="Skip"></span>
|
||||
> 构造一个无操作字段,这在处理其他 Field 构造函数中的无效输入时通常很有用
|
||||
> - 该函数还支持将其他字段快捷的转换为 Skip 字段
|
||||
|
||||
***
|
||||
#### func Duration(key string, val time.Duration) slog.Attr
|
||||
<span id="Duration"></span>
|
||||
> 使用给定的键和值构造一个字段。编码器控制持续时间的序列化方式
|
||||
|
||||
***
|
||||
#### func DurationP(key string, val *time.Duration) slog.Attr
|
||||
<span id="DurationP"></span>
|
||||
> 构造一个带有 time.Duration 的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Bool(key string, val bool) slog.Attr
|
||||
<span id="Bool"></span>
|
||||
> 构造一个带有布尔值的字段
|
||||
|
||||
***
|
||||
#### func BoolP(key string, val *bool) slog.Attr
|
||||
<span id="BoolP"></span>
|
||||
> 构造一个带有布尔值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func String(key string, val string) slog.Attr
|
||||
<span id="String"></span>
|
||||
> 构造一个带有字符串值的字段
|
||||
|
||||
***
|
||||
#### func StringP(key string, val *string) slog.Attr
|
||||
<span id="StringP"></span>
|
||||
> 构造一个带有字符串值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Int(key string, val I) slog.Attr
|
||||
<span id="Int"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func IntP(key string, val *I) slog.Attr
|
||||
<span id="IntP"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Int8(key string, val I) slog.Attr
|
||||
<span id="Int8"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func Int8P(key string, val *I) slog.Attr
|
||||
<span id="Int8P"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Int16(key string, val I) slog.Attr
|
||||
<span id="Int16"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func Int16P(key string, val *I) slog.Attr
|
||||
<span id="Int16P"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Int32(key string, val I) slog.Attr
|
||||
<span id="Int32"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func Int32P(key string, val *I) slog.Attr
|
||||
<span id="Int32P"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Int64(key string, val I) slog.Attr
|
||||
<span id="Int64"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func Int64P(key string, val *I) slog.Attr
|
||||
<span id="Int64P"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Uint(key string, val I) slog.Attr
|
||||
<span id="Uint"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func UintP(key string, val *I) slog.Attr
|
||||
<span id="UintP"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Uint8(key string, val I) slog.Attr
|
||||
<span id="Uint8"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func Uint8P(key string, val *I) slog.Attr
|
||||
<span id="Uint8P"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Uint16(key string, val I) slog.Attr
|
||||
<span id="Uint16"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func Uint16P(key string, val *I) slog.Attr
|
||||
<span id="Uint16P"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Uint32(key string, val I) slog.Attr
|
||||
<span id="Uint32"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func Uint32P(key string, val *I) slog.Attr
|
||||
<span id="Uint32P"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Uint64(key string, val I) slog.Attr
|
||||
<span id="Uint64"></span>
|
||||
> 构造一个带有整数值的字段
|
||||
|
||||
***
|
||||
#### func Uint64P(key string, val *I) slog.Attr
|
||||
<span id="Uint64P"></span>
|
||||
> 构造一个带有整数值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Float(key string, val F) slog.Attr
|
||||
<span id="Float"></span>
|
||||
> 构造一个带有浮点值的字段
|
||||
|
||||
***
|
||||
#### func FloatP(key string, val *F) slog.Attr
|
||||
<span id="FloatP"></span>
|
||||
> 构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Float32(key string, val F) slog.Attr
|
||||
<span id="Float32"></span>
|
||||
> 构造一个带有浮点值的字段
|
||||
|
||||
***
|
||||
#### func Float32P(key string, val *F) slog.Attr
|
||||
<span id="Float32P"></span>
|
||||
> 构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Float64(key string, val F) slog.Attr
|
||||
<span id="Float64"></span>
|
||||
> 构造一个带有浮点值的字段
|
||||
|
||||
***
|
||||
#### func Float64P(key string, val *F) slog.Attr
|
||||
<span id="Float64P"></span>
|
||||
> 构造一个带有浮点值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Time(key string, val time.Time) slog.Attr
|
||||
<span id="Time"></span>
|
||||
> 构造一个带有时间值的字段
|
||||
|
||||
***
|
||||
#### func TimeP(key string, val *time.Time) slog.Attr
|
||||
<span id="TimeP"></span>
|
||||
> 构造一个带有时间值的字段。返回的 Field 将在适当的时候安全且显式地表示 "null"
|
||||
|
||||
***
|
||||
#### func Any(key string, val any) slog.Attr
|
||||
<span id="Any"></span>
|
||||
> 构造一个带有任意值的字段
|
||||
|
||||
***
|
||||
#### func Group(key string, args ...any) slog.Attr
|
||||
<span id="Group"></span>
|
||||
> 返回分组字段
|
||||
|
||||
***
|
||||
#### func Stack(key string) slog.Attr
|
||||
<span id="Stack"></span>
|
||||
> 返回堆栈字段
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestStack(t *testing.T) {
|
||||
var i int
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
Debug("TestStack")
|
||||
Info("TestStack")
|
||||
Warn("TestStack")
|
||||
Error("TestStack")
|
||||
i++
|
||||
if i == 3 {
|
||||
Default().Logger.Handler().(*handler).opts.GerRuntimeHandler().ChangeLevel(slog.LevelInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func Err(err error) slog.Attr
|
||||
<span id="Err"></span>
|
||||
> 构造一个带有错误值的字段
|
||||
|
||||
***
|
||||
#### func NewHandler(w io.Writer, opts *Options) slog.Handler
|
||||
<span id="NewHandler"></span>
|
||||
> 创建一个更偏向于人类可读的处理程序,该处理程序也是默认的处理程序
|
||||
|
||||
***
|
||||
#### func NewLogger(handlers ...slog.Handler) *Logger
|
||||
<span id="NewLogger"></span>
|
||||
> 创建一个新的日志记录器
|
||||
|
||||
***
|
||||
#### func NewMultiHandler(handlers ...slog.Handler) slog.Handler
|
||||
<span id="NewMultiHandler"></span>
|
||||
> 创建一个新的多处理程序
|
||||
|
||||
***
|
||||
#### func NewOptions() *Options
|
||||
<span id="NewOptions"></span>
|
||||
> 创建一个新的日志选项
|
||||
|
||||
***
|
||||
### Field `STRUCT`
|
||||
|
||||
```go
|
||||
type Field slog.Attr
|
||||
```
|
||||
### Logger `STRUCT`
|
||||
|
||||
```go
|
||||
type Logger struct {
|
||||
*slog.Logger
|
||||
}
|
||||
```
|
||||
### MultiHandler `STRUCT`
|
||||
|
||||
```go
|
||||
type MultiHandler struct {
|
||||
handlers []slog.Handler
|
||||
}
|
||||
```
|
||||
#### func (MultiHandler) Enabled(ctx context.Context, level slog.Level) bool
|
||||
***
|
||||
#### func (MultiHandler) Handle(ctx context.Context, record slog.Record) (err error)
|
||||
***
|
||||
#### func (MultiHandler) WithAttrs(attrs []slog.Attr) slog.Handler
|
||||
***
|
||||
#### func (MultiHandler) WithGroup(name string) slog.Handler
|
||||
***
|
||||
### Option `STRUCT`
|
||||
|
||||
```go
|
||||
type Option func(opts *Options)
|
||||
```
|
|
@ -0,0 +1,316 @@
|
|||
# Survey
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewFileFlusher](#NewFileFlusher)|创建一个文件刷新器
|
||||
|[WithFlushInterval](#WithFlushInterval)|设置日志文件刷新间隔
|
||||
|[Reg](#Reg)|注册一个运营日志记录器
|
||||
|[Record](#Record)|记录一条运营日志
|
||||
|[RecordBytes](#RecordBytes)|记录一条运营日志
|
||||
|[Flush](#Flush)|将运营日志记录器的缓冲区数据写入到文件
|
||||
|[Close](#Close)|关闭运营日志记录器
|
||||
|[Analyze](#Analyze)|分析特定文件的记录,当发生错误时,会发生 panic
|
||||
|[AnalyzeMulti](#AnalyzeMulti)|与 Analyze 类似,但是可以分析多个文件
|
||||
|[IncrementAnalyze](#IncrementAnalyze)|增量分析,返回一个函数,每次调用该函数都会分析文件中新增的内容
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Analyzer](#analyzer)|分析器
|
||||
|`INTERFACE`|[Flusher](#flusher)|用于刷新缓冲区的接口
|
||||
|`STRUCT`|[FileFlusher](#fileflusher)|暂无描述...
|
||||
|`STRUCT`|[Option](#option)|选项
|
||||
|`STRUCT`|[Result](#result)|暂无描述...
|
||||
|`STRUCT`|[R](#r)|记录器所记录的一条数据
|
||||
|`STRUCT`|[Report](#report)|分析报告
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewFileFlusher(filePath string, layout ...string) *FileFlusher
|
||||
<span id="NewFileFlusher"></span>
|
||||
> 创建一个文件刷新器
|
||||
> - layout 为日志文件名的时间戳格式 (默认为 time.DateOnly)
|
||||
|
||||
***
|
||||
#### func WithFlushInterval(interval time.Duration) Option
|
||||
<span id="WithFlushInterval"></span>
|
||||
> 设置日志文件刷新间隔
|
||||
> - 默认为 3s,当日志文件刷新间隔 <= 0 时,将会在每次写入日志时刷新日志文件
|
||||
|
||||
***
|
||||
#### func Reg(name string, flusher Flusher, options ...Option)
|
||||
<span id="Reg"></span>
|
||||
> 注册一个运营日志记录器
|
||||
|
||||
***
|
||||
#### func Record(name string, data map[string]any)
|
||||
<span id="Record"></span>
|
||||
> 记录一条运营日志
|
||||
|
||||
***
|
||||
#### func RecordBytes(name string, data []byte)
|
||||
<span id="RecordBytes"></span>
|
||||
> 记录一条运营日志
|
||||
|
||||
***
|
||||
#### func Flush(names ...string)
|
||||
<span id="Flush"></span>
|
||||
> 将运营日志记录器的缓冲区数据写入到文件
|
||||
> - name 为空时,将所有记录器的缓冲区数据写入到文件
|
||||
|
||||
***
|
||||
#### func Close(names ...string)
|
||||
<span id="Close"></span>
|
||||
> 关闭运营日志记录器
|
||||
|
||||
***
|
||||
#### func Analyze(filePath string, handle func (analyzer *Analyzer, record R)) *Report
|
||||
<span id="Analyze"></span>
|
||||
> 分析特定文件的记录,当发生错误时,会发生 panic
|
||||
> - handle 为并行执行的,需要自行处理并发安全
|
||||
> - 适用于外部进程对于日志文件的读取,但是需要注意的是,此时日志文件可能正在被写入,所以可能会读取到错误的数据
|
||||
|
||||
***
|
||||
#### func AnalyzeMulti(filePaths []string, handle func (analyzer *Analyzer, record R)) *Report
|
||||
<span id="AnalyzeMulti"></span>
|
||||
> 与 Analyze 类似,但是可以分析多个文件
|
||||
|
||||
***
|
||||
#### func IncrementAnalyze(filePath string, handle func (analyzer *Analyzer, record R)) func () ( *Report, error)
|
||||
<span id="IncrementAnalyze"></span>
|
||||
> 增量分析,返回一个函数,每次调用该函数都会分析文件中新增的内容
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestIncrementAnalyze(t *testing.T) {
|
||||
path := `./test/day.2023-09-06.log`
|
||||
reader := survey.IncrementAnalyze(path, func(analyzer *survey.Analyzer, record survey.R) {
|
||||
switch record.GetString("type") {
|
||||
case "open_conn":
|
||||
analyzer.IncreaseValueNonRepeat("开播人数", record, 1, "live_id")
|
||||
case "report_rank":
|
||||
analyzer.IncreaseValue("开始游戏次数", 1)
|
||||
analyzer.Increase("开播时长", record, "game_time")
|
||||
analyzer.Sub(record.GetString("live_id")).IncreaseValue("开始游戏次数", 1)
|
||||
analyzer.Sub(record.GetString("live_id")).Increase("开播时长", record, "game_time")
|
||||
case "statistics":
|
||||
analyzer.IncreaseValueNonRepeat("活跃人数", record, 1, "active_player")
|
||||
analyzer.IncreaseValueNonRepeat("评论人数", record, 1, "comment_player")
|
||||
analyzer.IncreaseValueNonRepeat("点赞人数", record, 1, "like_player")
|
||||
analyzer.Sub(record.GetString("live_id")).IncreaseValueNonRepeat("活跃人数", record, 1, "active_player")
|
||||
analyzer.Sub(record.GetString("live_id")).IncreaseValueNonRepeat("评论人数", record, 1, "comment_player")
|
||||
analyzer.Sub(record.GetString("live_id")).IncreaseValueNonRepeat("点赞人数", record, 1, "like_player")
|
||||
giftId := record.GetString("gift.gift_id")
|
||||
if len(giftId) > 0 {
|
||||
giftPrice := record.GetFloat64("gift.price")
|
||||
giftCount := record.GetFloat64("gift.count")
|
||||
giftSender := record.GetString("gift.gift_senders")
|
||||
analyzer.IncreaseValue("礼物总价值", giftPrice*giftCount)
|
||||
analyzer.IncreaseValueNonRepeat(fmt.Sprintf("送礼人数_%s", giftId), record, 1, giftSender)
|
||||
analyzer.IncreaseValue(fmt.Sprintf("礼物总数_%s", giftId), giftCount)
|
||||
analyzer.Sub(record.GetString("live_id")).IncreaseValue("礼物总价值", giftPrice*giftCount)
|
||||
analyzer.Sub(record.GetString("live_id")).IncreaseValueNonRepeat(fmt.Sprintf("送礼人数_%s", giftId), record, 1, giftSender)
|
||||
analyzer.Sub(record.GetString("live_id")).IncreaseValue(fmt.Sprintf("礼物总数_%s", giftId), giftCount)
|
||||
}
|
||||
}
|
||||
})
|
||||
for i := 0; i < 10; i++ {
|
||||
report, err := reader()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(report.FilterSub("warzone0009"))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### Analyzer `STRUCT`
|
||||
分析器
|
||||
```go
|
||||
type Analyzer struct {
|
||||
v map[string]any
|
||||
vc map[string]int64
|
||||
repeat map[string]struct{}
|
||||
subs map[string]*Analyzer
|
||||
format map[string]func(v any) any
|
||||
m sync.Mutex
|
||||
}
|
||||
```
|
||||
#### func (*Analyzer) Sub(key string) *Analyzer
|
||||
> 获取子分析器
|
||||
***
|
||||
#### func (*Analyzer) SetFormat(key string, format func (v any) any)
|
||||
> 设置格式化函数
|
||||
***
|
||||
#### func (*Analyzer) SetValueIfGreaterThan(key string, value float64)
|
||||
> 设置指定 key 的值,当新值大于旧值时
|
||||
> - 当已有值不为 float64 时,将会被忽略
|
||||
***
|
||||
#### func (*Analyzer) SetValueIfLessThan(key string, value float64)
|
||||
> 设置指定 key 的值,当新值小于旧值时
|
||||
> - 当已有值不为 float64 时,将会被忽略
|
||||
***
|
||||
#### func (*Analyzer) SetValueIf(key string, expression bool, value float64)
|
||||
> 当表达式满足的时候将设置指定 key 的值为 value
|
||||
***
|
||||
#### func (*Analyzer) SetValueStringIf(key string, expression bool, value string)
|
||||
> 当表达式满足的时候将设置指定 key 的值为 value
|
||||
***
|
||||
#### func (*Analyzer) SetValue(key string, value float64)
|
||||
> 设置指定 key 的值
|
||||
***
|
||||
#### func (*Analyzer) SetValueString(key string, value string)
|
||||
> 设置指定 key 的值
|
||||
***
|
||||
#### func (*Analyzer) Increase(key string, record R, recordKey string)
|
||||
> 在指定 key 现有值的基础上增加 recordKey 的值
|
||||
> - 当分析器已经记录过相同 key 的值时,会根据已有的值类型进行不同处理
|
||||
>
|
||||
> 处理方式:
|
||||
> - 当已有值类型为 string 时,将会使用新的值的 string 类型进行覆盖
|
||||
> - 当已有值类型为 float64 时,当新的值类型不为 float64 时,将会被忽略
|
||||
***
|
||||
#### func (*Analyzer) IncreaseValue(key string, value float64)
|
||||
> 在指定 key 现有值的基础上增加 value
|
||||
***
|
||||
#### func (*Analyzer) IncreaseNonRepeat(key string, record R, recordKey string, dimension ...string)
|
||||
> 在指定 key 现有值的基础上增加 recordKey 的值,但是当去重维度 dimension 相同时,不会增加
|
||||
***
|
||||
#### func (*Analyzer) IncreaseValueNonRepeat(key string, record R, value float64, dimension ...string)
|
||||
> 在指定 key 现有值的基础上增加 value,但是当去重维度 dimension 相同时,不会增加
|
||||
***
|
||||
#### func (*Analyzer) GetValue(key string) float64
|
||||
> 获取当前记录的值
|
||||
***
|
||||
#### func (*Analyzer) GetValueString(key string) string
|
||||
> 获取当前记录的值
|
||||
***
|
||||
### Flusher `INTERFACE`
|
||||
用于刷新缓冲区的接口
|
||||
```go
|
||||
type Flusher interface {
|
||||
Flush(records []string)
|
||||
Info() string
|
||||
}
|
||||
```
|
||||
### FileFlusher `STRUCT`
|
||||
|
||||
```go
|
||||
type FileFlusher struct {
|
||||
dir string
|
||||
fn string
|
||||
fe string
|
||||
layout string
|
||||
layoutLen int
|
||||
}
|
||||
```
|
||||
#### func (*FileFlusher) Flush(records []string)
|
||||
***
|
||||
#### func (*FileFlusher) Info() string
|
||||
***
|
||||
### Option `STRUCT`
|
||||
选项
|
||||
```go
|
||||
type Option func(logger *logger)
|
||||
```
|
||||
### Result `STRUCT`
|
||||
|
||||
```go
|
||||
type Result gjson.Result
|
||||
```
|
||||
### R `STRUCT`
|
||||
记录器所记录的一条数据
|
||||
```go
|
||||
type R string
|
||||
```
|
||||
#### func (R) GetTime(layout string) time.Time
|
||||
> 获取该记录的时间
|
||||
***
|
||||
#### func (R) Get(key string) Result
|
||||
> 获取指定 key 的值
|
||||
> - 当 key 为嵌套 key 时,使用 . 进行分割,例如:a.b.c
|
||||
> - 更多用法参考:https://github.com/tidwall/gjson
|
||||
***
|
||||
#### func (R) Exist(key string) bool
|
||||
> 判断指定 key 是否存在
|
||||
***
|
||||
#### func (R) GetString(key string) string
|
||||
> 该函数为 Get(key).String() 的简写
|
||||
***
|
||||
#### func (R) GetInt64(key string) int64
|
||||
> 该函数为 Get(key).Int() 的简写
|
||||
***
|
||||
#### func (R) GetInt(key string) int
|
||||
> 该函数为 Get(key).Int() 的简写,但是返回值为 int 类型
|
||||
***
|
||||
#### func (R) GetFloat64(key string) float64
|
||||
> 该函数为 Get(key).Float() 的简写
|
||||
***
|
||||
#### func (R) GetBool(key string) bool
|
||||
> 该函数为 Get(key).Bool() 的简写
|
||||
***
|
||||
#### func (R) String() string
|
||||
***
|
||||
### Report `STRUCT`
|
||||
分析报告
|
||||
```go
|
||||
type Report struct {
|
||||
analyzer *Analyzer
|
||||
Name string
|
||||
Values map[string]any
|
||||
Counter map[string]int64
|
||||
Subs []*Report
|
||||
}
|
||||
```
|
||||
#### func (*Report) Avg(key string) float64
|
||||
> 计算平均值
|
||||
***
|
||||
#### func (*Report) Count(key string) int64
|
||||
> 获取特定 key 的计数次数
|
||||
***
|
||||
#### func (*Report) Sum(keys ...string) float64
|
||||
> 获取特定 key 的总和
|
||||
***
|
||||
#### func (*Report) Sub(name string) *Report
|
||||
> 获取特定名称的子报告
|
||||
***
|
||||
#### func (*Report) ReserveSubByPrefix(prefix string) *Report
|
||||
> 仅保留特定前缀的子报告
|
||||
***
|
||||
#### func (*Report) ReserveSub(names ...string) *Report
|
||||
> 仅保留特定名称子报告
|
||||
***
|
||||
#### func (*Report) FilterSub(names ...string) *Report
|
||||
> 将特定名称的子报告过滤掉
|
||||
***
|
||||
#### func (*Report) String() string
|
||||
***
|
|
@ -0,0 +1,220 @@
|
|||
# Maths
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[Compare](#Compare)|根据特定表达式比较两个值
|
||||
|[IsContinuity](#IsContinuity)|检查一组值是否连续
|
||||
|[IsContinuityWithSort](#IsContinuityWithSort)|检查一组值排序后是否连续
|
||||
|[GetDefaultTolerance](#GetDefaultTolerance)|获取默认误差范围
|
||||
|[Pow](#Pow)|整数幂运算
|
||||
|[PowInt64](#PowInt64)|整数幂运算
|
||||
|[Min](#Min)|返回两个数之中较小的值
|
||||
|[Max](#Max)|返回两个数之中较大的值
|
||||
|[MinMax](#MinMax)|将两个数按照较小的和较大的顺序进行返回
|
||||
|[MaxMin](#MaxMin)|将两个数按照较大的和较小的顺序进行返回
|
||||
|[Clamp](#Clamp)|将给定值限制在最小值和最大值之间
|
||||
|[Tolerance](#Tolerance)|检查两个值是否在一个误差范围内
|
||||
|[Merge](#Merge)|通过一个参考值合并两个数字
|
||||
|[UnMerge](#UnMerge)|通过一个参考值取消合并的两个数字
|
||||
|[MergeToInt64](#MergeToInt64)|将两个数字合并为一个 int64 数字
|
||||
|[UnMergeInt64](#UnMergeInt64)|将一个 int64 数字拆分为两个数字
|
||||
|[ToContinuous](#ToContinuous)|将一组非连续的数字转换为从1开始的连续数字
|
||||
|[CountDigits](#CountDigits)|接收一个整数 num 作为输入,并返回该数字的位数
|
||||
|[GetDigitValue](#GetDigitValue)|接收一个整数 num 和一个表示目标位数的整数 digit 作为输入,并返
|
||||
|[JoinNumbers](#JoinNumbers)|将一组数字连接起来
|
||||
|[IsOdd](#IsOdd)|返回 n 是否为奇数
|
||||
|[IsEven](#IsEven)|返回 n 是否为偶数
|
||||
|[MakeLastDigitsZero](#MakeLastDigitsZero)|返回一个新的数,其中 num 的最后 digits 位数被设为零。
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[CompareExpression](#compareexpression)|比较表达式
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func Compare(a V, expression CompareExpression, b V) bool
|
||||
<span id="Compare"></span>
|
||||
> 根据特定表达式比较两个值
|
||||
|
||||
***
|
||||
#### func IsContinuity(values S) bool
|
||||
<span id="IsContinuity"></span>
|
||||
> 检查一组值是否连续
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleIsContinuity() {
|
||||
fmt.Println(maths.IsContinuity([]int{1, 2, 3, 4, 5, 6, 7}))
|
||||
fmt.Println(maths.IsContinuity([]int{1, 2, 3, 5, 5, 6, 7}))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func IsContinuityWithSort(values S) bool
|
||||
<span id="IsContinuityWithSort"></span>
|
||||
> 检查一组值排序后是否连续
|
||||
|
||||
***
|
||||
#### func GetDefaultTolerance() float64
|
||||
<span id="GetDefaultTolerance"></span>
|
||||
> 获取默认误差范围
|
||||
|
||||
***
|
||||
#### func Pow(a int, n int) int
|
||||
<span id="Pow"></span>
|
||||
> 整数幂运算
|
||||
|
||||
***
|
||||
#### func PowInt64(a int64, n int64) int64
|
||||
<span id="PowInt64"></span>
|
||||
> 整数幂运算
|
||||
|
||||
***
|
||||
#### func Min(a V, b V) V
|
||||
<span id="Min"></span>
|
||||
> 返回两个数之中较小的值
|
||||
|
||||
***
|
||||
#### func Max(a V, b V) V
|
||||
<span id="Max"></span>
|
||||
> 返回两个数之中较大的值
|
||||
|
||||
***
|
||||
#### func MinMax(a V, b V) (min V, max V)
|
||||
<span id="MinMax"></span>
|
||||
> 将两个数按照较小的和较大的顺序进行返回
|
||||
|
||||
***
|
||||
#### func MaxMin(a V, b V) (max V, min V)
|
||||
<span id="MaxMin"></span>
|
||||
> 将两个数按照较大的和较小的顺序进行返回
|
||||
|
||||
***
|
||||
#### func Clamp(value V, min V, max V) V
|
||||
<span id="Clamp"></span>
|
||||
> 将给定值限制在最小值和最大值之间
|
||||
|
||||
***
|
||||
#### func Tolerance(value1 V, value2 V, tolerance V) bool
|
||||
<span id="Tolerance"></span>
|
||||
> 检查两个值是否在一个误差范围内
|
||||
|
||||
***
|
||||
#### func Merge(refer V, a V, b V) V
|
||||
<span id="Merge"></span>
|
||||
> 通过一个参考值合并两个数字
|
||||
|
||||
***
|
||||
#### func UnMerge(refer V, num V) (a V, b V)
|
||||
<span id="UnMerge"></span>
|
||||
> 通过一个参考值取消合并的两个数字
|
||||
|
||||
***
|
||||
#### func MergeToInt64(v1 V, v2 V) int64
|
||||
<span id="MergeToInt64"></span>
|
||||
> 将两个数字合并为一个 int64 数字
|
||||
|
||||
***
|
||||
#### func UnMergeInt64(n int64) V, V
|
||||
<span id="UnMergeInt64"></span>
|
||||
> 将一个 int64 数字拆分为两个数字
|
||||
|
||||
***
|
||||
#### func ToContinuous(nums S) map[V]V
|
||||
<span id="ToContinuous"></span>
|
||||
> 将一组非连续的数字转换为从1开始的连续数字
|
||||
> - 返回值是一个 map,key 是从 1 开始的连续数字,value 是原始数字
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleToContinuous() {
|
||||
var nums = []int{1, 2, 3, 5, 6, 7, 9, 10, 11}
|
||||
var continuous = maths.ToContinuous(nums)
|
||||
fmt.Println(nums)
|
||||
fmt.Println(continuous)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func CountDigits(num V) int
|
||||
<span id="CountDigits"></span>
|
||||
> 接收一个整数 num 作为输入,并返回该数字的位数
|
||||
|
||||
***
|
||||
#### func GetDigitValue(num int64, digit int) int64
|
||||
<span id="GetDigitValue"></span>
|
||||
> 接收一个整数 num 和一个表示目标位数的整数 digit 作为输入,并返
|
||||
> 回数字 num 在指定位数上的数值。我们使用 math.Abs() 函数获取 num 的绝对值,并通
|
||||
> 过除以10的操作将 num 移动到目标位数上。然后,通过取余运算得到位数上的数值
|
||||
|
||||
***
|
||||
#### func JoinNumbers(num1 V, n ...V) V
|
||||
<span id="JoinNumbers"></span>
|
||||
> 将一组数字连接起来
|
||||
|
||||
***
|
||||
#### func IsOdd(n V) bool
|
||||
<span id="IsOdd"></span>
|
||||
> 返回 n 是否为奇数
|
||||
|
||||
***
|
||||
#### func IsEven(n V) bool
|
||||
<span id="IsEven"></span>
|
||||
> 返回 n 是否为偶数
|
||||
|
||||
***
|
||||
#### func MakeLastDigitsZero(num T, digits int) T
|
||||
<span id="MakeLastDigitsZero"></span>
|
||||
> 返回一个新的数,其中 num 的最后 digits 位数被设为零。
|
||||
> - 函数首先创建一个 10 的 digits 次方的遮罩,然后通过整除和乘以这个遮罩来使 num 的最后 digits 位归零。
|
||||
> - 当 T 类型为浮点型时,将被向下取整后再进行转换
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestMakeLastDigitsZero(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
n := float64(random.Int64(100, 999999))
|
||||
t.Log(n, 3, maths.MakeLastDigitsZero(n, 3))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### CompareExpression `STRUCT`
|
||||
比较表达式
|
||||
```go
|
||||
type CompareExpression int
|
||||
```
|
|
@ -0,0 +1,115 @@
|
|||
# Memory
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[Run](#Run)|运行持久化缓存程序
|
||||
|[BindPersistCacheProgram](#BindPersistCacheProgram)|绑定持久化缓存程序
|
||||
|[BindAction](#BindAction)|绑定需要缓存的操作函数
|
||||
|[NewOption](#NewOption)|暂无描述...
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Option](#option)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func Run()
|
||||
<span id="Run"></span>
|
||||
> 运行持久化缓存程序
|
||||
|
||||
***
|
||||
#### func BindPersistCacheProgram(name string, handler OutputParamHandlerFunc, option ...*Option) func ()
|
||||
<span id="BindPersistCacheProgram"></span>
|
||||
> 绑定持久化缓存程序
|
||||
> - name 持久化缓存程序名称
|
||||
> - handler 持久化缓存程序处理函数
|
||||
> - option 持久化缓存程序选项
|
||||
>
|
||||
> 注意事项:
|
||||
> - 持久化程序建议声明为全局变量进行使用
|
||||
> - 持久化程序处理函数参数类型必须与绑定的缓存程序输出参数类型一致,并且相同 name 的持久化程序必须在 BindAction 之后进行绑定
|
||||
> - 默认情况下只有执行该函数返回的函数才会进行持久化,如果需要持久化策略,可以设置 option 参数或者自行实现策略调用返回的函数
|
||||
> - 所有持久化程序绑定完成后,应该主动调用 Run 函数运行
|
||||
|
||||
***
|
||||
#### func BindAction(name string, handler Func) Func
|
||||
<span id="BindAction"></span>
|
||||
> 绑定需要缓存的操作函数
|
||||
> - name 缓存操作名称
|
||||
> - handler 缓存操作处理函数
|
||||
>
|
||||
> 注意事项:
|
||||
> - 关于持久化缓存程序的绑定请参考 BindPersistCacheProgram
|
||||
> - handler 函数的返回值将被作为缓存目标,如果返回值为非指针类型,将可能会发生意外的情况
|
||||
> - 当传入的 handler 没有任何返回值时,将不会被缓存,并且不会占用缓存操作名称
|
||||
>
|
||||
> 使用场景:
|
||||
> - 例如在游戏中,需要根据玩家 ID 查询玩家信息,可以使用该函数进行绑定,当查询玩家信息时,如果缓存中存在该玩家信息,将直接返回缓存中的数据,否则将执行 handler 函数进行查询并缓存
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestBindAction(t *testing.T) {
|
||||
var player *Player
|
||||
player = QueryPlayer(1)
|
||||
fmt.Println(player.ID)
|
||||
player.ID = 666
|
||||
player = QueryPlayer(1)
|
||||
fmt.Println(player.ID)
|
||||
player = QueryPlayer(2)
|
||||
fmt.Println(player.ID)
|
||||
QueryPlayerPersist()
|
||||
time.Sleep(times.Week)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func NewOption() *Option
|
||||
<span id="NewOption"></span>
|
||||
|
||||
***
|
||||
### Option `STRUCT`
|
||||
|
||||
```go
|
||||
type Option struct {
|
||||
ticker *timer.Ticker
|
||||
firstDelay time.Duration
|
||||
interval time.Duration
|
||||
delay time.Duration
|
||||
}
|
||||
```
|
||||
#### func (*Option) WithPeriodicity(ticker *timer.Ticker, firstDelay time.Duration, interval time.Duration, delay time.Duration) *Option
|
||||
> 设置持久化周期
|
||||
> - ticker 定时器,通常建议使用服务器的定时器,这样可以降低多线程的程序复杂性
|
||||
> - firstDelay 首次持久化延迟,当首次持久化为 0 时,将会在下一个持久化周期开始时持久化
|
||||
> - interval 持久化间隔
|
||||
> - delay 每条数据持久化间隔,适当的设置该值可以使持久化期间尽量降低对用户体验的影响,如果为0,将会一次性持久化所有数据
|
||||
***
|
|
@ -0,0 +1,135 @@
|
|||
# Moving
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewTwoDimensional](#NewTwoDimensional)|创建一个用于2D对象移动的实例(TwoDimensional)
|
||||
|[WithTwoDimensionalTimeUnit](#WithTwoDimensionalTimeUnit)|通过特定时间单位创建
|
||||
|[WithTwoDimensionalIdleWaitTime](#WithTwoDimensionalIdleWaitTime)|通过特定的空闲等待时间创建
|
||||
|[WithTwoDimensionalInterval](#WithTwoDimensionalInterval)|通过特定的移动间隔时间创建
|
||||
|[NewEntity](#NewEntity)|暂无描述...
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[TwoDimensional](#twodimensional)|用于2D对象移动的数据结构
|
||||
|`INTERFACE`|[TwoDimensionalEntity](#twodimensionalentity)|2D移动对象接口定义
|
||||
|`STRUCT`|[Position2DChangeEventHandle](#position2dchangeeventhandle)|暂无描述...
|
||||
|`STRUCT`|[TwoDimensionalOption](#twodimensionaloption)|暂无描述...
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewTwoDimensional(options ...TwoDimensionalOption[EID, PosType]) *TwoDimensional[EID, PosType]
|
||||
<span id="NewTwoDimensional"></span>
|
||||
> 创建一个用于2D对象移动的实例(TwoDimensional)
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleNewTwoDimensional() {
|
||||
m := moving2.NewTwoDimensional[int64, float64]()
|
||||
defer func() {
|
||||
m.Release()
|
||||
}()
|
||||
fmt.Println(m != nil)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewTwoDimensional(t *testing.T) {
|
||||
m := moving2.NewTwoDimensional[int64, float64]()
|
||||
defer func() {
|
||||
m.Release()
|
||||
}()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func WithTwoDimensionalTimeUnit(duration time.Duration) TwoDimensionalOption[EID, PosType]
|
||||
<span id="WithTwoDimensionalTimeUnit"></span>
|
||||
> 通过特定时间单位创建
|
||||
> - 默认单位为1毫秒,最小单位也为1毫秒
|
||||
|
||||
***
|
||||
#### func WithTwoDimensionalIdleWaitTime(duration time.Duration) TwoDimensionalOption[EID, PosType]
|
||||
<span id="WithTwoDimensionalIdleWaitTime"></span>
|
||||
> 通过特定的空闲等待时间创建
|
||||
> - 默认情况下在没有新的移动计划时将限制 100毫秒 + 移动间隔事件(默认100毫秒)
|
||||
|
||||
***
|
||||
#### func WithTwoDimensionalInterval(duration time.Duration) TwoDimensionalOption[EID, PosType]
|
||||
<span id="WithTwoDimensionalInterval"></span>
|
||||
> 通过特定的移动间隔时间创建
|
||||
|
||||
***
|
||||
#### func NewEntity(guid int64, speed float64) *MoveEntity
|
||||
<span id="NewEntity"></span>
|
||||
|
||||
***
|
||||
### TwoDimensional `STRUCT`
|
||||
用于2D对象移动的数据结构
|
||||
- 通过对象调用 MoveTo 方法后将开始执行该对象的移动
|
||||
- 移动将在根据设置的每次移动间隔时间(WithTwoDimensionalInterval)进行移动,当无对象移动需要移动时将会进入短暂的休眠
|
||||
- 当对象移动速度永久为0时,将会导致永久无法完成的移动
|
||||
```go
|
||||
type TwoDimensional[EID generic.Basic, PosType generic.SignedNumber] struct {
|
||||
rw sync.RWMutex
|
||||
entities map[EID]*moving2DTarget[EID, PosType]
|
||||
timeUnit float64
|
||||
idle time.Duration
|
||||
interval time.Duration
|
||||
close bool
|
||||
position2DChangeEventHandles []Position2DChangeEventHandle[EID, PosType]
|
||||
position2DDestinationEventHandles []Position2DDestinationEventHandle[EID, PosType]
|
||||
position2DStopMoveEventHandles []Position2DStopMoveEventHandle[EID, PosType]
|
||||
}
|
||||
```
|
||||
### TwoDimensionalEntity `INTERFACE`
|
||||
2D移动对象接口定义
|
||||
```go
|
||||
type TwoDimensionalEntity[EID generic.Basic, PosType generic.SignedNumber] interface {
|
||||
GetTwoDimensionalEntityID() EID
|
||||
GetSpeed() float64
|
||||
GetPosition() geometry.Point[PosType]
|
||||
SetPosition(geometry.Point[PosType])
|
||||
}
|
||||
```
|
||||
### Position2DChangeEventHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type Position2DChangeEventHandle[EID generic.Basic, PosType generic.SignedNumber] func(moving *TwoDimensional[EID, PosType], entity TwoDimensionalEntity[EID, PosType], oldX PosType)
|
||||
```
|
||||
### TwoDimensionalOption `STRUCT`
|
||||
|
||||
```go
|
||||
type TwoDimensionalOption[EID generic.Basic, PosType generic.SignedNumber] func(moving *TwoDimensional[EID, PosType])
|
||||
```
|
|
@ -0,0 +1,32 @@
|
|||
# Network
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[IP](#IP)|返回本机出站地址
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func IP() (ip net.IP, err error)
|
||||
<span id="IP"></span>
|
||||
> 返回本机出站地址
|
||||
|
||||
***
|
|
@ -0,0 +1,77 @@
|
|||
# Offset
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewTime](#NewTime)|新建一个包含偏移的时间
|
||||
|[SetGlobal](#SetGlobal)|设置全局偏移时间
|
||||
|[GetGlobal](#GetGlobal)|获取全局偏移时间
|
||||
|[Now](#Now)|获取当前时间偏移后的时间
|
||||
|[Since](#Since)|获取当前时间偏移后的时间自从 t 以来经过的时间
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Time](#time)|带有偏移量的时间
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewTime(offset time.Duration) *Time
|
||||
<span id="NewTime"></span>
|
||||
> 新建一个包含偏移的时间
|
||||
|
||||
***
|
||||
#### func SetGlobal(offset time.Duration)
|
||||
<span id="SetGlobal"></span>
|
||||
> 设置全局偏移时间
|
||||
|
||||
***
|
||||
#### func GetGlobal() *Time
|
||||
<span id="GetGlobal"></span>
|
||||
> 获取全局偏移时间
|
||||
|
||||
***
|
||||
#### func Now() time.Time
|
||||
<span id="Now"></span>
|
||||
> 获取当前时间偏移后的时间
|
||||
|
||||
***
|
||||
#### func Since(t time.Time) time.Duration
|
||||
<span id="Since"></span>
|
||||
> 获取当前时间偏移后的时间自从 t 以来经过的时间
|
||||
|
||||
***
|
||||
### Time `STRUCT`
|
||||
带有偏移量的时间
|
||||
```go
|
||||
type Time struct {
|
||||
offset time.Duration
|
||||
}
|
||||
```
|
||||
#### func (*Time) SetOffset(offset time.Duration)
|
||||
> 设置时间偏移
|
||||
***
|
||||
#### func (*Time) Now() time.Time
|
||||
> 获取当前时间偏移后的时间
|
||||
***
|
||||
#### func (*Time) Since(t time.Time) time.Duration
|
||||
> 获取当前时间偏移后的时间自从 t 以来经过的时间
|
||||
***
|
|
@ -0,0 +1,222 @@
|
|||
# Random
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[Dice](#Dice)|掷骰子
|
||||
|[DiceN](#DiceN)|掷骰子
|
||||
|[NetIP](#NetIP)|返回一个随机的IP地址
|
||||
|[Port](#Port)|返回一个随机的端口号
|
||||
|[IPv4](#IPv4)|返回一个随机产生的IPv4地址。
|
||||
|[IPv4Port](#IPv4Port)|返回一个随机产生的IPv4地址和端口。
|
||||
|[Int64](#Int64)|返回一个介于min和max之间的int64类型的随机数。
|
||||
|[Int](#Int)|返回一个介于min和max之间的的int类型的随机数。
|
||||
|[Duration](#Duration)|返回一个介于min和max之间的的Duration类型的随机数。
|
||||
|[Float64](#Float64)|返回一个0~1的浮点数
|
||||
|[Float32](#Float32)|返回一个0~1的浮点数
|
||||
|[IntN](#IntN)|返回一个0~n的整数
|
||||
|[Bool](#Bool)|返回一个随机的布尔值
|
||||
|[ProbabilitySlice](#ProbabilitySlice)|按概率随机从切片中产生一个数据并返回命中的对象及是否未命中
|
||||
|[ProbabilitySliceIndex](#ProbabilitySliceIndex)|按概率随机从切片中产生一个数据并返回命中的对象及对象索引以及是否未命中
|
||||
|[Probability](#Probability)|输入一个概率,返回是否命中
|
||||
|[ProbabilityChooseOne](#ProbabilityChooseOne)|输入一组概率,返回命中的索引
|
||||
|[RefreshSeed](#RefreshSeed)|暂无描述...
|
||||
|[ChineseName](#ChineseName)|返回一个随机组成的中文姓名。
|
||||
|[EnglishName](#EnglishName)|返回一个随机组成的英文姓名。
|
||||
|[Name](#Name)|返回一个随机组成的中文或英文姓名
|
||||
|[NumberString](#NumberString)|返回一个介于min和max之间的string类型的随机数。
|
||||
|[NumberStringRepair](#NumberStringRepair)|返回一个介于min和max之间的string类型的随机数
|
||||
|[HostName](#HostName)|返回一个随机产生的hostname。
|
||||
|[WeightSlice](#WeightSlice)|按权重随机从切片中产生一个数据并返回
|
||||
|[WeightSliceIndex](#WeightSliceIndex)|按权重随机从切片中产生一个数据并返回数据和对应索引
|
||||
|[WeightMap](#WeightMap)|按权重随机从map中产生一个数据并返回
|
||||
|[WeightMapKey](#WeightMapKey)|按权重随机从map中产生一个数据并返回数据和对应 key
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func Dice() int
|
||||
<span id="Dice"></span>
|
||||
> 掷骰子
|
||||
> - 常规掷骰子将返回 1-6 的随机数
|
||||
|
||||
***
|
||||
#### func DiceN(n int) int
|
||||
<span id="DiceN"></span>
|
||||
> 掷骰子
|
||||
> - 与 Dice 不同的是,将返回 1-N 的随机数
|
||||
|
||||
***
|
||||
#### func NetIP() net.IP
|
||||
<span id="NetIP"></span>
|
||||
> 返回一个随机的IP地址
|
||||
|
||||
***
|
||||
#### func Port() int
|
||||
<span id="Port"></span>
|
||||
> 返回一个随机的端口号
|
||||
|
||||
***
|
||||
#### func IPv4() string
|
||||
<span id="IPv4"></span>
|
||||
> 返回一个随机产生的IPv4地址。
|
||||
|
||||
***
|
||||
#### func IPv4Port() string
|
||||
<span id="IPv4Port"></span>
|
||||
> 返回一个随机产生的IPv4地址和端口。
|
||||
|
||||
***
|
||||
#### func Int64(min int64, max int64) int64
|
||||
<span id="Int64"></span>
|
||||
> 返回一个介于min和max之间的int64类型的随机数。
|
||||
|
||||
***
|
||||
#### func Int(min int, max int) int
|
||||
<span id="Int"></span>
|
||||
> 返回一个介于min和max之间的的int类型的随机数。
|
||||
|
||||
***
|
||||
#### func Duration(min int64, max int64) time.Duration
|
||||
<span id="Duration"></span>
|
||||
> 返回一个介于min和max之间的的Duration类型的随机数。
|
||||
|
||||
***
|
||||
#### func Float64() float64
|
||||
<span id="Float64"></span>
|
||||
> 返回一个0~1的浮点数
|
||||
|
||||
***
|
||||
#### func Float32() float32
|
||||
<span id="Float32"></span>
|
||||
> 返回一个0~1的浮点数
|
||||
|
||||
***
|
||||
#### func IntN(n int) int
|
||||
<span id="IntN"></span>
|
||||
> 返回一个0~n的整数
|
||||
|
||||
***
|
||||
#### func Bool() bool
|
||||
<span id="Bool"></span>
|
||||
> 返回一个随机的布尔值
|
||||
|
||||
***
|
||||
#### func ProbabilitySlice(getProbabilityHandle func (data T) float64, data ...T) (hit T, miss bool)
|
||||
<span id="ProbabilitySlice"></span>
|
||||
> 按概率随机从切片中产生一个数据并返回命中的对象及是否未命中
|
||||
> - 当总概率小于 1 将会发生未命中的情况
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestProbabilitySlice(t *testing.T) {
|
||||
var awards = []int{1, 2, 3, 4, 5, 6, 7}
|
||||
var probability = []float64{0.1, 2, 0.1, 0.1, 0.1, 0.1, 0.1}
|
||||
for i := 0; i < 50; i++ {
|
||||
t.Log(random.ProbabilitySlice(func(data int) float64 {
|
||||
return probability[data-1]
|
||||
}, awards...))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func ProbabilitySliceIndex(getProbabilityHandle func (data T) float64, data ...T) (hit T, index int, miss bool)
|
||||
<span id="ProbabilitySliceIndex"></span>
|
||||
> 按概率随机从切片中产生一个数据并返回命中的对象及对象索引以及是否未命中
|
||||
> - 当总概率小于 1 将会发生未命中的情况
|
||||
|
||||
***
|
||||
#### func Probability(p int, full ...int) bool
|
||||
<span id="Probability"></span>
|
||||
> 输入一个概率,返回是否命中
|
||||
> - 当 full 不为空时,将以 full 为基数,p 为分子,计算命中概率
|
||||
|
||||
***
|
||||
#### func ProbabilityChooseOne(ps ...int) int
|
||||
<span id="ProbabilityChooseOne"></span>
|
||||
> 输入一组概率,返回命中的索引
|
||||
|
||||
***
|
||||
#### func RefreshSeed(seed ...int64)
|
||||
<span id="RefreshSeed"></span>
|
||||
|
||||
***
|
||||
#### func ChineseName() string
|
||||
<span id="ChineseName"></span>
|
||||
> 返回一个随机组成的中文姓名。
|
||||
|
||||
***
|
||||
#### func EnglishName() string
|
||||
<span id="EnglishName"></span>
|
||||
> 返回一个随机组成的英文姓名。
|
||||
|
||||
***
|
||||
#### func Name() string
|
||||
<span id="Name"></span>
|
||||
> 返回一个随机组成的中文或英文姓名
|
||||
> - 以1/2的概率决定生产的是中文还是英文姓名。
|
||||
|
||||
***
|
||||
#### func NumberString(min int, max int) string
|
||||
<span id="NumberString"></span>
|
||||
> 返回一个介于min和max之间的string类型的随机数。
|
||||
|
||||
***
|
||||
#### func NumberStringRepair(min int, max int) string
|
||||
<span id="NumberStringRepair"></span>
|
||||
> 返回一个介于min和max之间的string类型的随机数
|
||||
> - 通过Int64生成一个随机数,当结果的字符串长度小于max的字符串长度的情况下,使用0在开头补齐。
|
||||
|
||||
***
|
||||
#### func HostName() string
|
||||
<span id="HostName"></span>
|
||||
> 返回一个随机产生的hostname。
|
||||
|
||||
***
|
||||
#### func WeightSlice(getWeightHandle func (data T) int64, data ...T) T
|
||||
<span id="WeightSlice"></span>
|
||||
> 按权重随机从切片中产生一个数据并返回
|
||||
|
||||
***
|
||||
#### func WeightSliceIndex(getWeightHandle func (data T) int64, data ...T) (item T, index int)
|
||||
<span id="WeightSliceIndex"></span>
|
||||
> 按权重随机从切片中产生一个数据并返回数据和对应索引
|
||||
|
||||
***
|
||||
#### func WeightMap(getWeightHandle func (data T) int64, data map[K]T) T
|
||||
<span id="WeightMap"></span>
|
||||
> 按权重随机从map中产生一个数据并返回
|
||||
|
||||
***
|
||||
#### func WeightMapKey(getWeightHandle func (data T) int64, data map[K]T) (item T, key K)
|
||||
<span id="WeightMapKey"></span>
|
||||
> 按权重随机从map中产生一个数据并返回数据和对应 key
|
||||
|
||||
***
|
|
@ -0,0 +1,74 @@
|
|||
# Reflects
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[WrapperFunc](#WrapperFunc)|包装函数
|
||||
|[WrapperFuncBefore2After](#WrapperFuncBefore2After)|包装函数,前置函数执行前,后置函数执行后
|
||||
|[WrapperFuncBefore](#WrapperFuncBefore)|包装函数,前置函数执行前
|
||||
|[WrapperFuncAfter](#WrapperFuncAfter)|包装函数,后置函数执行后
|
||||
|[GetPtrUnExportFiled](#GetPtrUnExportFiled)|获取指针类型的未导出字段
|
||||
|[SetPtrUnExportFiled](#SetPtrUnExportFiled)|设置指针类型的未导出字段
|
||||
|[Copy](#Copy)|拷贝
|
||||
|[GetPointer](#GetPointer)|获取指针
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func WrapperFunc(f any, wrapper func (call func ( []reflect.Value) []reflect.Value) func (args []reflect.Value) []reflect.Value) (wf Func, err error)
|
||||
<span id="WrapperFunc"></span>
|
||||
> 包装函数
|
||||
|
||||
***
|
||||
#### func WrapperFuncBefore2After(f Func, before func (), after func ()) (wf Func, err error)
|
||||
<span id="WrapperFuncBefore2After"></span>
|
||||
> 包装函数,前置函数执行前,后置函数执行后
|
||||
|
||||
***
|
||||
#### func WrapperFuncBefore(f Func, before func ()) (wf Func, err error)
|
||||
<span id="WrapperFuncBefore"></span>
|
||||
> 包装函数,前置函数执行前
|
||||
|
||||
***
|
||||
#### func WrapperFuncAfter(f Func, after func ()) (wf Func, err error)
|
||||
<span id="WrapperFuncAfter"></span>
|
||||
> 包装函数,后置函数执行后
|
||||
|
||||
***
|
||||
#### func GetPtrUnExportFiled(s reflect.Value, filedIndex int) reflect.Value
|
||||
<span id="GetPtrUnExportFiled"></span>
|
||||
> 获取指针类型的未导出字段
|
||||
|
||||
***
|
||||
#### func SetPtrUnExportFiled(s reflect.Value, filedIndex int, val reflect.Value)
|
||||
<span id="SetPtrUnExportFiled"></span>
|
||||
> 设置指针类型的未导出字段
|
||||
|
||||
***
|
||||
#### func Copy(s reflect.Value) reflect.Value
|
||||
<span id="Copy"></span>
|
||||
> 拷贝
|
||||
|
||||
***
|
||||
#### func GetPointer(src T) reflect.Value
|
||||
<span id="GetPointer"></span>
|
||||
> 获取指针
|
||||
|
||||
***
|
|
@ -0,0 +1,56 @@
|
|||
# Runtimes
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[GetWorkingDir](#GetWorkingDir)|获取工作目录绝对路径
|
||||
|[GetTempDir](#GetTempDir)|获取系统临时目录
|
||||
|[GetExecutablePathByBuild](#GetExecutablePathByBuild)|获取当前执行文件绝对路径(go build)
|
||||
|[GetExecutablePathByCaller](#GetExecutablePathByCaller)|获取当前执行文件绝对路径(go run)
|
||||
|[CurrentRunningFuncName](#CurrentRunningFuncName)|获取正在运行的函数名
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func GetWorkingDir() string
|
||||
<span id="GetWorkingDir"></span>
|
||||
> 获取工作目录绝对路径
|
||||
|
||||
***
|
||||
#### func GetTempDir() string
|
||||
<span id="GetTempDir"></span>
|
||||
> 获取系统临时目录
|
||||
|
||||
***
|
||||
#### func GetExecutablePathByBuild() string
|
||||
<span id="GetExecutablePathByBuild"></span>
|
||||
> 获取当前执行文件绝对路径(go build)
|
||||
|
||||
***
|
||||
#### func GetExecutablePathByCaller() string
|
||||
<span id="GetExecutablePathByCaller"></span>
|
||||
> 获取当前执行文件绝对路径(go run)
|
||||
|
||||
***
|
||||
#### func CurrentRunningFuncName(skip ...int) string
|
||||
<span id="CurrentRunningFuncName"></span>
|
||||
> 获取正在运行的函数名
|
||||
|
||||
***
|
|
@ -0,0 +1,140 @@
|
|||
# Sole
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[RegNameSpace](#RegNameSpace)|注册特定命名空间的唯一标识符
|
||||
|[UnRegNameSpace](#UnRegNameSpace)|解除注销特定命名空间的唯一标识符
|
||||
|[Get](#Get)|获取全局唯一标识符
|
||||
|[Reset](#Reset)|重置全局唯一标识符
|
||||
|[GetWith](#GetWith)|获取特定命名空间的唯一标识符
|
||||
|[ResetWith](#ResetWith)|重置特定命名空间的唯一标识符
|
||||
|[NewOnce](#NewOnce)|创建一个用于数据取值去重的结构实例
|
||||
|[SonyflakeIDE](#SonyflakeIDE)|获取一个雪花id
|
||||
|[SonyflakeID](#SonyflakeID)|获取一个雪花id
|
||||
|[SonyflakeSetting](#SonyflakeSetting)|配置雪花id生成策略
|
||||
|[AutoIncrementUint32](#AutoIncrementUint32)|获取一个自增的 uint32 值
|
||||
|[AutoIncrementUint64](#AutoIncrementUint64)|获取一个自增的 uint64 值
|
||||
|[AutoIncrementInt32](#AutoIncrementInt32)|获取一个自增的 int32 值
|
||||
|[AutoIncrementInt64](#AutoIncrementInt64)|获取一个自增的 int64 值
|
||||
|[AutoIncrementInt](#AutoIncrementInt)|获取一个自增的 int 值
|
||||
|[AutoIncrementString](#AutoIncrementString)|获取一个自增的字符串
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[Once](#once)|用于数据取值去重的结构体
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func RegNameSpace(name any)
|
||||
<span id="RegNameSpace"></span>
|
||||
> 注册特定命名空间的唯一标识符
|
||||
|
||||
***
|
||||
#### func UnRegNameSpace(name any)
|
||||
<span id="UnRegNameSpace"></span>
|
||||
> 解除注销特定命名空间的唯一标识符
|
||||
|
||||
***
|
||||
#### func Get() int64
|
||||
<span id="Get"></span>
|
||||
> 获取全局唯一标识符
|
||||
|
||||
***
|
||||
#### func Reset()
|
||||
<span id="Reset"></span>
|
||||
> 重置全局唯一标识符
|
||||
|
||||
***
|
||||
#### func GetWith(name any) int64
|
||||
<span id="GetWith"></span>
|
||||
> 获取特定命名空间的唯一标识符
|
||||
|
||||
***
|
||||
#### func ResetWith(name any)
|
||||
<span id="ResetWith"></span>
|
||||
> 重置特定命名空间的唯一标识符
|
||||
|
||||
***
|
||||
#### func NewOnce() *Once[V]
|
||||
<span id="NewOnce"></span>
|
||||
> 创建一个用于数据取值去重的结构实例
|
||||
|
||||
***
|
||||
#### func SonyflakeIDE() int64, error
|
||||
<span id="SonyflakeIDE"></span>
|
||||
> 获取一个雪花id
|
||||
|
||||
***
|
||||
#### func SonyflakeID() int64
|
||||
<span id="SonyflakeID"></span>
|
||||
> 获取一个雪花id
|
||||
|
||||
***
|
||||
#### func SonyflakeSetting(settings sonyflake.Settings)
|
||||
<span id="SonyflakeSetting"></span>
|
||||
> 配置雪花id生成策略
|
||||
|
||||
***
|
||||
#### func AutoIncrementUint32() uint32
|
||||
<span id="AutoIncrementUint32"></span>
|
||||
> 获取一个自增的 uint32 值
|
||||
|
||||
***
|
||||
#### func AutoIncrementUint64() uint64
|
||||
<span id="AutoIncrementUint64"></span>
|
||||
> 获取一个自增的 uint64 值
|
||||
|
||||
***
|
||||
#### func AutoIncrementInt32() int32
|
||||
<span id="AutoIncrementInt32"></span>
|
||||
> 获取一个自增的 int32 值
|
||||
|
||||
***
|
||||
#### func AutoIncrementInt64() int64
|
||||
<span id="AutoIncrementInt64"></span>
|
||||
> 获取一个自增的 int64 值
|
||||
|
||||
***
|
||||
#### func AutoIncrementInt() int
|
||||
<span id="AutoIncrementInt"></span>
|
||||
> 获取一个自增的 int 值
|
||||
|
||||
***
|
||||
#### func AutoIncrementString() string
|
||||
<span id="AutoIncrementString"></span>
|
||||
> 获取一个自增的字符串
|
||||
|
||||
***
|
||||
### Once `STRUCT`
|
||||
用于数据取值去重的结构体
|
||||
```go
|
||||
type Once[V any] struct {
|
||||
r map[any]struct{}
|
||||
}
|
||||
```
|
||||
#### func (*Once) Get(key any, value V, defaultValue V) V
|
||||
> 获取一个值,当该值已经被获取过的时候,返回 defaultValue,否则返回 value
|
||||
***
|
||||
#### func (*Once) Reset(key ...any)
|
||||
> 当 key 数量大于 0 时,将会重置对应 key 的记录,否则重置所有记录
|
||||
***
|
|
@ -0,0 +1,125 @@
|
|||
# Sorts
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[Topological](#Topological)|拓扑排序是一种对有向图进行排序的算法,它可以用来解决一些依赖关系的问题,比如计算字段的依赖关系。拓扑排序会将存在依赖关系的元素进行排序,使得依赖关系的元素总是排在被依赖的元素之前。
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func Topological(slice S, queryIndexHandler func (item V) Index, queryDependsHandler func (item V) []Index) S, error
|
||||
<span id="Topological"></span>
|
||||
> 拓扑排序是一种对有向图进行排序的算法,它可以用来解决一些依赖关系的问题,比如计算字段的依赖关系。拓扑排序会将存在依赖关系的元素进行排序,使得依赖关系的元素总是排在被依赖的元素之前。
|
||||
> - slice: 需要排序的切片
|
||||
> - queryIndexHandler: 用于查询切片中每个元素的索引
|
||||
> - queryDependsHandler: 用于查询切片中每个元素的依赖关系,返回的是一个索引切片,如果没有依赖关系,那么返回空切片
|
||||
>
|
||||
> 该函数在存在循环依赖的情况下将会返回 ErrCircularDependencyDetected 错误
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleTopological() {
|
||||
type Item struct {
|
||||
ID int
|
||||
Depends []int
|
||||
}
|
||||
var items = []Item{{ID: 2, Depends: []int{4}}, {ID: 1, Depends: []int{2, 3}}, {ID: 3, Depends: []int{4}}, {ID: 4, Depends: []int{5}}, {ID: 5, Depends: []int{}}}
|
||||
var sorted, err = sorts.Topological(items, func(item Item) int {
|
||||
return item.ID
|
||||
}, func(item Item) []int {
|
||||
return item.Depends
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, item := range sorted {
|
||||
fmt.Println(item.ID, "|", item.Depends)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestTopological(t *testing.T) {
|
||||
type Item struct {
|
||||
ID int
|
||||
Depends []int
|
||||
}
|
||||
var items = []Item{{ID: 2, Depends: []int{4}}, {ID: 1, Depends: []int{2, 3}}, {ID: 3, Depends: []int{4}}, {ID: 4, Depends: []int{5}}, {ID: 5, Depends: []int{}}}
|
||||
var sorted, err = sorts.Topological(items, func(item Item) int {
|
||||
return item.ID
|
||||
}, func(item Item) []int {
|
||||
return item.Depends
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
for _, item := range sorted {
|
||||
t.Log(item.ID, "|", item.Depends)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起基准测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func BenchmarkTopological(b *testing.B) {
|
||||
type Item struct {
|
||||
ID int
|
||||
Depends []int
|
||||
}
|
||||
var items = []Item{{ID: 2, Depends: []int{4}}, {ID: 1, Depends: []int{2, 3}}, {ID: 3, Depends: []int{4}}, {ID: 4, Depends: []int{5}}, {ID: 5, Depends: []int{}}}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := Topological(items, func(item Item) int {
|
||||
return item.ID
|
||||
}, func(item Item) []int {
|
||||
return item.Depends
|
||||
})
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
|
@ -0,0 +1,176 @@
|
|||
# Str
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[RangeLine](#RangeLine)|对传入的eachString进行按行切片后再进行遍历
|
||||
|[SplitTrimSpace](#SplitTrimSpace)|按照空格分割字符串并去除空格
|
||||
|[FirstUpper](#FirstUpper)|首字母大写
|
||||
|[FirstLower](#FirstLower)|首字母小写
|
||||
|[FirstUpperBytes](#FirstUpperBytes)|首字母大写
|
||||
|[FirstLowerBytes](#FirstLowerBytes)|首字母小写
|
||||
|[IsEmpty](#IsEmpty)|判断字符串是否为空
|
||||
|[IsEmptyBytes](#IsEmptyBytes)|判断字符串是否为空
|
||||
|[IsNotEmpty](#IsNotEmpty)|判断字符串是否不为空
|
||||
|[IsNotEmptyBytes](#IsNotEmptyBytes)|判断字符串是否不为空
|
||||
|[SnakeString](#SnakeString)|蛇形字符串
|
||||
|[SnakeStringBytes](#SnakeStringBytes)|蛇形字符串
|
||||
|[CamelString](#CamelString)|驼峰字符串
|
||||
|[CamelStringBytes](#CamelStringBytes)|驼峰字符串
|
||||
|[SortJoin](#SortJoin)|将多个字符串排序后拼接
|
||||
|[HideSensitivity](#HideSensitivity)|返回防敏感化后的字符串
|
||||
|[ThousandsSeparator](#ThousandsSeparator)|返回将str进行千位分隔符处理后的字符串。
|
||||
|[KV](#KV)|返回str经过转换后形成的key、value
|
||||
|[FormatSpeedyInt](#FormatSpeedyInt)|返回numberStr经过格式化后去除空格和“,”分隔符的结果
|
||||
|[FormatSpeedyInt64](#FormatSpeedyInt64)|返回numberStr经过格式化后去除空格和“,”分隔符的结果
|
||||
|[FormatSpeedyFloat32](#FormatSpeedyFloat32)|返回numberStr经过格式化后去除空格和“,”分隔符的结果
|
||||
|[FormatSpeedyFloat64](#FormatSpeedyFloat64)|返回numberStr经过格式化后去除空格和“,”分隔符的结果
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func RangeLine(eachString string, eachFunc func (index int, line string) error) error
|
||||
<span id="RangeLine"></span>
|
||||
> 对传入的eachString进行按行切片后再进行遍历
|
||||
> - 该函数会预先对“\r\n”进行处理替换为“\n”。
|
||||
> - 在遍历到每一行的时候会将结果index和line作为入参传入eachFunc中进行调用。
|
||||
> - index表示了当前行的行号(由0开始),line表示了当前行的内容。
|
||||
|
||||
***
|
||||
#### func SplitTrimSpace(str string, sep string) []string
|
||||
<span id="SplitTrimSpace"></span>
|
||||
> 按照空格分割字符串并去除空格
|
||||
|
||||
***
|
||||
#### func FirstUpper(str string) string
|
||||
<span id="FirstUpper"></span>
|
||||
> 首字母大写
|
||||
|
||||
***
|
||||
#### func FirstLower(str string) string
|
||||
<span id="FirstLower"></span>
|
||||
> 首字母小写
|
||||
|
||||
***
|
||||
#### func FirstUpperBytes(str []byte) []byte
|
||||
<span id="FirstUpperBytes"></span>
|
||||
> 首字母大写
|
||||
|
||||
***
|
||||
#### func FirstLowerBytes(str []byte) []byte
|
||||
<span id="FirstLowerBytes"></span>
|
||||
> 首字母小写
|
||||
|
||||
***
|
||||
#### func IsEmpty(str string) bool
|
||||
<span id="IsEmpty"></span>
|
||||
> 判断字符串是否为空
|
||||
|
||||
***
|
||||
#### func IsEmptyBytes(str []byte) bool
|
||||
<span id="IsEmptyBytes"></span>
|
||||
> 判断字符串是否为空
|
||||
|
||||
***
|
||||
#### func IsNotEmpty(str string) bool
|
||||
<span id="IsNotEmpty"></span>
|
||||
> 判断字符串是否不为空
|
||||
|
||||
***
|
||||
#### func IsNotEmptyBytes(str []byte) bool
|
||||
<span id="IsNotEmptyBytes"></span>
|
||||
> 判断字符串是否不为空
|
||||
|
||||
***
|
||||
#### func SnakeString(str string) string
|
||||
<span id="SnakeString"></span>
|
||||
> 蛇形字符串
|
||||
|
||||
***
|
||||
#### func SnakeStringBytes(str []byte) []byte
|
||||
<span id="SnakeStringBytes"></span>
|
||||
> 蛇形字符串
|
||||
|
||||
***
|
||||
#### func CamelString(str string) string
|
||||
<span id="CamelString"></span>
|
||||
> 驼峰字符串
|
||||
|
||||
***
|
||||
#### func CamelStringBytes(str []byte) []byte
|
||||
<span id="CamelStringBytes"></span>
|
||||
> 驼峰字符串
|
||||
|
||||
***
|
||||
#### func SortJoin(delimiter string, s ...string) string
|
||||
<span id="SortJoin"></span>
|
||||
> 将多个字符串排序后拼接
|
||||
|
||||
***
|
||||
#### func HideSensitivity(str string) (result string)
|
||||
<span id="HideSensitivity"></span>
|
||||
> 返回防敏感化后的字符串
|
||||
> - 隐藏身份证、邮箱、手机号等敏感信息用*号替代
|
||||
|
||||
***
|
||||
#### func ThousandsSeparator(str string) string
|
||||
<span id="ThousandsSeparator"></span>
|
||||
> 返回将str进行千位分隔符处理后的字符串。
|
||||
|
||||
***
|
||||
#### func KV(str string, tag ...string) string, string
|
||||
<span id="KV"></span>
|
||||
> 返回str经过转换后形成的key、value
|
||||
> - 这里tag表示使用什么字符串来区分key和value的分隔符。
|
||||
> - 默认情况即不传入tag的情况下分隔符为“=”。
|
||||
|
||||
***
|
||||
#### func FormatSpeedyInt(numberStr string) int, error
|
||||
<span id="FormatSpeedyInt"></span>
|
||||
> 返回numberStr经过格式化后去除空格和“,”分隔符的结果
|
||||
> - 当字符串为“123,456,789”的时候,返回结果为“123456789”。
|
||||
> - 当字符串为“123 456 789”的时候,返回结果为“123456789”。
|
||||
> - 当字符串为“1 23, 45 6, 789”的时候,返回结果为“123456789”。
|
||||
|
||||
***
|
||||
#### func FormatSpeedyInt64(numberStr string) int64, error
|
||||
<span id="FormatSpeedyInt64"></span>
|
||||
> 返回numberStr经过格式化后去除空格和“,”分隔符的结果
|
||||
> - 当字符串为“123,456,789”的时候,返回结果为“123456789”。
|
||||
> - 当字符串为“123 456 789”的时候,返回结果为“123456789”。
|
||||
> - 当字符串为“1 23, 45 6, 789”的时候,返回结果为“123456789”。
|
||||
|
||||
***
|
||||
#### func FormatSpeedyFloat32(numberStr string) float64, error
|
||||
<span id="FormatSpeedyFloat32"></span>
|
||||
> 返回numberStr经过格式化后去除空格和“,”分隔符的结果
|
||||
> - 当字符串为“123,456,789.123”的时候,返回结果为“123456789.123”。
|
||||
> - 当字符串为“123 456 789.123”的时候,返回结果为“123456789.123”。
|
||||
> - 当字符串为“1 23, 45 6, 789.123”的时候,返回结果为“123456789.123”。
|
||||
|
||||
***
|
||||
#### func FormatSpeedyFloat64(numberStr string) float64, error
|
||||
<span id="FormatSpeedyFloat64"></span>
|
||||
> 返回numberStr经过格式化后去除空格和“,”分隔符的结果
|
||||
> - 当字符串为“123,456,789.123”的时候,返回结果为“123456789.123”。
|
||||
> - 当字符串为“123 456 789.123”的时候,返回结果为“123456789.123”。
|
||||
> - 当字符串为“1 23, 45 6, 789.123”的时候,返回结果为“123456789.123”。
|
||||
|
||||
***
|
|
@ -0,0 +1,986 @@
|
|||
# Super
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[NewBitSet](#NewBitSet)|通过指定的 Bit 位创建一个 BitSet
|
||||
|[TryWriteChannel](#TryWriteChannel)|尝试写入 channel,如果 channel 无法写入则忽略,返回是否写入成功
|
||||
|[TryWriteChannelByHandler](#TryWriteChannelByHandler)|尝试写入 channel,如果 channel 无法写入则执行 handler
|
||||
|[RegError](#RegError)|通过错误码注册错误,返回错误的引用
|
||||
|[RegErrorRef](#RegErrorRef)|通过错误码注册错误,返回错误的引用
|
||||
|[GetError](#GetError)|通过错误引用获取错误码和真实错误信息,如果错误不存在则返回 0,如果错误引用不存在则返回原本的错误
|
||||
|[RecoverTransform](#RecoverTransform)|recover 错误转换
|
||||
|[Handle](#Handle)|执行 f 函数,如果 f 为 nil,则不执行
|
||||
|[HandleErr](#HandleErr)|执行 f 函数,如果 f 为 nil,则不执行
|
||||
|[HandleV](#HandleV)|执行 f 函数,如果 f 为 nil,则不执行
|
||||
|[GoFormat](#GoFormat)|go 代码格式化
|
||||
|[If](#If)|暂无描述...
|
||||
|[MarshalJSON](#MarshalJSON)|将对象转换为 json
|
||||
|[MarshalJSONE](#MarshalJSONE)|将对象转换为 json
|
||||
|[UnmarshalJSON](#UnmarshalJSON)|将 json 转换为对象
|
||||
|[MarshalIndentJSON](#MarshalIndentJSON)|将对象转换为 json
|
||||
|[MarshalToTargetWithJSON](#MarshalToTargetWithJSON)|将对象转换为目标对象
|
||||
|[StartLossCounter](#StartLossCounter)|开始损耗计数
|
||||
|[Match](#Match)|匹配
|
||||
|[IsNumber](#IsNumber)|判断是否为数字
|
||||
|[NumberToRome](#NumberToRome)|将数字转换为罗马数字
|
||||
|[StringToInt](#StringToInt)|字符串转换为整数
|
||||
|[StringToFloat64](#StringToFloat64)|字符串转换为 float64
|
||||
|[StringToBool](#StringToBool)|字符串转换为 bool
|
||||
|[StringToUint64](#StringToUint64)|字符串转换为 uint64
|
||||
|[StringToUint](#StringToUint)|字符串转换为 uint
|
||||
|[StringToFloat32](#StringToFloat32)|字符串转换为 float32
|
||||
|[StringToInt64](#StringToInt64)|字符串转换为 int64
|
||||
|[StringToUint32](#StringToUint32)|字符串转换为 uint32
|
||||
|[StringToInt32](#StringToInt32)|字符串转换为 int32
|
||||
|[StringToUint16](#StringToUint16)|字符串转换为 uint16
|
||||
|[StringToInt16](#StringToInt16)|字符串转换为 int16
|
||||
|[StringToUint8](#StringToUint8)|字符串转换为 uint8
|
||||
|[StringToInt8](#StringToInt8)|字符串转换为 int8
|
||||
|[StringToByte](#StringToByte)|字符串转换为 byte
|
||||
|[StringToRune](#StringToRune)|字符串转换为 rune
|
||||
|[IntToString](#IntToString)|整数转换为字符串
|
||||
|[Float64ToString](#Float64ToString)|float64 转换为字符串
|
||||
|[BoolToString](#BoolToString)|bool 转换为字符串
|
||||
|[Uint64ToString](#Uint64ToString)|uint64 转换为字符串
|
||||
|[UintToString](#UintToString)|uint 转换为字符串
|
||||
|[Float32ToString](#Float32ToString)|float32 转换为字符串
|
||||
|[Int64ToString](#Int64ToString)|int64 转换为字符串
|
||||
|[Uint32ToString](#Uint32ToString)|uint32 转换为字符串
|
||||
|[Int32ToString](#Int32ToString)|int32 转换为字符串
|
||||
|[Uint16ToString](#Uint16ToString)|uint16 转换为字符串
|
||||
|[Int16ToString](#Int16ToString)|int16 转换为字符串
|
||||
|[Uint8ToString](#Uint8ToString)|uint8 转换为字符串
|
||||
|[Int8ToString](#Int8ToString)|int8 转换为字符串
|
||||
|[ByteToString](#ByteToString)|byte 转换为字符串
|
||||
|[RuneToString](#RuneToString)|rune 转换为字符串
|
||||
|[StringToSlice](#StringToSlice)|字符串转换为切片
|
||||
|[SliceToString](#SliceToString)|切片转换为字符串
|
||||
|[NewPermission](#NewPermission)|创建权限
|
||||
|[Retry](#Retry)|根据提供的 count 次数尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功或者达到 count 次数
|
||||
|[RetryByRule](#RetryByRule)|根据提供的规则尝试执行 f 函数,如果 f 函数返回错误,则根据 rule 的返回值进行重试
|
||||
|[RetryByExponentialBackoff](#RetryByExponentialBackoff)|根据指数退避算法尝试执行 f 函数
|
||||
|[ConditionalRetryByExponentialBackoff](#ConditionalRetryByExponentialBackoff)|该函数与 RetryByExponentialBackoff 类似,但是可以被中断
|
||||
|[RetryAsync](#RetryAsync)|与 Retry 类似,但是是异步执行
|
||||
|[RetryForever](#RetryForever)|根据提供的 interval 时间间隔尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功
|
||||
|[NewStackGo](#NewStackGo)|返回一个用于获取上一个协程调用的堆栈信息的收集器
|
||||
|[LaunchTime](#LaunchTime)|获取程序启动时间
|
||||
|[Hostname](#Hostname)|获取主机名
|
||||
|[PID](#PID)|获取进程 PID
|
||||
|[StringToBytes](#StringToBytes)|以零拷贝的方式将字符串转换为字节切片
|
||||
|[BytesToString](#BytesToString)|以零拷贝的方式将字节切片转换为字符串
|
||||
|[Convert](#Convert)|以零拷贝的方式将一个对象转换为另一个对象
|
||||
|[Verify](#Verify)|对特定表达式进行校验,当表达式不成立时,将执行 handle
|
||||
|[OldVersion](#OldVersion)|检查 version2 对于 version1 来说是不是旧版本
|
||||
|[CompareVersion](#CompareVersion)|返回一个整数,用于表示两个版本号的比较结果:
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[BitSet](#bitset)|是一个可以动态增长的比特位集合
|
||||
|`STRUCT`|[LossCounter](#losscounter)|暂无描述...
|
||||
|`STRUCT`|[Matcher](#matcher)|匹配器
|
||||
|`STRUCT`|[Permission](#permission)|暂无描述...
|
||||
|`STRUCT`|[StackGo](#stackgo)|用于获取上一个协程调用的堆栈信息
|
||||
|`STRUCT`|[VerifyHandle](#verifyhandle)|校验句柄
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func NewBitSet(bits ...Bit) *BitSet[Bit]
|
||||
<span id="NewBitSet"></span>
|
||||
> 通过指定的 Bit 位创建一个 BitSet
|
||||
|
||||
***
|
||||
#### func TryWriteChannel(ch chan T, data T) bool
|
||||
<span id="TryWriteChannel"></span>
|
||||
> 尝试写入 channel,如果 channel 无法写入则忽略,返回是否写入成功
|
||||
> - 无法写入的情况包括:channel 已满、channel 已关闭
|
||||
|
||||
***
|
||||
#### func TryWriteChannelByHandler(ch chan T, data T, handler func ())
|
||||
<span id="TryWriteChannelByHandler"></span>
|
||||
> 尝试写入 channel,如果 channel 无法写入则执行 handler
|
||||
> - 无法写入的情况包括:channel 已满、channel 已关闭
|
||||
|
||||
***
|
||||
#### func RegError(code int, message string) error
|
||||
<span id="RegError"></span>
|
||||
> 通过错误码注册错误,返回错误的引用
|
||||
|
||||
***
|
||||
#### func RegErrorRef(code int, message string, ref error) error
|
||||
<span id="RegErrorRef"></span>
|
||||
> 通过错误码注册错误,返回错误的引用
|
||||
> - 引用将会被重定向到注册的错误信息
|
||||
|
||||
***
|
||||
#### func GetError(err error) int, error
|
||||
<span id="GetError"></span>
|
||||
> 通过错误引用获取错误码和真实错误信息,如果错误不存在则返回 0,如果错误引用不存在则返回原本的错误
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestGetError(t *testing.T) {
|
||||
var ErrNotFound = errors.New("not found")
|
||||
var _ = super.RegErrorRef(100, "test error", ErrNotFound)
|
||||
t.Log(super.GetError(ErrNotFound))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func RecoverTransform(a any) error
|
||||
<span id="RecoverTransform"></span>
|
||||
> recover 错误转换
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleRecoverTransform() {
|
||||
defer func() {
|
||||
if err := super.RecoverTransform(recover()); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}()
|
||||
panic("test")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func Handle(f func ())
|
||||
<span id="Handle"></span>
|
||||
> 执行 f 函数,如果 f 为 nil,则不执行
|
||||
|
||||
***
|
||||
#### func HandleErr(f func () error) error
|
||||
<span id="HandleErr"></span>
|
||||
> 执行 f 函数,如果 f 为 nil,则不执行
|
||||
|
||||
***
|
||||
#### func HandleV(v V, f func (v V))
|
||||
<span id="HandleV"></span>
|
||||
> 执行 f 函数,如果 f 为 nil,则不执行
|
||||
|
||||
***
|
||||
#### func GoFormat(filePath string)
|
||||
<span id="GoFormat"></span>
|
||||
> go 代码格式化
|
||||
|
||||
***
|
||||
#### func If(expression bool, t T, f T) T
|
||||
<span id="If"></span>
|
||||
|
||||
***
|
||||
#### func MarshalJSON(v interface {}) []byte
|
||||
<span id="MarshalJSON"></span>
|
||||
> 将对象转换为 json
|
||||
> - 当转换失败时,将返回 json 格式的空对象
|
||||
|
||||
***
|
||||
#### func MarshalJSONE(v interface {}) []byte, error
|
||||
<span id="MarshalJSONE"></span>
|
||||
> 将对象转换为 json
|
||||
> - 当转换失败时,将返回错误信息
|
||||
|
||||
***
|
||||
#### func UnmarshalJSON(data []byte, v interface {}) error
|
||||
<span id="UnmarshalJSON"></span>
|
||||
> 将 json 转换为对象
|
||||
|
||||
***
|
||||
#### func MarshalIndentJSON(v interface {}, prefix string, indent string) []byte
|
||||
<span id="MarshalIndentJSON"></span>
|
||||
> 将对象转换为 json
|
||||
|
||||
***
|
||||
#### func MarshalToTargetWithJSON(src interface {}, dest interface {}) error
|
||||
<span id="MarshalToTargetWithJSON"></span>
|
||||
> 将对象转换为目标对象
|
||||
|
||||
***
|
||||
#### func StartLossCounter() *LossCounter
|
||||
<span id="StartLossCounter"></span>
|
||||
> 开始损耗计数
|
||||
|
||||
***
|
||||
#### func Match(value Value) *Matcher[Value, Result]
|
||||
<span id="Match"></span>
|
||||
> 匹配
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
Convey("TestMatch", t, func() {
|
||||
So(super.Match[int, string](1).Case(1, "a").Case(2, "b").Default("c"), ShouldEqual, "a")
|
||||
So(super.Match[int, string](2).Case(1, "a").Case(2, "b").Default("c"), ShouldEqual, "b")
|
||||
So(super.Match[int, string](3).Case(1, "a").Case(2, "b").Default("c"), ShouldEqual, "c")
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func IsNumber(v any) bool
|
||||
<span id="IsNumber"></span>
|
||||
> 判断是否为数字
|
||||
|
||||
***
|
||||
#### func NumberToRome(num int) string
|
||||
<span id="NumberToRome"></span>
|
||||
> 将数字转换为罗马数字
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNumberToRome(t *testing.T) {
|
||||
tests := []struct {
|
||||
input int
|
||||
output string
|
||||
}{{input: 1, output: "I"}, {input: 5, output: "V"}, {input: 10, output: "X"}, {input: 50, output: "L"}, {input: 100, output: "C"}, {input: 500, output: "D"}, {input: 1000, output: "M"}}
|
||||
for _, test := range tests {
|
||||
result := super.NumberToRome(test.input)
|
||||
if result != test.output {
|
||||
t.Errorf("NumberToRome(%d) = %s; want %s", test.input, result, test.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func StringToInt(value string) int
|
||||
<span id="StringToInt"></span>
|
||||
> 字符串转换为整数
|
||||
|
||||
***
|
||||
#### func StringToFloat64(value string) float64
|
||||
<span id="StringToFloat64"></span>
|
||||
> 字符串转换为 float64
|
||||
|
||||
***
|
||||
#### func StringToBool(value string) bool
|
||||
<span id="StringToBool"></span>
|
||||
> 字符串转换为 bool
|
||||
|
||||
***
|
||||
#### func StringToUint64(value string) uint64
|
||||
<span id="StringToUint64"></span>
|
||||
> 字符串转换为 uint64
|
||||
|
||||
***
|
||||
#### func StringToUint(value string) uint
|
||||
<span id="StringToUint"></span>
|
||||
> 字符串转换为 uint
|
||||
|
||||
***
|
||||
#### func StringToFloat32(value string) float32
|
||||
<span id="StringToFloat32"></span>
|
||||
> 字符串转换为 float32
|
||||
|
||||
***
|
||||
#### func StringToInt64(value string) int64
|
||||
<span id="StringToInt64"></span>
|
||||
> 字符串转换为 int64
|
||||
|
||||
***
|
||||
#### func StringToUint32(value string) uint32
|
||||
<span id="StringToUint32"></span>
|
||||
> 字符串转换为 uint32
|
||||
|
||||
***
|
||||
#### func StringToInt32(value string) int32
|
||||
<span id="StringToInt32"></span>
|
||||
> 字符串转换为 int32
|
||||
|
||||
***
|
||||
#### func StringToUint16(value string) uint16
|
||||
<span id="StringToUint16"></span>
|
||||
> 字符串转换为 uint16
|
||||
|
||||
***
|
||||
#### func StringToInt16(value string) int16
|
||||
<span id="StringToInt16"></span>
|
||||
> 字符串转换为 int16
|
||||
|
||||
***
|
||||
#### func StringToUint8(value string) uint8
|
||||
<span id="StringToUint8"></span>
|
||||
> 字符串转换为 uint8
|
||||
|
||||
***
|
||||
#### func StringToInt8(value string) int8
|
||||
<span id="StringToInt8"></span>
|
||||
> 字符串转换为 int8
|
||||
|
||||
***
|
||||
#### func StringToByte(value string) byte
|
||||
<span id="StringToByte"></span>
|
||||
> 字符串转换为 byte
|
||||
|
||||
***
|
||||
#### func StringToRune(value string) rune
|
||||
<span id="StringToRune"></span>
|
||||
> 字符串转换为 rune
|
||||
|
||||
***
|
||||
#### func IntToString(value int) string
|
||||
<span id="IntToString"></span>
|
||||
> 整数转换为字符串
|
||||
|
||||
***
|
||||
#### func Float64ToString(value float64) string
|
||||
<span id="Float64ToString"></span>
|
||||
> float64 转换为字符串
|
||||
|
||||
***
|
||||
#### func BoolToString(value bool) string
|
||||
<span id="BoolToString"></span>
|
||||
> bool 转换为字符串
|
||||
|
||||
***
|
||||
#### func Uint64ToString(value uint64) string
|
||||
<span id="Uint64ToString"></span>
|
||||
> uint64 转换为字符串
|
||||
|
||||
***
|
||||
#### func UintToString(value uint) string
|
||||
<span id="UintToString"></span>
|
||||
> uint 转换为字符串
|
||||
|
||||
***
|
||||
#### func Float32ToString(value float32) string
|
||||
<span id="Float32ToString"></span>
|
||||
> float32 转换为字符串
|
||||
|
||||
***
|
||||
#### func Int64ToString(value int64) string
|
||||
<span id="Int64ToString"></span>
|
||||
> int64 转换为字符串
|
||||
|
||||
***
|
||||
#### func Uint32ToString(value uint32) string
|
||||
<span id="Uint32ToString"></span>
|
||||
> uint32 转换为字符串
|
||||
|
||||
***
|
||||
#### func Int32ToString(value int32) string
|
||||
<span id="Int32ToString"></span>
|
||||
> int32 转换为字符串
|
||||
|
||||
***
|
||||
#### func Uint16ToString(value uint16) string
|
||||
<span id="Uint16ToString"></span>
|
||||
> uint16 转换为字符串
|
||||
|
||||
***
|
||||
#### func Int16ToString(value int16) string
|
||||
<span id="Int16ToString"></span>
|
||||
> int16 转换为字符串
|
||||
|
||||
***
|
||||
#### func Uint8ToString(value uint8) string
|
||||
<span id="Uint8ToString"></span>
|
||||
> uint8 转换为字符串
|
||||
|
||||
***
|
||||
#### func Int8ToString(value int8) string
|
||||
<span id="Int8ToString"></span>
|
||||
> int8 转换为字符串
|
||||
|
||||
***
|
||||
#### func ByteToString(value byte) string
|
||||
<span id="ByteToString"></span>
|
||||
> byte 转换为字符串
|
||||
|
||||
***
|
||||
#### func RuneToString(value rune) string
|
||||
<span id="RuneToString"></span>
|
||||
> rune 转换为字符串
|
||||
|
||||
***
|
||||
#### func StringToSlice(value string) []string
|
||||
<span id="StringToSlice"></span>
|
||||
> 字符串转换为切片
|
||||
|
||||
***
|
||||
#### func SliceToString(value []string) string
|
||||
<span id="SliceToString"></span>
|
||||
> 切片转换为字符串
|
||||
|
||||
***
|
||||
#### func NewPermission() *Permission[Code, EntityID]
|
||||
<span id="NewPermission"></span>
|
||||
> 创建权限
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewPermission(t *testing.T) {
|
||||
const (
|
||||
Read = 1 << iota
|
||||
Write
|
||||
Execute
|
||||
)
|
||||
p := super.NewPermission[int, int]()
|
||||
p.AddPermission(1, Read, Write)
|
||||
t.Log(p.HasPermission(1, Read))
|
||||
t.Log(p.HasPermission(1, Write))
|
||||
p.SetPermission(2, Read|Write)
|
||||
t.Log(p.HasPermission(2, Read))
|
||||
t.Log(p.HasPermission(2, Execute))
|
||||
p.SetPermission(2, Execute)
|
||||
t.Log(p.HasPermission(2, Execute))
|
||||
t.Log(p.HasPermission(2, Read))
|
||||
t.Log(p.HasPermission(2, Write))
|
||||
p.RemovePermission(2, Execute)
|
||||
t.Log(p.HasPermission(2, Execute))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func Retry(count int, interval time.Duration, f func () error) error
|
||||
<span id="Retry"></span>
|
||||
> 根据提供的 count 次数尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功或者达到 count 次数
|
||||
|
||||
***
|
||||
#### func RetryByRule(f func () error, rule func (count int) time.Duration) error
|
||||
<span id="RetryByRule"></span>
|
||||
> 根据提供的规则尝试执行 f 函数,如果 f 函数返回错误,则根据 rule 的返回值进行重试
|
||||
> - rule 将包含一个入参,表示第几次重试,返回值表示下一次重试的时间间隔,当返回值为 0 时,表示不再重试
|
||||
> - rule 的 count 将在 f 首次失败后变为 1,因此 rule 的入参将从 1 开始
|
||||
|
||||
***
|
||||
#### func RetryByExponentialBackoff(f func () error, maxRetries int, baseDelay time.Duration, maxDelay time.Duration, multiplier float64, randomization float64, ignoreErrors ...error) error
|
||||
<span id="RetryByExponentialBackoff"></span>
|
||||
> 根据指数退避算法尝试执行 f 函数
|
||||
> - maxRetries:最大重试次数
|
||||
> - baseDelay:基础延迟
|
||||
> - maxDelay:最大延迟
|
||||
> - multiplier:延迟时间的乘数,通常为 2
|
||||
> - randomization:延迟时间的随机化因子,通常为 0.5
|
||||
> - ignoreErrors:忽略的错误,当 f 返回的错误在 ignoreErrors 中时,将不会进行重试
|
||||
|
||||
***
|
||||
#### func ConditionalRetryByExponentialBackoff(f func () error, cond func () bool, maxRetries int, baseDelay time.Duration, maxDelay time.Duration, multiplier float64, randomization float64, ignoreErrors ...error) error
|
||||
<span id="ConditionalRetryByExponentialBackoff"></span>
|
||||
> 该函数与 RetryByExponentialBackoff 类似,但是可以被中断
|
||||
> - cond 为中断条件,当 cond 返回 false 时,将会中断重试
|
||||
>
|
||||
> 该函数通常用于在重试过程中,需要中断重试的场景,例如:
|
||||
> - 用户请求开始游戏,由于网络等情况,进入重试状态。此时用户再次发送开始游戏请求,此时需要中断之前的重试,避免重复进入游戏
|
||||
|
||||
***
|
||||
#### func RetryAsync(count int, interval time.Duration, f func () error, callback func (err error))
|
||||
<span id="RetryAsync"></span>
|
||||
> 与 Retry 类似,但是是异步执行
|
||||
> - 传入的 callback 函数会在执行完毕后被调用,如果执行成功,则 err 为 nil,否则为错误信息
|
||||
> - 如果 callback 为 nil,则不会在执行完毕后被调用
|
||||
|
||||
***
|
||||
#### func RetryForever(interval time.Duration, f func () error)
|
||||
<span id="RetryForever"></span>
|
||||
> 根据提供的 interval 时间间隔尝试执行 f 函数,如果 f 函数返回错误,则在 interval 后重试,直到成功
|
||||
|
||||
***
|
||||
#### func NewStackGo() *StackGo
|
||||
<span id="NewStackGo"></span>
|
||||
> 返回一个用于获取上一个协程调用的堆栈信息的收集器
|
||||
|
||||
***
|
||||
#### func LaunchTime() time.Time
|
||||
<span id="LaunchTime"></span>
|
||||
> 获取程序启动时间
|
||||
|
||||
***
|
||||
#### func Hostname() string
|
||||
<span id="Hostname"></span>
|
||||
> 获取主机名
|
||||
|
||||
***
|
||||
#### func PID() int
|
||||
<span id="PID"></span>
|
||||
> 获取进程 PID
|
||||
|
||||
***
|
||||
#### func StringToBytes(s string) []byte
|
||||
<span id="StringToBytes"></span>
|
||||
> 以零拷贝的方式将字符串转换为字节切片
|
||||
|
||||
***
|
||||
#### func BytesToString(b []byte) string
|
||||
<span id="BytesToString"></span>
|
||||
> 以零拷贝的方式将字节切片转换为字符串
|
||||
|
||||
***
|
||||
#### func Convert(src A) B
|
||||
<span id="Convert"></span>
|
||||
> 以零拷贝的方式将一个对象转换为另一个对象
|
||||
> - 两个对象字段必须完全一致
|
||||
> - 该函数可以绕过私有字段的访问限制
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
type B struct {
|
||||
nocmp [0]func()
|
||||
v atomic.Value
|
||||
}
|
||||
var a = atomic.NewString("hello")
|
||||
var b = super.Convert[*atomic.String, *B](a)
|
||||
fmt.Println(b.v.Load())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func Verify(handle func ( V)) *VerifyHandle[V]
|
||||
<span id="Verify"></span>
|
||||
> 对特定表达式进行校验,当表达式不成立时,将执行 handle
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleVerify() {
|
||||
var getId = func() int {
|
||||
return 1
|
||||
}
|
||||
var n *super.VerifyHandle[int]
|
||||
super.Verify(func(err error) {
|
||||
fmt.Println(err)
|
||||
}).Case(getId() == 1, errors.New("id can't be 1")).Do()
|
||||
super.Verify(func(err error) {
|
||||
fmt.Println(err)
|
||||
}).PreCase(func() bool {
|
||||
return n == nil
|
||||
}, errors.New("n can't be nil"), func(verify *super.VerifyHandle[error]) bool {
|
||||
return verify.Do()
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func OldVersion(version1 string, version2 string) bool
|
||||
<span id="OldVersion"></span>
|
||||
> 检查 version2 对于 version1 来说是不是旧版本
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleOldVersion() {
|
||||
result := super.OldVersion("1.2.3", "1.2.2")
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestOldVersion(t *testing.T) {
|
||||
testCases := []struct {
|
||||
version1 string
|
||||
version2 string
|
||||
want bool
|
||||
}{{"1.2.3", "1.2.2", true}, {"1.2.1", "1.2.2", false}, {"1.2.3", "1.2.3", false}, {"v1.2.3", "v1.2.2", true}, {"v1.2.3", "v1.2.4", false}, {"v1.2.3", "1.2.3", false}, {"vxx2faf.d2ad5.dd3", "gga2faf.d2ad5.dd2", true}, {"awd2faf.d2ad4.dd3", "vsd2faf.d2ad5.dd3", false}, {"vxd2faf.d2ad5.dd3", "qdq2faf.d2ad5.dd3", false}, {"1.2.3", "vdafe2faf.d2ad5.dd3", false}, {"v1.2.3", "vdafe2faf.d2ad5.dd3", false}}
|
||||
for _, tc := range testCases {
|
||||
got := super.OldVersion(tc.version1, tc.version2)
|
||||
if got != tc.want {
|
||||
t.Errorf("OldVersion(%q, %q) = %v; want %v", tc.version1, tc.version2, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起基准测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func BenchmarkOldVersion(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
super.OldVersion("vfe2faf.d2ad5.dd3", "vda2faf.d2ad5.dd2")
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func CompareVersion(version1 string, version2 string) int
|
||||
<span id="CompareVersion"></span>
|
||||
> 返回一个整数,用于表示两个版本号的比较结果:
|
||||
> - 如果 version1 大于 version2,它将返回 1
|
||||
> - 如果 version1 小于 version2,它将返回 -1
|
||||
> - 如果 version1 和 version2 相等,它将返回 0
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleCompareVersion() {
|
||||
result := super.CompareVersion("1.2.3", "1.2.2")
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestCompareVersion(t *testing.T) {
|
||||
testCases := []struct {
|
||||
version1 string
|
||||
version2 string
|
||||
want int
|
||||
}{{"1.2.3", "1.2.2", 1}, {"1.2.1", "1.2.2", -1}, {"1.2.3", "1.2.3", 0}, {"v1.2.3", "v1.2.2", 1}, {"v1.2.3", "v1.2.4", -1}, {"v1.2.3", "1.2.3", 0}, {"vde2faf.d2ad5.dd3", "e2faf.d2ad5.dd2", 1}, {"vde2faf.d2ad4.dd3", "vde2faf.d2ad5.dd3", -1}, {"vfe2faf.d2ad5.dd3", "ve2faf.d2ad5.dd3", 0}, {"1.2.3", "vdafe2faf.d2ad5.dd3", -1}, {"v1.2.3", "vdafe2faf.d2ad5.dd3", -1}}
|
||||
for _, tc := range testCases {
|
||||
got := super.CompareVersion(tc.version1, tc.version2)
|
||||
if got != tc.want {
|
||||
t.Errorf("CompareVersion(%q, %q) = %v; want %v", tc.version1, tc.version2, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起基准测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func BenchmarkCompareVersion(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
super.CompareVersion("vfe2faf.d2ad5.dd3", "afe2faf.d2ad5.dd2")
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
### BitSet `STRUCT`
|
||||
是一个可以动态增长的比特位集合
|
||||
- 默认情况下将使用 64 位无符号整数来表示比特位,当需要表示的比特位超过 64 位时,将自动增长
|
||||
```go
|
||||
type BitSet[Bit generic.Integer] struct {
|
||||
set []uint64
|
||||
}
|
||||
```
|
||||
#### func (*BitSet) Set(bit Bit) *BitSet[Bit]
|
||||
> 将指定的位 bit 设置为 1
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestBitSet_Set(t *testing.T) {
|
||||
bs := super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||
bs.Set(11)
|
||||
bs.Set(12)
|
||||
bs.Set(13)
|
||||
t.Log(bs)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*BitSet) Del(bit Bit) *BitSet[Bit]
|
||||
> 将指定的位 bit 设置为 0
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestBitSet_Del(t *testing.T) {
|
||||
bs := super.NewBitSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||
bs.Del(11)
|
||||
bs.Del(12)
|
||||
bs.Del(13)
|
||||
bs.Del(10)
|
||||
t.Log(bs)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*BitSet) Shrink() *BitSet[Bit]
|
||||
> 将 BitSet 中的比特位集合缩小到最小
|
||||
> - 正常情况下当 BitSet 中的比特位超出 64 位时,将自动增长,当 BitSet 中的比特位数量减少时,可以使用该方法将 BitSet 中的比特位集合缩小到最小
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestBitSet_Shrink(t *testing.T) {
|
||||
bs := super.NewBitSet(63)
|
||||
t.Log(bs.Cap())
|
||||
bs.Set(200)
|
||||
t.Log(bs.Cap())
|
||||
bs.Del(200)
|
||||
bs.Shrink()
|
||||
t.Log(bs.Cap())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*BitSet) Cap() int
|
||||
> 返回当前 BitSet 中可以表示的最大比特位数量
|
||||
***
|
||||
#### func (*BitSet) Has(bit Bit) bool
|
||||
> 检查指定的位 bit 是否被设置为 1
|
||||
***
|
||||
#### func (*BitSet) Clear() *BitSet[Bit]
|
||||
> 清空所有的比特位
|
||||
***
|
||||
#### func (*BitSet) Len() int
|
||||
> 返回当前 BitSet 中被设置的比特位数量
|
||||
***
|
||||
#### func (*BitSet) Bits() []Bit
|
||||
> 返回当前 BitSet 中被设置的比特位
|
||||
***
|
||||
#### func (*BitSet) Reverse() *BitSet[Bit]
|
||||
> 反转当前 BitSet 中的所有比特位
|
||||
***
|
||||
#### func (*BitSet) Not() *BitSet[Bit]
|
||||
> 返回当前 BitSet 中所有比特位的反转
|
||||
***
|
||||
#### func (*BitSet) And(other *BitSet[Bit]) *BitSet[Bit]
|
||||
> 将当前 BitSet 与另一个 BitSet 进行按位与运算
|
||||
***
|
||||
#### func (*BitSet) Or(other *BitSet[Bit]) *BitSet[Bit]
|
||||
> 将当前 BitSet 与另一个 BitSet 进行按位或运算
|
||||
***
|
||||
#### func (*BitSet) Xor(other *BitSet[Bit]) *BitSet[Bit]
|
||||
> 将当前 BitSet 与另一个 BitSet 进行按位异或运算
|
||||
***
|
||||
#### func (*BitSet) Sub(other *BitSet[Bit]) *BitSet[Bit]
|
||||
> 将当前 BitSet 与另一个 BitSet 进行按位减运算
|
||||
***
|
||||
#### func (*BitSet) IsZero() bool
|
||||
> 检查当前 BitSet 是否为空
|
||||
***
|
||||
#### func (*BitSet) Clone() *BitSet[Bit]
|
||||
> 返回当前 BitSet 的副本
|
||||
***
|
||||
#### func (*BitSet) Equal(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否与另一个 BitSet 相等
|
||||
***
|
||||
#### func (*BitSet) Contains(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否包含另一个 BitSet
|
||||
***
|
||||
#### func (*BitSet) ContainsAny(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否包含另一个 BitSet 中的任意比特位
|
||||
***
|
||||
#### func (*BitSet) ContainsAll(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否包含另一个 BitSet 中的所有比特位
|
||||
***
|
||||
#### func (*BitSet) Intersect(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否与另一个 BitSet 有交集
|
||||
***
|
||||
#### func (*BitSet) Union(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否与另一个 BitSet 有并集
|
||||
***
|
||||
#### func (*BitSet) Difference(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否与另一个 BitSet 有差集
|
||||
***
|
||||
#### func (*BitSet) SymmetricDifference(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否与另一个 BitSet 有对称差集
|
||||
***
|
||||
#### func (*BitSet) Subset(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否为另一个 BitSet 的子集
|
||||
***
|
||||
#### func (*BitSet) Superset(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否为另一个 BitSet 的超集
|
||||
***
|
||||
#### func (*BitSet) Complement(other *BitSet[Bit]) bool
|
||||
> 检查当前 BitSet 是否为另一个 BitSet 的补集
|
||||
***
|
||||
#### func (*BitSet) Max() Bit
|
||||
> 返回当前 BitSet 中最大的比特位
|
||||
***
|
||||
#### func (*BitSet) Min() Bit
|
||||
> 返回当前 BitSet 中最小的比特位
|
||||
***
|
||||
#### func (*BitSet) String() string
|
||||
> 返回当前 BitSet 的字符串表示
|
||||
***
|
||||
#### func (*BitSet) MarshalJSON() []byte, error
|
||||
> 实现 json.Marshaler 接口
|
||||
***
|
||||
#### func (*BitSet) UnmarshalJSON(data []byte) error
|
||||
> 实现 json.Unmarshaler 接口
|
||||
***
|
||||
### LossCounter `STRUCT`
|
||||
|
||||
```go
|
||||
type LossCounter struct {
|
||||
curr time.Time
|
||||
loss []time.Duration
|
||||
lossKey []string
|
||||
}
|
||||
```
|
||||
#### func (*LossCounter) Record(name string)
|
||||
> 记录一次损耗
|
||||
***
|
||||
#### func (*LossCounter) GetLoss(handler func (step int, name string, loss time.Duration))
|
||||
> 获取损耗
|
||||
***
|
||||
#### func (*LossCounter) String() string
|
||||
***
|
||||
### Matcher `STRUCT`
|
||||
匹配器
|
||||
```go
|
||||
type Matcher[Value any, Result any] struct {
|
||||
value Value
|
||||
r Result
|
||||
d bool
|
||||
}
|
||||
```
|
||||
### Permission `STRUCT`
|
||||
|
||||
```go
|
||||
type Permission[Code generic.Integer, EntityID comparable] struct {
|
||||
permissions map[EntityID]Code
|
||||
l sync.RWMutex
|
||||
}
|
||||
```
|
||||
### StackGo `STRUCT`
|
||||
用于获取上一个协程调用的堆栈信息
|
||||
- 应当最先运行 Wait 函数,然后在其他协程中调用 Stack 函数或者 GiveUp 函数
|
||||
- 适用于跨协程同步通讯,例如单线程的消息处理统计耗时打印堆栈信息
|
||||
```go
|
||||
type StackGo struct {
|
||||
stack chan *struct{}
|
||||
collect chan []byte
|
||||
}
|
||||
```
|
||||
#### func (*StackGo) Wait()
|
||||
> 等待收集消息堆栈
|
||||
> - 在调用 Wait 函数后,当前协程将会被挂起,直到调用 Stack 或 GiveUp 函数
|
||||
***
|
||||
#### func (*StackGo) Stack() []byte
|
||||
> 获取消息堆栈
|
||||
> - 在调用 Wait 函数后调用该函数,将会返回上一个协程的堆栈信息
|
||||
> - 在调用 GiveUp 函数后调用该函数,将会 panic
|
||||
***
|
||||
#### func (*StackGo) GiveUp()
|
||||
> 放弃收集消息堆栈
|
||||
> - 在调用 Wait 函数后调用该函数,将会放弃收集消息堆栈并且释放资源
|
||||
> - 在调用 GiveUp 函数后调用 Stack 函数,将会 panic
|
||||
***
|
||||
### VerifyHandle `STRUCT`
|
||||
校验句柄
|
||||
```go
|
||||
type VerifyHandle[V any] struct {
|
||||
handle func(V)
|
||||
v V
|
||||
hit bool
|
||||
}
|
||||
```
|
||||
#### func (*VerifyHandle) PreCase(expression func () bool, value V, caseHandle func (verify *VerifyHandle[V]) bool) bool
|
||||
> 先决校验用例,当 expression 成立时,将跳过 caseHandle 的执行,直接执行 handle 并返回 false
|
||||
> - 常用于对前置参数的空指针校验,例如当 a 为 nil 时,不执行 a.B(),而是直接返回 false
|
||||
***
|
||||
#### func (*VerifyHandle) Case(expression bool, value V) *VerifyHandle[V]
|
||||
> 校验用例,当 expression 成立时,将忽略后续 Case,并将在 Do 时执行 handle,返回 false
|
||||
***
|
||||
#### func (*VerifyHandle) Do() bool
|
||||
> 执行校验,当校验失败时,将执行 handle,并返回 false
|
||||
***
|
|
@ -0,0 +1,218 @@
|
|||
# Timer
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[RegSystemNewDayEvent](#RegSystemNewDayEvent)|注册系统新的一天事件
|
||||
|[OnSystemNewDayEvent](#OnSystemNewDayEvent)|系统新的一天事件
|
||||
|[RegOffsetTimeNewDayEvent](#RegOffsetTimeNewDayEvent)|注册偏移时间新的一天事件
|
||||
|[OnOffsetTimeNewDayEvent](#OnOffsetTimeNewDayEvent)|偏移时间新的一天事件
|
||||
|[WithCaller](#WithCaller)|通过其他的 handle 执行 Caller
|
||||
|[WithMark](#WithMark)|通过特定的标记创建定时器
|
||||
|[NewPool](#NewPool)|创建一个定时器池,当 tickerPoolSize 小于等于 0 时,将会引发 panic,可指定为 DefaultTickerPoolSize
|
||||
|[SetPoolSize](#SetPoolSize)|设置标准池定时器池大小
|
||||
|[GetTicker](#GetTicker)|获取标准池中的一个定时器
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[SystemNewDayEventHandle](#systemnewdayeventhandle)|暂无描述...
|
||||
|`STRUCT`|[Option](#option)|暂无描述...
|
||||
|`STRUCT`|[Pool](#pool)|定时器池
|
||||
|`STRUCT`|[Scheduler](#scheduler)|调度器
|
||||
|`STRUCT`|[Ticker](#ticker)|定时器
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func RegSystemNewDayEvent(ticker *Ticker, name string, trigger bool, handle SystemNewDayEventHandle)
|
||||
<span id="RegSystemNewDayEvent"></span>
|
||||
> 注册系统新的一天事件
|
||||
> - 建议全局注册一个事件后再另行拓展
|
||||
> - 将特定 name 的定时任务注册到 ticker 中,在系统时间到达每天的 00:00:00 时触发,如果 trigger 为 true,则立即触发一次
|
||||
|
||||
***
|
||||
#### func OnSystemNewDayEvent(name string)
|
||||
<span id="OnSystemNewDayEvent"></span>
|
||||
> 系统新的一天事件
|
||||
|
||||
***
|
||||
#### func RegOffsetTimeNewDayEvent(ticker *Ticker, name string, offset *offset.Time, trigger bool, handle OffsetTimeNewDayEventHandle)
|
||||
<span id="RegOffsetTimeNewDayEvent"></span>
|
||||
> 注册偏移时间新的一天事件
|
||||
> - 建议全局注册一个事件后再另行拓展
|
||||
> - 与 RegSystemNewDayEvent 类似,但是触发时间为 offset 时间到达每天的 00:00:00
|
||||
|
||||
***
|
||||
#### func OnOffsetTimeNewDayEvent(name string)
|
||||
<span id="OnOffsetTimeNewDayEvent"></span>
|
||||
> 偏移时间新的一天事件
|
||||
|
||||
***
|
||||
#### func WithCaller(handle func (name string, caller func ())) Option
|
||||
<span id="WithCaller"></span>
|
||||
> 通过其他的 handle 执行 Caller
|
||||
|
||||
***
|
||||
#### func WithMark(mark string) Option
|
||||
<span id="WithMark"></span>
|
||||
> 通过特定的标记创建定时器
|
||||
|
||||
***
|
||||
#### func NewPool(tickerPoolSize int) *Pool
|
||||
<span id="NewPool"></span>
|
||||
> 创建一个定时器池,当 tickerPoolSize 小于等于 0 时,将会引发 panic,可指定为 DefaultTickerPoolSize
|
||||
|
||||
***
|
||||
#### func SetPoolSize(size int)
|
||||
<span id="SetPoolSize"></span>
|
||||
> 设置标准池定时器池大小
|
||||
> - 默认值为 DefaultTickerPoolSize,当定时器池中的定时器不足时,会自动创建新的定时器,当定时器释放时,会将多余的定时器进行释放,否则将放入定时器池中
|
||||
|
||||
***
|
||||
#### func GetTicker(size int, options ...Option) *Ticker
|
||||
<span id="GetTicker"></span>
|
||||
> 获取标准池中的一个定时器
|
||||
|
||||
***
|
||||
### SystemNewDayEventHandle `STRUCT`
|
||||
|
||||
```go
|
||||
type SystemNewDayEventHandle func()
|
||||
```
|
||||
### Option `STRUCT`
|
||||
|
||||
```go
|
||||
type Option func(ticker *Ticker)
|
||||
```
|
||||
### Pool `STRUCT`
|
||||
定时器池
|
||||
```go
|
||||
type Pool struct {
|
||||
tickers []*Ticker
|
||||
lock sync.Mutex
|
||||
tickerPoolSize int
|
||||
closed bool
|
||||
}
|
||||
```
|
||||
#### func (*Pool) ChangePoolSize(size int) error
|
||||
> 改变定时器池大小
|
||||
> - 当传入的大小小于或等于 0 时,将会返回错误,并且不会发生任何改变
|
||||
***
|
||||
#### func (*Pool) GetTicker(size int, options ...Option) *Ticker
|
||||
> 获取一个新的定时器
|
||||
***
|
||||
#### func (*Pool) Release()
|
||||
> 释放定时器池的资源,释放后由其产生的 Ticker 在 Ticker.Release 后将不再回到池中,而是直接释放
|
||||
> - 虽然定时器池已被释放,但是依旧可以产出 Ticker
|
||||
***
|
||||
### Scheduler `STRUCT`
|
||||
调度器
|
||||
```go
|
||||
type Scheduler struct {
|
||||
name string
|
||||
after time.Duration
|
||||
interval time.Duration
|
||||
total int
|
||||
trigger int
|
||||
kill bool
|
||||
cbFunc reflect.Value
|
||||
cbArgs []reflect.Value
|
||||
timer *timingwheel.Timer
|
||||
ticker *Ticker
|
||||
lock sync.RWMutex
|
||||
expr *cronexpr.Expression
|
||||
}
|
||||
```
|
||||
#### func (*Scheduler) Name() string
|
||||
> 获取调度器名称
|
||||
***
|
||||
#### func (*Scheduler) Next(prev time.Time) time.Time
|
||||
> 获取下一次执行的时间
|
||||
***
|
||||
#### func (*Scheduler) Caller()
|
||||
> 可由外部发起调用的执行函数
|
||||
***
|
||||
### Ticker `STRUCT`
|
||||
定时器
|
||||
```go
|
||||
type Ticker struct {
|
||||
timer *Pool
|
||||
wheel *timingwheel.TimingWheel
|
||||
timers map[string]*Scheduler
|
||||
lock sync.RWMutex
|
||||
handle func(name string, caller func())
|
||||
mark string
|
||||
}
|
||||
```
|
||||
#### func (*Ticker) Mark() string
|
||||
> 获取定时器的标记
|
||||
> - 通常用于鉴别定时器来源
|
||||
***
|
||||
#### func (*Ticker) Release()
|
||||
> 释放定时器,并将定时器重新放回 Pool 池中
|
||||
***
|
||||
#### func (*Ticker) StopTimer(name string)
|
||||
> 停止特定名称的调度器
|
||||
***
|
||||
#### func (*Ticker) IsStopped(name string) bool
|
||||
> 特定名称的调度器是否已停止
|
||||
***
|
||||
#### func (*Ticker) GetSchedulers() []string
|
||||
> 获取所有调度器名称
|
||||
***
|
||||
#### func (*Ticker) Cron(name string, expression string, handleFunc interface {}, args ...interface {})
|
||||
> 通过 cron 表达式设置一个调度器,当 cron 表达式错误时,将会引发 panic
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestTicker_Cron(t *testing.T) {
|
||||
ticker := timer.GetTicker(10)
|
||||
ticker.After("1_sec", time.Second, func() {
|
||||
t.Log(time.Now().Format(time.DateTime), "1_sec")
|
||||
})
|
||||
ticker.Loop("1_sec_loop_3", 0, time.Second, 3, func() {
|
||||
t.Log(time.Now().Format(time.DateTime), "1_sec_loop_3")
|
||||
})
|
||||
ticker.Cron("5_sec_cron", "0/5 * * * * * ?", func() {
|
||||
t.Log(time.Now().Format(time.DateTime), "5_sec_cron")
|
||||
})
|
||||
time.Sleep(times.Week)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func (*Ticker) CronByInstantly(name string, expression string, handleFunc interface {}, args ...interface {})
|
||||
> 与 Cron 相同,但是会立即执行一次
|
||||
***
|
||||
#### func (*Ticker) After(name string, after time.Duration, handleFunc interface {}, args ...interface {})
|
||||
> 设置一个在特定时间后运行一次的调度器
|
||||
***
|
||||
#### func (*Ticker) Loop(name string, after time.Duration, interval time.Duration, times int, handleFunc interface {}, args ...interface {})
|
||||
> 设置一个在特定时间后反复运行的调度器
|
||||
***
|
|
@ -0,0 +1,551 @@
|
|||
# Times
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[CalcNextSec](#CalcNextSec)|计算下一个N秒在多少秒之后
|
||||
|[CalcNextSecWithTime](#CalcNextSecWithTime)|计算下一个N秒在多少秒之后
|
||||
|[CalcNextTimeWithRefer](#CalcNextTimeWithRefer)|根据参考时间计算下一个整点时间
|
||||
|[IntervalFormatSet](#IntervalFormatSet)|针对 IntervalFormat 函数设置格式化内容
|
||||
|[IntervalFormat](#IntervalFormat)|返回指定时间戳之间的间隔
|
||||
|[GetMonthDays](#GetMonthDays)|获取一个时间当月共有多少天
|
||||
|[WeekDay](#WeekDay)|获取一个时间是星期几
|
||||
|[GetNextDayInterval](#GetNextDayInterval)|获取一个时间到下一天间隔多少秒
|
||||
|[GetToday](#GetToday)|获取一个时间的今天
|
||||
|[GetSecond](#GetSecond)|获取共有多少秒
|
||||
|[IsSameDay](#IsSameDay)|两个时间是否是同一天
|
||||
|[IsSameHour](#IsSameHour)|两个时间是否是同一小时
|
||||
|[GetMondayZero](#GetMondayZero)|获取本周一零点
|
||||
|[Date](#Date)|返回一个特定日期的时间
|
||||
|[DateWithHMS](#DateWithHMS)|返回一个精确到秒的时间
|
||||
|[GetDeltaDay](#GetDeltaDay)|获取两个时间需要加减的天数
|
||||
|[GetDeltaWeek](#GetDeltaWeek)|获取两个时间需要加减的周数
|
||||
|[GetHSMFromString](#GetHSMFromString)|从时间字符串中获取时分秒
|
||||
|[GetTimeFromString](#GetTimeFromString)|将时间字符串转化为时间
|
||||
|[GetDayZero](#GetDayZero)|获取 t 增加 day 天后的零点时间
|
||||
|[GetYesterday](#GetYesterday)|获取昨天
|
||||
|[GetDayLast](#GetDayLast)|获取某天的最后一刻
|
||||
|[GetYesterdayLast](#GetYesterdayLast)|获取昨天最后一刻
|
||||
|[GetMinuteStart](#GetMinuteStart)|获取一个时间的 0 秒
|
||||
|[GetMinuteEnd](#GetMinuteEnd)|获取一个时间的 59 秒
|
||||
|[GetHourStart](#GetHourStart)|获取一个时间的 0 分 0 秒
|
||||
|[GetHourEnd](#GetHourEnd)|获取一个时间的 59 分 59 秒
|
||||
|[GetMonthStart](#GetMonthStart)|获取一个时间的月初
|
||||
|[GetMonthEnd](#GetMonthEnd)|获取一个时间的月末
|
||||
|[GetYearStart](#GetYearStart)|获取一个时间的年初
|
||||
|[GetYearEnd](#GetYearEnd)|获取一个时间的年末
|
||||
|[NewStateLine](#NewStateLine)|创建一个从左向右由早到晚的状态时间线
|
||||
|[SetGlobalTimeOffset](#SetGlobalTimeOffset)|设置全局时间偏移量
|
||||
|[NowByNotOffset](#NowByNotOffset)|获取未偏移的当前时间
|
||||
|[GetGlobalTimeOffset](#GetGlobalTimeOffset)|获取全局时间偏移量
|
||||
|[ResetGlobalTimeOffset](#ResetGlobalTimeOffset)|重置全局时间偏移量
|
||||
|[NewPeriod](#NewPeriod)|创建一个时间段
|
||||
|[NewPeriodWindow](#NewPeriodWindow)|创建一个特定长度的时间窗口
|
||||
|[NewPeriodWindowWeek](#NewPeriodWindowWeek)|创建一周长度的时间窗口,从周一零点开始至周日 23:59:59 结束
|
||||
|[NewPeriodWithTimeArray](#NewPeriodWithTimeArray)|创建一个时间段
|
||||
|[NewPeriodWithDayZero](#NewPeriodWithDayZero)|创建一个时间段,从 t 开始,持续到 day 天后的 0 点
|
||||
|[NewPeriodWithDay](#NewPeriodWithDay)|创建一个时间段,从 t 开始,持续 day 天
|
||||
|[NewPeriodWithHour](#NewPeriodWithHour)|创建一个时间段,从 t 开始,持续 hour 小时
|
||||
|[NewPeriodWithMinute](#NewPeriodWithMinute)|创建一个时间段,从 t 开始,持续 minute 分钟
|
||||
|[NewPeriodWithSecond](#NewPeriodWithSecond)|创建一个时间段,从 t 开始,持续 second 秒
|
||||
|[NewPeriodWithMillisecond](#NewPeriodWithMillisecond)|创建一个时间段,从 t 开始,持续 millisecond 毫秒
|
||||
|[NewPeriodWithMicrosecond](#NewPeriodWithMicrosecond)|创建一个时间段,从 t 开始,持续 microsecond 微秒
|
||||
|[NewPeriodWithNanosecond](#NewPeriodWithNanosecond)|创建一个时间段,从 t 开始,持续 nanosecond 纳秒
|
||||
|
||||
|
||||
> 类型定义
|
||||
|
||||
|类型|名称|描述
|
||||
|:--|:--|:--
|
||||
|`STRUCT`|[StateLine](#stateline)|状态时间线
|
||||
|`STRUCT`|[Period](#period)|表示一个时间段
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func CalcNextSec(sec int) int
|
||||
<span id="CalcNextSec"></span>
|
||||
> 计算下一个N秒在多少秒之后
|
||||
|
||||
***
|
||||
#### func CalcNextSecWithTime(t time.Time, sec int) int
|
||||
<span id="CalcNextSecWithTime"></span>
|
||||
> 计算下一个N秒在多少秒之后
|
||||
|
||||
示例代码:
|
||||
```go
|
||||
|
||||
func ExampleCalcNextSecWithTime() {
|
||||
now := time.Date(2023, 9, 20, 0, 0, 3, 0, time.Local)
|
||||
fmt.Println(times.CalcNextSecWithTime(now, 10))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
***
|
||||
#### func CalcNextTimeWithRefer(now time.Time, refer time.Duration) time.Time
|
||||
<span id="CalcNextTimeWithRefer"></span>
|
||||
> 根据参考时间计算下一个整点时间
|
||||
> - 假设当 now 为 14:15:16 , 参考时间为 10 分钟, 则返回 14:20:00
|
||||
> - 假设当 now 为 14:15:16 , 参考时间为 20 分钟, 则返回 14:20:00
|
||||
>
|
||||
> 当 refer 小于 1 分钟时,将会返回当前时间
|
||||
|
||||
***
|
||||
#### func IntervalFormatSet(intervalType int, str string)
|
||||
<span id="IntervalFormatSet"></span>
|
||||
> 针对 IntervalFormat 函数设置格式化内容
|
||||
|
||||
***
|
||||
#### func IntervalFormat(time1 time.Time, time2 time.Time) string
|
||||
<span id="IntervalFormat"></span>
|
||||
> 返回指定时间戳之间的间隔
|
||||
> - 使用传入的时间进行计算换算,将结果体现为几年前、几天前、几小时前、几分钟前、几秒前。
|
||||
|
||||
***
|
||||
#### func GetMonthDays(t time.Time) int
|
||||
<span id="GetMonthDays"></span>
|
||||
> 获取一个时间当月共有多少天
|
||||
|
||||
***
|
||||
#### func WeekDay(t time.Time) int
|
||||
<span id="WeekDay"></span>
|
||||
> 获取一个时间是星期几
|
||||
> - 1 ~ 7
|
||||
|
||||
***
|
||||
#### func GetNextDayInterval(t time.Time) time.Duration
|
||||
<span id="GetNextDayInterval"></span>
|
||||
> 获取一个时间到下一天间隔多少秒
|
||||
|
||||
***
|
||||
#### func GetToday(t time.Time) time.Time
|
||||
<span id="GetToday"></span>
|
||||
> 获取一个时间的今天
|
||||
|
||||
***
|
||||
#### func GetSecond(d time.Duration) int
|
||||
<span id="GetSecond"></span>
|
||||
> 获取共有多少秒
|
||||
|
||||
***
|
||||
#### func IsSameDay(t1 time.Time, t2 time.Time) bool
|
||||
<span id="IsSameDay"></span>
|
||||
> 两个时间是否是同一天
|
||||
|
||||
***
|
||||
#### func IsSameHour(t1 time.Time, t2 time.Time) bool
|
||||
<span id="IsSameHour"></span>
|
||||
> 两个时间是否是同一小时
|
||||
|
||||
***
|
||||
#### func GetMondayZero(t time.Time) time.Time
|
||||
<span id="GetMondayZero"></span>
|
||||
> 获取本周一零点
|
||||
|
||||
***
|
||||
#### func Date(year int, month time.Month, day int) time.Time
|
||||
<span id="Date"></span>
|
||||
> 返回一个特定日期的时间
|
||||
|
||||
***
|
||||
#### func DateWithHMS(year int, month time.Month, day int, hour int, min int, sec int) time.Time
|
||||
<span id="DateWithHMS"></span>
|
||||
> 返回一个精确到秒的时间
|
||||
|
||||
***
|
||||
#### func GetDeltaDay(t1 time.Time, t2 time.Time) int
|
||||
<span id="GetDeltaDay"></span>
|
||||
> 获取两个时间需要加减的天数
|
||||
|
||||
***
|
||||
#### func GetDeltaWeek(t1 time.Time, t2 time.Time) int
|
||||
<span id="GetDeltaWeek"></span>
|
||||
> 获取两个时间需要加减的周数
|
||||
|
||||
***
|
||||
#### func GetHSMFromString(timeStr string, layout string) (hour int, min int, sec int)
|
||||
<span id="GetHSMFromString"></span>
|
||||
> 从时间字符串中获取时分秒
|
||||
|
||||
***
|
||||
#### func GetTimeFromString(timeStr string, layout string) time.Time
|
||||
<span id="GetTimeFromString"></span>
|
||||
> 将时间字符串转化为时间
|
||||
|
||||
***
|
||||
#### func GetDayZero(t time.Time, day int) time.Time
|
||||
<span id="GetDayZero"></span>
|
||||
> 获取 t 增加 day 天后的零点时间
|
||||
|
||||
***
|
||||
#### func GetYesterday(t time.Time) time.Time
|
||||
<span id="GetYesterday"></span>
|
||||
> 获取昨天
|
||||
|
||||
***
|
||||
#### func GetDayLast(t time.Time) time.Time
|
||||
<span id="GetDayLast"></span>
|
||||
> 获取某天的最后一刻
|
||||
> - 最后一刻即 23:59:59
|
||||
|
||||
***
|
||||
#### func GetYesterdayLast(t time.Time) time.Time
|
||||
<span id="GetYesterdayLast"></span>
|
||||
> 获取昨天最后一刻
|
||||
|
||||
***
|
||||
#### func GetMinuteStart(t time.Time) time.Time
|
||||
<span id="GetMinuteStart"></span>
|
||||
> 获取一个时间的 0 秒
|
||||
|
||||
***
|
||||
#### func GetMinuteEnd(t time.Time) time.Time
|
||||
<span id="GetMinuteEnd"></span>
|
||||
> 获取一个时间的 59 秒
|
||||
|
||||
***
|
||||
#### func GetHourStart(t time.Time) time.Time
|
||||
<span id="GetHourStart"></span>
|
||||
> 获取一个时间的 0 分 0 秒
|
||||
|
||||
***
|
||||
#### func GetHourEnd(t time.Time) time.Time
|
||||
<span id="GetHourEnd"></span>
|
||||
> 获取一个时间的 59 分 59 秒
|
||||
|
||||
***
|
||||
#### func GetMonthStart(t time.Time) time.Time
|
||||
<span id="GetMonthStart"></span>
|
||||
> 获取一个时间的月初
|
||||
|
||||
***
|
||||
#### func GetMonthEnd(t time.Time) time.Time
|
||||
<span id="GetMonthEnd"></span>
|
||||
> 获取一个时间的月末
|
||||
|
||||
***
|
||||
#### func GetYearStart(t time.Time) time.Time
|
||||
<span id="GetYearStart"></span>
|
||||
> 获取一个时间的年初
|
||||
|
||||
***
|
||||
#### func GetYearEnd(t time.Time) time.Time
|
||||
<span id="GetYearEnd"></span>
|
||||
> 获取一个时间的年末
|
||||
|
||||
***
|
||||
#### func NewStateLine(zero State) *StateLine[State]
|
||||
<span id="NewStateLine"></span>
|
||||
> 创建一个从左向右由早到晚的状态时间线
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewStateLine(t *testing.T) {
|
||||
sl := times.NewStateLine(0)
|
||||
sl.AddState(1, time.Now())
|
||||
sl.AddState(2, time.Now().Add(-times.Hour))
|
||||
sl.Range(func(index int, state int, ts time.Time) bool {
|
||||
t.Log(index, state, ts)
|
||||
return true
|
||||
})
|
||||
t.Log(sl.GetStateByTime(time.Now()))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func SetGlobalTimeOffset(offset time.Duration)
|
||||
<span id="SetGlobalTimeOffset"></span>
|
||||
> 设置全局时间偏移量
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestSetGlobalTimeOffset(t *testing.T) {
|
||||
fmt.Println(time.Now())
|
||||
times.SetGlobalTimeOffset(-times.Hour)
|
||||
fmt.Println(time.Now())
|
||||
times.SetGlobalTimeOffset(times.Hour)
|
||||
fmt.Println(time.Now())
|
||||
fmt.Println(times.NowByNotOffset())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func NowByNotOffset() time.Time
|
||||
<span id="NowByNotOffset"></span>
|
||||
> 获取未偏移的当前时间
|
||||
|
||||
***
|
||||
#### func GetGlobalTimeOffset() time.Duration
|
||||
<span id="GetGlobalTimeOffset"></span>
|
||||
> 获取全局时间偏移量
|
||||
|
||||
***
|
||||
#### func ResetGlobalTimeOffset()
|
||||
<span id="ResetGlobalTimeOffset"></span>
|
||||
> 重置全局时间偏移量
|
||||
|
||||
***
|
||||
#### func NewPeriod(start time.Time, end time.Time) Period
|
||||
<span id="NewPeriod"></span>
|
||||
> 创建一个时间段
|
||||
> - 如果 start 比 end 晚,则会自动交换两个时间
|
||||
|
||||
***
|
||||
#### func NewPeriodWindow(t time.Time, size time.Duration) Period
|
||||
<span id="NewPeriodWindow"></span>
|
||||
> 创建一个特定长度的时间窗口
|
||||
|
||||
<details>
|
||||
<summary>查看 / 收起单元测试</summary>
|
||||
|
||||
|
||||
```go
|
||||
|
||||
func TestNewPeriodWindow(t *testing.T) {
|
||||
cur := time.Now()
|
||||
fmt.Println(cur)
|
||||
window := times.NewPeriodWindow(cur, times.Day)
|
||||
fmt.Println(window)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
#### func NewPeriodWindowWeek(t time.Time) Period
|
||||
<span id="NewPeriodWindowWeek"></span>
|
||||
> 创建一周长度的时间窗口,从周一零点开始至周日 23:59:59 结束
|
||||
|
||||
***
|
||||
#### func NewPeriodWithTimeArray(times [2]time.Time) Period
|
||||
<span id="NewPeriodWithTimeArray"></span>
|
||||
> 创建一个时间段
|
||||
|
||||
***
|
||||
#### func NewPeriodWithDayZero(t time.Time, day int) Period
|
||||
<span id="NewPeriodWithDayZero"></span>
|
||||
> 创建一个时间段,从 t 开始,持续到 day 天后的 0 点
|
||||
|
||||
***
|
||||
#### func NewPeriodWithDay(t time.Time, day int) Period
|
||||
<span id="NewPeriodWithDay"></span>
|
||||
> 创建一个时间段,从 t 开始,持续 day 天
|
||||
|
||||
***
|
||||
#### func NewPeriodWithHour(t time.Time, hour int) Period
|
||||
<span id="NewPeriodWithHour"></span>
|
||||
> 创建一个时间段,从 t 开始,持续 hour 小时
|
||||
|
||||
***
|
||||
#### func NewPeriodWithMinute(t time.Time, minute int) Period
|
||||
<span id="NewPeriodWithMinute"></span>
|
||||
> 创建一个时间段,从 t 开始,持续 minute 分钟
|
||||
|
||||
***
|
||||
#### func NewPeriodWithSecond(t time.Time, second int) Period
|
||||
<span id="NewPeriodWithSecond"></span>
|
||||
> 创建一个时间段,从 t 开始,持续 second 秒
|
||||
|
||||
***
|
||||
#### func NewPeriodWithMillisecond(t time.Time, millisecond int) Period
|
||||
<span id="NewPeriodWithMillisecond"></span>
|
||||
> 创建一个时间段,从 t 开始,持续 millisecond 毫秒
|
||||
|
||||
***
|
||||
#### func NewPeriodWithMicrosecond(t time.Time, microsecond int) Period
|
||||
<span id="NewPeriodWithMicrosecond"></span>
|
||||
> 创建一个时间段,从 t 开始,持续 microsecond 微秒
|
||||
|
||||
***
|
||||
#### func NewPeriodWithNanosecond(t time.Time, nanosecond int) Period
|
||||
<span id="NewPeriodWithNanosecond"></span>
|
||||
> 创建一个时间段,从 t 开始,持续 nanosecond 纳秒
|
||||
|
||||
***
|
||||
### StateLine `STRUCT`
|
||||
状态时间线
|
||||
```go
|
||||
type StateLine[State generic.Basic] struct {
|
||||
states []State
|
||||
points []time.Time
|
||||
trigger [][]func()
|
||||
}
|
||||
```
|
||||
#### func (*StateLine) Check(missingAllowed bool, states ...State) bool
|
||||
> 根据状态顺序检查时间线是否合法
|
||||
> - missingAllowed: 是否允许状态缺失,如果为 true,则状态可以不连续,如果为 false,则状态必须连续
|
||||
>
|
||||
> 状态不连续表示时间线中存在状态缺失,例如:
|
||||
> - 状态为 [1, 2, 3, 4, 5] 的时间线,如果 missingAllowed 为 true,则状态为 [1, 3, 5] 也是合法的
|
||||
> - 状态为 [1, 2, 3, 4, 5] 的时间线,如果 missingAllowed 为 false,则状态为 [1, 3, 5] 是不合法的
|
||||
***
|
||||
#### func (*StateLine) GetMissingStates(states ...State) []State
|
||||
> 获取缺失的状态
|
||||
***
|
||||
#### func (*StateLine) HasState(state State) bool
|
||||
> 检查时间线中是否包含指定状态
|
||||
***
|
||||
#### func (*StateLine) String() string
|
||||
> 获取时间线的字符串表示
|
||||
***
|
||||
#### func (*StateLine) AddState(state State, t time.Time, onTrigger ...func ()) *StateLine[State]
|
||||
> 添加一个状态到时间线中,状态不能与任一时间点重合,否则将被忽略
|
||||
> - onTrigger: 该状态绑定的触发器,该触发器不会被主动执行,需要主动获取触发器执行
|
||||
***
|
||||
#### func (*StateLine) GetTimeByState(state State) time.Time
|
||||
> 获取指定状态的时间点
|
||||
***
|
||||
#### func (*StateLine) GetNextTimeByState(state State) time.Time
|
||||
> 获取指定状态的下一个时间点
|
||||
***
|
||||
#### func (*StateLine) GetLastState() State
|
||||
> 获取最后一个状态
|
||||
***
|
||||
#### func (*StateLine) GetPrevTimeByState(state State) time.Time
|
||||
> 获取指定状态的上一个时间点
|
||||
***
|
||||
#### func (*StateLine) GetIndexByState(state State) int
|
||||
> 获取指定状态的索引
|
||||
***
|
||||
#### func (*StateLine) GetStateByTime(t time.Time) State
|
||||
> 获取指定时间点的状态
|
||||
***
|
||||
#### func (*StateLine) GetTimeByIndex(index int) time.Time
|
||||
> 获取指定索引的时间点
|
||||
***
|
||||
#### func (*StateLine) Move(d time.Duration) *StateLine[State]
|
||||
> 时间线整体移动
|
||||
***
|
||||
#### func (*StateLine) GetNextStateTimeByIndex(index int) time.Time
|
||||
> 获取指定索引的下一个时间点
|
||||
***
|
||||
#### func (*StateLine) GetPrevStateTimeByIndex(index int) time.Time
|
||||
> 获取指定索引的上一个时间点
|
||||
***
|
||||
#### func (*StateLine) GetStateIndexByTime(t time.Time) int
|
||||
> 获取指定时间点的索引
|
||||
***
|
||||
#### func (*StateLine) GetStateCount() int
|
||||
> 获取状态数量
|
||||
***
|
||||
#### func (*StateLine) GetStateByIndex(index int) State
|
||||
> 获取指定索引的状态
|
||||
***
|
||||
#### func (*StateLine) GetTriggerByTime(t time.Time) []func ()
|
||||
> 获取指定时间点的触发器
|
||||
***
|
||||
#### func (*StateLine) GetTriggerByIndex(index int) []func ()
|
||||
> 获取指定索引的触发器
|
||||
***
|
||||
#### func (*StateLine) GetTriggerByState(state State) []func ()
|
||||
> 获取指定状态的触发器
|
||||
***
|
||||
#### func (*StateLine) AddTriggerToState(state State, onTrigger ...func ()) *StateLine[State]
|
||||
> 给指定状态添加触发器
|
||||
***
|
||||
#### func (*StateLine) Range(handler func (index int, state State, t time.Time) bool)
|
||||
> 按照时间顺序遍历时间线
|
||||
***
|
||||
#### func (*StateLine) RangeReverse(handler func (index int, state State, t time.Time) bool)
|
||||
> 按照时间逆序遍历时间线
|
||||
***
|
||||
### Period `STRUCT`
|
||||
表示一个时间段
|
||||
```go
|
||||
type Period [2]time.Time
|
||||
```
|
||||
#### func (Period) Start() time.Time
|
||||
> 返回时间段的开始时间
|
||||
***
|
||||
#### func (Period) End() time.Time
|
||||
> 返回时间段的结束时间
|
||||
***
|
||||
#### func (Period) Duration() time.Duration
|
||||
> 返回时间段的持续时间
|
||||
***
|
||||
#### func (Period) Day() int
|
||||
> 返回时间段的持续天数
|
||||
***
|
||||
#### func (Period) Hour() int
|
||||
> 返回时间段的持续小时数
|
||||
***
|
||||
#### func (Period) Minute() int
|
||||
> 返回时间段的持续分钟数
|
||||
***
|
||||
#### func (Period) Seconds() int
|
||||
> 返回时间段的持续秒数
|
||||
***
|
||||
#### func (Period) Milliseconds() int
|
||||
> 返回时间段的持续毫秒数
|
||||
***
|
||||
#### func (Period) Microseconds() int
|
||||
> 返回时间段的持续微秒数
|
||||
***
|
||||
#### func (Period) Nanoseconds() int
|
||||
> 返回时间段的持续纳秒数
|
||||
***
|
||||
#### func (Period) IsZero() bool
|
||||
> 判断时间段是否为零值
|
||||
***
|
||||
#### func (Period) IsInvalid() bool
|
||||
> 判断时间段是否无效
|
||||
***
|
||||
#### func (Period) IsBefore(t time.Time) bool
|
||||
> 判断时间段是否在指定时间之前
|
||||
***
|
||||
#### func (Period) IsAfter(t time.Time) bool
|
||||
> 判断时间段是否在指定时间之后
|
||||
***
|
||||
#### func (Period) IsBetween(t time.Time) bool
|
||||
> 判断指定时间是否在时间段之间
|
||||
***
|
||||
#### func (Period) IsOngoing(t time.Time) bool
|
||||
> 判断指定时间是否正在进行时
|
||||
> - 如果时间段的开始时间在指定时间之前或者等于指定时间,且时间段的结束时间在指定时间之后,则返回 true
|
||||
***
|
||||
#### func (Period) IsBetweenOrEqual(t time.Time) bool
|
||||
> 判断指定时间是否在时间段之间或者等于时间段的开始或结束时间
|
||||
***
|
||||
#### func (Period) IsBetweenOrEqualPeriod(t Period) bool
|
||||
> 判断指定时间是否在时间段之间或者等于时间段的开始或结束时间
|
||||
***
|
||||
#### func (Period) IsOverlap(t Period) bool
|
||||
> 判断时间段是否与指定时间段重叠
|
||||
***
|
|
@ -0,0 +1,32 @@
|
|||
# Xlsxtool
|
||||
|
||||
[](https://pkg.go.dev/github.com/kercylan98/minotaur)
|
||||

|
||||
|
||||
暂无介绍...
|
||||
|
||||
|
||||
## 目录导航
|
||||
列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
|
||||
<details>
|
||||
<summary>展开 / 折叠目录导航</summary>
|
||||
|
||||
|
||||
> 包级函数定义
|
||||
|
||||
|函数名称|描述
|
||||
|:--|:--
|
||||
|[GetSheetMatrix](#GetSheetMatrix)|将sheet转换为二维矩阵
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
***
|
||||
## 详情信息
|
||||
#### func GetSheetMatrix(sheet *xlsx.Sheet) *matrix.Matrix[*xlsx.Cell]
|
||||
<span id="GetSheetMatrix"></span>
|
||||
> 将sheet转换为二维矩阵
|
||||
|
||||
***
|
Loading…
Reference in New Issue