From a59164689a768d396cf3175d66942f344719d906 Mon Sep 17 00:00:00 2001 From: milindmadhukar Date: Mon, 22 Nov 2021 14:31:21 +0530 Subject: [PATCH] New way to add optional parameters --- README.md | 10 ++-- {examples => _examples}/from_files/main.go | 8 +-- {examples => _examples}/from_files/main.py | 0 {examples => _examples}/from_files/test.py | 0 {examples => _examples}/get_languages/main.go | 3 +- .../get_latest_version/main.go | 3 +- {examples => _examples}/get_runtimes/main.go | 3 +- {examples => _examples}/hello_world/main.go | 5 +- _examples/with_input/main.go | 21 +++++++ models.go | 13 ----- params.go | 57 +++++++++++++++++++ piston.go | 48 ++++------------ piston_test.go | 6 +- test.sh | 2 + utils.go | 14 ++++- 15 files changed, 120 insertions(+), 73 deletions(-) rename {examples => _examples}/from_files/main.go (57%) rename {examples => _examples}/from_files/main.py (100%) rename {examples => _examples}/from_files/test.py (100%) rename {examples => _examples}/get_languages/main.go (74%) rename {examples => _examples}/get_latest_version/main.go (81%) rename {examples => _examples}/get_runtimes/main.go (78%) rename {examples => _examples}/hello_world/main.go (80%) create mode 100644 _examples/with_input/main.go create mode 100644 params.go create mode 100755 test.sh diff --git a/README.md b/README.md index f386c5b..6c97a58 100644 --- a/README.md +++ b/README.md @@ -23,16 +23,18 @@ package main import ( "fmt" - "net/http" piston "github.com/milindmadhukar/go-piston" ) func main() { - client := piston.GetDefaultClient(http.DefaultClient) + client := piston.CreateDefaultClient() output, err := client.Execute("python", "", // Passing language. Since no version is specified, it uses the latest supported version. - []piston.Code{{Content: "inp = input()\nprint(inp[::-1])"}}, // Passing Code. - &piston.OptionalParams{Stdin: "hello world"}) // Passing input as "hello world". + []piston.Code{ + {Content: "inp = input()\nprint(inp[::-1])"}, + }, // Passing Code. + piston.Stdin("hello world"), // Passing input as "hello world". + ) if err != nil { panic(err) } diff --git a/examples/from_files/main.go b/_examples/from_files/main.go similarity index 57% rename from examples/from_files/main.go rename to _examples/from_files/main.go index 4aef257..13faad3 100644 --- a/examples/from_files/main.go +++ b/_examples/from_files/main.go @@ -2,20 +2,18 @@ package main import ( "log" - "net/http" piston "github.com/milindmadhukar/go-piston" ) func main() { - client := piston.GetDefaultClient(http.DefaultClient) - paths := []string{"main.py", "test.py"} - files, err := piston.Files(paths) + client := piston.CreateDefaultClient() + files, err := piston.Files("main.py", "test.py") if err != nil { log.Fatal(err) } output, err := client.Execute("python", "", - files, nil) + files) log.Println(output.GetOutput()) } diff --git a/examples/from_files/main.py b/_examples/from_files/main.py similarity index 100% rename from examples/from_files/main.py rename to _examples/from_files/main.py diff --git a/examples/from_files/test.py b/_examples/from_files/test.py similarity index 100% rename from examples/from_files/test.py rename to _examples/from_files/test.py diff --git a/examples/get_languages/main.go b/_examples/get_languages/main.go similarity index 74% rename from examples/get_languages/main.go rename to _examples/get_languages/main.go index a5daee0..69c5b28 100644 --- a/examples/get_languages/main.go +++ b/_examples/get_languages/main.go @@ -2,13 +2,12 @@ package main import ( "log" - "net/http" piston "github.com/milindmadhukar/go-piston" ) func main() { - client := piston.GetDefaultClient(http.DefaultClient) + client := piston.CreateDefaultClient() languages := client.GetLanguages() log.Println("Supported Languages by Piston are: ", *languages) diff --git a/examples/get_latest_version/main.go b/_examples/get_latest_version/main.go similarity index 81% rename from examples/get_latest_version/main.go rename to _examples/get_latest_version/main.go index 5f47f27..59cd621 100644 --- a/examples/get_latest_version/main.go +++ b/_examples/get_latest_version/main.go @@ -2,13 +2,12 @@ package main import ( "log" - "net/http" piston "github.com/milindmadhukar/go-piston" ) func main() { - client := piston.GetDefaultClient(http.DefaultClient) + client := piston.CreateDefaultClient() lang := "python" latestVersion, err := client.GetLatestVersion(lang) diff --git a/examples/get_runtimes/main.go b/_examples/get_runtimes/main.go similarity index 78% rename from examples/get_runtimes/main.go rename to _examples/get_runtimes/main.go index 040289c..1c8b693 100644 --- a/examples/get_runtimes/main.go +++ b/_examples/get_runtimes/main.go @@ -2,13 +2,12 @@ package main import ( "log" - "net/http" piston "github.com/milindmadhukar/go-piston" ) func main() { - client := piston.GetDefaultClient(http.DefaultClient) + client := piston.CreateDefaultClient() runtimes, err := client.GetRuntimes() diff --git a/examples/hello_world/main.go b/_examples/hello_world/main.go similarity index 80% rename from examples/hello_world/main.go rename to _examples/hello_world/main.go index 114f02c..e4739a3 100644 --- a/examples/hello_world/main.go +++ b/_examples/hello_world/main.go @@ -2,18 +2,17 @@ package main import ( "log" - "net/http" piston "github.com/milindmadhukar/go-piston" ) func main() { - client := piston.GetDefaultClient(http.DefaultClient) + client := piston.CreateDefaultClient() output, err := client.Execute("python", "", []piston.Code{ {Content: "print('Hello World')"}, - }, nil) + }) if err != nil { log.Fatal(err) diff --git a/_examples/with_input/main.go b/_examples/with_input/main.go new file mode 100644 index 0000000..9d4d41d --- /dev/null +++ b/_examples/with_input/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + + piston "github.com/milindmadhukar/go-piston" +) + +func main() { + client := piston.CreateDefaultClient() + output, err := client.Execute("python", "", // Passing language. Since no version is specified, it uses the latest supported version. + []piston.Code{ + {Content: "inp = input()\nprint(inp[::-1])"}, + }, // Passing Code. + piston.Stdin("hello world"), // Passing input as "hello world". + ) + if err != nil { + panic(err) + } + fmt.Println(output.GetOutput()) +} diff --git a/models.go b/models.go index 15243cf..ce846f6 100644 --- a/models.go +++ b/models.go @@ -2,7 +2,6 @@ package gopiston import ( "net/http" - "time" ) /* @@ -61,15 +60,3 @@ type PistonResponse struct { Signal interface{} `json:"signal,omitempty"` } `json:"run"` } - -/* -Optional Paramaters that can be passed for the execute endpoint -*/ -type OptionalParams struct { - Stdin string - Args []string - CompileTimeout time.Duration - RunTimeout time.Duration - CompileMemoryLimit int - RunMemoryLimit int -} diff --git a/params.go b/params.go new file mode 100644 index 0000000..3fbe2db --- /dev/null +++ b/params.go @@ -0,0 +1,57 @@ +package gopiston + +import "time" + +// Function to pass the Params struct. +type Param func(*Params) + +// Struct that contains all piston parameters. +type Params struct { + requestBody *RequestBody +} + +// Stdin (optional) The text to pass as stdin to the program. Must be a string or left out. Defaults to blank string. +func Stdin(input string) Param { + return func(param *Params) { + param.requestBody.Stdin = input + } +} + +// Args (optional) The arguments to pass to the program. Must be an array or left out. Defaults to []. +func Args(args []string) Param { + return func(param *Params) { + param.requestBody.Args = args + } +} + +// CompileTimeout (optional) The maximum time allowed for the compile stage to finish before bailing out in milliseconds. Must be a "time.Duration" object. Defaults to 10 seconds. +func CompileTimeout(timeout time.Duration) Param { + + return func(param *Params) { + param.requestBody.CompileTimeout = int(timeout.Seconds()) + } +} + +// RunTimeout (optional) The maximum time allowed for the run stage to finish before bailing out in milliseconds. Must be a "time.Duration" object. Defaults to 3 seconds. +func RunTimeout(timeout time.Duration) Param { + + return func(param *Params) { + param.requestBody.RunTimeout = int(timeout.Seconds()) + } +} + +// CompileMemoryLimit (optional) The maximum amount of memory the compile stage is allowed to use in bytes. Must be a number or left out. Defaults to -1 (no limit) +func CompileMemoryLimit(limit int) Param { + return func(param *Params) { + param.requestBody.CompileMemoryLimit = limit + } + +} + +// RunMemoryLimit (optional) The maximum amount of memory the run stage is allowed to use in bytes. Must be a number or left out. Defaults to -1 (no limit) +func RunMemoryLimit(limit int) Param { + + return func(param *Params) { + param.requestBody.RunMemoryLimit = limit + } +} diff --git a/piston.go b/piston.go index 81381de..7719245 100644 --- a/piston.go +++ b/piston.go @@ -9,9 +9,9 @@ import ( /* Creates a default client object and returns it for access to the methods. */ -func GetDefaultClient(httpClient *http.Client) *Client { +func CreateDefaultClient() *Client { return &Client{ - httpClient: httpClient, + httpClient: http.DefaultClient, baseUrl: "https://emkc.org/api/v2/piston/", apiKey: "", } @@ -71,19 +71,19 @@ version (required) The version of the language to use for execution, must be a s files (required) A Slice of files containing code or other data that should be used for execution. The first file in this array is considered the main file. The name of the files is optional. Files can be added using path with the "Files()" method. To provide Code directly, provide a slice of "Code" struct. -optionalParams.Stdin (optional) The text to pass as stdin to the program. Must be a string or left out. Defaults to blank string. +Stdin (optional) The text to pass as stdin to the program. Must be a string or left out. Defaults to blank string. -optionalParams.Args (optional) The arguments to pass to the program. Must be an array or left out. Defaults to []. +Args (optional) The arguments to pass to the program. Must be an array or left out. Defaults to []. -optionalParams.CompileTimeout (optional) The maximum time allowed for the compile stage to finish before bailing out in milliseconds. Must be a "time.Duration" object. Defaults to 10 seconds. +CompileTimeout (optional) The maximum time allowed for the compile stage to finish before bailing out in milliseconds. Must be a "time.Duration" object. Defaults to 10 seconds. -optionalParams.RunTimeout (optional) The maximum time allowed for the run stage to finish before bailing out in milliseconds. Must be a "time.Duration" object. Defaults to 3 seconds. +RunTimeout (optional) The maximum time allowed for the run stage to finish before bailing out in milliseconds. Must be a "time.Duration" object. Defaults to 3 seconds. -optionalParams.CompileMemoryLimit (optional) The maximum amount of memory the compile stage is allowed to use in bytes. Must be a number or left out. Defaults to -1 (no limit) +CompileMemoryLimit (optional) The maximum amount of memory the compile stage is allowed to use in bytes. Must be a number or left out. Defaults to -1 (no limit) -optionalParams.RunMemoryLimit (optional) The maximum amount of memory the run stage is allowed to use in bytes. Must be a number or left out. Defaults to -1 (no limit) +RunMemoryLimit (optional) The maximum amount of memory the run stage is allowed to use in bytes. Must be a number or left out. Defaults to -1 (no limit) */ -func (client *Client) Execute(language string, version string, files []Code, optionalParams *OptionalParams) (*PistonResponse, error) { +func (client *Client) Execute(language string, version string, code []Code, params ...Param) (*PistonResponse, error) { // Initializing the request body. reqBody := RequestBody{} @@ -102,35 +102,9 @@ func (client *Client) Execute(language string, version string, files []Code, opt } reqBody.Version = version - reqBody.Files = files - - // Handling Optional parameters for the request body. - if optionalParams != nil { - - if stdin := optionalParams.Stdin; stdin != "" { - reqBody.Stdin = stdin - } - - if args := optionalParams.Args; args != nil { - reqBody.Args = args - } - - if compileTimeout := optionalParams.CompileTimeout; compileTimeout.Milliseconds() != 0 { - reqBody.CompileTimeout = int(compileTimeout.Milliseconds()) - } - - if runTimeout := optionalParams.RunTimeout; runTimeout.Microseconds() != 0 { - reqBody.RunTimeout = int(runTimeout.Milliseconds()) - } + reqBody.Files = code - if compileMemoryLimit := optionalParams.CompileMemoryLimit; compileMemoryLimit != 0 { - reqBody.CompileMemoryLimit = compileMemoryLimit - } - - if runMemoryLimit := optionalParams.RunMemoryLimit; runMemoryLimit != 0 { - reqBody.RunMemoryLimit = runMemoryLimit - } - } + reqBody = *processParams(&reqBody, params...) // Getting a json bytes. bytesBody, err := json.Marshal(reqBody) diff --git a/piston_test.go b/piston_test.go index 8ff5654..0a34906 100644 --- a/piston_test.go +++ b/piston_test.go @@ -1,12 +1,11 @@ package gopiston import ( - "net/http" "testing" "time" ) -var client = GetDefaultClient(http.DefaultClient) +var client = CreateDefaultClient() func assert(expected, got interface{}, t *testing.T) { if expected != got { @@ -30,7 +29,6 @@ func TestExecutionCode(t *testing.T) { output, err := client.Execute( "python", "", []Code{{Content: "print([i for i in range(4)])"}}, - nil, ) if err != nil { @@ -49,7 +47,7 @@ func TestTimeout(t *testing.T) { Content: "import time\nprint('before sleep')\ntime.sleep(3)\nprint('after sleep')", }, }, - &OptionalParams{RunTimeout: 2 * time.Second}, + RunTimeout(2*time.Second), ) if err != nil { diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..cf6bd21 --- /dev/null +++ b/test.sh @@ -0,0 +1,2 @@ + +go clean -testcache && go test ./... -v -cover | sed ''/PASS/s//$(printf "\033[32mPASS\033[0m")/'' | sed ''/FAIL/s//$(printf "\033[31mFAIL\033[0m")/'' | sed ''/RUN/s//$(printf "\033[33mRUN\033[0m")/'' | GREP_COLOR='01;32' grep -E --color 'ok.*$|^.*ok.*$|$' diff --git a/utils.go b/utils.go index ab91b10..f7a9e90 100644 --- a/utils.go +++ b/utils.go @@ -9,6 +9,17 @@ import ( "os" ) +func processParams(body *RequestBody, params ...Param) *RequestBody { + p := Params{ + requestBody: body, + } + for _, param := range params { + param(&p) + } + + return body +} + /* Returns the output of the given code. */ @@ -20,7 +31,7 @@ func (resp *PistonResponse) GetOutput() string { Utility method to pass file paths instead of actual code in the string. Providing a slice of paths will send all the files. */ -func Files(paths []string) ([]Code, error) { +func Files(paths ...string) ([]Code, error) { var files []Code for _, path := range paths { @@ -112,6 +123,7 @@ func handleStatusCode(code int, respBody string) error { // Handles sending the request to the Piston API and returing a response. func (client *Client) handleRequest(method string, url string, body *bytes.Reader) (*http.Response, error) { + // HACK: Why is this needed? if body == nil { body = &bytes.Reader{} }