Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/broadcast/libs/bufio:all-srcs",
"//app/service/main/broadcast/libs/bytes:all-srcs",
"//app/service/main/broadcast/libs/encoding/binary:all-srcs",
"//app/service/main/broadcast/libs/time:all-srcs",
"//app/service/main/broadcast/libs/websocket:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["bufio.go"],
importpath = "go-common/app/service/main/broadcast/libs/bufio",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_xtest",
srcs = ["bufio_test.go"],
tags = ["automanaged"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,521 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer
// object, creating another object (Reader or Writer) that also implements
// the interface but provides buffering and some help for textual I/O.
package bufio
import (
"bytes"
"errors"
"io"
)
const (
defaultBufSize = 4096
)
var (
// ErrInvalidUnreadByte invalid use of UnreadByete
ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte")
// ErrInvalidUnreadRune invalid use of UnreadRune
ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune")
// ErrBufferFull buffer full
ErrBufferFull = errors.New("bufio: buffer full")
// ErrNegativeCount negative count
ErrNegativeCount = errors.New("bufio: negative count")
)
// Buffered input.
// Reader implements buffering for an io.Reader object.
type Reader struct {
buf []byte
rd io.Reader // reader provided by the client
r, w int // buf read and write positions
err error
}
const minReadBufferSize = 16
const maxConsecutiveEmptyReads = 100
// NewReaderSize returns a new Reader whose buffer has at least the specified
// size. If the argument io.Reader is already a Reader with large enough
// size, it returns the underlying Reader.
func NewReaderSize(rd io.Reader, size int) *Reader {
// Is it already a Reader?
b, ok := rd.(*Reader)
if ok && len(b.buf) >= size {
return b
}
if size < minReadBufferSize {
size = minReadBufferSize
}
r := new(Reader)
r.reset(make([]byte, size), rd)
return r
}
// NewReader returns a new Reader whose buffer has the default size.
func NewReader(rd io.Reader) *Reader {
return NewReaderSize(rd, defaultBufSize)
}
// Reset discards any buffered data, resets all state, and switches
// the buffered reader to read from r.
func (b *Reader) Reset(r io.Reader) {
b.reset(b.buf, r)
}
// ResetBuffer discards any buffered data, resets all state, and switches
// the buffered reader to read from r.
func (b *Reader) ResetBuffer(r io.Reader, buf []byte) {
b.reset(buf, r)
}
func (b *Reader) reset(buf []byte, r io.Reader) {
*b = Reader{
buf: buf,
rd: r,
}
}
var errNegativeRead = errors.New("bufio: reader returned negative count from Read")
// fill reads a new chunk into the buffer.
func (b *Reader) fill() {
// Slide existing data to beginning.
if b.r > 0 {
copy(b.buf, b.buf[b.r:b.w])
b.w -= b.r
b.r = 0
}
if b.w >= len(b.buf) {
panic("bufio: tried to fill full buffer")
}
// Read new data: try a limited number of times.
for i := maxConsecutiveEmptyReads; i > 0; i-- {
n, err := b.rd.Read(b.buf[b.w:])
if n < 0 {
panic(errNegativeRead)
}
b.w += n
if err != nil {
b.err = err
return
}
if n > 0 {
return
}
}
b.err = io.ErrNoProgress
}
func (b *Reader) readErr() error {
err := b.err
b.err = nil
return err
}
// Peek returns the next n bytes without advancing the reader. The bytes stop
// being valid at the next read call. If Peek returns fewer than n bytes, it
// also returns an error explaining why the read is short. The error is
// ErrBufferFull if n is larger than b's buffer size.
func (b *Reader) Peek(n int) ([]byte, error) {
if n < 0 {
return nil, ErrNegativeCount
}
if n > len(b.buf) {
return nil, ErrBufferFull
}
// 0 <= n <= len(b.buf)
for b.w-b.r < n && b.err == nil {
b.fill() // b.w-b.r < len(b.buf) => buffer is not full
}
var err error
if avail := b.w - b.r; avail < n {
// not enough data in buffer
n = avail
err = b.readErr()
if err == nil {
err = ErrBufferFull
}
}
return b.buf[b.r : b.r+n], err
}
// Pop returns the next n bytes with advancing the reader. The bytes stop
// being valid at the next read call. If Pop returns fewer than n bytes, it
// also returns an error explaining why the read is short. The error is
// ErrBufferFull if n is larger than b's buffer size.
func (b *Reader) Pop(n int) ([]byte, error) {
d, err := b.Peek(n)
if err == nil {
b.r += n
return d, err
}
return nil, err
}
// Discard skips the next n bytes, returning the number of bytes discarded.
//
// If Discard skips fewer than n bytes, it also returns an error.
// If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without
// reading from the underlying io.Reader.
func (b *Reader) Discard(n int) (discarded int, err error) {
if n < 0 {
return 0, ErrNegativeCount
}
if n == 0 {
return
}
remain := n
for {
skip := b.Buffered()
if skip == 0 {
b.fill()
skip = b.Buffered()
}
if skip > remain {
skip = remain
}
b.r += skip
remain -= skip
if remain == 0 {
return n, nil
}
if b.err != nil {
return n - remain, b.readErr()
}
}
}
// Read reads data into p.
// It returns the number of bytes read into p.
// It calls Read at most once on the underlying Reader,
// hence n may be less than len(p).
// At EOF, the count will be zero and err will be io.EOF.
func (b *Reader) Read(p []byte) (n int, err error) {
n = len(p)
if n == 0 {
return 0, b.readErr()
}
if b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
if len(p) >= len(b.buf) {
// Large read, empty buffer.
// Read directly into p to avoid copy.
n, b.err = b.rd.Read(p)
if n < 0 {
panic(errNegativeRead)
}
return n, b.readErr()
}
b.fill() // buffer is empty
if b.r == b.w {
return 0, b.readErr()
}
}
// copy as much as we can
n = copy(p, b.buf[b.r:b.w])
b.r += n
return n, nil
}
// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
func (b *Reader) ReadByte() (c byte, err error) {
//b.lastRuneSize = -1
for b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
b.fill() // buffer is empty
}
c = b.buf[b.r]
b.r++
//b.lastByte = int(c)
return c, nil
}
// ReadSlice reads until the first occurrence of delim in the input,
// returning a slice pointing at the bytes in the buffer.
// The bytes stop being valid at the next read.
// If ReadSlice encounters an error before finding a delimiter,
// it returns all the data in the buffer and the error itself (often io.EOF).
// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim.
// Because the data returned from ReadSlice will be overwritten
// by the next I/O operation, most clients should use
// ReadBytes or ReadString instead.
// ReadSlice returns err != nil if and only if line does not end in delim.
func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
for {
// Search buffer.
if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
line = b.buf[b.r : b.r+i+1]
b.r += i + 1
break
}
// Pending error?
if b.err != nil {
line = b.buf[b.r:b.w]
b.r = b.w
err = b.readErr()
break
}
// Buffer full?
if b.Buffered() >= len(b.buf) {
b.r = b.w
line = b.buf
err = ErrBufferFull
break
}
b.fill() // buffer is not full
}
return
}
// ReadLine is a low-level line-reading primitive. Most callers should use
// ReadBytes('\n') or ReadString('\n') instead or use a Scanner.
//
// ReadLine tries to return a single line, not including the end-of-line bytes.
// If the line was too long for the buffer then isPrefix is set and the
// beginning of the line is returned. The rest of the line will be returned
// from future calls. isPrefix will be false when returning the last fragment
// of the line. The returned buffer is only valid until the next call to
// ReadLine. ReadLine either returns a non-nil line or it returns an error,
// never both.
//
// The text returned from ReadLine does not include the line end ("\r\n" or "\n").
// No indication or error is given if the input ends without a final line end.
// Calling UnreadByte after ReadLine will always unread the last byte read
// (possibly a character belonging to the line end) even if that byte is not
// part of the line returned by ReadLine.
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
line, err = b.ReadSlice('\n')
if err == ErrBufferFull {
// Handle the case where "\r\n" straddles the buffer.
if len(line) > 0 && line[len(line)-1] == '\r' {
// Put the '\r' back on buf and drop it from line.
// Let the next call to ReadLine check for "\r\n".
if b.r == 0 {
// should be unreachable
panic("bufio: tried to rewind past start of buffer")
}
b.r--
line = line[:len(line)-1]
}
return line, true, nil
}
if len(line) == 0 {
if err != nil {
line = nil
}
return
}
err = nil
if line[len(line)-1] == '\n' {
drop := 1
if len(line) > 1 && line[len(line)-2] == '\r' {
drop = 2
}
line = line[:len(line)-drop]
}
return
}
// Buffered returns the number of bytes that can be read from the current buffer.
func (b *Reader) Buffered() int { return b.w - b.r }
// buffered output
// Writer implements buffering for an io.Writer object.
// If an error occurs writing to a Writer, no more data will be
// accepted and all subsequent writes will return the error.
// After all data has been written, the client should call the
// Flush method to guarantee all data has been forwarded to
// the underlying io.Writer.
type Writer struct {
err error
buf []byte
n int
wr io.Writer
}
// NewWriterSize returns a new Writer whose buffer has at least the specified
// size. If the argument io.Writer is already a Writer with large enough
// size, it returns the underlying Writer.
func NewWriterSize(w io.Writer, size int) *Writer {
// Is it already a Writer?
b, ok := w.(*Writer)
if ok && len(b.buf) >= size {
return b
}
if size <= 0 {
size = defaultBufSize
}
return &Writer{
buf: make([]byte, size),
wr: w,
}
}
// NewWriter returns a new Writer whose buffer has the default size.
func NewWriter(w io.Writer) *Writer {
return NewWriterSize(w, defaultBufSize)
}
// Reset discards any unflushed buffered data, clears any error, and
// resets b to write its output to w.
func (b *Writer) Reset(w io.Writer) {
b.err = nil
b.n = 0
b.wr = w
}
// ResetBuffer discards any unflushed buffered data, clears any error, and
// resets b to write its output to w.
func (b *Writer) ResetBuffer(w io.Writer, buf []byte) {
b.buf = buf
b.err = nil
b.n = 0
b.wr = w
}
// Flush writes any buffered data to the underlying io.Writer.
func (b *Writer) Flush() error {
err := b.flush()
return err
}
func (b *Writer) flush() error {
if b.err != nil {
return b.err
}
if b.n == 0 {
return nil
}
n, err := b.wr.Write(b.buf[0:b.n])
if n < b.n && err == nil {
err = io.ErrShortWrite
}
if err != nil {
if n > 0 && n < b.n {
copy(b.buf[0:b.n-n], b.buf[n:b.n])
}
b.n -= n
b.err = err
return err
}
b.n = 0
return nil
}
// Available returns how many bytes are unused in the buffer.
func (b *Writer) Available() int { return len(b.buf) - b.n }
// Buffered returns the number of bytes that have been written into the current buffer.
func (b *Writer) Buffered() int { return b.n }
// Write writes the contents of p into the buffer.
// It returns the number of bytes written.
// If nn < len(p), it also returns an error explaining
// why the write is short.
func (b *Writer) Write(p []byte) (nn int, err error) {
for len(p) > b.Available() && b.err == nil {
var n int
if b.Buffered() == 0 {
// Large write, empty buffer.
// Write directly from p to avoid copy.
n, b.err = b.wr.Write(p)
} else {
n = copy(b.buf[b.n:], p)
b.n += n
b.flush()
}
nn += n
p = p[n:]
}
if b.err != nil {
return nn, b.err
}
n := copy(b.buf[b.n:], p)
b.n += n
nn += n
return nn, nil
}
// WriteRaw writes the contents of p into the raw io.Writer without buffer.
// It returns the number of bytes written.
// If nn < len(p), it also returns an error explaining
// why the write is short.
func (b *Writer) WriteRaw(p []byte) (nn int, err error) {
if b.err != nil {
return 0, b.err
}
if b.Buffered() == 0 {
// if no buffer data, write raw writer
nn, err = b.wr.Write(p)
b.err = err
} else {
nn, err = b.Write(p)
}
return
}
// Peek returns the next n bytes with advancing the writer. The bytes stop
// being used at the next write call. If Peek returns fewer than n bytes, it
// also returns an error explaining why the read is short. The error is
// ErrBufferFull if n is larger than b's buffer size.
func (b *Writer) Peek(n int) ([]byte, error) {
if n < 0 {
return nil, ErrNegativeCount
}
if n > len(b.buf) {
return nil, ErrBufferFull
}
for b.Available() < n && b.err == nil {
b.flush()
}
if b.err != nil {
return nil, b.err
}
d := b.buf[b.n : b.n+n]
b.n += n
return d, nil
}
// WriteString writes a string.
// It returns the number of bytes written.
// If the count is less than len(s), it also returns an error explaining
// why the write is short.
func (b *Writer) WriteString(s string) (int, error) {
nn := 0
for len(s) > b.Available() && b.err == nil {
n := copy(b.buf[b.n:], s)
b.n += n
nn += n
s = s[n:]
b.flush()
}
if b.err != nil {
return nn, b.err
}
n := copy(b.buf[b.n:], s)
b.n += n
nn += n
return nn, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["buffer_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"buffer.go",
"writer.go",
],
importpath = "go-common/app/service/main/broadcast/libs/bytes",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,86 @@
package bytes
import (
"sync"
)
// Buffer buffer.
type Buffer struct {
buf []byte
next *Buffer // next free buffer
}
// Bytes bytes.
func (b *Buffer) Bytes() []byte {
return b.buf
}
// Pool is a buffer pool.
type Pool struct {
lock sync.Mutex
free *Buffer
max int
num int
size int
}
// NewPool new a memory buffer pool struct.
func NewPool(num, size int) (p *Pool) {
p = new(Pool)
p.init(num, size)
return
}
// Init init the memory buffer.
func (p *Pool) Init(num, size int) {
p.init(num, size)
}
// init init the memory buffer.
func (p *Pool) init(num, size int) {
p.num = num
p.size = size
p.max = num * size
p.grow()
}
// grow grow the memory buffer size, and update free pointer.
func (p *Pool) grow() {
var (
i int
b *Buffer
bs []Buffer
buf []byte
)
buf = make([]byte, p.max)
bs = make([]Buffer, p.num)
p.free = &bs[0]
b = p.free
for i = 1; i < p.num; i++ {
b.buf = buf[(i-1)*p.size : i*p.size]
b.next = &bs[i]
b = b.next
}
b.buf = buf[(i-1)*p.size : i*p.size]
b.next = nil
}
// Get get a free memory buffer.
func (p *Pool) Get() (b *Buffer) {
p.lock.Lock()
if b = p.free; b == nil {
p.grow()
b = p.free
}
p.free = b.next
p.lock.Unlock()
return
}
// Put put back a memory buffer to free.
func (p *Pool) Put(b *Buffer) {
p.lock.Lock()
b.next = p.free
p.free = b
p.lock.Unlock()
}

View File

@@ -0,0 +1,21 @@
package bytes
import (
"testing"
)
func TestBuffer(t *testing.T) {
p := NewPool(2, 10)
b := p.Get()
if b.Bytes() == nil || len(b.Bytes()) == 0 {
t.FailNow()
}
b = p.Get()
if b.Bytes() == nil || len(b.Bytes()) == 0 {
t.FailNow()
}
b = p.Get()
if b.Bytes() == nil || len(b.Bytes()) == 0 {
t.FailNow()
}
}

View File

@@ -0,0 +1,57 @@
package bytes
// Writer writer.
type Writer struct {
n int
buf []byte
}
// NewWriterSize new a writer with size.
func NewWriterSize(n int) *Writer {
return &Writer{buf: make([]byte, n)}
}
// Len buff len.
func (w *Writer) Len() int {
return w.n
}
// Size buff cap.
func (w *Writer) Size() int {
return len(w.buf)
}
// Reset reset the buff.
func (w *Writer) Reset() {
w.n = 0
}
// Buffer return buff.
func (w *Writer) Buffer() []byte {
return w.buf[:w.n]
}
// Peek peek a buf.
func (w *Writer) Peek(n int) []byte {
var buf []byte
w.grow(n)
buf = w.buf[w.n : w.n+n]
w.n += n
return buf
}
// Write write a buff.
func (w *Writer) Write(p []byte) {
w.grow(len(p))
w.n += copy(w.buf[w.n:], p)
}
func (w *Writer) grow(n int) {
var buf []byte
if w.n+n < len(w.buf) {
return
}
buf = make([]byte, 2*len(w.buf)+n)
copy(buf, w.buf[:w.n])
w.buf = buf
}

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["endian.go"],
importpath = "go-common/app/service/main/broadcast/libs/encoding/binary",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,30 @@
package binary
// BigEndian big endian.
var BigEndian bigEndian
type bigEndian struct{}
func (bigEndian) Int8(b []byte) int8 { return int8(b[0]) }
func (bigEndian) PutInt8(b []byte, v int8) {
b[0] = byte(v)
}
func (bigEndian) Int16(b []byte) int16 { return int16(b[1]) | int16(b[0])<<8 }
func (bigEndian) PutInt16(b []byte, v int16) {
b[0] = byte(v >> 8)
b[1] = byte(v)
}
func (bigEndian) Int32(b []byte) int32 {
return int32(b[3]) | int32(b[2])<<8 | int32(b[1])<<16 | int32(b[0])<<24
}
func (bigEndian) PutInt32(b []byte, v int32) {
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
b[2] = byte(v >> 8)
b[3] = byte(v)
}

View File

@@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["timer_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//library/log:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"debug.go",
"timer.go",
],
importpath = "go-common/app/service/main/broadcast/libs/time",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//library/log:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,6 @@
package time
const (
// Debug debug switch
Debug = false
)

View File

@@ -0,0 +1,268 @@
package time
import (
"sync"
itime "time"
"go-common/library/log"
)
const (
timerFormat = "2006-01-02 15:04:05"
infiniteDuration = itime.Duration(1<<63 - 1)
)
var (
timerLazyDelay = 300 * itime.Millisecond
)
// TimerData timer data.
type TimerData struct {
Key string
expire itime.Time
fn func()
index int
next *TimerData
}
// Delay delay duration.
func (td *TimerData) Delay() itime.Duration {
return td.expire.Sub(itime.Now())
}
// ExpireString expire string.
func (td *TimerData) ExpireString() string {
return td.expire.Format(timerFormat)
}
// Timer timer.
type Timer struct {
lock sync.Mutex
free *TimerData
timers []*TimerData
signal *itime.Timer
num int
}
// NewTimer new a timer.
// A heap must be initialized before any of the heap operations
// can be used. Init is idempotent with respect to the heap invariants
// and may be called whenever the heap invariants may have been invalidated.
// Its complexity is O(n) where n = h.Len().
//
func NewTimer(num int) (t *Timer) {
t = new(Timer)
t.init(num)
return t
}
// Init init the timer.
func (t *Timer) Init(num int) {
t.init(num)
}
func (t *Timer) init(num int) {
t.signal = itime.NewTimer(infiniteDuration)
t.timers = make([]*TimerData, 0, num)
t.num = num
t.grow()
go t.start()
}
func (t *Timer) grow() {
var (
i int
td *TimerData
tds = make([]TimerData, t.num)
)
t.free = &(tds[0])
td = t.free
for i = 1; i < t.num; i++ {
td.next = &(tds[i])
td = td.next
}
td.next = nil
}
// get get a free timer data.
func (t *Timer) get() (td *TimerData) {
if td = t.free; td == nil {
t.grow()
td = t.free
}
t.free = td.next
return
}
// put put back a timer data.
func (t *Timer) put(td *TimerData) {
td.fn = nil
td.next = t.free
t.free = td
}
// Add add the element x onto the heap. The complexity is
// O(log(n)) where n = h.Len().
func (t *Timer) Add(expire itime.Duration, fn func()) (td *TimerData) {
t.lock.Lock()
td = t.get()
td.expire = itime.Now().Add(expire)
td.fn = fn
t.add(td)
t.lock.Unlock()
return
}
// Del removes the element at index i from the heap.
// The complexity is O(log(n)) where n = h.Len().
func (t *Timer) Del(td *TimerData) {
t.lock.Lock()
t.del(td)
t.put(td)
t.lock.Unlock()
}
// Push pushes the element x onto the heap. The complexity is
// O(log(n)) where n = h.Len().
func (t *Timer) add(td *TimerData) {
var d itime.Duration
td.index = len(t.timers)
// add to the minheap last node
t.timers = append(t.timers, td)
t.up(td.index)
if td.index == 0 {
// if first node, signal start goroutine
d = td.Delay()
t.signal.Reset(d)
if Debug {
log.Info("timer: add reset delay %d ms", int64(d)/int64(itime.Millisecond))
}
}
if Debug {
log.Info("timer: push item key: %s, expire: %s, index: %d", td.Key, td.ExpireString(), td.index)
}
}
func (t *Timer) del(td *TimerData) {
var (
i = td.index
last = len(t.timers) - 1
)
if i < 0 || i > last || t.timers[i] != td {
// already remove, usually by expire
if Debug {
log.Info("timer del i: %d, last: %d, %p", i, last, td)
}
return
}
if i != last {
t.swap(i, last)
t.down(i, last)
t.up(i)
}
// remove item is the last node
t.timers[last].index = -1 // for safety
t.timers = t.timers[:last]
if Debug {
log.Info("timer: remove item key: %s, expire: %s, index: %d", td.Key, td.ExpireString(), td.index)
}
}
// Set update timer data.
func (t *Timer) Set(td *TimerData, expire itime.Duration) {
t.lock.Lock()
t.del(td)
td.expire = itime.Now().Add(expire)
t.add(td)
t.lock.Unlock()
}
// start start the timer.
func (t *Timer) start() {
for {
t.expire()
<-t.signal.C
}
}
// expire removes the minimum element (according to Less) from the heap.
// The complexity is O(log(n)) where n = max.
// It is equivalent to Del(0).
func (t *Timer) expire() {
var (
fn func()
td *TimerData
d itime.Duration
)
t.lock.Lock()
for {
if len(t.timers) == 0 {
d = infiniteDuration
if Debug {
log.Info("timer: no other instance")
}
break
}
td = t.timers[0]
if d = td.Delay(); d > 0 {
break
}
fn = td.fn
// let caller put back
t.del(td)
t.lock.Unlock()
if fn == nil {
log.Warn("expire timer no fn")
} else {
if Debug {
log.Info("timer key: %s, expire: %s, index: %d expired, call fn", td.Key, td.ExpireString(), td.index)
}
fn()
}
t.lock.Lock()
}
t.signal.Reset(d)
if Debug {
log.Info("timer: expier reset delay %d ms", int64(d)/int64(itime.Millisecond))
}
t.lock.Unlock()
}
func (t *Timer) up(j int) {
for {
i := (j - 1) / 2 // parent
if i <= j || !t.less(j, i) {
break
}
t.swap(i, j)
j = i
}
}
func (t *Timer) down(i, n int) {
for {
j1 := 2*i + 1
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
break
}
j := j1 // left child
if j2 := j1 + 1; j2 < n && !t.less(j1, j2) {
j = j2 // = 2*i + 2 // right child
}
if !t.less(j, i) {
break
}
t.swap(i, j)
i = j
}
}
func (t *Timer) less(i, j int) bool {
return t.timers[i].expire.Before(t.timers[j].expire)
}
func (t *Timer) swap(i, j int) {
t.timers[i], t.timers[j] = t.timers[j], t.timers[i]
t.timers[i].index = i
t.timers[j].index = j
}

View File

@@ -0,0 +1,43 @@
package time
import (
"testing"
"time"
"go-common/library/log"
)
func TestTimer(t *testing.T) {
timer := NewTimer(100)
tds := make([]*TimerData, 100)
for i := 0; i < 100; i++ {
tds[i] = timer.Add(time.Duration(i)*time.Second+5*time.Minute, nil)
}
printTimer(timer)
for i := 0; i < 100; i++ {
log.Info("td: %s, %s, %d", tds[i].Key, tds[i].ExpireString(), tds[i].index)
timer.Del(tds[i])
}
printTimer(timer)
for i := 0; i < 100; i++ {
tds[i] = timer.Add(time.Duration(i)*time.Second+5*time.Minute, nil)
}
printTimer(timer)
for i := 0; i < 100; i++ {
timer.Del(tds[i])
}
printTimer(timer)
timer.Add(time.Second, nil)
time.Sleep(time.Second * 2)
if len(timer.timers) != 0 {
t.FailNow()
}
}
func printTimer(timer *Timer) {
log.Info("----------timers: %d ----------", len(timer.timers))
for i := 0; i < len(timer.timers); i++ {
log.Info("timer: %s, %s, index: %d", timer.timers[i].Key, timer.timers[i].ExpireString(), timer.timers[i].index)
}
log.Info("--------------------")
}

View File

@@ -0,0 +1,33 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"conn.go",
"request.go",
"server.go",
],
importpath = "go-common/app/service/main/broadcast/libs/websocket",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//app/service/main/broadcast/libs/bufio:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,256 @@
package websocket
import (
"encoding/binary"
"errors"
"fmt"
"io"
"go-common/app/service/main/broadcast/libs/bufio"
)
const (
// Frame header byte 0 bits from Section 5.2 of RFC 6455
finBit = 1 << 7
rsv1Bit = 1 << 6
rsv2Bit = 1 << 5
rsv3Bit = 1 << 4
opBit = 0x0f
// Frame header byte 1 bits from Section 5.2 of RFC 6455
maskBit = 1 << 7
lenBit = 0x7f
continuationFrame = 0
continuationFrameMaxRead = 100
)
// The message types are defined in RFC 6455, section 11.8.
const (
// TextMessage denotes a text data message. The text message payload is
// interpreted as UTF-8 encoded text data.
TextMessage = 1
// BinaryMessage denotes a binary data message.
BinaryMessage = 2
// CloseMessage denotes a close control message. The optional message
// payload contains a numeric code and text. Use the FormatCloseMessage
// function to format a close message payload.
CloseMessage = 8
// PingMessage denotes a ping control message. The optional message payload
// is UTF-8 encoded text.
PingMessage = 9
// PongMessage denotes a ping control message. The optional message payload
// is UTF-8 encoded text.
PongMessage = 10
)
var (
// ErrMessageClose close control message
ErrMessageClose = errors.New("close control message")
// ErrMessageMaxRead continuation frrame max read
ErrMessageMaxRead = errors.New("continuation frame max read")
)
// Conn represents a WebSocket connection.
type Conn struct {
rwc io.ReadWriteCloser
r *bufio.Reader
w *bufio.Writer
}
// new connection
func newConn(rwc io.ReadWriteCloser, r *bufio.Reader, w *bufio.Writer) *Conn {
return &Conn{rwc: rwc, r: r, w: w}
}
// WriteMessage write a message by type.
func (c *Conn) WriteMessage(msgType int, msg []byte) (err error) {
if err = c.WriteHeader(msgType, len(msg)); err != nil {
return
}
err = c.WriteBody(msg)
return
}
// WriteHeader write header frame.
func (c *Conn) WriteHeader(msgType int, length int) (err error) {
var h []byte
if h, err = c.w.Peek(2); err != nil {
return
}
// 1.First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
h[0] = 0
h[0] |= finBit | byte(msgType)
// 2.Second byte. Mask/Payload len(7bits)
h[1] = 0
switch {
case length <= 125:
// 7 bits
h[1] |= byte(length)
case length < 65536:
// 16 bits
h[1] |= 126
if h, err = c.w.Peek(2); err != nil {
return
}
binary.BigEndian.PutUint16(h, uint16(length))
default:
// 64 bits
h[1] |= 127
if h, err = c.w.Peek(8); err != nil {
return
}
binary.BigEndian.PutUint64(h, uint64(length))
}
return
}
// WriteBody write a message body.
func (c *Conn) WriteBody(b []byte) (err error) {
if len(b) > 0 {
_, err = c.w.Write(b)
}
return
}
// Peek write peek.
func (c *Conn) Peek(n int) ([]byte, error) {
return c.w.Peek(n)
}
// Flush flush writer buffer
func (c *Conn) Flush() error {
return c.w.Flush()
}
// ReadMessage read a message.
func (c *Conn) ReadMessage() (op int, payload []byte, err error) {
var (
fin bool
finOp, n int
partPayload []byte
)
for {
// read frame
if fin, op, partPayload, err = c.readFrame(); err != nil {
return
}
switch op {
case BinaryMessage, TextMessage, continuationFrame:
if fin && len(payload) == 0 {
return op, partPayload, nil
}
// continuation frame
payload = append(payload, partPayload...)
if op != continuationFrame {
finOp = op
}
// final frame
if fin {
op = finOp
return
}
case PingMessage:
// handler ping
if err = c.WriteMessage(PongMessage, partPayload); err != nil {
return
}
case PongMessage:
// handler pong
case CloseMessage:
// handler close
err = ErrMessageClose
return
default:
err = fmt.Errorf("unknown control message, fin=%t, op=%d", fin, op)
return
}
if n > continuationFrameMaxRead {
err = ErrMessageMaxRead
return
}
n++
}
}
func (c *Conn) readFrame() (fin bool, op int, payload []byte, err error) {
var (
b byte
p []byte
mask bool
maskKey []byte
payloadLen int64
)
// 1.First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
b, err = c.r.ReadByte()
if err != nil {
return
}
// final frame
fin = (b & finBit) != 0
// rsv MUST be 0
if rsv := b & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 {
return false, 0, nil, fmt.Errorf("unexpected reserved bits rsv1=%d, rsv2=%d, rsv3=%d", b&rsv1Bit, b&rsv2Bit, b&rsv3Bit)
}
// op code
op = int(b & opBit)
// 2.Second byte. Mask/Payload len(7bits)
b, err = c.r.ReadByte()
if err != nil {
return
}
// is mask payload
mask = (b & maskBit) != 0
// payload length
switch b & lenBit {
case 126:
// 16 bits
if p, err = c.r.Pop(2); err != nil {
return
}
payloadLen = int64(binary.BigEndian.Uint16(p))
case 127:
// 64 bits
if p, err = c.r.Pop(8); err != nil {
return
}
payloadLen = int64(binary.BigEndian.Uint64(p))
default:
// 7 bits
payloadLen = int64(b & lenBit)
}
// read mask key
if mask {
maskKey, err = c.r.Pop(4)
if err != nil {
return
}
}
// read payload
if payloadLen > 0 {
if payload, err = c.r.Pop(int(payloadLen)); err != nil {
return
}
if mask {
maskBytes(maskKey, 0, payload)
}
}
return
}
// Close close the connection.
func (c *Conn) Close() error {
return c.rwc.Close()
}
func maskBytes(key []byte, pos int, b []byte) int {
for i := range b {
b[i] ^= key[pos&3]
pos++
}
return pos & 3
}

View File

@@ -0,0 +1,115 @@
package websocket
import (
"bytes"
"fmt"
"net/http"
"strings"
"go-common/app/service/main/broadcast/libs/bufio"
)
// Request request.
type Request struct {
Method string
RequestURI string
Proto string
Host string
Header http.Header
reader *bufio.Reader
}
// ReadRequest reads and parses an incoming request from b.
func ReadRequest(r *bufio.Reader) (req *Request, err error) {
var (
b []byte
ok bool
)
req = &Request{reader: r}
if b, err = req.readLine(); err != nil {
return
}
if req.Method, req.RequestURI, req.Proto, ok = parseRequestLine(string(b)); !ok {
return nil, fmt.Errorf("malformed HTTP request %s", b)
}
if req.Header, err = req.readMIMEHeader(); err != nil {
return
}
req.Host = req.Header.Get("Host")
return req, nil
}
func (r *Request) readLine() ([]byte, error) {
var line []byte
for {
l, more, err := r.reader.ReadLine()
if err != nil {
return nil, err
}
// Avoid the copy if the first call produced a full line.
if line == nil && !more {
return l, nil
}
line = append(line, l...)
if !more {
break
}
}
return line, nil
}
func (r *Request) readMIMEHeader() (header http.Header, err error) {
var (
line []byte
i int
k, v string
)
header = make(http.Header, 16)
for {
if line, err = r.readLine(); err != nil {
return
}
line = trim(line)
if len(line) == 0 {
return
}
if i = bytes.IndexByte(line, ':'); i <= 0 {
err = fmt.Errorf("malformed MIME header line: " + string(line))
return
}
k = string(line[:i])
// Skip initial spaces in value.
i++ // skip colon
for i < len(line) && (line[i] == ' ' || line[i] == '\t') {
i++
}
v = string(line[i:])
header.Add(k, v)
}
}
// parseRequestLine parses "GET /foo HTTP/1.1" into its three parts.
func parseRequestLine(line string) (method, requestURI, proto string, ok bool) {
s1 := strings.Index(line, " ")
s2 := strings.Index(line[s1+1:], " ")
if s1 < 0 || s2 < 0 {
return
}
s2 += s1 + 1
return line[:s1], line[s1+1 : s2], line[s2+1:], true
}
// trim returns s with leading and trailing spaces and tabs removed.
// It does not assume Unicode or UTF-8.
func trim(s []byte) []byte {
i := 0
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
i++
}
n := len(s)
for n > i && (s[n-1] == ' ' || s[n-1] == '\t') {
n--
}
return s[i:n]
}

View File

@@ -0,0 +1,56 @@
package websocket
import (
"crypto/sha1"
"encoding/base64"
"errors"
"io"
"strings"
"go-common/app/service/main/broadcast/libs/bufio"
)
var (
keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
// ErrBadRequestMethod bad request method
ErrBadRequestMethod = errors.New("bad method")
// ErrNotWebSocket not websocket protocal
ErrNotWebSocket = errors.New("not websocket protocol")
// ErrBadWebSocketVersion bad websocket version
ErrBadWebSocketVersion = errors.New("missing or bad WebSocket Version")
// ErrChallengeResponse mismatch challenge response
ErrChallengeResponse = errors.New("mismatch challenge/response")
)
// Upgrade Switching Protocols
func Upgrade(rwc io.ReadWriteCloser, rr *bufio.Reader, wr *bufio.Writer, req *Request) (conn *Conn, err error) {
if req.Method != "GET" {
return nil, ErrBadRequestMethod
}
if req.Header.Get("Sec-Websocket-Version") != "13" {
return nil, ErrBadWebSocketVersion
}
if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" {
return nil, ErrNotWebSocket
}
if !strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
return nil, ErrNotWebSocket
}
challengeKey := req.Header.Get("Sec-Websocket-Key")
if challengeKey == "" {
return nil, ErrChallengeResponse
}
wr.WriteString("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n")
wr.WriteString("Sec-WebSocket-Accept: " + computeAcceptKey(challengeKey) + "\r\n\r\n")
if err = wr.Flush(); err != nil {
return
}
return newConn(rwc, rr, wr), nil
}
func computeAcceptKey(challengeKey string) string {
h := sha1.New()
h.Write([]byte(challengeKey))
h.Write(keyGUID)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}