aboutsummaryrefslogtreecommitdiff
path: root/exec_response.go
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2023-11-22 13:16:21 +0700
committerShulhan <ms@kilabit.info>2023-12-01 13:17:30 +0700
commita73f0d5d0108e2e10d89f93c7867addbe073add9 (patch)
tree042e69e2c1d10d836a006abca37417af02bba826 /exec_response.go
parenta9701f66c2e38a3a7f3d12deed6ebba5144e208e (diff)
downloadawwan-a73f0d5d0108e2e10d89f93c7867addbe073add9.tar.xz
all: refactoring HTTP endpoint for Execute
Previously, the Execute endpoint wait for command execution to finish. In case the command takes longer than proxy or server write timeout, it will return with an timeout error to client. In this changes, we generate an execution ID for each request and return it immediately. The next commit will implement HTTP endpoint to fetch the latest status and/or output by execution ID. References: https://todo.sr.ht/~shulhan/awwan/5
Diffstat (limited to 'exec_response.go')
-rw-r--r--exec_response.go79
1 files changed, 76 insertions, 3 deletions
diff --git a/exec_response.go b/exec_response.go
index 661189f..9569aab 100644
--- a/exec_response.go
+++ b/exec_response.go
@@ -3,10 +3,83 @@
package awwan
+import (
+ "bytes"
+ "fmt"
+ "time"
+)
+
// ExecResponse contains the request and output of command execution, from
// ExecRequest.
type ExecResponse struct {
- *ExecRequest
- Error string `json:"error"`
- Output []byte `json:"output"`
+ // Copy of request.
+
+ Mode string `json:"mode"`
+ Script string `json:"script"`
+ LineRange string `json:"line_range"`
+
+ // ID of execution request that can be used to stream output or
+ // got get full status.
+ ID string `json:"id"`
+
+ // BeginAt contains when the execution begin.
+ BeginAt string `json:"begin_at"`
+
+ // EndAt contains when the execution finished.
+ EndAt string `json:"end_at"`
+
+ Error string `json:"error"`
+
+ Output []string `json:"output"`
+}
+
+func newExecResponse(req *ExecRequest) (execRes *ExecResponse) {
+ var now = timeNow().UTC()
+
+ execRes = &ExecResponse{
+ Mode: req.Mode,
+ Script: req.Script,
+ LineRange: req.LineRange,
+
+ ID: fmt.Sprintf(`%s:%s:%s:%d`, req.Mode, req.Script, req.LineRange, now.Unix()),
+ BeginAt: now.Format(time.RFC3339),
+
+ Output: make([]string, 0, 8),
+ }
+
+ // Use the ExecResponse itself as handler for output.
+ req.registerLogWriter(`response`, execRes)
+
+ return execRes
+}
+
+// Write convert the raw output from execution into multiline string, and
+// push it to field Output.
+func (execres *ExecResponse) Write(out []byte) (n int, err error) {
+ if len(out) == 0 {
+ return 0, nil
+ }
+
+ var outlen = len(out)
+ if out[outlen-1] == '\n' {
+ out = out[:outlen-1]
+ outlen--
+ }
+
+ var (
+ lines = bytes.Split(out, []byte{'\n'})
+ line []byte
+ )
+ for _, line = range lines {
+ execres.Output = append(execres.Output, string(line))
+ }
+
+ return outlen, nil
+}
+
+func (execres *ExecResponse) end(execErr error) {
+ if execErr != nil {
+ execres.Error = execErr.Error()
+ }
+ execres.EndAt = timeNow().UTC().Format(time.RFC3339)
}