init
This commit is contained in:
commit
08382b2f65
158
circlebuffer.go
Normal file
158
circlebuffer.go
Normal file
@ -0,0 +1,158 @@
|
||||
package starnet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CircleByteBuffer struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
io.Closer
|
||||
datas []byte
|
||||
|
||||
start int
|
||||
end int
|
||||
size int
|
||||
isClose bool
|
||||
isEnd bool
|
||||
}
|
||||
|
||||
func NewCircleByteBuffer(len int) *CircleByteBuffer {
|
||||
var e = new(CircleByteBuffer)
|
||||
e.datas = make([]byte, len)
|
||||
e.start = 0
|
||||
e.end = 0
|
||||
e.size = len
|
||||
e.isClose = false
|
||||
e.isEnd = false
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *CircleByteBuffer) getLen() int {
|
||||
if e.start == e.end {
|
||||
return 0
|
||||
} else if e.start < e.end {
|
||||
return e.end - e.start
|
||||
} else {
|
||||
return e.start - e.end
|
||||
}
|
||||
}
|
||||
func (e *CircleByteBuffer) getFree() int {
|
||||
return e.size - e.getLen()
|
||||
}
|
||||
func (e *CircleByteBuffer) putByte(b byte) error {
|
||||
if e.isClose {
|
||||
return io.EOF
|
||||
}
|
||||
e.datas[e.end] = b
|
||||
var pos = e.end + 1
|
||||
for pos == e.start {
|
||||
if e.isClose {
|
||||
return io.EOF
|
||||
}
|
||||
time.Sleep(time.Microsecond)
|
||||
}
|
||||
if pos == e.size {
|
||||
e.end = 0
|
||||
} else {
|
||||
e.end = pos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *CircleByteBuffer) getByte() (byte, error) {
|
||||
if e.isClose {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if e.isEnd && e.getLen() <= 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if e.getLen() <= 0 {
|
||||
return 0, errors.New("no datas")
|
||||
}
|
||||
var ret = e.datas[e.start]
|
||||
e.start++
|
||||
if e.start == e.size {
|
||||
e.start = 0
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
func (e *CircleByteBuffer) geti(i int) byte {
|
||||
if i >= e.getLen() {
|
||||
panic("out buffer")
|
||||
}
|
||||
var pos = e.start + i
|
||||
if pos >= e.size {
|
||||
pos -= e.size
|
||||
}
|
||||
return e.datas[pos]
|
||||
}
|
||||
|
||||
/*func (e*CircleByteBuffer)puts(bts []byte){
|
||||
for i:=0;i<len(bts);i++{
|
||||
e.put(bts[i])
|
||||
}
|
||||
}
|
||||
func (e*CircleByteBuffer)gets(bts []byte)int{
|
||||
if bts==nil {return 0}
|
||||
var ret=0
|
||||
for i:=0;i<len(bts);i++{
|
||||
if e.getLen()<=0{break}
|
||||
bts[i]=e.get()
|
||||
ret++
|
||||
}
|
||||
return ret
|
||||
}*/
|
||||
func (e *CircleByteBuffer) Close() error {
|
||||
e.isClose = true
|
||||
return nil
|
||||
}
|
||||
func (e *CircleByteBuffer) Read(bts []byte) (int, error) {
|
||||
if e.isClose {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if bts == nil {
|
||||
return 0, errors.New("bts is nil")
|
||||
}
|
||||
var ret = 0
|
||||
for i := 0; i < len(bts); i++ {
|
||||
b, err := e.getByte()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return ret, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
bts[i] = b
|
||||
ret++
|
||||
}
|
||||
if e.isClose {
|
||||
return ret, io.EOF
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
func (e *CircleByteBuffer) Write(bts []byte) (int, error) {
|
||||
if e.isClose {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if bts == nil {
|
||||
e.isEnd = true
|
||||
return 0, io.EOF
|
||||
}
|
||||
var ret = 0
|
||||
for i := 0; i < len(bts); i++ {
|
||||
err := e.putByte(bts[i])
|
||||
if err != nil {
|
||||
fmt.Println("Write bts err:", err)
|
||||
return ret, err
|
||||
}
|
||||
ret++
|
||||
}
|
||||
if e.isClose {
|
||||
return ret, io.EOF
|
||||
}
|
||||
return ret, nil
|
||||
}
|
125
curl.go
Normal file
125
curl.go
Normal file
@ -0,0 +1,125 @@
|
||||
package starnet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
TimeOut int
|
||||
DialTimeOut int
|
||||
Url string
|
||||
Method string
|
||||
RecvData []byte
|
||||
WriteRecvData bool
|
||||
RecvIo io.Writer
|
||||
ReqHeader http.Header
|
||||
ReqCookies []*http.Cookie
|
||||
RespHeader http.Header
|
||||
RespCookies []*http.Cookie
|
||||
RespHttpCode int
|
||||
PostBuffer *bytes.Buffer
|
||||
CircleBuffer *CircleByteBuffer
|
||||
Proxy string
|
||||
}
|
||||
|
||||
func NewRequests(url string, postdata []byte, method string) Request {
|
||||
return Request{
|
||||
TimeOut: 30,
|
||||
DialTimeOut: 15,
|
||||
Url: url,
|
||||
PostBuffer: bytes.NewBuffer(postdata),
|
||||
Method: method,
|
||||
}
|
||||
}
|
||||
|
||||
func (curl *Request) ResetReqHeader() {
|
||||
curl.ReqHeader = make(http.Header)
|
||||
}
|
||||
|
||||
func (curl *Request) ResetReqCookies() {
|
||||
curl.ReqCookies = []*http.Cookie{}
|
||||
}
|
||||
|
||||
func (curl *Request) AddSimpleCookie(key, value string) {
|
||||
curl.ReqCookies = append(curl.ReqCookies, &http.Cookie{Name: key, Value: value, Path: "/"})
|
||||
}
|
||||
|
||||
func randomBoundary() string {
|
||||
var buf [30]byte
|
||||
_, err := io.ReadFull(rand.Reader, buf[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fmt.Sprintf("%x", buf[:])
|
||||
}
|
||||
|
||||
func Curl(curl Request) (resps Request, err error) {
|
||||
var req *http.Request
|
||||
if curl.Method == "" {
|
||||
return Request{}, errors.New("Error Method Not Entered")
|
||||
}
|
||||
if curl.PostBuffer != nil {
|
||||
req, err = http.NewRequest(curl.Method, curl.Url, curl.PostBuffer)
|
||||
} else {
|
||||
req, err = http.NewRequest(curl.Method, curl.Url, curl.CircleBuffer)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header = curl.ReqHeader
|
||||
if len(curl.ReqCookies) != 0 {
|
||||
for _, v := range curl.ReqCookies {
|
||||
req.AddCookie(v)
|
||||
}
|
||||
}
|
||||
transport := &http.Transport{
|
||||
Dial: func(netw, addr string) (net.Conn, error) {
|
||||
deadline := time.Now().Add(time.Duration(curl.TimeOut) * time.Second)
|
||||
c, err := net.DialTimeout(netw, addr, time.Second*time.Duration(curl.DialTimeOut))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if curl.TimeOut != 0 {
|
||||
c.SetDeadline(deadline)
|
||||
}
|
||||
return c, nil
|
||||
},
|
||||
}
|
||||
if curl.Proxy != "" {
|
||||
purl, _ := url.Parse(curl.Proxy)
|
||||
transport.Proxy = http.ProxyURL(purl)
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
curl.PostBuffer = nil
|
||||
curl.CircleBuffer = nil
|
||||
curl.RespHttpCode = resp.StatusCode
|
||||
curl.RespHeader = resp.Header
|
||||
curl.RespCookies = resp.Cookies()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if curl.WriteRecvData {
|
||||
curl.RecvData = body
|
||||
}
|
||||
if curl.RecvIo != nil {
|
||||
_, err = curl.RecvIo.Write(body)
|
||||
}
|
||||
return curl, err
|
||||
}
|
338
http.go
Normal file
338
http.go
Normal file
@ -0,0 +1,338 @@
|
||||
package starnet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http"
|
||||
urls "net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StarCurl struct {
|
||||
TimeOut int
|
||||
DialTimeOut int
|
||||
ReqHeader http.Header
|
||||
ReqCookies []*http.Cookie
|
||||
RespHeader http.Header
|
||||
RespCookies []*http.Cookie
|
||||
RespHttpCode int
|
||||
PostBuffer *bytes.Buffer
|
||||
CircleBuffer *CircleByteBuffer
|
||||
Proxy string
|
||||
}
|
||||
|
||||
func NewStarCurl() *StarCurl {
|
||||
star := new(StarCurl)
|
||||
star.ReqHeader = make(http.Header)
|
||||
star.TimeOut = 60
|
||||
star.DialTimeOut = 15
|
||||
star.PostBuffer = nil
|
||||
return star
|
||||
}
|
||||
|
||||
func (this *StarCurl) ResetReqHeader() {
|
||||
this.ReqHeader = make(http.Header)
|
||||
}
|
||||
|
||||
func (this *StarCurl) ResetReqCookies() {
|
||||
this.ReqCookies = []*http.Cookie{}
|
||||
}
|
||||
|
||||
func (this *StarCurl) AddSimpleCookie(key, value string) {
|
||||
this.ReqCookies = append(this.ReqCookies, &http.Cookie{Name: key, Value: value, Path: "/"})
|
||||
}
|
||||
|
||||
func (this *StarCurl) CurlWithFile(url string, postdata map[string]string, formname, fpath, savepath string, tofile bool, shell func(float64)) (result []byte, err error) {
|
||||
fpsrc, err := os.Open(fpath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fpsrc.Close()
|
||||
boundary := randomBoundary()
|
||||
boundarybytes := []byte("\r\n--" + boundary + "\r\n")
|
||||
endbytes := []byte("\r\n--" + boundary + "--\r\n")
|
||||
fpstat, _ := os.Stat(fpath)
|
||||
filebig := float64(fpstat.Size())
|
||||
sum, n := 0, 0
|
||||
fpdst := NewCircleByteBuffer(1048576)
|
||||
if postdata != nil {
|
||||
for k, v := range postdata {
|
||||
header := fmt.Sprintf("Content-Disposition: form-data; name=\"%s\";\r\nContent-Type: x-www-form-urlencoded \r\n\r\n", k)
|
||||
fpdst.Write(boundarybytes)
|
||||
fpdst.Write([]byte(header))
|
||||
fpdst.Write([]byte(v))
|
||||
}
|
||||
}
|
||||
header := fmt.Sprintf("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: application/octet-stream\r\n\r\n", formname, fpstat.Name())
|
||||
fpdst.Write(boundarybytes)
|
||||
fpdst.Write([]byte(header))
|
||||
go func() {
|
||||
for {
|
||||
bufs := make([]byte, 393213)
|
||||
n, err = fpsrc.Read(bufs)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
if n != 0 {
|
||||
fpdst.Write(bufs[0:n])
|
||||
go shell(float64(sum+n) / filebig * 100)
|
||||
}
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
sum += n
|
||||
go shell(float64(sum) / filebig * 100)
|
||||
fpdst.Write(bufs[0:n])
|
||||
}
|
||||
fpdst.Write(endbytes)
|
||||
fpdst.Write(nil)
|
||||
}()
|
||||
this.CircleBuffer = fpdst
|
||||
this.ReqHeader.Set("Content-Type", "multipart/form-data;boundary="+boundary)
|
||||
if tofile {
|
||||
err = this.CurlDataToFile(url, []byte{}, "POST", savepath, shell)
|
||||
this.ResetReqHeader()
|
||||
} else {
|
||||
result, err = this.Curl(url, []byte{}, "POST")
|
||||
}
|
||||
this.ResetReqHeader()
|
||||
return
|
||||
}
|
||||
|
||||
func (this *StarCurl) CurlWithFileByBytes(url string, postdata map[string]string, formname, fname string, data []byte, savepath string, tofile bool) (result []byte, err error) {
|
||||
buf := &bytes.Buffer{}
|
||||
bufwriter := multipart.NewWriter(buf)
|
||||
if postdata != nil {
|
||||
for k, v := range postdata {
|
||||
bufwriter.WriteField(k, v)
|
||||
}
|
||||
}
|
||||
fpdst, err := bufwriter.CreateFormFile(formname, fname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fpdst.Write(data)
|
||||
this.PostBuffer = buf
|
||||
this.ReqHeader.Set("Content-Type", "multipart/form-data;boundary="+bufwriter.Boundary())
|
||||
bufwriter.Close()
|
||||
if tofile {
|
||||
err = this.CurlDataToFile(url, []byte{}, "POST", savepath, func(float64) {})
|
||||
this.ResetReqHeader()
|
||||
} else {
|
||||
result, err = this.Curl(url, []byte{}, "POST")
|
||||
}
|
||||
this.ResetReqHeader()
|
||||
return
|
||||
}
|
||||
|
||||
func (this *StarCurl) CurlWithFileByMemory(url string, postdata map[string]string, formname, fpath, savepath string, tofile bool, shell func(float64)) (result []byte, err error) {
|
||||
buf := &bytes.Buffer{}
|
||||
bufwriter := multipart.NewWriter(buf)
|
||||
if postdata != nil {
|
||||
for k, v := range postdata {
|
||||
bufwriter.WriteField(k, v)
|
||||
}
|
||||
}
|
||||
fpdst, err := bufwriter.CreateFormFile(formname, filepath.Base(fpath))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fpsrc, err := os.Open(fpath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fpsrc.Close()
|
||||
fpstat, _ := os.Stat(fpath)
|
||||
filebig := float64(fpstat.Size())
|
||||
sum, n := 0, 0
|
||||
for {
|
||||
bufs := make([]byte, 393213)
|
||||
n, err = fpsrc.Read(bufs)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
if n != 0 {
|
||||
fpdst.Write(bufs[0:n])
|
||||
go shell(float64(sum+n) / filebig * 100)
|
||||
}
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
sum += n
|
||||
go shell(float64(sum) / filebig * 100)
|
||||
fpdst.Write(bufs[0:n])
|
||||
}
|
||||
|
||||
this.PostBuffer = buf
|
||||
this.ReqHeader.Set("Content-Type", "multipart/form-data;boundary="+bufwriter.Boundary())
|
||||
bufwriter.Close()
|
||||
if tofile {
|
||||
err = this.CurlDataToFile(url, []byte{}, "POST", savepath, shell)
|
||||
this.ResetReqHeader()
|
||||
} else {
|
||||
result, err = this.Curl(url, []byte{}, "POST")
|
||||
}
|
||||
this.ResetReqHeader()
|
||||
return
|
||||
}
|
||||
|
||||
func (this *StarCurl) CurlDataToFile(url string, postdata []byte, method, fpath string, shell func(float64)) (err error) {
|
||||
var req *http.Request
|
||||
if method == "" {
|
||||
if len(postdata) != 0 {
|
||||
method = "POST"
|
||||
} else {
|
||||
method = "GET"
|
||||
}
|
||||
}
|
||||
if len(postdata) == 0 && this.PostBuffer == nil && this.CircleBuffer == nil {
|
||||
req, err = http.NewRequest(method, url, nil)
|
||||
} else if len(postdata) != 0 {
|
||||
req, err = http.NewRequest(method, url, bytes.NewBuffer(postdata))
|
||||
} else if this.PostBuffer != nil {
|
||||
req, err = http.NewRequest(method, url, this.PostBuffer)
|
||||
} else {
|
||||
req, err = http.NewRequest(method, url, this.CircleBuffer)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if (this.ReqHeader == nil) && method == "POST" {
|
||||
this.ReqHeader.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
req.Header = this.ReqHeader
|
||||
if len(this.ReqCookies) != 0 {
|
||||
for _, v := range this.ReqCookies {
|
||||
req.AddCookie(v)
|
||||
}
|
||||
}
|
||||
transport := &http.Transport{
|
||||
Dial: func(netw, addr string) (net.Conn, error) {
|
||||
deadline := time.Now().Add(time.Duration(this.TimeOut) * time.Second)
|
||||
c, err := net.DialTimeout(netw, addr, time.Second*time.Duration(this.DialTimeOut))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if this.TimeOut != 0 {
|
||||
c.SetDeadline(deadline)
|
||||
}
|
||||
return c, nil
|
||||
},
|
||||
}
|
||||
if this.Proxy != "" {
|
||||
purl, _ := urls.Parse(this.Proxy)
|
||||
transport.Proxy = http.ProxyURL(purl)
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
this.PostBuffer = nil
|
||||
this.CircleBuffer = nil
|
||||
this.RespHttpCode = resp.StatusCode
|
||||
this.RespHeader = resp.Header
|
||||
this.RespCookies = resp.Cookies()
|
||||
fpsrc, err := os.Create(fpath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fpsrc.Close()
|
||||
filebig := float64(resp.ContentLength)
|
||||
if filebig <= 0 {
|
||||
filebig = 100
|
||||
}
|
||||
var n, sum int = 0, 0
|
||||
for {
|
||||
buf := make([]byte, 393213)
|
||||
n, err = resp.Body.Read(buf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
if n != 0 {
|
||||
fpsrc.Write(buf[0:n])
|
||||
}
|
||||
go shell(100.00)
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
sum += n
|
||||
go shell(float64(sum) / filebig * 100.00)
|
||||
fpsrc.Write(buf[0:n])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (this *StarCurl) Curl(url string, postdata []byte, method string) (body []byte, err error) {
|
||||
var req *http.Request
|
||||
if method == "" {
|
||||
if len(postdata) != 0 {
|
||||
method = "POST"
|
||||
} else {
|
||||
method = "GET"
|
||||
}
|
||||
}
|
||||
if len(postdata) == 0 && this.PostBuffer == nil && this.CircleBuffer == nil {
|
||||
req, err = http.NewRequest(method, url, nil)
|
||||
} else if len(postdata) != 0 {
|
||||
req, err = http.NewRequest(method, url, bytes.NewBuffer(postdata))
|
||||
} else if this.PostBuffer != nil {
|
||||
req, err = http.NewRequest(method, url, this.PostBuffer)
|
||||
} else {
|
||||
req, err = http.NewRequest(method, url, this.CircleBuffer)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if (this.ReqHeader == nil) && method == "POST" {
|
||||
this.ReqHeader.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
req.Header = this.ReqHeader
|
||||
if len(this.ReqCookies) != 0 {
|
||||
for _, v := range this.ReqCookies {
|
||||
req.AddCookie(v)
|
||||
}
|
||||
}
|
||||
transport := &http.Transport{
|
||||
Dial: func(netw, addr string) (net.Conn, error) {
|
||||
deadline := time.Now().Add(time.Duration(this.TimeOut) * time.Second)
|
||||
c, err := net.DialTimeout(netw, addr, time.Second*time.Duration(this.DialTimeOut))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if this.TimeOut != 0 {
|
||||
c.SetDeadline(deadline)
|
||||
}
|
||||
return c, nil
|
||||
},
|
||||
}
|
||||
if this.Proxy != "" {
|
||||
purl, _ := urls.Parse(this.Proxy)
|
||||
transport.Proxy = http.ProxyURL(purl)
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
this.PostBuffer = nil
|
||||
this.CircleBuffer = nil
|
||||
this.RespHttpCode = resp.StatusCode
|
||||
this.RespHeader = resp.Header
|
||||
this.RespCookies = resp.Cookies()
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
return
|
||||
}
|
291
que.go
Normal file
291
que.go
Normal file
@ -0,0 +1,291 @@
|
||||
package starnet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 识别头
|
||||
var header = []byte{11, 27, 19, 96, 12, 25, 02, 20}
|
||||
|
||||
// MsgQueue 为基本的信息单位
|
||||
type MsgQueue struct {
|
||||
ID uint16
|
||||
Msg []byte
|
||||
Conn interface{}
|
||||
}
|
||||
|
||||
// StarQueue 为流数据中的消息队列分发
|
||||
type StarQueue struct {
|
||||
Encode bool
|
||||
Reserve uint16
|
||||
Msgid uint16
|
||||
MsgPool []MsgQueue
|
||||
UnFinMsg sync.Map
|
||||
LastID int //= -1
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
duration time.Duration
|
||||
EncodeFunc func([]byte) []byte
|
||||
DecodeFunc func([]byte) []byte
|
||||
}
|
||||
|
||||
// NewQueue 建立一个新消息队列
|
||||
func NewQueue() *StarQueue {
|
||||
var que StarQueue
|
||||
que.Encode = false
|
||||
que.ctx, que.cancel = context.WithCancel(context.Background())
|
||||
que.duration = 0
|
||||
return &que
|
||||
}
|
||||
|
||||
// Uint32ToByte 4位uint32转byte
|
||||
func Uint32ToByte(src uint32) []byte {
|
||||
res := make([]byte, 4)
|
||||
res[3] = uint8(src)
|
||||
res[2] = uint8(src >> 8)
|
||||
res[1] = uint8(src >> 16)
|
||||
res[0] = uint8(src >> 24)
|
||||
return res
|
||||
}
|
||||
|
||||
// ByteToUint32 byte转4位uint32
|
||||
func ByteToUint32(src []byte) uint32 {
|
||||
var res uint32
|
||||
buffer := bytes.NewBuffer(src)
|
||||
binary.Read(buffer, binary.BigEndian, &res)
|
||||
return res
|
||||
}
|
||||
|
||||
// Uint16ToByte 2位uint16转byte
|
||||
func Uint16ToByte(src uint16) []byte {
|
||||
res := make([]byte, 2)
|
||||
res[1] = uint8(src)
|
||||
res[0] = uint8(src >> 8)
|
||||
return res
|
||||
}
|
||||
|
||||
// ByteToUint16 用于byte转uint16
|
||||
func ByteToUint16(src []byte) uint16 {
|
||||
var res uint16
|
||||
buffer := bytes.NewBuffer(src)
|
||||
binary.Read(buffer, binary.BigEndian, &res)
|
||||
return res
|
||||
}
|
||||
|
||||
// BuildMessage 生成编码后的信息用于发送
|
||||
func (que *StarQueue) BuildMessage(src []byte) []byte {
|
||||
var buff bytes.Buffer
|
||||
que.Msgid++
|
||||
if que.Encode {
|
||||
src = que.EncodeFunc(src)
|
||||
}
|
||||
length := uint32(len(src))
|
||||
buff.Write(header)
|
||||
buff.Write(Uint32ToByte(length))
|
||||
buff.Write(Uint16ToByte(que.Msgid))
|
||||
buff.Write(src)
|
||||
return buff.Bytes()
|
||||
}
|
||||
|
||||
// BuildHeader 生成编码后的Header用于发送
|
||||
func (que *StarQueue) BuildHeader(length uint32) []byte {
|
||||
var buff bytes.Buffer
|
||||
que.Msgid++
|
||||
buff.Write(header)
|
||||
buff.Write(Uint32ToByte(length))
|
||||
buff.Write(Uint16ToByte(que.Msgid))
|
||||
return buff.Bytes()
|
||||
}
|
||||
|
||||
type unFinMsg struct {
|
||||
ID uint16
|
||||
LengthRecv uint32
|
||||
// HeaderMsg 信息头,应当为14位:8位识别码+4位长度码+2位id
|
||||
HeaderMsg []byte
|
||||
RecvMsg []byte
|
||||
}
|
||||
|
||||
// ParseMessage 用于解析收到的msg信息
|
||||
func (que *StarQueue) ParseMessage(msg []byte, conn interface{}) error {
|
||||
tmp, ok := que.UnFinMsg.Load(conn)
|
||||
if ok { //存在未完成的信息
|
||||
lastMsg := tmp.(*unFinMsg)
|
||||
headerLen := len(lastMsg.HeaderMsg)
|
||||
if headerLen < 14 { //未完成头标题
|
||||
//传输的数据不能填充header头
|
||||
if len(msg) < 14-headerLen {
|
||||
//加入header头并退出
|
||||
lastMsg.HeaderMsg = bytesMerge(lastMsg.HeaderMsg, msg)
|
||||
que.UnFinMsg.Store(conn, lastMsg)
|
||||
return nil
|
||||
}
|
||||
//获取14字节完整的header
|
||||
header := msg[0 : 14-headerLen]
|
||||
lastMsg.HeaderMsg = bytesMerge(lastMsg.HeaderMsg, header)
|
||||
//检查收到的header是否为认证header
|
||||
//若不是,丢弃并重新来过
|
||||
if !checkHeader(lastMsg.HeaderMsg[0:8]) {
|
||||
que.UnFinMsg.Delete(conn)
|
||||
if len(msg) == 0 {
|
||||
return nil
|
||||
}
|
||||
return que.ParseMessage(msg, conn)
|
||||
}
|
||||
//获得本数据包长度
|
||||
lastMsg.LengthRecv = ByteToUint32(lastMsg.HeaderMsg[8:12])
|
||||
//获得本数据包ID
|
||||
lastMsg.ID = ByteToUint16(lastMsg.HeaderMsg[12:14])
|
||||
//存入列表
|
||||
que.UnFinMsg.Store(conn, lastMsg)
|
||||
msg = msg[14-headerLen:]
|
||||
if uint32(len(msg)) < lastMsg.LengthRecv {
|
||||
lastMsg.RecvMsg = msg
|
||||
que.UnFinMsg.Store(conn, lastMsg)
|
||||
return nil
|
||||
}
|
||||
if uint32(len(msg)) >= lastMsg.LengthRecv {
|
||||
lastMsg.RecvMsg = msg[0:lastMsg.LengthRecv]
|
||||
if que.Encode {
|
||||
lastMsg.RecvMsg = que.DecodeFunc(lastMsg.RecvMsg)
|
||||
}
|
||||
msg = msg[lastMsg.LengthRecv:]
|
||||
stroeMsg := MsgQueue{
|
||||
ID: lastMsg.ID,
|
||||
Msg: lastMsg.RecvMsg,
|
||||
Conn: conn,
|
||||
}
|
||||
que.MsgPool = append(que.MsgPool, stroeMsg)
|
||||
que.UnFinMsg.Delete(conn)
|
||||
return que.ParseMessage(msg, conn)
|
||||
}
|
||||
} else {
|
||||
lastID := int(lastMsg.LengthRecv) - len(lastMsg.RecvMsg)
|
||||
if lastID < 0 {
|
||||
que.UnFinMsg.Delete(conn)
|
||||
return que.ParseMessage(msg, conn)
|
||||
}
|
||||
if len(msg) >= lastID {
|
||||
lastMsg.RecvMsg = bytesMerge(lastMsg.RecvMsg, msg[0:lastID])
|
||||
if que.Encode {
|
||||
lastMsg.RecvMsg = que.DecodeFunc(lastMsg.RecvMsg)
|
||||
}
|
||||
stroeMsg := MsgQueue{
|
||||
ID: lastMsg.ID,
|
||||
Msg: lastMsg.RecvMsg,
|
||||
Conn: conn,
|
||||
}
|
||||
que.MsgPool = append(que.MsgPool, stroeMsg)
|
||||
que.UnFinMsg.Delete(conn)
|
||||
if len(msg) == lastID {
|
||||
return nil
|
||||
}
|
||||
msg = msg[lastID:]
|
||||
return que.ParseMessage(msg, conn)
|
||||
}
|
||||
lastMsg.RecvMsg = bytesMerge(lastMsg.RecvMsg, msg)
|
||||
que.UnFinMsg.Store(conn, lastMsg)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(msg) == 0 {
|
||||
return nil
|
||||
}
|
||||
var start int
|
||||
if start = searchHeader(msg); start == -1 {
|
||||
return errors.New("data format error")
|
||||
}
|
||||
msg = msg[start:]
|
||||
lastMsg := unFinMsg{}
|
||||
que.UnFinMsg.Store(conn, &lastMsg)
|
||||
return que.ParseMessage(msg, conn)
|
||||
}
|
||||
|
||||
func checkHeader(msg []byte) bool {
|
||||
if len(msg) != 8 {
|
||||
return false
|
||||
}
|
||||
for k, v := range msg {
|
||||
if v != header[k] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func searchHeader(msg []byte) int {
|
||||
if len(msg) < 8 {
|
||||
return 0
|
||||
}
|
||||
for k, v := range msg {
|
||||
find := 0
|
||||
if v == header[0] {
|
||||
for k2, v2 := range header {
|
||||
if msg[k+k2] == v2 {
|
||||
find++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if find == 8 {
|
||||
return k
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func bytesMerge(src ...[]byte) []byte {
|
||||
var buff bytes.Buffer
|
||||
for _, v := range src {
|
||||
buff.Write(v)
|
||||
}
|
||||
return buff.Bytes()
|
||||
}
|
||||
|
||||
// Restore 获取收到的信息
|
||||
func (que *StarQueue) Restore(n int) ([]MsgQueue, error) {
|
||||
var res []MsgQueue
|
||||
dura := time.Duration(0)
|
||||
for len(que.MsgPool) < n {
|
||||
select {
|
||||
case <-que.ctx.Done():
|
||||
return res, errors.New("Stoped By External Function Call")
|
||||
default:
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
dura = time.Millisecond*20 + dura
|
||||
if que.duration != 0 && dura > que.duration {
|
||||
return res, errors.New("Time Exceed")
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(que.MsgPool) < n {
|
||||
return res, errors.New("Result Not Enough")
|
||||
}
|
||||
res = que.MsgPool[0:n]
|
||||
que.MsgPool = que.MsgPool[n:]
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// RestoreOne 获取收到的一个信息
|
||||
func (que *StarQueue) RestoreOne() (MsgQueue, error) {
|
||||
data, err := que.Restore(1)
|
||||
if len(data) == 1 {
|
||||
return data[0], err
|
||||
}
|
||||
return MsgQueue{}, err
|
||||
}
|
||||
|
||||
// Stop 立即停止Restore
|
||||
func (que *StarQueue) Stop() {
|
||||
que.cancel()
|
||||
}
|
||||
|
||||
// RestoreDuration Restore最大超时时间
|
||||
func (que *StarQueue) RestoreDuration(tm time.Duration) {
|
||||
que.duration = tm
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user