| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- package socketio
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "reflect"
- )
- // Attachment is an attachment handler used in emit args. All attachments will be sent as binary data in the transport layer. When using an attachment, make sure it is a pointer.
- //
- // For example:
- //
- // type Arg struct {
- // Title string `json:"title"`
- // File *Attachment `json:"file"`
- // }
- //
- // f, _ := os.Open("./some_file")
- // arg := Arg{
- // Title: "some_file",
- // File: &Attachment{
- // Data: f,
- // }
- // }
- //
- // socket.Emit("send file", arg)
- // socket.On("get file", func(so Socket, arg Arg) {
- // b, _ := ioutil.ReadAll(arg.File.Data)
- // })
- type Attachment struct {
- Data io.ReadWriter
- num int
- }
- func encodeAttachments(v interface{}) []io.Reader {
- index := 0
- return encodeAttachmentValue(reflect.ValueOf(v), &index)
- }
- func encodeAttachmentValue(v reflect.Value, index *int) []io.Reader {
- v = reflect.Indirect(v)
- ret := []io.Reader{}
- if !v.IsValid() {
- return ret
- }
- switch v.Kind() {
- case reflect.Struct:
- if v.Type().Name() == "Attachment" {
- a, ok := v.Addr().Interface().(*Attachment)
- if !ok {
- panic("can't convert")
- }
- a.num = *index
- ret = append(ret, a.Data)
- (*index)++
- return ret
- }
- for i, n := 0, v.NumField(); i < n; i++ {
- var r []io.Reader
- r = encodeAttachmentValue(v.Field(i), index)
- ret = append(ret, r...)
- }
- case reflect.Map:
- if v.IsNil() {
- return ret
- }
- for _, key := range v.MapKeys() {
- var r []io.Reader
- r = encodeAttachmentValue(v.MapIndex(key), index)
- ret = append(ret, r...)
- }
- case reflect.Slice:
- if v.IsNil() {
- return ret
- }
- fallthrough
- case reflect.Array:
- for i, n := 0, v.Len(); i < n; i++ {
- var r []io.Reader
- r = encodeAttachmentValue(v.Index(i), index)
- ret = append(ret, r...)
- }
- case reflect.Interface:
- ret = encodeAttachmentValue(reflect.ValueOf(v.Interface()), index)
- }
- return ret
- }
- func decodeAttachments(v interface{}, binary [][]byte) error {
- return decodeAttachmentValue(reflect.ValueOf(v), binary)
- }
- func decodeAttachmentValue(v reflect.Value, binary [][]byte) error {
- v = reflect.Indirect(v)
- if !v.IsValid() {
- return fmt.Errorf("invalid value")
- }
- switch v.Kind() {
- case reflect.Struct:
- if v.Type().Name() == "Attachment" {
- a, ok := v.Addr().Interface().(*Attachment)
- if !ok {
- panic("can't convert")
- }
- if a.num >= len(binary) || a.num < 0 {
- return fmt.Errorf("out of range")
- }
- if a.Data == nil {
- a.Data = bytes.NewBuffer(nil)
- }
- for b := binary[a.num]; len(b) > 0; {
- n, err := a.Data.Write(b)
- if err != nil {
- return err
- }
- b = b[n:]
- }
- return nil
- }
- for i, n := 0, v.NumField(); i < n; i++ {
- if err := decodeAttachmentValue(v.Field(i), binary); err != nil {
- return err
- }
- }
- case reflect.Map:
- if v.IsNil() {
- return nil
- }
- for _, key := range v.MapKeys() {
- if err := decodeAttachmentValue(v.MapIndex(key), binary); err != nil {
- return err
- }
- }
- case reflect.Slice:
- if v.IsNil() {
- return nil
- }
- fallthrough
- case reflect.Array:
- for i, n := 0, v.Len(); i < n; i++ {
- if err := decodeAttachmentValue(v.Index(i), binary); err != nil {
- return err
- }
- }
- case reflect.Interface:
- if err := decodeAttachmentValue(reflect.ValueOf(v.Interface()), binary); err != nil {
- return err
- }
- }
- return nil
- }
- func (a Attachment) MarshalJSON() ([]byte, error) {
- return []byte(fmt.Sprintf("{\"_placeholder\":true,\"num\":%d}", a.num)), nil
- }
- func (a *Attachment) UnmarshalJSON(b []byte) error {
- var v struct {
- Num int `json:"num"`
- }
- if err := json.Unmarshal(b, &v); err != nil {
- return err
- }
- a.num = v.Num
- return nil
- }
|