-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ BUG ] - Object creation and usage #7
Comments
UpdateI extended the // Object interface defines the common behavior/functionalities each object exported on the main API should have.
// Client, Request, TCP, etc. are objects
type Object interface {
Define() error
ParseParams(*sobek.Runtime, []sobek.Value) (Params, error)
} To: // Object interface defines the common behavior/functionalities each object exported on the main API should have.
// Client, Request, TCP, etc. are objects
type Object interface {
sobek.DynamicObject
Define() error
ParseParams(*sobek.Runtime, []sobek.Value) (Params, error)
} From now on each Object in golang / module in javascript is an extended implementation of Example usage of func (c *Client) createRequest(method string, arg sobek.Value, body io.Reader) (*request.Request, error) {
// add default options to requests function
addDefault := func(req *request.Request) {
for k, vlist := range c.params.headers {
if len(vlist) == 0 {
continue
}
for _, v := range vlist {
req.Header.Add(k, v)
}
}
}
// if the input is an req object then everything has been set before so we just add defaults and return
if v, ok := arg.Export().(*request.Request); ok {
addDefault(v)
return v, nil
}
if v, ok := arg.Export().(string); ok {
r, err := http.NewRequest(method, v, body)
req := &request.Request{Request: r}
addDefault(req)
return req, err
}
return &request.Request{}, fmt.Errorf(
"invalid input! couldn't make the request from argument: %+v",
arg.Export())
} For implementing such a thing we need to have a The full example of implementation would be like this: // Client struct is the Client object type that users is going to use in js like this:
//
// const client = new Client();
// const response = await client.get('https://httpbin.test.k6.io/get');
//
// you can see more usage examples in js through examples dir.
type Client struct {
// The http.Client struct to have all the functionalities of a http.Client in Client struct
http.Client
// Multiple vus in k6 can create multiple Client objects so we need to have access the vu Runtime, etc.
Vu modules.VU
M map[string]sobek.Value
// Params is the way to config the global params for Client object to do requests.
params *Clientparams
}
var _ interfaces.Object = &Client{}
func (c *Client) Delete(k string) bool {
delete(c.M, k)
return true
}
func (c *Client) Get(k string) sobek.Value {
return c.M[k]
}
func (c *Client) Has(k string) bool {
_, exists := c.M[k]
return exists
}
func (c *Client) Keys() []string {
keys := make([]string, 0, len(c.M))
for k := range c.M {
keys = append(keys, k)
}
return keys
}
func (c *Client) Set(k string, val sobek.Value) bool {
c.M[k] = val
return true
}
// Define func defines data properties on obj attatched to Client struct.
func (c *Client) Define() error {
rt := c.Vu.Runtime()
c.Set("get", rt.ToValue(c.getAsync))
return nil
}
// ParseParams parses Client params and save them to it's instance
func (c *Client) ParseParams(rt *sobek.Runtime, args []sobek.Value) (interfaces.Params, error) {
parsed := &Clientparams{
headers: make(http.Header),
}
if len(args) == 0 {
c.params = parsed
return parsed, nil
}
if len(args) > 1 {
return nil, fmt.Errorf(
"you can't have multiple arguments when creating a new Client, but you've had %d args",
len(args),
)
}
rawParams := args[0]
params := rawParams.ToObject(rt)
for _, k := range params.Keys() {
switch k {
case "headers":
headers := params.Get(k)
if sobek.IsUndefined(headers) || sobek.IsNull(headers) {
continue
}
headersObj := headers.ToObject(rt)
if headersObj == nil {
continue
}
for _, key := range headersObj.Keys() {
parsed.headers.Set(key, headersObj.Get(key).String())
}
case "proxy":
proxy := params.Get(k)
if sobek.IsUndefined(proxy) || sobek.IsNull(proxy) {
continue
}
if v, ok := proxy.Export().(*url.URL); ok {
parsed.proxy = *v
}
case "url":
urlV := params.Get(k)
if sobek.IsUndefined(urlV) || sobek.IsNull(urlV) {
continue
}
if v, ok := urlV.Export().(string); ok {
addr, err := url.Parse(v)
if err != nil {
return parsed, fmt.Errorf(
"invalid url for Client: %s",
v,
)
}
parsed.url = *addr
} else {
return parsed, fmt.Errorf(
"invalid url for Client: %s",
v,
)
}
default:
return parsed, fmt.Errorf(
"unknown Client's option: %s",
k,
)
}
}
c.params = parsed
return parsed, nil
} It was easier than i thought :) |
I have fixed and merged this issue with mentioned implementation on pull request #8 |
Describe the bug
There is some features on the design document such as these:
TCP.open
module output to be used on dial parameter ofClient
moduleRequest
andResponse
modules to other modules likeClient
Thus these features are important part of the design documentation, I couldn't implement them because of how i implement these modules.
These modules are generally implementing Object interface i wrote
There is two bug with this implementation:
Request
toClient
like this:I encountered an error while restoring the object in go when i used the
sobek.Object.Export
method because it will return amap[string]Value
or something like this.To run the code above. I needed to do a trick initializing the
Request
module:The trick is
rt.ToValue(r).ToObject(rt)
so as the documentation onsobek engine
says, in this way when we callExport()
on a*sobek.Object
type it returns the original object in go.But this is just a trick to continue development so i need to re-implement it another way.
To Reproduce
Not using the trick mentioned above will raise us not knowing what is the original object in golang is.
can't do this:
Expected implementation
I need to find a way to wrap the original object and restore it whenever i want, so i can use its functionalities after i pass the module to another.
Additional context
I did some research and found out that we can somehow use
sobek.DynamicObject
, but i don't know exactly how.I would be very happy if anyone have the solution, please share the solution you think of.
The text was updated successfully, but these errors were encountered: