diff --git a/api/messaging/spec.json b/api/messaging/spec.json index 51b2ce57c..0ff6d0a40 100644 --- a/api/messaging/spec.json +++ b/api/messaging/spec.json @@ -24,6 +24,21 @@ } ] }, + { + "title": "Commands", + "parameters": {}, + "entrypoint": "commands", + "path": "/commands", + "authentication": [], + "apis": [ + { + "name": "list", + "path": "/", + "method": "GET", + "title": "List of available commands" + } + ] + }, { "title": "Channels", "description": "A channel is a representation of a sequence of messages. It has meta data like channel subject. Channels may be public, private or group.", diff --git a/api/messaging/spec/commands.json b/api/messaging/spec/commands.json new file mode 100644 index 000000000..d35a8b025 --- /dev/null +++ b/api/messaging/spec/commands.json @@ -0,0 +1,18 @@ +{ + "Title": "Commands", + "Interface": "Commands", + "Struct": null, + "Parameters": {}, + "Protocol": "", + "Authentication": [], + "Path": "/commands", + "APIs": [ + { + "Name": "list", + "Method": "GET", + "Title": "List of available commands", + "Path": "/", + "Parameters": null + } + ] +} \ No newline at end of file diff --git a/docs/messaging/README.md b/docs/messaging/README.md index f0fbe307b..b79d12a43 100644 --- a/docs/messaging/README.md +++ b/docs/messaging/README.md @@ -251,6 +251,30 @@ A channel is a representation of a sequence of messages. It has meta data like c +# Commands + +| Method | Endpoint | Purpose | +| ------ | -------- | ------- | +| `GET` | `/commands/` | List of available commands | + +## List of available commands + +#### Method + +| URI | Protocol | Method | Authentication | +| --- | -------- | ------ | -------------- | +| `/commands/` | HTTP/S | GET | | + +#### Request parameters + +| Parameter | Type | Method | Description | Default | Required? | +| --------- | ---- | ------ | ----------- | ------- | --------- | + +--- + + + + # Messages Messages represent individual messages in the chat system. Messages are typed, indicating the event which triggered the message. diff --git a/messaging/rest/commands.go b/messaging/rest/commands.go new file mode 100644 index 000000000..80efc42b6 --- /dev/null +++ b/messaging/rest/commands.go @@ -0,0 +1,31 @@ +package rest + +import ( + "context" + + "github.com/pkg/errors" + + "github.com/crusttech/crust/messaging/rest/request" + "github.com/crusttech/crust/messaging/types" +) + +var _ = errors.Wrap + +type Commands struct { + // xxx service.XXXService +} + +func (Commands) New() *Commands { + return &Commands{} +} + +func (ctrl *Commands) List(ctx context.Context, r *request.CommandsList) (interface{}, error) { + return types.CommandSet{ + &types.Command{ + Name: "echo", + Description: "It does exactly what it says on the tin"}, + &types.Command{ + Name: "shrug", + Description: "It does exactly what it says on the tin"}, + }, nil +} diff --git a/messaging/rest/handlers/commands.go b/messaging/rest/handlers/commands.go new file mode 100644 index 000000000..25b340c34 --- /dev/null +++ b/messaging/rest/handlers/commands.go @@ -0,0 +1,56 @@ +package handlers + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `commands.go`, `commands.util.go` or `commands_test.go` to + implement your API calls, helper functions and tests. The file `commands.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "context" + + "net/http" + + "github.com/go-chi/chi" + "github.com/titpetric/factory/resputil" + + "github.com/crusttech/crust/messaging/rest/request" +) + +// Internal API interface +type CommandsAPI interface { + List(context.Context, *request.CommandsList) (interface{}, error) +} + +// HTTP API interface +type Commands struct { + List func(http.ResponseWriter, *http.Request) +} + +func NewCommands(ch CommandsAPI) *Commands { + return &Commands{ + List: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewCommandsList() + resputil.JSON(w, params.Fill(r), func() (interface{}, error) { + return ch.List(r.Context(), params) + }) + }, + } +} + +func (ch *Commands) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) { + r.Group(func(r chi.Router) { + r.Use(middlewares...) + r.Get("/commands/", ch.List) + }) +} diff --git a/messaging/rest/request/commands.go b/messaging/rest/request/commands.go new file mode 100644 index 000000000..a448fd021 --- /dev/null +++ b/messaging/rest/request/commands.go @@ -0,0 +1,71 @@ +package request + +/* + Hello! This file is auto-generated from `docs/src/spec.json`. + + For development: + In order to update the generated files, edit this file under the location, + add your struct fields, imports, API definitions and whatever you want, and: + + 1. run [spec](https://github.com/titpetric/spec) in the same folder, + 2. run `./_gen.php` in this folder. + + You may edit `commands.go`, `commands.util.go` or `commands_test.go` to + implement your API calls, helper functions and tests. The file `commands.go` + is only generated the first time, and will not be overwritten if it exists. +*/ + +import ( + "io" + "strings" + + "encoding/json" + "mime/multipart" + "net/http" + + "github.com/go-chi/chi" + "github.com/pkg/errors" +) + +var _ = chi.URLParam +var _ = multipart.FileHeader{} + +// Commands list request parameters +type CommandsList struct { +} + +func NewCommandsList() *CommandsList { + return &CommandsList{} +} + +func (cReq *CommandsList) Fill(r *http.Request) (err error) { + if strings.ToLower(r.Header.Get("content-type")) == "application/json" { + err = json.NewDecoder(r.Body).Decode(cReq) + + switch { + case err == io.EOF: + err = nil + case err != nil: + return errors.Wrap(err, "error parsing http request body") + } + } + + if err = r.ParseForm(); err != nil { + return err + } + + get := map[string]string{} + post := map[string]string{} + urlQuery := r.URL.Query() + for name, param := range urlQuery { + get[name] = string(param[0]) + } + postVars := r.Form + for name, param := range postVars { + post[name] = string(param[0]) + } + + return err +} + +var _ RequestFiller = NewCommandsList() diff --git a/messaging/rest/router.go b/messaging/rest/router.go index 54f4b24fd..4df79a217 100644 --- a/messaging/rest/router.go +++ b/messaging/rest/router.go @@ -26,6 +26,7 @@ func MountRoutes() func(chi.Router) { handlers.NewChannel(Channel{}.New()).MountRoutes(r) handlers.NewMessage(Message{}.New()).MountRoutes(r) handlers.NewSearch(Search{}.New()).MountRoutes(r) + handlers.NewCommands(Commands{}.New()).MountRoutes(r) }) } } diff --git a/messaging/types/command.go b/messaging/types/command.go index 4329155cf..ee2477f9b 100644 --- a/messaging/types/command.go +++ b/messaging/types/command.go @@ -7,18 +7,3 @@ type ( Description string `db:"description" json:"description"` } ) - -var ( - Preset CommandSet // @todo move this to someplace safe -) - -func init() { - Preset = CommandSet{ - &Command{ - Name: "echo", - Description: "It does exactly what it says on the tin"}, - &Command{ - Name: "shrug", - Description: "It does exactly what it says on the tin"}, - } -} diff --git a/messaging/websocket/session.go b/messaging/websocket/session.go index a97ca7de1..b880709e7 100644 --- a/messaging/websocket/session.go +++ b/messaging/websocket/session.go @@ -113,10 +113,6 @@ func (sess *Session) connected() (err error) { } } - if err = sess.sendReply(payload.Commands(types.Preset)); err != nil { - return - } - // Tell everyone that user has connected if err = sess.sendToAll(&outgoing.Connected{UserID: payload.Uint64toa(sess.user.Identity())}); err != nil { return