How to link html - go

I use this library to create the GUI: github.com/Equanox/gotron
I need this when I click the html button to run a Go code with the username and password.
Do you know any way to do this? I tried to google it, but I didn't find any code related to it, maybe I searched it the wrong way.
My code:
package main
import (
"github.com/Equanox/gotron"
"log"
"os"
"text/template"
)
var tpl *template.Template
func LinkinInit() {
tpl = template.Must(template.ParseFiles("tpl.html"))
}
func main() {
// Create a new browser window instance
window, err := gotron.New()
if err != nil {
panic(err)
}
// Alter default window size and window title.
window.WindowOptions.Width = 720
window.WindowOptions.Height = 485
window.WindowOptions.Title = "Login APP"
// Start the browser window.
// This will establish a Go <=> nodejs bridge using websockets,
// to control ElectronBrowserWindow with our window object.
done, err := window.Start()
if err != nil {
panic(err)
}
<-done
}
HTML CODE
https://hastebin.com/usitorimil.xml

Look at the Gotron readme file
https://github.com/Equanox/gotron#communicate-between-backend-and-frontend
Backend: Handle incoming events
window.On(&gotron.Event{Event: "event-name"}, func(bin []byte) {
//Handle event here
}
Frontend: Send event to backend
ws.send(JSON.stringify({
"event": "event-name",
"AtrNameInFrontend": "Hello World!",
}))

Related

How to send data to a WebApp opening with either menu or inline buttons with Telebot Go API

I understand that it is possible to initialise a WebApp opened from Telegram using a menu or inline button. Ideally I want to provide the Telegram client's contact list to the WebApp. If anyone can provide an example of how to do that I would be very grateful.
var (
webapp = &tele.ReplyMarkup{}
app = &tele.WebApp{URL: "SomeURL"}
helloMsg = &tele.Message{Text: "SomeMessage"}
// Inline buttons.
btnGo = webapp.WebApp("Start inviting friends", app)
)
func main() {
webapp.Inline(
webapp.Row(btnGo),
)
log.Println("Starting Noah_HQ_bot")
pref := tele.Settings{
Token: os.Getenv("TOKEN"),
Poller: &tele.LongPoller{Timeout: 5 * time.Second},
}
b, err := tele.NewBot(pref)
if err != nil {
log.Fatal(err)
return
}
b.Handle("/start", func(c tele.Context) error {
log.Println("Detected Start")
b.Send(c.Message().Sender, helloMsg.Text, &tele.SendOptions{
ParseMode: "MARKDOWN",
}, webapp)
return nil
})
b.Start()
}

chromedp - Go - Show invalid printer settings error (-32000) - When setting WithMarginTop

I'm playing around with chromedp and been trying to replicate the functionality in puppeteer node.js but in golang.
I'm finding that the same JSON payload to chromium is causing an error when using chromedp
package main
import (
"context"
"io/ioutil"
"log"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/chromedp"
)
func main() {
// create context
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
// capture pdf
var buf []byte
if err := chromedp.Run(ctx, printToPDF(`<html><body><h1>Yeeeew!</h1></body></html>`, &buf)); err != nil {
log.Fatal(err)
}
if err := ioutil.WriteFile("sample.pdf", buf, 0644); err != nil {
log.Fatal(err)
}
}
// https://github.com/puppeteer/puppeteer/blob/4d9dc8c0e613f22d4cdf237e8bd0b0da3c588edb/src/common/PDFOptions.ts#L74
// https://github.com/puppeteer/puppeteer/blob/4d9dc8c0e613f22d4cdf237e8bd0b0da3c588edb/src/common/Page.ts#L3366
//https://github.com/chromedp/chromedp/issues/836
func printToPDF(html string, res *[]byte) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Navigate("about:blank"),
chromedp.ActionFunc(func(ctx context.Context) error {
frameTree, err := page.GetFrameTree().Do(ctx)
if err != nil {
return err
}
return page.SetDocumentContent(frameTree.Frame.ID, html).Do(ctx)
}),
chromedp.ActionFunc(func(ctx context.Context) error {
buf, _, err := page.PrintToPDF().
// WithPrintBackground(false).
WithMarginTop(20.0).
// WithMarginLeft(20).
// WithMarginBottom(20.0).
// WithMarginRight(20).
Do(ctx)
if err != nil {
return err
}
*res = buf
return nil
}),
}
}
I've vendored the modules and edited cdproto/page/page.go to print out the JSON being sent to chromium
{"marginTop":20,"marginBottom":0,"marginLeft":0,"marginRight":0,"transferMode":"ReturnAsStream"}
I've also done this in node.js and logged out the json to compare
node index.js
PDF command: 'Page.printToPDF' {
transferMode: 'ReturnAsStream',
marginTop: 20,
marginBottom: 20,
marginLeft: 0,
marginRight: 0
}
I'm not sure why I'm getting this error? Any ideas?
TL;DR
The margin value is too big. I think you meant to pass 20.0/96 inches:
- WithMarginTop(20.0).
+ WithMarginTop(20.0/96).
Explanation
The error message returned from chromium is misleading. I guess here is what happened: the provided margin settings is invalid, and since chromium is running in headless mode, it can not show the error dialog. The error message can be interpreted as "I can not show a dialog to alert the user that the provided printer settings are invalid".
"marginTop":20 in the raw CDP message means 20 inches on the top, which is too big for an A4 page (A4: 8.27in x 11.7in). Please note that a number in puppeteer is treated as pixels and will be converted to inches before sending to chromium (see https://github.com/puppeteer/puppeteer/blob/4d9dc8c0e613f22d4cdf237e8bd0b0da3c588edb/src/common/Page.ts#L3366-L3402). So the fix is obvious.
BTW, there are easy ways to see the raw CDP messages:
chromedp: use the chromedp.WithDebugf option:
ctx, cancel = chromedp.NewContext(context.Background(), chromedp.WithDebugf(log.Printf))`
puppeteer: env DEBUG="puppeteer:*" node script.js. See https://github.com/puppeteer/puppeteer#debugging-tips

golang cgi + apache login session management

I am new to golang. I want to use golang as cgi for my apache server. I dont want to run my golang program as a listener/server. I write .go files for each action such as login.go, logout.go, welcome.go and compile them into individual exes. I rename the exes into cgi and put them in the cgi-bin folder of apache and post from my html file to cgi bin folder. I want my go lang to serve through apache.
This is my simple html form
<html>
<head><title>Go Test</title></head>
<body>
<form action='cgi-bin/login.cgi' method='post'>
username : <input name='username' value='vimal'><br>
password : <input name='password' value='hello'><br>
<input type='submit' value='submit'>
</form>
</body>
</html>
This is my golang source for login. I compile into login.exe rename it to login.cgi and put it in cgibin folder of apache.
package main
import (
"net/http/cgi"
"net/http"
"fmt"
)
var (
// key must be 16, 24 or 32 bytes long (AES-128, AES-192 or AES-256)
// key = []byte("super-secret-key")
key = uuid.NewV4().String()
store = sessions.NewCookieStore(key)
)
func errorResponse(code int, msg string) {
fmt.Printf("Status:%d %s\r\n", code, msg)
fmt.Printf("Content-Type: text/plain\r\n")
fmt.Printf("\r\n")
fmt.Printf("%s\r\n", msg)
}
func main() {
var req *http.Request
var w *http.ResponseWriter
var err error
req, err = cgi.Request()
if err != nil {
errorResponse(500, "cannot get cgi request" + err.Error())
return
}
if err := req.ParseForm(); err != nil {
errorResponse(500, "cannot get cgi request" + err.Error())
}
username := req.FormValue("username")
password := req.FormValue("password")
//create session
//store session variables like user id, user name etc., that can be accessed through other .cgi files like welcome.cgi
// Use req to handle request
fmt.Printf("Content-type: text/html\n\n")
fmt.Printf("<!DOCTYPE html>\n")
fmt.Printf("<p>username: %s\n",username)
fmt.Printf("<p>password: %s\n",password)
fmt.Printf("req=%v\r\n", req)
}
I need help to create a session and store session variables like user id, username etc.,
If my another golang cgi file welcome.cgi is called it should be able to access the session variables like user id, name and print them
Please provide me with complete code. I am new to golang.
I dont want to use my golang as server. I just want to make small cgi pages.
Thanks
You can use normal handlers like the ones used in several examples on the internet, that way you don't need to use a series of fmt.Printf to send data to the CGI server. One way that I found easy to work is by using the cgi.Serve function which can be used in conjunction with an http.HandlerFunc. Using http.HandlerFunc or http.Handler will allow you to use any session manager implementation in go that uses http.ResponseWriter and http.Request. Note however that you should not initialize your store with a randomly generated key from inside your program, and also, if you use a database back-end you will not be able to use connection polling directly from go, since your program main function will be executed on each request and it should open an close connections on each invocation.
Following is a simple example that uses the approach discussed above:
package main
import (
"encoding/hex"
"fmt"
"io"
"net/http"
"net/http/cgi"
"os"
"github.com/gorilla/sessions"
)
func main() {
// Use Serve function with an anonymous function, you can also use instances
// of http.Handler. The function does not need to be an anonymous function, it
// just has to match the HandlerFunc signature
err := cgi.Serve(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// Get the session auth key from a trusted source,
// in this example an env var is used. You can use any mechanism you want
// so long that you don't generate it from within this program
key, _ := hex.DecodeString(os.Getenv("SESSION_AUTH_KEY"))
store := sessions.NewCookieStore(key)
// Get a session from the store if any
sess, err := store.Get(r, "mysess")
if err != nil {
io.WriteString(rw, fmt.Sprintf("error reading cookies: %v", err))
return
}
if sess.IsNew {
sess.Values["val"] = 1
//Save your store before writing anything to the client
if err := sess.Save(r, rw); err != nil {
io.WriteString(rw, "error writing sesion")
} else {
io.WriteString(rw, "new session")
}
return
}
//Write session values to validate that your session is working
io.WriteString(rw, "Values:")
for name, value := range sess.Values {
io.WriteString(rw, fmt.Sprintf("name: %s, val: %v", name, value))
}
}))
if err != nil {
fmt.Fprintf(os.Stderr, "Error :%v", err)
}
}

How to open an URL in a browser with an authentication header?

In Golang we can launch a browser window to open an URL using exec.Command method. An example can be found here
My question is how can we open that URL with a header?
If you're using Chrome, you could use Chrome DevTools Protocol to attach to a running Chrome instance and issue a command to navigate to a URL with specific headers.
First, Launch Chrome with Chrome Devtools Protocol enabled by using the flag --remote-debugging-port=9222
You'll get a response similar to DevTools listening on ws://127.0.0.1:9222/devtools/browser/2393d6e8-a85d-40a2-a79e-13f1585ff336
Pass that ws://... URL into the program below:
package main
import (
"context"
"flag"
"log"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
)
func main() {
var devToolWsURL string
flag.StringVar(&devToolWsURL, "devtools-ws-url", "", "DevTools Websocket URL")
flag.Parse()
// Create contexts.
actxt, cancelActxt := chromedp.NewRemoteAllocator(context.Background(), devToolWsURL)
defer cancelActxt()
// Create new tab.
ctxt, _ := chromedp.NewContext(actxt)
// Custom header.
headers := map[string]interface{}{
"X-Header": "my request header",
}
task := chromedp.Tasks{
network.Enable(),
network.SetExtraHTTPHeaders(network.Headers(headers)),
chromedp.Navigate("http://google.com"),
}
// Run task.
err := chromedp.Run(ctxt, task)
if err != nil {
log.Fatal(err)
}
}
Notes:
9222 is the default port for this protocol but you can use any port
you want.
I didn't include the exec.Command code for brevity.
References:
Header example
Remote Chrome control example
UPDATE
Found a simpler way. You can just launch Chrome straight from chromedp by overriding the default headless option:
func main() {
// Create contexts.
opts := append(chromedp.DefaultExecAllocatorOptions[:], chromedp.Flag("headless", false))
actx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
ctx, cancel := chromedp.NewContext(actx)
// Call cancel() to close Chrome on some condition.
if false {
cancel()
}
// Custom header.
headers := map[string]interface{}{
"X-Header": "my request header",
}
task := chromedp.Tasks{
network.Enable(),
network.SetExtraHTTPHeaders(network.Headers(headers)),
chromedp.Navigate("http://tested.com"),
}
// Run task.
err := chromedp.Run(ctx, task)
if err != nil {
log.Fatal(err)
}
}

How is recwatch supposed to work?

I'm trying to get recwatch to work. I'm confused by its interface, though. Yes, I can make a watcher and add folders to it, but there does not seem to be a way to start an event loop that will allow me to receive notifications.
In the original code, there was a Run receiver for just this purpose.
Am I missing something?
The watcher starts emitting events as soon as it is created. All that's required is to read them from RecursiveWatcher.Watcher.Events. Example:
package main
import (
"fmt"
"github.com/xyproto/recwatch"
)
func main() {
w, err := recwatch.NewRecursiveWatcher("sample_dir")
if err != nil {
panic(err)
}
for {
select {
case event := <-w.Events:
fmt.Printf("Event: %s\n", event)
case event := <-w.Errors:
fmt.Printf("Error: %s\n", event)
}
}
}

Resources