Этот коммит содержится в:
2023-12-13 20:07:22 +01:00
Коммит 5d0311b731
79 изменённых файлов: 3143 добавлений и 0 удалений

35
pkg/browser/browser.go Обычный файл
Просмотреть файл

@ -0,0 +1,35 @@
package browser
import "fmt"
type Status int
const (
StatusUnknown Status = iota
StatusIdle
StatusCasting
)
func (s Status) String() string {
switch s {
case StatusIdle:
return "idle"
case StatusCasting:
return "casting"
default:
return fmt.Sprintf("unknown (%d)", s)
}
}
type Browser interface {
// Cast loads an URL
Load(url string) error
// Reset resets the browser to the given idle URL
Reset(url string) error
// Status returns the browser's current status
Status() (Status, error)
// Title returns the browser's currently loaded page title
Title() (string, error)
// URL returns the browser's currently loaded page URL
URL() (string, error)
}

52
pkg/browser/dummy/browser.go Обычный файл
Просмотреть файл

@ -0,0 +1,52 @@
package dummy
import (
"context"
"forge.cadoles.com/arcad/arcast/pkg/browser"
"gitlab.com/wpetit/goweb/logger"
)
type Browser struct {
status browser.Status
url string
}
// Load implements browser.Browser.
func (b *Browser) Load(url string) error {
logger.Debug(context.Background(), "loading url", logger.F("url", url))
b.status = browser.StatusCasting
b.url = url
return nil
}
// Status implements browser.Browser.
func (b *Browser) Status() (browser.Status, error) {
return b.status, nil
}
// Title implements browser.Browser.
func (b *Browser) Title() (string, error) {
return "", nil
}
// URL implements browser.Browser.
func (b *Browser) URL() (string, error) {
return b.url, nil
}
// Reset implements browser.Browser.
func (b *Browser) Reset(url string) error {
b.status = browser.StatusIdle
b.url = url
return nil
}
func NewBrowser() *Browser {
return &Browser{
status: browser.StatusIdle,
url: "",
}
}
var _ browser.Browser = &Browser{}

118
pkg/browser/gioui/browser.go Обычный файл
Просмотреть файл

@ -0,0 +1,118 @@
package gioui
import (
"context"
"sync"
"forge.cadoles.com/arcad/arcast/pkg/browser"
"gioui.org/app"
"gioui.org/f32"
"gioui.org/layout"
"github.com/gioui-plugins/gio-plugins/webviewer"
"gitlab.com/wpetit/goweb/logger"
)
type Browser struct {
window *app.Window
tag int
url string
changed bool
status browser.Status
title string
mutex sync.Mutex
}
func (b *Browser) Layout(gtx layout.Context) {
b.mutex.Lock()
defer b.mutex.Unlock()
events := gtx.Events(&b.tag)
for _, evt := range events {
switch ev := evt.(type) {
case webviewer.TitleEvent:
b.title = ev.Title
case webviewer.NavigationEvent:
b.url = ev.URL
}
}
ctx := context.Background()
logger.Debug(ctx, "drawing")
webviewer.WebViewOp{Tag: &b.tag}.Push(gtx.Ops)
webviewer.OffsetOp{Point: f32.Point{Y: float32(gtx.Constraints.Max.Y - gtx.Constraints.Max.Y)}}.Add(gtx.Ops)
webviewer.RectOp{Size: f32.Point{X: float32(gtx.Constraints.Max.X), Y: float32(gtx.Constraints.Max.Y)}}.Add(gtx.Ops)
if b.changed {
logger.Debug(ctx, "url changed", logger.F("url", b.url))
webviewer.NavigateOp{URL: b.url}.Add(gtx.Ops)
b.changed = false
}
}
// Load implements browser.Browser.
func (b *Browser) Load(url string) error {
b.mutex.Lock()
defer b.mutex.Unlock()
b.url = url
b.changed = true
b.status = browser.StatusCasting
b.window.Invalidate()
return nil
}
// Status implements browser.Browser.
func (b *Browser) Status() (browser.Status, error) {
b.mutex.Lock()
defer b.mutex.Unlock()
return b.status, nil
}
// Title implements browser.Browser.
func (b *Browser) Title() (string, error) {
b.mutex.Lock()
defer b.mutex.Unlock()
return b.title, nil
}
// URL implements browser.Browser.
func (b *Browser) URL() (string, error) {
b.mutex.Lock()
defer b.mutex.Unlock()
return b.url, nil
}
// Reset implements browser.Browser.
func (b *Browser) Reset(url string) error {
b.mutex.Lock()
defer b.mutex.Unlock()
b.url = url
b.changed = true
b.status = browser.StatusIdle
b.window.Invalidate()
return nil
}
func NewBrowser(window *app.Window) *Browser {
return &Browser{
window: window,
url: "",
changed: true,
status: browser.StatusIdle,
}
}
var _ browser.Browser = &Browser{}

100
pkg/browser/lorca/browser.go Обычный файл
Просмотреть файл

@ -0,0 +1,100 @@
package lorca
import (
"context"
"forge.cadoles.com/arcad/arcast/pkg/browser"
"github.com/pkg/errors"
"github.com/zserge/lorca"
"gitlab.com/wpetit/goweb/logger"
)
type Browser struct {
ui lorca.UI
status browser.Status
opts *Options
}
func (b *Browser) Start() error {
logger.Debug(context.Background(), "starting browser", logger.F("opts", b.opts))
ui, err := lorca.New("", "", b.opts.Width, b.opts.Height, b.opts.ChromeArgs...)
if err != nil {
return errors.WithStack(err)
}
b.ui = ui
return nil
}
func (b *Browser) Stop() error {
if err := b.ui.Close(); err != nil {
return errors.WithStack(err)
}
b.ui = nil
return nil
}
func (b *Browser) Wait() {
<-b.ui.Done()
}
// Load implements browser.Browser.
func (b *Browser) Load(url string) error {
if err := b.ui.Load(url); err != nil {
return errors.WithStack(err)
}
b.status = browser.StatusCasting
return nil
}
// Unload implements browser.Browser.
func (b *Browser) Reset(url string) error {
if err := b.ui.Load(url); err != nil {
return errors.WithStack(err)
}
b.status = browser.StatusIdle
return nil
}
// Status implements browser.Browser.
func (b *Browser) Status() (browser.Status, error) {
return b.status, nil
}
// Title implements browser.Browser.
func (b *Browser) Title() (string, error) {
result := b.ui.Eval("document.title.toString()")
if err := result.Err(); err != nil {
return "", errors.WithStack(err)
}
return result.String(), nil
}
// URL implements browser.Browser.
func (b *Browser) URL() (string, error) {
result := b.ui.Eval("window.location.toString()")
if err := result.Err(); err != nil {
return "", errors.WithStack(err)
}
return result.String(), nil
}
func NewBrowser(funcs ...OptionsFunc) *Browser {
opts := NewOptions(funcs...)
return &Browser{
status: browser.StatusIdle,
opts: opts,
}
}
var _ browser.Browser = &Browser{}

40
pkg/browser/lorca/options.go Обычный файл
Просмотреть файл

@ -0,0 +1,40 @@
package lorca
type Options struct {
Width int
Height int
ChromeArgs []string
}
type OptionsFunc func(opts *Options)
var DefaultChromeArgs = []string{
"--remote-allow-origins=*",
}
func NewOptions(funcs ...OptionsFunc) *Options {
opts := &Options{
Width: 800,
Height: 600,
ChromeArgs: DefaultChromeArgs,
}
for _, fn := range funcs {
fn(opts)
}
return opts
}
func WithWindowSize(width, height int) OptionsFunc {
return func(opts *Options) {
opts.Width = width
opts.Height = height
}
}
func WithAdditionalChromeArgs(args ...string) OptionsFunc {
return func(opts *Options) {
opts.ChromeArgs = append(args, DefaultChromeArgs...)
}
}