diff options
Diffstat (limited to 'marusia.go')
-rw-r--r-- | marusia.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/marusia.go b/marusia.go new file mode 100644 index 0000000..5356720 --- /dev/null +++ b/marusia.go @@ -0,0 +1,114 @@ +// Copyright (c) 2020 Alexander Kiryukhin <a.kiryukhin@mail.ru> + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package marusia + +import ( + "context" + "encoding/json" + "net/http" + "strconv" + "strings" +) + +// Marusia is main API object +type Marusia struct { + handler MessageHandler + ctx context.Context + errorLogger func(error) +} + +// SetCtx sets optional parent context +func (m *Marusia) SetCtx(ctx context.Context) *Marusia { + m.ctx = ctx + return m +} + +// SetErrorLogger sets optional error logger +func (m *Marusia) SetErrorLogger(errorLogger func(error)) *Marusia { + m.errorLogger = errorLogger + return m +} + +// NewMarusia is API constructor +func NewMarusia(handler MessageHandler) *Marusia { + return &Marusia{handler: handler, ctx: context.Background()} +} + +// MessageHandler is http.MessageHandler that proceed requests from Marusia and sends responses to Marusia +func (m *Marusia) Handler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + reqEnvelope := new(requestEnvelope) + if err := json.NewDecoder(r.Body).Decode(reqEnvelope); err != nil { + w.WriteHeader(http.StatusBadRequest) + if m.errorLogger != nil { + m.errorLogger(err) + } + return + } + ctx := getContext(m.ctx, reqEnvelope) + resp, err := m.handler(ctx, reqEnvelope.Request) + if err != nil { + if m.errorLogger != nil { + m.errorLogger(err) + } + w.WriteHeader(http.StatusInternalServerError) + return + } + respEnvelope := &responseEnvelope{ + Response: resp, + Session: reqEnvelope.Session, + Version: version, + } + w.WriteHeader(http.StatusOK) + if err := json.NewEncoder(w).Encode(respEnvelope); err != nil { + if m.errorLogger != nil { + m.errorLogger(err) + } + w.WriteHeader(http.StatusInternalServerError) + } + }) +} + +func getContext(parent context.Context, req *requestEnvelope) context.Context { + data := map[string]string{ + CtxSessionID: req.Session.SessionID, + CtxUserID: req.Session.UserID, + CtxSkillID: req.Session.SkillID, + CtxMessageID: strconv.Itoa(req.Session.MessageID), + CtxClientID: req.Meta.ClientID, + CtxLocale: req.Meta.Locale, + CtxTimezone: req.Meta.Timezone, + } + var interfaces []string + for iface := range req.Meta.Interfaces { + interfaces = append(interfaces, iface) + } + data[CtxInterfaces] = strings.Join(interfaces, ",") + if req.Session.New { + data[CtxNew] = "true" + } + ctx := parent + for k, v := range data { + ctx = context.WithValue(ctx, k, v) + } + return ctx +} |