I have this right now:
// people
handler := routes.PersonHandler{}
subRouter := router.PathPrefix("/person").Subrouter()
subRouter.Use(authMiddleware)
handler.Mount(subRouter, routes.PersonInjection{People: models.PersonInit()})
I am wonder if there is a way to send both "/person" and "/people" to the same subrouter? Just in need of an alias at the moment.
Related
I want to start a child process (i'm on windows 10) and I would like to be able to suspend and resume the process at will.
I found this neat undocumented windows function NtSuspendProcess from ntdll.dll that should do the job but now I need to get the handle of the process to issue the suspend command.
this is an example:
modntdll = syscall.NewLazyDLL("ntdll.dll")
procNtSuspendProcess = modntdll.NewProc("NtSuspendProcess")
procNtResumeProcess = modntdll.NewProc("NtResumeProcess")
_, _, err = procNtSuspendProcess.Call(uintptr(handle))
_, _, err = procNtResumeProcess.Call(uintptr(handle))
To start the process I would normally use the exec.Command function but I can't find a way to retrieve the handle of the process.
Is there a way to get the handle when starting a process?
If not with exec.Command, what other library should I use to start a process that returns also the process handle?
As a side note:
I've looked into syscall.StartProcess but it's quite low level and I don't feel able to handle such a raw implementation.
_, handle, err := syscall.StartProcess("C:\\WINDOWS\\system32\\cmd.exe", []string{}, procAttr)
Go does not publicly expose the handle in exec.Command, you will have to access it either by.
Reflection
cmd := exec.Command("cmd.exe")
cmd.Start()
handle := uintptr(reflect.ValueOf(cmd.Process).Elem().FieldByName("handle").Uint())
or by creating an identical Process type and casting the Cmd.Process to your own type to access the private fields.
type Process struct {
Pid int
handle uintptr
isdone uint32
sigMu sync.RWMutex
}
cmd := exec.Command("cmd.exe")
cmd.Start()
proc := (*Process)(unsafe.Pointer(cmd.Process))
println(proc.handle)
The answer by "Make that 4" were both flawless, being simple and well explained.
I would just add an additional method that I found, just for completeness (requires the import of golang.org/x/sys/windows)
Update: apparently this method might lead to bugs/errors and it's probably better not to implement it (check the comments)
cmd := exec.Command("cmd.exe")
cmd.Start()
// using PROCESS_SUSPEND_RESUME since I want to call NtSuspendProcess function
handle, _ := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(cmd.Process.Pid))
defer windows.CloseHandle(handle)
fmt.Println(handle)
I try to Handle any pattern another than "/app/*" to FileServer Handler. I use mux router to handle "/app/*" urls, and than I need to handle any others urls to static FileServer.This is my code:
r := mux.NewRouter()
r.Handle("/app/deleteComment", c.Handler(PreHandler(DeleteCommentHandler)))
r.Handle("/app/adminDeleteComment", c.Handler(PreHandler(AdminDeleteCommentHandler)))
(...)
fsa := justFilesFilesystem{http.Dir("build/")}
http.Handle("/", http.StripPrefix("/", http.FileServer(fsa)))
And now it works with pattern "/" but i want it to works with any pattern diffrent then "/app/*". I try it many ways but i think there is a simple solution how to handle it. Please help. Cheers.
If I have a mux.Router, how do I set it to be a "subrouter"? All examples I can find creates a new router by calling Route.Subrouter() and then setting Handlers on it, but I already have a router!
// does not know about "/api/v1/"
v1_router := mux.NewRouter()
subrouter.HandleFuc("/route1/", ...)
subrouter.HandleFuc("/route2/", ...)
// does not now about route1, route2
r := mux.NewRouter()
r.PathPrefix("/api/v1/").???(v1_router)
I hope I'm making sense...
I feel the same way, and have to live with the same "workaround". I would like to set the subrouter to an existing router. Like:
r.PathPrefix("/api").SetSubrouter(api.GetRouter()) //won't work
That would let my api feel more autonomous / loosely coupled. But getting a subrouter is all we have from gorilla.
s := r.PathPrefix("/api").Subrouter()
api.SetRoutes(s)
You can do it like this:
v1 package file:
func Handlers(subrouter *mux.Router) {
//base handler, i.e. /v1
r.StrictSlash(true)
subrouter.HandleFuc("/route1/", ...)
subrouter.HandleFuc("/route2/", ...)
}
main file:
r := mux.NewRouter()
package.Handlers(r.PathPrefix("/api/v1").Subrouter())
I'm running on HTTPS (port 10443) and use subroutes:
mainRoute := mux.NewRouter()
mainRoute.StrictSlash(true)
mainRoute.Handle("/", http.RedirectHandler("/static/", 302))
mainRoute.PathPrefix("/static/").Handler(http.StripPrefix("/static", *fh))
// Bind API Routes
apiRoute := mainRoute.PathPrefix("/api").Subrouter()
apiProductRoute := apiRoute.PathPrefix("/products").Subrouter()
apiProductRoute.Handle("/", handler(listProducts)).Methods("GET")
And the functions:
func listProducts(w http.ResponseWriter, r *http.Request) (interface{}, *handleHTTPError) {
vars := mux.Vars(r)
productType, ok := vars["id"]
log.Println(productType)
log.Println(ok)
}
ok is false and I have no idea why. I'm doing a simple ?type=model after my URL..
When you enter a URL like somedomain.com/products?type=model you're specifying a query string, not a variable.
Query strings in Go are accessed via r.URL.Query - e.g.
vals := r.URL.Query() // Returns a url.Values, which is a map[string][]string
productTypes, ok := vals["type"] // Note type, not ID. ID wasn't specified anywhere.
var pt string
if ok {
if len(productTypes) >= 1 {
pt = productTypes[0] // The first `?type=model`
}
}
As you can see, this can be a little clunky as it has to account for the map value being empty and for the possibility of a URL like somedomain.com/products?type=model&this=that&here=there&type=cat where a key can be specified more than once.
As per the gorilla/mux docs you can use route variables:
// List all products, or the latest
apiProductRoute.Handle("/", handler(listProducts)).Methods("GET")
// List a specific product
apiProductRoute.Handle("/{id}/", handler(showProduct)).Methods("GET")
This is where you would use mux.Vars:
vars := mux.Vars(request)
id := vars["id"]
Hope that helps clarify. I'd recommend the variables approach unless you specifically need to use query strings.
An easier way to solve this is to add query parameters in your route through Queries, like:
apiProductRoute.Handle("/", handler(listProducts)).
Queries("type","{type}").Methods("GET")
You can get it using:
v := mux.Vars(r)
type := v["type"]
NOTE: This might not have been possible when the question was originally posted but I stumbled across this when I encountered a similar problem and the gorilla docs helped.
I've been using gorilla/mux for my routing needs. But I noticed one problem, when I nest multiple Subrouters it doesn't work.
Here is the example:
func main() {
r := mux.NewRouter().StrictSlash(true)
api := r.Path("/api").Subrouter()
u := api.Path("/user").Subrouter()
u.Methods("GET").HandleFunc(UserHandler)
http.ListenAndServe(":8080", r)
}
I wanted to use this approach so I can delegate populating the router to some other package, for example user.Populate(api)
However this doesn't seem to work. It works only if I use single Subrouter in the chain.
Any ideas?
I figured it out, so I'll just post it here in case someone is as stupid as I was. :D
When creating path-based subrouter, you have to obtain it with PathPrefix instead of Path.
r.PathPrefix("/api").Subrouter()
Use r.Path("/api") only when attaching handlers to that endpoint.
For those who are struggling to split between auth and noauth routes, the following works fine for me:
r := mux.NewRouter()
noAuthRouter := r.MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
return r.Header.Get("Authorization") == ""
}).Subrouter()
authRouter := r.MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
return true
}).Subrouter()
Then you can apply middleware for authRouter only
If you need to Separate out the UI and API routers, you can simply do what the OP suggested:
appRouter := r.PathPrefix("/").Subrouter()
appRouter.Use(myAppRouter)
apiRouter := r.PathPrefix("/api").Subrouter()
apiRouter.Use(myAPIRouter)
Many thanks for the OP for providing the answer. Hopefully having it all in one place for my use case will help someone.