// ParseEvent parse s into an Event struct. // The input must be single event line, stripped of the "000 " prefix. func ParseEvent(s []byte) (Event, error) { var e Event cmd := ssmp.NewCommand(s) from, err := ssmp.IdField(cmd) if err != nil { return e, ErrInvalidEvent } e.From = from ev, err := ssmp.VerbField(cmd) if err != nil { return e, ErrInvalidEvent } fields := events[string(ev)] if fields == 0 { return e, ErrInvalidEvent } e.Name = ev if fields == noFields { return e, nil } if (fields & fieldTo) != 0 { to, err := ssmp.IdField(cmd) if err != nil { return e, ErrInvalidEvent } e.To = to } if (fields & fieldOption) != 0 { payload, err := ssmp.OptionField(cmd) if err != nil { return e, ErrInvalidEvent } e.Payload = payload } else if (fields & fieldPayload) != 0 { payload, err := ssmp.PayloadField(cmd) if err != nil { return e, ErrInvalidEvent } e.Payload = payload } return e, nil }
// NewConnection creates a SSMP connection out of a streaming netwrok connection. // // This method blocks until either a first message is received or a 10s timeout // elapses. // // Each accepted connection spawns a goroutine continuously reading from the // underlying network connection and triggering the Dispatcher. The caller must // keep track of the returned Connection and call the Close method to stop the // read goroutine and close the udnerlying netwrok connection. // // errInvalidLogin is returned if the first message is not a well-formed LOGIN // request. // errUnauthorized is returned if the authenticator doesn't accept the provided // credentials. func NewConnection(c net.Conn, a Authenticator, d *Dispatcher) (*Connection, error) { r := bufio.NewReaderSize(c, 1024) c.SetReadDeadline(time.Now().Add(10 * time.Second)) l, err := r.ReadSlice('\n') if err != nil { return nil, err } // strip LF delimiter l = l[0 : len(l)-1] cmd := ssmp.NewCommand(l) verb, err := ssmp.VerbField(cmd) if err != nil || !ssmp.Equal(verb, ssmp.LOGIN) { return nil, ErrInvalidLogin } user, err := ssmp.IdField(cmd) if err != nil { return nil, ErrInvalidLogin } scheme, err := ssmp.IdField(cmd) if err != nil { return nil, ErrInvalidLogin } cred := cmd.Trailing() if !a.Auth(c, user, scheme, cred) { return nil, ErrUnauthorized } cc := &Connection{ c: c, r: r, User: string(user), } go cc.readLoop(d) cc.Write(respOk) return cc, nil }