Documentation
¶
Index ¶
- Constants
- Variables
- func BytesI8[T ~int8](b []byte) T
- func BytesI16[T ~int16](b []byte) T
- func BytesI32[T ~int32](b []byte) T
- func BytesI64[T ~int64](b []byte) T
- func DefaultPingHandler[MEAT any](i IOContext, m MEAT, pingMsg string) error
- func DefaultUpgrader() *websocket.Upgrader
- func I8Bytes[T ~int8](cmd T) []byte
- func I16Bytes[T ~int16](cmd T) []byte
- func I32Bytes[T ~int32](cmd T) []byte
- func I64Bytes[T ~int64](cmd T) []byte
- func ReadBufferPreprocessingBinary(b []byte) []byte
- func ReadBufferPreprocessingText(b []byte) []byte
- type Client
- func (c *Client[META, HEADER]) Close()
- func (c *Client[META, HEADER]) ConnectionID() ClientID
- func (c *Client[META, HEADER]) Context() context.Context
- func (c *Client[META, HEADER]) ExecAsync(exec func())
- func (c *Client[META, HEADER]) ExecSync(work func() error) error
- func (c *Client[META, HEADER]) GetContext() context.Context
- func (c *Client[META, HEADER]) Hub() IHub
- func (c *Client[META, HEADER]) HubBroadcast(data []byte)
- func (c *Client[META, HEADER]) IsWriteConsumed(u uint64) bool
- func (c *Client[META, HEADER]) Logger() ILogger
- func (c *Client[META, HEADER]) Meta() any
- func (c *Client[META, HEADER]) Payload() []byte
- func (c *Client[META, HEADER]) Sub() META
- func (c *Client[META, HEADER]) Write(data []byte) uint64
- func (c *Client[META, HEADER]) WriteCount() uint64
- func (c *Client[META, HEADER]) WriteJson(data any) (uint64, error)
- func (c *Client[META, HEADER]) WriteMessageType(msgType int, message []byte) uint64
- func (c *Client[META, HEADER]) WriteSerialization(data any) (uint64, error)
- func (c *Client[META, HEADER]) WriteSplicing(splicing []byte, data any) (uint64, error)
- func (c *Client[META, HEADER]) WriteString(data string) uint64
- func (c *Client[META, HEADER]) WsConn() *websocket.Conn
- type ClientID
- type ConnectionProtocols
- type ConnectionType
- type DHub
- type DataSize
- type Empty
- type HandleFunc
- type HandlePack
- type HotlineFrameOption
- type HotlineID
- type HotlineOption
- type Hub
- func (*Hub[META, HEADER]) Befunc() func(ctx IOContext, meta META, req *struct{})
- func (hub *Hub[META, HEADER]) BroadcastWithFilter(data []byte, filter func(IHub, IOContext, META) bool)
- func (hub *Hub[META, HEADER]) ByteSplicing(b []byte, data any) ([]byte, error)
- func (hub *Hub[META, HEADER]) Close()
- func (hub *Hub[META, HEADER]) Context() context.Context
- func (hub *Hub[META, HEADER]) ContextIterAAsyncExec(iterTask func(ClientID, IOContext, META))
- func (hub *Hub[META, HEADER]) ContextIterASyncExec(iterTask func(ClientID, IOContext, META) error)
- func (hub *Hub[META, HEADER]) ContextIterSAsyncExec(iterTask func(ClientID, IOContext, META))
- func (hub *Hub[META, HEADER]) ExecAsync(work func(DHub))
- func (hub *Hub[META, HEADER]) ExecSync(work func(DHub) error) error
- func (hub *Hub[META, HEADER]) HubBroadcast(data []byte)
- func (hub *Hub[META, HEADER]) Logger() ILogger
- func (hub *Hub[META, HEADER]) LongPolling(option LongPollingOption) error
- func (hub *Hub[META, HEADER]) Marshal(any any) ([]byte, error)
- func (hub *Hub[META, HEADER]) NewHotline() IHotline
- func (hub *Hub[META, HEADER]) NewHotlineDirect() *hotline[META]
- func (hub *Hub[META, HEADER]) NewHotlineDirectWithOption(option HotlineOption) *hotline[META]
- func (hub *Hub[META, HEADER]) NewHotlineSilence() IHotline
- func (hub *Hub[META, HEADER]) NewHotlineSilenceDirect() *hotline[META]
- func (hub *Hub[META, HEADER]) NewHotlineWithOption(option HotlineOption) IHotline
- func (hub *Hub[META, HEADER]) Run()
- func (hub *Hub[META, HEADER]) SocketHandles(addr, port string, proto ConnectionProtocols)
- func (hub *Hub[META, HEADER]) Unmarshal(data []byte, any any) error
- func (hub *Hub[META, HEADER]) WaitAdd(num int)
- func (hub *Hub[META, HEADER]) WaitDone()
- func (hub *Hub[META, HEADER]) WebSocketHandler(w http.ResponseWriter, r *http.Request)
- func (hub *Hub[META, HEADER]) WebSocketHandlerWithMeta(w http.ResponseWriter, r *http.Request, m META)
- type HubSetting
- type IHotline
- type IHotlineFrameControl
- type IHub
- type ILogger
- type IOContext
- type IOperationCountdown
- type IOperationCountdownTicker
- type IncrementByte
- type LongPollingOption
- type LongPollingResult
- type MatcherMap
- func (matcher *MatcherMap[META, HEADER]) GenSub() SubMatcher[META, HEADER]
- func (matcher *MatcherMap[META, HEADER]) HeaderParsing(ReceiveData []byte) (HEADER, []byte)
- func (matcher *MatcherMap[META, HEADER]) Init(logger ILogger)
- func (matcher *MatcherMap[META, HEADER]) Marshal(handleRequest any) ([]byte, error)
- func (matcher *MatcherMap[META, HEADER]) Unmarshal(body []byte, handleRequest any) error
- type OperationCountdown
- type OperationCountdownTicker
- type PingPongPlan
- type ReadBufferPreprocessing
- type SocketPeriod
- type SubMatcher
- type WebsocketPeriod
Constants ¶
const ( TextMessage messageType = websocket.TextMessage BinaryMessage messageType = websocket.BinaryMessage CloseMessage messageType = websocket.CloseMessage PingMessage messageType = websocket.PingMessage PongMessage messageType = websocket.PongMessage )
Variables ¶
var ( ErrHandleAnyNotPtr = "handle any not ptr: %+v" ErrHandleNotFunc = "handle not func: %+v" ErrContextNotClient = "context not client: %+v" ErrHandleNotFind = "handle not find header: %+v" ErrHandleKindError = "handle kind error: header %+v" ErrLongPollingTimeOutZeroError = errors.New("LongPolling option.Timeout can't be zero") )
var ( DefaultNewline = []byte{'\n'} DefaultSpace = []byte{' '} )
Functions ¶
func DefaultPingHandler ¶
func DefaultUpgrader ¶
func ReadBufferPreprocessingBinary ¶
BinaryBufferPreprocessing 處理二進制時的預處理模式 例如pb 就是不處理
func ReadBufferPreprocessingText ¶
TextBufferPreprocessing 處理文本時的預處理模式 例如json 會有換行符號
Types ¶
type Client ¶
type Client[META any, HEADER comparable] struct { ID ClientID // ReceiveBuffer only Receive , after processing ReceiveBuffer []byte PayloadBuffer []byte // contains filtered or unexported fields }
func (*Client[META, HEADER]) ConnectionID ¶
func (*Client[META, HEADER]) GetContext ¶
func (*Client[META, HEADER]) HubBroadcast ¶
func (*Client[META, HEADER]) IsWriteConsumed ¶
func (*Client[META, HEADER]) WriteCount ¶
func (*Client[META, HEADER]) WriteMessageType ¶
func (*Client[META, HEADER]) WriteSerialization ¶
func (*Client[META, HEADER]) WriteSplicing ¶
func (*Client[META, HEADER]) WriteString ¶
type ConnectionProtocols ¶
type ConnectionProtocols string
const ( TCP ConnectionProtocols = "tcp" UDP ConnectionProtocols = "udp" )
type ConnectionType ¶
type ConnectionType string
const ( Websocket ConnectionType = "Websocket" Socket ConnectionType = "Socket" )
type Empty ¶
type Empty struct{}
If you want to skip the serialization method and return the value, use this
type HandleFunc ¶
func (HandleFunc[META]) Check ¶
func (h HandleFunc[META]) Check() HandleFunc[META]
type HandlePack ¶
type HotlineFrameOption ¶
type HotlineFrameOption[Obj any] struct { ControlSze int Hz int64 // if Hz HzBasic both zero , Logic is skip HzBasic time.Duration NewObj func() *Obj OnStart func(hotline IHotlineFrameControl[Obj], obj *Obj) Logic func(hotline IHotlineFrameControl[Obj], obj *Obj) OnClose func(hotline IHotlineFrameControl[Obj], obj *Obj) // contains filtered or unexported fields }
func (HotlineFrameOption[Obj]) HotlineFrameRun ¶
func (ho HotlineFrameOption[Obj]) HotlineFrameRun(hotline IHotline) (IHotlineFrameControl[Obj], error)
func (HotlineFrameOption[Obj]) MakeFrameRun ¶
func (ho HotlineFrameOption[Obj]) MakeFrameRun(hotline IHotline) IHotlineFrameControl[Obj]
type HotlineOption ¶
type Hub ¶
type Hub[META any, HEADER comparable] struct { // contains filtered or unexported fields }
func NewHub ¶
func NewHub[META any, HEADER comparable](setting HubSetting[META, HEADER]) *Hub[META, HEADER]
func NewHubRun ¶
func NewHubRun[META any, HEADER comparable](setting HubSetting[META, HEADER]) *Hub[META, HEADER]
func (*Hub[META, HEADER]) Befunc ¶
It does nothing but serves as an example to help you make a HandleSetting
func (*Hub[META, HEADER]) BroadcastWithFilter ¶
func (*Hub[META, HEADER]) ByteSplicing ¶
func (*Hub[META, HEADER]) ContextIterAAsyncExec ¶
ContextIterAAsyncExec executes Hub internal operation asynchronously and executes async tasks for each client
Returns immediately without waiting for Hub internal operation or client tasks to complete
func (*Hub[META, HEADER]) ContextIterASyncExec ¶
ContextIterASyncExec executes Hub internal operation asynchronously, but executes sync tasks for each client
Returns immediately without waiting for Hub internal operation, but each client waits for its task to complete and handles errors
func (*Hub[META, HEADER]) ContextIterSAsyncExec ¶
ContextIterSAsyncExec executes Hub internal operation synchronously, but executes async tasks for each client
Waits for Hub internal operation to complete before returning, but does not wait for individual client tasks to finish
func (*Hub[META, HEADER]) ExecAsync ¶
ExecAsync sends work to the main thread of the Hub to ensure that there are no data race conflicts.
func (*Hub[META, HEADER]) ExecSync ¶
ExecSync sends work to the main thread of the Hub to ensure that there are no data race conflicts.
and return error
func (*Hub[META, HEADER]) HubBroadcast ¶
func (*Hub[META, HEADER]) LongPolling ¶
func (hub *Hub[META, HEADER]) LongPolling(option LongPollingOption) error
func (*Hub[META, HEADER]) NewHotline ¶
NewHotline 返回一個IHotline介面 方便書寫的調用
func (*Hub[META, HEADER]) NewHotlineDirect ¶
func (hub *Hub[META, HEADER]) NewHotlineDirect() *hotline[META]
NewHotlineDirect 和 NewHotline 相比 主要差異在於多了 ContextIterSAsyncExec ContextIterAAsyncExec ContextIterASyncExec 三個方法
這三個方法都是用於安全透過跌代器調用
func (*Hub[META, HEADER]) NewHotlineDirectWithOption ¶
func (hub *Hub[META, HEADER]) NewHotlineDirectWithOption(option HotlineOption) *hotline[META]
NewHotlineDirectWithOption NewHotlineDirect 的選項版
func (*Hub[META, HEADER]) NewHotlineSilence ¶
NewHotlineSilence 不會進行任何處理的 IHotline 若
func (*Hub[META, HEADER]) NewHotlineSilenceDirect ¶
func (hub *Hub[META, HEADER]) NewHotlineSilenceDirect() *hotline[META]
func (*Hub[META, HEADER]) NewHotlineWithOption ¶
func (hub *Hub[META, HEADER]) NewHotlineWithOption(option HotlineOption) IHotline
NewHotlineWithOption NewHotline的選項版
func (*Hub[META, HEADER]) SocketHandles ¶
func (hub *Hub[META, HEADER]) SocketHandles(addr, port string, proto ConnectionProtocols)
TODO 還要檢查UDP
func (*Hub[META, HEADER]) WebSocketHandler ¶
func (hub *Hub[META, HEADER]) WebSocketHandler(w http.ResponseWriter, r *http.Request)
WebSocketHandler handles websocket requests from the peer.
func (*Hub[META, HEADER]) WebSocketHandlerWithMeta ¶
func (hub *Hub[META, HEADER]) WebSocketHandlerWithMeta(w http.ResponseWriter, r *http.Request, m META)
like BuildingWebSocketHandles , but can assign meta direct
using this will skip hub.setting.MetaGen()
type HubSetting ¶
type HubSetting[META any, HEADER comparable] struct { // if empty , set uuid HubName string // if nil , will gen to background ContextOption context.Context CancelFunc context.CancelFunc Logger ILogger // when create new client , need to gen a sub into client // must be set , you can use fn()struct{}{return struct{}{}} // if nil , will panic MetaGen func() META // option akaseea.MatcherMap ReceiveMatcher *MatcherMap[META, HEADER] ReceiveMatcherError func(IOContext, META, error) // OnReceiveMessage You can customize the interceptor here // // for example, to prevent continuous command attacks, and when the output is false // // the message will not be processed. OnReceiveMessage func(IOContext, META) bool // when client connection message to server , how to handle the data // in this stage , the payload is nil , do not use // if nil , // default func(IOContext, META) {} OnConnectionStart HandleFunc[META] // OnConnectionClose when connection close // default func(IOContext, META) {} OnConnectionClose HandleFunc[META] // every this struct mark chan size depends on this value // determines the maximum allowable buffer for handling spikes // default 8 ChanQueueSize uint // WebsocketPeriod setting websocket Period // default &WebsocketPeriod{ // PingPeriod: ((60 * time.Second) * 9) / 10, // PongWait: 60 * time.Second, // WriteWait: 10 * time.Second, // WsPongHandler: func(c *websocket.Conn) func(string) error { // return func(string) error { // c.SetReadDeadline(time.Now().Add(60 * time.Second)) // return nil // } // }, // WsWriteTimeOutHandle: func(c *websocket.Conn) { // c.SetWriteDeadline(time.Now().Add(10 * time.Second)) // if err := c.WriteMessage(websocket.PingMessage, nil); err != nil { // set.Logger.Warn(err.Error()) // } // return // }, // } WebsocketPeriod *WebsocketPeriod[META] // SocketPeriod setting socket Period SocketPeriod *SocketPeriod // This content will be executed before the hub is officially launched. DelayedExecution func(IHub) }
type IHotline ¶
type IHotline interface {
GetHotline() HotlineID
// Answer will send any IHotline broadcast to IOContext
Answer(IOContext)
Hangup(IOContext)
// Push does not copy data, so sharing security is not guaranteed.
//
// The current pushCount will be returned when the call is made.
//
// You can then call pushCount to hotline to check whether the previous message has been consumed.
Push(data []byte) uint64
PushCount() uint64
PushSplicing(splicing []byte, data any) (uint64, error)
IsPushConsumed(uint64) bool
MembersNum() int
Members() []IOContext
Logger() ILogger
Close()
CloseIfEmpty() (isCloseAfterCall bool)
IsClosed() bool
Context() context.Context
// contains filtered or unexported methods
}
type IHotlineFrameControl ¶
type IHotlineFrameControl[Obj any] interface { IHotline Pause() Resume() ExecAsync(fn func(hotline IHotlineFrameControl[Obj], obj *Obj)) ExecSync(fn func(hotline IHotlineFrameControl[Obj], obj *Obj) error) error Close() LatencyTime(t time.Duration) time.Duration // 房間若為10Hz 參數為1秒 則回傳1/10秒的time.Duration 通常用於倒計時 OperationTimeout( timeOut time.Duration, timeoutCallback func(hotline IHotlineFrameControl[Obj], obj *Obj)) IOperationCountdown[Obj] OperationTicker( timeOut time.Duration, timeoutCallback func(hotline IHotlineFrameControl[Obj], obj *Obj), pollingInterval time.Duration, tickerCallback func(hotline IHotlineFrameControl[Obj], obj *Obj), ) IOperationCountdownTicker[Obj] }
type ILogger ¶
type ILogger interface {
Debug(format string, a ...any)
Info(format string, a ...any)
Warn(format string, a ...any)
Error(format string, a ...any)
Panic(format string, a ...any)
Fatal(format string, a ...any)
}
func DefaultLogger ¶
func DefaultLogger() ILogger
type IOContext ¶
type IOContext interface {
Payload() []byte
// when message flow to hub handle , Client may be Receive new message
// PayloadHub provide context data , so if use in OnClientReceiveOption()
// you will get last requested data
// PayloadHub() []byte
Logger() ILogger
// Write is Server send message to Client ,
// it will send to chan , is safe
GetContext() context.Context
Write([]byte) uint64
WriteJson(any) (uint64, error)
WriteString(string) uint64
WriteSerialization(any) (uint64, error)
WriteCount() uint64
WriteSplicing(splicing []byte, data any) (uint64, error)
WriteMessageType(int, []byte) uint64
IsWriteConsumed(uint64) bool
Close()
HubBroadcast(data []byte)
Context() context.Context
ConnectionID() ClientID
Hub() IHub
WsConn() *websocket.Conn
Meta() any
ExecAsync(func())
ExecSync(func() error) error
// contains filtered or unexported methods
}
IO as interface omit , diff between Context , is not need [META any]
type IOperationCountdown ¶
type IOperationCountdown[Obj any] interface { IHotlineFrameControl[Obj] Operation(func(hotline IOperationCountdown[Obj], obj *Obj)) Done() }
type IOperationCountdownTicker ¶
type IOperationCountdownTicker[Obj any] interface { IHotlineFrameControl[Obj] Operation(func(hotline IOperationCountdownTicker[Obj], obj *Obj)) Done() }
type IncrementByte ¶
type IncrementByte struct {
Count byte
}
type LongPollingOption ¶
type LongPollingOption struct {
Retry int // if zero , do for timeout
Timeout time.Duration // must
Frequency time.Duration // if zero , set 1 sec
Do func(ihub IHub, done func()) // If shared data operations are involved, hub.exec should be called
TimeoutCallback func(ihub IHub) // Notes are the same as Do
}
type LongPollingResult ¶
type LongPollingResult struct {
}
type MatcherMap ¶
type MatcherMap[META any, HEADER comparable] struct { // HeaderParsingFunc will be use to parsing header and payload from Receive data HeaderParsingFunc func([]byte) (header HEADER, payload []byte) // HandleSetting only check type is "" will be accept // // otherwise will be panic // // example: // func(IOContext, META, any) HandleSetting map[HEADER]any MarshalFunc func(any) ([]byte, error) UnmarshalFunc func([]byte, any) error // contains filtered or unexported fields }
func (*MatcherMap[META, HEADER]) GenSub ¶
func (matcher *MatcherMap[META, HEADER]) GenSub() SubMatcher[META, HEADER]
func (*MatcherMap[META, HEADER]) HeaderParsing ¶
func (matcher *MatcherMap[META, HEADER]) HeaderParsing(ReceiveData []byte) (HEADER, []byte)
func (*MatcherMap[META, HEADER]) Init ¶
func (matcher *MatcherMap[META, HEADER]) Init(logger ILogger)
type OperationCountdown ¶
type OperationCountdown[Obj any] struct { IHotlineFrameControl[Obj] // contains filtered or unexported fields }
OperationCountdown 該功能主要用於為房間建立一個等待輸入選項
func (*OperationCountdown[Obj]) Done ¶
func (o *OperationCountdown[Obj]) Done()
func (*OperationCountdown[Obj]) Operation ¶
func (o *OperationCountdown[Obj]) Operation(operationDo func(hotline IOperationCountdown[Obj], obj *Obj))
type OperationCountdownTicker ¶
type OperationCountdownTicker[Obj any] struct { IHotlineFrameControl[Obj] // contains filtered or unexported fields }
func (*OperationCountdownTicker[Obj]) Done ¶
func (o *OperationCountdownTicker[Obj]) Done()
func (*OperationCountdownTicker[Obj]) Operation ¶
func (o *OperationCountdownTicker[Obj]) Operation(operationDo func(hotline IOperationCountdownTicker[Obj], obj *Obj))
type PingPongPlan ¶
type PingPongPlan[META any] struct { //PingHandler The default situation is that the client initiates a ping to maintain the connection. PingHandler func(ctx IOContext, m META, pingMsg string) error // After how long after pinging, if no ping is received, it will be timed out. PingTimeout time.Duration // PongHandler What to do when you receive a pong PongHandler func(ctx IOContext, m META, pongMsg string) error }
type ReadBufferPreprocessing ¶
type SocketPeriod ¶
type SocketPeriod struct {
// Send pings to peer with this period. Must be less than pongWait.
PingPeriod time.Duration
// PongWait sets the read deadline on the underlying network connection.
// After a read has timed out, the websocket connection state is corrupt and
// all future reads will return an error. A zero value for t means reads will
// not time out.
PongWait time.Duration
// Time allowed to write a message to the peer.
// sets the write deadline on the underlying network.
// connection. After a write has timed out, the websocket state is corrupt and
// all future writes will return an error. A zero value for t means writes will
// not time out.
WriteWait time.Duration
// WsPongHandler sets the handler for pong messages received from the peer.
// The appData argument to h is the PONG message application data. The default
// pong handler does nothing.
//
// The handler function is called from the NextReader, ReadMessage and message
// reader Read methods. The application must read the connection to process
// pong messages as described in the section on Control Messages above.
WsPongHandler func(c *websocket.Conn) func(string) error
// setting when write time out handle
WsWriteTimeOutHandle func(c *websocket.Conn)
// WriteMessageType
// TextMessage messageType = websocket.TextMessage
// BinaryMessage messageType = websocket.BinaryMessage
// CloseMessage messageType = websocket.CloseMessage
// PingMessage messageType = websocket.PingMessage
// PongMessage messageType = websocket.PongMessage
// default TextMessage = 1
WriteMessageType messageType
// MessageBufferSize sets the maximum size in bytes for a message read from the peer. If a
// message exceeds the limit, the connection sends a close message to the peer
// and returns ErrReadLimit to the application.
// default 1KB
MessageBufferSize DataSize
}
type SubMatcher ¶
type SubMatcher[META any, HEADER comparable] struct { // contains filtered or unexported fields }
type WebsocketPeriod ¶
type WebsocketPeriod[META any] struct { // Upgrader // default &websocket.Upgrader{ // HandshakeTimeout: 1, // ReadBufferSize: int(KB * 1), // WriteBufferSize: int(KB * 1), // WriteBufferPool: &sync.Pool{ // New: func() any { // return make([]byte, KB) // }, // }, // Subprotocols: []string{}, // Error: func(w http.ResponseWriter, r *http.Request, status int, reason error) { // }, // CheckOrigin: func(r *http.Request) bool { // return true // }, // EnableCompression: false, // } Upgrader *websocket.Upgrader PingPongPlan PingPongPlan[META] // WriteMessageType // TextMessage messageType = websocket.TextMessage // BinaryMessage messageType = websocket.BinaryMessage // CloseMessage messageType = websocket.CloseMessage // PingMessage messageType = websocket.PingMessage // PongMessage messageType = websocket.PongMessage // default TextMessage = 1 WriteMessageType messageType ExpectedWsError []int // WriteNewline 寫入時的換行符號 WriteNewline []byte // ReadBufferPreprocessing 必須 可用 ReadBufferPreprocessingText ReadBufferPreprocessingBinary 或自定義 ReadBufferPreprocessing ReadBufferPreprocessing }
func DefaultWebsocketPeriod ¶
func DefaultWebsocketPeriod[MEAT any]() *WebsocketPeriod[MEAT]
DefaultWebsocketPeriod 注意ReadBufferPreprocessing 只適用於json等文本類型
Source Files
¶
- buffer_size.go
- client.go
- client_socket.go
- client_websocket.go
- connection_type.go
- context.go
- errors.go
- hotline.go
- hotline_frame.go
- hotline_frame_make.go
- hotline_frame_operation.go
- hotline_frame_operation_ticker.go
- hotline_new.go
- hotline_run.go
- hub.go
- hub_context_merge.go
- hub_frame.go
- hub_id_allotment.go
- hub_long_polling.go
- hub_setting.go
- logger.go
- matcher.go
- matcher_map.go
- matcher_sub.go
- matcher_unit.go
- socket_period.go
- unit.go
- websocket_period.go